aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--.qmake.conf2
-rw-r--r--examples/quick/scenegraph/openglunderqml/squircle.cpp5
-rw-r--r--src/3rdparty/masm/assembler/MacroAssemblerARMv7.h10
-rw-r--r--src/3rdparty/masm/assembler/MacroAssemblerX86Common.h20
-rw-r--r--src/imports/localstorage/plugin.cpp4
-rw-r--r--src/particles/qquickv4particledata.cpp2
-rw-r--r--src/qml/compiler/qqmlcodegenerator.cpp310
-rw-r--r--src/qml/compiler/qqmlcodegenerator_p.h32
-rw-r--r--src/qml/compiler/qv4codegen.cpp4
-rw-r--r--src/qml/compiler/qv4codegen_p.h3
-rw-r--r--src/qml/compiler/qv4compiler.cpp91
-rw-r--r--src/qml/compiler/qv4compiler_p.h7
-rw-r--r--src/qml/compiler/qv4instr_moth_p.h35
-rw-r--r--src/qml/compiler/qv4isel_masm.cpp170
-rw-r--r--src/qml/compiler/qv4isel_masm_p.h39
-rw-r--r--src/qml/compiler/qv4isel_moth.cpp50
-rw-r--r--src/qml/compiler/qv4isel_moth_p.h13
-rw-r--r--src/qml/compiler/qv4isel_p.cpp39
-rw-r--r--src/qml/compiler/qv4isel_p.h9
-rw-r--r--src/qml/compiler/qv4jsir.cpp58
-rw-r--r--src/qml/compiler/qv4jsir_p.h116
-rw-r--r--src/qml/compiler/qv4regalloc.cpp25
-rw-r--r--src/qml/compiler/qv4ssa.cpp830
-rw-r--r--src/qml/compiler/qv4ssa_p.h3
-rw-r--r--src/qml/debugger/qqmlprofilerservice.cpp200
-rw-r--r--src/qml/debugger/qqmlprofilerservice_p.h90
-rw-r--r--src/qml/debugger/qv4debugservice.cpp8
-rw-r--r--src/qml/jsapi/qjsengine.cpp51
-rw-r--r--src/qml/jsapi/qjsvalue.cpp89
-rw-r--r--src/qml/jsapi/qjsvalue_p.h7
-rw-r--r--src/qml/jsapi/qjsvalueiterator.cpp6
-rw-r--r--src/qml/jsruntime/qv4argumentsobject.cpp115
-rw-r--r--src/qml/jsruntime/qv4argumentsobject_p.h18
-rw-r--r--src/qml/jsruntime/qv4arrayobject.cpp18
-rw-r--r--src/qml/jsruntime/qv4booleanobject.cpp2
-rw-r--r--src/qml/jsruntime/qv4booleanobject_p.h2
-rw-r--r--src/qml/jsruntime/qv4context.cpp204
-rw-r--r--src/qml/jsruntime/qv4context_p.h107
-rw-r--r--src/qml/jsruntime/qv4dateobject.cpp4
-rw-r--r--src/qml/jsruntime/qv4dateobject_p.h3
-rw-r--r--src/qml/jsruntime/qv4debugging.cpp27
-rw-r--r--src/qml/jsruntime/qv4debugging_p.h2
-rw-r--r--src/qml/jsruntime/qv4engine.cpp113
-rw-r--r--src/qml/jsruntime/qv4engine_p.h48
-rw-r--r--src/qml/jsruntime/qv4errorobject.cpp22
-rw-r--r--src/qml/jsruntime/qv4errorobject_p.h12
-rw-r--r--src/qml/jsruntime/qv4function.cpp35
-rw-r--r--src/qml/jsruntime/qv4function_p.h10
-rw-r--r--src/qml/jsruntime/qv4functionobject.cpp189
-rw-r--r--src/qml/jsruntime/qv4functionobject_p.h22
-rw-r--r--src/qml/jsruntime/qv4global_p.h2
-rw-r--r--src/qml/jsruntime/qv4globalobject.cpp12
-rw-r--r--src/qml/jsruntime/qv4include.cpp6
-rw-r--r--src/qml/jsruntime/qv4internalclass.cpp60
-rw-r--r--src/qml/jsruntime/qv4internalclass_p.h14
-rw-r--r--src/qml/jsruntime/qv4jsonobject.cpp2
-rw-r--r--src/qml/jsruntime/qv4jsonobject_p.h4
-rw-r--r--src/qml/jsruntime/qv4lookup.cpp6
-rw-r--r--src/qml/jsruntime/qv4managed.cpp36
-rw-r--r--src/qml/jsruntime/qv4managed_p.h42
-rw-r--r--src/qml/jsruntime/qv4mathobject_p.h2
-rw-r--r--src/qml/jsruntime/qv4mm.cpp69
-rw-r--r--src/qml/jsruntime/qv4mm_p.h12
-rw-r--r--src/qml/jsruntime/qv4numberobject.cpp2
-rw-r--r--src/qml/jsruntime/qv4object.cpp39
-rw-r--r--src/qml/jsruntime/qv4object_p.h14
-rw-r--r--src/qml/jsruntime/qv4objectiterator.cpp11
-rw-r--r--src/qml/jsruntime/qv4objectiterator_p.h2
-rw-r--r--src/qml/jsruntime/qv4objectproto.cpp13
-rw-r--r--src/qml/jsruntime/qv4qobjectwrapper.cpp78
-rw-r--r--src/qml/jsruntime/qv4qobjectwrapper_p.h6
-rw-r--r--src/qml/jsruntime/qv4regexp.cpp3
-rw-r--r--src/qml/jsruntime/qv4regexpobject.cpp6
-rw-r--r--src/qml/jsruntime/qv4runtime.cpp73
-rw-r--r--src/qml/jsruntime/qv4runtime_p.h7
-rw-r--r--src/qml/jsruntime/qv4scopedvalue_p.h6
-rw-r--r--src/qml/jsruntime/qv4script.cpp36
-rw-r--r--src/qml/jsruntime/qv4sequenceobject.cpp13
-rw-r--r--src/qml/jsruntime/qv4serialize.cpp2
-rw-r--r--src/qml/jsruntime/qv4string.cpp27
-rw-r--r--src/qml/jsruntime/qv4string_p.h4
-rw-r--r--src/qml/jsruntime/qv4stringobject.cpp18
-rw-r--r--src/qml/jsruntime/qv4value.cpp6
-rw-r--r--src/qml/jsruntime/qv4variantobject.cpp2
-rw-r--r--src/qml/jsruntime/qv4vme_moth.cpp27
-rw-r--r--src/qml/qml.pro4
-rw-r--r--src/qml/qml/ftw/qhashedstring.cpp14
-rw-r--r--src/qml/qml/qqml.h4
-rw-r--r--src/qml/qml/qqmlbinding.cpp10
-rw-r--r--src/qml/qml/qqmlboundsignal.cpp4
-rw-r--r--src/qml/qml/qqmlcompileddata.cpp22
-rw-r--r--src/qml/qml/qqmlcompiler.cpp68
-rw-r--r--src/qml/qml/qqmlcompiler_p.h20
-rw-r--r--src/qml/qml/qqmlcomponent.cpp20
-rw-r--r--src/qml/qml/qqmlcomponent_p.h4
-rw-r--r--src/qml/qml/qqmlcontextwrapper.cpp99
-rw-r--r--src/qml/qml/qqmlcontextwrapper_p.h18
-rw-r--r--src/qml/qml/qqmlcustomparser.cpp3
-rw-r--r--src/qml/qml/qqmldata_p.h3
-rw-r--r--src/qml/qml/qqmlengine.cpp54
-rw-r--r--src/qml/qml/qqmlengine_p.h15
-rw-r--r--src/qml/qml/qqmlinstruction_p.h6
-rw-r--r--src/qml/qml/qqmljavascriptexpression.cpp6
-rw-r--r--src/qml/qml/qqmllistwrapper.cpp6
-rw-r--r--src/qml/qml/qqmllocale.cpp4
-rw-r--r--src/qml/qml/qqmlmemoryprofiler.cpp3
-rw-r--r--src/qml/qml/qqmlmetatype.cpp8
-rw-r--r--src/qml/qml/qqmltypeloader.cpp9
-rw-r--r--src/qml/qml/qqmltypewrapper.cpp16
-rw-r--r--src/qml/qml/qqmlvaluetype_p.h42
-rw-r--r--src/qml/qml/qqmlvaluetypewrapper.cpp12
-rw-r--r--src/qml/qml/qqmlvme.cpp27
-rw-r--r--src/qml/qml/qqmlvme_p.h2
-rw-r--r--src/qml/qml/qqmlvmemetaobject.cpp2
-rw-r--r--src/qml/qml/qqmlxmlhttprequest.cpp28
-rw-r--r--src/qml/qml/v8/qqmlbuiltinfunctions.cpp10
-rw-r--r--src/qml/qml/v8/qv8engine.cpp8
-rw-r--r--src/qml/types/qqmldelegatemodel.cpp14
-rw-r--r--src/qml/types/qqmldelegatemodel_p_p.h2
-rw-r--r--src/qml/types/qquickworkerscript.cpp6
-rw-r--r--src/qml/util/qqmladaptormodel.cpp6
-rw-r--r--src/quick/doc/src/concepts/visualcanvas/scenegraph.qdoc5
-rw-r--r--src/quick/items/context2d/qquickcanvascontext_p.h2
-rw-r--r--src/quick/items/context2d/qquickcanvasitem.cpp64
-rw-r--r--src/quick/items/context2d/qquickcanvasitem_p.h8
-rw-r--r--src/quick/items/context2d/qquickcontext2d.cpp60
-rw-r--r--src/quick/items/context2d/qquickcontext2d_p.h6
-rw-r--r--src/quick/items/context2d/qquickcontext2dcommandbuffer.cpp34
-rw-r--r--src/quick/items/context2d/qquickcontext2dcommandbuffer_p.h2
-rw-r--r--src/quick/items/context2d/qquickcontext2dtexture.cpp193
-rw-r--r--src/quick/items/context2d/qquickcontext2dtexture_p.h70
-rw-r--r--src/quick/items/items.pri1
-rw-r--r--src/quick/items/qquickflickable.cpp127
-rw-r--r--src/quick/items/qquickflickablebehavior_p.h105
-rw-r--r--src/quick/items/qquickitem_p.h2
-rw-r--r--src/quick/items/qquickitemview.cpp2
-rw-r--r--src/quick/items/qquickitemview_p.h15
-rw-r--r--src/quick/items/qquicklistview.cpp68
-rw-r--r--src/quick/items/qquickloader.cpp5
-rw-r--r--src/quick/items/qquickloader_p_p.h1
-rw-r--r--src/quick/items/qquickmousearea.cpp6
-rw-r--r--src/quick/items/qquickpathview.cpp17
-rw-r--r--src/quick/items/qquickshadereffect.cpp1
-rw-r--r--src/quick/items/qquickshadereffectnode.cpp7
-rw-r--r--src/quick/items/qquicktextinput.cpp8
-rw-r--r--src/quick/items/qquickwindow.cpp27
-rw-r--r--src/quick/scenegraph/coreapi/qsgbatchrenderer.cpp3
-rw-r--r--src/quick/scenegraph/coreapi/qsgrenderer.cpp6
-rw-r--r--src/quick/scenegraph/qsgcontext.cpp2
-rw-r--r--src/quick/scenegraph/qsgrenderloop.cpp10
-rw-r--r--src/quick/scenegraph/qsgthreadedrenderloop.cpp7
-rw-r--r--src/quick/scenegraph/qsgwindowsrenderloop.cpp4
-rw-r--r--src/quick/scenegraph/shaders/distancefieldshiftedtext.frag2
-rw-r--r--src/quick/scenegraph/util/qsgatlastexture.cpp1
-rw-r--r--src/quick/util/qquickapplication.cpp2
-rw-r--r--src/quick/util/qquickpixmapcache.cpp11
-rw-r--r--src/quick/util/qquicksmoothedanimation.cpp3
-rw-r--r--src/quick/util/qquickvaluetypes_p.h82
-rw-r--r--tests/auto/particles/qquicktrailemitter/tst_qquicktrailemitter.cpp2
-rw-r--r--tests/auto/qml/animation/qpauseanimationjob/tst_qpauseanimationjob.cpp51
-rw-r--r--tests/auto/qml/debugger/qqmlprofilerservice/tst_qqmlprofilerservice.cpp20
-rw-r--r--tests/auto/qml/debugger/shared/qqmldebugclient.cpp1
-rw-r--r--tests/auto/qml/qqmlecmascript/data/misctypetest.qml4
-rw-r--r--tests/auto/qml/qqmlecmascript/data/noCaptureWhenWritingProperty.qml14
-rw-r--r--tests/auto/qml/qqmlecmascript/data/sequenceConversion.array.qml16
-rw-r--r--tests/auto/qml/qqmlecmascript/data/signalHandlers.qml34
-rw-r--r--tests/auto/qml/qqmlecmascript/testtypes.cpp2
-rw-r--r--tests/auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp22
-rw-r--r--tests/auto/qml/qqmllanguage/data/customParserBindingScopes.qml19
-rw-r--r--tests/auto/qml/qqmllanguage/testtypes.cpp60
-rw-r--r--tests/auto/qml/qqmllanguage/testtypes.h23
-rw-r--r--tests/auto/qml/qqmllanguage/tst_qqmllanguage.cpp13
-rw-r--r--tests/auto/qml/qqmlpropertymap/tst_qqmlpropertymap.cpp81
-rw-r--r--tests/auto/qml/qqmltranslation/data/jstranslation.qml20
-rw-r--r--tests/auto/qml/qqmltranslation/data/translation.js98
-rw-r--r--tests/auto/qml/qqmltranslation/tst_qqmltranslation.cpp47
-rw-r--r--tests/auto/qml/qqmlxmlhttprequest/tst_qqmlxmlhttprequest.cpp295
-rw-r--r--tests/auto/quick/qquickapplication/tst_qquickapplication.cpp1
-rw-r--r--tests/auto/quick/qquickflickable/data/stopAtBounds.qml22
-rw-r--r--tests/auto/quick/qquickflickable/qquickflickable.pro1
-rw-r--r--tests/auto/quick/qquickflickable/tst_qquickflickable.cpp110
-rw-r--r--tests/auto/quick/qquickitem/tst_qquickitem.cpp25
-rw-r--r--tests/auto/quick/qquicklistview/data/HighlightResize.qml23
-rw-r--r--tests/auto/quick/qquicklistview/data/headerchangesviewport.qml19
-rw-r--r--tests/auto/quick/qquicklistview/data/listview-sections.qml25
-rw-r--r--tests/auto/quick/qquicklistview/data/typedModel.qml23
-rw-r--r--tests/auto/quick/qquicklistview/tst_qquicklistview.cpp73
-rw-r--r--tests/auto/quick/qquickloader/data/SimpleTestComponent.qml2
-rw-r--r--tests/auto/quick/qquickloader/data/sourceComponentGarbageCollection.qml8
-rw-r--r--tests/auto/quick/qquickloader/tst_qquickloader.cpp22
-rw-r--r--tests/auto/quick/qquickmousearea/tst_qquickmousearea.cpp52
-rw-r--r--tests/auto/quick/qquicktextinput/data/signal_accepted.qml14
-rw-r--r--tests/auto/quick/qquicktextinput/data/signal_editingfinished.qml14
-rw-r--r--tests/auto/quick/qquicktextinput/tst_qquicktextinput.cpp238
-rw-r--r--tests/auto/quick/qquickwindow/data/focus.qml4
-rw-r--r--tests/auto/quick/qquickwindow/tst_qquickwindow.cpp15
-rw-r--r--tests/auto/quick/scenegraph/data/simple.qml60
-rw-r--r--tests/auto/quick/scenegraph/scenegraph.pro3
-rw-r--r--tests/auto/quick/scenegraph/tst_scenegraph.cpp36
-rw-r--r--tests/auto/shared/testhttpserver.cpp53
-rw-r--r--tests/auto/shared/testhttpserver.h9
-rw-r--r--tools/qmljs/main.cpp4
202 files changed, 4901 insertions, 2268 deletions
diff --git a/.qmake.conf b/.qmake.conf
index b0bc49d477..a0d132328a 100644
--- a/.qmake.conf
+++ b/.qmake.conf
@@ -2,5 +2,5 @@ load(qt_build_config)
CONFIG += qt_example_installs
CONFIG += warning_clean
-MODULE_VERSION = 5.2.0
+MODULE_VERSION = 5.2.1
diff --git a/examples/quick/scenegraph/openglunderqml/squircle.cpp b/examples/quick/scenegraph/openglunderqml/squircle.cpp
index 8ceb9c5f9e..91d69c90a4 100644
--- a/examples/quick/scenegraph/openglunderqml/squircle.cpp
+++ b/examples/quick/scenegraph/openglunderqml/squircle.cpp
@@ -129,7 +129,10 @@ void Squircle::paint()
m_program->setAttributeArray(0, GL_FLOAT, values, 2);
m_program->setUniformValue("t", (float) m_thread_t);
- glViewport(0, 0, window()->width(), window()->height());
+ qreal ratio = window()->devicePixelRatio();
+ int w = int(ratio * window()->width());
+ int h = int(ratio * window()->height());
+ glViewport(0, 0, w, h);
glDisable(GL_DEPTH_TEST);
diff --git a/src/3rdparty/masm/assembler/MacroAssemblerARMv7.h b/src/3rdparty/masm/assembler/MacroAssemblerARMv7.h
index 61c13acd35..9a8dc1f358 100644
--- a/src/3rdparty/masm/assembler/MacroAssemblerARMv7.h
+++ b/src/3rdparty/masm/assembler/MacroAssemblerARMv7.h
@@ -177,6 +177,11 @@ public:
}
}
+ void add32(RegisterID op1, RegisterID op2, RegisterID dest)
+ {
+ m_assembler.add(dest, op1, op2);
+ }
+
void add32(TrustedImm32 imm, Address address)
{
load32(address, dataTempRegister);
@@ -310,6 +315,11 @@ public:
m_assembler.smull(dest, dataTempRegister, src, dataTempRegister);
}
+ void mul32(RegisterID op1, RegisterID op2, RegisterID dest)
+ {
+ m_assembler.smull(dest, dataTempRegister, op1, op2);
+ }
+
void neg32(RegisterID srcDest)
{
m_assembler.neg(srcDest, srcDest);
diff --git a/src/3rdparty/masm/assembler/MacroAssemblerX86Common.h b/src/3rdparty/masm/assembler/MacroAssemblerX86Common.h
index 520cf915fa..94771be6a7 100644
--- a/src/3rdparty/masm/assembler/MacroAssemblerX86Common.h
+++ b/src/3rdparty/masm/assembler/MacroAssemblerX86Common.h
@@ -146,6 +146,16 @@ public:
m_assembler.andl_rr(src, dest);
}
+ void add32(RegisterID op1, RegisterID op2, RegisterID dest)
+ {
+ if (op2 == dest) {
+ add32(op1, dest);
+ } else {
+ move(op1, dest);
+ add32(op2, dest);
+ }
+ }
+
void and32(TrustedImm32 imm, RegisterID dest)
{
m_assembler.andl_ir(imm.m_value, dest);
@@ -226,6 +236,16 @@ public:
m_assembler.imull_rr(src, dest);
}
+ void mul32(RegisterID op1, RegisterID op2, RegisterID dest)
+ {
+ if (op2 == dest) {
+ mul32(op1, dest);
+ } else {
+ move(op1, dest);
+ mul32(op2, dest);
+ }
+ }
+
void mul32(Address src, RegisterID dest)
{
m_assembler.imull_mr(src.offset, src.base, dest);
diff --git a/src/imports/localstorage/plugin.cpp b/src/imports/localstorage/plugin.cpp
index 145487cf3e..48693dbbf3 100644
--- a/src/imports/localstorage/plugin.cpp
+++ b/src/imports/localstorage/plugin.cpp
@@ -108,7 +108,7 @@ public:
QQmlSqlDatabaseWrapper(QV8Engine *e)
: Object(QV8Engine::getV4(e)), type(Database), inTransaction(false), readonly(false), forwardOnly(false)
{
- vtbl = &static_vtbl;
+ setVTable(&static_vtbl);
}
~QQmlSqlDatabaseWrapper() {
@@ -659,7 +659,7 @@ void QQuickLocalStorage::openDatabaseSync(QQmlV4Function *args)
{
#ifndef QT_NO_SETTINGS
QV8Engine *engine = args->engine();
- QV4::ExecutionContext *ctx = args->v4engine()->current;
+ QV4::ExecutionContext *ctx = args->v4engine()->currentContext();
QV4::Scope scope(ctx);
if (engine->engine()->offlineStoragePath().isEmpty())
V4THROW_SQL2(SQLEXCEPTION_DATABASE_ERR, QQmlEngine::tr("SQL: can't create database, offline storage is disabled."));
diff --git a/src/particles/qquickv4particledata.cpp b/src/particles/qquickv4particledata.cpp
index 6f9cd829bb..d0e9a392d4 100644
--- a/src/particles/qquickv4particledata.cpp
+++ b/src/particles/qquickv4particledata.cpp
@@ -277,7 +277,7 @@ struct QV4ParticleData : public QV4::Object
QV4ParticleData(QV4::ExecutionEngine *engine, QQuickParticleData *datum)
: Object(engine)
{
- vtbl = &static_vtbl;
+ setVTable(&static_vtbl);
this->datum = datum;
}
diff --git a/src/qml/compiler/qqmlcodegenerator.cpp b/src/qml/compiler/qqmlcodegenerator.cpp
index 2215551b95..8809221abe 100644
--- a/src/qml/compiler/qqmlcodegenerator.cpp
+++ b/src/qml/compiler/qqmlcodegenerator.cpp
@@ -45,6 +45,7 @@
#include <private/qqmljsparser_p.h>
#include <private/qqmljslexer_p.h>
#include <private/qqmlcompiler_p.h>
+#include <private/qqmlglobal_p.h>
#include <QCoreApplication>
#ifdef CONST
@@ -53,6 +54,8 @@
QT_USE_NAMESPACE
+DEFINE_BOOL_CONFIG_OPTION(lookupHints, QML_LOOKUP_HINTS);
+
using namespace QtQml;
#define COMPILE_EXCEPTION(location, desc) \
@@ -278,7 +281,7 @@ bool QQmlCodeGenerator::sanityCheckFunctionNames()
{
QSet<QString> functionNames;
for (Function *f = _object->functions->first; f; f = f->next) {
- AST::FunctionDeclaration *function = AST::cast<AST::FunctionDeclaration*>(_functions.at(f->index));
+ AST::FunctionDeclaration *function = AST::cast<AST::FunctionDeclaration*>(_functions.at(f->index).node);
Q_ASSERT(function);
QString name = function->name.toString();
if (functionNames.contains(name))
@@ -1201,13 +1204,19 @@ int QmlUnitGenerator::getStringId(const QString &str) const
return jsUnitGenerator->getStringId(str);
}
-JSCodeGen::JSCodeGen(QQmlEnginePrivate *enginePrivate, const QString &fileName, const QString &sourceCode, V4IR::Module *jsModule, Engine *jsEngine, AST::UiProgram *qmlRoot, QQmlTypeNameCache *imports)
+JSCodeGen::JSCodeGen(const QString &fileName, const QString &sourceCode, V4IR::Module *jsModule, Engine *jsEngine, AST::UiProgram *qmlRoot, QQmlTypeNameCache *imports)
: QQmlJS::Codegen(/*strict mode*/false)
- , engine(enginePrivate)
, sourceCode(sourceCode)
, jsEngine(jsEngine)
, qmlRoot(qmlRoot)
, imports(imports)
+ , _disableAcceleratedLookups(false)
+ , _contextObject(0)
+ , _scopeObject(0)
+ , _contextObjectTemp(-1)
+ , _scopeObjectTemp(-1)
+ , _importedScriptsTemp(-1)
+ , _idArrayTemp(-1)
{
_module = jsModule;
_module->setFileName(fileName);
@@ -1226,23 +1235,23 @@ void JSCodeGen::beginObjectScope(QQmlPropertyCache *scopeObject)
_scopeObject = scopeObject;
}
-QVector<int> JSCodeGen::generateJSCodeForFunctionsAndBindings(const QList<AST::Node*> &functions, const QHash<int, QString> &functionNames)
+QVector<int> JSCodeGen::generateJSCodeForFunctionsAndBindings(const QList<CompiledFunctionOrExpression> &functions)
{
QVector<int> runtimeFunctionIndices(functions.size());
ScanFunctions scan(this, sourceCode, GlobalCode);
scan.enterEnvironment(0, QmlBinding);
scan.enterQmlScope(qmlRoot, QStringLiteral("context scope"));
- foreach (AST::Node *node, functions) {
- Q_ASSERT(node != qmlRoot);
- AST::FunctionDeclaration *function = AST::cast<AST::FunctionDeclaration*>(node);
+ foreach (const CompiledFunctionOrExpression &f, functions) {
+ Q_ASSERT(f.node != qmlRoot);
+ AST::FunctionDeclaration *function = AST::cast<AST::FunctionDeclaration*>(f.node);
if (function)
scan.enterQmlFunction(function);
else
- scan.enterEnvironment(node, QmlBinding);
+ scan.enterEnvironment(f.node, QmlBinding);
- scan(function ? function->body : node);
+ scan(function ? function->body : f.node);
scan.leaveEnvironment();
}
scan.leaveEnvironment();
@@ -1252,7 +1261,8 @@ QVector<int> JSCodeGen::generateJSCodeForFunctionsAndBindings(const QList<AST::N
_function = _module->functions.at(defineFunction(QStringLiteral("context scope"), qmlRoot, 0, 0));
for (int i = 0; i < functions.count(); ++i) {
- AST::Node *node = functions.at(i);
+ const CompiledFunctionOrExpression &qmlFunction = functions.at(i);
+ AST::Node *node = qmlFunction.node;
Q_ASSERT(node != qmlRoot);
AST::FunctionDeclaration *function = AST::cast<AST::FunctionDeclaration*>(node);
@@ -1260,8 +1270,10 @@ QVector<int> JSCodeGen::generateJSCodeForFunctionsAndBindings(const QList<AST::N
QString name;
if (function)
name = function->name.toString();
+ else if (!qmlFunction.name.isEmpty())
+ name = qmlFunction.name;
else
- name = functionNames.value(i, QStringLiteral("%qml-expression-entry"));
+ name = QStringLiteral("%qml-expression-entry");
AST::SourceElements *body;
if (function)
@@ -1281,6 +1293,7 @@ QVector<int> JSCodeGen::generateJSCodeForFunctionsAndBindings(const QList<AST::N
body = body->finish();
}
+ _disableAcceleratedLookups = qmlFunction.disableAcceleratedLookups;
int idx = defineFunction(name, node,
function ? function->formals : 0,
body);
@@ -1318,51 +1331,215 @@ QQmlPropertyData *JSCodeGen::lookupQmlCompliantProperty(QQmlPropertyCache *cache
return pd;
}
-V4IR::Expr *JSCodeGen::member(V4IR::Expr *base, const QString *name)
+static void initMetaObjectResolver(V4IR::MemberExpressionResolver *resolver, QQmlPropertyCache *metaObject);
+
+enum MetaObjectResolverFlags {
+ AllPropertiesAreFinal = 0x1,
+ LookupsIncludeEnums = 0x2,
+ LookupsExcludeProperties = 0x4,
+ ResolveTypeInformationOnly = 0x8
+};
+
+static void initMetaObjectResolver(V4IR::MemberExpressionResolver *resolver, QQmlPropertyCache *metaObject);
+
+static V4IR::Type resolveQmlType(QQmlEnginePrivate *qmlEngine, V4IR::MemberExpressionResolver *resolver, V4IR::Member *member)
{
- V4IR::Member *baseAsMember = base->asMember();
- if (baseAsMember) {
- QQmlPropertyCache *cache = 0;
+ V4IR::Type result = V4IR::VarType;
+
+ QQmlType *type = static_cast<QQmlType*>(resolver->data);
+ if (type->isSingleton()) {
+ if (type->isCompositeSingleton()) {
+ QQmlTypeData *tdata = qmlEngine->typeLoader.getType(type->singletonInstanceInfo()->url);
+ Q_ASSERT(tdata);
+ Q_ASSERT(tdata->isComplete());
+ initMetaObjectResolver(resolver, qmlEngine->propertyCacheForType(tdata->compiledData()->metaTypeId));
+ resolver->flags |= AllPropertiesAreFinal;
+ } else {
+ const QMetaObject *singletonMo = type->singletonInstanceInfo()->instanceMetaObject;
+ if (!singletonMo) { // We can only accelerate C++ singletons that were registered with their meta-type
+ resolver->clear();
+ return result;
+ }
+ initMetaObjectResolver(resolver, qmlEngine->cache(singletonMo));
+ resolver->flags |= LookupsIncludeEnums;
+ }
+ return resolver->resolveMember(qmlEngine, resolver, member);
+ } else {
+ if (member->name->constData()->isUpper()) {
+ bool ok = false;
+ int value = type->enumValue(*member->name, &ok);
+ if (ok) {
+ member->setEnumValue(value);
+ resolver->clear();
+ return V4IR::SInt32Type;
+ }
+ } else if (const QMetaObject *attachedMeta = type->attachedPropertiesType()) {
+ QQmlPropertyCache *cache = qmlEngine->cache(attachedMeta);
+ initMetaObjectResolver(resolver, cache);
+ member->setAttachedPropertiesId(type->attachedPropertiesId());
+ return resolver->resolveMember(qmlEngine, resolver, member);
+ }
+ }
- if (baseAsMember->type == V4IR::Member::MemberOfQObject
- && baseAsMember->property->isQObject()) {
+ resolver->clear();
+ return result;
+}
- bool propertySuitable = baseAsMember->property->isFinal();
+static void initQmlTypeResolver(V4IR::MemberExpressionResolver *resolver, QQmlType *qmlType)
+{
+ resolver->resolveMember = &resolveQmlType;
+ resolver->data = qmlType;
+ resolver->extraData = 0;
+ resolver->flags = 0;
+}
- if (!propertySuitable) {
- // Properties of the scope or context object do not need to be final, as we
- // intend to find the version of a property available at compile time, not at run-time.
- if (V4IR::Name *baseName = baseAsMember->base->asName())
- propertySuitable = baseName->builtin == V4IR::Name::builtin_qml_scope_object || baseName->builtin == V4IR::Name::builtin_qml_context_object;
+static V4IR::Type resolveImportNamespace(QQmlEnginePrivate *, V4IR::MemberExpressionResolver *resolver, V4IR::Member *member)
+{
+ V4IR::Type result = V4IR::VarType;
+ QQmlTypeNameCache *typeNamespace = static_cast<QQmlTypeNameCache*>(resolver->extraData);
+ void *importNamespace = resolver->data;
+
+ QQmlTypeNameCache::Result r = typeNamespace->query(*member->name, importNamespace);
+ if (r.isValid()) {
+ member->freeOfSideEffects = true;
+ if (r.scriptIndex != -1) {
+ // TODO: remember the index and replace with subscript later.
+ result = V4IR::VarType;
+ } else if (r.type) {
+ // TODO: Propagate singleton information, so that it is loaded
+ // through the singleton getter in the run-time. Until then we
+ // can't accelerate access :(
+ if (!r.type->isSingleton()) {
+ initQmlTypeResolver(resolver, r.type);
+ return V4IR::QObjectType;
}
+ } else {
+ Q_ASSERT(false); // How can this happen?
+ }
+ }
- // Check if it's suitable for caching
- if (propertySuitable)
- cache = engine->propertyCacheForType(baseAsMember->property->propType);
- } else if (baseAsMember->type == V4IR::Member::MemberOfQmlContext) {
- // Similarly, properties of an id referenced object also don't need to be final, because
- // we intend to find the version of a property available at compile time, not at run-time.
- foreach (const IdMapping &mapping, _idObjects) {
- if (baseAsMember->memberIndex == mapping.idIndex) {
- cache = mapping.type;
- break;
+ resolver->clear();
+ return result;
+}
+
+static void initImportNamespaceResolver(V4IR::MemberExpressionResolver *resolver, QQmlTypeNameCache *imports, const void *importNamespace)
+{
+ resolver->resolveMember = &resolveImportNamespace;
+ resolver->data = const_cast<void*>(importNamespace);
+ resolver->extraData = imports;
+ resolver->flags = 0;
+}
+
+static V4IR::Type resolveMetaObjectProperty(QQmlEnginePrivate *qmlEngine, V4IR::MemberExpressionResolver *resolver, V4IR::Member *member)
+{
+ V4IR::Type result = V4IR::VarType;
+ QQmlPropertyCache *metaObject = static_cast<QQmlPropertyCache*>(resolver->data);
+
+ if (member->name->constData()->isUpper() && (resolver->flags & LookupsIncludeEnums)) {
+ const QMetaObject *mo = metaObject->createMetaObject();
+ QByteArray enumName = member->name->toUtf8();
+ for (int ii = mo->enumeratorCount() - 1; ii >= 0; --ii) {
+ QMetaEnum metaEnum = mo->enumerator(ii);
+ bool ok;
+ int value = metaEnum.keyToValue(enumName.constData(), &ok);
+ if (ok) {
+ member->setEnumValue(value);
+ resolver->clear();
+ return V4IR::SInt32Type;
+ }
+ }
+ }
+
+ if (qmlEngine && !(resolver->flags & LookupsExcludeProperties)) {
+ QQmlPropertyData *property = member->property;
+ if (!property && metaObject) {
+ if (QQmlPropertyData *candidate = metaObject->property(*member->name, /*object*/0, /*context*/0)) {
+ const bool isFinalProperty = (candidate->isFinal() || (resolver->flags & AllPropertiesAreFinal))
+ && !candidate->isFunction();
+
+ if (lookupHints()
+ && !(resolver->flags & AllPropertiesAreFinal)
+ && !candidate->isFinal()
+ && !candidate->isFunction()
+ && candidate->isDirect()) {
+ qWarning() << "Hint: Access to property" << *member->name << "of" << metaObject->className() << "could be accelerated if it was marked as FINAL";
+ }
+
+ if (isFinalProperty && metaObject->isAllowedInRevision(candidate)) {
+ property = candidate;
+ member->inhibitTypeConversionOnWrite = true;
+ if (!(resolver->flags & ResolveTypeInformationOnly))
+ member->property = candidate; // Cache for next iteration and isel needs it.
}
}
}
- if (cache) {
- if (QQmlPropertyData *pd = lookupQmlCompliantProperty(cache, *name)) {
- const unsigned baseTemp = _block->newTemp();
- move(_block->TEMP(baseTemp), base);
- return _block->QML_QOBJECT_PROPERTY(_block->TEMP(baseTemp), name, pd);
+ if (property) {
+ // Enums cannot be mapped to IR types, they need to go through the run-time handling
+ // of accepting strings that will then be converted to the right values.
+ if (property->isEnum())
+ return V4IR::VarType;
+
+ switch (property->propType) {
+ case QMetaType::Bool: result = V4IR::BoolType; break;
+ case QMetaType::Int: result = V4IR::SInt32Type; break;
+ case QMetaType::Double: result = V4IR::DoubleType; break;
+ case QMetaType::QString: result = V4IR::StringType; break;
+ default:
+ if (property->isQObject()) {
+ if (QQmlPropertyCache *cache = qmlEngine->propertyCacheForType(property->propType)) {
+ initMetaObjectResolver(resolver, cache);
+ return V4IR::QObjectType;
+ }
+ } else if (QQmlValueType *valueType = QQmlValueTypeFactory::valueType(property->propType)) {
+ if (QQmlPropertyCache *cache = qmlEngine->cache(valueType->metaObject())) {
+ initMetaObjectResolver(resolver, cache);
+ resolver->flags |= ResolveTypeInformationOnly;
+ return V4IR::QObjectType;
+ }
+ }
+ break;
}
}
}
- return QQmlJS::Codegen::member(base, name);
+ resolver->clear();
+ return result;
+}
+
+static void initMetaObjectResolver(V4IR::MemberExpressionResolver *resolver, QQmlPropertyCache *metaObject)
+{
+ resolver->resolveMember = &resolveMetaObjectProperty;
+ resolver->data = metaObject;
+ resolver->flags = 0;
+ resolver->isQObjectResolver = true;
+}
+
+void JSCodeGen::beginFunctionBodyHook()
+{
+ _contextObjectTemp = _block->newTemp();
+ _scopeObjectTemp = _block->newTemp();
+ _importedScriptsTemp = _block->newTemp();
+ _idArrayTemp = _block->newTemp();
+
+ V4IR::Temp *temp = _block->TEMP(_contextObjectTemp);
+ initMetaObjectResolver(&temp->memberResolver, _contextObject);
+ move(temp, _block->NAME(V4IR::Name::builtin_qml_context_object, 0, 0));
+
+ temp = _block->TEMP(_scopeObjectTemp);
+ initMetaObjectResolver(&temp->memberResolver, _scopeObject);
+ move(temp, _block->NAME(V4IR::Name::builtin_qml_scope_object, 0, 0));
+
+ move(_block->TEMP(_importedScriptsTemp), _block->NAME(V4IR::Name::builtin_qml_imported_scripts_object, 0, 0));
+ move(_block->TEMP(_idArrayTemp), _block->NAME(V4IR::Name::builtin_qml_id_array, 0, 0));
}
V4IR::Expr *JSCodeGen::fallbackNameLookup(const QString &name, int line, int col)
{
+ if (_disableAcceleratedLookups)
+ return 0;
+
+ Q_UNUSED(line)
+ Q_UNUSED(col)
// Implement QML lookup semantics in the current file context.
//
// Note: We do not check if properties of the qml scope object or context object
@@ -1378,17 +1555,42 @@ V4IR::Expr *JSCodeGen::fallbackNameLookup(const QString &name, int line, int col
foreach (const IdMapping &mapping, _idObjects)
if (name == mapping.name) {
_function->idObjectDependencies.insert(mapping.idIndex);
- return _block->QML_CONTEXT_MEMBER(_block->NAME(V4IR::Name::builtin_qml_id_scope, line, col),
- _function->newString(mapping.name), mapping.idIndex);
+ V4IR::Expr *s = subscript(_block->TEMP(_idArrayTemp), _block->CONST(V4IR::SInt32Type, mapping.idIndex));
+ V4IR::Temp *result = _block->TEMP(_block->newTemp());
+ _block->MOVE(result, s);
+ result = _block->TEMP(result->index);
+ initMetaObjectResolver(&result->memberResolver, mapping.type);
+ result->memberResolver.flags |= AllPropertiesAreFinal;
+ result->isReadOnly = true; // don't allow use as lvalue
+ return result;
}
{
QQmlTypeNameCache::Result r = imports->query(name);
if (r.isValid()) {
- if (r.scriptIndex != -1)
- return subscript(_block->NAME(V4IR::Name::builtin_qml_imported_scripts_object, line, col), _block->CONST(V4IR::NumberType, r.scriptIndex));
- else
- return 0; // TODO: We can't do fast lookup for these yet.
+ if (r.scriptIndex != -1) {
+ return subscript(_block->TEMP(_importedScriptsTemp), _block->CONST(V4IR::SInt32Type, r.scriptIndex));
+ } else if (r.type) {
+ V4IR::Name *typeName = _block->NAME(name, line, col);
+ // Make sure the run-time loads this through the more efficient singleton getter.
+ typeName->qmlSingleton = r.type->isSingleton();
+ typeName->freeOfSideEffects = true;
+
+ V4IR::Temp *result = _block->TEMP(_block->newTemp());
+ initQmlTypeResolver(&result->memberResolver, r.type);
+
+ _block->MOVE(result, typeName);
+ return _block->TEMP(result->index);
+ } else {
+ Q_ASSERT(r.importNamespace);
+ V4IR::Name *namespaceName = _block->NAME(name, line, col);
+ namespaceName->freeOfSideEffects = true;
+ V4IR::Temp *result = _block->TEMP(_block->newTemp());
+ initImportNamespaceResolver(&result->memberResolver, imports, r.importNamespace);
+
+ _block->MOVE(result, namespaceName);
+ return _block->TEMP(result->index);
+ }
}
}
@@ -1398,11 +1600,9 @@ V4IR::Expr *JSCodeGen::fallbackNameLookup(const QString &name, int line, int col
if (propertyExistsButForceNameLookup)
return 0;
if (pd) {
- if (!pd->isConstant())
- _function->scopeObjectDependencies.insert(pd);
- int base = _block->newTemp();
- move(_block->TEMP(base), _block->NAME(V4IR::Name::builtin_qml_scope_object, line, col));
- return _block->QML_QOBJECT_PROPERTY(_block->TEMP(base), _function->newString(name), pd);
+ V4IR::Temp *base = _block->TEMP(_scopeObjectTemp);
+ initMetaObjectResolver(&base->memberResolver, _scopeObject);
+ return _block->MEMBER(base, _function->newString(name), pd, V4IR::Member::MemberOfQmlScopeObject);
}
}
@@ -1412,11 +1612,9 @@ V4IR::Expr *JSCodeGen::fallbackNameLookup(const QString &name, int line, int col
if (propertyExistsButForceNameLookup)
return 0;
if (pd) {
- if (!pd->isConstant())
- _function->contextObjectDependencies.insert(pd);
- int base = _block->newTemp();
- move(_block->TEMP(base), _block->NAME(V4IR::Name::builtin_qml_context_object, line, col));
- return _block->QML_QOBJECT_PROPERTY(_block->TEMP(base), _function->newString(name), pd);
+ V4IR::Temp *base = _block->TEMP(_contextObjectTemp);
+ initMetaObjectResolver(&base->memberResolver, _contextObject);
+ return _block->MEMBER(base, _function->newString(name), pd, V4IR::Member::MemberOfQmlContextObject);
}
}
@@ -1556,7 +1754,7 @@ bool SignalHandlerConverter::convertSignalHandlerExpressionsToFunctionDeclaratio
if (paramList)
paramList = paramList->finish();
- AST::Statement *statement = static_cast<AST::Statement*>(parsedQML->functions[binding->value.compiledScriptIndex]);
+ AST::Statement *statement = static_cast<AST::Statement*>(parsedQML->functions[binding->value.compiledScriptIndex].node);
AST::SourceElement *sourceElement = new (pool) AST::StatementSourceElement(statement);
AST::SourceElements *elements = new (pool) AST::SourceElements(sourceElement);
elements = elements->finish();
diff --git a/src/qml/compiler/qqmlcodegenerator_p.h b/src/qml/compiler/qqmlcodegenerator_p.h
index a5fec65111..0a0e4f2d5b 100644
--- a/src/qml/compiler/qqmlcodegenerator_p.h
+++ b/src/qml/compiler/qqmlcodegenerator_p.h
@@ -166,6 +166,20 @@ struct Pragma
QV4::CompiledData::Location location;
};
+struct CompiledFunctionOrExpression
+{
+ CompiledFunctionOrExpression()
+ : disableAcceleratedLookups(false)
+ {}
+ CompiledFunctionOrExpression(AST::Node *n)
+ : node(n)
+ , disableAcceleratedLookups(false)
+ {}
+ AST::Node *node; // FunctionDeclaration, Statement or Expression
+ QString name;
+ bool disableAcceleratedLookups;
+};
+
struct ParsedQML
{
ParsedQML(bool debugMode)
@@ -180,7 +194,7 @@ struct ParsedQML
AST::UiProgram *program;
int indexOfRootObject;
QList<QmlObject*> objects;
- QList<AST::Node*> functions; // FunctionDeclaration, Statement or Expression
+ QList<CompiledFunctionOrExpression> functions;
QV4::Compiler::JSUnitGenerator jsGenerator;
QV4::CompiledData::TypeReferenceMap typeReferences;
@@ -269,7 +283,7 @@ public:
QList<QV4::CompiledData::Import*> _imports;
QList<Pragma*> _pragmas;
QList<QmlObject*> _objects;
- QList<AST::Node*> _functions;
+ QList<CompiledFunctionOrExpression> _functions;
QV4::CompiledData::TypeReferenceMap _typeReferences;
@@ -347,7 +361,7 @@ private:
struct Q_QML_EXPORT JSCodeGen : public QQmlJS::Codegen
{
- JSCodeGen(QQmlEnginePrivate *enginePrivate, const QString &fileName, const QString &sourceCode, V4IR::Module *jsModule,
+ JSCodeGen(const QString &fileName, const QString &sourceCode, V4IR::Module *jsModule,
QQmlJS::Engine *jsEngine, AST::UiProgram *qmlRoot, QQmlTypeNameCache *imports);
struct IdMapping
@@ -362,26 +376,28 @@ struct Q_QML_EXPORT JSCodeGen : public QQmlJS::Codegen
void beginObjectScope(QQmlPropertyCache *scopeObject);
// Returns mapping from input functions to index in V4IR::Module::functions / compiledData->runtimeFunctions
- QVector<int> generateJSCodeForFunctionsAndBindings(const QList<AST::Node*> &functions, const QHash<int, QString> &functionNames);
-
- // Resolve QObject members with the help of QQmlEngine's meta type registry
- virtual V4IR::Expr *member(V4IR::Expr *base, const QString *name);
+ QVector<int> generateJSCodeForFunctionsAndBindings(const QList<CompiledFunctionOrExpression> &functions);
protected:
+ virtual void beginFunctionBodyHook();
virtual V4IR::Expr *fallbackNameLookup(const QString &name, int line, int col);
private:
QQmlPropertyData *lookupQmlCompliantProperty(QQmlPropertyCache *cache, const QString &name, bool *propertyExistsButForceNameLookup = 0);
- QQmlEnginePrivate *engine;
QString sourceCode;
QQmlJS::Engine *jsEngine; // needed for memory pool
AST::UiProgram *qmlRoot;
QQmlTypeNameCache *imports;
+ bool _disableAcceleratedLookups;
ObjectIdMapping _idObjects;
QQmlPropertyCache *_contextObject;
QQmlPropertyCache *_scopeObject;
+ int _contextObjectTemp;
+ int _scopeObjectTemp;
+ int _importedScriptsTemp;
+ int _idArrayTemp;
};
} // namespace QtQml
diff --git a/src/qml/compiler/qv4codegen.cpp b/src/qml/compiler/qv4codegen.cpp
index 893abc9659..a920f1b419 100644
--- a/src/qml/compiler/qv4codegen.cpp
+++ b/src/qml/compiler/qv4codegen.cpp
@@ -1632,7 +1632,7 @@ bool Codegen::visit(ObjectLiteral *ast)
if (!valueMap.isEmpty()) {
V4IR::ExprList *current;
for (QMap<QString, ObjectPropertyValue>::iterator it = valueMap.begin(); it != valueMap.end(); ) {
- if (QV4::String(0, it.key()).asArrayIndex() != UINT_MAX) {
+ if (QV4::String::toArrayIndex(it.key()) != UINT_MAX) {
++it;
continue;
}
@@ -2050,6 +2050,8 @@ int Codegen::defineFunction(const QString &name, AST::Node *ast,
ast->firstSourceLocation().startLine, ast->firstSourceLocation().startColumn), 0));
}
+ beginFunctionBodyHook();
+
sourceElements(body);
_function->insertBasicBlock(_exitBlock);
diff --git a/src/qml/compiler/qv4codegen_p.h b/src/qml/compiler/qv4codegen_p.h
index de22e8904b..32f1f1bfd4 100644
--- a/src/qml/compiler/qv4codegen_p.h
+++ b/src/qml/compiler/qv4codegen_p.h
@@ -293,7 +293,7 @@ protected:
_exceptionHandlers.pop();
}
- virtual V4IR::Expr *member(V4IR::Expr *base, const QString *name); // Re-implemented by QML to resolve QObject property members
+ V4IR::Expr *member(V4IR::Expr *base, const QString *name);
V4IR::Expr *subscript(V4IR::Expr *base, V4IR::Expr *index);
V4IR::Expr *argument(V4IR::Expr *expr);
V4IR::Expr *reference(V4IR::Expr *expr);
@@ -330,6 +330,7 @@ protected:
V4IR::Expr *identifier(const QString &name, int line = 0, int col = 0);
// Hook provided to implement QML lookup semantics
virtual V4IR::Expr *fallbackNameLookup(const QString &name, int line, int col);
+ virtual void beginFunctionBodyHook() {}
// nodes
virtual bool visit(AST::ArgumentList *ast);
diff --git a/src/qml/compiler/qv4compiler.cpp b/src/qml/compiler/qv4compiler.cpp
index cb17b86702..9041b04837 100644
--- a/src/qml/compiler/qv4compiler.cpp
+++ b/src/qml/compiler/qv4compiler.cpp
@@ -170,20 +170,6 @@ QV4::CompiledData::Unit *QV4::Compiler::JSUnitGenerator::generateUnit(int *total
registerString(*f->formals.at(i));
for (int i = 0; i < f->locals.size(); ++i)
registerString(*f->locals.at(i));
-
- if (f->hasQmlDependencies()) {
- QSet<int> idObjectDeps = f->idObjectDependencies;
- QSet<QQmlPropertyData*> contextPropertyDeps = f->contextObjectDependencies;
- QSet<QQmlPropertyData*> scopePropertyDeps = f->scopeObjectDependencies;
-
- if (!idObjectDeps.isEmpty())
- qmlIdObjectDependenciesPerFunction.insert(f, idObjectDeps);
- if (!contextPropertyDeps.isEmpty())
- qmlContextPropertyDependenciesPerFunction.insert(f, contextPropertyDeps);
- if (!scopePropertyDeps.isEmpty())
- qmlScopePropertyDependenciesPerFunction.insert(f, scopePropertyDeps);
- }
-
}
int unitSize = QV4::CompiledData::Unit::calculateSize(headerSize, strings.size(), irModule->functions.size(), regexps.size(),
@@ -199,23 +185,8 @@ QV4::CompiledData::Unit *QV4::Compiler::JSUnitGenerator::generateUnit(int *total
if (lineNumberMapping != lineNumberMappingsPerFunction.constEnd())
lineNumberMappingCount = lineNumberMapping->count() / 2;
- int qmlIdDepsCount = 0;
- int qmlPropertyDepsCount = 0;
-
- if (f->hasQmlDependencies()) {
- IdDependencyHash::ConstIterator idIt = qmlIdObjectDependenciesPerFunction.find(f);
- if (idIt != qmlIdObjectDependenciesPerFunction.constEnd())
- qmlIdDepsCount += idIt->count();
-
- PropertyDependencyHash::ConstIterator it = qmlContextPropertyDependenciesPerFunction.find(f);
- if (it != qmlContextPropertyDependenciesPerFunction.constEnd())
- qmlPropertyDepsCount += it->count();
-
- it = qmlScopePropertyDependenciesPerFunction.find(f);
- if (it != qmlScopePropertyDependenciesPerFunction.constEnd())
- qmlPropertyDepsCount += it->count();
- }
-
+ 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(), lineNumberMappingCount, qmlIdDepsCount, qmlPropertyDepsCount);
}
@@ -353,32 +324,22 @@ int QV4::Compiler::JSUnitGenerator::writeFunction(char *f, int index, QQmlJS::V4
function->nDependingContextProperties = 0;
function->nDependingScopeProperties = 0;
- QSet<int> qmlIdObjectDeps;
- QSet<QQmlPropertyData*> qmlContextPropertyDeps;
- QSet<QQmlPropertyData*> qmlScopePropertyDeps;
-
- if (irFunction->hasQmlDependencies()) {
- qmlIdObjectDeps = qmlIdObjectDependenciesPerFunction.value(irFunction);
- qmlContextPropertyDeps = qmlContextPropertyDependenciesPerFunction.value(irFunction);
- qmlScopePropertyDeps = qmlScopePropertyDependenciesPerFunction.value(irFunction);
-
- if (!qmlIdObjectDeps.isEmpty()) {
- function->nDependingIdObjects = qmlIdObjectDeps.count();
- function->dependingIdObjectsOffset = currentOffset;
- currentOffset += function->nDependingIdObjects * sizeof(quint32);
- }
-
- if (!qmlContextPropertyDeps.isEmpty()) {
- function->nDependingContextProperties = qmlContextPropertyDeps.count();
- function->dependingContextPropertiesOffset = currentOffset;
- currentOffset += function->nDependingContextProperties * sizeof(quint32) * 2;
- }
-
- if (!qmlScopePropertyDeps.isEmpty()) {
- function->nDependingScopeProperties = qmlScopePropertyDeps.count();
- function->dependingScopePropertiesOffset = currentOffset;
- currentOffset += function->nDependingScopeProperties * sizeof(quint32) * 2;
- }
+ if (!irFunction->idObjectDependencies.isEmpty()) {
+ function->nDependingIdObjects = irFunction->idObjectDependencies.count();
+ function->dependingIdObjectsOffset = currentOffset;
+ currentOffset += function->nDependingIdObjects * sizeof(quint32);
+ }
+
+ if (!irFunction->contextObjectPropertyDependencies.isEmpty()) {
+ function->nDependingContextProperties = irFunction->contextObjectPropertyDependencies.count();
+ function->dependingContextPropertiesOffset = currentOffset;
+ currentOffset += function->nDependingContextProperties * sizeof(quint32) * 2;
+ }
+
+ if (!irFunction->scopeObjectPropertyDependencies.isEmpty()) {
+ function->nDependingScopeProperties = irFunction->scopeObjectPropertyDependencies.count();
+ function->dependingScopePropertiesOffset = currentOffset;
+ currentOffset += function->nDependingScopeProperties * sizeof(quint32) * 2;
}
function->location.line = irFunction->line;
@@ -407,19 +368,21 @@ int QV4::Compiler::JSUnitGenerator::writeFunction(char *f, int index, QQmlJS::V4
// write QML dependencies
quint32 *writtenDeps = (quint32 *)(f + function->dependingIdObjectsOffset);
- foreach (int id, qmlIdObjectDeps)
+ foreach (int id, irFunction->idObjectDependencies)
*writtenDeps++ = id;
writtenDeps = (quint32 *)(f + function->dependingContextPropertiesOffset);
- foreach (QQmlPropertyData *property, qmlContextPropertyDeps) {
- *writtenDeps++ = property->coreIndex;
- *writtenDeps++ = property->notifyIndex;
+ for (QQmlJS::V4IR::PropertyDependencyMap::ConstIterator property = irFunction->contextObjectPropertyDependencies.constBegin(), end = irFunction->contextObjectPropertyDependencies.constEnd();
+ property != end; ++property) {
+ *writtenDeps++ = property.key(); // property index
+ *writtenDeps++ = property.value(); // notify index
}
writtenDeps = (quint32 *)(f + function->dependingScopePropertiesOffset);
- foreach (QQmlPropertyData *property, qmlScopePropertyDeps) {
- *writtenDeps++ = property->coreIndex;
- *writtenDeps++ = property->notifyIndex;
+ for (QQmlJS::V4IR::PropertyDependencyMap::ConstIterator property = irFunction->scopeObjectPropertyDependencies.constBegin(), end = irFunction->scopeObjectPropertyDependencies.constEnd();
+ property != end; ++property) {
+ *writtenDeps++ = property.key(); // property index
+ *writtenDeps++ = property.value(); // notify index
}
return CompiledData::Function::calculateSize(function->nFormals, function->nLocals, function->nInnerFunctions, function->nLineNumberMappingEntries,
diff --git a/src/qml/compiler/qv4compiler_p.h b/src/qml/compiler/qv4compiler_p.h
index 6338babb5a..1596fcb622 100644
--- a/src/qml/compiler/qv4compiler_p.h
+++ b/src/qml/compiler/qv4compiler_p.h
@@ -94,13 +94,6 @@ struct Q_QML_EXPORT JSUnitGenerator {
QList<QList<CompiledData::JSClassMember> > jsClasses;
uint jsClassDataSize;
uint headerSize;
-
- typedef QHash<QQmlJS::V4IR::Function *, QSet<int> > IdDependencyHash;
- IdDependencyHash qmlIdObjectDependenciesPerFunction;
-
- typedef QHash<QQmlJS::V4IR::Function *, QSet<QQmlPropertyData*> > PropertyDependencyHash;
- PropertyDependencyHash qmlContextPropertyDependenciesPerFunction;
- PropertyDependencyHash qmlScopePropertyDependenciesPerFunction;
};
}
diff --git a/src/qml/compiler/qv4instr_moth_p.h b/src/qml/compiler/qv4instr_moth_p.h
index 9baf7f89ca..5b5667abb4 100644
--- a/src/qml/compiler/qv4instr_moth_p.h
+++ b/src/qml/compiler/qv4instr_moth_p.h
@@ -67,6 +67,7 @@ QT_BEGIN_NAMESPACE
F(SetLookup, setLookup) \
F(StoreQObjectProperty, storeQObjectProperty) \
F(LoadQObjectProperty, loadQObjectProperty) \
+ F(LoadAttachedQObjectProperty, loadAttachedQObjectProperty) \
F(Push, push) \
F(CallValue, callValue) \
F(CallProperty, callProperty) \
@@ -98,6 +99,7 @@ QT_BEGIN_NAMESPACE
F(CallBuiltinConvertThisToObject, callBuiltinConvertThisToObject) \
F(CreateValue, createValue) \
F(CreateProperty, createProperty) \
+ F(ConstructPropertyLookup, constructPropertyLookup) \
F(CreateActivationProperty, createActivationProperty) \
F(ConstructGlobalLookup, constructGlobalLookup) \
F(Jump, jump) \
@@ -125,10 +127,11 @@ QT_BEGIN_NAMESPACE
F(MulNumberParams, mulNumberParams) \
F(SubNumberParams, subNumberParams) \
F(LoadThis, loadThis) \
- F(LoadQmlIdObject, loadQmlIdObject) \
+ F(LoadQmlIdArray, loadQmlIdArray) \
F(LoadQmlImportedScripts, loadQmlImportedScripts) \
F(LoadQmlContextObject, loadQmlContextObject) \
- F(LoadQmlScopeObject, loadQmlScopeObject)
+ F(LoadQmlScopeObject, loadQmlScopeObject) \
+ F(LoadQmlSingleton, loadQmlSingleton)
#if defined(Q_CC_GNU) && (!defined(Q_CC_INTEL) || __INTEL_COMPILER >= 1200)
# define MOTH_THREADED_INTERPRETER
@@ -286,8 +289,15 @@ union Instr
int propertyIndex;
Param base;
Param result;
+ int attachedPropertiesId;
bool captureRequired;
};
+ struct instr_loadAttachedQObjectProperty {
+ MOTH_INSTR_HEADER
+ int propertyIndex;
+ Param result;
+ int attachedPropertiesId;
+ };
struct instr_storeProperty {
MOTH_INSTR_HEADER
int name;
@@ -491,6 +501,14 @@ union Instr
Param base;
Param result;
};
+ struct instr_constructPropertyLookup {
+ MOTH_INSTR_HEADER
+ int index;
+ quint32 argc;
+ quint32 callData;
+ Param base;
+ Param result;
+ };
struct instr_createActivationProperty {
MOTH_INSTR_HEADER
int name;
@@ -645,10 +663,9 @@ union Instr
MOTH_INSTR_HEADER
Param result;
};
- struct instr_loadQmlIdObject {
+ struct instr_loadQmlIdArray {
MOTH_INSTR_HEADER
Param result;
- int id;
};
struct instr_loadQmlImportedScripts {
MOTH_INSTR_HEADER
@@ -662,6 +679,11 @@ union Instr
MOTH_INSTR_HEADER
Param result;
};
+ struct instr_loadQmlSingleton {
+ MOTH_INSTR_HEADER
+ Param result;
+ int name;
+ };
instr_common common;
instr_ret ret;
@@ -678,6 +700,7 @@ union Instr
instr_loadProperty loadProperty;
instr_getLookup getLookup;
instr_loadQObjectProperty loadQObjectProperty;
+ instr_loadAttachedQObjectProperty loadAttachedQObjectProperty;
instr_storeProperty storeProperty;
instr_setLookup setLookup;
instr_storeQObjectProperty storeQObjectProperty;
@@ -712,6 +735,7 @@ union Instr
instr_callBuiltinConvertThisToObject callBuiltinConvertThisToObject;
instr_createValue createValue;
instr_createProperty createProperty;
+ instr_constructPropertyLookup constructPropertyLookup;
instr_createActivationProperty createActivationProperty;
instr_constructGlobalLookup constructGlobalLookup;
instr_jump jump;
@@ -739,10 +763,11 @@ union Instr
instr_mulNumberParams mulNumberParams;
instr_subNumberParams subNumberParams;
instr_loadThis loadThis;
- instr_loadQmlIdObject loadQmlIdObject;
+ instr_loadQmlIdArray loadQmlIdArray;
instr_loadQmlImportedScripts loadQmlImportedScripts;
instr_loadQmlContextObject loadQmlContextObject;
instr_loadQmlScopeObject loadQmlScopeObject;
+ instr_loadQmlSingleton loadQmlSingleton;
static int size(Type type);
};
diff --git a/src/qml/compiler/qv4isel_masm.cpp b/src/qml/compiler/qv4isel_masm.cpp
index a999dd4da1..35097bae49 100644
--- a/src/qml/compiler/qv4isel_masm.cpp
+++ b/src/qml/compiler/qv4isel_masm.cpp
@@ -68,7 +68,7 @@ using namespace QV4;
CompilationUnit::~CompilationUnit()
{
foreach (Function *f, runtimeFunctions)
- engine->allFunctions.remove(reinterpret_cast<quintptr>(f->codePtr));
+ engine->allFunctions.remove(reinterpret_cast<quintptr>(f->code));
}
void CompilationUnit::linkBackendToEngine(ExecutionEngine *engine)
@@ -85,7 +85,7 @@ void CompilationUnit::linkBackendToEngine(ExecutionEngine *engine)
}
foreach (Function *f, runtimeFunctions)
- engine->allFunctions.insert(reinterpret_cast<quintptr>(f->codePtr), f);
+ engine->allFunctions.insert(reinterpret_cast<quintptr>(f->code), f);
}
QV4::ExecutableAllocator::ChunkOfPages *CompilationUnit::chunkForFunction(int functionIndex)
@@ -439,15 +439,6 @@ static void printDisassembledOutputWithCalls(const char* output, const QHash<voi
}
#endif
-void Assembler::recordLineNumber(int lineNumber)
-{
- CodeLineNumerMapping mapping;
- mapping.location = label();
- mapping.lineNumber = lineNumber;
- codeLineNumberMappings << mapping;
-}
-
-
JSC::MacroAssemblerCodeRef Assembler::link(int *codeSize)
{
Label endOfCode = label();
@@ -467,14 +458,6 @@ JSC::MacroAssemblerCodeRef Assembler::link(int *codeSize)
JSC::JSGlobalData dummy(_executableAllocator);
JSC::LinkBuffer linkBuffer(dummy, this, 0);
- QVector<uint> lineNumberMapping(codeLineNumberMappings.count() * 2);
-
- for (int i = 0; i < codeLineNumberMappings.count(); ++i) {
- lineNumberMapping[i * 2] = linkBuffer.offsetOf(codeLineNumberMappings.at(i).location);
- lineNumberMapping[i * 2 + 1] = codeLineNumberMappings.at(i).lineNumber;
- }
- _isel->jsUnitGenerator()->registerLineNumberMapping(_function, lineNumberMapping);
-
QHash<void*, const char*> functions;
foreach (CallToLink ctl, _callsToLink) {
linkBuffer.link(ctl.call, ctl.externalFunction);
@@ -556,10 +539,11 @@ JSC::MacroAssemblerCodeRef Assembler::link(int *codeSize)
return codeRef;
}
-InstructionSelection::InstructionSelection(QV4::ExecutableAllocator *execAllocator, V4IR::Module *module, Compiler::JSUnitGenerator *jsGenerator)
+InstructionSelection::InstructionSelection(QQmlEnginePrivate *qmlEngine, QV4::ExecutableAllocator *execAllocator, V4IR::Module *module, Compiler::JSUnitGenerator *jsGenerator)
: EvalInstructionSelection(execAllocator, module, jsGenerator)
, _block(0)
, _as(0)
+ , qmlEngine(qmlEngine)
{
compilationUnit = new CompilationUnit;
compilationUnit->codeRefs.resize(module->functions.size());
@@ -578,7 +562,7 @@ void InstructionSelection::run(int functionIndex)
qSwap(_function, function);
V4IR::Optimizer opt(_function);
- opt.run();
+ opt.run(qmlEngine);
#if (CPU(X86_64) && (OS(MAC_OS_X) || OS(LINUX))) || (CPU(X86) && OS(LINUX))
static const bool withRegisterAllocator = qgetenv("QV4_NO_REGALLOC").isEmpty();
@@ -642,9 +626,9 @@ void InstructionSelection::run(int functionIndex)
foreach (V4IR::Stmt *s, _block->statements) {
if (s->location.isValid()) {
- _as->recordLineNumber(s->location.startLine);
if (int(s->location.startLine) != lastLine) {
- _as->saveInstructionPointer(Assembler::ScratchRegister);
+ Assembler::Address lineAddr(Assembler::ContextRegister, qOffsetOf(QV4::ExecutionContext, lineNumber));
+ _as->store32(Assembler::TrustedImm32(s->location.startLine), lineAddr);
lastLine = s->location.startLine;
}
}
@@ -896,9 +880,9 @@ void InstructionSelection::loadThisObject(V4IR::Temp *temp)
#endif
}
-void InstructionSelection::loadQmlIdObject(int id, V4IR::Temp *temp)
+void InstructionSelection::loadQmlIdArray(V4IR::Temp *temp)
{
- generateFunctionCall(temp, __qmljs_get_id_object, Assembler::ContextRegister, Assembler::TrustedImm32(id));
+ generateFunctionCall(temp, __qmljs_get_id_array, Assembler::ContextRegister);
}
void InstructionSelection::loadQmlImportedScripts(V4IR::Temp *temp)
@@ -916,6 +900,11 @@ void InstructionSelection::loadQmlScopeObject(V4IR::Temp *temp)
generateFunctionCall(temp, __qmljs_get_scope_object, Assembler::ContextRegister);
}
+void InstructionSelection::loadQmlSingleton(const QString &name, V4IR::Temp *temp)
+{
+ generateFunctionCall(temp, __qmljs_get_qml_singleton, Assembler::ContextRegister, Assembler::PointerToString(name));
+}
+
void InstructionSelection::loadConst(V4IR::Const *sourceConst, V4IR::Temp *targetTemp)
{
if (targetTemp->kind == V4IR::Temp::PhysicalRegister) {
@@ -994,10 +983,13 @@ void InstructionSelection::getProperty(V4IR::Expr *base, const QString &name, V4
}
}
-void InstructionSelection::getQObjectProperty(V4IR::Expr *base, int propertyIndex, bool captureRequired, V4IR::Temp *target)
+void InstructionSelection::getQObjectProperty(V4IR::Expr *base, int propertyIndex, bool captureRequired, int attachedPropertiesId, V4IR::Temp *target)
{
- generateFunctionCall(target, __qmljs_get_qobject_property, Assembler::ContextRegister, Assembler::PointerToValue(base), Assembler::TrustedImm32(propertyIndex),
- Assembler::TrustedImm32(captureRequired));
+ if (attachedPropertiesId != 0)
+ generateFunctionCall(target, __qmljs_get_attached_property, Assembler::ContextRegister, Assembler::TrustedImm32(attachedPropertiesId), Assembler::TrustedImm32(propertyIndex));
+ else
+ generateFunctionCall(target, __qmljs_get_qobject_property, Assembler::ContextRegister, Assembler::PointerToValue(base), Assembler::TrustedImm32(propertyIndex),
+ Assembler::TrustedImm32(captureRequired));
}
void InstructionSelection::setProperty(V4IR::Expr *source, V4IR::Expr *targetBase,
@@ -1786,9 +1778,18 @@ void InstructionSelection::constructActivationProperty(V4IR::Name *func, V4IR::E
void InstructionSelection::constructProperty(V4IR::Temp *base, const QString &name, V4IR::ExprList *args, V4IR::Temp *result)
{
- prepareCallData(args, 0);
+ prepareCallData(args, base);
+ if (useFastLookups) {
+ uint index = registerGetterLookup(name);
+ generateFunctionCall(result, __qmljs_construct_property_lookup,
+ Assembler::ContextRegister,
+ Assembler::TrustedImm32(index),
+ baseAddressForCallData());
+ return;
+ }
+
generateFunctionCall(result, __qmljs_construct_property, Assembler::ContextRegister,
- Assembler::Reference(base), Assembler::PointerToString(name),
+ Assembler::PointerToString(name),
baseAddressForCallData());
}
@@ -2493,11 +2494,10 @@ bool InstructionSelection::int32Binop(V4IR::AluOp oper, V4IR::Expr *leftSource,
else
targetReg = Assembler::ReturnValueRegister;
- _as->move(_as->toInt32Register(leftSource, targetReg), targetReg);
- Assembler::RegisterID rReg = _as->toInt32Register(rightSource, Assembler::ScratchRegister);
- _as->and32(rReg, targetReg);
- if (Assembler::ReturnValueRegister == targetReg)
- _as->storeInt32(targetReg, target);
+ _as->and32(_as->toInt32Register(leftSource, targetReg),
+ _as->toInt32Register(rightSource, Assembler::ScratchRegister),
+ targetReg);
+ _as->storeInt32(targetReg, target);
} return true;
case V4IR::OpBitOr: {
Q_ASSERT(rightSource->type == V4IR::SInt32Type);
@@ -2514,11 +2514,10 @@ bool InstructionSelection::int32Binop(V4IR::AluOp oper, V4IR::Expr *leftSource,
else
targetReg = Assembler::ReturnValueRegister;
- _as->move(_as->toInt32Register(leftSource, targetReg), targetReg);
- Assembler::RegisterID rReg = _as->toInt32Register(rightSource, Assembler::ScratchRegister);
- _as->or32(rReg, targetReg);
- if (Assembler::ReturnValueRegister == targetReg)
- _as->storeInt32(targetReg, target);
+ _as->or32(_as->toInt32Register(leftSource, targetReg),
+ _as->toInt32Register(rightSource, Assembler::ScratchRegister),
+ targetReg);
+ _as->storeInt32(targetReg, target);
} return true;
case V4IR::OpBitXor: {
Q_ASSERT(rightSource->type == V4IR::SInt32Type);
@@ -2535,32 +2534,41 @@ bool InstructionSelection::int32Binop(V4IR::AluOp oper, V4IR::Expr *leftSource,
else
targetReg = Assembler::ReturnValueRegister;
- _as->move(_as->toInt32Register(leftSource, targetReg), targetReg);
- Assembler::RegisterID rReg = _as->toInt32Register(rightSource, Assembler::ScratchRegister);
- _as->xor32(rReg, targetReg);
- if (Assembler::ReturnValueRegister == targetReg)
- _as->storeInt32(targetReg, target);
+ _as->xor32(_as->toInt32Register(leftSource, targetReg),
+ _as->toInt32Register(rightSource, Assembler::ScratchRegister),
+ targetReg);
+ _as->storeInt32(targetReg, target);
} return true;
- case V4IR::OpLShift:
+ case V4IR::OpLShift: {
Q_ASSERT(rightSource->type == V4IR::SInt32Type);
- _as->move(_as->toInt32Register(leftSource, Assembler::ReturnValueRegister),
- Assembler::ReturnValueRegister);
+ Assembler::RegisterID targetReg;
+ if (target->kind == V4IR::Temp::PhysicalRegister)
+ targetReg = (Assembler::RegisterID) target->index;
+ else
+ targetReg = Assembler::ReturnValueRegister;
+
_as->move(_as->toInt32Register(rightSource, Assembler::ScratchRegister),
Assembler::ScratchRegister);
_as->and32(Assembler::TrustedImm32(0x1f), Assembler::ScratchRegister); // TODO: for constants, do this in the IR
- _as->lshift32(Assembler::ScratchRegister, Assembler::ReturnValueRegister);
+ _as->lshift32(_as->toInt32Register(leftSource, targetReg), Assembler::ScratchRegister,
+ Assembler::ReturnValueRegister);
_as->storeInt32(Assembler::ReturnValueRegister, target);
- return true;
- case V4IR::OpRShift:
+ } return true;
+ case V4IR::OpRShift: {
Q_ASSERT(rightSource->type == V4IR::SInt32Type);
- _as->move(_as->toInt32Register(leftSource, Assembler::ReturnValueRegister),
- Assembler::ReturnValueRegister);
+ Assembler::RegisterID targetReg;
+ if (target->kind == V4IR::Temp::PhysicalRegister)
+ targetReg = (Assembler::RegisterID) target->index;
+ else
+ targetReg = Assembler::ReturnValueRegister;
+
_as->move(_as->toInt32Register(rightSource, Assembler::ScratchRegister),
Assembler::ScratchRegister);
_as->and32(Assembler::TrustedImm32(0x1f), Assembler::ScratchRegister); // TODO: for constants, do this in the IR
- _as->rshift32(Assembler::ScratchRegister, Assembler::ReturnValueRegister);
+ _as->rshift32(_as->toInt32Register(leftSource, targetReg), Assembler::ScratchRegister,
+ Assembler::ReturnValueRegister);
_as->storeInt32(Assembler::ReturnValueRegister, target);
- return true;
+ } return true;
case V4IR::OpURShift:
Q_ASSERT(rightSource->type == V4IR::SInt32Type);
_as->move(_as->toInt32Register(leftSource, Assembler::ReturnValueRegister),
@@ -2571,6 +2579,58 @@ bool InstructionSelection::int32Binop(V4IR::AluOp oper, V4IR::Expr *leftSource,
_as->urshift32(Assembler::ScratchRegister, Assembler::ReturnValueRegister);
_as->storeUInt32(Assembler::ReturnValueRegister, target);
return true;
+ case V4IR::OpAdd: {
+ Q_ASSERT(rightSource->type == V4IR::SInt32Type);
+
+ Assembler::RegisterID targetReg;
+ if (target->kind == V4IR::Temp::PhysicalRegister)
+ targetReg = (Assembler::RegisterID) target->index;
+ else
+ targetReg = Assembler::ReturnValueRegister;
+
+ _as->add32(_as->toInt32Register(leftSource, targetReg),
+ _as->toInt32Register(rightSource, Assembler::ScratchRegister),
+ targetReg);
+ _as->storeInt32(targetReg, target);
+ } return true;
+ case V4IR::OpSub: {
+ Q_ASSERT(rightSource->type == V4IR::SInt32Type);
+
+ if (rightSource->asTemp() && rightSource->asTemp()->kind == V4IR::Temp::PhysicalRegister
+ && target->kind == V4IR::Temp::PhysicalRegister
+ && target->index == rightSource->asTemp()->index) {
+ Assembler::RegisterID targetReg = (Assembler::RegisterID) target->index;
+ _as->move(targetReg, Assembler::ScratchRegister);
+ _as->move(_as->toInt32Register(leftSource, targetReg), targetReg);
+ _as->sub32(Assembler::ScratchRegister, targetReg);
+ _as->storeInt32(targetReg, target);
+ return true;
+ }
+
+ Assembler::RegisterID targetReg;
+ if (target->kind == V4IR::Temp::PhysicalRegister)
+ targetReg = (Assembler::RegisterID) target->index;
+ else
+ targetReg = Assembler::ReturnValueRegister;
+
+ _as->move(_as->toInt32Register(leftSource, targetReg), targetReg);
+ _as->sub32(_as->toInt32Register(rightSource, Assembler::ScratchRegister), targetReg);
+ _as->storeInt32(targetReg, target);
+ } return true;
+ case V4IR::OpMul: {
+ Q_ASSERT(rightSource->type == V4IR::SInt32Type);
+
+ Assembler::RegisterID targetReg;
+ if (target->kind == V4IR::Temp::PhysicalRegister)
+ targetReg = (Assembler::RegisterID) target->index;
+ else
+ targetReg = Assembler::ReturnValueRegister;
+
+ _as->mul32(_as->toInt32Register(leftSource, targetReg),
+ _as->toInt32Register(rightSource, Assembler::ScratchRegister),
+ targetReg);
+ _as->storeInt32(targetReg, target);
+ } return true;
default:
return false;
}
diff --git a/src/qml/compiler/qv4isel_masm_p.h b/src/qml/compiler/qv4isel_masm_p.h
index e3b41857ea..f5d4e469e5 100644
--- a/src/qml/compiler/qv4isel_masm_p.h
+++ b/src/qml/compiler/qv4isel_masm_p.h
@@ -466,23 +466,6 @@ public:
V4IR::BasicBlock *block;
};
- void saveInstructionPointer(RegisterID freeScratchRegister) {
- Address ipAddr(ContextRegister, qOffsetOf(QV4::ExecutionContext, jitInstructionPointer));
- RegisterID sourceRegister = freeScratchRegister;
-
-#if CPU(X86_64) || CPU(X86)
- callToRetrieveIP();
- peek(sourceRegister);
- pop();
-#elif CPU(ARM)
- move(JSC::ARMRegisters::pc, sourceRegister);
-#else
-#error "Port me!"
-#endif
-
- storePtr(sourceRegister, ipAddr);
- }
-
void callAbsolute(const char* functionName, FunctionPtr function) {
CallToLink ctl;
ctl.call = call();
@@ -1056,7 +1039,6 @@ public:
static const BinaryOperationInfo &binaryOperation(V4IR::AluOp operation)
{ return binaryOperations[operation]; }
-
Jump inline_add32(Address addr, RegisterID reg)
{
#if HAVE(ALU_OPS_WITH_MEM_OPERAND)
@@ -1397,8 +1379,6 @@ public:
JSC::MacroAssemblerCodeRef link(int *codeSize);
- void recordLineNumber(int lineNumber);
-
const StackLayout stackLayout() const { return _stackLayout; }
ConstantTable &constantTable() { return _constTable; }
@@ -1424,13 +1404,6 @@ private:
QV4::ExecutableAllocator *_executableAllocator;
InstructionSelection *_isel;
-
- struct CodeLineNumerMapping
- {
- Assembler::Label location;
- int lineNumber;
- };
- QVector<CodeLineNumerMapping> codeLineNumberMappings;
};
template <typename T> inline void prepareRelativeCall(const T &, Assembler *){}
@@ -1445,7 +1418,7 @@ class Q_QML_EXPORT InstructionSelection:
public EvalInstructionSelection
{
public:
- InstructionSelection(QV4::ExecutableAllocator *execAllocator, V4IR::Module *module, QV4::Compiler::JSUnitGenerator *jsGenerator);
+ InstructionSelection(QQmlEnginePrivate *qmlEngine, QV4::ExecutableAllocator *execAllocator, V4IR::Module *module, QV4::Compiler::JSUnitGenerator *jsGenerator);
~InstructionSelection();
virtual void run(int functionIndex);
@@ -1483,10 +1456,11 @@ protected:
virtual void callSubscript(V4IR::Expr *base, V4IR::Expr *index, V4IR::ExprList *args, V4IR::Temp *result);
virtual void convertType(V4IR::Temp *source, V4IR::Temp *target);
virtual void loadThisObject(V4IR::Temp *temp);
- virtual void loadQmlIdObject(int id, V4IR::Temp *temp);
+ virtual void loadQmlIdArray(V4IR::Temp *temp);
virtual void loadQmlImportedScripts(V4IR::Temp *temp);
virtual void loadQmlContextObject(V4IR::Temp *temp);
virtual void loadQmlScopeObject(V4IR::Temp *temp);
+ virtual void loadQmlSingleton(const QString &name, V4IR::Temp *temp);
virtual void loadConst(V4IR::Const *sourceConst, V4IR::Temp *targetTemp);
virtual void loadString(const QString &str, V4IR::Temp *targetTemp);
virtual void loadRegexp(V4IR::RegExp *sourceRegexp, V4IR::Temp *targetTemp);
@@ -1496,7 +1470,7 @@ protected:
virtual void getProperty(V4IR::Expr *base, const QString &name, V4IR::Temp *target);
virtual void setProperty(V4IR::Expr *source, V4IR::Expr *targetBase, const QString &targetName);
virtual void setQObjectProperty(V4IR::Expr *source, V4IR::Expr *targetBase, int propertyIndex);
- virtual void getQObjectProperty(V4IR::Expr *base, int propertyIndex, bool captureRequired, V4IR::Temp *target);
+ virtual void getQObjectProperty(V4IR::Expr *base, int propertyIndex, bool captureRequired, int attachedPropertiesId, V4IR::Temp *target);
virtual void getElement(V4IR::Expr *base, V4IR::Expr *index, V4IR::Temp *target);
virtual void setElement(V4IR::Expr *source, V4IR::Expr *targetBase, V4IR::Expr *targetIndex);
virtual void copyValue(V4IR::Temp *sourceTemp, V4IR::Temp *targetTemp);
@@ -1655,14 +1629,15 @@ private:
Assembler* _as;
CompilationUnit *compilationUnit;
+ QQmlEnginePrivate *qmlEngine;
};
class Q_QML_EXPORT ISelFactory: public EvalISelFactory
{
public:
virtual ~ISelFactory() {}
- virtual EvalInstructionSelection *create(QV4::ExecutableAllocator *execAllocator, V4IR::Module *module, QV4::Compiler::JSUnitGenerator *jsGenerator)
- { return new InstructionSelection(execAllocator, module, jsGenerator); }
+ virtual EvalInstructionSelection *create(QQmlEnginePrivate *qmlEngine, QV4::ExecutableAllocator *execAllocator, V4IR::Module *module, QV4::Compiler::JSUnitGenerator *jsGenerator)
+ { return new InstructionSelection(qmlEngine, execAllocator, module, jsGenerator); }
virtual bool jitCompileRegexps() const
{ return true; }
};
diff --git a/src/qml/compiler/qv4isel_moth.cpp b/src/qml/compiler/qv4isel_moth.cpp
index 6db8f11a9e..bf9af178fe 100644
--- a/src/qml/compiler/qv4isel_moth.cpp
+++ b/src/qml/compiler/qv4isel_moth.cpp
@@ -152,8 +152,9 @@ inline bool isBoolType(V4IR::Expr *e)
} // anonymous namespace
-InstructionSelection::InstructionSelection(QV4::ExecutableAllocator *execAllocator, V4IR::Module *module, QV4::Compiler::JSUnitGenerator *jsGenerator)
+InstructionSelection::InstructionSelection(QQmlEnginePrivate *qmlEngine, QV4::ExecutableAllocator *execAllocator, V4IR::Module *module, QV4::Compiler::JSUnitGenerator *jsGenerator)
: EvalInstructionSelection(execAllocator, module, jsGenerator)
+ , qmlEngine(qmlEngine)
, _block(0)
, _codeStart(0)
, _codeNext(0)
@@ -191,7 +192,7 @@ void InstructionSelection::run(int functionIndex)
qSwap(codeEnd, _codeEnd);
V4IR::Optimizer opt(_function);
- opt.run();
+ opt.run(qmlEngine);
if (opt.isInSSA()) {
opt.convertOutOfSSA();
opt.showMeTheCode(_function);
@@ -351,6 +352,16 @@ void InstructionSelection::constructActivationProperty(V4IR::Name *func,
void InstructionSelection::constructProperty(V4IR::Temp *base, const QString &name, V4IR::ExprList *args, V4IR::Temp *result)
{
+ if (useFastLookups) {
+ Instruction::ConstructPropertyLookup call;
+ call.base = getParam(base);
+ call.index = registerGetterLookup(name);
+ prepareCallArgs(args, call.argc);
+ call.callData = callDataStart();
+ call.result = getResultParam(result);
+ addInstruction(call);
+ return;
+ }
Instruction::CreateProperty create;
create.base = getParam(base);
create.name = registerString(name);
@@ -377,11 +388,10 @@ void InstructionSelection::loadThisObject(V4IR::Temp *temp)
addInstruction(load);
}
-void InstructionSelection::loadQmlIdObject(int id, V4IR::Temp *temp)
+void InstructionSelection::loadQmlIdArray(V4IR::Temp *temp)
{
- Instruction::LoadQmlIdObject load;
+ Instruction::LoadQmlIdArray load;
load.result = getResultParam(temp);
- load.id = id;
addInstruction(load);
}
@@ -406,6 +416,14 @@ void InstructionSelection::loadQmlScopeObject(V4IR::Temp *temp)
addInstruction(load);
}
+void InstructionSelection::loadQmlSingleton(const QString &name, V4IR::Temp *temp)
+{
+ Instruction::LoadQmlSingleton load;
+ load.result = getResultParam(temp);
+ load.name = registerString(name);
+ addInstruction(load);
+}
+
void InstructionSelection::loadConst(V4IR::Const *sourceConst, V4IR::Temp *targetTemp)
{
assert(sourceConst);
@@ -508,14 +526,22 @@ void InstructionSelection::setQObjectProperty(V4IR::Expr *source, V4IR::Expr *ta
addInstruction(store);
}
-void InstructionSelection::getQObjectProperty(V4IR::Expr *base, int propertyIndex, bool captureRequired, V4IR::Temp *target)
+void InstructionSelection::getQObjectProperty(V4IR::Expr *base, int propertyIndex, bool captureRequired, int attachedPropertiesId, V4IR::Temp *target)
{
- Instruction::LoadQObjectProperty load;
- load.base = getParam(base);
- load.propertyIndex = propertyIndex;
- load.result = getResultParam(target);
- load.captureRequired = captureRequired;
- addInstruction(load);
+ if (attachedPropertiesId != 0) {
+ Instruction::LoadAttachedQObjectProperty load;
+ load.propertyIndex = propertyIndex;
+ load.result = getResultParam(target);
+ load.attachedPropertiesId = attachedPropertiesId;
+ addInstruction(load);
+ } else {
+ Instruction::LoadQObjectProperty load;
+ load.base = getParam(base);
+ load.propertyIndex = propertyIndex;
+ load.result = getResultParam(target);
+ load.captureRequired = captureRequired;
+ addInstruction(load);
+ }
}
void InstructionSelection::getElement(V4IR::Expr *base, V4IR::Expr *index, V4IR::Temp *target)
diff --git a/src/qml/compiler/qv4isel_moth_p.h b/src/qml/compiler/qv4isel_moth_p.h
index ffb8ff4539..d8a85ff249 100644
--- a/src/qml/compiler/qv4isel_moth_p.h
+++ b/src/qml/compiler/qv4isel_moth_p.h
@@ -68,7 +68,7 @@ class Q_QML_EXPORT InstructionSelection:
public EvalInstructionSelection
{
public:
- InstructionSelection(QV4::ExecutableAllocator *execAllocator, V4IR::Module *module, QV4::Compiler::JSUnitGenerator *jsGenerator);
+ InstructionSelection(QQmlEnginePrivate *qmlEngine, QV4::ExecutableAllocator *execAllocator, V4IR::Module *module, QV4::Compiler::JSUnitGenerator *jsGenerator);
~InstructionSelection();
virtual void run(int functionIndex);
@@ -112,10 +112,11 @@ protected:
virtual void constructProperty(V4IR::Temp *base, const QString &name, V4IR::ExprList *args, V4IR::Temp *result);
virtual void constructValue(V4IR::Temp *value, V4IR::ExprList *args, V4IR::Temp *result);
virtual void loadThisObject(V4IR::Temp *temp);
- virtual void loadQmlIdObject(int id, V4IR::Temp *temp);
+ virtual void loadQmlIdArray(V4IR::Temp *temp);
virtual void loadQmlImportedScripts(V4IR::Temp *temp);
virtual void loadQmlContextObject(V4IR::Temp *temp);
virtual void loadQmlScopeObject(V4IR::Temp *temp);
+ virtual void loadQmlSingleton(const QString &name, V4IR::Temp *temp);
virtual void loadConst(V4IR::Const *sourceConst, V4IR::Temp *targetTemp);
virtual void loadString(const QString &str, V4IR::Temp *targetTemp);
virtual void loadRegexp(V4IR::RegExp *sourceRegexp, V4IR::Temp *targetTemp);
@@ -125,7 +126,7 @@ protected:
virtual void getProperty(V4IR::Expr *base, const QString &name, V4IR::Temp *target);
virtual void setProperty(V4IR::Expr *source, V4IR::Expr *targetBase, const QString &targetName);
virtual void setQObjectProperty(V4IR::Expr *source, V4IR::Expr *targetBase, int propertyIndex);
- virtual void getQObjectProperty(V4IR::Expr *base, int propertyIndex, bool captureRequired, V4IR::Temp *target);
+ virtual void getQObjectProperty(V4IR::Expr *base, int propertyIndex, bool captureRequired, int attachedPropertiesId, V4IR::Temp *target);
virtual void getElement(V4IR::Expr *base, V4IR::Expr *index, V4IR::Temp *target);
virtual void setElement(V4IR::Expr *source, V4IR::Expr *targetBase, V4IR::Expr *targetIndex);
virtual void copyValue(V4IR::Temp *sourceTemp, V4IR::Temp *targetTemp);
@@ -168,6 +169,8 @@ private:
void patchJumpAddresses();
QByteArray squeezeCode() const;
+ QQmlEnginePrivate *qmlEngine;
+
V4IR::BasicBlock *_block;
V4IR::BasicBlock *_nextBlock;
@@ -189,8 +192,8 @@ class Q_QML_EXPORT ISelFactory: public EvalISelFactory
{
public:
virtual ~ISelFactory() {}
- virtual EvalInstructionSelection *create(QV4::ExecutableAllocator *execAllocator, V4IR::Module *module, QV4::Compiler::JSUnitGenerator *jsGenerator)
- { return new InstructionSelection(execAllocator, module, jsGenerator); }
+ virtual EvalInstructionSelection *create(QQmlEnginePrivate *qmlEngine, QV4::ExecutableAllocator *execAllocator, V4IR::Module *module, QV4::Compiler::JSUnitGenerator *jsGenerator)
+ { return new InstructionSelection(qmlEngine, execAllocator, module, jsGenerator); }
virtual bool jitCompileRegexps() const
{ return false; }
};
diff --git a/src/qml/compiler/qv4isel_p.cpp b/src/qml/compiler/qv4isel_p.cpp
index 45b1e9f3b0..b86837e167 100644
--- a/src/qml/compiler/qv4isel_p.cpp
+++ b/src/qml/compiler/qv4isel_p.cpp
@@ -103,12 +103,16 @@ void IRDecoder::visitMove(V4IR::Move *s)
if (V4IR::Name *n = s->source->asName()) {
if (n->id && *n->id == QStringLiteral("this")) // TODO: `this' should be a builtin.
loadThisObject(t);
+ else if (n->builtin == V4IR::Name::builtin_qml_id_array)
+ loadQmlIdArray(t);
else if (n->builtin == V4IR::Name::builtin_qml_context_object)
loadQmlContextObject(t);
else if (n->builtin == V4IR::Name::builtin_qml_scope_object)
loadQmlScopeObject(t);
else if (n->builtin == V4IR::Name::builtin_qml_imported_scripts_object)
loadQmlImportedScripts(t);
+ else if (n->qmlSingleton)
+ loadQmlSingleton(*n->id, t);
else
getActivationProperty(n, t);
return;
@@ -142,21 +146,22 @@ void IRDecoder::visitMove(V4IR::Move *s)
return;
}
} else if (V4IR::Member *m = s->source->asMember()) {
- if (m->type == V4IR::Member::MemberOfQmlContext) {
- V4IR::Name *base = m->base->asName();
- Q_ASSERT(base);
-
- if (base->builtin == V4IR::Name::builtin_qml_id_scope) {
- loadQmlIdObject(m->memberIndex, t);
- return;
- }
- } else if (m->type == V4IR::Member::MemberOfQObject) {
+ if (m->property) {
bool captureRequired = true;
- if (_function) {
- captureRequired = !_function->contextObjectDependencies.contains(m->property)
- && !_function->scopeObjectDependencies.contains(m->property);
+
+ Q_ASSERT(m->kind != V4IR::Member::MemberOfEnum);
+ const int attachedPropertiesId = m->attachedPropertiesIdOrEnumValue;
+
+ if (_function && attachedPropertiesId == 0 && !m->property->isConstant()) {
+ if (m->kind == V4IR::Member::MemberOfQmlContextObject) {
+ _function->contextObjectPropertyDependencies.insert(m->property->coreIndex, m->property->notifyIndex);
+ captureRequired = false;
+ } else if (m->kind == V4IR::Member::MemberOfQmlScopeObject) {
+ _function->scopeObjectPropertyDependencies.insert(m->property->coreIndex, m->property->notifyIndex);
+ captureRequired = false;
+ }
}
- getQObjectProperty(m->base, m->property->coreIndex, captureRequired, t);
+ getQObjectProperty(m->base, m->property->coreIndex, captureRequired, attachedPropertiesId, t);
return;
} else if (m->base->asTemp() || m->base->asConst()) {
getProperty(m->base, *m->name, t);
@@ -195,7 +200,9 @@ void IRDecoder::visitMove(V4IR::Move *s)
} else if (V4IR::Member *m = s->target->asMember()) {
if (m->base->asTemp() || m->base->asConst()) {
if (s->source->asTemp() || s->source->asConst()) {
- if (m->type == V4IR::Member::MemberOfQObject) {
+ Q_ASSERT(m->kind != V4IR::Member::MemberOfEnum);
+ const int attachedPropertiesId = m->attachedPropertiesIdOrEnumValue;
+ if (m->property && attachedPropertiesId == 0) {
setQObjectProperty(s->source, m->base, m->property->coreIndex);
return;
} else {
@@ -234,9 +241,7 @@ void IRDecoder::visitExp(V4IR::Exp *s)
Q_ASSERT(member->base->asTemp());
callProperty(member->base->asTemp(), *member->name, c->args, 0);
} else if (Subscript *s = c->base->asSubscript()) {
- Q_ASSERT(s->base->asTemp());
- Q_ASSERT(s->index->asTemp());
- callSubscript(s->base->asTemp(), s->index->asTemp(), c->args, 0);
+ callSubscript(s->base, s->index, c->args, 0);
} else {
Q_UNIMPLEMENTED();
}
diff --git a/src/qml/compiler/qv4isel_p.h b/src/qml/compiler/qv4isel_p.h
index 23ef7cc69e..5ddafc07ab 100644
--- a/src/qml/compiler/qv4isel_p.h
+++ b/src/qml/compiler/qv4isel_p.h
@@ -52,6 +52,8 @@
QT_BEGIN_NAMESPACE
+class QQmlEnginePrivate;
+
namespace QV4 {
class ExecutableAllocator;
struct Function;
@@ -92,7 +94,7 @@ class Q_QML_EXPORT EvalISelFactory
{
public:
virtual ~EvalISelFactory() = 0;
- virtual EvalInstructionSelection *create(QV4::ExecutableAllocator *execAllocator, V4IR::Module *module, QV4::Compiler::JSUnitGenerator *jsGenerator) = 0;
+ virtual EvalInstructionSelection *create(QQmlEnginePrivate *qmlEngine, QV4::ExecutableAllocator *execAllocator, V4IR::Module *module, QV4::Compiler::JSUnitGenerator *jsGenerator) = 0;
virtual bool jitCompileRegexps() const = 0;
};
@@ -142,10 +144,11 @@ public: // to implement by subclasses:
virtual void constructProperty(V4IR::Temp *base, const QString &name, V4IR::ExprList *args, V4IR::Temp *result) = 0;
virtual void constructValue(V4IR::Temp *value, V4IR::ExprList *args, V4IR::Temp *result) = 0;
virtual void loadThisObject(V4IR::Temp *temp) = 0;
- virtual void loadQmlIdObject(int id, V4IR::Temp *temp) = 0;
+ virtual void loadQmlIdArray(V4IR::Temp *temp) = 0;
virtual void loadQmlImportedScripts(V4IR::Temp *temp) = 0;
virtual void loadQmlContextObject(V4IR::Temp *temp) = 0;
virtual void loadQmlScopeObject(V4IR::Temp *temp) = 0;
+ virtual void loadQmlSingleton(const QString &name, V4IR::Temp *temp) = 0;
virtual void loadConst(V4IR::Const *sourceConst, V4IR::Temp *targetTemp) = 0;
virtual void loadString(const QString &str, V4IR::Temp *targetTemp) = 0;
virtual void loadRegexp(V4IR::RegExp *sourceRegexp, V4IR::Temp *targetTemp) = 0;
@@ -153,7 +156,7 @@ public: // to implement by subclasses:
virtual void setActivationProperty(V4IR::Expr *source, const QString &targetName) = 0;
virtual void initClosure(V4IR::Closure *closure, V4IR::Temp *target) = 0;
virtual void getProperty(V4IR::Expr *base, const QString &name, V4IR::Temp *target) = 0;
- virtual void getQObjectProperty(V4IR::Expr *base, int propertyIndex, bool captureRequired, V4IR::Temp *targetTemp) = 0;
+ virtual void getQObjectProperty(V4IR::Expr *base, int propertyIndex, bool captureRequired, int attachedPropertiesId, V4IR::Temp *targetTemp) = 0;
virtual void setProperty(V4IR::Expr *source, V4IR::Expr *targetBase, const QString &targetName) = 0;
virtual void setQObjectProperty(V4IR::Expr *source, V4IR::Expr *targetBase, int propertyIndex) = 0;
virtual void getElement(V4IR::Expr *base, V4IR::Expr *index, V4IR::Temp *target) = 0;
diff --git a/src/qml/compiler/qv4jsir.cpp b/src/qml/compiler/qv4jsir.cpp
index 75261b2469..deb1af51b4 100644
--- a/src/qml/compiler/qv4jsir.cpp
+++ b/src/qml/compiler/qv4jsir.cpp
@@ -72,6 +72,7 @@ QString typeName(Type t)
case NumberType: return QStringLiteral("number");
case StringType: return QStringLiteral("string");
case VarType: return QStringLiteral("var");
+ case QObjectType: return QStringLiteral("qobject");
default: return QStringLiteral("multiple");
}
}
@@ -274,8 +275,16 @@ static QString dumpStart(const Expr *e) {
if (e->type == UnknownType)
// return QStringLiteral("**UNKNOWN**");
return QString();
- else
- return typeName(e->type) + QStringLiteral("{");
+
+ QString result = typeName(e->type);
+ const Temp *temp = const_cast<Expr*>(e)->asTemp();
+ if (e->type == QObjectType && temp && temp->memberResolver.isQObjectResolver) {
+ result += QLatin1Char('<');
+ result += QString::fromUtf8(static_cast<QQmlPropertyCache*>(temp->memberResolver.data)->className());
+ result += QLatin1Char('>');
+ }
+ result += QLatin1Char('{');
+ return result;
}
static const char *dumpEnd(const Expr *e) {
@@ -363,6 +372,8 @@ void Name::initGlobal(const QString *id, quint32 line, quint32 column)
this->id = id;
this->builtin = builtin_invalid;
this->global = true;
+ this->qmlSingleton = false;
+ this->freeOfSideEffects = false;
this->line = line;
this->column = column;
}
@@ -372,6 +383,8 @@ void Name::init(const QString *id, quint32 line, quint32 column)
this->id = id;
this->builtin = builtin_invalid;
this->global = false;
+ this->qmlSingleton = false;
+ this->freeOfSideEffects = false;
this->line = line;
this->column = column;
}
@@ -381,6 +394,8 @@ void Name::init(Builtin builtin, quint32 line, quint32 column)
this->id = 0;
this->builtin = builtin;
this->global = false;
+ this->qmlSingleton = false;
+ this->freeOfSideEffects = false;
this->line = line;
this->column = column;
}
@@ -424,8 +439,8 @@ static const char *builtin_to_string(Name::Builtin b)
return "builtin_setup_argument_object";
case V4IR::Name::builtin_convert_this_to_object:
return "builtin_convert_this_to_object";
- case V4IR::Name::builtin_qml_id_scope:
- return "builtin_qml_id_scope";
+ case V4IR::Name::builtin_qml_id_array:
+ return "builtin_qml_id_array";
case V4IR::Name::builtin_qml_imported_scripts_object:
return "builtin_qml_imported_scripts_object";
case V4IR::Name::builtin_qml_scope_object:
@@ -539,9 +554,12 @@ void Subscript::dump(QTextStream &out) const
void Member::dump(QTextStream &out) const
{
- base->dump(out);
+ if (kind != MemberOfEnum && attachedPropertiesIdOrEnumValue != 0 && !base->asTemp())
+ out << "[[attached property from " << attachedPropertiesIdOrEnumValue << "]]";
+ else
+ base->dump(out);
out << '.' << *name;
- if (type == MemberOfQObject)
+ if (property)
out << " (meta-property " << property->coreIndex << " <" << QMetaType::typeName(property->propType) << ">)";
}
@@ -825,24 +843,10 @@ Expr *BasicBlock::SUBSCRIPT(Expr *base, Expr *index)
return e;
}
-Expr *BasicBlock::MEMBER(Expr *base, const QString *name)
-{
- Member*e = function->New<Member>();
- e->init(base, name);
- return e;
-}
-
-Expr *BasicBlock::QML_CONTEXT_MEMBER(Expr *base, const QString *id, int memberIndex)
-{
- Member*e = function->New<Member>();
- e->initQmlContextMember(base, id, memberIndex);
- return e;
-}
-
-Expr *BasicBlock::QML_QOBJECT_PROPERTY(Expr *base, const QString *id, QQmlPropertyData *property)
+Expr *BasicBlock::MEMBER(Expr *base, const QString *name, QQmlPropertyData *property, uchar kind, int attachedPropertiesIdOrEnumValue)
{
Member*e = function->New<Member>();
- e->initMetaProperty(base, id, property);
+ e->init(base, name, property, kind, attachedPropertiesIdOrEnumValue);
return e;
}
@@ -1032,14 +1036,8 @@ void CloneExpr::visitSubscript(Subscript *e)
void CloneExpr::visitMember(Member *e)
{
- if (e->type == Member::MemberByName)
- cloned = block->MEMBER(clone(e->base), e->name);
- else if (e->type == Member::MemberOfQmlContext)
- cloned = block->QML_CONTEXT_MEMBER(clone(e->base), e->name, e->memberIndex);
- else if (e->type == Member::MemberOfQObject)
- cloned = block->QML_QOBJECT_PROPERTY(clone(e->base), e->name, e->property);
- else
- Q_ASSERT(!"Unimplemented!");
+ Expr *clonedBase = clone(e->base);
+ cloned = block->MEMBER(clonedBase, e->name, e->property, e->kind, e->attachedPropertiesIdOrEnumValue);
}
} // end of namespace IR
diff --git a/src/qml/compiler/qv4jsir_p.h b/src/qml/compiler/qv4jsir_p.h
index 9a1bd87a1d..2eba3405fe 100644
--- a/src/qml/compiler/qv4jsir_p.h
+++ b/src/qml/compiler/qv4jsir_p.h
@@ -55,6 +55,7 @@
#include "private/qv4global_p.h"
#include <private/qqmljsmemorypool_p.h>
#include <private/qqmljsastfwd_p.h>
+#include <private/qflagpointer_p.h>
#include <QtCore/QVector>
#include <QtCore/QString>
@@ -73,6 +74,8 @@ QT_BEGIN_NAMESPACE
class QTextStream;
class QQmlType;
class QQmlPropertyData;
+class QQmlPropertyCache;
+class QQmlEnginePrivate;
namespace QV4 {
struct ExecutionContext;
@@ -122,6 +125,14 @@ struct CJump;
struct Ret;
struct Phi;
+// Flag pointer:
+// * The first flag indicates whether the meta object is final.
+// If final, then none of its properties themselves need to
+// be final when considering for lookups in QML.
+// * The second flag indicates whether enums should be included
+// in the lookup of properties or not. The default is false.
+typedef QFlagPointer<QQmlPropertyCache> IRMetaObject;
+
enum AluOp {
OpInvalid = 0,
@@ -181,7 +192,8 @@ enum Type {
NumberType = SInt32Type | UInt32Type | DoubleType,
StringType = 1 << 7,
- VarType = 1 << 8
+ QObjectType = 1 << 8,
+ VarType = 1 << 9
};
inline bool strictlyEqualTypes(Type t1, Type t2)
@@ -218,6 +230,24 @@ struct StmtVisitor {
virtual void visitPhi(Phi *) = 0;
};
+
+struct MemberExpressionResolver
+{
+ typedef Type (*ResolveFunction)(QQmlEnginePrivate *engine, MemberExpressionResolver *resolver, Member *member);
+
+ MemberExpressionResolver()
+ : resolveMember(0), data(0), extraData(0), flags(0), isQObjectResolver(false) {}
+
+ bool isValid() const { return !!resolveMember; }
+ void clear() { *this = MemberExpressionResolver(); }
+
+ ResolveFunction resolveMember;
+ void *data; // Could be pointer to meta object, importNameSpace, etc. - depends on resolveMember implementation
+ void *extraData; // Could be QQmlTypeNameCache
+ unsigned int flags : 31;
+ unsigned int isQObjectResolver; // neede for IR dump helpers
+};
+
struct Expr {
Type type;
@@ -325,7 +355,7 @@ struct Name: Expr {
builtin_define_object_literal,
builtin_setup_argument_object,
builtin_convert_this_to_object,
- builtin_qml_id_scope,
+ builtin_qml_id_array,
builtin_qml_imported_scripts_object,
builtin_qml_context_object,
builtin_qml_scope_object
@@ -333,7 +363,9 @@ struct Name: Expr {
const QString *id;
Builtin builtin;
- bool global;
+ bool global : 1;
+ bool qmlSingleton : 1;
+ bool freeOfSideEffects : 1;
quint32 line;
quint32 column;
@@ -360,9 +392,12 @@ struct Temp: Expr {
};
unsigned index;
- unsigned scope : 28; // how many scopes outside the current one?
+ unsigned scope : 27; // how many scopes outside the current one?
unsigned kind : 3;
unsigned isArgumentsOrEval : 1;
+ unsigned isReadOnly : 1;
+ // Used when temp is used as base in member expression
+ MemberExpressionResolver memberResolver;
void init(unsigned kind, unsigned index, unsigned scope)
{
@@ -374,10 +409,11 @@ struct Temp: Expr {
this->index = index;
this->scope = scope;
this->isArgumentsOrEval = false;
+ this->isReadOnly = false;
}
virtual void accept(ExprVisitor *v) { v->visitTemp(this); }
- virtual bool isLValue() { return true; }
+ virtual bool isLValue() { return !isReadOnly; }
virtual Temp *asTemp() { return this; }
virtual void dump(QTextStream &out) const;
@@ -518,47 +554,53 @@ struct Subscript: Expr {
};
struct Member: Expr {
- enum MemberType {
- MemberByName,
- // QML extensions
- MemberOfQmlContext, // lookup in context's id values
- MemberOfQObject
+ // Used for property dependency tracking
+ enum MemberKind {
+ UnspecifiedMember,
+ MemberOfEnum,
+ MemberOfQmlScopeObject,
+ MemberOfQmlContextObject
};
- MemberType type;
Expr *base;
const QString *name;
- int memberIndex; // used if type == MemberOfQmlContext
QQmlPropertyData *property;
+ int attachedPropertiesIdOrEnumValue; // depending on kind
+ uchar memberIsEnum : 1;
+ uchar freeOfSideEffects : 1;
- void init(Expr *base, const QString *name)
- {
- this->type = MemberByName;
- this->base = base;
- this->name = name;
- this->memberIndex = -1;
- this->property = 0;
+ // This is set for example for for QObject properties. All sorts of extra behavior
+ // is defined when writing to them, for example resettable properties are reset
+ // when writing undefined to them, and an exception is thrown when they're missing
+ // a reset function. And then there's also Qt.binding().
+ uchar inhibitTypeConversionOnWrite: 1;
+
+ uchar kind: 3; // MemberKind
+
+ void setEnumValue(int value) {
+ kind = MemberOfEnum;
+ attachedPropertiesIdOrEnumValue = value;
}
- void initQmlContextMember(Expr *base, const QString *name, int memberIndex)
- {
- this->type = MemberOfQmlContext;
- this->base = base;
- this->name = name;
- this->memberIndex = memberIndex;
- this->property = 0;
+ void setAttachedPropertiesId(int id) {
+ Q_ASSERT(kind != MemberOfEnum);
+ attachedPropertiesIdOrEnumValue = id;
}
- void initMetaProperty(Expr *base, const QString *name, QQmlPropertyData *property)
+ void init(Expr *base, const QString *name, QQmlPropertyData *property = 0, uchar kind = UnspecifiedMember, int attachedPropertiesIdOrEnumValue = 0)
{
- this->type = MemberOfQObject;
this->base = base;
this->name = name;
this->property = property;
+ this->attachedPropertiesIdOrEnumValue = attachedPropertiesIdOrEnumValue;
+ this->memberIsEnum = false;
+ this->freeOfSideEffects = false;
+ this->inhibitTypeConversionOnWrite = property != 0;
+ this->kind = kind;
}
virtual void accept(ExprVisitor *v) { v->visitMember(this); }
- virtual bool isLValue() { return type != MemberOfQmlContext; }
+ virtual bool isLValue() { return true; }
virtual Member *asMember() { return this; }
virtual void dump(QTextStream &out) const;
@@ -717,6 +759,9 @@ struct Q_QML_EXPORT Module {
void setFileName(const QString &name);
};
+// Map from meta property index (existence implies dependency) to notify signal index
+typedef QHash<int, int> PropertyDependencyMap;
+
struct Function {
Module *module;
MemoryPool *pool;
@@ -747,10 +792,8 @@ struct Function {
// Qml extension:
QSet<int> idObjectDependencies;
- QSet<QQmlPropertyData*> contextObjectDependencies;
- QSet<QQmlPropertyData*> scopeObjectDependencies;
-
- bool hasQmlDependencies() const { return !idObjectDependencies.isEmpty() || !contextObjectDependencies.isEmpty() || !scopeObjectDependencies.isEmpty(); }
+ PropertyDependencyMap contextObjectPropertyDependencies;
+ PropertyDependencyMap scopeObjectPropertyDependencies;
template <typename _Tp> _Tp *New() { return new (pool->allocate(sizeof(_Tp))) _Tp(); }
@@ -860,9 +903,7 @@ struct BasicBlock {
Expr *CALL(Expr *base, ExprList *args = 0);
Expr *NEW(Expr *base, ExprList *args = 0);
Expr *SUBSCRIPT(Expr *base, Expr *index);
- Expr *MEMBER(Expr *base, const QString *name);
- Expr *QML_CONTEXT_MEMBER(Expr *base, const QString *id, int memberIndex);
- Expr *QML_QOBJECT_PROPERTY(Expr *base, const QString *id, QQmlPropertyData *property);
+ Expr *MEMBER(Expr *base, const QString *name, QQmlPropertyData *property = 0, uchar kind = Member::UnspecifiedMember, int attachedPropertiesIdOrEnumValue = 0);
Stmt *EXP(Expr *expr);
@@ -927,6 +968,8 @@ public:
newName->id = n->id;
newName->builtin = n->builtin;
newName->global = n->global;
+ newName->qmlSingleton = n->qmlSingleton;
+ newName->freeOfSideEffects = n->freeOfSideEffects;
newName->line = n->line;
newName->column = n->column;
return newName;
@@ -937,6 +980,7 @@ public:
Temp *newTemp = f->New<Temp>();
newTemp->init(t->kind, t->index, t->scope);
newTemp->type = t->type;
+ newTemp->memberResolver = t->memberResolver;
return newTemp;
}
diff --git a/src/qml/compiler/qv4regalloc.cpp b/src/qml/compiler/qv4regalloc.cpp
index a6e66d2722..93ecdb2602 100644
--- a/src/qml/compiler/qv4regalloc.cpp
+++ b/src/qml/compiler/qv4regalloc.cpp
@@ -338,9 +338,8 @@ protected: // IRDecoder
addDef(temp);
}
- virtual void loadQmlIdObject(int id, V4IR::Temp *temp)
+ virtual void loadQmlIdArray(V4IR::Temp *temp)
{
- Q_UNUSED(id);
addDef(temp);
addCall();
}
@@ -365,6 +364,14 @@ protected: // IRDecoder
addCall();
}
+ virtual void loadQmlSingleton(const QString &/*name*/, Temp *temp)
+ {
+ Q_UNUSED(temp);
+
+ addDef(temp);
+ addCall();
+ }
+
virtual void loadConst(V4IR::Const *sourceConst, V4IR::Temp *targetTemp)
{
Q_UNUSED(sourceConst);
@@ -428,7 +435,7 @@ protected: // IRDecoder
addCall();
}
- virtual void getQObjectProperty(V4IR::Expr *base, int /*propertyIndex*/, bool /*captureRequired*/, V4IR::Temp *target)
+ virtual void getQObjectProperty(V4IR::Expr *base, int /*propertyIndex*/, bool /*captureRequired*/, int /*attachedPropertiesId*/, V4IR::Temp *target)
{
addDef(target);
addUses(base->asTemp(), Use::CouldHaveRegister);
@@ -511,8 +518,15 @@ protected: // IRDecoder
|| (oper >= OpGt && oper <= OpStrictNotEqual)) {
needsCall = false;
}
- } if (oper == OpBitAnd || oper == OpBitOr || oper == OpBitXor || oper == OpLShift || oper == OpRShift || oper == OpURShift) {
+ } else if (oper == OpBitAnd || oper == OpBitOr || oper == OpBitXor || oper == OpLShift || oper == OpRShift || oper == OpURShift) {
needsCall = false;
+ } else if (oper == OpAdd
+ || oper == OpMul
+ ||
+ oper == OpSub
+ ) {
+ if (leftSource->type == SInt32Type && rightSource->type == SInt32Type)
+ needsCall = false;
}
addDef(target);
@@ -589,6 +603,7 @@ private:
Q_ASSERT(!_defs.contains(*t));
bool canHaveReg = true;
switch (t->type) {
+ case QObjectType:
case VarType:
case StringType:
case UndefinedType:
@@ -889,9 +904,9 @@ private:
}
}
if (!moveFrom) {
- Q_ASSERT(!_info->isPhiTarget(it.temp()) || it.isSplitFromInterval() || lifeTimeHole);
Q_UNUSED(lifeTimeHole);
#if !defined(QT_NO_DEBUG)
+ Q_ASSERT(!_info->isPhiTarget(it.temp()) || it.isSplitFromInterval() || lifeTimeHole);
if (_info->def(it.temp()) != successorStart && !it.isSplitFromInterval()) {
const int successorEnd = successor->statements.last()->id;
const int idx = successor->in.indexOf(predecessor);
diff --git a/src/qml/compiler/qv4ssa.cpp b/src/qml/compiler/qv4ssa.cpp
index 6b1169d30a..4fee3c04a0 100644
--- a/src/qml/compiler/qv4ssa.cpp
+++ b/src/qml/compiler/qv4ssa.cpp
@@ -52,6 +52,7 @@
#include <qv4runtime_p.h>
#include <qv4context_p.h>
#include <private/qqmlpropertycache_p.h>
+#include <private/qqmlengine_p.h>
#include <cmath>
#include <iostream>
#include <cassert>
@@ -212,6 +213,22 @@ void showMeTheCode(Function *function)
}
}
+inline Temp *unescapableTemp(Expr *e, bool variablesCanEscape)
+{
+ Temp *t = e->asTemp();
+ if (!t)
+ return 0;
+
+ switch (t->kind) {
+ case Temp::VirtualRegister:
+ return t;
+ case Temp::Local:
+ return variablesCanEscape ? 0 : t;
+ default:
+ return 0;
+ }
+}
+
class DominatorTree {
int N;
QHash<BasicBlock *, int> dfnum;
@@ -625,15 +642,98 @@ void insertPhiNode(const Temp &a, BasicBlock *y, Function *f) {
}
}
+// High-level (recursive) algorithm:
+// Mapping: old temp number -> new temp number
+//
+// Start:
+// Rename(start-node)
+//
+// Rename(node, mapping):
+// for each statement S in block n
+// if S not in a phi-function
+// for each use of some variable x in S
+// y = mapping[x]
+// replace the use of x with y in S
+// for each definition of some variable a in S [1]
+// a_new = generate new/unique temp
+// mapping[a] = a_new
+// replace definition of a with definition of a_new in S
+// for each successor Y of block n
+// Suppose n is the j-th predecessor of Y
+// for each phi function in Y
+// suppose the j-th operand of the phi-function is a
+// i = mapping[a]
+// replace the j-th operand with a_i
+// for each child X of n [2]
+// Rename(X)
+// for each newly generated temp from step [1] restore the old value [3]
+//
+// This algorithm can run out of CPU stack space when there are lots of basic-blocks, like in a
+// switch statement with 8000 cases that all fall-through. The iterativer version below uses a
+// work-item stack, where step [1] from the algorithm above also pushes an "undo mapping change",
+// and step [2] pushes a "rename(X)" action. This eliminates step [3].
+//
+// Iterative version:
+// Mapping: old temp number -> new temp number
+//
+// The stack can hold two kinds of actions:
+// "Rename basic block n"
+// "Restore count for temp"
+//
+// Start:
+// counter = 0
+// push "Rename start node" onto the stack
+// while the stack is not empty:
+// take the last item, and process it
+//
+// Rename(n) =
+// for each statement S in block n
+// if S not in a phi-function
+// for each use of some variable x in S
+// y = mapping[x]
+// replace the use of x with y in S
+// for each definition of some variable a in S
+// old = mapping[a]
+// push Undo(a, old)
+// counter = counter + 1
+// new = counter;
+// mapping[a] = new
+// replace definition of a with definition of a_new in S
+// for each successor Y of block n
+// Suppose n is the j-th predecessor of Y
+// for each phi function in Y
+// suppose the j-th operand of the phi-function is a
+// i = mapping[a]
+// replace the j-th operand with a_i
+// for each child X of n
+// push Rename(X)
+//
+// Undo(t, c) =
+// mapping[t] = c
class VariableRenamer: public StmtVisitor, public ExprVisitor
{
Function *function;
- QHash<Temp, QStack<unsigned> > stack;
- QSet<BasicBlock *> seen;
+ const bool variablesCanEscape;
+ unsigned tempCount;
- QHash<Temp, unsigned> defCounts;
+ typedef QHash<unsigned, int> Mapping; // maps from existing/old temp number to the new and unique temp number.
+ enum { Absent = -1 };
+ Mapping localMapping;
+ Mapping vregMapping;
+ QBitArray processed;
+
+ bool alreadyProcessed(BasicBlock *bb) const
+ {
+ Q_ASSERT(bb);
+
+ return processed.at(bb->index);
+ }
+
+ void markAsProcessed(BasicBlock *bb)
+ {
+ processed.setBit(bb->index);
+ }
- const bool variablesCanEscape;
bool isRenamable(Temp *t) const
{
switch (t->kind) {
@@ -650,99 +750,125 @@ class VariableRenamer: public StmtVisitor, public ExprVisitor
return false;
}
}
- int nextFreeTemp() {
- const int next = function->tempCount++;
-// qDebug()<<"Next free temp:"<<next;
- return next;
- }
-
- /*
-
- Initialization:
- for each variable a
- count[a] = 0;
- stack[a] = empty;
- push 0 onto stack
-
- Rename(n) =
- for each statement S in block n [1]
- if S not in a phi-function
- for each use of some variable x in S
- i = top(stack[x])
- replace the use of x with x_i in S
- for each definition of some variable a in S
- count[a] = count[a] + 1
- i = count[a]
- push i onto stack[a]
- replace definition of a with definition of a_i in S
- for each successor Y of block n [2]
- Suppose n is the j-th predecessor of Y
- for each phi function in Y
- suppose the j-th operand of the phi-function is a
- i = top(stack[a])
- replace the j-th operand with a_i
- for each child X of n [3]
- Rename(X)
- for each statement S in block n [4]
- for each definition of some variable a in S
- pop stack[a]
-
- */
+
+ struct TodoAction {
+ enum { RestoreLocal, RestoreVReg, Rename } action;
+ union {
+ struct {
+ unsigned temp;
+ int previous;
+ } restoreData;
+ struct {
+ BasicBlock *basicBlock;
+ } renameData;
+ };
+
+ bool isValid() const { return action != Rename || renameData.basicBlock != 0; }
+
+ TodoAction()
+ {
+ action = Rename;
+ renameData.basicBlock = 0;
+ }
+
+ TodoAction(const Temp &t, int prev)
+ {
+ Q_ASSERT(t.kind == Temp::Local || t.kind == Temp::VirtualRegister);
+
+ action = t.kind == Temp::Local ? RestoreLocal : RestoreVReg;
+ restoreData.temp = t.index;
+ restoreData.previous = prev;
+ }
+
+ TodoAction(BasicBlock *bb)
+ {
+ Q_ASSERT(bb);
+
+ action = Rename;
+ renameData.basicBlock = bb;
+ }
+ };
+
+ QVector<TodoAction> todo;
public:
VariableRenamer(Function *f)
: function(f)
, variablesCanEscape(f->variablesCanEscape())
+ , tempCount(0)
{
- if (!variablesCanEscape) {
- Temp t;
- t.init(Temp::Local, 0, 0);
- for (int i = 0, ei = f->locals.size(); i != ei; ++i) {
- t.index = i;
- stack[t].push(nextFreeTemp());
+ int maxBB = 0;
+ foreach (BasicBlock *bb, f->basicBlocks)
+ maxBB = qMax(maxBB, bb->index);
+ processed = QBitArray(maxBB + 1, false);
+ }
+
+ void run() {
+ todo.append(TodoAction(function->basicBlocks.first()));
+
+ while (!todo.isEmpty()) {
+ TodoAction todoAction = todo.back();
+ Q_ASSERT(todoAction.isValid());
+ todo.pop_back();
+
+ switch (todoAction.action) {
+ case TodoAction::Rename:
+ rename(todoAction.renameData.basicBlock);
+ break;
+ case TodoAction::RestoreLocal:
+ restore(localMapping, todoAction.restoreData.temp, todoAction.restoreData.previous);
+ break;
+ case TodoAction::RestoreVReg:
+ restore(vregMapping, todoAction.restoreData.temp, todoAction.restoreData.previous);
+ break;
+ default:
+ Q_UNREACHABLE();
}
}
- Temp t;
- t.init(Temp::VirtualRegister, 0, 0);
- for (int i = 0, ei = f->tempCount; i != ei; ++i) {
- t.index = i;
- stack[t].push(i);
- }
+ function->tempCount = tempCount;
}
- void run() {
- foreach (BasicBlock *n, function->basicBlocks)
- rename(n);
-
-#ifdef SHOW_SSA
-// qout << "Temp to local mapping:" << endl;
-// foreach (int key, tempMapping.keys())
-// qout << '\t' << key << " -> " << tempMapping[key] << endl;
-#endif
+private:
+ static inline void restore(Mapping &mapping, unsigned temp, int previous)
+ {
+ if (previous == Absent)
+ mapping.remove(temp);
+ else
+ mapping[temp] = previous;
}
- void rename(BasicBlock *n) {
- if (seen.contains(n))
- return;
- seen.insert(n);
-// qDebug() << "I: L"<<n->index;
+ void rename(BasicBlock *bb)
+ {
+ while (bb && !alreadyProcessed(bb)) {
+ renameStatementsAndPhis(bb);
+ markAsProcessed(bb);
- // [1]:
- foreach (Stmt *s, n->statements)
- s->accept(this);
+ BasicBlock *next = 0;
+ foreach (BasicBlock *out, bb->out) {
+ if (alreadyProcessed(out))
+ continue;
+ if (!next)
+ next = out;
+ else
+ todo.append(TodoAction(out));
+ }
+ bb = next;
+ }
+ }
- QHash<Temp, unsigned> dc = defCounts;
- defCounts.clear();
+ void renameStatementsAndPhis(BasicBlock *bb)
+ {
+ foreach (Stmt *s, bb->statements)
+ s->accept(this);
- // [2]:
- foreach (BasicBlock *Y, n->out) {
- const int j = Y->in.indexOf(n);
+ foreach (BasicBlock *Y, bb->out) {
+ const int j = Y->in.indexOf(bb);
Q_ASSERT(j >= 0 && j < Y->in.size());
foreach (Stmt *s, Y->statements) {
if (Phi *phi = s->asPhi()) {
Temp *t = phi->d->incoming[j]->asTemp();
- unsigned newTmp = stack[*t].top();
+ unsigned newTmp = currentNumber(*t);
// qDebug()<<"I: replacing phi use"<<a<<"with"<<newTmp<<"in L"<<Y->index;
t->index = newTmp;
t->kind = Temp::VirtualRegister;
@@ -751,24 +877,65 @@ public:
}
}
}
+ }
- // [3]:
- foreach (BasicBlock *X, n->out)
- rename(X);
+ unsigned currentNumber(const Temp &t)
+ {
+ int nr = Absent;
+ switch (t.kind) {
+ case Temp::Local:
+ nr = localMapping.value(t.index, Absent);
+ break;
+ case Temp::VirtualRegister:
+ nr = vregMapping.value(t.index, Absent);
+ break;
+ default:
+ Q_UNREACHABLE();
+ nr = Absent;
+ break;
+ }
+ if (nr == Absent) {
+ // Special case: we didn't prune the Phi nodes yet, so for proper temps (virtual
+ // registers) the SSA algorithm might insert superfluous Phis that have uses without
+ // definition. E.g.: if a temporary got introduced in the "then" clause, it "could"
+ // reach the "end-if" block, so there will be a phi node for that temp. A later pass
+ // will clean this up by looking for uses-without-defines in phi nodes. So, what we do
+ // is to generate a new unique number, and leave it dangling.
+ nr = nextFreeTemp(t);
+ }
+
+ return nr;
+ }
+
+ unsigned nextFreeTemp(const Temp &t)
+ {
+ unsigned newIndex = tempCount++;
+ Q_ASSERT(newIndex <= INT_MAX);
+ int oldIndex = Absent;
- // [4]:
- for (QHash<Temp, unsigned>::const_iterator i = dc.begin(), ei = dc.end(); i != ei; ++i) {
-// qDebug()<<i.key() <<" -> " << i.value();
- for (unsigned j = 0, ej = i.value(); j < ej; ++j)
- stack[i.key()].pop();
+ switch (t.kind) {
+ case Temp::Local:
+ oldIndex = localMapping.value(t.index, Absent);
+ localMapping.insert(t.index, newIndex);
+ break;
+ case Temp::VirtualRegister:
+ oldIndex = vregMapping.value(t.index, Absent);
+ vregMapping.insert(t.index, newIndex);
+ break;
+ default:
+ Q_UNREACHABLE();
}
+
+ todo.append(TodoAction(t, oldIndex));
+
+ return newIndex;
}
protected:
virtual void visitTemp(Temp *e) { // only called for uses, not defs
if (isRenamable(e)) {
// qDebug()<<"I: replacing use of"<<e->index<<"with"<<stack[e->index].top();
- e->index = stack[*e].top();
+ e->index = currentNumber(*e);
e->kind = Temp::VirtualRegister;
}
}
@@ -786,9 +953,7 @@ protected:
void renameTemp(Temp *t) {
if (isRenamable(t)) {
- defCounts[*t] = defCounts.value(*t, 0) + 1;
- const int newIdx = nextFreeTemp();
- stack[*t].push(newIdx);
+ const int newIdx = nextFreeTemp(*t);
// qDebug()<<"I: replacing def of"<<a<<"with"<<newIdx;
t->kind = Temp::VirtualRegister;
t->index = newIdx;
@@ -874,12 +1039,15 @@ void convertToSSA(Function *function, const DominatorTree &df)
struct UntypedTemp {
Temp temp;
+ UntypedTemp() {}
UntypedTemp(const Temp &t): temp(t) {}
};
inline uint qHash(const UntypedTemp &t, uint seed = 0) Q_DECL_NOTHROW
{ return t.temp.index ^ (t.temp.kind | (t.temp.scope << 3)) ^ seed; }
inline bool operator==(const UntypedTemp &t1, const UntypedTemp &t2) Q_DECL_NOTHROW
{ return t1.temp.index == t2.temp.index && t1.temp.scope == t2.temp.scope && t1.temp.kind == t2.temp.kind; }
+inline bool operator!=(const UntypedTemp &t1, const UntypedTemp &t2) Q_DECL_NOTHROW
+{ return !(t1 == t2); }
class DefUsesCalculator: public StmtVisitor, public ExprVisitor {
public:
@@ -964,6 +1132,8 @@ public:
defUse.blockOfStatement = defBlock;
}
+ QList<UntypedTemp> defsUntyped() const { return _defUses.keys(); }
+
QList<Temp> defs() const {
QList<Temp> res;
res.reserve(_defUses.size());
@@ -982,10 +1152,10 @@ public:
void addUse(const Temp &variable, Stmt * newUse)
{ _defUses[variable].uses.append(newUse); }
- int useCount(const Temp &variable) const
+ int useCount(const UntypedTemp &variable) const
{ return _defUses[variable].uses.size(); }
- Stmt *defStmt(const Temp &variable) const
+ Stmt *defStmt(const UntypedTemp &variable) const
{ return _defUses[variable].defStmt; }
BasicBlock *defStmtBlock(const Temp &variable) const
@@ -997,7 +1167,7 @@ public:
QList<Temp> usedVars(Stmt *s) const
{ return _usesPerStatement[s]; }
- QList<Stmt *> uses(const Temp &var) const
+ QList<Stmt *> uses(const UntypedTemp &var) const
{ return _defUses[var].uses; }
QVector<Stmt*> removeDefUses(Stmt *s)
@@ -1188,6 +1358,8 @@ protected:
virtual 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
// a side-effect.
if (e->builtin == Name::builtin_invalid || (e->id && *e->id != QStringLiteral("this")))
@@ -1209,6 +1381,7 @@ protected:
e->expr->accept(this);
switch (e->expr->type) {
+ case QObjectType:
case StringType:
case VarType:
markAsSideEffect();
@@ -1227,7 +1400,7 @@ protected:
case OpNot:
case OpIncrement:
case OpDecrement:
- if (e->expr->type == VarType || e->expr->type == StringType)
+ if (e->expr->type == VarType || e->expr->type == StringType || e->expr->type == QObjectType)
markAsSideEffect();
break;
@@ -1243,8 +1416,8 @@ protected:
_sideEffect = checkForSideEffects(e->left);
_sideEffect |= checkForSideEffects(e->right);
- if (e->left->type == VarType || e->left->type == StringType
- || e->right->type == VarType || e->right->type == StringType)
+ if (e->left->type == VarType || e->left->type == StringType || e->left->type == QObjectType
+ || e->right->type == VarType || e->right->type == StringType || e->right->type == QObjectType)
markAsSideEffect();
}
@@ -1256,6 +1429,8 @@ protected:
virtual void visitMember(Member *e) {
e->base->accept(this);
+ if (e->freeOfSideEffects)
+ return;
markAsSideEffect();
}
@@ -1274,23 +1449,115 @@ protected:
}
};
+struct DiscoveredType {
+ int type;
+ MemberExpressionResolver memberResolver;
+
+ DiscoveredType() : type(UnknownType) {}
+ DiscoveredType(Type t) : type(t) { Q_ASSERT(type != QObjectType); }
+ explicit DiscoveredType(int t) : type(t) { Q_ASSERT(type != QObjectType); }
+ explicit DiscoveredType(MemberExpressionResolver memberResolver) : type(QObjectType), memberResolver(memberResolver) {}
+
+ bool test(Type t) const { return type & t; }
+ bool isNumber() const { return (type & NumberType) && !(type & ~NumberType); }
+
+ bool operator!=(Type other) const { return type != other; }
+ bool operator==(Type other) const { return type == other; }
+ bool operator==(const DiscoveredType &other) const { return type == other.type; }
+ bool operator!=(const DiscoveredType &other) const { return type != other.type; }
+};
+
+class PropagateTempTypes: public StmtVisitor, ExprVisitor
+{
+ const DefUsesCalculator &defUses;
+ UntypedTemp theTemp;
+ DiscoveredType newType;
+
+public:
+ PropagateTempTypes(const DefUsesCalculator &defUses)
+ : defUses(defUses)
+ {}
+
+ void run(const UntypedTemp &temp, const DiscoveredType &type)
+ {
+ newType = type;
+ theTemp = temp;
+ if (Stmt *defStmt = defUses.defStmt(temp))
+ defStmt->accept(this);
+ foreach (Stmt *use, defUses.uses(temp))
+ use->accept(this);
+ }
+
+protected:
+ virtual void visitConst(Const *) {}
+ virtual void visitString(String *) {}
+ virtual void visitRegExp(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 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);
+ }
+
+ 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->d->incoming)
+ e->accept(this);
+ }
+};
+
class TypeInference: public StmtVisitor, public ExprVisitor {
+ QQmlEnginePrivate *qmlEngine;
bool _variablesCanEscape;
const DefUsesCalculator &_defUses;
- QHash<Temp, int> _tempTypes;
+ QHash<Temp, DiscoveredType> _tempTypes;
QSet<Stmt *> _worklist;
struct TypingResult {
- int type;
+ DiscoveredType type;
bool fullyTyped;
- TypingResult(int type, bool fullyTyped): type(type), fullyTyped(fullyTyped) {}
- explicit TypingResult(int type = UnknownType): type(type), fullyTyped(type != UnknownType) {}
+ TypingResult(const DiscoveredType &type = DiscoveredType()) : type(type), fullyTyped(type.type != UnknownType) {}
+ explicit TypingResult(MemberExpressionResolver memberResolver): type(memberResolver), fullyTyped(true) {}
};
TypingResult _ty;
public:
- TypeInference(const DefUsesCalculator &defUses)
- : _defUses(defUses)
+ TypeInference(QQmlEnginePrivate *qmlEngine, const DefUsesCalculator &defUses)
+ : qmlEngine(qmlEngine)
+ , _defUses(defUses)
, _ty(UnknownType)
{}
@@ -1329,74 +1596,12 @@ public:
}
}
- PropagateTempTypes(_tempTypes).run(function);
+ PropagateTempTypes propagator(_defUses);
+ for (QHash<Temp, DiscoveredType>::const_iterator i = _tempTypes.begin(), ei = _tempTypes.end(); i != ei; ++i)
+ propagator.run(i.key(), i.value());
}
private:
- class PropagateTempTypes: public StmtVisitor, ExprVisitor
- {
- public:
- PropagateTempTypes(const QHash<Temp, int> &tempTypes)
- : _tempTypes(tempTypes)
- {}
-
- void run(Function *function)
- {
- foreach (BasicBlock *bb, function->basicBlocks)
- foreach (Stmt *s, bb->statements)
- s->accept(this);
- }
-
- protected:
- virtual void visitConst(Const *) {}
- virtual void visitString(String *) {}
- virtual void visitRegExp(RegExp *) {}
- virtual void visitName(Name *) {}
- virtual void visitTemp(Temp *e) { e->type = (Type) _tempTypes[*e]; }
- 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);
- }
-
- 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->d->incoming)
- e->accept(this);
- }
-
- private:
- QHash<Temp, int> _tempTypes;
- };
-
-private:
bool run(Stmt *s) {
TypingResult ty;
std::swap(_ty, ty);
@@ -1416,26 +1621,29 @@ private:
return ty;
}
- bool isAlwaysAnObject(Temp *t) {
+ bool isAlwaysVar(Temp *t) {
switch (t->kind) {
case Temp::Formal:
case Temp::ScopedFormal:
case Temp::ScopedLocal:
+ t->type = VarType;
return true;
case Temp::Local:
+ if (_variablesCanEscape)
+ t->type = VarType;
return _variablesCanEscape;
default:
return false;
}
}
- void setType(Expr *e, int ty) {
+ void setType(Expr *e, DiscoveredType ty) {
if (Temp *t = e->asTemp()) {
#if defined(SHOW_SSA)
qout<<"Setting type for "<< (t->scope?"scoped temp ":"temp ") <<t->index<< " to "<<typeName(Type(ty)) << " (" << ty << ")" << endl;
#endif
- if (isAlwaysAnObject(t))
- ty = VarType;
+ if (isAlwaysVar(t))
+ ty = DiscoveredType(VarType);
if (_tempTypes[*t] != ty) {
_tempTypes[*t] = ty;
@@ -1450,7 +1658,7 @@ private:
_worklist += QSet<Stmt *>::fromList(_defUses.uses(*t));
}
} else {
- e->type = (Type) ty;
+ e->type = (Type) ty.type;
}
}
@@ -1470,10 +1678,12 @@ protected:
virtual void visitRegExp(RegExp *) { _ty = TypingResult(VarType); }
virtual void visitName(Name *) { _ty = TypingResult(VarType); }
virtual void visitTemp(Temp *e) {
- if (isAlwaysAnObject(e))
+ if (isAlwaysVar(e))
_ty = TypingResult(VarType);
+ else if (e->memberResolver.isValid())
+ _ty = TypingResult(e->memberResolver);
else
- _ty = TypingResult(_tempTypes.value(*e, UnknownType));
+ _ty = TypingResult(_tempTypes.value(*e));
setType(e, _ty.type);
}
virtual void visitClosure(Closure *) { _ty = TypingResult(VarType); }
@@ -1505,9 +1715,9 @@ protected:
switch (e->op) {
case OpAdd:
- if (leftTy.type & VarType || rightTy.type & VarType)
+ if (leftTy.type.test(VarType) || leftTy.type.test(QObjectType) || rightTy.type.test(VarType) || rightTy.type.test(QObjectType))
_ty.type = VarType;
- else if (leftTy.type & StringType || rightTy.type & StringType)
+ else if (leftTy.type.test(StringType) || rightTy.type.test(StringType))
_ty.type = StringType;
else if (leftTy.type != UnknownType && rightTy.type != UnknownType)
_ty.type = DoubleType;
@@ -1574,14 +1784,13 @@ protected:
}
virtual void visitMember(Member *e) {
- if (e->type == Member::MemberOfQObject
- && !e->property->isEnum() // Enums need to go through run-time getters/setters to ensure correct string handling.
- ) {
- _ty = TypingResult(irTypeFromPropertyType(e->property->propType));
- return;
- }
_ty = run(e->base);
- _ty.type = VarType;
+
+ if (_ty.fullyTyped && _ty.type.memberResolver.isValid()) {
+ MemberExpressionResolver &resolver = _ty.type.memberResolver;
+ _ty.type.type = resolver.resolveMember(qmlEngine, &resolver, e);
+ } else
+ _ty.type = VarType;
}
virtual void visitExp(Exp *s) { _ty = run(s->expr); }
@@ -1611,11 +1820,13 @@ protected:
_ty.fullyTyped = false;
break;
}
- _ty.type |= ty.type;
+ _ty.type.type |= ty.type.type;
_ty.fullyTyped &= ty.fullyTyped;
+ if (_ty.type.test(QObjectType))
+ _ty.type.memberResolver.clear(); // ### TODO: find common ancestor meta-object
}
- switch (_ty.type) {
+ switch (_ty.type.type) {
case UnknownType:
case UndefinedType:
case NullType:
@@ -1624,13 +1835,14 @@ protected:
case UInt32Type:
case DoubleType:
case StringType:
+ case QObjectType:
case VarType:
// The type is not a combination of two or more types, so we're done.
break;
default:
// There are multiple types involved, so:
- if ((_ty.type & NumberType) && !(_ty.type & ~NumberType))
+ if (_ty.type.isNumber())
// The type is any combination of double/int32/uint32, but nothing else. So we can
// type it as double.
_ty.type = DoubleType;
@@ -1641,17 +1853,146 @@ protected:
setType(s->targetTemp, _ty.type);
}
+};
+
+class ReverseInference
+{
+ const DefUsesCalculator &_defUses;
+ bool _variablesCanExcape;
+
+public:
+ ReverseInference(const DefUsesCalculator &defUses)
+ : _defUses(defUses)
+ {}
- static int irTypeFromPropertyType(int propType)
+ void run(Function *f)
{
- switch (propType) {
- case QMetaType::Bool: return BoolType;
- case QMetaType::Int: return SInt32Type;
- case QMetaType::Double: return DoubleType;
- case QMetaType::QString: return StringType;
- default: break;
+ _variablesCanExcape = f->variablesCanEscape();
+
+ QTextStream os(stderr, QIODevice::WriteOnly);
+
+ QVector<UntypedTemp> knownOk;
+ QList<UntypedTemp> candidates = _defUses.defsUntyped();
+ while (!candidates.isEmpty()) {
+ UntypedTemp temp = candidates.last();
+ candidates.removeLast();
+
+ if (knownOk.contains(temp))
+ continue;
+
+ if (!isUsedAsInt32(temp, knownOk))
+ continue;
+
+ Stmt *s = _defUses.defStmt(temp);
+ Move *m = s->asMove();
+ if (!m)
+ continue;
+ Temp *target = m->target->asTemp();
+ if (!target || temp != UntypedTemp(*target) || target->type == SInt32Type)
+ continue;
+ if (Temp *t = m->source->asTemp()) {
+ candidates.append(*t);
+ } else if (m->source->asConvert()) {
+ break;
+ } else if (Binop *b = m->source->asBinop()) {
+ switch (b->op) {
+ case OpAdd:
+ if (b->left->type & NumberType || b->right->type & NumberType)
+ break;
+ else
+ continue;
+ case OpBitAnd:
+ case OpBitOr:
+ case OpBitXor:
+ case OpSub:
+ case OpMul:
+ case OpLShift:
+ case OpRShift:
+ case OpURShift:
+ break;
+ default:
+ continue;
+ }
+ if (Temp *lt = unescapableTemp(b->left, _variablesCanExcape))
+ candidates.append(*lt);
+ if (Temp *rt = unescapableTemp(b->right, _variablesCanExcape))
+ candidates.append(*rt);
+ } else if (Unop *u = m->source->asUnop()) {
+ if (u->op == OpCompl || u->op == OpUPlus) {
+ if (Temp *t = unescapableTemp(u->expr, _variablesCanExcape))
+ candidates.append(*t);
+ }
+ } else {
+ continue;
+ }
+
+ knownOk.append(temp);
+ }
+
+ PropagateTempTypes propagator(_defUses);
+ foreach (const UntypedTemp &t, knownOk) {
+ propagator.run(t, SInt32Type);
+ if (Stmt *defStmt = _defUses.defStmt(t)) {
+ if (Move *m = defStmt->asMove()) {
+ if (Convert *c = m->source->asConvert())
+ c->type = SInt32Type;
+ else if (Unop *u = m->source->asUnop())
+ u->type = SInt32Type;
+ else if (Binop *b = m->source->asBinop())
+ b->type = SInt32Type;
+ }
+ }
+ }
+ }
+
+private:
+ bool isUsedAsInt32(const UntypedTemp &t, const QVector<UntypedTemp> &knownOk) const
+ {
+ QList<Stmt *> uses = _defUses.uses(t);
+ if (uses.isEmpty())
+ return false;
+
+ foreach (Stmt *use, uses) {
+ if (Move *m = use->asMove()) {
+ Temp *targetTemp = m->target->asTemp();
+
+ if (m->source->asTemp()) {
+ if (!targetTemp || !knownOk.contains(*targetTemp))
+ return false;
+ } else if (m->source->asConvert()) {
+ continue;
+ } else if (Binop *b = m->source->asBinop()) {
+ switch (b->op) {
+ case OpAdd:
+ case OpSub:
+ case OpMul:
+ if (!targetTemp || !knownOk.contains(*targetTemp))
+ return false;
+ case OpBitAnd:
+ case OpBitOr:
+ case OpBitXor:
+ case OpRShift:
+ case OpLShift:
+ case OpURShift:
+ continue;
+ default:
+ return false;
+ }
+ } else if (Unop *u = m->source->asUnop()) {
+ if (u->op == OpUPlus) {
+ if (!targetTemp || !knownOk.contains(*targetTemp))
+ return false;
+ } else if (u->op != OpCompl) {
+ return false;
+ }
+ } else {
+ return false;
+ }
+ } else
+ return false;
}
- return VarType;
+
+ return true;
}
};
@@ -1884,12 +2225,8 @@ protected:
}
}
- // Don't convert when writing to QObject properties. All sorts of extra behavior
- // is defined when writing to them, for example resettable properties are reset
- // when writing undefined to them, and an exception is thrown when they're missing
- // a reset function.
const Member *targetMember = s->target->asMember();
- const bool inhibitConversion = targetMember && targetMember->type == Member::MemberOfQObject && targetMember->property;
+ const bool inhibitConversion = targetMember && targetMember->inhibitTypeConversionOnWrite;
run(s->source, s->target->type, !inhibitConversion);
}
@@ -1964,7 +2301,7 @@ QHash<BasicBlock *, BasicBlock *> scheduleBlocks(Function *function, const Domin
QSet<BasicBlock *> visited;
QVector<BasicBlock *> &sequence;
BasicBlock *currentGroup;
- QList<BasicBlock *> postponed;
+ QSet<BasicBlock *> postponed;
I(const DominatorTree &df, QVector<BasicBlock *> &sequence,
QHash<BasicBlock *, BasicBlock *> &startEndLoops)
@@ -1980,7 +2317,7 @@ QHash<BasicBlock *, BasicBlock *> scheduleBlocks(Function *function, const Domin
return;
if (bb->containingGroup() != currentGroup) {
- postponed.append(bb);
+ postponed.insert(bb);
return;
}
if (bb->isGroupStart())
@@ -2013,7 +2350,7 @@ QHash<BasicBlock *, BasicBlock *> scheduleBlocks(Function *function, const Domin
if (bb->isGroupStart()) {
currentGroup = bb->containingGroup();
startEndLoops.insert(bb, sequence.last());
- QList<BasicBlock *> p = postponed;
+ QSet<BasicBlock *> p = postponed;
foreach (BasicBlock *pBB, p)
DFS(pBB);
}
@@ -2022,7 +2359,7 @@ QHash<BasicBlock *, BasicBlock *> scheduleBlocks(Function *function, const Domin
void layout(BasicBlock *bb) {
sequence.append(bb);
visited.insert(bb);
- postponed.removeAll(bb);
+ postponed.remove(bb);
}
};
@@ -2259,22 +2596,6 @@ private:
}
};
-inline Temp *unescapableTemp(Expr *e, bool variablesCanEscape)
-{
- Temp *t = e->asTemp();
- if (!t)
- return 0;
-
- switch (t->kind) {
- case Temp::VirtualRegister:
- return t;
- case Temp::Local:
- return variablesCanEscape ? 0 : t;
- default:
- return 0;
- }
-}
-
namespace {
/// This function removes the basic-block from the function's list, unlinks any uses and/or defs,
/// and removes unreachable staements from the worklist, so that optimiseSSA won't consider them
@@ -2356,10 +2677,10 @@ bool tryOptimizingComparison(Expr *&expr)
if (!b)
return false;
Const *leftConst = b->left->asConst();
- if (!leftConst || leftConst->type == StringType || leftConst->type == VarType)
+ if (!leftConst || leftConst->type == StringType || leftConst->type == VarType || leftConst->type == QObjectType)
return false;
Const *rightConst = b->right->asConst();
- if (!rightConst || rightConst->type == StringType || rightConst->type == VarType)
+ if (!rightConst || rightConst->type == StringType || rightConst->type == VarType || rightConst->type == QObjectType)
return false;
QV4::Primitive l = convertToValue(leftConst);
@@ -2494,6 +2815,26 @@ void optimizeSSA(Function *function, DefUsesCalculator &defUses)
}
continue;
}
+ if (Member *member = m->source->asMember()) {
+ if (member->kind == Member::MemberOfEnum) {
+ Const *c = function->New<Const>();
+ const int enumValue = member->attachedPropertiesIdOrEnumValue;
+ c->init(SInt32Type, enumValue);
+ W += replaceUses(targetTemp, c);
+ defUses.removeDef(*targetTemp);
+ *ref[s] = 0;
+ defUses.removeUse(s, *member->base->asTemp());
+ continue;
+ } else if (member->attachedPropertiesIdOrEnumValue != 0 && member->property && member->base->asTemp()) {
+ // Attached properties have no dependency on their base. Isel doesn't
+ // need it and we can eliminate the temp used to initialize it.
+ defUses.removeUse(s, *member->base->asTemp());
+ Const *c = function->New<Const>();
+ c->init(SInt32Type, 0);
+ member->base = c;
+ continue;
+ }
+ }
// copy propagation:
if (Temp *sourceTemp = unescapableTemp(m->source, variablesCanEscape)) {
@@ -2533,7 +2874,7 @@ void optimizeSSA(Function *function, DefUsesCalculator &defUses)
doneSomething = true;
break;
case OpUPlus:
- constOperand->type = DoubleType;
+ constOperand->type = unop->type;
doneSomething = true;
break;
case OpCompl:
@@ -2566,14 +2907,41 @@ void optimizeSSA(Function *function, DefUsesCalculator &defUses)
}
if (Binop *binop = m->source->asBinop()) {
+ Const *leftConst = binop->left->asConst();
+ Const *rightConst = binop->right->asConst();
+
+ { // Typical casts to int32:
+ Expr *casted = 0;
+ switch (binop->op) {
+ case OpBitAnd:
+ if (leftConst && !rightConst && leftConst->value == 0xffffffff)
+ casted = rightConst;
+ else if (!leftConst && rightConst && rightConst->value == 0xffffffff)
+ casted = leftConst;
+ break;
+ case OpBitOr:
+ if (leftConst && !rightConst && leftConst->value == 0)
+ casted = rightConst;
+ else if (!leftConst && rightConst && rightConst->value == 0)
+ casted = leftConst;
+ break;
+ default:
+ break;
+ }
+ if (casted) {
+ Q_ASSERT(casted->type == SInt32Type);
+ m->source = casted;
+ W += m;
+ continue;
+ }
+ }
+
// TODO: More constant binary expression evaluation
// TODO: If the result of the move is only used in one single cjump, then
// inline the binop into the cjump.
- Const *leftConst = binop->left->asConst();
- if (!leftConst || leftConst->type == StringType || leftConst->type == VarType)
+ if (!leftConst || leftConst->type == StringType || leftConst->type == VarType || leftConst->type == QObjectType)
continue;
- Const *rightConst = binop->right->asConst();
- if (!rightConst || rightConst->type == StringType || rightConst->type == VarType)
+ if (!rightConst || rightConst->type == StringType || rightConst->type == VarType || rightConst->type == QObjectType)
continue;
QV4::Primitive lc = convertToValue(leftConst);
@@ -2957,7 +3325,7 @@ bool LifeTimeInterval::lessThanForTemp(const LifeTimeInterval &r1, const LifeTim
return r1.temp() < r2.temp();
}
-void Optimizer::run()
+void Optimizer::run(QQmlEnginePrivate *qmlEngine)
{
#if defined(SHOW_SSA)
qout << "##### NOW IN FUNCTION " << (function->name ? qPrintable(*function->name) : "anonymous!")
@@ -2976,10 +3344,9 @@ void Optimizer::run()
// showMeTheCode(function);
static bool doSSA = qgetenv("QV4_NO_SSA").isEmpty();
- static bool doOpt = qgetenv("QV4_NO_OPT").isEmpty();
if (!function->hasTry && !function->hasWith && !function->module->debugMode && doSSA) {
-// qout << "SSA for " << *function->name << endl;
+// qout << "SSA for " << (function->name ? qPrintable(*function->name) : "<anonymous>") << endl;
// qout << "Starting edge splitting..." << endl;
splitCriticalEdges(function);
// showMeTheCode(function);
@@ -2999,13 +3366,18 @@ void Optimizer::run()
// showMeTheCode(function);
// qout << "Running type inference..." << endl;
- TypeInference(defUses).run(function);
+ TypeInference(qmlEngine, defUses).run(function);
+// showMeTheCode(function);
+
+// qout << "Doing reverse inference..." << endl;
+ ReverseInference(defUses).run(function);
// showMeTheCode(function);
// qout << "Doing type propagation..." << endl;
TypePropagation(defUses).run(function);
// showMeTheCode(function);
+ static bool doOpt = qgetenv("QV4_NO_OPT").isEmpty();
if (doOpt) {
// qout << "Running SSA optimization..." << endl;
optimizeSSA(function, defUses);
diff --git a/src/qml/compiler/qv4ssa_p.h b/src/qml/compiler/qv4ssa_p.h
index aa713d3fec..dcbc83ae65 100644
--- a/src/qml/compiler/qv4ssa_p.h
+++ b/src/qml/compiler/qv4ssa_p.h
@@ -46,6 +46,7 @@
QT_BEGIN_NAMESPACE
class QTextStream;
+class QQmlEnginePrivate;
namespace QQmlJS {
namespace V4IR {
@@ -129,7 +130,7 @@ public:
, inSSA(false)
{}
- void run();
+ void run(QQmlEnginePrivate *qmlEngine);
void convertOutOfSSA();
bool isInSSA() const
diff --git a/src/qml/debugger/qqmlprofilerservice.cpp b/src/qml/debugger/qqmlprofilerservice.cpp
index 0ba939cdca..b83de937c6 100644
--- a/src/qml/debugger/qqmlprofilerservice.cpp
+++ b/src/qml/debugger/qqmlprofilerservice.cpp
@@ -425,4 +425,204 @@ void QQmlProfilerService::messageReceived(const QByteArray &message)
m_initializeCondition.wakeAll();
}
+/*!
+ * \brief QQmlVmeProfiler::Data::clear Reset to defaults
+ * Reset the profiling data to defaults.
+ */
+void QQmlVmeProfiler::Data::clear()
+{
+ url = QUrl();
+ line = 0;
+ column = 0;
+ typeName = QString();
+}
+
+/*!
+ * \brief QQmlVmeProfiler::start Start profiler and set data
+ * \param url URL of file being executed
+ * \param line Curent line in file
+ * \param column Current column in file
+ * \param typeName Type of object be created
+ * Stops the profiler previously running in the foreground if there is one, then starts a
+ * new one and sets it up with the data given.
+ * Preconditions: Profiling must be enabled.
+ */
+void QQmlVmeProfiler::start(const QUrl &url, int line, int column, const QString &typeName)
+{
+ Q_ASSERT_X(enabled, Q_FUNC_INFO, "method called although profiler is not enabled.");
+ if (enabled) {
+ switchRange();
+ updateLocation(url, line, column);
+ updateTypeName(typeName);
+ }
+}
+
+/*!
+ * \brief QQmlVmeProfiler::start Start profiler without data
+ * Clears the current range data, then stops the profiler previously running in the
+ * foreground if any, then starts a new one.
+ * Preconditions: Profiling must be enabled.
+ */
+void QQmlVmeProfiler::start()
+{
+ Q_ASSERT_X(enabled, Q_FUNC_INFO, "method called although profiler is not enabled.");
+ if (enabled) {
+ currentRange.clear();
+ switchRange();
+ }
+}
+
+/*!
+ * \brief QQmlVmeProfiler::switchRange Switch foreground profilers
+ * Stops the current profiler if any, and starts a new one.
+ */
+void QQmlVmeProfiler::switchRange()
+{
+ if (running)
+ QQmlProfilerService::instance->endRange(QQmlProfilerService::Creating);
+ else
+ running = true;
+ QQmlProfilerService::instance->startRange(QQmlProfilerService::Creating);
+}
+
+/*!
+ * \brief QQmlVmeProfiler::updateLocation Update current location information
+ * \param url URL of file being executed
+ * \param line line Curent line in file
+ * \param column column Current column in file
+ * Updates the current profiler's location information.
+ * Preconditions: Profiling must be enabled and a profiler must be running in the foreground.
+ */
+void QQmlVmeProfiler::updateLocation(const QUrl &url, int line, int column)
+{
+ Q_ASSERT_X(enabled, Q_FUNC_INFO, "method called although profiler is not enabled.");
+ Q_ASSERT_X(running, Q_FUNC_INFO, "trying to update location on stopped profiler");
+ if (enabled && running) {
+ currentRange.url = url;
+ currentRange.line = line;
+ currentRange.column = column;
+ QQmlProfilerService::instance->rangeLocation(
+ QQmlProfilerService::Creating, url, line, column);
+ }
+}
+
+/*!
+ * \brief QQmlVmeProfiler::updateTypeName Update current type information
+ * \param typeName Type of object being created
+ * Updates the current profiler's type information.
+ * Preconditions: Profiling must be enabled and a profiler must be running in the foreground.
+ */
+void QQmlVmeProfiler::updateTypeName(const QString &typeName)
+{
+ Q_ASSERT_X(enabled, Q_FUNC_INFO, "method called although profiler is not enabled.");
+ Q_ASSERT_X(running, Q_FUNC_INFO, "trying to update typeName on stopped profiler");
+ if (enabled && running) {
+ currentRange.typeName = typeName;
+ QQmlProfilerService::instance->rangeData(QQmlProfilerService::Creating, typeName);
+ }
+}
+
+/*!
+ * \brief QQmlVmeProfiler::pop Pops a paused profiler from the stack and restarts it
+ * Stops the currently running profiler, if any, then retrieves an old one from the stack
+ * of paused profilers and starts that.
+ * Preconditions: Profiling must be enabled and there must be at least one profiler on the
+ * stack.
+ */
+void QQmlVmeProfiler::pop()
+{
+ Q_ASSERT_X(enabled, Q_FUNC_INFO, "method called although profiler is not enabled.");
+ Q_ASSERT_X(ranges.count() > 0, Q_FUNC_INFO, "trying to pop an invalid profiler");
+ if (enabled && ranges.count() > 0) {
+ start();
+ currentRange = ranges.pop();
+ QQmlProfilerService::instance->rangeLocation(
+ QQmlProfilerService::Creating, currentRange.url, currentRange.line, currentRange.column);
+ QQmlProfilerService::instance->rangeData(QQmlProfilerService::Creating, currentRange.typeName);
+ }
+}
+
+/*!
+ * \brief QQmlVmeProfiler::push Pushes the currently running profiler on the stack.
+ * Pushes the currently running profiler on the stack of paused profilers. Note: The profiler
+ * isn't paused here. That's a separate step. If it's never paused, but pop()'ed later that
+ * won't do any harm, though.
+ * Preconditions: Profiling must be enabled and a profiler must be running in the foreground.
+ */
+void QQmlVmeProfiler::push()
+{
+ Q_ASSERT_X(enabled, Q_FUNC_INFO, "method called although profiler is not enabled.");
+ Q_ASSERT_X(running, Q_FUNC_INFO, "trying to push stopped profiler");
+ if (enabled && running)
+ ranges.push(currentRange);
+}
+
+/*!
+ * \brief QQmlVmeProfiler::clear Stop all running profilers and clear all data.
+ * Stops the currently running (foreground and background) profilers and removes all saved
+ * data about paused profilers.
+ * Precondtions: Profiling must be enabled.
+ */
+void QQmlVmeProfiler::clear()
+{
+ Q_ASSERT_X(enabled, Q_FUNC_INFO, "method called although profiler is not enabled.");
+ if (enabled) {
+ stop();
+ ranges.clear();
+ for (int i = 0; i < backgroundRanges.count(); ++i) {
+ QQmlProfilerService::instance->endRange(QQmlProfilerService::Creating);
+ }
+ backgroundRanges.clear();
+ }
+}
+
+/*!
+ * \brief QQmlVmeProfiler::stop Stop profiler running in the foreground, if any.
+ * Precondition: Profiling must be enabled.
+ */
+void QQmlVmeProfiler::stop()
+{
+ Q_ASSERT_X(enabled, Q_FUNC_INFO, "method called although profiler is not enabled.");
+ if (enabled && running) {
+ QQmlProfilerService::instance->endRange(QQmlProfilerService::Creating);
+ currentRange.clear();
+ running = false;
+ }
+}
+
+/*!
+ * \brief QQmlVmeProfiler::background Push the current profiler to the background.
+ * Push the profiler currently running in the foreground to the background so that it
+ * won't be stopped by stop() or start(). There can be multiple profilers in the background.
+ * You can retrieve them in reverse order by calling foreground().
+ * Precondition: Profiling must be enabled and a profiler must be running in the foreground.
+ */
+void QQmlVmeProfiler::background()
+{
+ Q_ASSERT_X(enabled, Q_FUNC_INFO, "method called although profiler is not enabled.");
+ Q_ASSERT_X(running, Q_FUNC_INFO, "trying to push stopped profiler to the background.");
+ if (enabled && running) {
+ backgroundRanges.push(currentRange);
+ running = false;
+ }
+}
+
+/*!
+ * \brief QQmlVmeProfiler::foreground Retrieve a profiler from the background
+ * Stop the profiler currently running in the foreground, if any and put the next profiler
+ * from the background in its place.
+ * Preconditions: Profiling must be enabled and there must be at least one profiler in the
+ * background.
+ */
+void QQmlVmeProfiler::foreground()
+{
+ Q_ASSERT_X(enabled, Q_FUNC_INFO, "method called although profiler is not enabled.");
+ Q_ASSERT_X(backgroundRanges.count() > 0, Q_FUNC_INFO, "trying to foreground stopped profiler.");
+ if (enabled && backgroundRanges.count() > 0) {
+ stop();
+ currentRange = backgroundRanges.pop();
+ running = true;
+ }
+}
+
QT_END_NAMESPACE
diff --git a/src/qml/debugger/qqmlprofilerservice_p.h b/src/qml/debugger/qqmlprofilerservice_p.h
index fb08a30c6a..5959a526bb 100644
--- a/src/qml/debugger/qqmlprofilerservice_p.h
+++ b/src/qml/debugger/qqmlprofilerservice_p.h
@@ -225,7 +225,7 @@ private:
friend struct QQmlBindingProfiler;
friend struct QQmlHandlingSignalProfiler;
- friend struct QQmlObjectCreatingProfiler;
+ friend struct QQmlVmeProfiler;
friend struct QQmlCompilingProfiler;
friend struct QQmlPixmapProfiler;
};
@@ -277,40 +277,6 @@ struct QQmlHandlingSignalProfiler {
bool enabled;
};
-struct QQmlObjectCreatingProfiler {
- QQmlObjectCreatingProfiler()
- {
- enabled = QQmlProfilerService::instance
- ? QQmlProfilerService::instance->profilingEnabled() : false;
- if (enabled) {
- QQmlProfilerService *service = QQmlProfilerService::instance;
- service->startRange(QQmlProfilerService::Creating);
- }
- }
-
- void setTypeName(const QString &typeName)
- {
- Q_ASSERT_X(enabled, Q_FUNC_INFO, "method called although profiler is not enabled.");
- QQmlProfilerService::instance->rangeData(QQmlProfilerService::Creating, typeName);
- }
-
- void setLocation(const QUrl &url, int line, int column)
- {
- Q_ASSERT_X(enabled, Q_FUNC_INFO, "method called although profiler is not enabled.");
- if (enabled)
- QQmlProfilerService::instance->rangeLocation(
- QQmlProfilerService::Creating, url, line, column);
- }
-
- ~QQmlObjectCreatingProfiler()
- {
- if (enabled)
- QQmlProfilerService::instance->endRange(QQmlProfilerService::Creating);
- }
-
- bool enabled;
-};
-
struct QQmlCompilingProfiler {
QQmlCompilingProfiler(const QString &name)
{
@@ -333,6 +299,54 @@ struct QQmlCompilingProfiler {
bool enabled;
};
+struct QQmlVmeProfiler {
+public:
+ const bool enabled;
+
+ struct Data {
+ Data() : line(0), column(0) {}
+ QUrl url;
+ int line;
+ int column;
+ QString typeName;
+ void clear();
+ };
+
+ QQmlVmeProfiler() :
+ enabled(QQmlProfilerService::instance ? QQmlProfilerService::instance->profilingEnabled() : false),
+ running(false)
+ {}
+
+ ~QQmlVmeProfiler()
+ {
+ if (enabled)
+ clear();
+ }
+
+ void clear();
+
+ void start(const QUrl &url, int line, int column, const QString &typeName);
+ void start();
+ void stop();
+
+ void updateLocation(const QUrl &url, int line, int column);
+ void updateTypeName(const QString &typeName);
+
+ void pop();
+ void push();
+
+ void background();
+ void foreground();
+
+private:
+ void switchRange();
+
+ Data currentRange;
+ QStack<Data> ranges;
+ QStack<Data> backgroundRanges;
+ bool running;
+};
+
struct QQmlPixmapProfiler {
QQmlPixmapProfiler() {
QQmlProfilerService *instance = QQmlProfilerService::instance;
@@ -367,9 +381,9 @@ struct QQmlPixmapProfiler {
QQmlProfilerService::instance->pixmapEventImpl(QQmlProfilerService::PixmapReferenceCountChanged, pixmapUrl, referenceCount);
}
}
- void setSize(const QUrl &pixmapUrl, int width, int height) {
- if (enabled) {
- QQmlProfilerService::instance->pixmapEventImpl(QQmlProfilerService::PixmapSizeKnown, pixmapUrl, width, height);
+ void setSize(const QUrl &pixmapUrl, const QSize &size) {
+ if (enabled && size.width() > 0) {
+ QQmlProfilerService::instance->pixmapEventImpl(QQmlProfilerService::PixmapSizeKnown, pixmapUrl, size.width(), size.height());
}
}
diff --git a/src/qml/debugger/qv4debugservice.cpp b/src/qml/debugger/qv4debugservice.cpp
index 400bb18edd..372a51e997 100644
--- a/src/qml/debugger/qv4debugservice.cpp
+++ b/src/qml/debugger/qv4debugservice.cpp
@@ -432,7 +432,7 @@ public:
QJsonArray scopes;
// Only type and index are used by Qt Creator, so we keep it easy:
- QVector<QV4::ExecutionContext::Type> scopeTypes = debugger->getScopeTypes(frameNr);
+ QVector<QV4::ExecutionContext::ContextType> scopeTypes = debugger->getScopeTypes(frameNr);
for (int i = 0, ei = scopeTypes.count(); i != ei; ++i) {
int type = encodeScopeType(scopeTypes[i]);
if (type == -1)
@@ -448,7 +448,7 @@ public:
return frame;
}
- int encodeScopeType(QV4::ExecutionContext::Type scopeType)
+ int encodeScopeType(QV4::ExecutionContext::ContextType scopeType)
{
switch (scopeType) {
case QV4::ExecutionContext::Type_GlobalContext:
@@ -480,7 +480,7 @@ public:
QJsonObject anonymous;
anonymous[QLatin1String("properties")] = properties;
- QVector<QV4::ExecutionContext::Type> scopeTypes = debugger->getScopeTypes(frameNr);
+ QVector<QV4::ExecutionContext::ContextType> scopeTypes = debugger->getScopeTypes(frameNr);
scope[QLatin1String("type")] = encodeScopeType(scopeTypes[scopeNr]);
scope[QLatin1String("index")] = scopeNr;
scope[QLatin1String("frameIndex")] = frameNr;
@@ -619,7 +619,7 @@ public:
addRunning();
QJsonObject body;
body.insert(QStringLiteral("V8Version"),
- QStringLiteral("this is not V8, this is V4 in Qt %1").arg(QLatin1String(QT_VERSION_STR)));
+ QLatin1String("this is not V8, this is V4 in Qt " QT_VERSION_STR));
addBody(body);
}
};
diff --git a/src/qml/jsapi/qjsengine.cpp b/src/qml/jsapi/qjsengine.cpp
index 5d8a0202fa..a19c358231 100644
--- a/src/qml/jsapi/qjsengine.cpp
+++ b/src/qml/jsapi/qjsengine.cpp
@@ -49,6 +49,7 @@
#include "private/qv4mm_p.h"
#include "private/qv4globalobject_p.h"
#include "private/qv4script_p.h"
+#include "private/qv4runtime_p.h"
#include <QtCore/qdatetime.h>
#include <QtCore/qmetaobject.h>
@@ -260,7 +261,7 @@ void QJSEngine::collectGarbage()
QJSValue QJSEngine::evaluate(const QString& program, const QString& fileName, int lineNumber)
{
QV4::Scope scope(d->m_v4Engine);
- QV4::ExecutionContext *ctx = d->m_v4Engine->current;
+ QV4::ExecutionContext *ctx = d->m_v4Engine->currentContext();
QV4::ScopedValue result(scope);
QV4::Script script(ctx, program, fileName, lineNumber);
@@ -376,6 +377,54 @@ bool QJSEngine::convertV2(const QJSValue &value, int type, void *ptr)
QV4::Scope scope(engine->m_v4Engine);
QV4::ScopedValue v(scope, vp->getValue(engine->m_v4Engine));
return engine->metaTypeFromJS(v, type, ptr);
+ } else if (vp->value.isEmpty()) {
+ // have a string based value without engine. Do conversion manually
+ if (type == QMetaType::Bool) {
+ *reinterpret_cast<bool*>(ptr) = vp->string.length() != 0;
+ return true;
+ }
+ if (type == QMetaType::QString) {
+ *reinterpret_cast<QString*>(ptr) = vp->string;
+ return true;
+ }
+ double d = QV4::__qmljs_string_to_number(vp->string);
+ switch (type) {
+ case QMetaType::Int:
+ *reinterpret_cast<int*>(ptr) = QV4::Primitive::toInt32(d);
+ return true;
+ case QMetaType::UInt:
+ *reinterpret_cast<uint*>(ptr) = QV4::Primitive::toUInt32(d);
+ return true;
+ case QMetaType::LongLong:
+ *reinterpret_cast<qlonglong*>(ptr) = QV4::Primitive::toInteger(d);
+ return true;
+ case QMetaType::ULongLong:
+ *reinterpret_cast<qulonglong*>(ptr) = QV4::Primitive::toInteger(d);
+ return true;
+ case QMetaType::Double:
+ *reinterpret_cast<double*>(ptr) = d;
+ return true;
+ case QMetaType::Float:
+ *reinterpret_cast<float*>(ptr) = d;
+ return true;
+ case QMetaType::Short:
+ *reinterpret_cast<short*>(ptr) = QV4::Primitive::toInt32(d);
+ return true;
+ case QMetaType::UShort:
+ *reinterpret_cast<unsigned short*>(ptr) = QV4::Primitive::toUInt32(d);
+ return true;
+ case QMetaType::Char:
+ *reinterpret_cast<char*>(ptr) = QV4::Primitive::toInt32(d);
+ return true;
+ case QMetaType::UChar:
+ *reinterpret_cast<unsigned char*>(ptr) = QV4::Primitive::toUInt32(d);
+ return true;
+ case QMetaType::QChar:
+ *reinterpret_cast<QChar*>(ptr) = QV4::Primitive::toUInt32(d);
+ return true;
+ default:
+ return false;
+ }
} else {
switch (type) {
case QMetaType::Bool:
diff --git a/src/qml/jsapi/qjsvalue.cpp b/src/qml/jsapi/qjsvalue.cpp
index 4035fb9fa6..d7a1cef3ba 100644
--- a/src/qml/jsapi/qjsvalue.cpp
+++ b/src/qml/jsapi/qjsvalue.cpp
@@ -58,20 +58,22 @@
QV4::ReturnedValue QJSValuePrivate::getValue(QV4::ExecutionEngine *e)
{
- if (!this->engine)
+ if (!this->engine) {
this->engine = e;
- else if (this->engine != e) {
+ } else if (this->engine != e) {
qWarning("JSValue can't be reassigned to another engine.");
return QV4::Encode::undefined();
}
- if (value.asString() == &string) {
- value = QV4::Encode(engine->newString(string.toQString()));
+
+ if (value.isEmpty()) {
+ value = QV4::Encode(engine->newString(string));
PersistentValuePrivate **listRoot = &engine->memoryManager->m_persistentValues;
prev = listRoot;
next = *listRoot;
*prev = this;
if (next)
next->prev = &this->next;
+ string = QString();
}
return value.asReturnedValue();
}
@@ -210,7 +212,7 @@ QJSValue::QJSValue(const QLatin1String &value)
*/
#ifndef QT_NO_CAST_FROM_ASCII
QJSValue::QJSValue(const char *value)
- : d(new QJSValuePrivate(QString::fromLatin1(value)))
+ : d(new QJSValuePrivate(QString::fromUtf8(value)))
{
}
#endif
@@ -275,7 +277,7 @@ bool QJSValue::isNull() const
*/
bool QJSValue::isString() const
{
- return d->value.isString();
+ return d->value.isEmpty() || d->value.isString();
}
/*!
@@ -359,6 +361,8 @@ bool QJSValue::isVariant() const
*/
QString QJSValue::toString() const
{
+ if (d->value.isEmpty())
+ return d->string;
return d->value.toQStringNoThrow();
}
@@ -376,7 +380,10 @@ QString QJSValue::toString() const
*/
double QJSValue::toNumber() const
{
- QV4::ExecutionContext *ctx = d->engine ? d->engine->current : 0;
+ if (d->value.isEmpty())
+ return __qmljs_string_to_number(d->string);
+
+ QV4::ExecutionContext *ctx = d->engine ? d->engine->currentContext() : 0;
double dbl = d->value.toNumber();
if (ctx && ctx->engine->hasException) {
ctx->catchException();
@@ -399,7 +406,10 @@ double QJSValue::toNumber() const
*/
bool QJSValue::toBool() const
{
- QV4::ExecutionContext *ctx = d->engine ? d->engine->current : 0;
+ if (d->value.isEmpty())
+ return d->string.length() > 0;
+
+ QV4::ExecutionContext *ctx = d->engine ? d->engine->currentContext() : 0;
bool b = d->value.toBoolean();
if (ctx && ctx->engine->hasException) {
ctx->catchException();
@@ -422,7 +432,10 @@ bool QJSValue::toBool() const
*/
qint32 QJSValue::toInt() const
{
- QV4::ExecutionContext *ctx = d->engine ? d->engine->current : 0;
+ if (d->value.isEmpty())
+ return QV4::Primitive::toInt32(__qmljs_string_to_number(d->string));
+
+ QV4::ExecutionContext *ctx = d->engine ? d->engine->currentContext() : 0;
qint32 i = d->value.toInt32();
if (ctx && ctx->engine->hasException) {
ctx->catchException();
@@ -445,7 +458,10 @@ qint32 QJSValue::toInt() const
*/
quint32 QJSValue::toUInt() const
{
- QV4::ExecutionContext *ctx = d->engine ? d->engine->current : 0;
+ if (d->value.isEmpty())
+ return QV4::Primitive::toUInt32(__qmljs_string_to_number(d->string));
+
+ QV4::ExecutionContext *ctx = d->engine ? d->engine->currentContext() : 0;
quint32 u = d->value.toUInt32();
if (ctx && ctx->engine->hasException) {
ctx->catchException();
@@ -478,6 +494,9 @@ quint32 QJSValue::toUInt() const
*/
QVariant QJSValue::toVariant() const
{
+ if (d->value.isEmpty())
+ return QVariant(d->string);
+
return QV4::VariantObject::toVariant(d->value);
}
@@ -517,7 +536,7 @@ QJSValue QJSValue::call(const QJSValueList &args)
}
ScopedValue result(scope);
- QV4::ExecutionContext *ctx = engine->current;
+ QV4::ExecutionContext *ctx = engine->currentContext();
result = f->call(callData);
if (scope.hasException())
result = ctx->catchException();
@@ -571,7 +590,7 @@ QJSValue QJSValue::callWithInstance(const QJSValue &instance, const QJSValueList
}
ScopedValue result(scope);
- QV4::ExecutionContext *ctx = engine->current;
+ QV4::ExecutionContext *ctx = engine->currentContext();
result = f->call(callData);
if (scope.hasException())
result = ctx->catchException();
@@ -617,7 +636,7 @@ QJSValue QJSValue::callAsConstructor(const QJSValueList &args)
}
ScopedValue result(scope);
- QV4::ExecutionContext *ctx = engine->current;
+ QV4::ExecutionContext *ctx = engine->currentContext();
result = f->construct(callData);
if (scope.hasException())
result = ctx->catchException();
@@ -720,6 +739,22 @@ QJSValue& QJSValue::operator=(const QJSValue& other)
return *this;
}
+static bool js_equal(const QString &string, QV4::ValueRef value)
+{
+ if (value->isString())
+ return string == value->stringValue()->toQString();
+ if (value->isNumber())
+ return __qmljs_string_to_number(string) == value->asDouble();
+ if (value->isBoolean())
+ return __qmljs_string_to_number(string) == value->booleanValue();
+ if (value->isObject()) {
+ Scope scope(value->objectValue()->engine());
+ ScopedValue p(scope, __qmljs_to_primitive(value, PREFERREDTYPE_HINT));
+ return js_equal(string, p);
+ }
+ return false;
+}
+
/*!
Returns true if this QJSValue is equal to \a other, otherwise
returns false. The comparison follows the behavior described in
@@ -746,6 +781,14 @@ QJSValue& QJSValue::operator=(const QJSValue& other)
*/
bool QJSValue::equals(const QJSValue& other) const
{
+ if (d->value.isEmpty()) {
+ if (other.d->value.isEmpty())
+ return d->string == other.d->string;
+ return js_equal(d->string, QV4::ValueRef(other.d->value));
+ }
+ if (other.d->value.isEmpty())
+ return other.equals(*this);
+
return __qmljs_cmp_eq(QV4::ValueRef(d), QV4::ValueRef(other.d));
}
@@ -773,6 +816,16 @@ bool QJSValue::equals(const QJSValue& other) const
*/
bool QJSValue::strictlyEquals(const QJSValue& other) const
{
+ if (d->value.isEmpty()) {
+ if (other.d->value.isEmpty())
+ return d->string == other.d->string;
+ if (other.d->value.isString())
+ return d->string == other.d->value.stringValue()->toQString();
+ return false;
+ }
+ if (other.d->value.isEmpty())
+ return other.strictlyEquals(*this);
+
return __qmljs_strict_equal(QV4::ValueRef(d), QV4::ValueRef(other.d));
}
@@ -806,7 +859,7 @@ QJSValue QJSValue::property(const QString& name) const
return property(idx);
s->makeIdentifier();
- QV4::ExecutionContext *ctx = engine->current;
+ QV4::ExecutionContext *ctx = engine->currentContext();
QV4::ScopedValue result(scope);
result = o->get(s);
if (scope.hasException())
@@ -838,7 +891,7 @@ QJSValue QJSValue::property(quint32 arrayIndex) const
if (!o)
return QJSValue();
- QV4::ExecutionContext *ctx = engine->current;
+ QV4::ExecutionContext *ctx = engine->currentContext();
QV4::ScopedValue result(scope);
result = arrayIndex == UINT_MAX ? o->get(engine->id_uintMax) : o->getIndexed(arrayIndex);
if (scope.hasException())
@@ -880,7 +933,7 @@ void QJSValue::setProperty(const QString& name, const QJSValue& value)
return;
}
- QV4::ExecutionContext *ctx = engine->current;
+ QV4::ExecutionContext *ctx = engine->currentContext();
s->makeIdentifier();
QV4::ScopedValue v(scope, value.d->getValue(engine));
o->put(s, v);
@@ -911,7 +964,7 @@ void QJSValue::setProperty(quint32 arrayIndex, const QJSValue& value)
if (!o)
return;
- QV4::ExecutionContext *ctx = engine->current;
+ QV4::ExecutionContext *ctx = engine->currentContext();
QV4::ScopedValue v(scope, value.d->getValue(engine));
if (arrayIndex != UINT_MAX)
o->putIndexed(arrayIndex, v);
@@ -944,7 +997,7 @@ void QJSValue::setProperty(quint32 arrayIndex, const QJSValue& value)
bool QJSValue::deleteProperty(const QString &name)
{
ExecutionEngine *engine = d->engine;
- ExecutionContext *ctx = engine->current;
+ ExecutionContext *ctx = engine->currentContext();
Scope scope(engine);
ScopedObject o(scope, d->value.asObject());
if (!o)
diff --git a/src/qml/jsapi/qjsvalue_p.h b/src/qml/jsapi/qjsvalue_p.h
index bf839a6f1f..d8da664cc6 100644
--- a/src/qml/jsapi/qjsvalue_p.h
+++ b/src/qml/jsapi/qjsvalue_p.h
@@ -80,17 +80,16 @@ public:
Q_ASSERT(!value.isEmpty());
}
QJSValuePrivate(const QString &s)
- : PersistentValuePrivate(QV4::Encode::undefined())
- , string(0, s)
+ : PersistentValuePrivate(QV4::Primitive::emptyValue().asReturnedValue())
+ , string(s)
{
- value.val = QV4::Encode(string.asReturned<QV4::String>());
}
QV4::ReturnedValue getValue(QV4::ExecutionEngine *e);
static QJSValuePrivate *get(const QJSValue &v) { return v.d; }
- QV4::String string;
+ QString string;
};
QT_END_NAMESPACE
diff --git a/src/qml/jsapi/qjsvalueiterator.cpp b/src/qml/jsapi/qjsvalueiterator.cpp
index 245b75b384..ed011ef691 100644
--- a/src/qml/jsapi/qjsvalueiterator.cpp
+++ b/src/qml/jsapi/qjsvalueiterator.cpp
@@ -59,7 +59,7 @@ QJSValueIteratorPrivate::QJSValueIteratorPrivate(const QJSValue &v)
QV4::Scope scope(e);
QV4::ScopedObject o(scope, jsp->value);
- iterator = e->newForEachIteratorObject(e->current, o)->asReturnedValue();
+ iterator = e->newForEachIteratorObject(e->currentContext(), o)->asReturnedValue();
currentName = (QV4::String *)0;
nextName = (QV4::String *)0;
@@ -198,7 +198,7 @@ QJSValue QJSValueIterator::value() const
QV4::Scoped<QV4::ForEachIteratorObject> it(scope, d_ptr->iterator.value());
QV4::ScopedObject o(scope, it->it.object);
- QV4::ExecutionContext *ctx = engine->current;
+ QV4::ExecutionContext *ctx = engine->currentContext();
QV4::ScopedValue v(scope);
if (!!d_ptr->currentName) {
QV4::ScopedString n(scope, d_ptr->currentName);
@@ -237,7 +237,7 @@ QJSValueIterator& QJSValueIterator::operator=(QJSValue& object)
QJSValuePrivate *jsp = QJSValuePrivate::get(object);
QV4::Scope scope(v4);
QV4::ScopedObject o(scope, jsp->value);
- d_ptr->iterator = v4->newForEachIteratorObject(v4->current, o)->asReturnedValue();
+ d_ptr->iterator = v4->newForEachIteratorObject(v4->currentContext(), o)->asReturnedValue();
QV4::Scoped<QV4::ForEachIteratorObject> it(scope, d_ptr->iterator.value());
it->it.flags = QV4::ObjectIterator::NoFlags;
it->it.next(d_ptr->nextName, &d_ptr->nextIndex, &d_ptr->nextAttributes);
diff --git a/src/qml/jsruntime/qv4argumentsobject.cpp b/src/qml/jsruntime/qv4argumentsobject.cpp
index ed010b1230..629c255b48 100644
--- a/src/qml/jsruntime/qv4argumentsobject.cpp
+++ b/src/qml/jsruntime/qv4argumentsobject.cpp
@@ -47,21 +47,21 @@ using namespace QV4;
DEFINE_MANAGED_VTABLE(ArgumentsObject);
ArgumentsObject::ArgumentsObject(CallContext *context)
- : Object(context->engine), context(context)
+ : Object(context->strictMode ? context->engine->strictArgumentsObjectClass : context->engine->argumentsObjectClass)
+ , context(context)
+ , fullyCreated(false)
{
- vtbl = &static_vtbl;
type = Type_ArgumentsObject;
+ flags &= ~SimpleArray;
ExecutionEngine *v4 = context->engine;
Scope scope(v4);
ScopedObject protectThis(scope, this);
if (context->strictMode) {
- internalClass = v4->strictArgumentsObjectClass;
-
Property pd = Property::fromAccessor(v4->thrower, v4->thrower);
- assert(CalleePropertyIndex == internalClass->find(context->engine->id_callee));
- assert(CallerPropertyIndex == internalClass->find(context->engine->id_caller));
+ Q_ASSERT(CalleePropertyIndex == internalClass->find(context->engine->id_callee));
+ Q_ASSERT(CallerPropertyIndex == internalClass->find(context->engine->id_caller));
memberData[CalleePropertyIndex] = pd;
memberData[CallerPropertyIndex] = pd;
@@ -69,31 +69,17 @@ ArgumentsObject::ArgumentsObject(CallContext *context)
for (int i = 0; i < context->callData->argc; ++i)
arrayData[i].value = context->callData->args[i];
arrayDataLen = context->callData->argc;
+ fullyCreated = true;
} else {
- internalClass = engine()->argumentsObjectClass;
Q_ASSERT(CalleePropertyIndex == internalClass->find(context->engine->id_callee));
memberData[CalleePropertyIndex].value = context->function->asReturnedValue();
isNonStrictArgumentsObject = true;
-
- uint numAccessors = qMin((int)context->function->formalParameterCount, context->realArgumentCount);
- uint argCount = qMin(context->realArgumentCount, context->callData->argc);
- arrayReserve(argCount);
- ensureArrayAttributes();
- context->engine->requireArgumentsAccessors(numAccessors);
- for (uint i = 0; i < (uint)numAccessors; ++i) {
- mappedArguments.append(context->callData->args[i]);
- arrayData[i] = context->engine->argumentsAccessors.at(i);
- arrayAttributes[i] = Attr_Accessor;
- }
- for (uint i = numAccessors; i < argCount; ++i) {
- arrayData[i] = Property::fromValue(context->callData->args[i]);
- arrayAttributes[i] = Attr_Data;
- }
- arrayDataLen = argCount;
}
Q_ASSERT(LengthPropertyIndex == internalClass->find(context->engine->id_length));
Property *lp = memberData + ArrayObject::LengthPropertyIndex;
lp->value = Primitive::fromInt32(context->realArgumentCount);
+
+ Q_ASSERT(internalClass->vtable == &static_vtbl);
}
void ArgumentsObject::destroy(Managed *that)
@@ -101,8 +87,34 @@ void ArgumentsObject::destroy(Managed *that)
static_cast<ArgumentsObject *>(that)->~ArgumentsObject();
}
+void ArgumentsObject::fullyCreate()
+{
+ if (fullyCreated)
+ return;
+
+ uint numAccessors = qMin((int)context->function->formalParameterCount, context->realArgumentCount);
+ uint argCount = qMin(context->realArgumentCount, context->callData->argc);
+ arrayReserve(argCount);
+ ensureArrayAttributes();
+ context->engine->requireArgumentsAccessors(numAccessors);
+ for (uint i = 0; i < (uint)numAccessors; ++i) {
+ mappedArguments.append(context->callData->args[i]);
+ arrayData[i] = context->engine->argumentsAccessors.at(i);
+ arrayAttributes[i] = Attr_Accessor;
+ }
+ for (uint i = numAccessors; i < argCount; ++i) {
+ arrayData[i] = Property::fromValue(context->callData->args[i]);
+ arrayAttributes[i] = Attr_Data;
+ }
+ arrayDataLen = argCount;
+
+ fullyCreated = true;
+}
+
bool ArgumentsObject::defineOwnProperty(ExecutionContext *ctx, uint index, const Property &desc, PropertyAttributes attrs)
{
+ fullyCreate();
+
Scope scope(ctx);
uint pidx = propertyIndexFromArrayIndex(index);
Property *pd = arrayData + pidx;
@@ -143,6 +155,57 @@ bool ArgumentsObject::defineOwnProperty(ExecutionContext *ctx, uint index, const
return result;
}
+ReturnedValue ArgumentsObject::getIndexed(Managed *m, uint index, bool *hasProperty)
+{
+ ArgumentsObject *args = static_cast<ArgumentsObject *>(m);
+ if (args->fullyCreated)
+ return Object::getIndexed(m, index, hasProperty);
+
+ if (index < static_cast<uint>(args->context->callData->argc)) {
+ if (hasProperty)
+ *hasProperty = true;
+ return args->context->callData->args[index].asReturnedValue();
+ }
+ return Encode::undefined();
+}
+
+void ArgumentsObject::putIndexed(Managed *m, uint index, const ValueRef value)
+{
+ ArgumentsObject *args = static_cast<ArgumentsObject *>(m);
+ if (!args->fullyCreated && index >= static_cast<uint>(args->context->callData->argc))
+ args->fullyCreate();
+
+ if (args->fullyCreated) {
+ Object::putIndexed(m, index, value);
+ return;
+ }
+
+ args->context->callData->args[index] = value;
+}
+
+bool ArgumentsObject::deleteIndexedProperty(Managed *m, uint index)
+{
+ ArgumentsObject *args = static_cast<ArgumentsObject *>(m);
+ if (!args->fullyCreated)
+ args->fullyCreate();
+ return Object::deleteIndexedProperty(m, index);
+}
+
+PropertyAttributes ArgumentsObject::queryIndexed(const Managed *m, uint index)
+{
+ const ArgumentsObject *args = static_cast<const ArgumentsObject *>(m);
+ if (args->fullyCreated)
+ return Object::queryIndexed(m, index);
+
+ uint numAccessors = qMin((int)args->context->function->formalParameterCount, args->context->realArgumentCount);
+ uint argCount = qMin(args->context->realArgumentCount, args->context->callData->argc);
+ if (index >= argCount)
+ return PropertyAttributes();
+ if (index >= numAccessors)
+ return Attr_Data;
+ return Attr_Accessor;
+}
+
DEFINE_MANAGED_VTABLE(ArgumentsGetterFunction);
ReturnedValue ArgumentsGetterFunction::call(Managed *getter, CallData *callData)
@@ -152,7 +215,7 @@ ReturnedValue ArgumentsGetterFunction::call(Managed *getter, CallData *callData)
Scoped<ArgumentsGetterFunction> g(scope, static_cast<ArgumentsGetterFunction *>(getter));
Scoped<ArgumentsObject> o(scope, callData->thisObject.as<ArgumentsObject>());
if (!o)
- return v4->current->throwTypeError();
+ return v4->currentContext()->throwTypeError();
Q_ASSERT(g->index < static_cast<unsigned>(o->context->callData->argc));
return o->context->argument(g->index);
@@ -167,7 +230,7 @@ ReturnedValue ArgumentsSetterFunction::call(Managed *setter, CallData *callData)
Scoped<ArgumentsSetterFunction> s(scope, static_cast<ArgumentsSetterFunction *>(setter));
Scoped<ArgumentsObject> o(scope, callData->thisObject.as<ArgumentsObject>());
if (!o)
- return v4->current->throwTypeError();
+ return v4->currentContext()->throwTypeError();
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();
@@ -177,7 +240,7 @@ ReturnedValue ArgumentsSetterFunction::call(Managed *setter, CallData *callData)
void ArgumentsObject::markObjects(Managed *that, ExecutionEngine *e)
{
ArgumentsObject *o = static_cast<ArgumentsObject *>(that);
- o->context->mark();
+ o->context->mark(e);
for (int i = 0; i < o->mappedArguments.size(); ++i)
o->mappedArguments.at(i).mark(e);
diff --git a/src/qml/jsruntime/qv4argumentsobject_p.h b/src/qml/jsruntime/qv4argumentsobject_p.h
index 7a5b0817a3..d306fae92b 100644
--- a/src/qml/jsruntime/qv4argumentsobject_p.h
+++ b/src/qml/jsruntime/qv4argumentsobject_p.h
@@ -54,7 +54,9 @@ struct ArgumentsGetterFunction: FunctionObject
uint index;
ArgumentsGetterFunction(ExecutionContext *scope, uint index)
- : FunctionObject(scope), index(index) { vtbl = &static_vtbl; }
+ : FunctionObject(scope), index(index) {
+ setVTable(&static_vtbl);
+ }
static ReturnedValue call(Managed *that, CallData *d);
};
@@ -65,7 +67,9 @@ struct ArgumentsSetterFunction: FunctionObject
uint index;
ArgumentsSetterFunction(ExecutionContext *scope, uint index)
- : FunctionObject(scope), index(index) { vtbl = &static_vtbl; }
+ : FunctionObject(scope), index(index) {
+ setVTable(&static_vtbl);
+ }
static ReturnedValue call(Managed *that, CallData *callData);
};
@@ -74,20 +78,26 @@ struct ArgumentsSetterFunction: FunctionObject
struct ArgumentsObject: Object {
Q_MANAGED
CallContext *context;
+ bool fullyCreated;
QVector<SafeValue> mappedArguments;
ArgumentsObject(CallContext *context);
~ArgumentsObject() {}
+
enum {
LengthPropertyIndex = 0,
CalleePropertyIndex = 1,
CallerPropertyIndex = 2
};
bool defineOwnProperty(ExecutionContext *ctx, uint index, const Property &desc, PropertyAttributes attrs);
-
+ static ReturnedValue getIndexed(Managed *m, uint index, bool *hasProperty);
+ static void putIndexed(Managed *m, uint index, const ValueRef value);
+ static bool deleteIndexedProperty(Managed *m, uint index);
+ static PropertyAttributes queryIndexed(const Managed *m, uint index);
static void markObjects(Managed *that, ExecutionEngine *e);
-protected:
static void destroy(Managed *);
+
+ void fullyCreate();
};
}
diff --git a/src/qml/jsruntime/qv4arrayobject.cpp b/src/qml/jsruntime/qv4arrayobject.cpp
index a0f0345b8b..1628cfe4da 100644
--- a/src/qml/jsruntime/qv4arrayobject.cpp
+++ b/src/qml/jsruntime/qv4arrayobject.cpp
@@ -51,7 +51,7 @@ DEFINE_MANAGED_VTABLE(ArrayCtor);
ArrayCtor::ArrayCtor(ExecutionContext *scope)
: FunctionObject(scope, QStringLiteral("Array"))
{
- vtbl = &static_vtbl;
+ setVTable(&static_vtbl);
}
ReturnedValue ArrayCtor::construct(Managed *m, CallData *callData)
@@ -65,7 +65,7 @@ ReturnedValue ArrayCtor::construct(Managed *m, CallData *callData)
len = callData->args[0].asArrayLength(&ok);
if (!ok)
- return v4->current->throwRangeError(callData->args[0]);
+ return v4->currentContext()->throwRangeError(callData->args[0]);
if (len < 0x1000)
a->arrayReserve(len);
@@ -174,12 +174,22 @@ ReturnedValue ArrayPrototype::method_concat(CallContext *ctx)
}
ScopedArrayObject elt(scope);
+ ScopedObject eltAsObj(scope);
+ ScopedValue entry(scope);
for (int i = 0; i < ctx->callData->argc; ++i) {
+ eltAsObj = ctx->callData->args[i];
elt = ctx->callData->args[i];
- if (elt)
+ if (elt) {
result->arrayConcat(elt.getPointer());
- else
+ } else if (eltAsObj && eltAsObj->isListType()) {
+ const uint startIndex = getLength(ctx, result);
+ for (int i = 0, len = getLength(ctx, eltAsObj); i < len; ++i) {
+ entry = eltAsObj->getIndexed(i);
+ result->putIndexed(startIndex + i, entry);
+ }
+ } else {
result->arraySet(getLength(ctx, result), ctx->callData->args[i]);
+ }
}
return result.asReturnedValue();
diff --git a/src/qml/jsruntime/qv4booleanobject.cpp b/src/qml/jsruntime/qv4booleanobject.cpp
index a0d0027e5f..f8edfb7850 100644
--- a/src/qml/jsruntime/qv4booleanobject.cpp
+++ b/src/qml/jsruntime/qv4booleanobject.cpp
@@ -49,7 +49,7 @@ DEFINE_MANAGED_VTABLE(BooleanObject);
BooleanCtor::BooleanCtor(ExecutionContext *scope)
: FunctionObject(scope, QStringLiteral("Boolean"))
{
- vtbl = &static_vtbl;
+ setVTable(&static_vtbl);
}
ReturnedValue BooleanCtor::construct(Managed *m, CallData *callData)
diff --git a/src/qml/jsruntime/qv4booleanobject_p.h b/src/qml/jsruntime/qv4booleanobject_p.h
index 56c00f99ed..8d6adc0fb2 100644
--- a/src/qml/jsruntime/qv4booleanobject_p.h
+++ b/src/qml/jsruntime/qv4booleanobject_p.h
@@ -39,7 +39,7 @@
**
****************************************************************************/
#ifndef QV4BOOLEANOBJECT_H
-#define QBOOLEANOBJECT_H
+#define QV4BOOLEANOBJECT_H
#include "qv4object_p.h"
#include "qv4functionobject_p.h"
diff --git a/src/qml/jsruntime/qv4context.cpp b/src/qml/jsruntime/qv4context.cpp
index 97247ad368..05a0e66e09 100644
--- a/src/qml/jsruntime/qv4context.cpp
+++ b/src/qml/jsruntime/qv4context.cpp
@@ -51,19 +51,37 @@
using namespace QV4;
+const ManagedVTable ExecutionContext::static_vtbl =
+{
+ call,
+ construct,
+ markObjects,
+ destroy,
+ 0 /*collectDeletables*/,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ isEqualTo,
+ 0,
+ "ExecutionContext",
+};
+
CallContext *ExecutionContext::newCallContext(FunctionObject *function, CallData *callData)
{
- CallContext *c = static_cast<CallContext *>(engine->memoryManager->allocContext(requiredMemoryForExecutionContect(function, callData->argc)));
-
- engine->current = c;
-
- c->initBaseContext(Type_CallContext, engine, this);
+ CallContext *c = static_cast<CallContext *>(engine->memoryManager->allocManaged(requiredMemoryForExecutionContect(function, callData->argc)));
+ new (c) CallContext(engine, Type_CallContext);
c->function = function;
c->realArgumentCount = callData->argc;
c->strictMode = function->strictMode;
- c->marked = false;
c->outer = function->scope;
#ifndef QT_NO_DEBUG
assert(c->outer->next != (ExecutionContext *)0x1);
@@ -92,27 +110,20 @@ CallContext *ExecutionContext::newCallContext(FunctionObject *function, CallData
WithContext *ExecutionContext::newWithContext(ObjectRef with)
{
- WithContext *w = static_cast<WithContext *>(engine->memoryManager->allocContext(sizeof(WithContext)));
- engine->current = w;
- w->initWithContext(this, with);
+ WithContext *w = new (engine->memoryManager) WithContext(engine, with);
return w;
}
CatchContext *ExecutionContext::newCatchContext(const StringRef exceptionVarName, const ValueRef exceptionValue)
{
- CatchContext *c = static_cast<CatchContext *>(engine->memoryManager->allocContext(sizeof(CatchContext)));
- engine->current = c;
- c->initCatchContext(this, exceptionVarName, exceptionValue);
+ CatchContext *c = new (engine->memoryManager) CatchContext(engine, exceptionVarName, exceptionValue);
return c;
}
CallContext *ExecutionContext::newQmlContext(FunctionObject *f, ObjectRef qml)
{
- CallContext *c = static_cast<CallContext *>(engine->memoryManager->allocContext(requiredMemoryForExecutionContect(f, 0)));
-
- engine->current = c;
- c->initQmlContext(this, qml, f);
-
+ CallContext *c = static_cast<CallContext *>(engine->memoryManager->allocManaged(requiredMemoryForExecutionContect(f, 0)));
+ new (c) CallContext(engine, qml, f);
return c;
}
@@ -149,7 +160,7 @@ String * const *ExecutionContext::formals() const
if (type < Type_SimpleCallContext)
return 0;
QV4::FunctionObject *f = static_cast<const CallContext *>(this)->function;
- return f ? f->formalParameterList : 0;
+ return (f && f->function) ? f->function->internalClass->nameMap.constData() : 0;
}
unsigned int ExecutionContext::formalCount() const
@@ -165,7 +176,7 @@ String * const *ExecutionContext::variables() const
if (type < Type_SimpleCallContext)
return 0;
QV4::FunctionObject *f = static_cast<const CallContext *>(this)->function;
- return f ? f->varList : 0;
+ return (f && f->function) ? f->function->internalClass->nameMap.constData() + f->function->nArguments : 0;
}
unsigned int ExecutionContext::variableCount() const
@@ -177,53 +188,47 @@ unsigned int ExecutionContext::variableCount() const
}
-void GlobalContext::initGlobalContext(ExecutionEngine *eng)
+GlobalContext::GlobalContext(ExecutionEngine *eng)
+ : ExecutionContext(eng, Type_GlobalContext)
{
- initBaseContext(Type_GlobalContext, eng, /*parentContext*/0);
- callData = reinterpret_cast<CallData *>(this + 1);
- callData->tag = QV4::Value::_Integer_Type;
- callData->argc = 0;
- callData->thisObject = eng->globalObject;
- global = 0;
+ global = eng->globalObject;
}
-void WithContext::initWithContext(ExecutionContext *p, ObjectRef with)
+WithContext::WithContext(ExecutionEngine *engine, ObjectRef with)
+ : ExecutionContext(engine, Type_WithContext)
{
- initBaseContext(Type_WithContext, p->engine, p);
- callData = p->callData;
- outer = p;
- lookups = p->lookups;
- compilationUnit = p->compilationUnit;
+ callData = parent->callData;
+ outer = parent;
+ lookups = parent->lookups;
+ compilationUnit = parent->compilationUnit;
withObject = with.getPointer();
}
-void CatchContext::initCatchContext(ExecutionContext *p, const StringRef exceptionVarName, const ValueRef exceptionValue)
+CatchContext::CatchContext(ExecutionEngine *engine, const StringRef exceptionVarName, const ValueRef exceptionValue)
+ : ExecutionContext(engine, Type_CatchContext)
{
- initBaseContext(Type_CatchContext, p->engine, p);
- strictMode = p->strictMode;
- callData = p->callData;
- outer = p;
- lookups = p->lookups;
- compilationUnit = p->compilationUnit;
+ strictMode = parent->strictMode;
+ callData = parent->callData;
+ outer = parent;
+ lookups = parent->lookups;
+ compilationUnit = parent->compilationUnit;
this->exceptionVarName = exceptionVarName;
this->exceptionValue = exceptionValue;
}
-void CallContext::initQmlContext(ExecutionContext *parentContext, ObjectRef qml, FunctionObject *function)
+CallContext::CallContext(ExecutionEngine *engine, ObjectRef qml, FunctionObject *function)
+ : ExecutionContext(engine, Type_QmlContext)
{
- initBaseContext(Type_QmlContext, parentContext->engine, parentContext);
-
this->function = function;
- this->callData = reinterpret_cast<CallData *>(this + 1);
- this->callData->tag = QV4::Value::_Integer_Type;
- this->callData->argc = 0;
- this->callData->thisObject = Primitive::undefinedValue();
+ callData = reinterpret_cast<CallData *>(this + 1);
+ callData->tag = QV4::Value::_Integer_Type;
+ callData->argc = 0;
+ callData->thisObject = Primitive::undefinedValue();
strictMode = true;
- marked = false;
- this->outer = function->scope;
+ outer = function->scope;
#ifndef QT_NO_DEBUG
assert(outer->next != (ExecutionContext *)0x1);
#endif
@@ -259,12 +264,10 @@ bool ExecutionContext::deleteProperty(const StringRef name)
CallContext *c = static_cast<CallContext *>(ctx);
FunctionObject *f = c->function;
if (f->needsActivation || hasWith) {
- for (unsigned int i = 0; i < f->varCount; ++i)
- if (f->varList[i]->isEqualTo(name))
- return false;
- for (int i = (int)f->formalParameterCount - 1; i >= 0; --i)
- if (f->formalParameterList[i]->isEqualTo(name))
- return false;
+ uint index = f->function->internalClass->find(name);
+ if (index < UINT_MAX)
+ // ### throw in strict mode?
+ return false;
}
if (c->activation && c->activation->__hasProperty__(name))
return c->activation->deleteProperty(name);
@@ -285,36 +288,34 @@ bool CallContext::needsOwnArguments() const
return function->needsActivation || callData->argc < static_cast<int>(function->formalParameterCount);
}
-void ExecutionContext::mark()
+void ExecutionContext::markObjects(Managed *m, ExecutionEngine *engine)
{
- if (marked)
- return;
- marked = true;
+ ExecutionContext *ctx = static_cast<ExecutionContext *>(m);
- if (outer)
- outer->mark();
+ if (ctx->outer)
+ ctx->outer->mark(engine);
// ### shouldn't need these 3 lines
- callData->thisObject.mark(engine);
- for (int arg = 0; arg < callData->argc; ++arg)
- callData->args[arg].mark(engine);
+ ctx->callData->thisObject.mark(engine);
+ for (int arg = 0; arg < ctx->callData->argc; ++arg)
+ ctx->callData->args[arg].mark(engine);
- if (type >= Type_CallContext) {
- QV4::CallContext *c = static_cast<CallContext *>(this);
+ if (ctx->type >= Type_CallContext) {
+ QV4::CallContext *c = static_cast<CallContext *>(ctx);
for (unsigned local = 0, lastLocal = c->variableCount(); local < lastLocal; ++local)
c->locals[local].mark(engine);
if (c->activation)
c->activation->mark(engine);
c->function->mark(engine);
- } else if (type == Type_WithContext) {
- WithContext *w = static_cast<WithContext *>(this);
+ } else if (ctx->type == Type_WithContext) {
+ WithContext *w = static_cast<WithContext *>(ctx);
w->withObject->mark(engine);
- } else if (type == Type_CatchContext) {
- CatchContext *c = static_cast<CatchContext *>(this);
+ } else if (ctx->type == Type_CatchContext) {
+ CatchContext *c = static_cast<CatchContext *>(ctx);
c->exceptionVarName->mark(engine);
c->exceptionValue.mark(engine);
- } else if (type == Type_GlobalContext) {
- GlobalContext *g = static_cast<GlobalContext *>(this);
+ } else if (ctx->type == Type_GlobalContext) {
+ GlobalContext *g = static_cast<GlobalContext *>(ctx);
g->global->mark(engine);
}
}
@@ -336,24 +337,35 @@ void ExecutionContext::setProperty(const StringRef name, const ValueRef value)
ScopedObject activation(scope, (Object *)0);
if (ctx->type >= Type_CallContext) {
CallContext *c = static_cast<CallContext *>(ctx);
- for (unsigned int i = 0; i < c->function->varCount; ++i)
- if (c->function->varList[i]->isEqualTo(name)) {
- c->locals[i] = *value;
- return;
- }
- for (int i = (int)c->function->formalParameterCount - 1; i >= 0; --i)
- if (c->function->formalParameterList[i]->isEqualTo(name)) {
- c->callData->args[i] = *value;
+ if (c->function->function) {
+ uint index = c->function->function->internalClass->find(name);
+ if (index < UINT_MAX) {
+ if (index < c->function->formalParameterCount) {
+ c->callData->args[c->function->formalParameterCount - index - 1] = *value;
+ } else {
+ index -= c->function->formalParameterCount;
+ c->locals[index] = *value;
+ }
return;
}
+ }
activation = c->activation;
} else if (ctx->type == Type_GlobalContext) {
activation = static_cast<GlobalContext *>(ctx)->global;
}
- if (activation && (ctx->type == Type_QmlContext || activation->__hasProperty__(name))) {
- activation->put(name, value);
- return;
+ if (activation) {
+ if (ctx->type == Type_QmlContext) {
+ activation->put(name, value);
+ return;
+ } else {
+ PropertyAttributes attrs;
+ Property *p = activation->__getOwnProperty__(name, &attrs);
+ if (p) {
+ activation->putValue(p, attrs, value);
+ return;
+ }
+ }
}
}
}
@@ -398,13 +410,13 @@ ReturnedValue ExecutionContext::getProperty(const StringRef name)
else if (ctx->type >= Type_CallContext) {
QV4::CallContext *c = static_cast<CallContext *>(ctx);
ScopedFunctionObject f(scope, c->function);
- if (f->needsActivation || hasWith || hasCatchScope) {
- for (unsigned int i = 0; i < f->varCount; ++i)
- if (f->varList[i]->isEqualTo(name))
- return c->locals[i].asReturnedValue();
- for (int i = (int)f->formalParameterCount - 1; i >= 0; --i)
- if (f->formalParameterList[i]->isEqualTo(name))
- return c->callData->args[i].asReturnedValue();
+ if (f->function && (f->needsActivation || hasWith || hasCatchScope)) {
+ uint index = f->function->internalClass->find(name);
+ if (index < UINT_MAX) {
+ if (index < c->function->formalParameterCount)
+ return c->callData->args[c->function->formalParameterCount - index - 1].asReturnedValue();
+ return c->locals[index - c->function->formalParameterCount].asReturnedValue();
+ }
}
if (c->activation) {
bool hasProperty = false;
@@ -464,13 +476,13 @@ ReturnedValue ExecutionContext::getPropertyAndBase(const StringRef name, ObjectR
else if (ctx->type >= Type_CallContext) {
QV4::CallContext *c = static_cast<CallContext *>(ctx);
FunctionObject *f = c->function;
- if (f->needsActivation || hasWith || hasCatchScope) {
- for (unsigned int i = 0; i < f->varCount; ++i)
- if (f->varList[i]->isEqualTo(name))
- return c->locals[i].asReturnedValue();
- for (int i = (int)f->formalParameterCount - 1; i >= 0; --i)
- if (f->formalParameterList[i]->isEqualTo(name))
- return c->callData->args[i].asReturnedValue();
+ if (f->function && (f->needsActivation || hasWith || hasCatchScope)) {
+ uint index = f->function->internalClass->find(name);
+ if (index < UINT_MAX) {
+ if (index < c->function->formalParameterCount)
+ return c->callData->args[c->function->formalParameterCount - index - 1].asReturnedValue();
+ return c->locals[index - c->function->formalParameterCount].asReturnedValue();
+ }
}
if (c->activation) {
bool hasProperty = false;
diff --git a/src/qml/jsruntime/qv4context_p.h b/src/qml/jsruntime/qv4context_p.h
index ccb5cf98f8..4eb89ad905 100644
--- a/src/qml/jsruntime/qv4context_p.h
+++ b/src/qml/jsruntime/qv4context_p.h
@@ -44,6 +44,7 @@
#include "qv4global_p.h"
#include "qv4value_def_p.h"
#include "qv4managed_p.h"
+#include "qv4engine_p.h"
QT_BEGIN_NAMESPACE
@@ -66,9 +67,11 @@ struct CallContext;
struct CatchContext;
struct WithContext;
-struct Q_QML_EXPORT ExecutionContext
+struct Q_QML_EXPORT ExecutionContext : public Managed
{
- enum Type {
+ Q_MANAGED
+
+ enum ContextType {
Type_GlobalContext = 0x1,
Type_CatchContext = 0x2,
Type_WithContext = 0x3,
@@ -77,9 +80,24 @@ struct Q_QML_EXPORT ExecutionContext
Type_QmlContext = 0x6
};
- Type type;
+ ExecutionContext(ExecutionEngine *engine, ContextType t)
+ : Managed(engine->executionContextClass)
+ {
+ this->type = t;
+ strictMode = false;
+ this->engine = engine;
+ this->parent = engine->currentContext();
+ outer = 0;
+ lookups = 0;
+ compilationUnit = 0;
+ currentEvalCode = 0;
+ interpreterInstructionPointer = 0;
+ lineNumber = -1;
+ engine->current = this;
+ }
+
+ ContextType type;
bool strictMode;
- bool marked;
CallData *callData;
@@ -98,28 +116,14 @@ struct Q_QML_EXPORT ExecutionContext
EvalCode *currentEvalCode;
const uchar **interpreterInstructionPointer;
- char *jitInstructionPointer;
-
- void initBaseContext(Type type, ExecutionEngine *engine, ExecutionContext *parentContext)
- {
- this->type = type;
- strictMode = false;
- marked = false;
- this->engine = engine;
- parent = parentContext;
- outer = 0;
- lookups = 0;
- compilationUnit = 0;
- currentEvalCode = 0;
- interpreterInstructionPointer = 0;
- jitInstructionPointer = 0;
- }
+ int lineNumber;
CallContext *newCallContext(FunctionObject *f, CallData *callData);
WithContext *newWithContext(ObjectRef with);
CatchContext *newCatchContext(const StringRef exceptionVarName, const ValueRef exceptionValue);
CallContext *newQmlContext(FunctionObject *f, ObjectRef qml);
+ // formals are in reverse order
String * const *formals() const;
unsigned int formalCount() const;
String * const *variables() const;
@@ -130,11 +134,11 @@ struct Q_QML_EXPORT ExecutionContext
ReturnedValue throwError(const QV4::ValueRef value);
ReturnedValue throwError(const QString &message);
ReturnedValue throwSyntaxError(const QString &message);
- ReturnedValue throwSyntaxError(const QString &message, const QString &fileName, int line, int column);
+ ReturnedValue throwSyntaxError(const QString &message, const QString &fileName, int lineNumber, int column);
ReturnedValue throwTypeError();
ReturnedValue throwTypeError(const QString &message);
ReturnedValue throwReferenceError(const ValueRef value);
- ReturnedValue throwReferenceError(const QString &value, const QString &fileName, int line, int column);
+ ReturnedValue throwReferenceError(const QString &value, const QString &fileName, int lineNumber, int column);
ReturnedValue throwRangeError(const ValueRef value);
ReturnedValue throwRangeError(const QString &message);
ReturnedValue throwURIError(const ValueRef msg);
@@ -148,26 +152,27 @@ struct Q_QML_EXPORT ExecutionContext
// Can only be called from within catch(...), rethrows if no JS exception.
ReturnedValue catchException(StackTrace *trace = 0);
- void mark();
-
inline CallContext *asCallContext();
inline const CallContext *asCallContext() const;
+
+ static void markObjects(Managed *m, ExecutionEngine *e);
};
struct CallContext : public ExecutionContext
{
- FunctionObject *function;
- int realArgumentCount;
- SafeValue *locals;
- Object *activation;
-
- void initSimpleCallContext(ExecutionEngine *engine, ExecutionContext *parent) {
- initBaseContext(Type_SimpleCallContext, engine, parent);
+ CallContext(ExecutionEngine *engine, ContextType t = Type_SimpleCallContext)
+ : ExecutionContext(engine, t)
+ {
function = 0;
locals = 0;
activation = 0;
}
- void initQmlContext(ExecutionContext *parentContext, ObjectRef qml, QV4::FunctionObject *function);
+ CallContext(ExecutionEngine *engine, ObjectRef qml, QV4::FunctionObject *function);
+
+ FunctionObject *function;
+ int realArgumentCount;
+ SafeValue *locals;
+ Object *activation;
inline ReturnedValue argument(int i);
bool needsOwnArguments() const;
@@ -175,14 +180,14 @@ struct CallContext : public ExecutionContext
struct GlobalContext : public ExecutionContext
{
- void initGlobalContext(ExecutionEngine *e);
+ GlobalContext(ExecutionEngine *engine);
Object *global;
};
struct CatchContext : public ExecutionContext
{
- void initCatchContext(ExecutionContext *p, const StringRef exceptionVarName, const ValueRef exceptionValue);
+ CatchContext(ExecutionEngine *engine, const StringRef exceptionVarName, const ValueRef exceptionValue);
SafeString exceptionVarName;
SafeValue exceptionValue;
@@ -190,9 +195,8 @@ struct CatchContext : public ExecutionContext
struct WithContext : public ExecutionContext
{
+ WithContext(ExecutionEngine *engine, ObjectRef with);
Object *withObject;
-
- void initWithContext(ExecutionContext *p, ObjectRef with);
};
inline CallContext *ExecutionContext::asCallContext()
@@ -205,6 +209,37 @@ inline const CallContext *ExecutionContext::asCallContext() const
return type >= Type_SimpleCallContext ? static_cast<const CallContext *>(this) : 0;
}
+
+inline void ExecutionEngine::pushContext(CallContext *context)
+{
+ context->parent = current;
+ current = context;
+ current->currentEvalCode = 0;
+}
+
+inline ExecutionContext *ExecutionEngine::popContext()
+{
+ Q_ASSERT(current->parent);
+ current = current->parent;
+ return current;
+}
+
+struct ExecutionContextSaver
+{
+ ExecutionEngine *engine;
+ ExecutionContext *savedContext;
+
+ ExecutionContextSaver(ExecutionContext *context)
+ : engine(context->engine)
+ , savedContext(context)
+ {
+ }
+ ~ExecutionContextSaver()
+ {
+ engine->current = savedContext;
+ }
+};
+
/* Function *f, int argc */
#define requiredMemoryForExecutionContect(f, argc) \
sizeof(CallContext) + sizeof(Value) * (f->varCount + qMax((uint)argc, f->formalParameterCount)) + sizeof(CallData)
diff --git a/src/qml/jsruntime/qv4dateobject.cpp b/src/qml/jsruntime/qv4dateobject.cpp
index b732c8a04a..5d0c8ccf8e 100644
--- a/src/qml/jsruntime/qv4dateobject.cpp
+++ b/src/qml/jsruntime/qv4dateobject.cpp
@@ -646,7 +646,7 @@ DEFINE_MANAGED_VTABLE(DateObject);
DateObject::DateObject(ExecutionEngine *engine, const QDateTime &date)
: Object(engine->dateClass)
{
- vtbl = &static_vtbl;
+ setVTable(&static_vtbl);
type = Type_DateObject;
value.setDouble(date.isValid() ? date.toMSecsSinceEpoch() : qSNaN());
}
@@ -661,7 +661,7 @@ DEFINE_MANAGED_VTABLE(DateCtor);
DateCtor::DateCtor(ExecutionContext *scope)
: FunctionObject(scope, QStringLiteral("Date"))
{
- vtbl = &static_vtbl;
+ setVTable(&static_vtbl);
}
ReturnedValue DateCtor::construct(Managed *m, CallData *callData)
diff --git a/src/qml/jsruntime/qv4dateobject_p.h b/src/qml/jsruntime/qv4dateobject_p.h
index e96cac2f20..9c451dd251 100644
--- a/src/qml/jsruntime/qv4dateobject_p.h
+++ b/src/qml/jsruntime/qv4dateobject_p.h
@@ -55,7 +55,6 @@ struct DateObject: Object {
Q_MANAGED
SafeValue value;
DateObject(ExecutionEngine *engine, const ValueRef date): Object(engine->dateClass) {
- vtbl = &static_vtbl;
type = Type_DateObject;
value = date;
}
@@ -65,7 +64,7 @@ struct DateObject: Object {
protected:
DateObject(InternalClass *ic): Object(ic) {
- vtbl = &static_vtbl;
+ setVTable(&static_vtbl);
type = Type_DateObject;
value = Primitive::fromDouble(qSNaN());
}
diff --git a/src/qml/jsruntime/qv4debugging.cpp b/src/qml/jsruntime/qv4debugging.cpp
index 95b4100651..4170b6817f 100644
--- a/src/qml/jsruntime/qv4debugging.cpp
+++ b/src/qml/jsruntime/qv4debugging.cpp
@@ -185,7 +185,7 @@ void Debugger::resume(Speed speed)
if (speed == StepOver)
setTemporaryBreakPointOnNextLine();
if (speed == StepOut)
- m_temporaryBreakPoints = TemporaryBreakPoint(getFunction(), m_engine->current);
+ m_temporaryBreakPoints = TemporaryBreakPoint(getFunction(), m_engine->currentContext());
m_stepping = speed;
m_runningCondition.wakeAll();
@@ -293,15 +293,16 @@ void Debugger::collectArgumentsInContext(Collector *collector, int frameNr, int
if (frameNr < 0)
return;
- CallContext *ctxt = findScope(findContext(engine->current, frameNr), scopeNr);
+ CallContext *ctxt = findScope(findContext(engine->currentContext(), frameNr), scopeNr);
if (!ctxt)
return;
Scope scope(engine);
ScopedValue v(scope);
- for (unsigned i = 0, ei = ctxt->formalCount(); i != ei; ++i) {
+ int nFormals = ctxt->formalCount();
+ for (unsigned i = 0, ei = nFormals; i != ei; ++i) {
QString qName;
- if (String *name = ctxt->formals()[i])
+ if (String *name = ctxt->formals()[nFormals - i - 1])
qName = name->toQString();
v = ctxt->argument(i);
collector->collect(qName, v);
@@ -339,7 +340,7 @@ void Debugger::collectLocalsInContext(Collector *collector, int frameNr, int sco
if (frameNr < 0)
return;
- CallContext *ctxt = findScope(findContext(engine->current, frameNr), scopeNr);
+ CallContext *ctxt = findScope(findContext(engine->currentContext(), frameNr), scopeNr);
if (!ctxt)
return;
@@ -386,7 +387,7 @@ bool Debugger::collectThisInContext(Debugger::Collector *collector, int frame)
bool myRun()
{
- ExecutionContext *ctxt = findContext(engine->current, frameNr);
+ ExecutionContext *ctxt = findContext(engine->currentContext(), frameNr);
while (ctxt) {
if (CallContext *cCtxt = ctxt->asCallContext())
if (cCtxt->activation)
@@ -448,14 +449,14 @@ void Debugger::collectReturnedValue(Collector *collector) const
collector->collect(o);
}
-QVector<ExecutionContext::Type> Debugger::getScopeTypes(int frame) const
+QVector<ExecutionContext::ContextType> Debugger::getScopeTypes(int frame) const
{
- QVector<ExecutionContext::Type> types;
+ QVector<ExecutionContext::ContextType> types;
if (state() != Paused)
return types;
- CallContext *sctxt = findContext(m_engine->current, frame);
+ CallContext *sctxt = findContext(m_engine->currentContext(), frame);
if (!sctxt || sctxt->type < ExecutionContext::Type_SimpleCallContext)
return types;
CallContext *ctxt = static_cast<CallContext *>(sctxt);
@@ -499,7 +500,7 @@ void Debugger::maybeBreakAtInstruction(const uchar *code, bool breakPointHit)
m_pauseRequested = false;
pauseAndWait(PauseRequest);
} else if (breakPointHit) {
- if (m_stepping == StepOver && m_temporaryBreakPoints.context == m_engine->current)
+ if (m_stepping == StepOver && m_temporaryBreakPoints.context == m_engine->currentContext())
pauseAndWait(Step);
else if (reallyHitTheBreakPoint(state.fileName, state.lineNumber))
pauseAndWait(BreakPoint);
@@ -527,7 +528,7 @@ void Debugger::leavingFunction(const ReturnedValue &retVal)
QMutexLocker locker(&m_lock);
if ((m_stepping == StepOut || m_stepping == StepOver)
- && temporaryBreakPointInFunction(m_engine->current)) {
+ && temporaryBreakPointInFunction(m_engine->currentContext())) {
clearTemporaryBreakPoints();
m_stepping = NotStepping;
m_stopForStepping = true;
@@ -551,7 +552,7 @@ void Debugger::aboutToThrow()
Function *Debugger::getFunction() const
{
- ExecutionContext *context = m_engine->current;
+ ExecutionContext *context = m_engine->currentContext();
if (CallContext *callCtx = context->asCallContext())
return callCtx->function->function;
else {
@@ -594,7 +595,7 @@ void Debugger::setTemporaryBreakPointOnNextLine()
if (pcs.isEmpty())
return;
- m_temporaryBreakPoints = TemporaryBreakPoint(function, m_engine->current);
+ m_temporaryBreakPoints = TemporaryBreakPoint(function, m_engine->currentContext());
m_temporaryBreakPoints.codeOffsets.reserve(pcs.size());
for (QList<qptrdiff>::const_iterator i = pcs.begin(), ei = pcs.end(); i != ei; ++i) {
// note: we do set a breakpoint on the current line, because there could be a loop where
diff --git a/src/qml/jsruntime/qv4debugging_p.h b/src/qml/jsruntime/qv4debugging_p.h
index 98b549995e..0e19c51935 100644
--- a/src/qml/jsruntime/qv4debugging_p.h
+++ b/src/qml/jsruntime/qv4debugging_p.h
@@ -163,7 +163,7 @@ public:
bool collectThisInContext(Collector *collector, int frame = 0);
void collectThrownValue(Collector *collector);
void collectReturnedValue(Collector *collector) const;
- QVector<ExecutionContext::Type> getScopeTypes(int frame = 0) const;
+ QVector<ExecutionContext::ContextType> getScopeTypes(int frame = 0) const;
public: // compile-time interface
void maybeBreakAtInstruction(const uchar *code, bool breakPointHit);
diff --git a/src/qml/jsruntime/qv4engine.cpp b/src/qml/jsruntime/qv4engine.cpp
index 8cd059dd2b..dc8c0da321 100644
--- a/src/qml/jsruntime/qv4engine.cpp
+++ b/src/qml/jsruntime/qv4engine.cpp
@@ -39,6 +39,7 @@
**
****************************************************************************/
#include <qv4engine_p.h>
+#include <qv4context_p.h>
#include <qv4value_p.h>
#include <qv4object_p.h>
#include <qv4objectproto_p.h>
@@ -52,6 +53,7 @@
#include <qv4mathobject_p.h>
#include <qv4numberobject_p.h>
#include <qv4regexpobject_p.h>
+#include <qv4regexp_p.h>
#include <qv4variantobject_p.h>
#include <qv4runtime_p.h>
#include "qv4mm_p.h"
@@ -134,11 +136,13 @@ ExecutionEngine::ExecutionEngine(QQmlJS::EvalISelFactory *factory)
: memoryManager(new QV4::MemoryManager)
, executableAllocator(new QV4::ExecutableAllocator)
, regExpAllocator(new QV4::ExecutableAllocator)
+ , current(0)
, bumperPointerAllocator(new WTF::BumpPointerAllocator)
, jsStack(new WTF::PageAllocation)
, debugger(0)
, globalObject(0)
, globalCode(0)
+ , v8Engine(0)
, m_engineId(engineSerial.fetchAndAddOrdered(1))
, regExpCache(0)
, m_multiplyWrappedQObjects(0)
@@ -181,6 +185,9 @@ ExecutionEngine::ExecutionEngine(QQmlJS::EvalISelFactory *factory)
identifierTable = new IdentifierTable(this);
emptyClass = new (classPool.allocate(sizeof(InternalClass))) InternalClass(this);
+ executionContextClass = emptyClass->changeVTable(&ExecutionContext::static_vtbl);
+ stringClass = emptyClass->changeVTable(&String::static_vtbl);
+ regExpValueClass = emptyClass->changeVTable(&RegExp::static_vtbl);
id_undefined = newIdentifier(QStringLiteral("undefined"));
id_null = newIdentifier(QStringLiteral("null"));
@@ -213,33 +220,39 @@ ExecutionEngine::ExecutionEngine(QQmlJS::EvalISelFactory *factory)
id_toString = newIdentifier(QStringLiteral("toString"));
id_valueOf = newIdentifier(QStringLiteral("valueOf"));
- ObjectPrototype *objectPrototype = new (memoryManager) ObjectPrototype(emptyClass);
- objectClass = emptyClass->changePrototype(objectPrototype);
+ ObjectPrototype *objectPrototype = new (memoryManager) ObjectPrototype(emptyClass->changeVTable(&ObjectPrototype::static_vtbl));
+ objectClass = InternalClass::create(this, &Object::static_vtbl, objectPrototype);
+ Q_ASSERT(objectClass->vtable == &Object::static_vtbl);
- arrayClass = objectClass->addMember(id_length, Attr_NotConfigurable|Attr_NotEnumerable);
+ arrayClass = InternalClass::create(this, &ArrayObject::static_vtbl, objectPrototype);
+ arrayClass = arrayClass->addMember(id_length, Attr_NotConfigurable|Attr_NotEnumerable);
ArrayPrototype *arrayPrototype = new (memoryManager) ArrayPrototype(arrayClass);
arrayClass = arrayClass->changePrototype(arrayPrototype);
- InternalClass *argsClass = objectClass->addMember(id_length, Attr_NotEnumerable);
+ InternalClass *argsClass = InternalClass::create(this, &ArgumentsObject::static_vtbl, objectPrototype);
+ argsClass = argsClass->addMember(id_length, Attr_NotEnumerable);
argumentsObjectClass = argsClass->addMember(id_callee, Attr_Data|Attr_NotEnumerable);
strictArgumentsObjectClass = argsClass->addMember(id_callee, Attr_Accessor|Attr_NotConfigurable|Attr_NotEnumerable);
strictArgumentsObjectClass = strictArgumentsObjectClass->addMember(id_caller, Attr_Accessor|Attr_NotConfigurable|Attr_NotEnumerable);
+ Q_ASSERT(argumentsObjectClass->vtable == &ArgumentsObject::static_vtbl);
+ Q_ASSERT(strictArgumentsObjectClass->vtable == &ArgumentsObject::static_vtbl);
+
initRootContext();
StringPrototype *stringPrototype = new (memoryManager) StringPrototype(objectClass);
- stringClass = emptyClass->changePrototype(stringPrototype);
+ stringObjectClass = InternalClass::create(this, &String::static_vtbl, stringPrototype);
NumberPrototype *numberPrototype = new (memoryManager) NumberPrototype(objectClass);
- numberClass = emptyClass->changePrototype(numberPrototype);
+ numberClass = InternalClass::create(this, &NumberObject::static_vtbl, numberPrototype);
BooleanPrototype *booleanPrototype = new (memoryManager) BooleanPrototype(objectClass);
- booleanClass = emptyClass->changePrototype(booleanPrototype);
+ booleanClass = InternalClass::create(this, &BooleanObject::static_vtbl, booleanPrototype);
DatePrototype *datePrototype = new (memoryManager) DatePrototype(objectClass);
- dateClass = emptyClass->changePrototype(datePrototype);
+ dateClass = InternalClass::create(this, &DateObject::static_vtbl, datePrototype);
- FunctionPrototype *functionPrototype = new (memoryManager) FunctionPrototype(objectClass);
- functionClass = emptyClass->changePrototype(functionPrototype);
+ FunctionPrototype *functionPrototype = new (memoryManager) FunctionPrototype(InternalClass::create(this, &FunctionPrototype::static_vtbl, objectPrototype));
+ functionClass = InternalClass::create(this, &FunctionObject::static_vtbl, functionPrototype);
uint index;
functionWithProtoClass = functionClass->addMember(id_prototype, Attr_NotEnumerable|Attr_NotConfigurable, &index);
Q_ASSERT(index == FunctionObject::Index_Prototype);
@@ -247,32 +260,33 @@ ExecutionEngine::ExecutionEngine(QQmlJS::EvalISelFactory *factory)
Q_ASSERT(index == FunctionObject::Index_ProtoConstructor);
RegExpPrototype *regExpPrototype = new (memoryManager) RegExpPrototype(objectClass);
- regExpClass = emptyClass->changePrototype(regExpPrototype);
+ regExpClass = InternalClass::create(this, &RegExpObject::static_vtbl, regExpPrototype);
regExpExecArrayClass = arrayClass->addMember(id_index, Attr_Data, &index);
Q_ASSERT(index == RegExpObject::Index_ArrayIndex);
regExpExecArrayClass = regExpExecArrayClass->addMember(id_input, Attr_Data, &index);
Q_ASSERT(index == RegExpObject::Index_ArrayInput);
ErrorPrototype *errorPrototype = new (memoryManager) ErrorPrototype(objectClass);
- errorClass = emptyClass->changePrototype(errorPrototype);
+ errorClass = InternalClass::create(this, &ErrorObject::static_vtbl, errorPrototype);
EvalErrorPrototype *evalErrorPrototype = new (memoryManager) EvalErrorPrototype(errorClass);
- evalErrorClass = emptyClass->changePrototype(evalErrorPrototype);
+ evalErrorClass = InternalClass::create(this, &EvalErrorObject::static_vtbl, evalErrorPrototype);
RangeErrorPrototype *rangeErrorPrototype = new (memoryManager) RangeErrorPrototype(errorClass);
- rangeErrorClass = emptyClass->changePrototype(rangeErrorPrototype);
+ rangeErrorClass = InternalClass::create(this, &RangeErrorObject::static_vtbl, rangeErrorPrototype);
ReferenceErrorPrototype *referenceErrorPrototype = new (memoryManager) ReferenceErrorPrototype(errorClass);
- referenceErrorClass = emptyClass->changePrototype(referenceErrorPrototype);
+ referenceErrorClass = InternalClass::create(this, &ReferenceErrorObject::static_vtbl, referenceErrorPrototype);
SyntaxErrorPrototype *syntaxErrorPrototype = new (memoryManager) SyntaxErrorPrototype(errorClass);
- syntaxErrorClass = emptyClass->changePrototype(syntaxErrorPrototype);
+ syntaxErrorClass = InternalClass::create(this, &SyntaxErrorObject::static_vtbl, syntaxErrorPrototype);
TypeErrorPrototype *typeErrorPrototype = new (memoryManager) TypeErrorPrototype(errorClass);
- typeErrorClass = emptyClass->changePrototype(typeErrorPrototype);
+ typeErrorClass = InternalClass::create(this, &TypeErrorObject::static_vtbl, typeErrorPrototype);
URIErrorPrototype *uRIErrorPrototype = new (memoryManager) URIErrorPrototype(errorClass);
- uriErrorClass = emptyClass->changePrototype(uRIErrorPrototype);
+ uriErrorClass = InternalClass::create(this, &URIErrorObject::static_vtbl, uRIErrorPrototype);
- VariantPrototype *variantPrototype = new (memoryManager) VariantPrototype(objectClass);
- variantClass = emptyClass->changePrototype(variantPrototype);
+ VariantPrototype *variantPrototype = new (memoryManager) VariantPrototype(InternalClass::create(this, &VariantPrototype::static_vtbl, objectPrototype));
+ variantClass = InternalClass::create(this, &VariantObject::static_vtbl, variantPrototype);
+ Q_ASSERT(variantClass->prototype == variantPrototype);
+ Q_ASSERT(variantPrototype->internalClass->prototype == objectPrototype);
- SequencePrototype *sequencePrototype = new (memoryManager) SequencePrototype(arrayClass->changePrototype(arrayPrototype));
- sequenceClass = emptyClass->changePrototype(sequencePrototype);
+ sequencePrototype = new (memoryManager) SequencePrototype(arrayClass);
objectCtor = new (memoryManager) ObjectCtor(rootContext);
stringCtor = new (memoryManager) StringCtor(rootContext);
@@ -307,7 +321,7 @@ ExecutionEngine::ExecutionEngine(QQmlJS::EvalISelFactory *factory)
uRIErrorPrototype->init(this, uRIErrorCtor);
variantPrototype->init();
- sequencePrototype->init();
+ static_cast<SequencePrototype *>(sequencePrototype.managed())->init();
//
// set up the global object
@@ -315,6 +329,7 @@ ExecutionEngine::ExecutionEngine(QQmlJS::EvalISelFactory *factory)
globalObject = newObject()->getPointer();
rootContext->global = globalObject;
rootContext->callData->thisObject = globalObject;
+ Q_ASSERT(globalObject->internalClass->vtable);
globalObject->defineDefaultProperty(QStringLiteral("Object"), objectCtor);
globalObject->defineDefaultProperty(QStringLiteral("String"), stringCtor);
@@ -389,10 +404,13 @@ void ExecutionEngine::enableDebugger()
void ExecutionEngine::initRootContext()
{
- rootContext = static_cast<GlobalContext *>(memoryManager->allocContext(sizeof(GlobalContext) + sizeof(CallData)));
- current = rootContext;
- current->parent = 0;
- rootContext->initGlobalContext(this);
+ rootContext = static_cast<GlobalContext *>(memoryManager->allocManaged(sizeof(GlobalContext) + sizeof(CallData)));
+ new (rootContext) GlobalContext(this);
+ rootContext->callData = reinterpret_cast<CallData *>(rootContext + 1);
+ rootContext->callData->tag = QV4::Value::_Integer_Type;
+ rootContext->callData->argc = 0;
+ rootContext->callData->thisObject = globalObject;
+ rootContext->callData->args[0] = Encode::undefined();
}
InternalClass *ExecutionEngine::newClass(const InternalClass &other)
@@ -402,14 +420,11 @@ InternalClass *ExecutionEngine::newClass(const InternalClass &other)
ExecutionContext *ExecutionEngine::pushGlobalContext()
{
- GlobalContext *g = static_cast<GlobalContext *>(memoryManager->allocContext(sizeof(GlobalContext)));
- ExecutionContext *oldNext = g->next;
- *g = *rootContext;
- g->next = oldNext;
- g->parent = current;
- current = g;
+ GlobalContext *g = new (memoryManager) GlobalContext(this);
+ g->callData = rootContext->callData;
- return current;
+ Q_ASSERT(currentContext() == g);
+ return g;
}
Returned<FunctionObject> *ExecutionEngine::newBuiltinFunction(ExecutionContext *scope, const StringRef name, ReturnedValue (*code)(CallContext *))
@@ -597,7 +612,7 @@ Returned<Object> *ExecutionEngine::newForEachIteratorObject(ExecutionContext *ct
Returned<Object> *ExecutionEngine::qmlContextObject() const
{
- ExecutionContext *ctx = current;
+ ExecutionContext *ctx = currentContext();
if (ctx->type == QV4::ExecutionContext::Type_SimpleCallContext && !ctx->outer)
ctx = ctx->parent;
@@ -627,11 +642,12 @@ namespace {
void resolve(StackFrame *frame, ExecutionContext *context, Function *function)
{
qptrdiff offset;
- if (context->interpreterInstructionPointer)
+ if (context->interpreterInstructionPointer) {
offset = *context->interpreterInstructionPointer - 1 - function->codeData;
- else
- offset = context->jitInstructionPointer - (char*)function->codePtr;
- frame->line = function->lineNumberForProgramCounter(offset);
+ frame->line = function->lineNumberForProgramCounter(offset);
+ } else {
+ frame->line = context->lineNumber;
+ }
}
};
}
@@ -642,7 +658,7 @@ QVector<StackFrame> ExecutionEngine::stackTrace(int frameLimit) const
QVector<StackFrame> stack;
- QV4::ExecutionContext *c = current;
+ QV4::ExecutionContext *c = currentContext();
while (c && frameLimit) {
CallContext *callCtx = c->asCallContext();
if (callCtx && callCtx->function) {
@@ -696,7 +712,7 @@ QUrl ExecutionEngine::resolvedUrl(const QString &file)
return src;
QUrl base;
- QV4::ExecutionContext *c = current;
+ QV4::ExecutionContext *c = currentContext();
while (c) {
CallContext *callCtx = c->asCallContext();
if (callCtx && callCtx->function) {
@@ -752,9 +768,9 @@ void ExecutionEngine::markObjects()
setter->mark(this);
}
- ExecutionContext *c = current;
+ ExecutionContext *c = currentContext();
while (c) {
- c->mark();
+ c->mark(this);
c = c->parent;
}
@@ -794,6 +810,7 @@ void ExecutionEngine::markObjects()
syntaxErrorCtor.mark(this);
typeErrorCtor.mark(this);
uRIErrorCtor.mark(this);
+ sequencePrototype.mark(this);
exceptionValue.mark(this);
@@ -814,13 +831,13 @@ namespace {
{
bool operator()(Function *function, quintptr pc)
{
- return reinterpret_cast<quintptr>(function->codePtr) < pc
- && (reinterpret_cast<quintptr>(function->codePtr) + function->codeSize) < pc;
+ return reinterpret_cast<quintptr>(function->code) < pc
+ && (reinterpret_cast<quintptr>(function->code) + function->codeSize) < pc;
}
bool operator()(quintptr pc, Function *function)
{
- return pc < reinterpret_cast<quintptr>(function->codePtr);
+ return pc < reinterpret_cast<quintptr>(function->code);
}
};
}
@@ -887,8 +904,8 @@ ReturnedValue ExecutionEngine::throwException(const ValueRef value)
ReturnedValue ExecutionEngine::catchException(ExecutionContext *catchingContext, StackTrace *trace)
{
Q_ASSERT(hasException);
- while (current != catchingContext)
- popContext();
+ Q_UNUSED(catchingContext);
+ Q_ASSERT(currentContext() == catchingContext);
if (trace)
*trace = exceptionStackTrace;
exceptionStackTrace.clear();
diff --git a/src/qml/jsruntime/qv4engine_p.h b/src/qml/jsruntime/qv4engine_p.h
index b4972904ee..ecb5f2b4d5 100644
--- a/src/qml/jsruntime/qv4engine_p.h
+++ b/src/qml/jsruntime/qv4engine_p.h
@@ -44,7 +44,6 @@
#include "qv4global_p.h"
#include "private/qv4isel_p.h"
#include "qv4util_p.h"
-#include "qv4context_p.h"
#include "qv4property_p.h"
#include <private/qintrusivelist_p.h>
@@ -112,11 +111,12 @@ class RegExp;
class RegExpCache;
struct QmlExtensions;
struct Exception;
+struct ExecutionContextSaver;
#define CHECK_STACK_LIMITS(v4) \
if ((v4->jsStackTop <= v4->jsStackLimit) && (reinterpret_cast<quintptr>(&v4) >= v4->cStackLimit || v4->recheckCStackLimits())) {} \
else \
- return v4->current->throwRangeError(QStringLiteral("Maximum call stack size exceeded."))
+ return v4->currentContext()->throwRangeError(QStringLiteral("Maximum call stack size exceeded."))
struct Q_QML_EXPORT ExecutionEngine
@@ -126,7 +126,13 @@ struct Q_QML_EXPORT ExecutionEngine
ExecutableAllocator *regExpAllocator;
QScopedPointer<QQmlJS::EvalISelFactory> iselFactory;
+private:
+ friend struct ExecutionContextSaver;
+ friend struct ExecutionContext;
ExecutionContext *current;
+public:
+ ExecutionContext *currentContext() const { return current; }
+
GlobalContext *rootContext;
SafeValue *jsStackTop;
@@ -183,12 +189,16 @@ struct Q_QML_EXPORT ExecutionEngine
SafeValue syntaxErrorCtor;
SafeValue typeErrorCtor;
SafeValue uRIErrorCtor;
+ SafeValue sequencePrototype;
QQmlJS::MemoryPool classPool;
InternalClass *emptyClass;
+ InternalClass *executionContextClass;
+ InternalClass *stringClass;
+
InternalClass *objectClass;
InternalClass *arrayClass;
- InternalClass *stringClass;
+ InternalClass *stringObjectClass;
InternalClass *booleanClass;
InternalClass *numberClass;
InternalClass *dateClass;
@@ -199,6 +209,7 @@ struct Q_QML_EXPORT ExecutionEngine
InternalClass *regExpClass;
InternalClass *regExpExecArrayClass;
+ InternalClass *regExpValueClass;
InternalClass *errorClass;
InternalClass *evalErrorClass;
@@ -211,7 +222,6 @@ struct Q_QML_EXPORT ExecutionEngine
InternalClass *strictArgumentsObjectClass;
InternalClass *variantClass;
- InternalClass *sequenceClass;
EvalFunction *evalFunction;
FunctionObject *thrower;
@@ -356,38 +366,10 @@ private:
QmlExtensions *m_qmlExtensions;
};
-inline void ExecutionEngine::pushContext(CallContext *context)
-{
- context->parent = current;
- current = context;
- current->currentEvalCode = 0;
-}
-
-inline ExecutionContext *ExecutionEngine::popContext()
-{
- current = current->parent;
- return current;
-}
-
-struct ExecutionContextSaver
-{
- ExecutionEngine *engine;
- ExecutionContext *savedContext;
-
- ExecutionContextSaver(ExecutionContext *context)
- : engine(context->engine)
- , savedContext(context)
- {
- }
- ~ExecutionContextSaver()
- {
- engine->current = savedContext;
- }
-};
-
inline
void Managed::mark(QV4::ExecutionEngine *engine)
{
+ Q_ASSERT(inUse);
if (markBit)
return;
markBit = 1;
diff --git a/src/qml/jsruntime/qv4errorobject.cpp b/src/qml/jsruntime/qv4errorobject.cpp
index bac29d19e1..cf5c06dd41 100644
--- a/src/qml/jsruntime/qv4errorobject.cpp
+++ b/src/qml/jsruntime/qv4errorobject.cpp
@@ -77,7 +77,6 @@ ErrorObject::ErrorObject(InternalClass *ic)
, stack(0)
{
type = Type_ErrorObject;
- vtbl = &static_vtbl;
Scope scope(engine());
ScopedValue protectThis(scope, this);
@@ -91,7 +90,6 @@ ErrorObject::ErrorObject(InternalClass *ic, const ValueRef message, ErrorType t)
, stack(0)
{
type = Type_ErrorObject;
- vtbl = &static_vtbl;
subtype = t;
Scope scope(engine());
@@ -116,7 +114,6 @@ ErrorObject::ErrorObject(InternalClass *ic, const QString &message, ErrorObject:
, stack(0)
{
type = Type_ErrorObject;
- vtbl = &static_vtbl;
subtype = t;
Scope scope(engine());
@@ -141,7 +138,6 @@ ErrorObject::ErrorObject(InternalClass *ic, const QString &message, const QStrin
, stack(0)
{
type = Type_ErrorObject;
- vtbl = &static_vtbl;
subtype = t;
Scope scope(engine());
@@ -207,13 +203,11 @@ DEFINE_MANAGED_VTABLE(SyntaxErrorObject);
SyntaxErrorObject::SyntaxErrorObject(ExecutionEngine *engine, const ValueRef msg)
: ErrorObject(engine->syntaxErrorClass, msg, SyntaxError)
{
- vtbl = &static_vtbl;
}
SyntaxErrorObject::SyntaxErrorObject(ExecutionEngine *engine, const QString &msg, const QString &fileName, int lineNumber, int columnNumber)
: ErrorObject(engine->syntaxErrorClass, msg, fileName, lineNumber, columnNumber, SyntaxError)
{
- vtbl = &static_vtbl;
}
EvalErrorObject::EvalErrorObject(ExecutionEngine *engine, const ValueRef message)
@@ -272,13 +266,13 @@ DEFINE_MANAGED_VTABLE(URIErrorCtor);
ErrorCtor::ErrorCtor(ExecutionContext *scope)
: FunctionObject(scope, QStringLiteral("Error"))
{
- vtbl = &static_vtbl;
+ setVTable(&static_vtbl);
}
ErrorCtor::ErrorCtor(ExecutionContext *scope, const QString &name)
: FunctionObject(scope, name)
{
- vtbl = &static_vtbl;
+ setVTable(&static_vtbl);
}
ReturnedValue ErrorCtor::construct(Managed *m, CallData *callData)
@@ -296,7 +290,7 @@ ReturnedValue ErrorCtor::call(Managed *that, CallData *callData)
EvalErrorCtor::EvalErrorCtor(ExecutionContext *scope)
: ErrorCtor(scope, QStringLiteral("EvalError"))
{
- vtbl = &static_vtbl;
+ setVTable(&static_vtbl);
}
ReturnedValue EvalErrorCtor::construct(Managed *m, CallData *callData)
@@ -309,7 +303,7 @@ ReturnedValue EvalErrorCtor::construct(Managed *m, CallData *callData)
RangeErrorCtor::RangeErrorCtor(ExecutionContext *scope)
: ErrorCtor(scope, QStringLiteral("RangeError"))
{
- vtbl = &static_vtbl;
+ setVTable(&static_vtbl);
}
ReturnedValue RangeErrorCtor::construct(Managed *m, CallData *callData)
@@ -322,7 +316,7 @@ ReturnedValue RangeErrorCtor::construct(Managed *m, CallData *callData)
ReferenceErrorCtor::ReferenceErrorCtor(ExecutionContext *scope)
: ErrorCtor(scope, QStringLiteral("ReferenceError"))
{
- vtbl = &static_vtbl;
+ setVTable(&static_vtbl);
}
ReturnedValue ReferenceErrorCtor::construct(Managed *m, CallData *callData)
@@ -335,7 +329,7 @@ ReturnedValue ReferenceErrorCtor::construct(Managed *m, CallData *callData)
SyntaxErrorCtor::SyntaxErrorCtor(ExecutionContext *scope)
: ErrorCtor(scope, QStringLiteral("SyntaxError"))
{
- vtbl = &static_vtbl;
+ setVTable(&static_vtbl);
}
ReturnedValue SyntaxErrorCtor::construct(Managed *m, CallData *callData)
@@ -348,7 +342,7 @@ ReturnedValue SyntaxErrorCtor::construct(Managed *m, CallData *callData)
TypeErrorCtor::TypeErrorCtor(ExecutionContext *scope)
: ErrorCtor(scope, QStringLiteral("TypeError"))
{
- vtbl = &static_vtbl;
+ setVTable(&static_vtbl);
}
ReturnedValue TypeErrorCtor::construct(Managed *m, CallData *callData)
@@ -361,7 +355,7 @@ ReturnedValue TypeErrorCtor::construct(Managed *m, CallData *callData)
URIErrorCtor::URIErrorCtor(ExecutionContext *scope)
: ErrorCtor(scope, QStringLiteral("URIError"))
{
- vtbl = &static_vtbl;
+ setVTable(&static_vtbl);
}
ReturnedValue URIErrorCtor::construct(Managed *m, CallData *callData)
diff --git a/src/qml/jsruntime/qv4errorobject_p.h b/src/qml/jsruntime/qv4errorobject_p.h
index 3f4cb8fc43..def776d3b6 100644
--- a/src/qml/jsruntime/qv4errorobject_p.h
+++ b/src/qml/jsruntime/qv4errorobject_p.h
@@ -184,37 +184,37 @@ struct ErrorPrototype: ErrorObject
struct EvalErrorPrototype: ErrorObject
{
- EvalErrorPrototype(InternalClass *ic): ErrorObject(ic) { vtbl = &static_vtbl; }
+ EvalErrorPrototype(InternalClass *ic): ErrorObject(ic) { setVTable(&static_vtbl); }
void init(ExecutionEngine *engine, ObjectRef ctor) { ErrorPrototype::init(engine, ctor, this); }
};
struct RangeErrorPrototype: ErrorObject
{
- RangeErrorPrototype(InternalClass *ic): ErrorObject(ic) { vtbl = &static_vtbl; }
+ RangeErrorPrototype(InternalClass *ic): ErrorObject(ic) { setVTable(&static_vtbl); }
void init(ExecutionEngine *engine, ObjectRef ctor) { ErrorPrototype::init(engine, ctor, this); }
};
struct ReferenceErrorPrototype: ErrorObject
{
- ReferenceErrorPrototype(InternalClass *ic): ErrorObject(ic) { vtbl = &static_vtbl; }
+ ReferenceErrorPrototype(InternalClass *ic): ErrorObject(ic) { setVTable(&static_vtbl); }
void init(ExecutionEngine *engine, ObjectRef ctor) { ErrorPrototype::init(engine, ctor, this); }
};
struct SyntaxErrorPrototype: ErrorObject
{
- SyntaxErrorPrototype(InternalClass *ic): ErrorObject(ic) { vtbl = &static_vtbl; }
+ SyntaxErrorPrototype(InternalClass *ic): ErrorObject(ic) { setVTable(&static_vtbl); }
void init(ExecutionEngine *engine, ObjectRef ctor) { ErrorPrototype::init(engine, ctor, this); }
};
struct TypeErrorPrototype: ErrorObject
{
- TypeErrorPrototype(InternalClass *ic): ErrorObject(ic) { vtbl = &static_vtbl; }
+ TypeErrorPrototype(InternalClass *ic): ErrorObject(ic) { setVTable(&static_vtbl); }
void init(ExecutionEngine *engine, ObjectRef ctor) { ErrorPrototype::init(engine, ctor, this); }
};
struct URIErrorPrototype: ErrorObject
{
- URIErrorPrototype(InternalClass *ic): ErrorObject(ic) { vtbl = &static_vtbl; }
+ URIErrorPrototype(InternalClass *ic): ErrorObject(ic) { setVTable(&static_vtbl); }
void init(ExecutionEngine *engine, ObjectRef ctor) { ErrorPrototype::init(engine, ctor, this); }
};
diff --git a/src/qml/jsruntime/qv4function.cpp b/src/qml/jsruntime/qv4function.cpp
index ebe214ad72..0e90e213c4 100644
--- a/src/qml/jsruntime/qv4function.cpp
+++ b/src/qml/jsruntime/qv4function.cpp
@@ -54,7 +54,7 @@ Function::Function(ExecutionEngine *engine, CompiledData::CompilationUnit *unit,
ReturnedValue (*codePtr)(ExecutionContext *, const uchar *), quint32 _codeSize)
: compiledFunction(function)
, compilationUnit(unit)
- , codePtr(codePtr)
+ , code(codePtr)
, codeData(0)
, codeSize(_codeSize)
{
@@ -62,18 +62,29 @@ Function::Function(ExecutionEngine *engine, CompiledData::CompilationUnit *unit,
name = compilationUnit->runtimeStrings[compiledFunction->nameIndex].asString();
- formals.resize(compiledFunction->nFormals);
- formals.fill(0);
- const quint32 *formalsIndices = compiledFunction->formalsTable();
- for (quint32 i = 0; i < compiledFunction->nFormals; ++i)
- formals[i] = compilationUnit->runtimeStrings[formalsIndices[i]].asString();
+ nArguments = compiledFunction->nFormals;
+ internalClass = engine->emptyClass;
+ const quint32 *formalsIndices = compiledFunction->formalsTable();
+ // iterate backwards, so we get the right ordering for duplicate names
+ for (int i = static_cast<int>(compiledFunction->nFormals - 1); i >= 0; --i) {
+ String *arg = compilationUnit->runtimeStrings[formalsIndices[i]].asString();
+ while (1) {
+ InternalClass *newClass = internalClass->addMember(arg, Attr_NotConfigurable);
+ if (newClass != internalClass) {
+ internalClass = newClass;
+ break;
+ }
+ // duplicate arguments, need some trick to store them
+ arg = new (engine->memoryManager) String(engine, arg, engine->newString(QString(0xfffe))->getPointer());
+ }
+ }
- locals.resize(compiledFunction->nLocals);
- locals.fill(0);
const quint32 *localsIndices = compiledFunction->localsTable();
- for (quint32 i = 0; i < compiledFunction->nLocals; ++i)
- locals[i] = compilationUnit->runtimeStrings[localsIndices[i]].asString();
+ for (quint32 i = 0; i < compiledFunction->nLocals; ++i) {
+ String *local = compilationUnit->runtimeStrings[localsIndices[i]].asString();
+ internalClass = internalClass->addMember(local, Attr_NotConfigurable);
+ }
}
Function::~Function()
@@ -84,10 +95,6 @@ Function::~Function()
void Function::mark(ExecutionEngine *e)
{
name.mark(e);
- for (int i = 0; i < formals.size(); ++i)
- formals.at(i)->mark(e);
- for (int i = 0; i < locals.size(); ++i)
- locals.at(i)->mark(e);
}
namespace QV4 {
diff --git a/src/qml/jsruntime/qv4function_p.h b/src/qml/jsruntime/qv4function_p.h
index 5d284f1b2b..8d07853b45 100644
--- a/src/qml/jsruntime/qv4function_p.h
+++ b/src/qml/jsruntime/qv4function_p.h
@@ -85,16 +85,14 @@ struct Function {
const CompiledData::Function *compiledFunction;
CompiledData::CompilationUnit *compilationUnit;
- inline ReturnedValue code(ExecutionContext *ctx, const uchar *data) {
- return codePtr(ctx, data);
- }
- ReturnedValue (*codePtr)(ExecutionContext *, const uchar *);
+ ReturnedValue (*code)(ExecutionContext *, const uchar *);
const uchar *codeData;
quint32 codeSize;
- QVector<String *> formals;
- QVector<String *> locals;
+ // first nArguments names in internalClass are the actual arguments
+ int nArguments;
+ InternalClass *internalClass;
Function(ExecutionEngine *engine, CompiledData::CompilationUnit *unit, const CompiledData::Function *function,
ReturnedValue (*codePtr)(ExecutionContext *, const uchar *), quint32 _codeSize);
diff --git a/src/qml/jsruntime/qv4functionobject.cpp b/src/qml/jsruntime/qv4functionobject.cpp
index aa1cb89a44..6e5c137e0b 100644
--- a/src/qml/jsruntime/qv4functionobject.cpp
+++ b/src/qml/jsruntime/qv4functionobject.cpp
@@ -55,6 +55,7 @@
#include <private/qqmljsparser_p.h>
#include <private/qqmljsast_p.h>
#include <private/qqmlcontextwrapper_p.h>
+#include <private/qqmlengine_p.h>
#include <qv4jsir_p.h>
#include <qv4codegen_p.h>
#include "private/qlocale_tools_p.h"
@@ -75,11 +76,11 @@ DEFINE_MANAGED_VTABLE(FunctionObject);
FunctionObject::FunctionObject(ExecutionContext *scope, const StringRef name, bool createProto)
: Object(createProto ? scope->engine->functionWithProtoClass : scope->engine->functionClass)
, scope(scope)
- , formalParameterList(0)
- , varList(0)
, formalParameterCount(0)
, varCount(0)
, function(0)
+ , protoCacheClass(0)
+ , protoCacheIndex(UINT_MAX)
{
init(name, createProto);
}
@@ -87,11 +88,11 @@ FunctionObject::FunctionObject(ExecutionContext *scope, const StringRef name, bo
FunctionObject::FunctionObject(ExecutionContext *scope, const QString &name, bool createProto)
: Object(createProto ? scope->engine->functionWithProtoClass : scope->engine->functionClass)
, scope(scope)
- , formalParameterList(0)
- , varList(0)
, formalParameterCount(0)
, varCount(0)
, function(0)
+ , protoCacheClass(0)
+ , protoCacheIndex(UINT_MAX)
{
// set the name to something here, so that a gc run a few lines below doesn't crash on it
this->name = scope->engine->id_undefined;
@@ -105,13 +106,10 @@ FunctionObject::FunctionObject(ExecutionContext *scope, const QString &name, boo
FunctionObject::FunctionObject(InternalClass *ic)
: Object(ic)
, scope(ic->engine->rootContext)
- , formalParameterList(0)
- , varList(0)
, formalParameterCount(0)
, varCount(0)
, function(0)
{
- vtbl = &static_vtbl;
name = ic->engine->id_undefined;
type = Type_FunctionObject;
@@ -127,7 +125,6 @@ FunctionObject::~FunctionObject()
void FunctionObject::init(const StringRef n, bool createProto)
{
- vtbl = &static_vtbl;
name = n;
Scope s(internalClass->engine);
@@ -157,43 +154,13 @@ ReturnedValue FunctionObject::newInstance()
return construct(callData);
}
-bool FunctionObject::hasInstance(Managed *that, const ValueRef value)
-{
- Scope scope(that->internalClass->engine);
- ScopedFunctionObject f(scope, static_cast<FunctionObject *>(that));
-
- ScopedObject v(scope, value);
- if (!v)
- return false;
-
- Scoped<Object> o(scope, f->get(scope.engine->id_prototype));
- if (!o) {
- scope.engine->current->throwTypeError();
- return false;
- }
-
- while (v) {
- v = v->prototype();
-
- if (! v)
- break;
- else if (o.getPointer() == v)
- return true;
- }
-
- return false;
-}
-
ReturnedValue FunctionObject::construct(Managed *that, CallData *)
{
ExecutionEngine *v4 = that->internalClass->engine;
Scope scope(v4);
Scoped<FunctionObject> f(scope, that, Scoped<FunctionObject>::Cast);
- InternalClass *ic = v4->objectClass;
- Scoped<Object> proto(scope, f->get(v4->id_prototype));
- if (!!proto)
- ic = v4->emptyClass->changePrototype(proto.getPointer());
+ InternalClass *ic = f->internalClassForConstructor();
Scoped<Object> obj(scope, v4->newObject(ic));
return obj.asReturnedValue();
}
@@ -213,7 +180,7 @@ void FunctionObject::markObjects(Managed *that, ExecutionEngine *e)
// formalParameterList[i]->mark();
// for (uint i = 0; i < varCount; ++i)
// varList[i]->mark();
- o->scope->mark();
+ o->scope->mark(e);
if (o->function)
o->function->mark(e);
@@ -230,13 +197,49 @@ FunctionObject *FunctionObject::creatScriptFunction(ExecutionContext *scope, Fun
return new (scope->engine->memoryManager) SimpleScriptFunction(scope, function);
}
+ReturnedValue FunctionObject::protoProperty()
+{
+ if (protoCacheClass != internalClass) {
+ protoCacheClass = internalClass;
+ protoCacheIndex = internalClass->find(internalClass->engine->id_prototype);
+ }
+ if (protoCacheIndex < UINT_MAX) {
+ if (internalClass->propertyData.at(protoCacheIndex).isData()) {
+ ReturnedValue v = memberData[protoCacheIndex].value.asReturnedValue();
+ if (v != protoValue) {
+ classForConstructor = 0;
+ protoValue = v;
+ }
+ return v;
+ }
+ }
+ classForConstructor = 0;
+ return get(internalClass->engine->id_prototype);
+}
+
+InternalClass *FunctionObject::internalClassForConstructor()
+{
+ // need to call this first to ensure we don't use a wrong class
+ ReturnedValue proto = protoProperty();
+ if (classForConstructor)
+ return classForConstructor;
+
+ Scope scope(internalClass->engine);
+ ScopedObject p(scope, proto);
+ if (p)
+ classForConstructor = InternalClass::create(scope.engine, &Object::static_vtbl, p.getPointer());
+ else
+ classForConstructor = scope.engine->objectClass;
+
+ return classForConstructor;
+}
DEFINE_MANAGED_VTABLE(FunctionCtor);
FunctionCtor::FunctionCtor(ExecutionContext *scope)
: FunctionObject(scope, QStringLiteral("Function"))
{
- vtbl = &static_vtbl;
+ setVTable(&static_vtbl);
}
// 15.3.2
@@ -244,7 +247,7 @@ ReturnedValue FunctionCtor::construct(Managed *that, CallData *callData)
{
FunctionCtor *f = static_cast<FunctionCtor *>(that);
ExecutionEngine *v4 = f->internalClass->engine;
- ExecutionContext *ctx = v4->current;
+ ExecutionContext *ctx = v4->currentContext();
QString arguments;
QString body;
if (callData->argc > 0) {
@@ -268,20 +271,20 @@ ReturnedValue FunctionCtor::construct(Managed *that, CallData *callData)
const bool parsed = parser.parseExpression();
if (!parsed)
- return v4->current->throwSyntaxError(QLatin1String("Parse error"));
+ return v4->currentContext()->throwSyntaxError(QLatin1String("Parse error"));
using namespace QQmlJS::AST;
FunctionExpression *fe = QQmlJS::AST::cast<FunctionExpression *>(parser.rootNode());
if (!fe)
- return v4->current->throwSyntaxError(QLatin1String("Parse error"));
+ return v4->currentContext()->throwSyntaxError(QLatin1String("Parse error"));
QQmlJS::V4IR::Module module(v4->debugger != 0);
- QQmlJS::RuntimeCodegen cg(v4->current, f->strictMode);
+ QQmlJS::RuntimeCodegen cg(v4->currentContext(), f->strictMode);
cg.generateFromFunctionExpression(QString(), function, fe, &module);
QV4::Compiler::JSUnitGenerator jsGenerator(&module);
- QScopedPointer<QQmlJS::EvalInstructionSelection> isel(v4->iselFactory->create(v4->executableAllocator, &module, &jsGenerator));
+ QScopedPointer<QQmlJS::EvalInstructionSelection> isel(v4->iselFactory->create(QQmlEnginePrivate::get(v4), v4->executableAllocator, &module, &jsGenerator));
QV4::CompiledData::CompilationUnit *compilationUnit = isel->compile();
QV4::Function *vmf = compilationUnit->linkToEngine(v4);
@@ -348,7 +351,7 @@ ReturnedValue FunctionPrototype::method_apply(CallContext *ctx)
ScopedCallData callData(scope, len);
if (len) {
- if (arr->protoHasArray() || arr->hasAccessorProperty) {
+ if (!(arr->flags & SimpleArray) || arr->protoHasArray() || arr->hasAccessorProperty) {
for (quint32 i = 0; i < len; ++i)
callData->args[i] = arr->getIndexed(i);
} else {
@@ -401,7 +404,7 @@ DEFINE_MANAGED_VTABLE(ScriptFunction);
ScriptFunction::ScriptFunction(ExecutionContext *scope, Function *function)
: FunctionObject(scope, function->name, true)
{
- vtbl = &static_vtbl;
+ setVTable(&static_vtbl);
Scope s(scope);
ScopedValue protectThis(s, this);
@@ -409,7 +412,7 @@ ScriptFunction::ScriptFunction(ExecutionContext *scope, Function *function)
this->function = function;
this->function->compilationUnit->ref();
Q_ASSERT(function);
- Q_ASSERT(function->codePtr);
+ Q_ASSERT(function->code);
// global function
if (!scope)
@@ -419,12 +422,10 @@ ScriptFunction::ScriptFunction(ExecutionContext *scope, Function *function)
needsActivation = function->needsActivation();
strictMode = function->isStrict();
- formalParameterCount = function->formals.size();
- formalParameterList = function->formals.constData();
- defineReadonlyProperty(scope->engine->id_length, Primitive::fromInt32(formalParameterCount));
+ formalParameterCount = function->nArguments;
+ varCount = function->internalClass->size - function->nArguments;
- varCount = function->locals.size();
- varList = function->locals.constData();
+ defineReadonlyProperty(scope->engine->id_length, Primitive::fromInt32(formalParameterCount));
if (scope->strictMode) {
Property pd = Property::fromAccessor(v4->thrower, v4->thrower);
@@ -443,13 +444,10 @@ ReturnedValue ScriptFunction::construct(Managed *that, CallData *callData)
Scope scope(v4);
Scoped<ScriptFunction> f(scope, static_cast<ScriptFunction *>(that));
- InternalClass *ic = v4->objectClass;
- ScopedObject proto(scope, f->memberData[Index_Prototype].value);
- if (proto)
- ic = v4->emptyClass->changePrototype(proto.getPointer());
+ InternalClass *ic = f->internalClassForConstructor();
ScopedObject obj(scope, v4->newObject(ic));
- ExecutionContext *context = v4->current;
+ ExecutionContext *context = v4->currentContext();
callData->thisObject = obj.asReturnedValue();
ExecutionContext *ctx = context->newCallContext(f.getPointer(), callData);
@@ -471,7 +469,7 @@ ReturnedValue ScriptFunction::call(Managed *that, CallData *callData)
return Encode::undefined();
CHECK_STACK_LIMITS(v4);
- ExecutionContext *context = v4->current;
+ ExecutionContext *context = v4->currentContext();
Scope scope(context);
CallContext *ctx = context->newCallContext(f, callData);
@@ -488,7 +486,7 @@ DEFINE_MANAGED_VTABLE(SimpleScriptFunction);
SimpleScriptFunction::SimpleScriptFunction(ExecutionContext *scope, Function *function)
: FunctionObject(scope, function->name, true)
{
- vtbl = &static_vtbl;
+ setVTable(&static_vtbl);
Scope s(scope);
ScopedValue protectThis(s, this);
@@ -496,7 +494,7 @@ SimpleScriptFunction::SimpleScriptFunction(ExecutionContext *scope, Function *fu
this->function = function;
this->function->compilationUnit->ref();
Q_ASSERT(function);
- Q_ASSERT(function->codePtr);
+ Q_ASSERT(function->code);
// global function
if (!scope)
@@ -506,12 +504,10 @@ SimpleScriptFunction::SimpleScriptFunction(ExecutionContext *scope, Function *fu
needsActivation = function->needsActivation();
strictMode = function->isStrict();
- formalParameterCount = function->formals.size();
- formalParameterList = function->formals.constData();
- defineReadonlyProperty(scope->engine->id_length, Primitive::fromInt32(formalParameterCount));
+ formalParameterCount = function->nArguments;
+ varCount = function->internalClass->size - function->nArguments;
- varCount = function->locals.size();
- varList = function->locals.constData();
+ defineReadonlyProperty(scope->engine->id_length, Primitive::fromInt32(formalParameterCount));
if (scope->strictMode) {
Property pd = Property::fromAccessor(v4->thrower, v4->thrower);
@@ -530,33 +526,29 @@ ReturnedValue SimpleScriptFunction::construct(Managed *that, CallData *callData)
Scope scope(v4);
Scoped<SimpleScriptFunction> f(scope, static_cast<SimpleScriptFunction *>(that));
- InternalClass *ic = v4->objectClass;
- Scoped<Object> proto(scope, f->memberData[Index_Prototype].value);
- if (!!proto)
- ic = v4->emptyClass->changePrototype(proto.getPointer());
+ InternalClass *ic = f->internalClassForConstructor();
callData->thisObject = v4->newObject(ic);
- ExecutionContext *context = v4->current;
+ ExecutionContext *context = v4->currentContext();
+ ExecutionContextSaver ctxSaver(context);
- CallContext ctx;
- ctx.initSimpleCallContext(v4, context);
+ CallContext ctx(v4);
ctx.strictMode = f->strictMode;
ctx.callData = callData;
ctx.function = f.getPointer();
ctx.compilationUnit = f->function->compilationUnit;
ctx.lookups = ctx.compilationUnit->runtimeLookups;
ctx.outer = f->scope;
- ctx.locals = v4->stackPush(f->function->locals.size());
+ ctx.locals = v4->stackPush(f->varCount);
while (callData->argc < (int)f->formalParameterCount) {
callData->args[callData->argc] = Encode::undefined();
++callData->argc;
}
- v4->pushContext(&ctx);
+ Q_ASSERT(v4->currentContext() == &ctx);
if (f->function->compiledFunction->hasQmlDependencies())
QmlContextWrapper::registerQmlDependencies(v4, f->function->compiledFunction);
- ExecutionContextSaver ctxSaver(context);
Scoped<Object> result(scope, f->function->code(&ctx, f->function->codeData));
if (!result)
@@ -574,27 +566,26 @@ ReturnedValue SimpleScriptFunction::call(Managed *that, CallData *callData)
SimpleScriptFunction *f = static_cast<SimpleScriptFunction *>(that);
Scope scope(v4);
- ExecutionContext *context = v4->current;
+ ExecutionContext *context = v4->currentContext();
+ ExecutionContextSaver ctxSaver(context);
- CallContext ctx;
- ctx.initSimpleCallContext(v4, context);
+ CallContext ctx(v4);
ctx.strictMode = f->strictMode;
ctx.callData = callData;
ctx.function = f;
ctx.compilationUnit = f->function->compilationUnit;
ctx.lookups = ctx.compilationUnit->runtimeLookups;
ctx.outer = f->scope;
- ctx.locals = v4->stackPush(f->function->locals.size());
+ ctx.locals = v4->stackPush(f->varCount);
while (callData->argc < (int)f->formalParameterCount) {
callData->args[callData->argc] = Encode::undefined();
++callData->argc;
}
- v4->current = &ctx;
+ Q_ASSERT(v4->currentContext() == &ctx);
if (f->function->compiledFunction->hasQmlDependencies())
QmlContextWrapper::registerQmlDependencies(v4, f->function->compiledFunction);
- ExecutionContextSaver ctxSaver(context);
return f->function->code(&ctx, f->function->codeData);
}
@@ -607,12 +598,12 @@ BuiltinFunction::BuiltinFunction(ExecutionContext *scope, const StringRef name,
: FunctionObject(scope, name)
, code(code)
{
- vtbl = &static_vtbl;
+ setVTable(&static_vtbl);
}
ReturnedValue BuiltinFunction::construct(Managed *f, CallData *)
{
- return f->internalClass->engine->current->throwTypeError();
+ return f->internalClass->engine->currentContext()->throwTypeError();
}
ReturnedValue BuiltinFunction::call(Managed *that, CallData *callData)
@@ -623,15 +614,14 @@ ReturnedValue BuiltinFunction::call(Managed *that, CallData *callData)
return Encode::undefined();
CHECK_STACK_LIMITS(v4);
- ExecutionContext *context = v4->current;
+ ExecutionContext *context = v4->currentContext();
+ ExecutionContextSaver ctxSaver(context);
- CallContext ctx;
- ctx.initSimpleCallContext(v4, context);
+ CallContext ctx(v4);
ctx.strictMode = f->scope->strictMode; // ### needed? scope or parent context?
ctx.callData = callData;
- v4->pushContext(&ctx);
+ Q_ASSERT(v4->currentContext() == &ctx);
- ExecutionContextSaver ctxSaver(context);
return f->code(&ctx);
}
@@ -643,16 +633,14 @@ ReturnedValue IndexedBuiltinFunction::call(Managed *that, CallData *callData)
return Encode::undefined();
CHECK_STACK_LIMITS(v4);
- ExecutionContext *context = v4->current;
- Scope scope(v4);
+ ExecutionContext *context = v4->currentContext();
+ ExecutionContextSaver ctxSaver(context);
- CallContext ctx;
- ctx.initSimpleCallContext(v4, context);
+ CallContext ctx(v4);
ctx.strictMode = f->scope->strictMode; // ### needed? scope or parent context?
ctx.callData = callData;
- v4->pushContext(&ctx);
+ Q_ASSERT(v4->currentContext() == &ctx);
- ExecutionContextSaver ctxSaver(context);
return f->code(&ctx, f->index);
}
@@ -665,7 +653,8 @@ BoundFunction::BoundFunction(ExecutionContext *scope, FunctionObjectRef target,
, target(target)
, boundArgs(boundArgs)
{
- vtbl = &static_vtbl;
+ setVTable(&static_vtbl);
+ subtype = FunctionObject::BoundFunction;
this->boundThis = boundThis;
Scope s(scope);
@@ -717,12 +706,6 @@ ReturnedValue BoundFunction::construct(Managed *that, CallData *dd)
return f->target->construct(callData);
}
-bool BoundFunction::hasInstance(Managed *that, const ValueRef value)
-{
- BoundFunction *f = static_cast<BoundFunction *>(that);
- return FunctionObject::hasInstance(f->target, value);
-}
-
void BoundFunction::markObjects(Managed *that, ExecutionEngine *e)
{
BoundFunction *o = static_cast<BoundFunction *>(that);
diff --git a/src/qml/jsruntime/qv4functionobject_p.h b/src/qml/jsruntime/qv4functionobject_p.h
index 2fc36d862f..96534cb68c 100644
--- a/src/qml/jsruntime/qv4functionobject_p.h
+++ b/src/qml/jsruntime/qv4functionobject_p.h
@@ -97,7 +97,8 @@ struct Q_QML_EXPORT FunctionObject: Object {
// Used with Managed::subType
enum FunctionType {
RegularFunction = 0,
- WrappedQtMethod = 1
+ WrappedQtMethod = 1,
+ BoundFunction
};
enum {
@@ -107,11 +108,13 @@ struct Q_QML_EXPORT FunctionObject: Object {
ExecutionContext *scope;
SafeString name;
- String * const *formalParameterList;
- String * const *varList;
unsigned int formalParameterCount;
unsigned int varCount;
Function *function;
+ InternalClass *protoCacheClass;
+ uint protoCacheIndex;
+ ReturnedValue protoValue;
+ InternalClass *classForConstructor;
FunctionObject(ExecutionContext *scope, const StringRef name, bool createProto = false);
FunctionObject(ExecutionContext *scope, const QString &name = QString(), bool createProto = false);
@@ -124,10 +127,10 @@ struct Q_QML_EXPORT FunctionObject: Object {
static ReturnedValue construct(Managed *that, CallData *);
static ReturnedValue call(Managed *that, CallData *d);
inline ReturnedValue construct(CallData *callData) {
- return vtbl->construct(this, callData);
+ return internalClass->vtable->construct(this, callData);
}
inline ReturnedValue call(CallData *callData) {
- return vtbl->call(this, callData);
+ return internalClass->vtable->call(this, callData);
}
static FunctionObject *cast(const Value &v) {
@@ -136,11 +139,13 @@ struct Q_QML_EXPORT FunctionObject: Object {
static FunctionObject *creatScriptFunction(ExecutionContext *scope, Function *function);
+ ReturnedValue protoProperty();
+ InternalClass *internalClassForConstructor();
+
protected:
FunctionObject(InternalClass *ic);
static void markObjects(Managed *that, ExecutionEngine *e);
- static bool hasInstance(Managed *that, const ValueRef value);
static void destroy(Managed *that)
{ static_cast<FunctionObject*>(that)->~FunctionObject(); }
};
@@ -192,12 +197,12 @@ struct IndexedBuiltinFunction: FunctionObject
, code(code)
, index(index)
{
- vtbl = &static_vtbl;
+ setVTable(&static_vtbl);
}
static ReturnedValue construct(Managed *m, CallData *)
{
- return m->engine()->current->throwTypeError();
+ return m->engine()->currentContext()->throwTypeError();
}
static ReturnedValue call(Managed *that, CallData *callData);
@@ -235,7 +240,6 @@ struct BoundFunction: FunctionObject {
static void destroy(Managed *);
static void markObjects(Managed *that, ExecutionEngine *e);
- static bool hasInstance(Managed *that, const ValueRef value);
};
}
diff --git a/src/qml/jsruntime/qv4global_p.h b/src/qml/jsruntime/qv4global_p.h
index 7d7338f19c..1d465df0c0 100644
--- a/src/qml/jsruntime/qv4global_p.h
+++ b/src/qml/jsruntime/qv4global_p.h
@@ -119,6 +119,8 @@ struct Object;
struct ObjectPrototype;
struct ObjectIterator;
struct ExecutionContext;
+struct GlobalContext;
+struct CallContext;
struct ScriptFunction;
struct InternalClass;
struct Property;
diff --git a/src/qml/jsruntime/qv4globalobject.cpp b/src/qml/jsruntime/qv4globalobject.cpp
index 82622de5bb..fa8af8ed5d 100644
--- a/src/qml/jsruntime/qv4globalobject.cpp
+++ b/src/qml/jsruntime/qv4globalobject.cpp
@@ -349,7 +349,7 @@ DEFINE_MANAGED_VTABLE(EvalFunction);
EvalFunction::EvalFunction(ExecutionContext *scope)
: FunctionObject(scope, scope->engine->id_eval)
{
- vtbl = &static_vtbl;
+ setVTable(&static_vtbl);
defineReadonlyProperty(scope->engine->id_length, Primitive::fromInt32(1));
}
@@ -379,15 +379,17 @@ ReturnedValue EvalFunction::evalCall(CallData *callData, bool directCall)
if (callData->argc < 1)
return Encode::undefined();
- ExecutionContext *parentContext = engine()->current;
- ExecutionEngine *engine = parentContext->engine;
+ ExecutionEngine *v4 = engine();
+ ExecutionContext *parentContext = v4->currentContext();
+ ExecutionContextSaver ctxSaver(parentContext);
+
ExecutionContext *ctx = parentContext;
Scope scope(ctx);
if (!directCall) {
// the context for eval should be the global scope, so we fake a root
// context
- ctx = engine->pushGlobalContext();
+ ctx = v4->pushGlobalContext();
}
if (!callData->args[0].isString())
@@ -418,7 +420,6 @@ ReturnedValue EvalFunction::evalCall(CallData *callData, bool directCall)
return e->call(callData);
}
- ExecutionContextSaver ctxSaver(parentContext);
ContextStateSaver stateSaver(ctx);
ExecutionContext::EvalCode evalCode;
@@ -437,7 +438,6 @@ ReturnedValue EvalFunction::evalCall(CallData *callData, bool directCall)
ReturnedValue EvalFunction::call(Managed *that, CallData *callData)
{
// indirect call
- // ### const_cast
return static_cast<EvalFunction *>(that)->evalCall(callData, false);
}
diff --git a/src/qml/jsruntime/qv4include.cpp b/src/qml/jsruntime/qv4include.cpp
index 8f2548064a..d0e0e9413b 100644
--- a/src/qml/jsruntime/qv4include.cpp
+++ b/src/qml/jsruntime/qv4include.cpp
@@ -108,7 +108,7 @@ void QV4Include::callback(const QV4::ValueRef callback, const QV4::ValueRef stat
if (!f)
return;
- QV4::ExecutionContext *ctx = v4->current;
+ QV4::ExecutionContext *ctx = v4->currentContext();
QV4::ScopedCallData callData(scope, 1);
callData->thisObject = v4->globalObject->asReturnedValue();
callData->args[0] = status;
@@ -153,7 +153,7 @@ void QV4Include::finished()
QV4::ScopedObject qmlglobal(scope, m_qmlglobal.value());
QV4::Script script(v4, qmlglobal, code, m_url.toString());
- QV4::ExecutionContext *ctx = v4->current;
+ QV4::ExecutionContext *ctx = v4->currentContext();
QV4::ScopedString status(scope, v4->newString(QStringLiteral("status")));
script.parse();
if (!scope.engine->hasException)
@@ -220,7 +220,7 @@ QV4::ReturnedValue QV4Include::method_include(QV4::CallContext *ctx)
QV4::Script script(v4, qmlcontextobject, code, url.toString());
- QV4::ExecutionContext *ctx = v4->current;
+ QV4::ExecutionContext *ctx = v4->currentContext();
script.parse();
if (!v4->hasException)
script.run();
diff --git a/src/qml/jsruntime/qv4internalclass.cpp b/src/qml/jsruntime/qv4internalclass.cpp
index cb799a473c..29ede3d104 100644
--- a/src/qml/jsruntime/qv4internalclass.cpp
+++ b/src/qml/jsruntime/qv4internalclass.cpp
@@ -126,10 +126,21 @@ uint PropertyHash::lookup(const Identifier *identifier) const
}
}
+InternalClass::InternalClass(ExecutionEngine *engine)
+ : engine(engine)
+ , prototype(0)
+ , vtable(&Managed::static_vtbl)
+ , m_sealed(0)
+ , m_frozen(0)
+ , size(0)
+{
+}
+
InternalClass::InternalClass(const QV4::InternalClass &other)
: engine(other.engine)
, prototype(other.prototype)
+ , vtable(other.vtable)
, propertyTable(other.propertyTable)
, nameMap(other.nameMap)
, propertyData(other.propertyData)
@@ -169,6 +180,12 @@ InternalClass *InternalClass::changeMember(String *string, PropertyAttributes da
}
+InternalClass *InternalClass::create(ExecutionEngine *engine, const ManagedVTable *vtable, Object *proto)
+{
+ InternalClass *c = engine->emptyClass->changeVTable(vtable);
+ return c->changePrototype(proto);
+}
+
InternalClass *InternalClass::changePrototype(Object *proto)
{
if (prototype == proto)
@@ -184,11 +201,41 @@ InternalClass *InternalClass::changePrototype(Object *proto)
// create a new class and add it to the tree
InternalClass *newClass;
- if (this == engine->emptyClass) {
+ if (!size) {
newClass = engine->newClass(*this);
newClass->prototype = proto;
} else {
- newClass = engine->emptyClass->changePrototype(proto);
+ newClass = engine->emptyClass->changeVTable(vtable);
+ newClass = newClass->changePrototype(proto);
+ for (uint i = 0; i < size; ++i)
+ newClass = newClass->addMember(nameMap.at(i), propertyData.at(i));
+ }
+
+ transitions.insert(t, newClass);
+ return newClass;
+}
+
+InternalClass *InternalClass::changeVTable(const ManagedVTable *vt)
+{
+ if (vtable == vt)
+ return this;
+
+ Transition t;
+ t.vtable = vt;
+ t.flags = Transition::VTableChange;
+
+ QHash<Transition, InternalClass *>::const_iterator tit = transitions.constFind(t);
+ if (tit != transitions.constEnd())
+ return tit.value();
+
+ // create a new class and add it to the tree
+ InternalClass *newClass;
+ if (this == engine->emptyClass) {
+ newClass = engine->newClass(*this);
+ newClass->vtable = vt;
+ } else {
+ newClass = engine->emptyClass->changeVTable(vt);
+ newClass = newClass->changePrototype(prototype);
for (uint i = 0; i < size; ++i)
newClass = newClass->addMember(nameMap.at(i), propertyData.at(i));
}
@@ -250,7 +297,8 @@ void InternalClass::removeMember(Object *object, Identifier *id)
}
// create a new class and add it to the tree
- object->internalClass = engine->emptyClass->changePrototype(prototype);
+ object->internalClass = engine->emptyClass->changeVTable(vtable);
+ object->internalClass = object->internalClass->changePrototype(prototype);
for (uint i = 0; i < size; ++i) {
if (i == propIdx)
continue;
@@ -283,6 +331,7 @@ InternalClass *InternalClass::sealed()
return m_sealed;
m_sealed = engine->emptyClass;
+ m_sealed = m_sealed->changeVTable(vtable);
m_sealed = m_sealed->changePrototype(prototype);
for (uint i = 0; i < size; ++i) {
PropertyAttributes attrs = propertyData.at(i);
@@ -300,6 +349,7 @@ InternalClass *InternalClass::frozen()
return m_frozen;
m_frozen = engine->emptyClass;
+ m_frozen = m_frozen->changeVTable(vtable);
m_frozen = m_frozen->changePrototype(prototype);
for (uint i = 0; i < size; ++i) {
PropertyAttributes attrs = propertyData.at(i);
@@ -343,7 +393,9 @@ void InternalClass::markObjects()
for (QHash<Transition, InternalClass *>::ConstIterator it = transitions.begin(), end = transitions.end();
it != end; ++it) {
- if (it.key().flags == Transition::ProtoChange) {
+ if (it.key().flags == Transition::VTableChange) {
+ it.value()->markObjects();
+ } else if (it.key().flags == Transition::ProtoChange) {
Q_ASSERT(it.value()->prototype);
it.value()->prototype->mark(engine);
}
diff --git a/src/qml/jsruntime/qv4internalclass_p.h b/src/qml/jsruntime/qv4internalclass_p.h
index 9586637b32..b25b895183 100644
--- a/src/qml/jsruntime/qv4internalclass_p.h
+++ b/src/qml/jsruntime/qv4internalclass_p.h
@@ -53,6 +53,7 @@ struct String;
struct ExecutionEngine;
struct Object;
struct Identifier;
+struct ManagedVTable;
struct PropertyHashData;
struct PropertyHash
@@ -198,9 +199,14 @@ struct InternalClassTransition
union {
Identifier *id;
Object *prototype;
+ const ManagedVTable *vtable;
};
int flags;
- enum { ProtoChange = 0x100 };
+ enum {
+ // range 0-0xff is reserved for attribute changes
+ ProtoChange = 0x100,
+ VTableChange = 0x200
+ };
bool operator==(const InternalClassTransition &other) const
{ return id == other.id && flags == other.flags; }
@@ -210,6 +216,8 @@ uint qHash(const QV4::InternalClassTransition &t, uint = 0);
struct InternalClass {
ExecutionEngine *engine;
Object *prototype;
+ const ManagedVTable *vtable;
+
PropertyHash propertyTable; // id to valueIndex
SharedInternalClassData<String *> nameMap;
SharedInternalClassData<PropertyAttributes> propertyData;
@@ -222,7 +230,9 @@ struct InternalClass {
uint size;
+ static InternalClass *create(ExecutionEngine *engine, const ManagedVTable *vtable, Object *proto);
InternalClass *changePrototype(Object *proto);
+ InternalClass *changeVTable(const ManagedVTable *vt);
InternalClass *addMember(StringRef string, PropertyAttributes data, uint *index = 0);
InternalClass *addMember(String *string, PropertyAttributes data, uint *index = 0);
InternalClass *changeMember(String *string, PropertyAttributes data, uint *index = 0);
@@ -238,7 +248,7 @@ struct InternalClass {
private:
friend struct ExecutionEngine;
- InternalClass(ExecutionEngine *engine) : engine(engine), prototype(0), m_sealed(0), m_frozen(0), size(0) {}
+ InternalClass(ExecutionEngine *engine);
InternalClass(const InternalClass &other);
};
diff --git a/src/qml/jsruntime/qv4jsonobject.cpp b/src/qml/jsruntime/qv4jsonobject.cpp
index 5aac8c8197..6633435668 100644
--- a/src/qml/jsruntime/qv4jsonobject.cpp
+++ b/src/qml/jsruntime/qv4jsonobject.cpp
@@ -965,7 +965,7 @@ ReturnedValue JsonObject::method_stringify(CallContext *ctx)
ReturnedValue JsonObject::fromJsonValue(ExecutionEngine *engine, const QJsonValue &value)
{
if (value.isString())
- return engine->current->engine->newString(value.toString())->asReturnedValue();
+ return engine->currentContext()->engine->newString(value.toString())->asReturnedValue();
else if (value.isDouble())
return Encode(value.toDouble());
else if (value.isBool())
diff --git a/src/qml/jsruntime/qv4jsonobject_p.h b/src/qml/jsruntime/qv4jsonobject_p.h
index f63e7726f5..3bcbdeadbf 100644
--- a/src/qml/jsruntime/qv4jsonobject_p.h
+++ b/src/qml/jsruntime/qv4jsonobject_p.h
@@ -38,8 +38,8 @@
** $QT_END_LICENSE$
**
****************************************************************************/
-#ifndef QV4JSONOBJECTS_H
-#define QV4SJONOBJECTS_H
+#ifndef QV4JSONOBJECT_H
+#define QV4JSONOBJECT_H
#include "qv4object_p.h"
#include <qjsonarray.h>
diff --git a/src/qml/jsruntime/qv4lookup.cpp b/src/qml/jsruntime/qv4lookup.cpp
index f67b24c040..a870cdac61 100644
--- a/src/qml/jsruntime/qv4lookup.cpp
+++ b/src/qml/jsruntime/qv4lookup.cpp
@@ -87,13 +87,13 @@ ReturnedValue Lookup::getterGeneric(QV4::Lookup *l, const ValueRef object)
switch (object->type()) {
case Value::Undefined_Type:
case Value::Null_Type:
- return engine->current->throwTypeError();
+ return engine->currentContext()->throwTypeError();
case Value::Boolean_Type:
proto = engine->booleanClass->prototype;
break;
case Value::Managed_Type:
Q_ASSERT(object->isString());
- proto = engine->stringClass->prototype;
+ proto = engine->stringObjectClass->prototype;
if (l->name->equals(engine->id_length)) {
// special case, as the property is on the object itself
l->getter = stringLengthGetter;
@@ -446,7 +446,7 @@ void Lookup::setterGeneric(Lookup *l, const ValueRef object, const ValueRef valu
Scope scope(l->name->engine());
ScopedObject o(scope, object);
if (!o) {
- o = __qmljs_convert_to_object(scope.engine->current, object);
+ o = __qmljs_convert_to_object(scope.engine->currentContext(), object);
if (!o) // type error
return;
ScopedString s(scope, l->name);
diff --git a/src/qml/jsruntime/qv4managed.cpp b/src/qml/jsruntime/qv4managed.cpp
index 6455a08037..fef7489110 100644
--- a/src/qml/jsruntime/qv4managed.cpp
+++ b/src/qml/jsruntime/qv4managed.cpp
@@ -52,7 +52,6 @@ const ManagedVTable Managed::static_vtbl =
0 /*markObjects*/,
destroy,
0 /*collectDeletables*/,
- hasInstance,
0,
0,
0,
@@ -82,7 +81,6 @@ void Managed::operator delete(void *ptr)
return;
Managed *m = static_cast<Managed *>(ptr);
- m->vtbl = 0;
m->_data = 0;
m->markBit = 0;
m->~Managed();
@@ -178,29 +176,30 @@ QString Managed::className() const
return QString::fromLatin1(s);
}
-bool Managed::hasInstance(Managed *m, const ValueRef)
+void Managed::setVTable(const ManagedVTable *vt)
{
- return m->engine()->current->throwTypeError();
+ Q_ASSERT(internalClass);
+ internalClass = internalClass->changeVTable(vt);
}
ReturnedValue Managed::construct(Managed *m, CallData *)
{
- return m->engine()->current->throwTypeError();
+ return m->engine()->currentContext()->throwTypeError();
}
ReturnedValue Managed::call(Managed *m, CallData *)
{
- return m->engine()->current->throwTypeError();
+ return m->engine()->currentContext()->throwTypeError();
}
ReturnedValue Managed::getLookup(Managed *m, Lookup *)
{
- return m->engine()->current->throwTypeError();
+ return m->engine()->currentContext()->throwTypeError();
}
void Managed::setLookup(Managed *m, Lookup *, const ValueRef)
{
- m->engine()->current->throwTypeError();
+ m->engine()->currentContext()->throwTypeError();
}
bool Managed::isEqualTo(Managed *, Managed *)
@@ -208,47 +207,42 @@ bool Managed::isEqualTo(Managed *, Managed *)
return false;
}
-bool Managed::hasInstance(const ValueRef v)
-{
- return vtbl->hasInstance(this, v);
-}
-
ReturnedValue Managed::get(const StringRef name, bool *hasProperty)
{
- return vtbl->get(this, name, hasProperty);
+ return internalClass->vtable->get(this, name, hasProperty);
}
ReturnedValue Managed::getIndexed(uint index, bool *hasProperty)
{
- return vtbl->getIndexed(this, index, hasProperty);
+ return internalClass->vtable->getIndexed(this, index, hasProperty);
}
void Managed::put(const StringRef name, const ValueRef value)
{
- vtbl->put(this, name, value);
+ internalClass->vtable->put(this, name, value);
}
void Managed::setLookup(Lookup *l, const ValueRef v)
{
- vtbl->setLookup(this, l, v);
+ internalClass->vtable->setLookup(this, l, v);
}
void Managed::putIndexed(uint index, const ValueRef value)
{
- vtbl->putIndexed(this, index, value);
+ internalClass->vtable->putIndexed(this, index, value);
}
PropertyAttributes Managed::query(StringRef name) const
{
- return vtbl->query(this, name);
+ return internalClass->vtable->query(this, name);
}
bool Managed::deleteProperty(const StringRef name)
{
- return vtbl->deleteProperty(this, name);
+ return internalClass->vtable->deleteProperty(this, name);
}
Property *Managed::advanceIterator(ObjectIterator *it, StringRef name, uint *index, PropertyAttributes *attributes)
{
- return vtbl->advanceIterator(this, it, name, index, attributes);
+ return internalClass->vtable->advanceIterator(this, it, name, index, attributes);
}
diff --git a/src/qml/jsruntime/qv4managed_p.h b/src/qml/jsruntime/qv4managed_p.h
index 47ac5e05e4..63972688a7 100644
--- a/src/qml/jsruntime/qv4managed_p.h
+++ b/src/qml/jsruntime/qv4managed_p.h
@@ -46,6 +46,7 @@
#include <QtCore/QDebug>
#include "qv4global_p.h"
#include "qv4value_def_p.h"
+#include "qv4internalclass_p.h"
QT_BEGIN_NAMESPACE
@@ -84,7 +85,6 @@ struct ManagedVTable
void (*markObjects)(Managed *, ExecutionEngine *e);
void (*destroy)(Managed *);
void (*collectDeletables)(Managed *, GCDeletable **deletable);
- bool (*hasInstance)(Managed *, const ValueRef value);
ReturnedValue (*get)(Managed *, const StringRef name, bool *hasProperty);
ReturnedValue (*getIndexed)(Managed *, uint index, bool *hasProperty);
void (*put)(Managed *, const StringRef name, const ValueRef value);
@@ -108,7 +108,6 @@ const QV4::ManagedVTable classname::static_vtbl = \
markObjects, \
destroy, \
0, \
- hasInstance, \
get, \
getIndexed, \
put, \
@@ -132,7 +131,6 @@ const QV4::ManagedVTable classname::static_vtbl = \
markObjects, \
destroy, \
collectDeletables, \
- hasInstance, \
get, \
getIndexed, \
put, \
@@ -158,11 +156,15 @@ private:
protected:
Managed(InternalClass *internal)
- : _data(0), vtbl(&static_vtbl), internalClass(internal)
- { inUse = 1; extensible = 1; }
+ : internalClass(internal), _data(0)
+ {
+ Q_ASSERT(!internalClass || internalClass->vtable);
+ inUse = 1; extensible = 1;
+ }
public:
void *operator new(size_t size, MemoryManager *mm);
+ void *operator new(size_t, Managed *m) { return m; }
void operator delete(void *ptr);
void operator delete(void *ptr, MemoryManager *mm);
@@ -194,12 +196,12 @@ public:
template <typename T>
T *as() {
// ### FIXME:
- if (!this)
+ if (!this || !internalClass)
return 0;
#if !defined(QT_NO_QOBJECT_CHECK)
reinterpret_cast<T *>(this)->qt_check_for_QMANAGED_macro(*reinterpret_cast<T *>(this));
#endif
- return vtbl == &T::static_vtbl ? static_cast<T *>(this) : 0;
+ return internalClass->vtable == &T::static_vtbl ? static_cast<T *>(this) : 0;
}
template <typename T>
const T *as() const {
@@ -209,7 +211,7 @@ public:
#if !defined(QT_NO_QOBJECT_CHECK)
reinterpret_cast<T *>(this)->qt_check_for_QMANAGED_macro(*reinterpret_cast<T *>(const_cast<Managed *>(this)));
#endif
- return vtbl == &T::static_vtbl ? static_cast<const T *>(this) : 0;
+ return internalClass->vtable == &T::static_vtbl ? static_cast<const T *>(this) : 0;
}
String *asString() { return type == Type_String ? reinterpret_cast<String *>(this) : 0; }
@@ -240,7 +242,8 @@ public:
*reinterpret_cast<Managed **>(this) = m;
}
- bool hasInstance(const ValueRef v);
+ void setVTable(const ManagedVTable *vt);
+
ReturnedValue construct(CallData *d);
ReturnedValue call(CallData *d);
ReturnedValue get(const StringRef name, bool *hasProperty = 0);
@@ -249,21 +252,20 @@ public:
void putIndexed(uint index, const ValueRef value);
PropertyAttributes query(StringRef name) const;
PropertyAttributes queryIndexed(uint index) const
- { return vtbl->queryIndexed(this, index); }
+ { return internalClass->vtable->queryIndexed(this, index); }
bool deleteProperty(const StringRef name);
bool deleteIndexedProperty(uint index)
- { return vtbl->deleteIndexedProperty(this, index); }
+ { return internalClass->vtable->deleteIndexedProperty(this, index); }
ReturnedValue getLookup(Lookup *l)
- { return vtbl->getLookup(this, l); }
+ { return internalClass->vtable->getLookup(this, l); }
void setLookup(Lookup *l, const ValueRef v);
bool isEqualTo(Managed *other)
- { return vtbl->isEqualTo(this, other); }
+ { return internalClass->vtable->isEqualTo(this, other); }
Property *advanceIterator(ObjectIterator *it, StringRef name, uint *index, PropertyAttributes *attributes);
static void destroy(Managed *that) { that->_data = 0; }
- static bool hasInstance(Managed *that, const ValueRef value);
static ReturnedValue construct(Managed *m, CallData *d);
static ReturnedValue call(Managed *m, CallData *);
static ReturnedValue getLookup(Managed *m, Lookup *);
@@ -276,6 +278,9 @@ public:
ReturnedValue asReturnedValue() { return Value::fromManaged(this).asReturnedValue(); }
+
+ InternalClass *internalClass;
+
enum {
SimpleArray = 1
};
@@ -297,11 +302,6 @@ public:
};
};
-protected:
- const ManagedVTable *vtbl;
-public:
- InternalClass *internalClass;
-
private:
friend class MemoryManager;
friend struct Identifiers;
@@ -337,10 +337,10 @@ inline FunctionObject *managed_cast(Managed *m)
inline ReturnedValue Managed::construct(CallData *d) {
- return vtbl->construct(this, d);
+ return internalClass->vtable->construct(this, d);
}
inline ReturnedValue Managed::call(CallData *d) {
- return vtbl->call(this, d);
+ return internalClass->vtable->call(this, d);
}
}
diff --git a/src/qml/jsruntime/qv4mathobject_p.h b/src/qml/jsruntime/qv4mathobject_p.h
index dca75e6c28..6fe3db3950 100644
--- a/src/qml/jsruntime/qv4mathobject_p.h
+++ b/src/qml/jsruntime/qv4mathobject_p.h
@@ -39,7 +39,7 @@
**
****************************************************************************/
#ifndef QV4MATHOBJECT_H
-#define QV$MATHOBJECT_H
+#define QV4MATHOBJECT_H
#include "qv4object_p.h"
diff --git a/src/qml/jsruntime/qv4mm.cpp b/src/qml/jsruntime/qv4mm.cpp
index 9eb3ae7ec9..f67efaffb9 100644
--- a/src/qml/jsruntime/qv4mm.cpp
+++ b/src/qml/jsruntime/qv4mm.cpp
@@ -155,6 +155,19 @@ struct MemoryManager::Data
QVector<Chunk> heapChunks;
+
+ struct LargeItem {
+ LargeItem *next;
+ void *data;
+
+ Managed *managed() {
+ return reinterpret_cast<Managed *>(&data);
+ }
+ };
+
+ LargeItem *largeItems;
+
+
// statistics:
#ifdef DETAILED_MM_STATS
QVector<unsigned> allocSizeCounters;
@@ -167,6 +180,7 @@ struct MemoryManager::Data
, stackTop(0)
, totalItems(0)
, totalAlloc(0)
+ , largeItems(0)
{
memset(smallItems, 0, sizeof(smallItems));
memset(nChunks, 0, sizeof(nChunks));
@@ -200,7 +214,6 @@ bool operator<(const MemoryManager::Data::Chunk &a, const MemoryManager::Data::C
MemoryManager::MemoryManager()
: m_d(new Data(true))
- , m_contextList(0)
, m_persistentValues(0)
, m_weakValues(0)
{
@@ -258,8 +271,14 @@ Managed *MemoryManager::alloc(std::size_t size)
size_t pos = size >> 4;
- // fits into a small bucket
- Q_ASSERT(size < MemoryManager::Data::MaxItemSize);
+ // doesn't fit into a small bucket
+ if (size >= MemoryManager::Data::MaxItemSize) {
+ // we use malloc for this
+ MemoryManager::Data::LargeItem *item = static_cast<MemoryManager::Data::LargeItem *>(malloc(size + sizeof(MemoryManager::Data::LargeItem)));
+ item->next = m_d->largeItems;
+ m_d->largeItems = item;
+ return item->managed();
+ }
Managed *m = m_d->smallItems[pos];
if (m)
@@ -279,11 +298,11 @@ Managed *MemoryManager::alloc(std::size_t size)
uint shift = ++m_d->nChunks[pos];
if (shift > 10)
shift = 10;
- std::size_t allocSize = CHUNK_SIZE*(1 << shift);
+ std::size_t allocSize = CHUNK_SIZE*(size_t(1) << shift);
allocSize = roundUpToMultipleOf(WTF::pageSize(), allocSize);
Data::Chunk allocation;
allocation.memory = PageAllocation::allocate(allocSize, OSAllocator::JSGCHeapPages);
- allocation.chunkSize = size;
+ allocation.chunkSize = int(size);
m_d->heapChunks.append(allocation);
std::sort(m_d->heapChunks.begin(), m_d->heapChunks.end());
char *chunk = (char *)allocation.memory.base();
@@ -301,8 +320,9 @@ Managed *MemoryManager::alloc(std::size_t size)
}
*last = 0;
m = m_d->smallItems[pos];
- m_d->availableItems[pos] += allocation.memory.size()/size - 1;
- m_d->totalItems += allocation.memory.size()/size - 1;
+ const size_t increase = allocation.memory.size()/size - 1;
+ m_d->availableItems[pos] += uint(increase);
+ m_d->totalItems += int(increase);
#ifdef V4_USE_VALGRIND
VALGRIND_MAKE_MEM_NOACCESS(allocation.memory, allocation.chunkSize);
#endif
@@ -404,8 +424,8 @@ void MemoryManager::mark()
// now that we marked all roots, start marking recursively and popping from the mark stack
while (m_d->engine->jsStackTop > markBase) {
Managed *m = m_d->engine->popForGC();
- Q_ASSERT (m->vtbl->markObjects);
- m->vtbl->markObjects(m, m_d->engine);
+ Q_ASSERT (m->internalClass->vtable->markObjects);
+ m->internalClass->vtable->markObjects(m, m_d->engine);
}
}
@@ -447,18 +467,21 @@ void MemoryManager::sweep(bool lastSweep)
for (QVector<Data::Chunk>::iterator i = m_d->heapChunks.begin(), ei = m_d->heapChunks.end(); i != ei; ++i)
sweep(reinterpret_cast<char*>(i->memory.base()), i->memory.size(), i->chunkSize, &deletable);
- ExecutionContext *ctx = m_contextList;
- ExecutionContext **n = &m_contextList;
- while (ctx) {
- ExecutionContext *next = ctx->next;
- if (!ctx->marked) {
- free(ctx);
- *n = next;
- } else {
- ctx->marked = false;
- n = &ctx->next;
+ Data::LargeItem *i = m_d->largeItems;
+ Data::LargeItem **last = &m_d->largeItems;
+ while (i) {
+ Managed *m = i->managed();
+ Q_ASSERT(m->inUse);
+ if (m->markBit) {
+ m->markBit = 0;
+ last = &i->next;
+ i = i->next;
+ continue;
}
- ctx = next;
+
+ *last = i->next;
+ free(i);
+ i = *last;
}
deletable = *firstDeletable;
@@ -493,9 +516,9 @@ void MemoryManager::sweep(char *chunkStart, std::size_t chunkSize, size_t size,
#ifdef V4_USE_VALGRIND
VALGRIND_ENABLE_ERROR_REPORTING;
#endif
- if (m->vtbl->collectDeletables)
- m->vtbl->collectDeletables(m, deletable);
- m->vtbl->destroy(m);
+ if (m->internalClass->vtable->collectDeletables)
+ m->internalClass->vtable->collectDeletables(m, deletable);
+ m->internalClass->vtable->destroy(m);
m->setNextFree(*f);
#ifdef V4_USE_VALGRIND
diff --git a/src/qml/jsruntime/qv4mm_p.h b/src/qml/jsruntime/qv4mm_p.h
index f3258519de..7d28319536 100644
--- a/src/qml/jsruntime/qv4mm_p.h
+++ b/src/qml/jsruntime/qv4mm_p.h
@@ -103,8 +103,6 @@ public:
return o;
}
- ExecutionContext *allocContext(uint size);
-
bool isGCBlocked() const;
void setGCBlocked(bool blockGC);
void runGC();
@@ -134,21 +132,11 @@ private:
protected:
QScopedPointer<Data> m_d;
- ExecutionContext *m_contextList;
public:
PersistentValuePrivate *m_persistentValues;
PersistentValuePrivate *m_weakValues;
};
-inline ExecutionContext *MemoryManager::allocContext(uint size)
-{
- ExecutionContext *newContext = (ExecutionContext *)malloc(size);
- newContext->next = m_contextList;
- m_contextList = newContext;
- return newContext;
-}
-
-
}
QT_END_NAMESPACE
diff --git a/src/qml/jsruntime/qv4numberobject.cpp b/src/qml/jsruntime/qv4numberobject.cpp
index 039b790aed..a363a06242 100644
--- a/src/qml/jsruntime/qv4numberobject.cpp
+++ b/src/qml/jsruntime/qv4numberobject.cpp
@@ -54,7 +54,7 @@ DEFINE_MANAGED_VTABLE(NumberObject);
NumberCtor::NumberCtor(ExecutionContext *scope)
: FunctionObject(scope, QStringLiteral("Number"))
{
- vtbl = &static_vtbl;
+ setVTable(&static_vtbl);
}
ReturnedValue NumberCtor::construct(Managed *m, CallData *callData)
diff --git a/src/qml/jsruntime/qv4object.cpp b/src/qml/jsruntime/qv4object.cpp
index cca7d2b26a..106525d412 100644
--- a/src/qml/jsruntime/qv4object.cpp
+++ b/src/qml/jsruntime/qv4object.cpp
@@ -74,18 +74,17 @@ Object::Object(ExecutionEngine *engine)
, memberDataAlloc(InlinePropertySize), memberData(inlineProperties)
, arrayOffset(0), arrayDataLen(0), arrayAlloc(0), arrayAttributes(0), arrayData(0), sparseArray(0)
{
- vtbl = &static_vtbl;
type = Type_Object;
flags = SimpleArray;
memset(memberData, 0, sizeof(Property)*memberDataAlloc);
}
-Object::Object(InternalClass *internalClass)
- : Managed(internalClass)
+Object::Object(InternalClass *ic)
+ : Managed(ic)
, memberDataAlloc(InlinePropertySize), memberData(inlineProperties)
, arrayOffset(0), arrayDataLen(0), arrayAlloc(0), arrayAttributes(0), arrayData(0), sparseArray(0)
{
- vtbl = &static_vtbl;
+ Q_ASSERT(internalClass->vtable && internalClass->vtable != &Managed::static_vtbl);
type = Type_Object;
flags = SimpleArray;
@@ -169,8 +168,8 @@ void Object::putValue(Property *pd, PropertyAttributes attrs, const ValueRef val
return;
reject:
- if (engine()->current->strictMode)
- engine()->current->throwTypeError();
+ if (engine()->currentContext()->strictMode)
+ engine()->currentContext()->throwTypeError();
}
void Object::defineDefaultProperty(const StringRef name, ValueRef value)
@@ -721,7 +720,7 @@ void Object::internalPut(const StringRef name, const ValueRef value)
bool ok;
uint l = value->asArrayLength(&ok);
if (!ok) {
- engine()->current->throwRangeError(value);
+ engine()->currentContext()->throwRangeError(value);
return;
}
ok = setArrayLength(l);
@@ -769,11 +768,11 @@ void Object::internalPut(const StringRef name, const ValueRef value)
}
reject:
- if (engine()->current->strictMode) {
+ if (engine()->currentContext()->strictMode) {
QString message = QStringLiteral("Cannot assign to read-only property \"");
message += name->toQString();
message += QLatin1Char('\"');
- engine()->current->throwTypeError(message);
+ engine()->currentContext()->throwTypeError(message);
}
}
@@ -844,8 +843,8 @@ void Object::internalPutIndexed(uint index, const ValueRef value)
return;
reject:
- if (engine()->current->strictMode)
- engine()->current->throwTypeError();
+ if (engine()->currentContext()->strictMode)
+ engine()->currentContext()->throwTypeError();
}
// Section 8.12.7
@@ -867,8 +866,8 @@ bool Object::internalDeleteProperty(const StringRef name)
memmove(memberData + memberIdx, memberData + memberIdx + 1, (internalClass->size - memberIdx)*sizeof(Property));
return true;
}
- if (engine()->current->strictMode)
- engine()->current->throwTypeError();
+ if (engine()->currentContext()->strictMode)
+ engine()->currentContext()->throwTypeError();
return false;
}
@@ -897,8 +896,8 @@ bool Object::internalDeleteIndexedProperty(uint index)
return true;
}
- if (engine()->current->strictMode)
- engine()->current->throwTypeError();
+ if (engine()->currentContext()->strictMode)
+ engine()->currentContext()->throwTypeError();
return false;
}
@@ -1133,7 +1132,7 @@ ReturnedValue Object::arrayIndexOf(const ValueRef v, uint fromIndex, uint endInd
Scope scope(engine());
ScopedValue value(scope);
- if (!(flags & SimpleArray) || o->protoHasArray() || o->arrayAttributes) {
+ if (!(o->flags & SimpleArray) || o->protoHasArray()) {
// lets be safe and slow
for (uint i = fromIndex; i < endIndex; ++i) {
bool exists;
@@ -1262,13 +1261,9 @@ void Object::arraySort(ExecutionContext *context, ObjectRef thisObject, const Va
ArrayElementLessThan lessThan(context, thisObject, comparefn);
+ if (!len)
+ return;
Property *begin = arrayData;
- // We deliberately choose qSort over std::sort here, because with
- // MSVC in debug builds, std::sort has an ASSERT() that verifies
- // that the return values of lessThan are perfectly consistent
- // and aborts otherwise. We do not want JavaScript to easily crash
- // the entire application and therefore choose qSort, which doesn't
- // have this property.
std::sort(begin, begin + len, lessThan);
}
diff --git a/src/qml/jsruntime/qv4object_p.h b/src/qml/jsruntime/qv4object_p.h
index daef18d4e2..23f2f682fd 100644
--- a/src/qml/jsruntime/qv4object_p.h
+++ b/src/qml/jsruntime/qv4object_p.h
@@ -280,13 +280,13 @@ public:
void ensureMemberIndex(uint idx);
inline ReturnedValue get(const StringRef name, bool *hasProperty = 0)
- { return vtbl->get(this, name, hasProperty); }
+ { return internalClass->vtable->get(this, name, hasProperty); }
inline ReturnedValue getIndexed(uint idx, bool *hasProperty = 0)
- { return vtbl->getIndexed(this, idx, hasProperty); }
+ { return internalClass->vtable->getIndexed(this, idx, hasProperty); }
inline void put(const StringRef name, const ValueRef v)
- { vtbl->put(this, name, v); }
+ { internalClass->vtable->put(this, name, v); }
inline void putIndexed(uint idx, const ValueRef v)
- { vtbl->putIndexed(this, idx, v); }
+ { internalClass->vtable->putIndexed(this, idx, v); }
using Managed::get;
using Managed::getIndexed;
using Managed::put;
@@ -331,14 +331,13 @@ struct BooleanObject: Object {
SafeValue value;
BooleanObject(ExecutionEngine *engine, const ValueRef val)
: Object(engine->booleanClass) {
- vtbl = &static_vtbl;
type = Type_BooleanObject;
value = val;
}
protected:
BooleanObject(InternalClass *ic)
: Object(ic) {
- vtbl = &static_vtbl;
+ setVTable(&static_vtbl);
type = Type_BooleanObject;
value = Encode(false);
}
@@ -349,14 +348,13 @@ struct NumberObject: Object {
SafeValue value;
NumberObject(ExecutionEngine *engine, const ValueRef val)
: Object(engine->numberClass) {
- vtbl = &static_vtbl;
type = Type_NumberObject;
value = val;
}
protected:
NumberObject(InternalClass *ic)
: Object(ic) {
- vtbl = &static_vtbl;
+ setVTable(&static_vtbl);
type = Type_NumberObject;
value = Encode((int)0);
}
diff --git a/src/qml/jsruntime/qv4objectiterator.cpp b/src/qml/jsruntime/qv4objectiterator.cpp
index 62595b5176..04fa504991 100644
--- a/src/qml/jsruntime/qv4objectiterator.cpp
+++ b/src/qml/jsruntime/qv4objectiterator.cpp
@@ -42,6 +42,7 @@
#include "qv4object_p.h"
#include "qv4stringobject_p.h"
#include "qv4identifier_p.h"
+#include "qv4argumentsobject_p.h"
using namespace QV4;
@@ -56,6 +57,11 @@ ObjectIterator::ObjectIterator(SafeObject *scratch1, SafeObject *scratch2, const
object = o;
current = o;
tmpDynamicProperty.value = Primitive::undefinedValue();
+
+ if (object && object->isNonStrictArgumentsObject) {
+ Scope scope(object->engine());
+ Scoped<ArgumentsObject> (scope, object->asReturnedValue())->fullyCreate();
+ }
}
ObjectIterator::ObjectIterator(Scope &scope, const ObjectRef o, uint flags)
@@ -69,6 +75,11 @@ ObjectIterator::ObjectIterator(Scope &scope, const ObjectRef o, uint flags)
object = o;
current = o;
tmpDynamicProperty.value = Primitive::undefinedValue();
+
+ if (object && object->isNonStrictArgumentsObject) {
+ Scope scope(object->engine());
+ Scoped<ArgumentsObject> (scope, object->asReturnedValue())->fullyCreate();
+ }
}
Property *ObjectIterator::next(StringRef name, uint *index, PropertyAttributes *attrs)
diff --git a/src/qml/jsruntime/qv4objectiterator_p.h b/src/qml/jsruntime/qv4objectiterator_p.h
index 19aedf3766..6c333b328c 100644
--- a/src/qml/jsruntime/qv4objectiterator_p.h
+++ b/src/qml/jsruntime/qv4objectiterator_p.h
@@ -89,7 +89,7 @@ struct ForEachIteratorObject: Object {
ObjectIterator it;
ForEachIteratorObject(ExecutionContext *ctx, const ObjectRef o)
: Object(ctx->engine), it(workArea, workArea + 1, o, ObjectIterator::EnumerableOnly|ObjectIterator::WithProtoChain) {
- vtbl = &static_vtbl;
+ setVTable(&static_vtbl);
type = Type_ForeachIteratorObject;
}
diff --git a/src/qml/jsruntime/qv4objectproto.cpp b/src/qml/jsruntime/qv4objectproto.cpp
index 4369267278..7ca790b970 100644
--- a/src/qml/jsruntime/qv4objectproto.cpp
+++ b/src/qml/jsruntime/qv4objectproto.cpp
@@ -41,6 +41,7 @@
#include "qv4objectproto_p.h"
+#include "qv4argumentsobject_p.h"
#include "qv4mm_p.h"
#include "qv4scopedvalue_p.h"
#include <QtCore/qnumeric.h>
@@ -76,7 +77,7 @@ DEFINE_MANAGED_VTABLE(ObjectCtor);
ObjectCtor::ObjectCtor(ExecutionContext *scope)
: FunctionObject(scope, QStringLiteral("Object"))
{
- vtbl = &static_vtbl;
+ setVTable(&static_vtbl);
}
ReturnedValue ObjectCtor::construct(Managed *that, CallData *callData)
@@ -91,14 +92,14 @@ ReturnedValue ObjectCtor::construct(Managed *that, CallData *callData)
obj->setPrototype(proto.getPointer());
return obj.asReturnedValue();
}
- return __qmljs_to_object(v4->current, ValueRef(&callData->args[0]));
+ return __qmljs_to_object(v4->currentContext(), ValueRef(&callData->args[0]));
}
ReturnedValue ObjectCtor::call(Managed *m, CallData *callData)
{
if (!callData->argc || callData->args[0].isUndefined() || callData->args[0].isNull())
return m->engine()->newObject()->asReturnedValue();
- return __qmljs_to_object(m->engine()->current, ValueRef(&callData->args[0]));
+ return __qmljs_to_object(m->engine()->currentContext(), ValueRef(&callData->args[0]));
}
void ObjectPrototype::init(ExecutionEngine *v4, ObjectRef ctor)
@@ -156,6 +157,9 @@ ReturnedValue ObjectPrototype::method_getOwnPropertyDescriptor(CallContext *ctx)
if (!O)
return ctx->throwTypeError();
+ if (O->isNonStrictArgumentsObject)
+ Scoped<ArgumentsObject>(scope, O)->fullyCreate();
+
ScopedValue v(scope, ctx->argument(1));
Scoped<String> name(scope, v->toString(ctx));
if (scope.hasException())
@@ -283,6 +287,9 @@ ReturnedValue ObjectPrototype::method_freeze(CallContext *ctx)
if (!o)
return ctx->throwTypeError();
+ if (o->isNonStrictArgumentsObject)
+ Scoped<ArgumentsObject>(scope, o)->fullyCreate();
+
o->extensible = false;
o->internalClass = o->internalClass->frozen();
diff --git a/src/qml/jsruntime/qv4qobjectwrapper.cpp b/src/qml/jsruntime/qv4qobjectwrapper.cpp
index f1b0e0bdc4..61f92a0f5c 100644
--- a/src/qml/jsruntime/qv4qobjectwrapper.cpp
+++ b/src/qml/jsruntime/qv4qobjectwrapper.cpp
@@ -241,7 +241,7 @@ QObjectWrapper::QObjectWrapper(ExecutionEngine *engine, QObject *object)
: Object(engine)
, m_object(object)
{
- vtbl = &static_vtbl;
+ setVTable(&static_vtbl);
Scope scope(engine);
ScopedObject protectThis(scope, this);
@@ -331,23 +331,23 @@ ReturnedValue QObjectWrapper::getQmlProperty(ExecutionContext *ctx, QQmlContextD
if (hasProperty)
*hasProperty = true;
- return getProperty(ctx, result);
+ return getProperty(m_object, ctx, result);
}
-ReturnedValue QObjectWrapper::getProperty(ExecutionContext *ctx, QQmlPropertyData *property, bool captureRequired)
+ReturnedValue QObjectWrapper::getProperty(QObject *object, ExecutionContext *ctx, QQmlPropertyData *property, bool captureRequired)
{
QV4::Scope scope(ctx);
if (property->isFunction() && !property->isVarProperty()) {
if (property->isVMEFunction()) {
- QQmlVMEMetaObject *vmemo = QQmlVMEMetaObject::get(m_object);
+ QQmlVMEMetaObject *vmemo = QQmlVMEMetaObject::get(object);
Q_ASSERT(vmemo);
return vmemo->vmeMethod(property->coreIndex);
} else if (property->isV4Function()) {
QV4::Scoped<QV4::Object> qmlcontextobject(scope, ctx->engine->qmlContextObject());
- return QV4::QObjectMethod::create(ctx->engine->rootContext, m_object, property->coreIndex, qmlcontextobject);
+ return QV4::QObjectMethod::create(ctx->engine->rootContext, object, property->coreIndex, qmlcontextobject);
} else if (property->isSignalHandler()) {
- QV4::Scoped<QV4::QmlSignalHandler> handler(scope, new (ctx->engine->memoryManager) QV4::QmlSignalHandler(ctx->engine, m_object, property->coreIndex));
+ QV4::Scoped<QV4::QmlSignalHandler> handler(scope, new (ctx->engine->memoryManager) QV4::QmlSignalHandler(ctx->engine, object, property->coreIndex));
QV4::ScopedString connect(scope, ctx->engine->newIdentifier(QStringLiteral("connect")));
QV4::ScopedString disconnect(scope, ctx->engine->newIdentifier(QStringLiteral("disconnect")));
@@ -356,7 +356,7 @@ ReturnedValue QObjectWrapper::getProperty(ExecutionContext *ctx, QQmlPropertyDat
return handler.asReturnedValue();
} else {
- return QV4::QObjectMethod::create(ctx->engine->rootContext, m_object, property->coreIndex);
+ return QV4::QObjectMethod::create(ctx->engine->rootContext, object, property->coreIndex);
}
}
@@ -369,14 +369,14 @@ ReturnedValue QObjectWrapper::getProperty(ExecutionContext *ctx, QQmlPropertyDat
if (ep && ep->propertyCapture && property->accessors->notifier)
nptr = &n;
- QV4::ScopedValue rv(scope, LoadProperty<ReadAccessor::Accessor>(ctx->engine->v8Engine, m_object, *property, nptr));
+ QV4::ScopedValue rv(scope, LoadProperty<ReadAccessor::Accessor>(ctx->engine->v8Engine, object, *property, nptr));
if (captureRequired) {
if (property->accessors->notifier) {
if (n)
ep->captureProperty(n);
} else {
- ep->captureProperty(m_object, property->coreIndex, property->notifyIndex);
+ ep->captureProperty(object, property->coreIndex, property->notifyIndex);
}
}
@@ -384,16 +384,16 @@ ReturnedValue QObjectWrapper::getProperty(ExecutionContext *ctx, QQmlPropertyDat
}
if (captureRequired && ep && !property->isConstant())
- ep->captureProperty(m_object, property->coreIndex, property->notifyIndex);
+ ep->captureProperty(object, property->coreIndex, property->notifyIndex);
if (property->isVarProperty()) {
- QQmlVMEMetaObject *vmemo = QQmlVMEMetaObject::get(m_object);
+ QQmlVMEMetaObject *vmemo = QQmlVMEMetaObject::get(object);
Q_ASSERT(vmemo);
return vmemo->vmeProperty(property->coreIndex);
} else if (property->isDirect()) {
- return LoadProperty<ReadAccessor::Direct>(ctx->engine->v8Engine, m_object, *property, 0);
+ return LoadProperty<ReadAccessor::Direct>(ctx->engine->v8Engine, object, *property, 0);
} else {
- return LoadProperty<ReadAccessor::Indirect>(ctx->engine->v8Engine, m_object, *property, 0);
+ return LoadProperty<ReadAccessor::Indirect>(ctx->engine->v8Engine, object, *property, 0);
}
}
@@ -583,7 +583,7 @@ ReturnedValue QObjectWrapper::wrap(ExecutionEngine *engine, QObject *object)
ddata->jsEngineId == 0 || // No one owns the QObject
!ddata->hasTaintedV8Object)) { // Someone else has used the QObject, but it isn't tainted
- QV4::ScopedValue rv(scope, create(engine, ddata, object));
+ QV4::ScopedValue rv(scope, create(engine, object));
ddata->jsWrapper = rv;
ddata->jsEngineId = engine->m_engineId;
return rv.asReturnedValue();
@@ -598,14 +598,14 @@ ReturnedValue QObjectWrapper::wrap(ExecutionEngine *engine, QObject *object)
// If our tainted handle doesn't exist or has been collected, and there isn't
// a handle in the ddata, we can assume ownership of the ddata->v8object
if (ddata->jsWrapper.isUndefined() && !alternateWrapper) {
- QV4::ScopedValue result(scope, create(engine, ddata, object));
+ QV4::ScopedValue result(scope, create(engine, object));
ddata->jsWrapper = result;
ddata->jsEngineId = engine->m_engineId;
return result.asReturnedValue();
}
if (!alternateWrapper) {
- alternateWrapper = create(engine, ddata, object);
+ alternateWrapper = create(engine, object);
if (!engine->m_multiplyWrappedQObjects)
engine->m_multiplyWrappedQObjects = new MultiplyWrappedQObjectMap;
engine->m_multiplyWrappedQObjects->insert(object, alternateWrapper.getPointer());
@@ -616,11 +616,11 @@ ReturnedValue QObjectWrapper::wrap(ExecutionEngine *engine, QObject *object)
}
}
-ReturnedValue QObjectWrapper::getProperty(ExecutionContext *ctx, int propertyIndex, bool captureRequired)
+ReturnedValue QObjectWrapper::getProperty(QObject *object, ExecutionContext *ctx, int propertyIndex, bool captureRequired)
{
- if (QQmlData::wasDeleted(m_object))
+ if (QQmlData::wasDeleted(object))
return QV4::Encode::null();
- QQmlData *ddata = QQmlData::get(m_object, /*create*/false);
+ QQmlData *ddata = QQmlData::get(object, /*create*/false);
if (!ddata)
return QV4::Encode::undefined();
@@ -628,7 +628,7 @@ ReturnedValue QObjectWrapper::getProperty(ExecutionContext *ctx, int propertyInd
Q_ASSERT(cache);
QQmlPropertyData *property = cache->property(propertyIndex);
Q_ASSERT(property); // We resolved this property earlier, so it better exist!
- return getProperty(ctx, property, captureRequired);
+ return getProperty(object, ctx, property, captureRequired);
}
void QObjectWrapper::setProperty(ExecutionContext *ctx, int propertyIndex, const ValueRef value)
@@ -655,14 +655,11 @@ bool QObjectWrapper::isEqualTo(Managed *a, Managed *b)
return false;
}
-ReturnedValue QObjectWrapper::create(ExecutionEngine *engine, QQmlData *ddata, QObject *object)
+ReturnedValue QObjectWrapper::create(ExecutionEngine *engine, QObject *object)
{
QQmlEngine *qmlEngine = engine->v8Engine->engine();
- if (!ddata->propertyCache && qmlEngine) {
- ddata->propertyCache = QQmlEnginePrivate::get(qmlEngine)->cache(object);
- if (ddata->propertyCache) ddata->propertyCache->addref();
- }
-
+ if (qmlEngine)
+ QQmlData::ensurePropertyCache(qmlEngine, object);
return (new (engine->memoryManager) QV4::QObjectWrapper(engine, object))->asReturnedValue();
}
@@ -671,7 +668,7 @@ QV4::ReturnedValue QObjectWrapper::get(Managed *m, const StringRef name, bool *h
QObjectWrapper *that = static_cast<QObjectWrapper*>(m);
ExecutionEngine *v4 = m->engine();
QQmlContextData *qmlContext = QV4::QmlContextWrapper::callingContext(v4);
- return that->getQmlProperty(v4->current, qmlContext, name.getPointer(), IgnoreRevision, hasProperty, /*includeImports*/ true);
+ return that->getQmlProperty(v4->currentContext(), qmlContext, name.getPointer(), IgnoreRevision, hasProperty, /*includeImports*/ true);
}
void QObjectWrapper::put(Managed *m, const StringRef name, const ValueRef value)
@@ -683,10 +680,10 @@ void QObjectWrapper::put(Managed *m, const StringRef name, const ValueRef value)
return;
QQmlContextData *qmlContext = QV4::QmlContextWrapper::callingContext(v4);
- if (!setQmlProperty(v4->current, qmlContext, that->m_object, name.getPointer(), QV4::QObjectWrapper::IgnoreRevision, value)) {
+ if (!setQmlProperty(v4->currentContext(), qmlContext, that->m_object, name.getPointer(), QV4::QObjectWrapper::IgnoreRevision, value)) {
QString error = QLatin1String("Cannot assign to non-existent property \"") +
name->toQString() + QLatin1Char('\"');
- v4->current->throwError(error);
+ v4->currentContext()->throwError(error);
}
}
@@ -766,7 +763,7 @@ struct QObjectSlotDispatcher : public QtPrivate::QSlotObjectBase
Q_ASSERT(v4);
QV4::Scope scope(v4);
QV4::ScopedFunctionObject f(scope, This->function.value());
- QV4::ExecutionContext *ctx = v4->current;
+ QV4::ExecutionContext *ctx = v4->currentContext();
QV4::ScopedCallData callData(scope, argCount);
callData->thisObject = This->thisObject.isUndefined() ? v4->globalObject->asReturnedValue() : This->thisObject.value();
@@ -851,7 +848,7 @@ ReturnedValue QObjectWrapper::method_connect(CallContext *ctx)
QPair<QObject *, int> signalInfo = extractQtSignal(ctx->callData->thisObject);
QObject *signalObject = signalInfo.first;
- int signalIndex = signalInfo.second;
+ int signalIndex = signalInfo.second; // in method range, not signal range!
if (signalIndex < 0)
V4THROW_ERROR("Function.prototype.connect: this object is not a signal");
@@ -885,6 +882,11 @@ ReturnedValue QObjectWrapper::method_connect(CallContext *ctx)
slot->thisObject = thisObject;
slot->function = f;
+ if (QQmlData *ddata = QQmlData::get(signalObject)) {
+ if (QQmlPropertyCache *propertyCache = ddata->propertyCache) {
+ QQmlPropertyPrivate::flushSignal(signalObject, propertyCache->methodIndexToSignalIndex(signalIndex));
+ }
+ }
QObjectPrivate::connect(signalObject, signalIndex, slot, Qt::AutoConnection);
return Encode::undefined();
@@ -1335,7 +1337,7 @@ static QV4::ReturnedValue CallPrecise(QObject *object, const QQmlPropertyData &d
if (returnType == QMetaType::UnknownType) {
QString typeName = QString::fromLatin1(unknownTypeError);
QString error = QString::fromLatin1("Unknown method return type: %1").arg(typeName);
- return QV8Engine::getV4(engine)->current->throwError(error);
+ return QV8Engine::getV4(engine)->currentContext()->throwError(error);
}
if (data.hasArguments()) {
@@ -1349,12 +1351,12 @@ static QV4::ReturnedValue CallPrecise(QObject *object, const QQmlPropertyData &d
if (!args) {
QString typeName = QString::fromLatin1(unknownTypeError);
QString error = QString::fromLatin1("Unknown method parameter type: %1").arg(typeName);
- return QV8Engine::getV4(engine)->current->throwError(error);
+ return QV8Engine::getV4(engine)->currentContext()->throwError(error);
}
if (args[0] > callArgs->argc) {
QString error = QLatin1String("Insufficient arguments");
- return QV8Engine::getV4(engine)->current->throwError(error);
+ return QV8Engine::getV4(engine)->currentContext()->throwError(error);
}
return CallMethod(object, data.coreIndex, returnType, args[0], args + 1, engine, callArgs);
@@ -1453,7 +1455,7 @@ static QV4::ReturnedValue CallOverloaded(QObject *object, const QQmlPropertyData
candidate = RelatedMethod(object, candidate, dummy);
}
- return QV8Engine::getV4(engine)->current->throwError(error);
+ return QV8Engine::getV4(engine)->currentContext()->throwError(error);
}
}
@@ -1724,7 +1726,7 @@ QObjectMethod::QObjectMethod(ExecutionContext *scope, QObject *object, int index
, m_object(object)
, m_index(index)
{
- vtbl = &static_vtbl;
+ setVTable(&static_vtbl);
subtype = WrappedQtMethod;
m_qmlGlobal = qmlGlobal;
}
@@ -1780,7 +1782,7 @@ ReturnedValue QObjectMethod::call(Managed *m, CallData *callData)
ReturnedValue QObjectMethod::callInternal(CallData *callData)
{
- ExecutionContext *context = engine()->current;
+ ExecutionContext *context = engine()->currentContext();
if (m_index == DestroyMethod)
return method_destroy(context, callData->args, callData->argc);
else if (m_index == ToStringMethod)
@@ -1845,7 +1847,7 @@ QmlSignalHandler::QmlSignalHandler(ExecutionEngine *engine, QObject *object, int
, m_object(object)
, m_signalIndex(signalIndex)
{
- vtbl = &static_vtbl;
+ setVTable(&static_vtbl);
}
DEFINE_MANAGED_VTABLE(QmlSignalHandler);
diff --git a/src/qml/jsruntime/qv4qobjectwrapper_p.h b/src/qml/jsruntime/qv4qobjectwrapper_p.h
index a73c96d098..07de1933c5 100644
--- a/src/qml/jsruntime/qv4qobjectwrapper_p.h
+++ b/src/qml/jsruntime/qv4qobjectwrapper_p.h
@@ -94,17 +94,17 @@ struct Q_QML_EXPORT QObjectWrapper : public QV4::Object
using Object::get;
- ReturnedValue getProperty(ExecutionContext *ctx, int propertyIndex, bool captureRequired);
+ static ReturnedValue getProperty(QObject *object, ExecutionContext *ctx, int propertyIndex, bool captureRequired);
void setProperty(ExecutionContext *ctx, int propertyIndex, const ValueRef value);
protected:
static bool isEqualTo(Managed *that, Managed *o);
private:
- ReturnedValue getProperty(ExecutionContext *ctx, QQmlPropertyData *property, bool captureRequired = true);
+ static ReturnedValue getProperty(QObject *object, ExecutionContext *ctx, QQmlPropertyData *property, bool captureRequired = true);
static void setProperty(QObject *object, ExecutionContext *ctx, QQmlPropertyData *property, const ValueRef value);
- static ReturnedValue create(ExecutionEngine *engine, QQmlData *ddata, QObject *object);
+ static ReturnedValue create(ExecutionEngine *engine, QObject *object);
QObjectWrapper(ExecutionEngine *engine, QObject *object);
diff --git a/src/qml/jsruntime/qv4regexp.cpp b/src/qml/jsruntime/qv4regexp.cpp
index 5ec63061dc..41ff9f9741 100644
--- a/src/qml/jsruntime/qv4regexp.cpp
+++ b/src/qml/jsruntime/qv4regexp.cpp
@@ -92,14 +92,13 @@ RegExp* RegExp::create(ExecutionEngine* engine, const QString& pattern, bool ign
}
RegExp::RegExp(ExecutionEngine* engine, const QString &pattern, bool ignoreCase, bool multiline)
- : Managed(engine->emptyClass)
+ : Managed(engine->regExpValueClass)
, m_pattern(pattern)
, m_cache(0)
, m_subPatternCount(0)
, m_ignoreCase(ignoreCase)
, m_multiLine(multiline)
{
- vtbl = &static_vtbl;
type = Type_RegExpObject;
if (!engine)
diff --git a/src/qml/jsruntime/qv4regexpobject.cpp b/src/qml/jsruntime/qv4regexpobject.cpp
index a8597229c4..468fb34d76 100644
--- a/src/qml/jsruntime/qv4regexpobject.cpp
+++ b/src/qml/jsruntime/qv4regexpobject.cpp
@@ -142,7 +142,7 @@ RegExpObject::RegExpObject(ExecutionEngine *engine, const QRegExp &re)
void RegExpObject::init(ExecutionEngine *engine)
{
- vtbl = &static_vtbl;
+ setVTable(&static_vtbl);
type = Type_RegExpObject;
Scope scope(engine);
@@ -237,12 +237,12 @@ DEFINE_MANAGED_VTABLE(RegExpCtor);
RegExpCtor::RegExpCtor(ExecutionContext *scope)
: FunctionObject(scope, QStringLiteral("RegExp"))
{
- vtbl = &static_vtbl;
+ setVTable(&static_vtbl);
}
ReturnedValue RegExpCtor::construct(Managed *m, CallData *callData)
{
- ExecutionContext *ctx = m->engine()->current;
+ ExecutionContext *ctx = m->engine()->currentContext();
Scope scope(ctx);
ScopedValue r(scope, callData->argument(0));
diff --git a/src/qml/jsruntime/qv4runtime.cpp b/src/qml/jsruntime/qv4runtime.cpp
index a8cabcb374..011607f0ba 100644
--- a/src/qml/jsruntime/qv4runtime.cpp
+++ b/src/qml/jsruntime/qv4runtime.cpp
@@ -53,6 +53,7 @@
#include "qv4scopedvalue_p.h"
#include <private/qqmlcontextwrapper_p.h>
#include "qv4qobjectwrapper_p.h"
+#include <private/qv8engine_p.h>
#include <QtCore/qmath.h>
#include <QtCore/qnumeric.h>
@@ -299,12 +300,34 @@ ReturnedValue __qmljs_delete_name(ExecutionContext *ctx, const StringRef name)
QV4::ReturnedValue __qmljs_instanceof(ExecutionContext *ctx, const ValueRef left, const ValueRef right)
{
- Object *o = right->asObject();
- if (!o)
+ FunctionObject *f = right->asFunctionObject();
+ if (!f)
return ctx->throwTypeError();
- bool r = o->hasInstance(left);
- return Encode(r);
+ if (f->subtype == FunctionObject::BoundFunction)
+ f = static_cast<BoundFunction *>(f)->target;
+
+ Scope scope(ctx->engine);
+ ScopedObject v(scope, left);
+ if (!v)
+ return Encode(false);
+
+ Scoped<Object> o(scope, f->protoProperty());
+ if (!o) {
+ scope.engine->currentContext()->throwTypeError();
+ return Encode(false);
+ }
+
+ while (v) {
+ v = v->prototype();
+
+ if (! v)
+ break;
+ else if (o.getPointer() == v)
+ return Encode(true);
+ }
+
+ return Encode(false);
}
QV4::ReturnedValue __qmljs_in(ExecutionContext *ctx, const ValueRef left, const ValueRef right)
@@ -366,7 +389,7 @@ ReturnedValue __qmljs_object_default_value(Object *object, int typeHint)
if (typeHint == NUMBER_HINT)
qSwap(meth1, meth2);
- ExecutionContext *ctx = engine->current;
+ ExecutionContext *ctx = engine->currentContext();
Scope scope(ctx);
ScopedCallData callData(scope, 0);
callData->thisObject = object;
@@ -966,10 +989,10 @@ ReturnedValue __qmljs_construct_value(ExecutionContext *context, const ValueRef
return f->construct(callData);
}
-ReturnedValue __qmljs_construct_property(ExecutionContext *context, const ValueRef base, const StringRef name, CallDataRef callData)
+ReturnedValue __qmljs_construct_property(ExecutionContext *context, const StringRef name, CallDataRef callData)
{
Scope scope(context);
- ScopedObject thisObject(scope, base->toObject(context));
+ ScopedObject thisObject(scope, callData->thisObject.toObject(context));
if (scope.engine->hasException)
return Encode::undefined();
@@ -980,6 +1003,18 @@ ReturnedValue __qmljs_construct_property(ExecutionContext *context, const ValueR
return f->construct(callData);
}
+ReturnedValue __qmljs_construct_property_lookup(ExecutionContext *context, uint index, CallDataRef callData)
+{
+ Lookup *l = context->lookups + index;
+ SafeValue v;
+ v = l->getter(l, callData->thisObject);
+ if (!v.isManaged())
+ return context->throwTypeError();
+
+ return v.managed()->construct(callData);
+}
+
+
void __qmljs_throw(ExecutionContext *context, const ValueRef value)
{
if (!value->isEmpty())
@@ -1230,10 +1265,9 @@ ReturnedValue __qmljs_lookup_runtime_regexp(ExecutionContext *ctx, int id)
return ctx->compilationUnit->runtimeRegularExpressions[id].asReturnedValue();
}
-ReturnedValue __qmljs_get_id_object(NoThrowContext *ctx, int id)
+ReturnedValue __qmljs_get_id_array(NoThrowContext *ctx)
{
- QQmlContextData *context = QmlContextWrapper::callingContext(ctx->engine);
- return QObjectWrapper::wrap(ctx->engine, context->idValues[id].data());
+ return ctx->engine->qmlContextObject()->getPointer()->as<QmlContextWrapper>()->idObjectsArray();
}
ReturnedValue __qmljs_get_context_object(NoThrowContext *ctx)
@@ -1257,7 +1291,19 @@ ReturnedValue __qmljs_get_qobject_property(ExecutionContext *ctx, const ValueRef
ctx->throwTypeError(QStringLiteral("Cannot read property of null"));
return Encode::undefined();
}
- return wrapper->getProperty(ctx, propertyIndex, captureRequired);
+ return QV4::QObjectWrapper::getProperty(wrapper->object(), ctx, propertyIndex, captureRequired);
+}
+
+QV4::ReturnedValue __qmljs_get_attached_property(ExecutionContext *ctx, int attachedPropertiesId, int propertyIndex)
+{
+ Scope scope(ctx);
+ QV4::Scoped<QmlContextWrapper> c(scope, ctx->engine->qmlContextObject()->getPointer()->as<QmlContextWrapper>());
+ QObject *scopeObject = c->getScopeObject();
+ QObject *attachedObject = qmlAttachedPropertiesObjectById(attachedPropertiesId, scopeObject);
+
+ QQmlEngine *qmlEngine = ctx->engine->v8Engine->engine();
+ QQmlData::ensurePropertyCache(qmlEngine, attachedObject);
+ return QV4::QObjectWrapper::getProperty(attachedObject, ctx, propertyIndex, /*captureRequired*/true);
}
void __qmljs_set_qobject_property(ExecutionContext *ctx, const ValueRef object, int propertyIndex, const ValueRef value)
@@ -1277,6 +1323,11 @@ ReturnedValue __qmljs_get_imported_scripts(NoThrowContext *ctx)
return context->importedScripts.value();
}
+QV4::ReturnedValue __qmljs_get_qml_singleton(QV4::NoThrowContext *ctx, const QV4::StringRef name)
+{
+ return ctx->engine->qmlContextObject()->getPointer()->as<QmlContextWrapper>()->qmlSingletonWrapper(name);
+}
+
void __qmljs_builtin_convert_this_to_object(ExecutionContext *ctx)
{
SafeValue *t = &ctx->callData->thisObject;
diff --git a/src/qml/jsruntime/qv4runtime_p.h b/src/qml/jsruntime/qv4runtime_p.h
index b5567693e5..9524b2459c 100644
--- a/src/qml/jsruntime/qv4runtime_p.h
+++ b/src/qml/jsruntime/qv4runtime_p.h
@@ -125,7 +125,8 @@ QV4::ReturnedValue __qmljs_call_element(ExecutionContext *context, const ValueRe
QV4::ReturnedValue __qmljs_call_value(QV4::ExecutionContext *context, const QV4::ValueRef func, CallDataRef callData);
QV4::ReturnedValue __qmljs_construct_activation_property(QV4::ExecutionContext *, const QV4::StringRef name, CallDataRef callData);
-QV4::ReturnedValue __qmljs_construct_property(QV4::ExecutionContext *context, const QV4::ValueRef base, const QV4::StringRef name, CallDataRef callData);
+QV4::ReturnedValue __qmljs_construct_property(QV4::ExecutionContext *context, const QV4::StringRef name, CallDataRef callData);
+QV4::ReturnedValue __qmljs_construct_property_lookup(ExecutionContext *context, uint index, CallDataRef callData);
QV4::ReturnedValue __qmljs_construct_value(QV4::ExecutionContext *context, const QV4::ValueRef func, CallDataRef callData);
QV4::ReturnedValue __qmljs_builtin_typeof(QV4::ExecutionContext *ctx, const QV4::ValueRef val);
@@ -170,12 +171,14 @@ QV4::ReturnedValue __qmljs_construct_global_lookup(QV4::ExecutionContext *contex
QV4::ReturnedValue __qmljs_get_element(QV4::ExecutionContext *ctx, const QV4::ValueRef object, const QV4::ValueRef index);
void __qmljs_set_element(QV4::ExecutionContext *ctx, const QV4::ValueRef object, const QV4::ValueRef index, const QV4::ValueRef value);
-QV4::ReturnedValue __qmljs_get_id_object(NoThrowContext *ctx, int id);
+QV4::ReturnedValue __qmljs_get_id_array(NoThrowContext *ctx);
QV4::ReturnedValue __qmljs_get_imported_scripts(NoThrowContext *ctx);
QV4::ReturnedValue __qmljs_get_context_object(NoThrowContext *ctx);
QV4::ReturnedValue __qmljs_get_scope_object(NoThrowContext *ctx);
QV4::ReturnedValue __qmljs_get_qobject_property(ExecutionContext *ctx, const ValueRef object, int propertyIndex, bool captureRequired);
+QV4::ReturnedValue __qmljs_get_attached_property(ExecutionContext *ctx, int attachedPropertiesId, int propertyIndex);
void __qmljs_set_qobject_property(ExecutionContext *ctx, const ValueRef object, int propertyIndex, const ValueRef value);
+QV4::ReturnedValue __qmljs_get_qml_singleton(NoThrowContext *ctx, const QV4::StringRef name);
// For each
QV4::ReturnedValue __qmljs_foreach_iterator_object(QV4::ExecutionContext *ctx, const QV4::ValueRef in);
diff --git a/src/qml/jsruntime/qv4scopedvalue_p.h b/src/qml/jsruntime/qv4scopedvalue_p.h
index 17a19b5201..21f45745cb 100644
--- a/src/qml/jsruntime/qv4scopedvalue_p.h
+++ b/src/qml/jsruntime/qv4scopedvalue_p.h
@@ -41,7 +41,7 @@
#ifndef QV4SCOPEDVALUE_P_H
#define QV4SCOPEDVALUE_P_H
-#include "qv4engine_p.h"
+#include "qv4context_p.h"
#include "qv4value_def_p.h"
QT_BEGIN_NAMESPACE
@@ -231,7 +231,7 @@ struct Scoped
Scoped(const Scope &scope, const Value &v, _Convert)
{
ptr = scope.engine->jsStackTop++;
- ptr->val = value_convert<T>(scope.engine->current, v);
+ ptr->val = value_convert<T>(scope.engine->currentContext(), v);
#ifndef QT_NO_DEBUG
++scope.size;
#endif
@@ -278,7 +278,7 @@ struct Scoped
Scoped(const Scope &scope, const ReturnedValue &v, _Convert)
{
ptr = scope.engine->jsStackTop++;
- ptr->val = value_convert<T>(scope.engine->current, QV4::Value::fromReturnedValue(v));
+ ptr->val = value_convert<T>(scope.engine->currentContext(), QV4::Value::fromReturnedValue(v));
#ifndef QT_NO_DEBUG
++scope.size;
#endif
diff --git a/src/qml/jsruntime/qv4script.cpp b/src/qml/jsruntime/qv4script.cpp
index 25791cff61..4fd0569627 100644
--- a/src/qml/jsruntime/qv4script.cpp
+++ b/src/qml/jsruntime/qv4script.cpp
@@ -51,6 +51,7 @@
#include <private/qqmljslexer_p.h>
#include <private/qqmljsparser_p.h>
#include <private/qqmljsast_p.h>
+#include <private/qqmlengine_p.h>
#include <qv4jsir_p.h>
#include <qv4codegen_p.h>
@@ -62,27 +63,41 @@ using namespace QV4;
QmlBindingWrapper::QmlBindingWrapper(ExecutionContext *scope, Function *f, ObjectRef qml)
: FunctionObject(scope, scope->engine->id_eval)
, qml(qml)
+ , qmlContext(0)
{
- vtbl = &static_vtbl;
+ Q_ASSERT(scope->inUse);
+
+ setVTable(&static_vtbl);
function = f;
function->compilationUnit->ref();
needsActivation = function->needsActivation();
+
+ Scope s(scope);
+ ScopedValue protectThis(s, this);
+
defineReadonlyProperty(scope->engine->id_length, Primitive::fromInt32(1));
- qmlContext = scope->engine->current->newQmlContext(this, qml);
+ qmlContext = scope->engine->currentContext()->newQmlContext(this, qml);
scope->engine->popContext();
}
QmlBindingWrapper::QmlBindingWrapper(ExecutionContext *scope, ObjectRef qml)
: FunctionObject(scope, scope->engine->id_eval)
, qml(qml)
+ , qmlContext(0)
{
- vtbl = &static_vtbl;
+ Q_ASSERT(scope->inUse);
+
+ setVTable(&static_vtbl);
function = 0;
needsActivation = false;
+
+ Scope s(scope);
+ ScopedValue protectThis(s, this);
+
defineReadonlyProperty(scope->engine->id_length, Primitive::fromInt32(1));
- qmlContext = scope->engine->current->newQmlContext(this, qml);
+ qmlContext = scope->engine->currentContext()->newQmlContext(this, qml);
scope->engine->popContext();
}
@@ -110,7 +125,8 @@ void QmlBindingWrapper::markObjects(Managed *m, ExecutionEngine *e)
if (wrapper->qml)
wrapper->qml->mark(e);
FunctionObject::markObjects(m, e);
- wrapper->qmlContext->mark();
+ if (wrapper->qmlContext)
+ wrapper->qmlContext->mark(e);
}
DEFINE_MANAGED_VTABLE(QmlBindingWrapper);
@@ -124,7 +140,7 @@ struct CompilationUnitHolder : public QV4::Object
, unit(unit)
{
unit->ref();
- vtbl = &static_vtbl;
+ setVTable(&static_vtbl);
}
~CompilationUnitHolder()
{
@@ -214,7 +230,7 @@ void Script::parse()
return;
QV4::Compiler::JSUnitGenerator jsGenerator(&module);
- QScopedPointer<EvalInstructionSelection> isel(v4->iselFactory->create(v4->executableAllocator, &module, &jsGenerator));
+ QScopedPointer<EvalInstructionSelection> isel(v4->iselFactory->create(QQmlEnginePrivate::get(v4), v4->executableAllocator, &module, &jsGenerator));
if (inheritContext)
isel->setUseFastLookups(false);
QV4::CompiledData::CompilationUnit *compilationUnit = isel->compile();
@@ -226,7 +242,7 @@ void Script::parse()
if (!vmFunction) {
// ### FIX file/line number
Scoped<Object> error(valueScope, v4->newSyntaxErrorObject(QStringLiteral("Syntax error")));
- v4->current->throwError(error);
+ v4->currentContext()->throwError(error);
}
}
@@ -340,7 +356,7 @@ CompiledData::CompilationUnit *Script::precompile(ExecutionEngine *engine, const
}
Compiler::JSUnitGenerator jsGenerator(&module);
- QScopedPointer<QQmlJS::EvalInstructionSelection> isel(engine->iselFactory->create(engine->executableAllocator, &module, &jsGenerator));
+ QScopedPointer<QQmlJS::EvalInstructionSelection> isel(engine->iselFactory->create(QQmlEnginePrivate::get(engine), engine->executableAllocator, &module, &jsGenerator));
isel->setUseFastLookups(false);
return isel->compile();
}
@@ -361,7 +377,7 @@ QV4::ReturnedValue Script::evaluate(ExecutionEngine *engine, const QString &scr
QV4::Scope scope(engine);
QV4::Script qmlScript(engine, scopeObject, script, QString());
- QV4::ExecutionContext *ctx = engine->current;
+ QV4::ExecutionContext *ctx = engine->currentContext();
qmlScript.parse();
QV4::ScopedValue result(scope);
if (!scope.engine->hasException)
diff --git a/src/qml/jsruntime/qv4sequenceobject.cpp b/src/qml/jsruntime/qv4sequenceobject.cpp
index 26e4dcb8a2..8b0e31cb71 100644
--- a/src/qml/jsruntime/qv4sequenceobject.cpp
+++ b/src/qml/jsruntime/qv4sequenceobject.cpp
@@ -47,6 +47,7 @@
#include <private/qv4arrayobject_p.h>
#include <private/qqmlengine_p.h>
#include <private/qv4scopedvalue_p.h>
+#include <private/qv4internalclass_p.h>
#include <algorithm>
@@ -167,14 +168,13 @@ class QQmlSequence : public QV4::Object
Q_MANAGED
public:
QQmlSequence(QV4::ExecutionEngine *engine, const Container &container)
- : QV4::Object(engine->sequenceClass)
+ : QV4::Object(InternalClass::create(engine, &static_vtbl, engine->sequencePrototype.asObject()))
, m_container(container)
, m_object(0)
, m_propertyIndex(-1)
, m_isReference(false)
{
type = Type_QmlSequence;
- vtbl = &static_vtbl;
flags &= ~SimpleArray;
QV4::Scope scope(engine);
QV4::ScopedObject protectThis(scope, this);
@@ -183,13 +183,12 @@ public:
}
QQmlSequence(QV4::ExecutionEngine *engine, QObject *object, int propertyIndex)
- : QV4::Object(engine->sequenceClass)
+ : QV4::Object(InternalClass::create(engine, &static_vtbl, engine->sequencePrototype.asObject()))
, m_object(object)
, m_propertyIndex(propertyIndex)
, m_isReference(true)
{
type = Type_QmlSequence;
- vtbl = &static_vtbl;
flags &= ~SimpleArray;
QV4::Scope scope(engine);
QV4::ScopedObject protectThis(scope, this);
@@ -207,7 +206,7 @@ public:
{
/* Qt containers have int (rather than uint) allowable indexes. */
if (index > INT_MAX) {
- generateWarning(engine()->current, QLatin1String("Index out of range during indexed get"));
+ generateWarning(engine()->currentContext(), QLatin1String("Index out of range during indexed get"));
if (hasProperty)
*hasProperty = false;
return Encode::undefined();
@@ -238,7 +237,7 @@ public:
/* Qt containers have int (rather than uint) allowable indexes. */
if (index > INT_MAX) {
- generateWarning(engine()->current, QLatin1String("Index out of range during indexed set"));
+ generateWarning(engine()->currentContext(), QLatin1String("Index out of range during indexed set"));
return;
}
@@ -276,7 +275,7 @@ public:
{
/* Qt containers have int (rather than uint) allowable indexes. */
if (index > INT_MAX) {
- generateWarning(engine()->current, QLatin1String("Index out of range during indexed query"));
+ generateWarning(engine()->currentContext(), QLatin1String("Index out of range during indexed query"));
return QV4::Attr_Invalid;
}
if (m_isReference) {
diff --git a/src/qml/jsruntime/qv4serialize.cpp b/src/qml/jsruntime/qv4serialize.cpp
index 06a2603280..ee325db4c2 100644
--- a/src/qml/jsruntime/qv4serialize.cpp
+++ b/src/qml/jsruntime/qv4serialize.cpp
@@ -279,7 +279,7 @@ void Serialize::serialize(QByteArray &data, const QV4::ValueRef v, QV8Engine *en
s = properties->getIndexed(ii);
serialize(data, s, engine);
- QV4::ExecutionContext *ctx = v4->current;
+ QV4::ExecutionContext *ctx = v4->currentContext();
str = s;
val = o->get(str);
if (scope.hasException())
diff --git a/src/qml/jsruntime/qv4string.cpp b/src/qml/jsruntime/qv4string.cpp
index 0e43d03987..e5633eb06f 100644
--- a/src/qml/jsruntime/qv4string.cpp
+++ b/src/qml/jsruntime/qv4string.cpp
@@ -108,7 +108,6 @@ const ManagedVTable String::static_vtbl =
markObjects,
destroy,
0 /*collectDeletables*/,
- hasInstance,
get,
getIndexed,
put,
@@ -150,7 +149,7 @@ ReturnedValue String::get(Managed *m, const StringRef name, bool *hasProperty)
return Primitive::fromInt32(that->_text->size).asReturnedValue();
}
PropertyAttributes attrs;
- Property *pd = v4->stringClass->prototype->__getPropertyDescriptor__(name, &attrs);
+ Property *pd = v4->stringObjectClass->prototype->__getPropertyDescriptor__(name, &attrs);
if (!pd || attrs.isGeneric()) {
if (hasProperty)
*hasProperty = false;
@@ -158,7 +157,7 @@ ReturnedValue String::get(Managed *m, const StringRef name, bool *hasProperty)
}
if (hasProperty)
*hasProperty = true;
- return v4->stringClass->prototype->getValue(that, pd, attrs);
+ return v4->stringObjectClass->prototype->getValue(that, pd, attrs);
}
ReturnedValue String::getIndexed(Managed *m, uint index, bool *hasProperty)
@@ -173,7 +172,7 @@ ReturnedValue String::getIndexed(Managed *m, uint index, bool *hasProperty)
return Encode(engine->newString(that->toQString().mid(index, 1)));
}
PropertyAttributes attrs;
- Property *pd = engine->stringClass->prototype->__getPropertyDescriptor__(index, &attrs);
+ Property *pd = engine->stringObjectClass->prototype->__getPropertyDescriptor__(index, &attrs);
if (!pd || attrs.isGeneric()) {
if (hasProperty)
*hasProperty = false;
@@ -181,7 +180,7 @@ ReturnedValue String::getIndexed(Managed *m, uint index, bool *hasProperty)
}
if (hasProperty)
*hasProperty = true;
- return engine->stringClass->prototype->getValue(that, pd, attrs);
+ return engine->stringObjectClass->prototype->getValue(that, pd, attrs);
}
void String::put(Managed *m, const StringRef name, const ValueRef value)
@@ -252,24 +251,22 @@ bool String::isEqualTo(Managed *t, Managed *o)
String::String(ExecutionEngine *engine, const QString &text)
- : Managed(engine ? engine->emptyClass : 0), _text(const_cast<QString &>(text).data_ptr())
+ : Managed(engine->stringClass), _text(const_cast<QString &>(text).data_ptr())
, identifier(0), stringHash(UINT_MAX)
, largestSubLength(0)
{
_text->ref.ref();
len = _text->size;
- vtbl = &static_vtbl;
type = Type_String;
subtype = StringType_Unknown;
}
String::String(ExecutionEngine *engine, String *l, String *r)
- : Managed(engine ? engine->emptyClass : 0)
+ : Managed(engine->stringClass)
, left(l), right(r)
, stringHash(UINT_MAX), largestSubLength(qMax(l->largestSubLength, r->largestSubLength))
, len(l->len + r->len)
{
- vtbl = &static_vtbl;
type = Type_String;
subtype = StringType_Unknown;
@@ -360,7 +357,7 @@ void String::createHashValue() const
// array indices get their number as hash value
bool ok;
- stringHash = toArrayIndex(ch, end, &ok);
+ stringHash = ::toArrayIndex(ch, end, &ok);
if (ok) {
subtype = (stringHash == UINT_MAX) ? StringType_UInt : StringType_ArrayIndex;
return;
@@ -382,7 +379,7 @@ uint String::createHashValue(const QChar *ch, int length)
// array indices get their number as hash value
bool ok;
- uint stringHash = toArrayIndex(ch, end, &ok);
+ uint stringHash = ::toArrayIndex(ch, end, &ok);
if (ok)
return stringHash;
@@ -401,7 +398,7 @@ uint String::createHashValue(const char *ch, int length)
// array indices get their number as hash value
bool ok;
- uint stringHash = toArrayIndex(ch, end, &ok);
+ uint stringHash = ::toArrayIndex(ch, end, &ok);
if (ok)
return stringHash;
@@ -415,3 +412,9 @@ uint String::createHashValue(const char *ch, int length)
return h;
}
+
+uint String::toArrayIndex(const QString &str)
+{
+ bool ok;
+ return ::toArrayIndex(str.constData(), str.constData() + str.length(), &ok);
+}
diff --git a/src/qml/jsruntime/qv4string_p.h b/src/qml/jsruntime/qv4string_p.h
index bb6f1d2279..64e15b04c2 100644
--- a/src/qml/jsruntime/qv4string_p.h
+++ b/src/qml/jsruntime/qv4string_p.h
@@ -63,7 +63,7 @@ struct Q_QML_EXPORT String : public Managed {
String()
: Managed(0), _text(QStringData::sharedNull()), identifier(0)
, stringHash(UINT_MAX), largestSubLength(0), len(0)
- { vtbl = &static_vtbl; type = Type_String; subtype = StringType_Unknown; }
+ { type = Type_String; subtype = StringType_Unknown; }
String(ExecutionEngine *engine, const QString &text);
String(ExecutionEngine *engine, String *l, String *n);
~String() {
@@ -140,6 +140,8 @@ struct Q_QML_EXPORT String : public Managed {
return len;
}
+ static uint toArrayIndex(const QString &str);
+
union {
mutable QStringData *_text;
mutable String *left;
diff --git a/src/qml/jsruntime/qv4stringobject.cpp b/src/qml/jsruntime/qv4stringobject.cpp
index bff8f1f9cd..d468fb6b83 100644
--- a/src/qml/jsruntime/qv4stringobject.cpp
+++ b/src/qml/jsruntime/qv4stringobject.cpp
@@ -80,7 +80,7 @@ DEFINE_MANAGED_VTABLE(StringObject);
StringObject::StringObject(InternalClass *ic)
: Object(ic)
{
- vtbl = &static_vtbl;
+ setVTable(&static_vtbl);
type = Type_StringObject;
Scope scope(engine());
@@ -94,9 +94,9 @@ StringObject::StringObject(InternalClass *ic)
}
StringObject::StringObject(ExecutionEngine *engine, const ValueRef val)
- : Object(engine->stringClass)
+ : Object(engine->stringObjectClass)
{
- vtbl = &static_vtbl;
+ setVTable(&static_vtbl);
type = Type_StringObject;
Scope scope(engine);
@@ -125,13 +125,13 @@ bool StringObject::deleteIndexedProperty(Managed *m, uint index)
Scope scope(v4);
Scoped<StringObject> o(scope, m->asStringObject());
if (!o) {
- v4->current->throwTypeError();
+ v4->currentContext()->throwTypeError();
return false;
}
if (index < static_cast<uint>(o->value.stringValue()->toQString().length())) {
- if (v4->current->strictMode)
- v4->current->throwTypeError();
+ if (v4->currentContext()->strictMode)
+ v4->currentContext()->throwTypeError();
return false;
}
return true;
@@ -172,7 +172,7 @@ DEFINE_MANAGED_VTABLE(StringCtor);
StringCtor::StringCtor(ExecutionContext *scope)
: FunctionObject(scope, QStringLiteral("String"))
{
- vtbl = &static_vtbl;
+ setVTable(&static_vtbl);
}
ReturnedValue StringCtor::construct(Managed *m, CallData *callData)
@@ -181,7 +181,7 @@ ReturnedValue StringCtor::construct(Managed *m, CallData *callData)
Scope scope(v4);
ScopedValue value(scope);
if (callData->argc)
- value = callData->args[0].toString(v4->current);
+ value = callData->args[0].toString(v4->currentContext());
else
value = v4->newString(QString());
return Encode(v4->newStringObject(value));
@@ -193,7 +193,7 @@ ReturnedValue StringCtor::call(Managed *m, CallData *callData)
Scope scope(v4);
ScopedValue value(scope);
if (callData->argc)
- value = callData->args[0].toString(v4->current);
+ value = callData->args[0].toString(v4->currentContext());
else
value = v4->newString(QString());
return value.asReturnedValue();
diff --git a/src/qml/jsruntime/qv4value.cpp b/src/qml/jsruntime/qv4value.cpp
index 4ae570c8dc..30f7e8cdb0 100644
--- a/src/qml/jsruntime/qv4value.cpp
+++ b/src/qml/jsruntime/qv4value.cpp
@@ -90,7 +90,7 @@ double Value::toNumberImpl() const
if (isString())
return __qmljs_string_to_number(stringValue()->toQString());
{
- ExecutionContext *ctx = objectValue()->internalClass->engine->current;
+ ExecutionContext *ctx = objectValue()->internalClass->engine->currentContext();
Scope scope(ctx);
ScopedValue prim(scope, __qmljs_to_primitive(ValueRef::fromRawValue(this), NUMBER_HINT));
return prim->toNumber();
@@ -121,7 +121,7 @@ QString Value::toQStringNoThrow() const
if (isString())
return stringValue()->toQString();
{
- ExecutionContext *ctx = objectValue()->internalClass->engine->current;
+ ExecutionContext *ctx = objectValue()->internalClass->engine->currentContext();
Scope scope(ctx);
ScopedValue ex(scope);
bool caughtException = false;
@@ -174,7 +174,7 @@ QString Value::toQString() const
if (isString())
return stringValue()->toQString();
{
- ExecutionContext *ctx = objectValue()->internalClass->engine->current;
+ ExecutionContext *ctx = objectValue()->internalClass->engine->currentContext();
Scope scope(ctx);
ScopedValue prim(scope, __qmljs_to_primitive(ValueRef::fromRawValue(this), STRING_HINT));
return prim->toQString();
diff --git a/src/qml/jsruntime/qv4variantobject.cpp b/src/qml/jsruntime/qv4variantobject.cpp
index 470e8e206b..dfa4ac5775 100644
--- a/src/qml/jsruntime/qv4variantobject.cpp
+++ b/src/qml/jsruntime/qv4variantobject.cpp
@@ -56,7 +56,6 @@ VariantObject::VariantObject(InternalClass *ic)
, ExecutionEngine::ScarceResourceData(QVariant())
, m_vmePropertyReferenceCount(0)
{
- vtbl = &static_vtbl;
}
VariantObject::VariantObject(ExecutionEngine *engine, const QVariant &value)
@@ -64,7 +63,6 @@ VariantObject::VariantObject(ExecutionEngine *engine, const QVariant &value)
, ExecutionEngine::ScarceResourceData(value)
, m_vmePropertyReferenceCount(0)
{
- vtbl = &static_vtbl;
if (isScarce())
engine->scarceResources.insert(this);
}
diff --git a/src/qml/jsruntime/qv4vme_moth.cpp b/src/qml/jsruntime/qv4vme_moth.cpp
index 72db469ee6..9d6540ebe9 100644
--- a/src/qml/jsruntime/qv4vme_moth.cpp
+++ b/src/qml/jsruntime/qv4vme_moth.cpp
@@ -320,6 +320,10 @@ QV4::ReturnedValue VME::run(QV4::ExecutionContext *context, const uchar *code,
STOREVALUE(instr.result, __qmljs_get_qobject_property(context, VALUEPTR(instr.base), instr.propertyIndex, instr.captureRequired));
MOTH_END_INSTR(LoadQObjectProperty)
+ MOTH_BEGIN_INSTR(LoadAttachedQObjectProperty)
+ STOREVALUE(instr.result, __qmljs_get_attached_property(context, instr.attachedPropertiesId, instr.propertyIndex));
+ MOTH_END_INSTR(LoadAttachedQObjectProperty)
+
MOTH_BEGIN_INSTR(Push)
TRACE(inline, "stack size: %u", instr.value);
stackSize = instr.value;
@@ -503,10 +507,19 @@ QV4::ReturnedValue VME::run(QV4::ExecutionContext *context, const uchar *code,
QV4::CallData *callData = reinterpret_cast<QV4::CallData *>(stack + instr.callData);
callData->tag = QV4::Value::Integer_Type;
callData->argc = instr.argc;
- callData->thisObject = QV4::Primitive::undefinedValue();
- STOREVALUE(instr.result, __qmljs_construct_property(context, VALUEPTR(instr.base), runtimeStrings[instr.name], callData));
+ callData->thisObject = VALUE(instr.base);
+ STOREVALUE(instr.result, __qmljs_construct_property(context, runtimeStrings[instr.name], callData));
MOTH_END_INSTR(CreateProperty)
+ MOTH_BEGIN_INSTR(ConstructPropertyLookup)
+ Q_ASSERT(instr.callData + instr.argc + qOffsetOf(QV4::CallData, args)/sizeof(QV4::SafeValue) <= stackSize);
+ QV4::CallData *callData = reinterpret_cast<QV4::CallData *>(stack + instr.callData);
+ callData->tag = QV4::Value::Integer_Type;
+ callData->argc = instr.argc;
+ callData->thisObject = VALUE(instr.base);
+ STOREVALUE(instr.result, __qmljs_construct_property_lookup(context, instr.index, callData));
+ MOTH_END_INSTR(ConstructPropertyLookup)
+
MOTH_BEGIN_INSTR(CreateActivationProperty)
TRACE(inline, "property name = %s, args = %d, argc = %d", runtimeStrings[instr.name]->toQString().toUtf8().constData(), instr.args, instr.argc);
Q_ASSERT(instr.callData + instr.argc + qOffsetOf(QV4::CallData, args)/sizeof(QV4::SafeValue) <= stackSize);
@@ -648,9 +661,9 @@ QV4::ReturnedValue VME::run(QV4::ExecutionContext *context, const uchar *code,
VALUE(instr.result) = context->callData->thisObject;
MOTH_END_INSTR(LoadThis)
- MOTH_BEGIN_INSTR(LoadQmlIdObject)
- VALUE(instr.result) = __qmljs_get_id_object(static_cast<QV4::NoThrowContext*>(context), instr.id);
- MOTH_END_INSTR(LoadQmlIdObject)
+ MOTH_BEGIN_INSTR(LoadQmlIdArray)
+ VALUE(instr.result) = __qmljs_get_id_array(static_cast<QV4::NoThrowContext*>(context));
+ MOTH_END_INSTR(LoadQmlIdArray)
MOTH_BEGIN_INSTR(LoadQmlImportedScripts)
VALUE(instr.result) = __qmljs_get_imported_scripts(static_cast<QV4::NoThrowContext*>(context));
@@ -664,6 +677,10 @@ QV4::ReturnedValue VME::run(QV4::ExecutionContext *context, const uchar *code,
VALUE(instr.result) = __qmljs_get_scope_object(static_cast<QV4::NoThrowContext*>(context));
MOTH_END_INSTR(LoadScopeObject)
+ MOTH_BEGIN_INSTR(LoadQmlSingleton)
+ VALUE(instr.result) = __qmljs_get_qml_singleton(static_cast<QV4::NoThrowContext*>(context), runtimeStrings[instr.name]);
+ MOTH_END_INSTR(LoadQmlSingleton)
+
#ifdef MOTH_THREADED_INTERPRETER
// nothing to do
#else
diff --git a/src/qml/qml.pro b/src/qml/qml.pro
index 08bda0bce7..b0ea93e9fb 100644
--- a/src/qml/qml.pro
+++ b/src/qml/qml.pro
@@ -5,6 +5,7 @@ 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
solaris-cc*:QMAKE_CXXFLAGS_RELEASE -= -O2
MODULE_PLUGIN_TYPES = \
@@ -17,6 +18,9 @@ exists("qqml_enable_gcov") {
QMAKE_DOCS = $$PWD/doc/qtqml.qdocconf
+# 2415: variable "xx" of static storage duration was declared but never referenced
+intel_icc: WERROR += -ww2415
+
load(qt_module)
HEADERS += qtqmlglobal.h \
diff --git a/src/qml/qml/ftw/qhashedstring.cpp b/src/qml/qml/ftw/qhashedstring.cpp
index 321e6ccb41..012412b6b5 100644
--- a/src/qml/qml/ftw/qhashedstring.cpp
+++ b/src/qml/qml/ftw/qhashedstring.cpp
@@ -195,20 +195,6 @@ bool QHashedString::compare(const QChar *lhs, const QChar *rhs, int length)
return true;
}
-// Unicode stuff
-static inline bool isUnicodeNonCharacter(uint ucs4)
-{
- // Unicode has a couple of "non-characters" that one can use internally,
- // but are not allowed to be used for text interchange.
- //
- // Those are the last two entries each Unicode Plane (U+FFFE, U+FFFF,
- // U+1FFFE, U+1FFFF, etc.) as well as the entries between U+FDD0 and
- // U+FDEF (inclusive)
-
- return (ucs4 & 0xfffe) == 0xfffe
- || (ucs4 - 0xfdd0U) < 16;
-}
-
QHashedStringRef QHashedStringRef::mid(int offset, int length) const
{
Q_ASSERT(offset < m_length);
diff --git a/src/qml/qml/qqml.h b/src/qml/qml/qqml.h
index b6c6fe840d..641209d1f3 100644
--- a/src/qml/qml/qqml.h
+++ b/src/qml/qml/qqml.h
@@ -467,7 +467,7 @@ inline int qmlRegisterSingletonType(const char *uri, int versionMajor, int versi
return QQmlPrivate::qmlregister(QQmlPrivate::SingletonRegistration, &api);
}
-static const int CurrentSingletonTypeRegistrationVersion = 2;
+enum { QmlCurrentSingletonTypeRegistrationVersion = 2 };
template <typename T>
inline int qmlRegisterSingletonType(const char *uri, int versionMajor, int versionMinor, const char *typeName,
QObject *(*callback)(QQmlEngine *, QJSEngine *))
@@ -475,7 +475,7 @@ inline int qmlRegisterSingletonType(const char *uri, int versionMajor, int versi
QML_GETTYPENAMES
QQmlPrivate::RegisterSingletonType api = {
- CurrentSingletonTypeRegistrationVersion,
+ QmlCurrentSingletonTypeRegistrationVersion,
uri, versionMajor, versionMinor, typeName,
diff --git a/src/qml/qml/qqmlbinding.cpp b/src/qml/qml/qqmlbinding.cpp
index 557267d808..9e2fb07066 100644
--- a/src/qml/qml/qqmlbinding.cpp
+++ b/src/qml/qml/qqmlbinding.cpp
@@ -50,6 +50,7 @@
#include <private/qqmltrace_p.h>
#include <private/qqmlexpression_p.h>
#include <private/qqmlscriptstring_p.h>
+#include <private/qqmlcontextwrapper_p.h>
#include <QVariant>
#include <QtCore/qdebug.h>
@@ -85,7 +86,14 @@ QQmlBinding::createBinding(Identifier id, QObject *obj, QQmlContext *ctxt,
Q_ASSERT(typeData);
if (QQmlCompiledData *cdata = typeData->compiledData()) {
- rv = new QQmlBinding(cdata->primitives.at(id), obj, ctxtdata, url, lineNumber, 0);
+ QV4::ExecutionEngine *v4 = engine->v4engine();
+ QV4::Scope valueScope(v4);
+ QV4::ScopedObject scopeObject(valueScope, QV4::QmlContextWrapper::qmlScope(v4->v8Engine, ctxtdata, obj));
+ QV4::Scoped<QV4::QmlBindingWrapper> wrapper(valueScope, new (v4->memoryManager) QV4::QmlBindingWrapper(v4->rootContext, scopeObject));
+ QV4::ExecutionContext *qmlContext = wrapper->context();
+ QV4::Function *runtimeFunction = cdata->compilationUnit->runtimeFunctions[cdata->customParserBindings[id]];
+ QV4::ScopedValue function(valueScope, QV4::FunctionObject::creatScriptFunction(qmlContext, runtimeFunction));
+ rv = new QQmlBinding(function, obj, ctxtdata, url, lineNumber, 0);
}
typeData->release();
diff --git a/src/qml/qml/qqmlboundsignal.cpp b/src/qml/qml/qqmlboundsignal.cpp
index 11dc873dd4..68160edf5e 100644
--- a/src/qml/qml/qqmlboundsignal.cpp
+++ b/src/qml/qml/qqmlboundsignal.cpp
@@ -89,8 +89,8 @@ QQmlBoundSignalExpression::QQmlBoundSignalExpression(QObject *target, int index,
QQmlBoundSignalExpression::QQmlBoundSignalExpression(QObject *target, int index, QQmlContextData *ctxt, QObject *scope, const QV4::ValueRef &function)
: QQmlJavaScriptExpression(&QQmlBoundSignalExpression_jsvtable),
m_v8function(function),
- m_line(-1),
- m_column(-1),
+ m_line(USHRT_MAX),
+ m_column(USHRT_MAX),
m_target(target),
m_index(index),
m_expressionFunctionValid(true),
diff --git a/src/qml/qml/qqmlcompileddata.cpp b/src/qml/qml/qqmlcompileddata.cpp
index 9fcef176ad..76bf24fe6b 100644
--- a/src/qml/qml/qqmlcompileddata.cpp
+++ b/src/qml/qml/qqmlcompileddata.cpp
@@ -45,6 +45,7 @@
#include "qqmlcomponent_p.h"
#include "qqmlcontext.h"
#include "qqmlcontext_p.h"
+#include "qqmlpropertymap.h"
#ifdef QML_THREADED_VME_INTERPRETER
#include "qqmlvme_p.h"
#endif
@@ -173,6 +174,27 @@ QQmlPropertyCache *QQmlCompiledData::TypeReference::createPropertyCache(QQmlEngi
}
}
+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
+ mo = component->rootPropertyCache->firstCppMetaObject();
+ isFullyDynamicType = qtTypeInherits<QQmlPropertyMap>(mo);
+}
void QQmlCompiledData::dumpInstructions()
{
diff --git a/src/qml/qml/qqmlcompiler.cpp b/src/qml/qml/qqmlcompiler.cpp
index 187274890b..2e208f2f3b 100644
--- a/src/qml/qml/qqmlcompiler.cpp
+++ b/src/qml/qml/qqmlcompiler.cpp
@@ -62,7 +62,6 @@
#include "qqmlglobal_p.h"
#include "qqmlbinding_p.h"
#include "qqmlabstracturlinterceptor.h"
-#include "qqmlcodegenerator_p.h"
#include <QDebug>
#include <QPointF>
@@ -848,6 +847,8 @@ bool QQmlCompiler::compile(QQmlEngine *engine,
}
}
+ ref.doDynamicTypeCheck();
+
out->types << ref;
}
@@ -859,6 +860,19 @@ bool QQmlCompiler::compile(QQmlEngine *engine,
if (componentStats)
dumpStats();
Q_ASSERT(out->rootPropertyCache);
+
+ // Any QQmlPropertyMap instances for example need to have their property cache removed,
+ // because the class is too dynamic and allows adding properties at any point at run-time.
+ for (int i = 0; i < output->types.count(); ++i) {
+ QQmlCompiledData::TypeReference &tr = output->types[i];
+ if (!tr.typePropertyCache)
+ continue;
+
+ if (tr.isFullyDynamicType) {
+ tr.typePropertyCache->release();
+ tr.typePropertyCache = 0;
+ }
+ }
} else {
reset(out);
}
@@ -919,7 +933,7 @@ void QQmlCompiler::compileTree(QQmlScript::Object *tree)
if (!jsModule->functions.isEmpty()) {
QV4::ExecutionEngine *v4 = QV8Engine::getV4(engine);
QV4::Compiler::JSUnitGenerator jsUnitGenerator(jsModule.data());
- QScopedPointer<QQmlJS::EvalInstructionSelection> isel(v4->iselFactory->create(v4->executableAllocator, jsModule.data(), &jsUnitGenerator));
+ QScopedPointer<QQmlJS::EvalInstructionSelection> isel(v4->iselFactory->create(enginePrivate, v4->executableAllocator, jsModule.data(), &jsUnitGenerator));
isel->setUseFastLookups(false);
QV4::CompiledData::CompilationUnit *jsUnit = isel->compile(/*generated unit data*/true);
output->compilationUnit = jsUnit;
@@ -1227,6 +1241,7 @@ void QQmlCompiler::genObject(QQmlScript::Object *obj, bool parentToSuper)
// Setup the synthesized meta object if necessary
if (!obj->synthdata.isEmpty()) {
+ Q_ASSERT(!output->types.at(obj->type).isFullyDynamicType);
Instruction::StoreMetaObject meta;
meta.aliasData = output->indexForByteArray(obj->synthdata);
meta.propertyCache = output->propertyCaches.count();
@@ -2682,14 +2697,42 @@ const QMetaObject *QQmlCompiler::resolveType(const QString& name) const
return qmltype->metaObject();
}
-int QQmlCompiler::bindingIdentifier(const Variant &value)
+int QQmlCompiler::bindingIdentifier(const QString &name, const Variant &value, const BindingContext &ctxt)
{
- return output->indexForString(value.asScript());
+ JSBindingReference *reference = pool->New<JSBindingReference>();
+ reference->expression = value;
+ reference->property = pool->New<Property>();
+ reference->property->setName(name);
+ reference->value = 0;
+ reference->bindingContext = ctxt;
+ reference->bindingContext.owner++;
+ // Unfortunately this is required for example for PropertyChanges where the bindings
+ // will be executed in the dynamic scope of the target, so we can't resolve any lookups
+ // at run-time.
+ reference->disableLookupAcceleration = true;
+
+ const int id = output->customParserBindings.count();
+ output->customParserBindings.append(0); // Filled in later.
+ reference->customParserBindingsIndex = id;
+
+ compileState->totalBindingsCount++;
+ compileState->bindings.prepend(reference);
+
+ return id;
}
// Ensures that the dynamic meta specification on obj is valid
bool QQmlCompiler::checkDynamicMeta(QQmlScript::Object *obj)
{
+ if (output->types[obj->type].isFullyDynamicType) {
+ if (!obj->dynamicProperties.isEmpty())
+ COMPILE_EXCEPTION(obj, tr("Fully dynamic types cannot declare new properties."));
+ if (!obj->dynamicSignals.isEmpty())
+ COMPILE_EXCEPTION(obj, tr("Fully dynamic types cannot declare new signals."));
+ if (!obj->dynamicSlots.isEmpty())
+ COMPILE_EXCEPTION(obj, tr("Fully Dynamic types cannot declare new functions."));
+ }
+
bool seenDefaultProperty = false;
// We use a coarse grain, 31 bit hash to check if there are duplicates.
@@ -3644,11 +3687,14 @@ bool QQmlCompiler::completeComponentBuild()
}
ComponentCompileState::PerObjectCompileData *cd = &compileState->jsCompileData[b->bindingContext.object];
- cd->functionsToCompile.append(node);
+ QtQml::CompiledFunctionOrExpression f;
+ f.node = node;
+ f.name = binding.property->name().toString().prepend(QStringLiteral("expression for "));
+ f.disableAcceleratedLookups = binding.disableLookupAcceleration;
+ cd->functionsToCompile.append(f);
binding.compiledIndex = cd->functionsToCompile.count() - 1;
- cd->expressionNames.insert(binding.compiledIndex, binding.property->name().toString().prepend(QStringLiteral("expression for ")));
- if (componentStats)
+ if (componentStats && b->value)
componentStats->componentStat.scriptBindings.append(b->value->location);
}
@@ -3656,7 +3702,7 @@ bool QQmlCompiler::completeComponentBuild()
const QString &sourceCode = jsEngine->code();
AST::UiProgram *qmlRoot = parser.qmlRoot();
- JSCodeGen jsCodeGen(enginePrivate, unit->finalUrlString(), sourceCode, jsModule.data(), jsEngine, qmlRoot, output->importCache);
+ JSCodeGen jsCodeGen(unit->finalUrlString(), sourceCode, jsModule.data(), jsEngine, qmlRoot, output->importCache);
JSCodeGen::ObjectIdMapping idMapping;
if (compileState->ids.count() > 0) {
@@ -3679,7 +3725,7 @@ bool QQmlCompiler::completeComponentBuild()
jsCodeGen.beginObjectScope(scopeObject->metatype);
- cd->runtimeFunctionIndices = jsCodeGen.generateJSCodeForFunctionsAndBindings(cd->functionsToCompile, cd->expressionNames);
+ cd->runtimeFunctionIndices = jsCodeGen.generateJSCodeForFunctionsAndBindings(cd->functionsToCompile);
QList<QQmlError> errors = jsCodeGen.errors();
if (!errors.isEmpty()) {
exceptions << errors;
@@ -3697,6 +3743,10 @@ bool QQmlCompiler::completeComponentBuild()
for (JSBindingReference *b = compileState->bindings.first(); b; b = b->nextReference) {
JSBindingReference &binding = *b;
binding.compiledIndex = compileState->jsCompileData[binding.bindingContext.object].runtimeFunctionIndices[binding.compiledIndex];
+ if (!binding.value) { // Must be a binding requested from custom parser
+ Q_ASSERT(binding.customParserBindingsIndex >= 0 && binding.customParserBindingsIndex < output->customParserBindings.count());
+ output->customParserBindings[binding.customParserBindingsIndex] = binding.compiledIndex;
+ }
}
}
diff --git a/src/qml/qml/qqmlcompiler_p.h b/src/qml/qml/qqmlcompiler_p.h
index 3ca4566e41..516f6653ca 100644
--- a/src/qml/qml/qqmlcompiler_p.h
+++ b/src/qml/qml/qqmlcompiler_p.h
@@ -62,6 +62,7 @@
#include "qqmlpropertycache_p.h"
#include "qqmltypenamecache_p.h"
#include "qqmltypeloader_p.h"
+#include <private/qqmlcodegenerator_p.h>
#include "private/qv4identifier_p.h"
#include <private/qqmljsastfwd_p.h>
@@ -105,6 +106,7 @@ public:
: type(0), typePropertyCache(0), component(0)
, majorVersion(0)
, minorVersion(0)
+ , isFullyDynamicType(false)
{}
QQmlType *type;
@@ -113,9 +115,14 @@ public:
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();
};
// --- old compiler:
QList<TypeReference> types;
@@ -150,6 +157,7 @@ public:
// 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;
+ QVector<int> customParserBindings; // index is binding identifier, value is compiled function index.
bool isComponent(int objectIndex) const { return objectIndexToIdPerComponent.contains(objectIndex); }
bool isCompositeType() const { return !datas.at(qmlUnit->indexOfRootObject).isEmpty(); }
@@ -169,7 +177,7 @@ public:
int addInstruction(const QQmlInstructionData<Instr> &data)
{
QQmlInstruction genericInstr;
- QQmlInstructionMeta<Instr>::setData(genericInstr, data);
+ QQmlInstructionMeta<Instr>::setDataNoCommon(genericInstr, data);
return addInstructionHelper(static_cast<QQmlInstruction::Type>(Instr), genericInstr);
}
int nextInstructionIndex();
@@ -224,14 +232,15 @@ namespace QQmlCompilerTypes {
struct JSBindingReference : public QQmlPool::Class,
public BindingReference
{
- JSBindingReference() : nextReference(0) {}
+ JSBindingReference() : disableLookupAcceleration(false), nextReference(0) {}
QQmlScript::Variant expression;
QQmlScript::Property *property;
QQmlScript::Value *value;
int compiledIndex : 16;
- int sharedIndex : 16;
+ int customParserBindingsIndex : 15;
+ int disableLookupAcceleration: 1;
BindingContext bindingContext;
@@ -312,10 +321,9 @@ namespace QQmlCompilerTypes {
QList<CompiledMetaMethod> compiledMetaMethods;
struct PerObjectCompileData
{
- QList<QQmlJS::AST::Node*> functionsToCompile;
+ QList<QtQml::CompiledFunctionOrExpression> functionsToCompile;
QVector<int> runtimeFunctionIndices;
QVector<CompiledMetaMethod> compiledMetaMethods;
- QHash<int, QString> expressionNames;
};
QHash<QQmlScript::Object *, PerObjectCompileData> jsCompileData;
};
@@ -340,7 +348,7 @@ public:
int evaluateEnum(const QHashedStringRef &scope, const QByteArray& enumValue, bool *ok) const; // for QQmlCustomParser::evaluateEnum
const QMetaObject *resolveType(const QString& name) const; // for QQmlCustomParser::resolveType
- int bindingIdentifier(const QQmlScript::Variant& value); // for QQmlCustomParser::bindingIndex
+ int bindingIdentifier(const QString &name, const QQmlScript::Variant& value, const QQmlCompilerTypes::BindingContext &ctxt); // for QQmlCustomParser::bindingIndex
private:
typedef QQmlCompiledData::Instruction Instruction;
diff --git a/src/qml/qml/qqmlcomponent.cpp b/src/qml/qml/qqmlcomponent.cpp
index 2973944215..4a71c1a7e0 100644
--- a/src/qml/qml/qqmlcomponent.cpp
+++ b/src/qml/qml/qqmlcomponent.cpp
@@ -52,7 +52,6 @@
#include "qqmlbinding_p.h"
#include "qqmlglobal_p.h"
#include "qqmlscript_p.h"
-#include <private/qqmlprofilerservice_p.h>
#include <private/qqmlenginedebugservice_p.h>
#include "qqmlincubator.h"
#include "qqmlincubator_p.h"
@@ -884,11 +883,6 @@ QQmlComponentPrivate::beginCreate(QQmlContextData *context)
QQmlEnginePrivate *enginePriv = QQmlEnginePrivate::get(engine);
- if (enginePriv->inProgressCreations == 0) {
- // only track root, since further ones might not be properly nested
- profiler = new QQmlObjectCreatingProfiler();
- }
-
enginePriv->inProgressCreations++;
state.errors.clear();
state.completePending = true;
@@ -924,13 +918,6 @@ QQmlComponentPrivate::beginCreate(QQmlContextData *context)
if (!context->isInternal)
context->asQQmlContextPrivate()->instances.append(rv);
QQmlEngineDebugService::instance()->objectCreated(engine, rv);
-
- if (profiler && profiler->enabled) {
- profiler->setTypeName(buildTypeNameForDebug(rv->metaObject()));
- QQmlData *data = QQmlData::get(rv);
- Q_ASSERT(data);
- profiler->setLocation(cc->url, data->lineNumber, data->columnNumber);
- }
}
return rv;
@@ -995,9 +982,6 @@ void QQmlComponentPrivate::completeCreate()
if (state.completePending) {
QQmlEnginePrivate *ep = QQmlEnginePrivate::get(engine);
complete(ep, &state);
-
- delete profiler;
- profiler = 0;
}
if (depthIncreased) {
@@ -1507,7 +1491,7 @@ QmlIncubatorObject::QmlIncubatorObject(QV8Engine *engine, QQmlIncubator::Incubat
{
incubator.reset(new QQmlComponentIncubator(this, m));
v8 = engine;
- vtbl = &static_vtbl;
+ setVTable(&static_vtbl);
valuemap = QV4::Primitive::undefinedValue();
qmlGlobal = QV4::Primitive::undefinedValue();
@@ -1562,7 +1546,7 @@ void QmlIncubatorObject::statusChanged(QQmlIncubator::Status s)
QV4::ScopedFunctionObject f(scope, m_statusChanged);
if (f) {
- QV4::ExecutionContext *ctx = scope.engine->current;
+ QV4::ExecutionContext *ctx = scope.engine->currentContext();
QV4::ScopedCallData callData(scope, 1);
callData->thisObject = this;
callData->args[0] = QV4::Primitive::fromUInt32(s);
diff --git a/src/qml/qml/qqmlcomponent_p.h b/src/qml/qml/qqmlcomponent_p.h
index d9a2427cd5..8bf4005dd6 100644
--- a/src/qml/qml/qqmlcomponent_p.h
+++ b/src/qml/qml/qqmlcomponent_p.h
@@ -61,7 +61,6 @@
#include "qqmlvme_p.h"
#include "qqmlerror.h"
#include "qqml.h"
-#include <private/qqmlprofilerservice_p.h>
#include <private/qqmlobjectcreator_p.h>
#include <QtCore/QString>
@@ -85,7 +84,7 @@ class Q_QML_PRIVATE_EXPORT QQmlComponentPrivate : public QObjectPrivate, public
public:
QQmlComponentPrivate()
- : typeData(0), progress(0.), start(-1), cc(0), engine(0), creationContext(0), profiler(0), depthIncreased(false) {}
+ : typeData(0), progress(0.), start(-1), cc(0), engine(0), creationContext(0), depthIncreased(false) {}
void loadUrl(const QUrl &newUrl, QQmlComponent::CompilationMode mode = QQmlComponent::PreferSynchronous);
@@ -131,7 +130,6 @@ public:
QQmlEngine *engine;
QQmlGuardedContextData creationContext;
- QQmlObjectCreatingProfiler *profiler;
bool depthIncreased;
void clear();
diff --git a/src/qml/qml/qqmlcontextwrapper.cpp b/src/qml/qml/qqmlcontextwrapper.cpp
index 406826a6f6..b3c2105e68 100644
--- a/src/qml/qml/qqmlcontextwrapper.cpp
+++ b/src/qml/qml/qqmlcontextwrapper.cpp
@@ -53,6 +53,7 @@
#include <private/qv4compileddata_p.h>
#include <private/qqmltypewrapper_p.h>
#include <private/qqmllistwrapper_p.h>
+#include <private/qjsvalue_p.h>
QT_BEGIN_NAMESPACE
@@ -63,9 +64,9 @@ DEFINE_MANAGED_VTABLE(QmlContextWrapper);
QmlContextWrapper::QmlContextWrapper(QV8Engine *engine, QQmlContextData *context, QObject *scopeObject, bool ownsContext)
: Object(QV8Engine::getV4(engine)),
v8(engine), readOnly(true), ownsContext(ownsContext), isNullWrapper(false),
- context(context), scopeObject(scopeObject)
+ context(context), scopeObject(scopeObject), idObjectsWrapper(0)
{
- vtbl = &static_vtbl;
+ setVTable(&static_vtbl);
}
QmlContextWrapper::~QmlContextWrapper()
@@ -136,7 +137,7 @@ ReturnedValue QmlContextWrapper::get(Managed *m, const StringRef name, bool *has
QV4::Scope scope(v4);
QmlContextWrapper *resource = m->as<QmlContextWrapper>();
if (!resource)
- return v4->current->throwTypeError();
+ return v4->currentContext()->throwTypeError();
// In V8 the JS global object would come _before_ the QML global object,
// so simulate that here.
@@ -245,7 +246,7 @@ ReturnedValue QmlContextWrapper::get(Managed *m, const StringRef name, bool *has
// Search scope object
if (scopeObject) {
bool hasProp = false;
- QV4::ScopedValue result(scope, QV4::QObjectWrapper::getQmlProperty(v4->current, context, scopeObject,
+ QV4::ScopedValue result(scope, QV4::QObjectWrapper::getQmlProperty(v4->currentContext(), context, scopeObject,
name.getPointer(), QV4::QObjectWrapper::CheckRevision, &hasProp));
if (hasProp) {
if (hasProperty)
@@ -259,7 +260,7 @@ ReturnedValue QmlContextWrapper::get(Managed *m, const StringRef name, bool *has
// Search context object
if (context->contextObject) {
bool hasProp = false;
- result = QV4::QObjectWrapper::getQmlProperty(v4->current, context, context->contextObject, name.getPointer(), QV4::QObjectWrapper::CheckRevision, &hasProp);
+ result = QV4::QObjectWrapper::getQmlProperty(v4->currentContext(), context, context->contextObject, name.getPointer(), QV4::QObjectWrapper::CheckRevision, &hasProp);
if (hasProp) {
if (hasProperty)
*hasProperty = true;
@@ -283,7 +284,7 @@ void QmlContextWrapper::put(Managed *m, const StringRef name, const ValueRef val
return;
QV4::Scoped<QmlContextWrapper> wrapper(scope, m->as<QmlContextWrapper>());
if (!wrapper) {
- v4->current->throwTypeError();
+ v4->currentContext()->throwTypeError();
return;
}
@@ -291,8 +292,8 @@ void QmlContextWrapper::put(Managed *m, const StringRef name, const ValueRef val
if (wrapper && wrapper->readOnly) {
QString error = QLatin1String("Invalid write to global property \"") + name->toQString() +
QLatin1Char('"');
- Scoped<String> e(scope, v4->current->engine->newString(error));
- v4->current->throwError(e);
+ Scoped<String> e(scope, v4->currentContext()->engine->newString(error));
+ v4->currentContext()->throwError(e);
return;
}
@@ -326,13 +327,13 @@ void QmlContextWrapper::put(Managed *m, const StringRef name, const ValueRef val
// Search scope object
if (scopeObject &&
- QV4::QObjectWrapper::setQmlProperty(v4->current, context, scopeObject, name.getPointer(), QV4::QObjectWrapper::CheckRevision, value))
+ QV4::QObjectWrapper::setQmlProperty(v4->currentContext(), context, scopeObject, name.getPointer(), QV4::QObjectWrapper::CheckRevision, value))
return;
scopeObject = 0;
// Search context object
if (context->contextObject &&
- QV4::QObjectWrapper::setQmlProperty(v4->current, context, context->contextObject, name.getPointer(), QV4::QObjectWrapper::CheckRevision, value))
+ QV4::QObjectWrapper::setQmlProperty(v4->currentContext(), context, context->contextObject, name.getPointer(), QV4::QObjectWrapper::CheckRevision, value))
return;
context = context->parent;
@@ -343,7 +344,7 @@ void QmlContextWrapper::put(Managed *m, const StringRef name, const ValueRef val
if (wrapper->readOnly) {
QString error = QLatin1String("Invalid write to global property \"") + name->toQString() +
QLatin1Char('"');
- v4->current->throwError(error);
+ v4->currentContext()->throwError(error);
return;
}
@@ -355,6 +356,14 @@ void QmlContextWrapper::destroy(Managed *that)
static_cast<QmlContextWrapper *>(that)->~QmlContextWrapper();
}
+void QmlContextWrapper::markObjects(Managed *m, ExecutionEngine *engine)
+{
+ QmlContextWrapper *This = static_cast<QmlContextWrapper*>(m);
+ if (This->idObjectsWrapper)
+ This->idObjectsWrapper->mark(engine);
+ Object::markObjects(m, engine);
+}
+
void QmlContextWrapper::registerQmlDependencies(ExecutionEngine *engine, const CompiledData::Function *compiledFunction)
{
// Let the caller check and avoid the function call :)
@@ -395,4 +404,72 @@ void QmlContextWrapper::registerQmlDependencies(ExecutionEngine *engine, const C
}
+ReturnedValue QmlContextWrapper::idObjectsArray()
+{
+ if (!idObjectsWrapper) {
+ ExecutionEngine *v4 = engine();
+ idObjectsWrapper = new (v4->memoryManager) QQmlIdObjectsArray(v4, this);
+ }
+ return idObjectsWrapper->asReturnedValue();
+}
+
+ReturnedValue QmlContextWrapper::qmlSingletonWrapper(const StringRef &name)
+{
+ if (!context->imports)
+ return Encode::undefined();
+ // Search for attached properties, enums and imported scripts
+ QQmlTypeNameCache::Result r = context->imports->query(name);
+
+ Q_ASSERT(r.isValid());
+ Q_ASSERT(r.type);
+ Q_ASSERT(r.type->isSingleton());
+
+ QQmlEngine *e = v8->engine();
+ QQmlType::SingletonInstanceInfo *siinfo = r.type->singletonInstanceInfo();
+ siinfo->init(e);
+
+ if (QObject *qobjectSingleton = siinfo->qobjectApi(e))
+ return QV4::QObjectWrapper::wrap(engine(), qobjectSingleton);
+ return QJSValuePrivate::get(siinfo->scriptApi(e))->getValue(engine());
+}
+
+DEFINE_MANAGED_VTABLE(QQmlIdObjectsArray);
+
+QQmlIdObjectsArray::QQmlIdObjectsArray(ExecutionEngine *engine, QmlContextWrapper *contextWrapper)
+ : Object(engine)
+ , contextWrapper(contextWrapper)
+{
+ setVTable(&static_vtbl);
+}
+
+ReturnedValue QQmlIdObjectsArray::getIndexed(Managed *m, uint index, bool *hasProperty)
+{
+ QQmlIdObjectsArray *This = static_cast<QQmlIdObjectsArray*>(m);
+ QQmlContextData *context = This->contextWrapper->getContext();
+ if (!context) {
+ if (hasProperty)
+ *hasProperty = false;
+ return Encode::undefined();
+ }
+ if (index >= (uint)context->idValueCount) {
+ if (hasProperty)
+ *hasProperty = false;
+ return Encode::undefined();
+ }
+
+ ExecutionEngine *v4 = m->engine();
+ QQmlEnginePrivate *ep = v4->v8Engine->engine() ? QQmlEnginePrivate::get(v4->v8Engine->engine()) : 0;
+ if (ep)
+ ep->captureProperty(&context->idValues[index].bindings);
+
+ return QObjectWrapper::wrap(This->engine(), context->idValues[index].data());
+}
+
+void QQmlIdObjectsArray::markObjects(Managed *that, ExecutionEngine *engine)
+{
+ QQmlIdObjectsArray *This = static_cast<QQmlIdObjectsArray*>(that);
+ This->contextWrapper->mark(engine);
+ Object::markObjects(that, engine);
+}
+
QT_END_NAMESPACE
diff --git a/src/qml/qml/qqmlcontextwrapper_p.h b/src/qml/qml/qqmlcontextwrapper_p.h
index d85f440b15..89ace7090c 100644
--- a/src/qml/qml/qqmlcontextwrapper_p.h
+++ b/src/qml/qml/qqmlcontextwrapper_p.h
@@ -69,6 +69,8 @@ namespace CompiledData {
struct Function;
}
+struct QQmlIdObjectsArray;
+
struct Q_QML_EXPORT QmlContextWrapper : Object
{
Q_MANAGED
@@ -90,9 +92,12 @@ struct Q_QML_EXPORT QmlContextWrapper : Object
static ReturnedValue get(Managed *m, const StringRef name, bool *hasProperty);
static void put(Managed *m, const StringRef name, const ValueRef value);
static void destroy(Managed *that);
+ static void markObjects(Managed *m, ExecutionEngine *engine);
static void registerQmlDependencies(ExecutionEngine *context, const CompiledData::Function *compiledFunction);
+ ReturnedValue idObjectsArray();
+ ReturnedValue qmlSingletonWrapper(const StringRef &name);
QV8Engine *v8; // ### temporary, remove
bool readOnly;
@@ -101,6 +106,19 @@ struct Q_QML_EXPORT QmlContextWrapper : Object
QQmlGuardedContextData context;
QPointer<QObject> scopeObject;
+private:
+ QQmlIdObjectsArray *idObjectsWrapper;
+};
+
+struct QQmlIdObjectsArray : public Object
+{
+ Q_MANAGED
+ QQmlIdObjectsArray(ExecutionEngine *engine, QmlContextWrapper *contextWrapper);
+
+ static ReturnedValue getIndexed(Managed *m, uint index, bool *hasProperty);
+ static void markObjects(Managed *that, ExecutionEngine *engine);
+
+ QmlContextWrapper *contextWrapper;
};
}
diff --git a/src/qml/qml/qqmlcustomparser.cpp b/src/qml/qml/qqmlcustomparser.cpp
index eba2e14e51..19e49009ce 100644
--- a/src/qml/qml/qqmlcustomparser.cpp
+++ b/src/qml/qml/qqmlcustomparser.cpp
@@ -313,8 +313,7 @@ const QMetaObject *QQmlCustomParser::resolveType(const QString& name) const
*/
QQmlBinding::Identifier QQmlCustomParser::bindingIdentifier(const QQmlScript::Variant &value, const QString& name)
{
- Q_UNUSED(name);
- return compiler->bindingIdentifier(value);
+ return compiler->bindingIdentifier(name, value, QQmlCompilerTypes::BindingContext(object));
}
QT_END_NAMESPACE
diff --git a/src/qml/qml/qqmldata_p.h b/src/qml/qml/qqmldata_p.h
index 621b3d3c2e..982156ea15 100644
--- a/src/qml/qml/qqmldata_p.h
+++ b/src/qml/qml/qqmldata_p.h
@@ -61,6 +61,7 @@
QT_BEGIN_NAMESPACE
template <class Key, class T> class QHash;
+class QQmlEngine;
class QQmlGuardImpl;
class QQmlCompiledData;
class QQmlAbstractBinding;
@@ -222,6 +223,8 @@ public:
static inline void flushPendingBinding(QObject *, int coreIndex);
+ static void ensurePropertyCache(QQmlEngine *engine, QObject *object);
+
private:
// For attachedProperties
mutable QQmlDataExtended *extendedData;
diff --git a/src/qml/qml/qqmlengine.cpp b/src/qml/qml/qqmlengine.cpp
index 1320f51d25..f8e5ad5874 100644
--- a/src/qml/qml/qqmlengine.cpp
+++ b/src/qml/qml/qqmlengine.cpp
@@ -101,6 +101,9 @@
#ifdef Q_OS_WIN // for %APPDATA%
#include <qt_windows.h>
+# if !defined(Q_OS_WINCE) && !defined(Q_OS_WINRT)
+# include <shlobj.h>
+# endif
#include <qlibrary.h>
#include <windows.h>
@@ -556,7 +559,7 @@ QQmlEnginePrivate::QQmlEnginePrivate(QQmlEngine *e)
workerScriptEngine(0), activeVME(0),
activeObjectCreator(0),
networkAccessManager(0), networkAccessManagerFactory(0), urlInterceptor(0),
- scarceResourcesRefCount(0), typeLoader(e), importDatabase(e), uniqueId(1),
+ scarceResourcesRefCount(0), importDatabase(e), typeLoader(e), uniqueId(1),
incubatorCount(0), incubationController(0), mutex(QMutex::Recursive)
{
useNewCompiler = qmlUseNewCompiler();
@@ -1339,14 +1342,6 @@ void qmlExecuteDeferred(QObject *object)
QQmlData *data = QQmlData::get(object);
if (data && data->deferredData && !data->wasDeleted(object)) {
- QQmlObjectCreatingProfiler prof;
- if (prof.enabled) {
- QQmlType *type = QQmlMetaType::qmlType(object->metaObject());
- prof.setTypeName(type ? type->qmlTypeName()
- : QString::fromUtf8(object->metaObject()->className()));
- if (data->outerContext)
- prof.setLocation(data->outerContext->url, data->lineNumber, data->columnNumber);
- }
QQmlEnginePrivate *ep = QQmlEnginePrivate::get(data->context->engine);
QQmlComponentPrivate::ConstructionState state;
@@ -1734,6 +1729,16 @@ void QQmlData::setPendingBindingBit(QObject *obj, int coreIndex)
QQmlData_setBit(this, obj, coreIndex * 2 + 1);
}
+void QQmlData::ensurePropertyCache(QQmlEngine *engine, QObject *object)
+{
+ Q_ASSERT(engine);
+ QQmlData *ddata = QQmlData::get(object, /*create*/true);
+ if (ddata->propertyCache)
+ return;
+ ddata->propertyCache = QQmlEnginePrivate::get(engine)->cache(object);
+ if (ddata->propertyCache) ddata->propertyCache->addref();
+}
+
void QQmlEnginePrivate::sendQuit()
{
Q_Q(QQmlEngine);
@@ -2283,6 +2288,28 @@ bool QQmlEnginePrivate::isScriptLoaded(const QUrl &url) const
return typeLoader.isScriptLoaded(url);
}
+#if defined(Q_OS_WIN) && !defined(Q_OS_WINCE) && !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).
+static inline QString shellNormalizeFileName(const QString &name)
+{
+ const QString nativeSeparatorName(QDir::toNativeSeparators(name));
+ const LPCTSTR nameC = reinterpret_cast<LPCTSTR>(nativeSeparatorName.utf16());
+ PIDLIST_ABSOLUTE file;
+ if (FAILED(SHParseDisplayName(nameC, NULL, &file, 0, NULL)))
+ return name;
+ TCHAR buffer[MAX_PATH];
+ if (!SHGetPathFromIDList(file, buffer))
+ return name;
+ QString canonicalName = QString::fromWCharArray(buffer);
+ // Upper case drive letter
+ if (canonicalName.size() > 2 && canonicalName.at(1) == QLatin1Char(':'))
+ canonicalName[0] = canonicalName.at(0).toUpper();
+ return QDir::cleanPath(canonicalName);
+}
+#endif // Q_OS_WIN && !Q_OS_WINCE && !Q_OS_WINRT
+
bool QQml_isFileCaseCorrect(const QString &fileName, int lengthIn /* = -1 */)
{
#if defined(Q_OS_MAC) || defined(Q_OS_WIN)
@@ -2292,14 +2319,7 @@ bool QQml_isFileCaseCorrect(const QString &fileName, int lengthIn /* = -1 */)
#if defined(Q_OS_MAC) || defined(Q_OS_WINCE) || defined(Q_OS_WINRT)
const QString canonical = info.canonicalFilePath();
#elif defined(Q_OS_WIN)
- wchar_t buffer[1024];
-
- DWORD rv = ::GetShortPathName((wchar_t*)absolute.utf16(), buffer, 1024);
- if (rv == 0 || rv >= 1024) return true;
- rv = ::GetLongPathName(buffer, buffer, 1024);
- if (rv == 0 || rv >= 1024) return true;
-
- const QString canonical = QString::fromWCharArray(buffer);
+ const QString canonical = shellNormalizeFileName(absolute);
#endif
const int absoluteLength = absolute.length();
diff --git a/src/qml/qml/qqmlengine_p.h b/src/qml/qml/qqmlengine_p.h
index 5a2d6c4e00..19eb320fbe 100644
--- a/src/qml/qml/qqmlengine_p.h
+++ b/src/qml/qml/qqmlengine_p.h
@@ -186,8 +186,8 @@ public:
void referenceScarceResources();
void dereferenceScarceResources();
- QQmlTypeLoader typeLoader;
QQmlImportDatabase importDatabase;
+ QQmlTypeLoader typeLoader;
QString offlineStoragePath;
@@ -257,6 +257,7 @@ public:
inline static QQmlEnginePrivate *get(QQmlContext *c);
inline static QQmlEnginePrivate *get(QQmlContextData *c);
inline static QQmlEngine *get(QQmlEnginePrivate *p);
+ inline static QQmlEnginePrivate *get(QV4::ExecutionEngine *e);
static void registerBaseTypes(const char *uri, int versionMajor, int versionMinor);
static void registerQtQuick2Types(const char *uri, int versionMajor, int versionMinor);
@@ -516,7 +517,17 @@ QQmlEngine *QQmlEnginePrivate::get(QQmlEnginePrivate *p)
{
Q_ASSERT(p);
- return p->q_func();
+ return p->q_func();
+}
+
+QQmlEnginePrivate *QQmlEnginePrivate::get(QV4::ExecutionEngine *e)
+{
+ if (!e->v8Engine)
+ return 0;
+ QQmlEngine *qmlEngine = e->v8Engine->engine();
+ if (!qmlEngine)
+ return 0;
+ return get(qmlEngine);
}
void QQmlEnginePrivate::captureProperty(QQmlNotifier *n)
diff --git a/src/qml/qml/qqmlinstruction_p.h b/src/qml/qml/qqmlinstruction_p.h
index 150ee8df19..bda8c3db0d 100644
--- a/src/qml/qml/qqmlinstruction_p.h
+++ b/src/qml/qml/qqmlinstruction_p.h
@@ -536,7 +536,11 @@ struct QQmlInstructionMeta {
typedef QQmlInstruction::instr_##FMT DataType; \
static const DataType &data(const QQmlInstruction &instr) { return instr.FMT; } \
static void setData(QQmlInstruction &instr, const DataType &v) { memcpy(&instr.FMT, &v, Size); } \
- };
+ static void setDataNoCommon(QQmlInstruction &instr, const DataType &v) \
+ { memcpy(reinterpret_cast<char *>(&instr.FMT) + sizeof(QQmlInstruction::instr_common), \
+ reinterpret_cast<const char *>(&v) + sizeof(QQmlInstruction::instr_common), \
+ Size - sizeof(QQmlInstruction::instr_common)); } \
+ };
FOR_EACH_QML_INSTR(QML_INSTR_META_TEMPLATE);
#undef QML_INSTR_META_TEMPLATE
diff --git a/src/qml/qml/qqmljavascriptexpression.cpp b/src/qml/qml/qqmljavascriptexpression.cpp
index 3fd0003656..499ade1ca5 100644
--- a/src/qml/qml/qqmljavascriptexpression.cpp
+++ b/src/qml/qml/qqmljavascriptexpression.cpp
@@ -155,7 +155,7 @@ QV4::ReturnedValue QQmlJavaScriptExpression::evaluate(QQmlContextData *context,
QV4::ExecutionEngine *v4 = QV8Engine::getV4(ep->v8engine());
QV4::Scope scope(v4);
QV4::ScopedValue result(scope, QV4::Primitive::undefinedValue());
- QV4::ExecutionContext *ctx = v4->current;
+ QV4::ExecutionContext *ctx = v4->currentContext();
callData->thisObject = v4->globalObject;
if (scopeObject()) {
QV4::ScopedValue value(scope, QV4::QObjectWrapper::wrap(ctx->engine, scopeObject()));
@@ -294,7 +294,7 @@ QQmlJavaScriptExpression::evalFunction(QQmlContextData *ctxt, QObject *scopeObje
QQmlEnginePrivate *ep = QQmlEnginePrivate::get(engine);
QV4::ExecutionEngine *v4 = QV8Engine::getV4(ep->v8engine());
- QV4::ExecutionContext *ctx = v4->current;
+ QV4::ExecutionContext *ctx = v4->currentContext();
QV4::Scope scope(v4);
QV4::ScopedObject qmlScopeObject(scope, QV4::QmlContextWrapper::qmlScope(ep->v8engine(), ctxt, scopeObject));
@@ -328,7 +328,7 @@ QV4::ReturnedValue QQmlJavaScriptExpression::qmlBinding(QQmlContextData *ctxt, Q
QQmlEnginePrivate *ep = QQmlEnginePrivate::get(engine);
QV4::ExecutionEngine *v4 = QV8Engine::getV4(ep->v8engine());
- QV4::ExecutionContext *ctx = v4->current;
+ QV4::ExecutionContext *ctx = v4->currentContext();
QV4::Scope scope(v4);
QV4::ScopedObject qmlScopeObject(scope, QV4::QmlContextWrapper::qmlScope(ep->v8engine(), ctxt, qmlScope));
diff --git a/src/qml/qml/qqmllistwrapper.cpp b/src/qml/qml/qqmllistwrapper.cpp
index 73dc3192aa..7b975c2cc8 100644
--- a/src/qml/qml/qqmllistwrapper.cpp
+++ b/src/qml/qml/qqmllistwrapper.cpp
@@ -56,7 +56,7 @@ QmlListWrapper::QmlListWrapper(QV8Engine *engine)
: Object(QV8Engine::getV4(engine)),
v8(engine)
{
- vtbl = &static_vtbl;
+ setVTable(&static_vtbl);
flags &= ~SimpleArray;
}
@@ -106,7 +106,7 @@ ReturnedValue QmlListWrapper::get(Managed *m, const StringRef name, bool *hasPro
QV4::ExecutionEngine *v4 = m->engine();
QmlListWrapper *w = m->as<QmlListWrapper>();
if (!w)
- return v4->current->throwTypeError();
+ return v4->currentContext()->throwTypeError();
if (name->equals(v4->id_length) && !w->object.isNull()) {
quint32 count = w->property.count ? w->property.count(&w->property) : 0;
@@ -127,7 +127,7 @@ ReturnedValue QmlListWrapper::getIndexed(Managed *m, uint index, bool *hasProper
QV4::ExecutionEngine *e = m->engine();
QmlListWrapper *w = m->as<QmlListWrapper>();
if (!w)
- return e->current->throwTypeError();
+ return e->currentContext()->throwTypeError();
quint32 count = w->property.count ? w->property.count(&w->property) : 0;
if (index < count && w->property.at)
diff --git a/src/qml/qml/qqmllocale.cpp b/src/qml/qml/qqmllocale.cpp
index 5e8130f407..36e0da5b60 100644
--- a/src/qml/qml/qqmllocale.cpp
+++ b/src/qml/qml/qqmllocale.cpp
@@ -61,7 +61,7 @@ public:
QQmlLocaleData(QV4::ExecutionEngine *engine)
: QV4::Object(engine)
{
- vtbl = &static_vtbl;
+ setVTable(&static_vtbl);
type = Type_Object;
}
@@ -872,7 +872,7 @@ QV4::ReturnedValue QQmlLocale::locale(QV8Engine *v8engine, const QString &locale
void QQmlLocale::registerStringLocaleCompare(QV4::ExecutionEngine *engine)
{
- engine->stringClass->prototype->defineDefaultProperty(QStringLiteral("localeCompare"), method_localeCompare);
+ engine->stringObjectClass->prototype->defineDefaultProperty(QStringLiteral("localeCompare"), method_localeCompare);
}
QV4::ReturnedValue QQmlLocale::method_localeCompare(QV4::CallContext *ctx)
diff --git a/src/qml/qml/qqmlmemoryprofiler.cpp b/src/qml/qml/qqmlmemoryprofiler.cpp
index e7b6653532..d93276fc17 100644
--- a/src/qml/qml/qqmlmemoryprofiler.cpp
+++ b/src/qml/qml/qqmlmemoryprofiler.cpp
@@ -100,8 +100,7 @@ static bool openLibrary()
QQmlMemoryScope::QQmlMemoryScope(const QUrl &url) : pushed(false)
{
if (openLibrary() && memprofile_is_enabled()) {
- const char *location = url.path().toUtf8().constData();
- memprofile_push_location(location, 0);
+ memprofile_push_location(url.path().toUtf8().constData(), 0);
pushed = true;
}
}
diff --git a/src/qml/qml/qqmlmetatype.cpp b/src/qml/qml/qqmlmetatype.cpp
index 342d1dc69c..ed0c0afd6f 100644
--- a/src/qml/qml/qqmlmetatype.cpp
+++ b/src/qml/qml/qqmlmetatype.cpp
@@ -225,17 +225,21 @@ public:
void QQmlType::SingletonInstanceInfo::init(QQmlEngine *e)
{
QV4::ExecutionEngine *v4 = QV8Engine::getV4(e->handle());
- v4->pushGlobalContext();
if (scriptCallback && scriptApi(e).isUndefined()) {
+ v4->pushGlobalContext();
setScriptApi(e, scriptCallback(e, e));
+ v4->popContext();
} else if (qobjectCallback && !qobjectApi(e)) {
+ v4->pushGlobalContext();
setQObjectApi(e, qobjectCallback(e, e));
+ v4->popContext();
} else if (!url.isEmpty() && !qobjectApi(e)) {
+ v4->pushGlobalContext();
QQmlComponent component(e, url, QQmlComponent::PreferSynchronous);
QObject *o = component.create();
setQObjectApi(e, o);
+ v4->popContext();
}
- v4->popContext();
}
void QQmlType::SingletonInstanceInfo::destroy(QQmlEngine *e)
diff --git a/src/qml/qml/qqmltypeloader.cpp b/src/qml/qml/qqmltypeloader.cpp
index 85d2fe41d9..6eda55e35b 100644
--- a/src/qml/qml/qqmltypeloader.cpp
+++ b/src/qml/qml/qqmltypeloader.cpp
@@ -2371,13 +2371,12 @@ void QQmlTypeData::compile()
// Compile JS binding expressions and signal handlers
- JSCodeGen jsCodeGen(enginePrivate, finalUrlString(), parsedQML->code, &parsedQML->jsModule, &parsedQML->jsParserEngine, parsedQML->program, m_compiledData->importCache);
- QHash<int, QString> expressionNames; // ### TODO
- const QVector<int> runtimeFunctionIndices = jsCodeGen.generateJSCodeForFunctionsAndBindings(parsedQML->functions, expressionNames);
+ JSCodeGen jsCodeGen(finalUrlString(), parsedQML->code, &parsedQML->jsModule, &parsedQML->jsParserEngine, parsedQML->program, m_compiledData->importCache);
+ const QVector<int> runtimeFunctionIndices = jsCodeGen.generateJSCodeForFunctionsAndBindings(parsedQML->functions);
QV4::ExecutionEngine *v4 = QV8Engine::getV4(m_typeLoader->engine());
- QScopedPointer<QQmlJS::EvalInstructionSelection> isel(v4->iselFactory->create(v4->executableAllocator, &parsedQML->jsModule, &parsedQML->jsGenerator));
+ QScopedPointer<QQmlJS::EvalInstructionSelection> isel(v4->iselFactory->create(enginePrivate, v4->executableAllocator, &parsedQML->jsModule, &parsedQML->jsGenerator));
isel->setUseFastLookups(false);
QV4::CompiledData::CompilationUnit *jsUnit = isel->compile(/*generated unit data*/false);
@@ -2806,7 +2805,7 @@ QV4::PersistentValue QQmlScriptData::scriptValueForContext(QQmlContextData *pare
QV4::ScopedValue qmlglobal(scope, QV4::QmlContextWrapper::qmlScope(v8engine, ctxt, 0));
QV4::QmlContextWrapper::takeContextOwnership(qmlglobal);
- QV4::ExecutionContext *ctx = QV8Engine::getV4(v8engine)->current;
+ QV4::ExecutionContext *ctx = QV8Engine::getV4(v8engine)->currentContext();
m_program->qml = qmlglobal;
m_program->run();
if (scope.engine->hasException) {
diff --git a/src/qml/qml/qqmltypewrapper.cpp b/src/qml/qml/qqmltypewrapper.cpp
index 258442bc1d..9c350a54a5 100644
--- a/src/qml/qml/qqmltypewrapper.cpp
+++ b/src/qml/qml/qqmltypewrapper.cpp
@@ -60,7 +60,7 @@ QmlTypeWrapper::QmlTypeWrapper(QV8Engine *engine)
: Object(QV8Engine::getV4(engine)),
v8(engine), mode(IncludeEnums), type(0), typeNamespace(0), importNamespace(0)
{
- vtbl = &static_vtbl;
+ setVTable(&static_vtbl);
}
QmlTypeWrapper::~QmlTypeWrapper()
@@ -126,7 +126,7 @@ ReturnedValue QmlTypeWrapper::get(Managed *m, const StringRef name, bool *hasPro
Scoped<QmlTypeWrapper> w(scope, m->as<QmlTypeWrapper>());
if (!w)
- return v4->current->throwTypeError();
+ return v4->currentContext()->throwTypeError();
if (hasProperty)
@@ -165,7 +165,7 @@ ReturnedValue QmlTypeWrapper::get(Managed *m, const StringRef name, bool *hasPro
}
// check for property.
- return QV4::QObjectWrapper::getQmlProperty(v4->current, context, qobjectSingleton, name.getPointer(), QV4::QObjectWrapper::IgnoreRevision, hasProperty);
+ return QV4::QObjectWrapper::getQmlProperty(v4->currentContext(), context, qobjectSingleton, name.getPointer(), QV4::QObjectWrapper::IgnoreRevision, hasProperty);
} else if (!siinfo->scriptApi(e).isUndefined()) {
// NOTE: if used in a binding, changes will not trigger re-evaluation since non-NOTIFYable.
QV4::ScopedObject o(scope, QJSValuePrivate::get(siinfo->scriptApi(e))->getValue(v4));
@@ -188,7 +188,7 @@ ReturnedValue QmlTypeWrapper::get(Managed *m, const StringRef name, bool *hasPro
} else if (w->object) {
QObject *ao = qmlAttachedPropertiesObjectById(type->attachedPropertiesId(), object);
if (ao)
- return QV4::QObjectWrapper::getQmlProperty(v4->current, context, ao, name.getPointer(), QV4::QObjectWrapper::IgnoreRevision, hasProperty);
+ return QV4::QObjectWrapper::getQmlProperty(v4->currentContext(), context, ao, name.getPointer(), QV4::QObjectWrapper::IgnoreRevision, hasProperty);
// Fall through to base implementation
}
@@ -236,7 +236,7 @@ void QmlTypeWrapper::put(Managed *m, const StringRef name, const ValueRef value)
if (v4->hasException)
return;
if (!w) {
- v4->current->throwTypeError();
+ v4->currentContext()->throwTypeError();
return;
}
@@ -249,7 +249,7 @@ void QmlTypeWrapper::put(Managed *m, const StringRef name, const ValueRef value)
QObject *object = w->object;
QObject *ao = qmlAttachedPropertiesObjectById(type->attachedPropertiesId(), object);
if (ao)
- QV4::QObjectWrapper::setQmlProperty(v4->current, context, ao, name.getPointer(), QV4::QObjectWrapper::IgnoreRevision, value);
+ QV4::QObjectWrapper::setQmlProperty(v4->currentContext(), context, ao, name.getPointer(), QV4::QObjectWrapper::IgnoreRevision, value);
} else if (type && type->isSingleton()) {
QQmlEngine *e = v8engine->engine();
QQmlType::SingletonInstanceInfo *siinfo = type->singletonInstanceInfo();
@@ -257,12 +257,12 @@ void QmlTypeWrapper::put(Managed *m, const StringRef name, const ValueRef value)
QObject *qobjectSingleton = siinfo->qobjectApi(e);
if (qobjectSingleton) {
- QV4::QObjectWrapper::setQmlProperty(v4->current, context, qobjectSingleton, name.getPointer(), QV4::QObjectWrapper::IgnoreRevision, value);
+ QV4::QObjectWrapper::setQmlProperty(v4->currentContext(), context, qobjectSingleton, name.getPointer(), QV4::QObjectWrapper::IgnoreRevision, value);
} else if (!siinfo->scriptApi(e).isUndefined()) {
QV4::ScopedObject apiprivate(scope, QJSValuePrivate::get(siinfo->scriptApi(e))->value);
if (!apiprivate) {
QString error = QLatin1String("Cannot assign to read-only property \"") + name->toQString() + QLatin1Char('\"');
- v4->current->throwError(error);
+ v4->currentContext()->throwError(error);
return;
} else {
apiprivate->put(name, value);
diff --git a/src/qml/qml/qqmlvaluetype_p.h b/src/qml/qml/qqmlvaluetype_p.h
index c55b86b55a..bd44dfb0cf 100644
--- a/src/qml/qml/qqmlvaluetype_p.h
+++ b/src/qml/qml/qqmlvaluetype_p.h
@@ -169,8 +169,8 @@ public:
class Q_QML_PRIVATE_EXPORT QQmlPointFValueType : public QQmlValueTypeBase<QPointF>
{
- Q_PROPERTY(qreal x READ x WRITE setX)
- Q_PROPERTY(qreal y READ y WRITE setY)
+ Q_PROPERTY(qreal x READ x WRITE setX FINAL)
+ Q_PROPERTY(qreal y READ y WRITE setY FINAL)
Q_OBJECT
public:
QQmlPointFValueType(QObject *parent = 0);
@@ -185,8 +185,8 @@ public:
class Q_QML_PRIVATE_EXPORT QQmlPointValueType : public QQmlValueTypeBase<QPoint>
{
- Q_PROPERTY(int x READ x WRITE setX)
- Q_PROPERTY(int y READ y WRITE setY)
+ Q_PROPERTY(int x READ x WRITE setX FINAL)
+ Q_PROPERTY(int y READ y WRITE setY FINAL)
Q_OBJECT
public:
QQmlPointValueType(QObject *parent = 0);
@@ -201,8 +201,8 @@ public:
class Q_QML_PRIVATE_EXPORT QQmlSizeFValueType : public QQmlValueTypeBase<QSizeF>
{
- Q_PROPERTY(qreal width READ width WRITE setWidth)
- Q_PROPERTY(qreal height READ height WRITE setHeight)
+ Q_PROPERTY(qreal width READ width WRITE setWidth FINAL)
+ Q_PROPERTY(qreal height READ height WRITE setHeight FINAL)
Q_OBJECT
public:
QQmlSizeFValueType(QObject *parent = 0);
@@ -217,8 +217,8 @@ public:
class Q_QML_PRIVATE_EXPORT QQmlSizeValueType : public QQmlValueTypeBase<QSize>
{
- Q_PROPERTY(int width READ width WRITE setWidth)
- Q_PROPERTY(int height READ height WRITE setHeight)
+ Q_PROPERTY(int width READ width WRITE setWidth FINAL)
+ Q_PROPERTY(int height READ height WRITE setHeight FINAL)
Q_OBJECT
public:
QQmlSizeValueType(QObject *parent = 0);
@@ -233,10 +233,10 @@ public:
class Q_QML_PRIVATE_EXPORT QQmlRectFValueType : public QQmlValueTypeBase<QRectF>
{
- Q_PROPERTY(qreal x READ x WRITE setX)
- Q_PROPERTY(qreal y READ y WRITE setY)
- Q_PROPERTY(qreal width READ width WRITE setWidth)
- Q_PROPERTY(qreal height READ height WRITE setHeight)
+ Q_PROPERTY(qreal x READ x WRITE setX FINAL)
+ Q_PROPERTY(qreal y READ y WRITE setY FINAL)
+ Q_PROPERTY(qreal width READ width WRITE setWidth FINAL)
+ Q_PROPERTY(qreal height READ height WRITE setHeight FINAL)
Q_OBJECT
public:
QQmlRectFValueType(QObject *parent = 0);
@@ -256,10 +256,10 @@ public:
class Q_QML_PRIVATE_EXPORT QQmlRectValueType : public QQmlValueTypeBase<QRect>
{
- Q_PROPERTY(int x READ x WRITE setX)
- Q_PROPERTY(int y READ y WRITE setY)
- Q_PROPERTY(int width READ width WRITE setWidth)
- Q_PROPERTY(int height READ height WRITE setHeight)
+ Q_PROPERTY(int x READ x WRITE setX FINAL)
+ Q_PROPERTY(int y READ y WRITE setY FINAL)
+ Q_PROPERTY(int width READ width WRITE setWidth FINAL)
+ Q_PROPERTY(int height READ height WRITE setHeight FINAL)
Q_OBJECT
public:
QQmlRectValueType(QObject *parent = 0);
@@ -282,11 +282,11 @@ class Q_QML_PRIVATE_EXPORT QQmlEasingValueType : public QQmlValueTypeBase<QEasin
Q_OBJECT
Q_ENUMS(Type)
- Q_PROPERTY(QQmlEasingValueType::Type type READ type WRITE setType)
- Q_PROPERTY(qreal amplitude READ amplitude WRITE setAmplitude)
- Q_PROPERTY(qreal overshoot READ overshoot WRITE setOvershoot)
- Q_PROPERTY(qreal period READ period WRITE setPeriod)
- Q_PROPERTY(QVariantList bezierCurve READ bezierCurve WRITE setBezierCurve)
+ Q_PROPERTY(QQmlEasingValueType::Type type READ type WRITE setType FINAL)
+ Q_PROPERTY(qreal amplitude READ amplitude WRITE setAmplitude FINAL)
+ Q_PROPERTY(qreal overshoot READ overshoot WRITE setOvershoot FINAL)
+ Q_PROPERTY(qreal period READ period WRITE setPeriod FINAL)
+ Q_PROPERTY(QVariantList bezierCurve READ bezierCurve WRITE setBezierCurve FINAL)
public:
enum Type {
Linear = QEasingCurve::Linear,
diff --git a/src/qml/qml/qqmlvaluetypewrapper.cpp b/src/qml/qml/qqmlvaluetypewrapper.cpp
index d733694923..50d7cbcc5e 100644
--- a/src/qml/qml/qqmlvaluetypewrapper.cpp
+++ b/src/qml/qml/qqmlvaluetypewrapper.cpp
@@ -79,7 +79,7 @@ QmlValueTypeWrapper::QmlValueTypeWrapper(QV8Engine *engine, ObjectType objectTyp
: Object(QV8Engine::getV4(engine)), objectType(objectType)
{
v8 = engine;
- vtbl = &static_vtbl;
+ setVTable(&static_vtbl);
}
QmlValueTypeWrapper::~QmlValueTypeWrapper()
@@ -209,7 +209,7 @@ PropertyAttributes QmlValueTypeWrapper::query(const Managed *m, StringRef name)
const QmlValueTypeWrapper *r = m->as<const QmlValueTypeWrapper>();
QV4::ExecutionEngine *v4 = m->engine();
if (!r) {
- v4->current->throwTypeError();
+ v4->currentContext()->throwTypeError();
return PropertyAttributes();
}
@@ -273,7 +273,7 @@ ReturnedValue QmlValueTypeWrapper::get(Managed *m, const StringRef name, bool *h
QmlValueTypeWrapper *r = m->as<QmlValueTypeWrapper>();
QV4::ExecutionEngine *v4 = m->engine();
if (!r)
- return v4->current->throwTypeError();
+ return v4->currentContext()->throwTypeError();
// Note: readReferenceValue() can change the reference->type.
if (r->objectType == QmlValueTypeWrapper::Reference) {
@@ -306,7 +306,7 @@ ReturnedValue QmlValueTypeWrapper::get(Managed *m, const StringRef name, bool *h
if (result->isFunction()) {
// calling a Q_INVOKABLE function of a value type
QQmlContextData *qmlContext = QV4::QmlContextWrapper::callingContext(v4);
- return QV4::QObjectWrapper::getQmlProperty(v4->current, qmlContext, r->type, name.getPointer(), QV4::QObjectWrapper::IgnoreRevision);
+ return QV4::QObjectWrapper::getQmlProperty(v4->currentContext(), qmlContext, r->type, name.getPointer(), QV4::QObjectWrapper::IgnoreRevision);
}
#define VALUE_TYPE_LOAD(metatype, cpptype, constructor) \
@@ -339,7 +339,7 @@ void QmlValueTypeWrapper::put(Managed *m, const StringRef name, const ValueRef v
Scoped<QmlValueTypeWrapper> r(scope, m->as<QmlValueTypeWrapper>());
if (!r) {
- v4->current->throwTypeError();
+ v4->currentContext()->throwTypeError();
return;
}
@@ -365,7 +365,7 @@ void QmlValueTypeWrapper::put(Managed *m, const StringRef name, const ValueRef v
// assigning a JS function to a non-var-property is not allowed.
QString error = QLatin1String("Cannot assign JavaScript function to value-type property");
Scoped<String> e(scope, r->v8->toString(error));
- v4->current->throwError(e);
+ v4->currentContext()->throwError(e);
return;
}
diff --git a/src/qml/qml/qqmlvme.cpp b/src/qml/qml/qqmlvme.cpp
index 983136a846..ad1e9d862e 100644
--- a/src/qml/qml/qqmlvme.cpp
+++ b/src/qml/qml/qqmlvme.cpp
@@ -503,6 +503,12 @@ QObject *QQmlVME::run(QList<QQmlError> *errors,
const QQmlCompiledData::TypeReference &type = TYPES.at(instr.type);
Q_ASSERT(type.component);
+ if (profiler.enabled) {
+ profiler.start();
+ profiler.updateTypeName(type.component->name);
+ profiler.background();
+ }
+
states.push(State());
State *cState = &states[states.count() - 2];
@@ -524,6 +530,11 @@ QObject *QQmlVME::run(QList<QQmlError> *errors,
QML_END_INSTR(CreateQMLObject)
QML_BEGIN_INSTR(CompleteQMLObject)
+ if (profiler.enabled) {
+ profiler.foreground();
+ profiler.updateLocation(CTXT->url, instr.line, instr.column);
+ }
+
QObject *o = objects.top();
Q_ASSERT(o);
@@ -566,6 +577,8 @@ QObject *QQmlVME::run(QList<QQmlError> *errors,
QML_BEGIN_INSTR(CreateCppObject)
const QQmlCompiledData::TypeReference &type = TYPES.at(instr.type);
Q_ASSERT(type.type);
+ if (profiler.enabled)
+ profiler.start(CTXT->url, instr.line, instr.column, type.type->qmlTypeName());
QObject *o = 0;
void *memory = 0;
@@ -637,12 +650,14 @@ QObject *QQmlVME::run(QList<QQmlError> *errors,
QML_END_INSTR(CreateCppObject)
QML_BEGIN_INSTR(CreateSimpleObject)
+ const QQmlCompiledData::TypeReference &ref = TYPES.at(instr.type);
+ if (profiler.enabled)
+ profiler.start(CTXT->url, instr.line, instr.column, ref.type->qmlTypeName());
QObject *o = (QObject *)operator new(instr.typeSize + sizeof(QQmlData));
::memset(static_cast<void *>(o), 0, instr.typeSize + sizeof(QQmlData));
instr.create(o);
QQmlData *ddata = (QQmlData *)(((const char *)o) + instr.typeSize);
- const QQmlCompiledData::TypeReference &ref = TYPES.at(instr.type);
if (!ddata->propertyCache && ref.typePropertyCache) {
ddata->propertyCache = ref.typePropertyCache;
ddata->propertyCache->addref();
@@ -817,6 +832,8 @@ QObject *QQmlVME::run(QList<QQmlError> *errors,
QML_END_INSTR(StoreScriptString)
QML_BEGIN_INSTR(BeginObject)
+ if (profiler.enabled)
+ profiler.push();
QObject *target = objects.top();
QQmlParserStatus *status = reinterpret_cast<QQmlParserStatus *>(reinterpret_cast<char *>(target) + instr.castValue);
parserStatus.push(status);
@@ -1074,6 +1091,8 @@ normalExit:
objects.deallocate();
lists.deallocate();
states.clear();
+ if (profiler.enabled)
+ profiler.stop();
return rv;
}
@@ -1111,6 +1130,8 @@ void QQmlVME::reset()
states.clear();
rootContext = 0;
creationContext = 0;
+ if (profiler.enabled)
+ profiler.clear();
}
#ifdef QML_THREADED_VME_INTERPRETER
@@ -1170,6 +1191,8 @@ QQmlContextData *QQmlVME::complete(const Interrupt &interrupt)
if (componentCompleteEnabled()) { // the qml designer does the component complete later
QQmlTrace trace("VME Component Complete");
while (!parserStatus.isEmpty()) {
+ if (profiler.enabled)
+ profiler.pop();
QQmlParserStatus *status = parserStatus.pop();
#ifdef QML_ENABLE_TRACE
QQmlData *data = parserStatusData.pop();
@@ -1189,6 +1212,8 @@ QQmlContextData *QQmlVME::complete(const Interrupt &interrupt)
return 0;
}
parserStatus.deallocate();
+ if (profiler.enabled)
+ profiler.clear();
}
{
diff --git a/src/qml/qml/qqmlvme_p.h b/src/qml/qml/qqmlvme_p.h
index e76b485a5c..d5afd4c67a 100644
--- a/src/qml/qml/qqmlvme_p.h
+++ b/src/qml/qml/qqmlvme_p.h
@@ -68,6 +68,7 @@
#include <private/qfinitestack_p.h>
#include <private/qqmltrace_p.h>
+#include <private/qqmlprofilerservice_p.h>
QT_BEGIN_NAMESPACE
@@ -171,6 +172,7 @@ private:
#ifdef QML_ENABLE_TRACE
QFiniteStack<QQmlData *> parserStatusData;
#endif
+ QQmlVmeProfiler profiler;
QQmlGuardedContextData rootContext;
QQmlGuardedContextData creationContext;
diff --git a/src/qml/qml/qqmlvmemetaobject.cpp b/src/qml/qml/qqmlvmemetaobject.cpp
index 4b34792421..ebe72b2ff6 100644
--- a/src/qml/qml/qqmlvmemetaobject.cpp
+++ b/src/qml/qml/qqmlvmemetaobject.cpp
@@ -956,7 +956,7 @@ int QQmlVMEMetaObject::metaCall(QMetaObject::Call c, int _id, void **a)
callData->args[ii] = ep->v8engine()->fromVariant(*(QVariant *)a[ii + 1]);
QV4::ScopedValue result(scope);
- QV4::ExecutionContext *ctx = function->engine()->current;
+ QV4::ExecutionContext *ctx = function->engine()->currentContext();
result = function->call(callData);
if (scope.hasException()) {
QQmlError error = QV4::ExecutionEngine::catchExceptionAsQmlError(ctx);
diff --git a/src/qml/qml/qqmlxmlhttprequest.cpp b/src/qml/qml/qqmlxmlhttprequest.cpp
index 18e3e33c4b..ad231d0769 100644
--- a/src/qml/qml/qqmlxmlhttprequest.cpp
+++ b/src/qml/qml/qqmlxmlhttprequest.cpp
@@ -192,7 +192,7 @@ public:
, list(list)
, d(data)
{
- vtbl = &static_vtbl;
+ setVTable(&static_vtbl);
if (d)
d->addref();
@@ -226,7 +226,7 @@ public:
: Object(engine)
, d(data)
{
- vtbl = &static_vtbl;
+ setVTable(&static_vtbl);
if (d)
d->addref();
@@ -258,7 +258,7 @@ public:
NodePrototype(ExecutionEngine *engine)
: Object(engine)
{
- vtbl = &static_vtbl;
+ setVTable(&static_vtbl);
Scope scope(engine);
ScopedObject protectThis(scope, this);
@@ -312,7 +312,7 @@ class Node : public Object
: Object(engine)
, d(data)
{
- vtbl = &static_vtbl;
+ setVTable(&static_vtbl);
if (d)
d->addref();
@@ -906,7 +906,7 @@ ReturnedValue NamedNodeMap::getIndexed(Managed *m, uint index, bool *hasProperty
QV4::ExecutionEngine *v4 = m->engine();
NamedNodeMap *r = m->as<NamedNodeMap>();
if (!r)
- return v4->current->throwTypeError();
+ return v4->currentContext()->throwTypeError();
QV8Engine *engine = v4->v8Engine;
@@ -925,7 +925,7 @@ ReturnedValue NamedNodeMap::get(Managed *m, const StringRef name, bool *hasPrope
NamedNodeMap *r = m->as<NamedNodeMap>();
QV4::ExecutionEngine *v4 = m->engine();
if (!r)
- return v4->current->throwTypeError();
+ return v4->currentContext()->throwTypeError();
name->makeIdentifier();
if (name->equals(v4->id_length))
@@ -961,7 +961,7 @@ ReturnedValue NodeList::getIndexed(Managed *m, uint index, bool *hasProperty)
QV4::ExecutionEngine *v4 = m->engine();
NodeList *r = m->as<NodeList>();
if (!r)
- return v4->current->throwTypeError();
+ return v4->currentContext()->throwTypeError();
QV8Engine *engine = v4->v8Engine;
@@ -980,7 +980,7 @@ ReturnedValue NodeList::get(Managed *m, const StringRef name, bool *hasProperty)
QV4::ExecutionEngine *v4 = m->engine();
NodeList *r = m->as<NodeList>();
if (!r)
- return v4->current->throwTypeError();
+ return v4->currentContext()->throwTypeError();
name->makeIdentifier();
@@ -1535,7 +1535,7 @@ const QByteArray &QQmlXMLHttpRequest::rawResponseBody() const
void QQmlXMLHttpRequest::dispatchCallbackImpl(const ValueRef me)
{
- ExecutionContext *ctx = v4->current;
+ ExecutionContext *ctx = v4->currentContext();
QV4::Scope scope(v4);
Scoped<Object> o(scope, me);
if (!o) {
@@ -1560,7 +1560,7 @@ void QQmlXMLHttpRequest::dispatchCallbackImpl(const ValueRef me)
s = v4->newString(QStringLiteral("ActivationObject"));
Scoped<Object> activationObject(scope, o->get(s));
if (!activationObject) {
- v4->current->throwError(QStringLiteral("QQmlXMLHttpRequest: internal error: empty ActivationObject"));
+ v4->currentContext()->throwError(QStringLiteral("QQmlXMLHttpRequest: internal error: empty ActivationObject"));
return;
}
@@ -1580,7 +1580,7 @@ void QQmlXMLHttpRequest::dispatchCallbackImpl(const ValueRef me)
void QQmlXMLHttpRequest::dispatchCallback(const ValueRef me)
{
- ExecutionContext *ctx = v4->current;
+ ExecutionContext *ctx = v4->currentContext();
dispatchCallbackImpl(me);
if (v4->hasException) {
QQmlError error = QV4::ExecutionEngine::catchExceptionAsQmlError(ctx);
@@ -1605,7 +1605,7 @@ struct QQmlXMLHttpRequestWrapper : public Object
: Object(engine)
, request(request)
{
- vtbl = &static_vtbl;
+ setVTable(&static_vtbl);
}
~QQmlXMLHttpRequestWrapper() {
delete request;
@@ -1626,7 +1626,7 @@ struct QQmlXMLHttpRequestCtor : public FunctionObject
QQmlXMLHttpRequestCtor(ExecutionEngine *engine)
: FunctionObject(engine->rootContext, QStringLiteral("XMLHttpRequest"))
{
- vtbl = &static_vtbl;
+ setVTable(&static_vtbl);
Scope scope(engine);
ScopedValue protectThis(scope, this);
@@ -1656,7 +1656,7 @@ struct QQmlXMLHttpRequestCtor : public FunctionObject
Scope scope(that->engine());
Scoped<QQmlXMLHttpRequestCtor> ctor(scope, that->as<QQmlXMLHttpRequestCtor>());
if (!ctor)
- return that->engine()->current->throwTypeError();
+ return that->engine()->currentContext()->throwTypeError();
QV8Engine *engine = that->engine()->v8Engine;
QQmlXMLHttpRequest *r = new QQmlXMLHttpRequest(engine, engine->networkAccessManager());
diff --git a/src/qml/qml/v8/qqmlbuiltinfunctions.cpp b/src/qml/qml/v8/qqmlbuiltinfunctions.cpp
index c80a742af0..41d5de0862 100644
--- a/src/qml/qml/v8/qqmlbuiltinfunctions.cpp
+++ b/src/qml/qml/v8/qqmlbuiltinfunctions.cpp
@@ -90,7 +90,7 @@ QV4::QtObject::QtObject(ExecutionEngine *v4, QQmlEngine *qmlEngine)
, m_platform(0)
, m_application(0)
{
- vtbl = &static_vtbl;
+ setVTable(&static_vtbl);
Scope scope(v4);
ScopedObject protectThis(scope, this);
@@ -1183,7 +1183,7 @@ struct BindingFunction : public QV4::FunctionObject
: QV4::FunctionObject(originalFunction->scope, originalFunction->name)
, originalFunction(originalFunction)
{
- vtbl = &static_vtbl;
+ setVTable(&static_vtbl);
bindingKeyFlag = true;
}
@@ -1608,7 +1608,7 @@ void QV4::GlobalExtensions::init(QQmlEngine *qmlEngine, Object *globalObject)
globalObject->defineDefaultProperty(QStringLiteral("Qt"), qt);
// string prototype extension
- v4->stringClass->prototype->defineDefaultProperty(QStringLiteral("arg"), method_string_arg);
+ v4->stringObjectClass->prototype->defineDefaultProperty(QStringLiteral("arg"), method_string_arg);
}
@@ -1726,7 +1726,9 @@ ReturnedValue GlobalExtensions::method_qsTr(CallContext *ctx)
QString path = ctxt->url.toString();
int lastSlash = path.lastIndexOf(QLatin1Char('/'));
- QString context = (lastSlash > -1) ? path.mid(lastSlash + 1, path.length()-lastSlash-5) : QString();
+ int lastDot = path.lastIndexOf(QLatin1Char('.'));
+ int length = lastDot - (lastSlash + 1);
+ QString context = (lastSlash > -1) ? path.mid(lastSlash + 1, (length > -1) ? length : -1) : QString();
QString text = ctx->callData->args[0].toQStringNoThrow();
QString comment;
diff --git a/src/qml/qml/v8/qv8engine.cpp b/src/qml/qml/v8/qv8engine.cpp
index d0fc1b1295..33f5a00a6c 100644
--- a/src/qml/qml/v8/qv8engine.cpp
+++ b/src/qml/qml/v8/qv8engine.cpp
@@ -95,7 +95,7 @@ QV8Engine::QV8Engine(QJSEngine* qq)
, m_listModelData(0)
{
#ifdef Q_PROCESSOR_X86_32
- if (!(qCpuFeatures() & SSE2)) {
+ if (!qCpuHasFeature(SSE2)) {
qFatal("This program requires an X86 processor that supports SSE2 extension, at least a Pentium 4 or newer");
}
#endif
@@ -256,7 +256,7 @@ QV4::ReturnedValue QV8Engine::fromVariant(const QVariant &variant)
case QMetaType::Double:
return QV4::Encode(*reinterpret_cast<const double*>(ptr));
case QMetaType::QString:
- return m_v4Engine->current->engine->newString(*reinterpret_cast<const QString*>(ptr))->asReturnedValue();
+ return m_v4Engine->currentContext()->engine->newString(*reinterpret_cast<const QString*>(ptr))->asReturnedValue();
case QMetaType::Float:
return QV4::Encode(*reinterpret_cast<const float*>(ptr));
case QMetaType::Short:
@@ -667,7 +667,7 @@ QV4::ReturnedValue QV8Engine::metaTypeToJS(int type, const void *data)
case QMetaType::Double:
return QV4::Encode(*reinterpret_cast<const double*>(data));
case QMetaType::QString:
- return m_v4Engine->current->engine->newString(*reinterpret_cast<const QString*>(data))->asReturnedValue();
+ return m_v4Engine->currentContext()->engine->newString(*reinterpret_cast<const QString*>(data))->asReturnedValue();
case QMetaType::Float:
return QV4::Encode(*reinterpret_cast<const float*>(data));
case QMetaType::Short:
@@ -750,7 +750,7 @@ bool QV8Engine::metaTypeFromJS(const QV4::ValueRef value, int type, void *data)
if (value->isUndefined() || value->isNull())
*reinterpret_cast<QString*>(data) = QString();
else
- *reinterpret_cast<QString*>(data) = value->toString(m_v4Engine->current)->toQString();
+ *reinterpret_cast<QString*>(data) = value->toString(m_v4Engine->currentContext())->toQString();
return true;
case QMetaType::Float:
*reinterpret_cast<float*>(data) = value->toNumber();
diff --git a/src/qml/types/qqmldelegatemodel.cpp b/src/qml/types/qqmldelegatemodel.cpp
index 754d008745..7276c0e5c6 100644
--- a/src/qml/types/qqmldelegatemodel.cpp
+++ b/src/qml/types/qqmldelegatemodel.cpp
@@ -71,12 +71,12 @@ struct DelegateModelGroupFunction: QV4::FunctionObject
, code(code)
, flag(flag)
{
- vtbl = &static_vtbl;
+ setVTable(&static_vtbl);
}
static QV4::ReturnedValue construct(QV4::Managed *m, QV4::CallData *)
{
- return m->engine()->current->throwTypeError();
+ return m->engine()->currentContext()->throwTypeError();
}
static QV4::ReturnedValue call(QV4::Managed *that, QV4::CallData *callData)
@@ -86,7 +86,7 @@ struct DelegateModelGroupFunction: QV4::FunctionObject
QV4::Scoped<DelegateModelGroupFunction> f(scope, that, QV4::Scoped<DelegateModelGroupFunction>::Cast);
QV4::Scoped<QQmlDelegateModelItemObject> o(scope, callData->thisObject);
if (!o)
- return v4->current->throwTypeError(QStringLiteral("Not a valid VisualData object"));
+ return v4->currentContext()->throwTypeError(QStringLiteral("Not a valid VisualData object"));
QV4::ScopedValue v(scope, callData->argument(0));
return f->code(o->item, f->flag, v);
@@ -3144,7 +3144,7 @@ struct QQmlDelegateModelGroupChange : QV4::Object
QQmlDelegateModelGroupChange(QV4::ExecutionEngine *engine)
: Object(engine)
{
- vtbl = &static_vtbl;
+ setVTable(&static_vtbl);
}
static QV4::ReturnedValue method_get_index(QV4::CallContext *ctx) {
@@ -3183,7 +3183,7 @@ public:
QQmlDelegateModelGroupChangeArray(QV4::ExecutionEngine *engine)
: Object(engine)
{
- vtbl = &static_vtbl;
+ setVTable(&static_vtbl);
flags &= ~SimpleArray;
}
virtual ~QQmlDelegateModelGroupChangeArray() {}
@@ -3197,7 +3197,7 @@ public:
QV4::Scope scope(v4);
QV4::Scoped<QQmlDelegateModelGroupChangeArray> array(scope, m->as<QQmlDelegateModelGroupChangeArray>());
if (!array)
- return v4->current->throwTypeError();
+ return v4->currentContext()->throwTypeError();
if (index >= array->count()) {
if (hasProperty)
@@ -3221,7 +3221,7 @@ public:
{
QQmlDelegateModelGroupChangeArray *array = m->as<QQmlDelegateModelGroupChangeArray>();
if (!array)
- return m->engine()->current->throwTypeError();
+ return m->engine()->currentContext()->throwTypeError();
if (name->equals(m->engine()->id_length)) {
if (hasProperty)
diff --git a/src/qml/types/qqmldelegatemodel_p_p.h b/src/qml/types/qqmldelegatemodel_p_p.h
index 066c8e70e5..f78cf38535 100644
--- a/src/qml/types/qqmldelegatemodel_p_p.h
+++ b/src/qml/types/qqmldelegatemodel_p_p.h
@@ -165,7 +165,7 @@ struct QQmlDelegateModelItemObject : QV4::Object
QQmlDelegateModelItemObject(QV4::ExecutionEngine *engine, QQmlDelegateModelItem *item)
: Object(engine)
, item(item)
- { vtbl = &static_vtbl; }
+ { setVTable(&static_vtbl); }
~QQmlDelegateModelItemObject();
static void destroy(Managed *that);
diff --git a/src/qml/types/qquickworkerscript.cpp b/src/qml/types/qquickworkerscript.cpp
index 7607febe01..53e45e2003 100644
--- a/src/qml/types/qquickworkerscript.cpp
+++ b/src/qml/types/qquickworkerscript.cpp
@@ -252,7 +252,7 @@ QV4::ReturnedValue QQuickWorkerScriptEnginePrivate::WorkerEngine::sendFunction(i
QV4::Scope scope(v4);
QV4::ScopedFunctionObject f(scope, createsend.value());
- QV4::ExecutionContext *ctx = v4->current;
+ QV4::ExecutionContext *ctx = v4->currentContext();
QV4::ScopedValue v(scope);
QV4::ScopedCallData callData(scope, 1);
@@ -356,7 +356,7 @@ void QQuickWorkerScriptEnginePrivate::processMessage(int id, const QByteArray &d
QV4::ExecutionEngine *v4 = QV8Engine::getV4(workerEngine);
QV4::Scope scope(v4);
QV4::ScopedFunctionObject f(scope, workerEngine->onmessage.value());
- QV4::ExecutionContext *ctx = v4->current;
+ QV4::ExecutionContext *ctx = v4->currentContext();
QV4::ScopedValue value(scope, QV4::Serialize::deserialize(data, workerEngine));
@@ -398,7 +398,7 @@ void QQuickWorkerScriptEnginePrivate::processLoad(int id, const QUrl &url)
QV4::Script program(v4, activation, sourceCode, url.toString());
- QV4::ExecutionContext *ctx = v4->current;
+ QV4::ExecutionContext *ctx = v4->currentContext();
program.parse();
if (!v4->hasException)
program.run();
diff --git a/src/qml/util/qqmladaptormodel.cpp b/src/qml/util/qqmladaptormodel.cpp
index 9cd5709a49..38fdffdde6 100644
--- a/src/qml/util/qqmladaptormodel.cpp
+++ b/src/qml/util/qqmladaptormodel.cpp
@@ -902,7 +902,7 @@ void QQmlAdaptorModel::setModel(const QVariant &variant, QQmlDelegateModel *vdm,
list.setList(variant, engine);
- if (QObject *object = qvariant_cast<QObject *>(variant)) {
+ if (QObject *object = qvariant_cast<QObject *>(list.list())) {
setObject(object);
if (QAbstractItemModel *model = qobject_cast<QAbstractItemModel *>(object)) {
accessors = new VDMAbstractItemModelDataType(this);
@@ -927,8 +927,8 @@ void QQmlAdaptorModel::setModel(const QVariant &variant, QQmlDelegateModel *vdm,
} else if (list.type() == QQmlListAccessor::ListProperty) {
setObject(static_cast<const QQmlListReference *>(variant.constData())->object());
accessors = new VDMObjectDelegateDataType;
- } else if (list.type() != QQmlListAccessor::Invalid) {
- Q_ASSERT(list.type() != QQmlListAccessor::Instance); // Should have cast to QObject.
+ } else if (list.type() != QQmlListAccessor::Invalid
+ && list.type() != QQmlListAccessor::Instance) { // Null QObject
setObject(0);
accessors = &qt_vdm_list_accessors;
} else {
diff --git a/src/quick/doc/src/concepts/visualcanvas/scenegraph.qdoc b/src/quick/doc/src/concepts/visualcanvas/scenegraph.qdoc
index 384e8209c1..16075f0db3 100644
--- a/src/quick/doc/src/concepts/visualcanvas/scenegraph.qdoc
+++ b/src/quick/doc/src/concepts/visualcanvas/scenegraph.qdoc
@@ -724,6 +724,11 @@ with multiple windows.
\li Some material flags prevent batching, the most limiting one
being QSGMaterial::RequiresFullMatrix which prevents all batching.
+ \li Applications with a monochrome background should set it using
+ QQuickWindow::setColor() rather than using a top-level Rectangle item.
+ QQuickWindow::setColor() will be used in a call to \c glClear(),
+ which is potentially faster.
+
\endlist
If an application performs poorly, make sure that rendering is
diff --git a/src/quick/items/context2d/qquickcanvascontext_p.h b/src/quick/items/context2d/qquickcanvascontext_p.h
index 559f41e546..2d8fbb5f85 100644
--- a/src/quick/items/context2d/qquickcanvascontext_p.h
+++ b/src/quick/items/context2d/qquickcanvascontext_p.h
@@ -71,8 +71,6 @@ public:
virtual void setV8Engine(QV8Engine *engine) = 0;
virtual QV4::ReturnedValue v4value() const = 0;
- virtual QSGDynamicTexture *texture() const = 0;
-
virtual QImage toImage(const QRectF& bounds) = 0;
Q_SIGNALS:
diff --git a/src/quick/items/context2d/qquickcanvasitem.cpp b/src/quick/items/context2d/qquickcanvasitem.cpp
index ba3592986c..19a161a605 100644
--- a/src/quick/items/context2d/qquickcanvasitem.cpp
+++ b/src/quick/items/context2d/qquickcanvasitem.cpp
@@ -44,8 +44,10 @@
#include <private/qquickitem_p.h>
#include <private/qquickcanvascontext_p.h>
#include <private/qquickcontext2d_p.h>
+#include <private/qquickcontext2dtexture_p.h>
#include <qsgsimpletexturenode.h>
#include <QtQuick/private/qquickpixmapcache_p.h>
+#include <QtGui/QGuiApplication>
#include <qqmlinfo.h>
#include <private/qqmlengine_p.h>
@@ -58,19 +60,15 @@
QT_BEGIN_NAMESPACE
-QQuickCanvasPixmap::QQuickCanvasPixmap(const QImage& image, QQuickWindow *window)
+QQuickCanvasPixmap::QQuickCanvasPixmap(const QImage& image)
: m_pixmap(0)
, m_image(image)
- , m_texture(0)
- , m_window(window)
{
}
-QQuickCanvasPixmap::QQuickCanvasPixmap(QQuickPixmap *pixmap, QQuickWindow *window)
+QQuickCanvasPixmap::QQuickCanvasPixmap(QQuickPixmap *pixmap)
: m_pixmap(pixmap)
- , m_texture(0)
- , m_window(window)
{
}
@@ -78,8 +76,6 @@ QQuickCanvasPixmap::QQuickCanvasPixmap(QQuickPixmap *pixmap, QQuickWindow *windo
QQuickCanvasPixmap::~QQuickCanvasPixmap()
{
delete m_pixmap;
- if (m_texture)
- m_texture->deleteLater();
}
qreal QQuickCanvasPixmap::width() const
@@ -105,18 +101,6 @@ bool QQuickCanvasPixmap::isValid() const
return !m_image.isNull();
}
-QSGTexture *QQuickCanvasPixmap::texture()
-{
- if (!m_texture) {
- if (m_pixmap) {
- Q_ASSERT(m_pixmap->textureFactory());
- m_texture = m_pixmap->textureFactory()->createTexture(m_window);
- } else {
- m_texture = m_window->createTextureFromImage(m_image, QQuickWindow::TextureCanUseAtlas);
- }
- }
- return m_texture;
-}
QImage QQuickCanvasPixmap::image()
{
if (m_image.isNull() && m_pixmap)
@@ -194,7 +178,7 @@ QQuickCanvasItemPrivate::QQuickCanvasItemPrivate()
, hasCanvasWindow(false)
, available(false)
, renderTarget(QQuickCanvasItem::Image)
- , renderStrategy(QQuickCanvasItem::Cooperative)
+ , renderStrategy(QQuickCanvasItem::Immediate)
{
antialiasing = true;
}
@@ -246,10 +230,14 @@ QQuickCanvasItemPrivate::~QQuickCanvasItemPrivate()
The Canvas.FramebufferObject render target utilizes OpenGL hardware
acceleration rather than rendering into system memory, which in many cases
- results in faster rendering.
+ results in faster rendering. Canvas.FramebufferObject relies on the
+ OpenGL extensions \c GL_EXT_framebuffer_multisample and
+ \c GL_EXT_framebuffer_blit for antialiasing. It will also use more
+ graphics memory when rendering strategy is anything other than
+ Canvas.Cooperative.
The default render target is Canvas.Image and the default renderStrategy is
- Canvas.Cooperative.
+ Canvas.Immediate.
\section1 Tiled Canvas
The Canvas item supports tiled rendering by setting \l canvasSize, \l tileSize
@@ -489,7 +477,7 @@ void QQuickCanvasItem::setCanvasWindow(const QRectF& rect)
context will choose appropriate options and Canvas will signal the change
to the properties.
- The default render target is \c Canvas.FramebufferObject.
+ The default render target is \c Canvas.Image.
*/
QQuickCanvasItem::RenderTarget QQuickCanvasItem::renderTarget() const
{
@@ -531,7 +519,7 @@ void QQuickCanvasItem::setRenderTarget(QQuickCanvasItem::RenderTarget target)
the GUI thread. Selecting \c Canvas.Cooperative, does not guarantee
rendering will occur on a thread separate from the GUI thread.
- The default value is \c Canvas.Cooperative.
+ The default value is \c Canvas.Immediate.
\sa renderTarget
*/
@@ -689,6 +677,15 @@ void QQuickCanvasItem::updatePolish()
}
}
+class QQuickCanvasNode : public QSGSimpleTextureNode
+{
+public:
+ ~QQuickCanvasNode()
+ {
+ delete texture();
+ }
+};
+
QSGNode *QQuickCanvasItem::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData *)
{
Q_D(QQuickCanvasItem);
@@ -698,9 +695,9 @@ QSGNode *QQuickCanvasItem::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData
return 0;
}
- QSGSimpleTextureNode *node = static_cast<QSGSimpleTextureNode*>(oldNode);
+ QQuickCanvasNode *node = static_cast<QQuickCanvasNode*>(oldNode);
if (!node)
- node = new QSGSimpleTextureNode;
+ node = new QQuickCanvasNode();
if (d->smooth)
node->setFiltering(QSGTexture::Linear);
@@ -712,8 +709,15 @@ QSGNode *QQuickCanvasItem::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData
d->context->flush();
}
- node->setTexture(d->context->texture());
- node->markDirty(QSGNode::DirtyMaterial);
+ QQuickContext2D *ctx = qobject_cast<QQuickContext2D *>(d->context);
+ QQuickContext2DTexture *factory = ctx->texture();
+ QSGTexture *texture = factory->textureForNextFrame(node->texture());
+ if (!texture) {
+ delete node;
+ return 0;
+ }
+
+ node->setTexture(texture);
node->setRect(QRectF(QPoint(0, 0), d->canvasWindow.size()));
return node;
}
@@ -916,7 +920,7 @@ void QQuickCanvasItem::loadImage(const QUrl& url)
if (!d->pixmaps.contains(fullPathUrl)) {
QQuickPixmap* pix = new QQuickPixmap();
QQmlRefPointer<QQuickCanvasPixmap> canvasPix;
- canvasPix.take(new QQuickCanvasPixmap(pix, d->window));
+ canvasPix.take(new QQuickCanvasPixmap(pix));
d->pixmaps.insert(fullPathUrl, canvasPix);
pix->load(qmlEngine(this)
diff --git a/src/quick/items/context2d/qquickcanvasitem_p.h b/src/quick/items/context2d/qquickcanvasitem_p.h
index 2ec36cfe73..3baf68d418 100644
--- a/src/quick/items/context2d/qquickcanvasitem_p.h
+++ b/src/quick/items/context2d/qquickcanvasitem_p.h
@@ -52,17 +52,15 @@ QT_BEGIN_NAMESPACE
class QQuickCanvasContext;
class QQuickCanvasItemPrivate;
-class QSGTexture;
class QQuickPixmap;
class QQuickCanvasPixmap : public QQmlRefCount
{
public:
- QQuickCanvasPixmap(const QImage& image, QQuickWindow *window);
- QQuickCanvasPixmap(QQuickPixmap *pixmap, QQuickWindow *window);
+ QQuickCanvasPixmap(const QImage& image);
+ QQuickCanvasPixmap(QQuickPixmap *pixmap);
~QQuickCanvasPixmap();
- QSGTexture *texture();
QImage image();
qreal width() const;
@@ -73,8 +71,6 @@ public:
private:
QQuickPixmap *m_pixmap;
QImage m_image;
- QSGTexture *m_texture;
- QQuickWindow *m_window;
};
class QQuickCanvasItem : public QQuickItem
diff --git a/src/quick/items/context2d/qquickcontext2d.cpp b/src/quick/items/context2d/qquickcontext2d.cpp
index 2a9e0f2ac2..b6eb2db33d 100644
--- a/src/quick/items/context2d/qquickcontext2d.cpp
+++ b/src/quick/items/context2d/qquickcontext2d.cpp
@@ -484,7 +484,7 @@ public:
QQuickJSContext2D(QV4::ExecutionEngine *engine)
: QV4::Object(engine)
{
- vtbl = &static_vtbl;
+ setVTable(&static_vtbl);
}
QQuickContext2D* context;
@@ -653,7 +653,7 @@ public:
, patternRepeatX(false)
, patternRepeatY(false)
{
- vtbl = &static_vtbl;
+ setVTable(&static_vtbl);
}
QBrush brush;
bool patternRepeatX:1;
@@ -870,7 +870,7 @@ struct QQuickJSContext2DPixelData : public QV4::Object
QQuickJSContext2DPixelData(QV4::ExecutionEngine *engine)
: QV4::Object(engine)
{
- vtbl = &static_vtbl;
+ setVTable(&static_vtbl);
flags &= ~SimpleArray;
}
@@ -893,7 +893,7 @@ struct QQuickJSContext2DImageData : public QV4::Object
QQuickJSContext2DImageData(QV4::ExecutionEngine *engine)
: QV4::Object(engine)
{
- vtbl = &static_vtbl;
+ setVTable(&static_vtbl);
pixelData = QV4::Primitive::undefinedValue();
QV4::Scope scope(engine);
@@ -2985,14 +2985,14 @@ QV4::ReturnedValue QQuickJSContext2DPrototype::method_drawImage(QV4::CallContext
} else if (QQuickCanvasItem *canvas = qobject_cast<QQuickCanvasItem*>(qobjectWrapper->object())) {
QImage img = canvas->toImage();
if (!img.isNull())
- pixmap.take(new QQuickCanvasPixmap(img, canvas->window()));
+ pixmap.take(new QQuickCanvasPixmap(img));
} else {
V4THROW_DOM(DOMEXCEPTION_TYPE_MISMATCH_ERR, "drawImage(), type mismatch");
}
} else if (QV4::Referenced<QQuickJSContext2DImageData> imageData = arg->asRef<QQuickJSContext2DImageData>()) {
QV4::Scoped<QQuickJSContext2DPixelData> pix(scope, imageData->pixelData.as<QQuickJSContext2DPixelData>());
if (pix && !pix->image.isNull()) {
- pixmap.take(new QQuickCanvasPixmap(pix->image, r->context->canvas()->window()));
+ pixmap.take(new QQuickCanvasPixmap(pix->image));
} else {
V4THROW_DOM(DOMEXCEPTION_TYPE_MISMATCH_ERR, "drawImage(), type mismatch");
}
@@ -3165,7 +3165,7 @@ QV4::ReturnedValue QQuickJSContext2DPixelData::getIndexed(QV4::Managed *m, uint
QV4::Scope scope(v4);
QV4::Scoped<QQuickJSContext2DPixelData> r(scope, m->as<QQuickJSContext2DPixelData>());
if (!m)
- return m->engine()->current->throwTypeError();
+ return m->engine()->currentContext()->throwTypeError();
if (r && index < static_cast<quint32>(r->image.width() * r->image.height() * 4)) {
if (hasProperty)
@@ -3200,7 +3200,7 @@ void QQuickJSContext2DPixelData::putIndexed(QV4::Managed *m, uint index, const Q
QV4::Scoped<QQuickJSContext2DPixelData> r(scope, m->as<QQuickJSContext2DPixelData>());
if (!r) {
- v4->current->throwTypeError();
+ v4->currentContext()->throwTypeError();
return;
}
@@ -4084,6 +4084,15 @@ void QQuickContext2D::init(QQuickCanvasItem *canvasItem, const QVariantMap &args
QQuickWindow *window = canvasItem->window();
m_renderStrategy = canvasItem->renderStrategy();
+#ifdef Q_OS_WIN
+ if (m_renderTarget == QQuickCanvasItem::FramebufferObject
+ && (m_renderStrategy != QQuickCanvasItem::Cooperative)) {
+ // On windows a context needs to be unbound set up sharing, so
+ // for simplicity we disallow FBO + !coop here.
+ m_renderTarget = QQuickCanvasItem::Image;
+ }
+#endif
+
switch (m_renderTarget) {
case QQuickCanvasItem::Image:
m_texture = new QQuickContext2DImageTexture;
@@ -4099,6 +4108,7 @@ void QQuickContext2D::init(QQuickCanvasItem *canvasItem, const QVariantMap &args
m_texture->setCanvasSize(canvasItem->canvasSize().toSize());
m_texture->setSmooth(canvasItem->smooth());
m_texture->setAntialiasing(canvasItem->antialiasing());
+ m_texture->setOnCustomThread(m_renderStrategy == QQuickCanvasItem::Threaded);
m_thread = QThread::currentThread();
QThread *renderThread = m_thread;
@@ -4129,28 +4139,31 @@ void QQuickContext2D::init(QQuickCanvasItem *canvasItem, const QVariantMap &args
void QQuickContext2D::prepare(const QSize& canvasSize, const QSize& tileSize, const QRect& canvasWindow, const QRect& dirtyRect, bool smooth, bool antialiasing)
{
- QMetaObject::invokeMethod(m_texture
- , "canvasChanged"
- , Qt::AutoConnection
- , Q_ARG(QSize, canvasSize)
- , Q_ARG(QSize, tileSize)
- , Q_ARG(QRect, canvasWindow)
- , Q_ARG(QRect, dirtyRect)
- , Q_ARG(bool, smooth)
- , Q_ARG(bool, antialiasing));
+ if (m_texture->thread() == QThread::currentThread()) {
+ m_texture->canvasChanged(canvasSize, tileSize, canvasWindow, dirtyRect, smooth, antialiasing);
+ } else {
+ QEvent *e = new QQuickContext2DTexture::CanvasChangeEvent(canvasSize,
+ tileSize,
+ canvasWindow,
+ dirtyRect,
+ smooth,
+ antialiasing);
+ QCoreApplication::postEvent(m_texture, e);
+ }
}
void QQuickContext2D::flush()
{
- if (m_buffer)
- QMetaObject::invokeMethod(m_texture,
- "paint",
- Qt::AutoConnection,
- Q_ARG(QQuickContext2DCommandBuffer*, m_buffer));
+ if (m_buffer) {
+ if (m_texture->thread() == QThread::currentThread())
+ m_texture->paint(m_buffer);
+ else
+ QCoreApplication::postEvent(m_texture, new QQuickContext2DTexture::PaintEvent(m_buffer));
+ }
m_buffer = new QQuickContext2DCommandBuffer();
}
-QSGDynamicTexture *QQuickContext2D::texture() const
+QQuickContext2DTexture *QQuickContext2D::texture() const
{
return m_texture;
}
@@ -4164,6 +4177,7 @@ QImage QQuickContext2D::toImage(const QRectF& bounds)
qWarning() << "Pixel readback is not supported in Cooperative mode, please try Threaded or Immediate mode";
return QImage();
} else {
+ QCoreApplication::postEvent(m_texture, new QEvent(QEvent::Type(QEvent::User + 10)));
QMetaObject::invokeMethod(m_texture,
"grabImage",
Qt::BlockingQueuedConnection,
diff --git a/src/quick/items/context2d/qquickcontext2d_p.h b/src/quick/items/context2d/qquickcontext2d_p.h
index 4bef50d9cd..6399da3dee 100644
--- a/src/quick/items/context2d/qquickcontext2d_p.h
+++ b/src/quick/items/context2d/qquickcontext2d_p.h
@@ -74,6 +74,8 @@ class QOpenGLContext;
class QQuickContext2D : public QQuickCanvasContext
{
+ Q_OBJECT
+
public:
Q_DISABLE_COPY(QQuickContext2D)
@@ -171,8 +173,8 @@ public:
void prepare(const QSize& canvasSize, const QSize& tileSize, const QRect& canvasWindow, const QRect& dirtyRect, bool smooth, bool antialiasing);
void flush();
void sync();
- QThread *thread() const {return m_thread;}
- QSGDynamicTexture *texture() const;
+ QThread *thread() const { return m_thread; }
+ QQuickContext2DTexture *texture() const;
QImage toImage(const QRectF& bounds);
QV4::ReturnedValue v4value() const;
diff --git a/src/quick/items/context2d/qquickcontext2dcommandbuffer.cpp b/src/quick/items/context2d/qquickcontext2dcommandbuffer.cpp
index d2f4e3317d..06a0713365 100644
--- a/src/quick/items/context2d/qquickcontext2dcommandbuffer.cpp
+++ b/src/quick/items/context2d/qquickcontext2dcommandbuffer.cpp
@@ -420,38 +420,8 @@ void QQuickContext2DCommandBuffer::replay(QPainter* p, QQuickContext2D::State& s
Q_ASSERT(!pix.isNull());
const bool hasShadow = HAS_SHADOW(state.shadowOffsetX, state.shadowOffsetY, state.shadowBlur, state.shadowColor);
- if (p->paintEngine()->type() != QPaintEngine::OpenGL2 || hasShadow){
- //TODO: generate shadow blur with shaders
- qt_drawImage(p, state, pix->image(), sr, dr, hasShadow);
- } else if (pix->texture()){
- QSGTexture *tex = pix->texture();
- QSGDynamicTexture *dynamicTexture = qobject_cast<QSGDynamicTexture *>(tex);
- if (dynamicTexture)
- dynamicTexture->updateTexture();
-
- if (tex->textureId()) {
-
- if (sr.width() < 0)
- sr.setWidth(tex->textureSize().width());
- if (sr.height() < 0)
- sr.setHeight(tex->textureSize().height());
-
- if (dr.width() < 0)
- dr.setWidth(sr.width());
- if (dr.height() < 0)
- dr.setHeight(sr.height());
-
- qreal srBottom = sr.bottom();
- sr.setBottom(sr.top());
- sr.setTop(srBottom);
-
- tex->bind();
- if (p->paintEngine()->type() == QPaintEngine::OpenGL2) {
- QOpenGL2PaintEngineEx *engine = static_cast<QOpenGL2PaintEngineEx *>(p->paintEngine());
- engine->drawTexture(dr, tex->textureId(), tex->textureSize(), sr);
- }
- }
- }
+ //TODO: generate shadow blur with shaders
+ qt_drawImage(p, state, pix->image(), sr, dr, hasShadow);
break;
}
case QQuickContext2D::GetImageData:
diff --git a/src/quick/items/context2d/qquickcontext2dcommandbuffer_p.h b/src/quick/items/context2d/qquickcontext2dcommandbuffer_p.h
index 29cdc73708..9e79333a0c 100644
--- a/src/quick/items/context2d/qquickcontext2dcommandbuffer_p.h
+++ b/src/quick/items/context2d/qquickcontext2dcommandbuffer_p.h
@@ -58,8 +58,6 @@ public:
void reset();
void clear();
- void lockQueue() { queueLock.lock(); }
- void unlockQueue() { queueLock.unlock(); }
inline int size() {return commands.size();}
inline bool isEmpty() const {return commands.isEmpty(); }
inline bool hasNext() const {return cmdIdx < commands.size(); }
diff --git a/src/quick/items/context2d/qquickcontext2dtexture.cpp b/src/quick/items/context2d/qquickcontext2dtexture.cpp
index 8dc9978089..8dd48b4988 100644
--- a/src/quick/items/context2d/qquickcontext2dtexture.cpp
+++ b/src/quick/items/context2d/qquickcontext2dtexture.cpp
@@ -50,6 +50,7 @@
#include <QOpenGLFramebufferObject>
#include <QOpenGLFramebufferObjectFormat>
#include <QtCore/QThread>
+#include <QtGui/QGuiApplication>
QT_BEGIN_NAMESPACE
@@ -90,7 +91,6 @@ struct GLAcquireContext {
QQuickContext2DTexture::QQuickContext2DTexture()
: m_context(0)
, m_item(0)
- , m_dirtyCanvas(false)
, m_canvasWindowChanged(false)
, m_dirtyTexture(false)
, m_smooth(true)
@@ -105,23 +105,20 @@ QQuickContext2DTexture::~QQuickContext2DTexture()
clearTiles();
}
-QSize QQuickContext2DTexture::textureSize() const
-{
- return m_canvasWindow.size();
-}
-
void QQuickContext2DTexture::markDirtyTexture()
{
+ if (m_onCustomThread)
+ m_mutex.lock();
m_dirtyTexture = true;
- updateTexture();
emit textureChanged();
+ if (m_onCustomThread)
+ m_mutex.unlock();
}
bool QQuickContext2DTexture::setCanvasSize(const QSize &size)
{
if (m_canvasSize != size) {
m_canvasSize = size;
- m_dirtyCanvas = true;
return true;
}
return false;
@@ -131,7 +128,6 @@ bool QQuickContext2DTexture::setTileSize(const QSize &size)
{
if (m_tileSize != size) {
m_tileSize = size;
- m_dirtyCanvas = true;
return true;
}
return false;
@@ -195,7 +191,6 @@ void QQuickContext2DTexture::canvasChanged(const QSize& canvasSize, const QSize&
if (canvasSize == canvasWindow.size()) {
m_tiledCanvas = false;
- m_dirtyCanvas = false;
} else {
m_tiledCanvas = true;
}
@@ -309,7 +304,6 @@ QRect QQuickContext2DTexture::createTiles(const QRect& window)
m_tiles.clear();
if (window.isEmpty()) {
- m_dirtyCanvas = false;
return QRect();
}
@@ -351,7 +345,6 @@ QRect QQuickContext2DTexture::createTiles(const QRect& window)
qDeleteAll(oldTiles);
- m_dirtyCanvas = false;
return r;
}
@@ -366,6 +359,20 @@ QSize QQuickContext2DTexture::adjustedTileSize(const QSize &ts)
return ts;
}
+bool QQuickContext2DTexture::event(QEvent *e)
+{
+ if ((int) e->type() == QEvent::User + 1) {
+ PaintEvent *pe = static_cast<PaintEvent *>(e);
+ paint(pe->buffer);
+ return true;
+ } else if ((int) e->type() == QEvent::User + 2) {
+ CanvasChangeEvent *ce = static_cast<CanvasChangeEvent *>(e);
+ canvasChanged(ce->canvasSize, ce->tileSize, ce->canvasWindow, ce->dirtyRect, ce->smooth, ce->antialiasing);
+ return true;
+ }
+ return QObject::event(e);
+}
+
static inline QSize npotAdjustedSize(const QSize &size)
{
static bool checked = false;
@@ -391,6 +398,9 @@ QQuickContext2DFBOTexture::QQuickContext2DFBOTexture()
, m_multisampledFbo(0)
, m_paint_device(0)
{
+ m_displayTextures[0] = 0;
+ m_displayTextures[1] = 0;
+ m_displayTexture = -1;
}
QQuickContext2DFBOTexture::~QQuickContext2DFBOTexture()
@@ -403,17 +413,52 @@ QQuickContext2DFBOTexture::~QQuickContext2DFBOTexture()
delete m_fbo;
delete m_multisampledFbo;
delete m_paint_device;
+
+ glDeleteTextures(2, m_displayTextures);
}
-QSize QQuickContext2DFBOTexture::adjustedTileSize(const QSize &ts)
+QSGTexture *QQuickContext2DFBOTexture::textureForNextFrame(QSGTexture *lastTexture)
{
- return npotAdjustedSize(ts);
+ QSGPlainTexture *texture = static_cast<QSGPlainTexture *>(lastTexture);
+
+ if (m_onCustomThread)
+ m_mutex.lock();
+
+ if (m_fbo) {
+ if (!texture) {
+ texture = new QSGPlainTexture();
+ texture->setHasMipmaps(false);
+ texture->setHasAlphaChannel(true);
+ texture->setOwnsTexture(false);
+ m_dirtyTexture = true;
+ }
+
+ if (m_dirtyTexture) {
+ if (!m_context->glContext()) {
+ // on a rendering thread, use the fbo directly...
+ texture->setTextureId(m_fbo->texture());
+ } else {
+ // on GUI or custom thread, use display textures...
+ m_displayTexture = m_displayTexture == 0 ? 1 : 0;
+ texture->setTextureId(m_displayTextures[m_displayTexture]);
+ }
+ texture->setTextureSize(m_fbo->size());
+ m_dirtyTexture = false;
+ }
+
+ }
+
+ if (m_onCustomThread) {
+ m_condition.wakeOne();
+ m_mutex.unlock();
+ }
+
+ return texture;
}
-void QQuickContext2DFBOTexture::bind()
+QSize QQuickContext2DFBOTexture::adjustedTileSize(const QSize &ts)
{
- glBindTexture(GL_TEXTURE_2D, textureId());
- updateBindOptions();
+ return npotAdjustedSize(ts);
}
QRectF QQuickContext2DFBOTexture::normalizedTextureSubRect() const
@@ -424,20 +469,6 @@ QRectF QQuickContext2DFBOTexture::normalizedTextureSubRect() const
, qreal(m_canvasWindow.height()) / m_fboSize.height());
}
-
-int QQuickContext2DFBOTexture::textureId() const
-{
- return m_fbo? m_fbo->texture() : 0;
-}
-
-
-bool QQuickContext2DFBOTexture::updateTexture()
-{
- bool textureUpdated = m_dirtyTexture;
- m_dirtyTexture = false;
- return textureUpdated;
-}
-
QQuickContext2DTile* QQuickContext2DFBOTexture::createTile() const
{
return new QQuickContext2DFBOTile();
@@ -461,7 +492,6 @@ bool QQuickContext2DFBOTexture::doMultisampling() const
void QQuickContext2DFBOTexture::grabImage(const QRectF& rf)
{
Q_ASSERT(rf.isValid());
-
if (!m_fbo) {
m_context->setGrabbedImage(QImage());
return;
@@ -531,7 +561,6 @@ QPaintDevice* QQuickContext2DFBOTexture::beginPainting()
} else {
QOpenGLFramebufferObjectFormat format;
format.setAttachment(QOpenGLFramebufferObject::CombinedDepthStencil);
-
m_fbo = new QOpenGLFramebufferObject(m_fboSize, format);
}
}
@@ -541,7 +570,6 @@ QPaintDevice* QQuickContext2DFBOTexture::beginPainting()
else
m_fbo->bind();
-
if (!m_paint_device) {
QOpenGLPaintDevice *gl_device = new QOpenGLPaintDevice(m_fbo->size());
gl_device->setPaintFlipped(true);
@@ -557,25 +585,47 @@ void QQuickContext2DFBOTexture::endPainting()
QQuickContext2DTexture::endPainting();
if (m_multisampledFbo)
QOpenGLFramebufferObject::blitFramebuffer(m_fbo, m_multisampledFbo);
+
+ if (m_context->glContext()) {
+ /* When rendering happens on the render thread, the fbo's texture is
+ * used directly for display. If we are on the GUI thread or a
+ * dedicated Canvas render thread, we need to decouple the FBO from
+ * the texture we are displaying in the SG rendering thread to avoid
+ * stalls and read/write issues in the GL pipeline as the FBO's texture
+ * could then potentially be used in different threads.
+ *
+ * We could have gotten away with only one display texture, but this
+ * would have implied that beginPainting would have to wait for SG
+ * to release that texture.
+ */
+
+ if (m_onCustomThread)
+ m_mutex.lock();
+
+ if (m_displayTextures[0] == 0) {
+ m_displayTexture = 1;
+ glGenTextures(2, m_displayTextures);
+ }
+
+ m_fbo->bind();
+ GLuint target = m_displayTexture == 0 ? 1 : 0;
+ glBindTexture(GL_TEXTURE_2D, m_displayTextures[target]);
+ glCopyTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 0, 0, m_fbo->width(), m_fbo->height(), 0);
+
+ if (m_onCustomThread)
+ m_mutex.unlock();
+ }
+
+ m_fbo->bindDefault();
}
QQuickContext2DImageTexture::QQuickContext2DImageTexture()
: QQuickContext2DTexture()
- , m_texture(0)
{
}
QQuickContext2DImageTexture::~QQuickContext2DImageTexture()
{
- if (m_texture && m_texture->thread() != QThread::currentThread())
- m_texture->deleteLater();
- else
- delete m_texture;
-}
-
-int QQuickContext2DImageTexture::textureId() const
-{
- return imageTexture()->textureId();
}
QQuickCanvasItem::RenderTarget QQuickContext2DImageTexture::renderTarget() const
@@ -583,22 +633,6 @@ QQuickCanvasItem::RenderTarget QQuickContext2DImageTexture::renderTarget() const
return QQuickCanvasItem::Image;
}
-void QQuickContext2DImageTexture::bind()
-{
- imageTexture()->setFiltering(filtering());
- imageTexture()->bind();
-}
-
-bool QQuickContext2DImageTexture::updateTexture()
-{
- bool textureUpdated = m_dirtyTexture;
- if (m_dirtyTexture) {
- imageTexture()->setImage(m_image);
- m_dirtyTexture = false;
- }
- return textureUpdated;
-}
-
QQuickContext2DTile* QQuickContext2DImageTexture::createTile() const
{
return new QQuickContext2DImageTile();
@@ -608,19 +642,32 @@ void QQuickContext2DImageTexture::grabImage(const QRectF& rf)
{
Q_ASSERT(rf.isValid());
Q_ASSERT(m_context);
- QImage grabbed = m_image.copy(rf.toRect());
+ QImage grabbed = m_displayImage.copy(rf.toRect());
m_context->setGrabbedImage(grabbed);
}
-QSGPlainTexture *QQuickContext2DImageTexture::imageTexture() const
+QSGTexture *QQuickContext2DImageTexture::textureForNextFrame(QSGTexture *last)
{
- if (!m_texture) {
- QQuickContext2DImageTexture *that = const_cast<QQuickContext2DImageTexture *>(this);
- that->m_texture = new QSGPlainTexture;
- that->m_texture->setOwnsTexture(true);
- that->m_texture->setHasMipmaps(false);
+ QSGPlainTexture *texture = static_cast<QSGPlainTexture *>(last);
+
+ if (m_onCustomThread)
+ m_mutex.lock();
+
+ if (!texture) {
+ texture = new QSGPlainTexture();
+ texture->setHasMipmaps(false);
+ texture->setHasAlphaChannel(true);
+ m_dirtyTexture = true;
+ }
+ if (m_dirtyTexture) {
+ texture->setImage(m_displayImage);
+ m_dirtyTexture = false;
}
- return m_texture;
+
+ if (m_onCustomThread)
+ m_mutex.unlock();
+
+ return texture;
}
QPaintDevice* QQuickContext2DImageTexture::beginPainting()
@@ -639,6 +686,16 @@ QPaintDevice* QQuickContext2DImageTexture::beginPainting()
return &m_image;
}
+void QQuickContext2DImageTexture::endPainting()
+{
+ QQuickContext2DTexture::endPainting();
+ if (m_onCustomThread)
+ m_mutex.lock();
+ m_displayImage = m_image;
+ if (m_onCustomThread)
+ m_mutex.unlock();
+}
+
void QQuickContext2DImageTexture::compositeTile(QQuickContext2DTile* tile)
{
Q_ASSERT(!tile->dirty());
diff --git a/src/quick/items/context2d/qquickcontext2dtexture_p.h b/src/quick/items/context2d/qquickcontext2dtexture_p.h
index 2a5b7a318a..cf0e8e3fa9 100644
--- a/src/quick/items/context2d/qquickcontext2dtexture_p.h
+++ b/src/quick/items/context2d/qquickcontext2dtexture_p.h
@@ -58,16 +58,44 @@ QT_BEGIN_NAMESPACE
class QQuickContext2DTile;
class QQuickContext2DCommandBuffer;
-class QQuickContext2DTexture : public QSGDynamicTexture
+class QQuickContext2DTexture : public QObject
{
Q_OBJECT
public:
+ class PaintEvent : public QEvent {
+ public:
+ PaintEvent(QQuickContext2DCommandBuffer *b) : QEvent(QEvent::Type(QEvent::User + 1)), buffer(b) {}
+ QQuickContext2DCommandBuffer *buffer;
+ };
+
+ class CanvasChangeEvent : public QEvent {
+ public:
+ CanvasChangeEvent(const QSize &cSize,
+ const QSize &tSize,
+ const QRect &cWindow,
+ const QRect &dRect,
+ bool sm,
+ bool aa)
+ : QEvent(QEvent::Type(QEvent::User + 2))
+ , canvasSize(cSize)
+ , tileSize(tSize)
+ , canvasWindow(cWindow)
+ , dirtyRect(dRect)
+ , smooth(sm)
+ , antialiasing(aa)
+ {
+ }
+ QSize canvasSize;
+ QSize tileSize;
+ QRect canvasWindow;
+ QRect dirtyRect;
+ bool smooth;
+ bool antialiasing;
+ };
+
QQuickContext2DTexture();
~QQuickContext2DTexture();
- virtual bool hasAlphaChannel() const {return true;}
- virtual bool hasMipmaps() const {return false;}
- virtual QSize textureSize() const;
virtual QQuickCanvasItem::RenderTarget renderTarget() const = 0;
static QRect tiledRect(const QRectF& window, const QSize& tileSize);
@@ -78,15 +106,20 @@ public:
void setAntialiasing(bool antialiasing);
bool setDirtyRect(const QRect &dirtyRect);
bool canvasDestroyed();
+ void setOnCustomThread(bool is) { m_onCustomThread = is; }
+
+ // Called during sync() on the scene graph thread while GUI is blocked.
+ virtual QSGTexture *textureForNextFrame(QSGTexture *lastFrame) = 0;
+ bool event(QEvent *e);
Q_SIGNALS:
void textureChanged();
public Q_SLOTS:
- void markDirtyTexture();
- void setItem(QQuickCanvasItem* item);
void canvasChanged(const QSize& canvasSize, const QSize& tileSize, const QRect& canvasWindow, const QRect& dirtyRect, bool smooth, bool antialiasing);
void paint(QQuickContext2DCommandBuffer *ccb);
+ void markDirtyTexture();
+ void setItem(QQuickCanvasItem* item);
virtual void grabImage(const QRectF& region = QRectF()) = 0;
protected:
@@ -110,13 +143,16 @@ protected:
QSize m_tileSize;
QRect m_canvasWindow;
- uint m_dirtyCanvas : 1;
+ QMutex m_mutex;
+ QWaitCondition m_condition;
+
uint m_canvasWindowChanged : 1;
uint m_dirtyTexture : 1;
uint m_smooth : 1;
uint m_antialiasing : 1;
uint m_tiledCanvas : 1;
uint m_painting : 1;
+ uint m_onCustomThread : 1; // Not GUI and not SGRender
};
class QQuickContext2DFBOTexture : public QQuickContext2DTexture
@@ -126,17 +162,16 @@ class QQuickContext2DFBOTexture : public QQuickContext2DTexture
public:
QQuickContext2DFBOTexture();
~QQuickContext2DFBOTexture();
- virtual int textureId() const;
- virtual bool updateTexture();
virtual QQuickContext2DTile* createTile() const;
virtual QPaintDevice* beginPainting();
virtual void endPainting();
QRectF normalizedTextureSubRect() const;
virtual QQuickCanvasItem::RenderTarget renderTarget() const;
virtual void compositeTile(QQuickContext2DTile* tile);
- virtual void bind();
QSize adjustedTileSize(const QSize &ts);
+ QSGTexture *textureForNextFrame(QSGTexture *);
+
public Q_SLOTS:
virtual void grabImage(const QRectF& region = QRectF());
@@ -144,10 +179,12 @@ private:
bool doMultisampling() const;
QOpenGLFramebufferObject *m_fbo;
QOpenGLFramebufferObject *m_multisampledFbo;
- QMutex m_mutex;
- QWaitCondition m_condition;
QSize m_fboSize;
QPaintDevice *m_paint_device;
+
+
+ GLuint m_displayTextures[2];
+ int m_displayTexture;
};
class QSGPlainTexture;
@@ -158,24 +195,23 @@ class QQuickContext2DImageTexture : public QQuickContext2DTexture
public:
QQuickContext2DImageTexture();
~QQuickContext2DImageTexture();
- virtual int textureId() const;
- virtual void bind();
virtual QQuickCanvasItem::RenderTarget renderTarget() const;
- virtual bool updateTexture();
virtual QQuickContext2DTile* createTile() const;
virtual QPaintDevice* beginPainting();
+ virtual void endPainting();
virtual void compositeTile(QQuickContext2DTile* tile);
+ virtual QSGTexture *textureForNextFrame(QSGTexture *lastFrame);
+
public Q_SLOTS:
virtual void grabImage(const QRectF& region = QRectF());
private:
- QSGPlainTexture *imageTexture() const;
QImage m_image;
+ QImage m_displayImage;
QPainter m_painter;
- QSGPlainTexture* m_texture;
};
QT_END_NAMESPACE
diff --git a/src/quick/items/items.pri b/src/quick/items/items.pri
index 3996512f9d..41cdb3526b 100644
--- a/src/quick/items/items.pri
+++ b/src/quick/items/items.pri
@@ -39,6 +39,7 @@ HEADERS += \
$$PWD/qquickpincharea_p_p.h \
$$PWD/qquickflickable_p.h \
$$PWD/qquickflickable_p_p.h \
+ $$PWD/qquickflickablebehavior_p.h \
$$PWD/qquicklistview_p.h \
$$PWD/qquickrepeater_p.h \
$$PWD/qquickrepeater_p_p.h \
diff --git a/src/quick/items/qquickflickable.cpp b/src/quick/items/qquickflickable.cpp
index f0a68b184a..15627aad84 100644
--- a/src/quick/items/qquickflickable.cpp
+++ b/src/quick/items/qquickflickable.cpp
@@ -41,6 +41,7 @@
#include "qquickflickable_p.h"
#include "qquickflickable_p_p.h"
+#include "qquickflickablebehavior_p.h"
#include "qquickwindow.h"
#include "qquickwindow_p.h"
#include "qquickevents_p_p.h"
@@ -58,52 +59,6 @@
QT_BEGIN_NAMESPACE
-// The maximum number of pixels a flick can overshoot
-#ifndef QML_FLICK_OVERSHOOT
-#define QML_FLICK_OVERSHOOT 150
-#endif
-
-// The number of samples to use in calculating the velocity of a flick
-#ifndef QML_FLICK_SAMPLEBUFFER
-#define QML_FLICK_SAMPLEBUFFER 3
-#endif
-
-// The number of samples to discard when calculating the flick velocity.
-// Touch panels often produce inaccurate results as the finger is lifted.
-#ifndef QML_FLICK_DISCARDSAMPLES
-#define QML_FLICK_DISCARDSAMPLES 0
-#endif
-
-// The default maximum velocity of a flick.
-#ifndef QML_FLICK_DEFAULTMAXVELOCITY
-#define QML_FLICK_DEFAULTMAXVELOCITY 2500
-#endif
-
-// The default deceleration of a flick.
-#ifndef QML_FLICK_DEFAULTDECELERATION
-#define QML_FLICK_DEFAULTDECELERATION 1500
-#endif
-
-// How much faster to decelerate when overshooting
-#ifndef QML_FLICK_OVERSHOOTFRICTION
-#define QML_FLICK_OVERSHOOTFRICTION 8
-#endif
-
-// Multiflick acceleration minimum flick velocity threshold
-#ifndef QML_FLICK_MULTIFLICK_THRESHOLD
-#define QML_FLICK_MULTIFLICK_THRESHOLD 1250
-#endif
-
-// Multiflick acceleration minimum contentSize/viewSize ratio
-#ifndef QML_FLICK_MULTIFLICK_RATIO
-#define QML_FLICK_MULTIFLICK_RATIO 10
-#endif
-
-// Multiflick acceleration maximum velocity multiplier
-#ifndef QML_FLICK_MULTIFLICK_MAXBOOST
-#define QML_FLICK_MULTIFLICK_MAXBOOST 3.0
-#endif
-
// FlickThreshold determines how far the "mouse" must have moved
// before we perform a flick.
static const int FlickThreshold = 15;
@@ -508,16 +463,27 @@ void QQuickFlickablePrivate::fixup(AxisData &data, qreal minExtent, qreal maxExt
data.vTime = timeline.time();
}
+static bool fuzzyLessThanOrEqualTo(qreal a, qreal b)
+{
+ if (a == 0.0 || b == 0.0) {
+ // qFuzzyCompare is broken
+ a += 1.0;
+ b += 1.0;
+ }
+ return a <= b || qFuzzyCompare(a, b);
+}
+
void QQuickFlickablePrivate::updateBeginningEnd()
{
Q_Q(QQuickFlickable);
bool atBoundaryChange = false;
// Vertical
- const int maxyextent = int(-q->maxYExtent());
+ const qreal maxyextent = -q->maxYExtent();
+ const qreal minyextent = -q->minYExtent();
const qreal ypos = -vData.move.value();
- bool atBeginning = (ypos <= -q->minYExtent());
- bool atEnd = (maxyextent <= ypos);
+ bool atBeginning = fuzzyLessThanOrEqualTo(ypos, minyextent);
+ bool atEnd = fuzzyLessThanOrEqualTo(maxyextent, ypos);
if (atBeginning != vData.atBeginning) {
vData.atBeginning = atBeginning;
@@ -529,10 +495,11 @@ void QQuickFlickablePrivate::updateBeginningEnd()
}
// Horizontal
- const int maxxextent = int(-q->maxXExtent());
+ const qreal maxxextent = -q->maxXExtent();
+ const qreal minxextent = -q->minXExtent();
const qreal xpos = -hData.move.value();
- atBeginning = (xpos <= -q->minXExtent());
- atEnd = (maxxextent <= xpos);
+ atBeginning = fuzzyLessThanOrEqualTo(xpos, minxextent);
+ atEnd = fuzzyLessThanOrEqualTo(maxxextent, xpos);
if (atBeginning != hData.atBeginning) {
hData.atBeginning = atBeginning;
@@ -1046,17 +1013,20 @@ void QQuickFlickablePrivate::handleMouseMoveEvent(QMouseEvent *event)
// the estimate to be altered
const qreal minY = vData.dragMinBound + vData.startMargin;
const qreal maxY = vData.dragMaxBound - vData.endMargin;
- if (newY > minY)
- newY = minY + (newY - minY) / 2;
- if (newY < maxY && maxY - minY <= 0)
- newY = maxY + (newY - maxY) / 2;
- if (boundsBehavior == QQuickFlickable::StopAtBounds && newY <= maxY) {
- newY = maxY;
- rejectY = vData.pressPos == maxY && dy < 0;
- }
- if (boundsBehavior == QQuickFlickable::StopAtBounds && newY >= minY) {
- newY = minY;
- rejectY = vData.pressPos == minY && dy > 0;
+ if (boundsBehavior == QQuickFlickable::StopAtBounds) {
+ if (newY <= maxY) {
+ newY = maxY;
+ rejectY = vData.pressPos == maxY && vData.move.value() == maxY && dy < 0;
+ }
+ if (newY >= minY) {
+ newY = minY;
+ rejectY = vData.pressPos == minY && vData.move.value() == minY && dy > 0;
+ }
+ } else {
+ if (newY > minY)
+ newY = minY + (newY - minY) / 2;
+ if (newY < maxY && maxY - minY <= 0)
+ newY = maxY + (newY - maxY) / 2;
}
if (!rejectY && stealMouse && dy != 0.0) {
clearTimeline();
@@ -1077,17 +1047,20 @@ void QQuickFlickablePrivate::handleMouseMoveEvent(QMouseEvent *event)
qreal newX = dx + hData.pressPos - hData.dragStartOffset;
const qreal minX = hData.dragMinBound + hData.startMargin;
const qreal maxX = hData.dragMaxBound - hData.endMargin;
- if (newX > minX)
- newX = minX + (newX - minX) / 2;
- if (newX < maxX && maxX - minX <= 0)
- newX = maxX + (newX - maxX) / 2;
- if (boundsBehavior == QQuickFlickable::StopAtBounds && newX <= maxX) {
- newX = maxX;
- rejectX = hData.pressPos == maxX && dx < 0;
- }
- if (boundsBehavior == QQuickFlickable::StopAtBounds && newX >= minX) {
- newX = minX;
- rejectX = hData.pressPos == minX && dx > 0;
+ if (boundsBehavior == QQuickFlickable::StopAtBounds) {
+ if (newX <= maxX) {
+ newX = maxX;
+ rejectX = hData.pressPos == maxX && hData.move.value() == maxX && dx < 0;
+ }
+ if (newX >= minX) {
+ newX = minX;
+ rejectX = hData.pressPos == minX && hData.move.value() == minX && dx > 0;
+ }
+ } else {
+ if (newX > minX)
+ newX = minX + (newX - minX) / 2;
+ if (newX < maxX && maxX - minX <= 0)
+ newX = maxX + (newX - maxX) / 2;
}
if (!rejectX && stealMouse && dx != 0.0) {
@@ -1116,10 +1089,10 @@ void QQuickFlickablePrivate::handleMouseMoveEvent(QMouseEvent *event)
hData.velocity = 0;
}
- if ((hMoved && !prevHMoved) || (vMoved && !prevVMoved)) {
- draggingStarting();
+ draggingStarting();
+
+ if ((hMoved && !prevHMoved) || (vMoved && !prevVMoved))
q->movementStarting();
- }
qint64 currentTimestamp = computeCurrentTime(event);
qreal elapsed = qreal(currentTimestamp - (lastPos.isNull() ? lastPressTime : lastPosTime)) / 1000.;
diff --git a/src/quick/items/qquickflickablebehavior_p.h b/src/quick/items/qquickflickablebehavior_p.h
new file mode 100644
index 0000000000..317d6512e6
--- /dev/null
+++ b/src/quick/items/qquickflickablebehavior_p.h
@@ -0,0 +1,105 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 Research In Motion.
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QQUICKFLICKABLEBEHAVIOR_H
+#define QQUICKFLICKABLEBEHAVIOR_H
+
+/* ### Platform specific flickable mechanics are defined either here, or in
+ mkspec files. Long-term (QtQuick 3) Flickable needs to allow such
+ mechanic details to be controlled via QML so that platforms can easily
+ load custom behavior at QML compile time.
+*/
+
+// The maximum number of pixels a flick can overshoot
+#ifndef QML_FLICK_OVERSHOOT
+#define QML_FLICK_OVERSHOOT 150
+#endif
+
+// The number of samples to use in calculating the velocity of a flick
+#ifndef QML_FLICK_SAMPLEBUFFER
+#define QML_FLICK_SAMPLEBUFFER 3
+#endif
+
+// The number of samples to discard when calculating the flick velocity.
+// Touch panels often produce inaccurate results as the finger is lifted.
+#ifndef QML_FLICK_DISCARDSAMPLES
+#define QML_FLICK_DISCARDSAMPLES 0
+#endif
+
+// The default maximum velocity of a flick.
+#ifndef QML_FLICK_DEFAULTMAXVELOCITY
+#ifdef Q_OS_BLACKBERRY
+#define QML_FLICK_DEFAULTMAXVELOCITY 10000
+#else
+#define QML_FLICK_DEFAULTMAXVELOCITY 2500
+#endif
+#endif
+
+// The default deceleration of a flick.
+#ifndef QML_FLICK_DEFAULTDECELERATION
+#ifdef Q_OS_BLACKBERRY
+#define QML_FLICK_DEFAULTDECELERATION 5000
+#else
+#define QML_FLICK_DEFAULTDECELERATION 1500
+#endif
+#endif
+
+// How much faster to decelerate when overshooting
+#ifndef QML_FLICK_OVERSHOOTFRICTION
+#define QML_FLICK_OVERSHOOTFRICTION 8
+#endif
+
+// Multiflick acceleration minimum flick velocity threshold
+#ifndef QML_FLICK_MULTIFLICK_THRESHOLD
+#define QML_FLICK_MULTIFLICK_THRESHOLD 1250
+#endif
+
+// Multiflick acceleration minimum contentSize/viewSize ratio
+#ifndef QML_FLICK_MULTIFLICK_RATIO
+#define QML_FLICK_MULTIFLICK_RATIO 10
+#endif
+
+// Multiflick acceleration maximum velocity multiplier
+#ifndef QML_FLICK_MULTIFLICK_MAXBOOST
+#define QML_FLICK_MULTIFLICK_MAXBOOST 3.0
+#endif
+
+#endif //QQUICKFLICKABLEBEHAVIOR_H
diff --git a/src/quick/items/qquickitem_p.h b/src/quick/items/qquickitem_p.h
index 7faf39f8e5..44eabcf0d5 100644
--- a/src/quick/items/qquickitem_p.h
+++ b/src/quick/items/qquickitem_p.h
@@ -449,7 +449,7 @@ public:
// dirtyToString()
TransformUpdateMask = TransformOrigin | Transform | BasicTransform | Position |
- Size | Window,
+ Window,
ComplexTransformUpdateMask = Transform | Window,
ContentUpdateMask = Size | Content | Smooth | Window | Antialiasing,
ChildrenUpdateMask = ChildrenChanged | ChildrenStackingChanged | EffectReference | Window
diff --git a/src/quick/items/qquickitemview.cpp b/src/quick/items/qquickitemview.cpp
index 513f8f3857..d9ff024d9f 100644
--- a/src/quick/items/qquickitemview.cpp
+++ b/src/quick/items/qquickitemview.cpp
@@ -1118,11 +1118,13 @@ void QQuickItemViewPrivate::itemGeometryChanged(QQuickItem *item, const QRectF &
if (header && header->item == item) {
updateHeader();
markExtentsDirty();
+ updateViewport();
if (!q->isMoving() && !q->isFlicking())
fixupPosition();
} else if (footer && footer->item == item) {
updateFooter();
markExtentsDirty();
+ updateViewport();
if (!q->isMoving() && !q->isFlicking())
fixupPosition();
}
diff --git a/src/quick/items/qquickitemview_p.h b/src/quick/items/qquickitemview_p.h
index 318f5361b5..17d150f480 100644
--- a/src/quick/items/qquickitemview_p.h
+++ b/src/quick/items/qquickitemview_p.h
@@ -324,6 +324,21 @@ public:
}
}
+ void setSections(const QString &prev, const QString &sect, const QString &next) {
+ bool prevChanged = prev != m_prevSection;
+ bool sectChanged = sect != m_section;
+ bool nextChanged = next != m_nextSection;
+ m_prevSection = prev;
+ m_section = sect;
+ m_nextSection = next;
+ if (prevChanged)
+ Q_EMIT prevSectionChanged();
+ if (sectChanged)
+ Q_EMIT sectionChanged();
+ if (nextChanged)
+ Q_EMIT nextSectionChanged();
+ }
+
void emitAdd() { Q_EMIT add(); }
void emitRemove() { Q_EMIT remove(); }
diff --git a/src/quick/items/qquicklistview.cpp b/src/quick/items/qquicklistview.cpp
index c55f9ef696..424b5ac385 100644
--- a/src/quick/items/qquicklistview.cpp
+++ b/src/quick/items/qquicklistview.cpp
@@ -143,7 +143,8 @@ public:
QQuickListView::SnapMode snapMode;
QSmoothedAnimation *highlightPosAnimator;
- QSmoothedAnimation *highlightSizeAnimator;
+ QSmoothedAnimation *highlightWidthAnimator;
+ QSmoothedAnimation *highlightHeightAnimator;
qreal highlightMoveVelocity;
qreal highlightResizeVelocity;
int highlightResizeDuration;
@@ -168,7 +169,7 @@ public:
, visiblePos(0)
, averageSize(100.0), spacing(0.0)
, snapMode(QQuickListView::NoSnap)
- , highlightPosAnimator(0), highlightSizeAnimator(0)
+ , highlightPosAnimator(0), highlightWidthAnimator(0), highlightHeightAnimator(0)
, highlightMoveVelocity(400), highlightResizeVelocity(400), highlightResizeDuration(-1)
, sectionCriteria(0), currentSectionItem(0), nextSectionItem(0)
, overshootDist(0.0), correctFlick(false), inFlickCorrection(false)
@@ -177,7 +178,8 @@ public:
}
~QQuickListViewPrivate() {
delete highlightPosAnimator;
- delete highlightSizeAnimator;
+ delete highlightWidthAnimator;
+ delete highlightHeightAnimator;
}
friend class QQuickViewSection;
@@ -487,7 +489,7 @@ QString QQuickListViewPrivate::sectionAt(int modelIndex)
return item->attached->section();
QString section;
- if (sectionCriteria) {
+ if (sectionCriteria && modelIndex >= 0 && modelIndex < itemCount) {
QString propValue = model->stringValue(modelIndex, sectionCriteria->property());
section = sectionCriteria->sectionString(propValue);
}
@@ -565,19 +567,19 @@ FxViewItem *QQuickListViewPrivate::newViewItem(int modelIndex, QQuickItem *item)
// initialise attached properties
if (sectionCriteria) {
QString propValue = model->stringValue(modelIndex, sectionCriteria->property());
- listItem->attached->setSection(sectionCriteria->sectionString(propValue));
+ QString section = sectionCriteria->sectionString(propValue);
+ QString prevSection;
+ QString nextSection;
if (modelIndex > 0) {
if (FxViewItem *item = itemBefore(modelIndex))
- listItem->attached->setPrevSection(item->attached->section());
+ prevSection = item->attached->section();
else
- listItem->attached->setPrevSection(sectionAt(modelIndex-1));
+ prevSection = sectionAt(modelIndex-1);
}
if (modelIndex < model->count()-1) {
- if (FxViewItem *item = visibleItem(modelIndex+1))
- listItem->attached->setNextSection(static_cast<QQuickListViewAttached*>(item->attached)->section());
- else
- listItem->attached->setNextSection(sectionAt(modelIndex+1));
+ nextSection = sectionAt(modelIndex+1);
}
+ listItem->attached->setSections(prevSection, section, nextSection);
}
return listItem;
@@ -855,9 +857,11 @@ void QQuickListViewPrivate::createHighlight()
highlight = 0;
delete highlightPosAnimator;
- delete highlightSizeAnimator;
+ delete highlightWidthAnimator;
+ delete highlightHeightAnimator;
highlightPosAnimator = 0;
- highlightSizeAnimator = 0;
+ highlightWidthAnimator = 0;
+ highlightHeightAnimator = 0;
changed = true;
}
@@ -878,11 +882,15 @@ void QQuickListViewPrivate::createHighlight()
highlightPosAnimator->velocity = highlightMoveVelocity;
highlightPosAnimator->userDuration = highlightMoveDuration;
- const QLatin1String sizeProp(orient == QQuickListView::Vertical ? "height" : "width");
- highlightSizeAnimator = new QSmoothedAnimation;
- highlightSizeAnimator->velocity = highlightResizeVelocity;
- highlightSizeAnimator->userDuration = highlightResizeDuration;
- highlightSizeAnimator->target = QQmlProperty(item, sizeProp);
+ highlightWidthAnimator = new QSmoothedAnimation;
+ highlightWidthAnimator->velocity = highlightResizeVelocity;
+ highlightWidthAnimator->userDuration = highlightResizeDuration;
+ highlightWidthAnimator->target = QQmlProperty(item, "width");
+
+ highlightHeightAnimator = new QSmoothedAnimation;
+ highlightHeightAnimator->velocity = highlightResizeVelocity;
+ highlightHeightAnimator->userDuration = highlightResizeDuration;
+ highlightHeightAnimator->target = QQmlProperty(item, "height");
highlight = newHighlight;
changed = true;
@@ -905,7 +913,8 @@ void QQuickListViewPrivate::updateHighlight()
highlightPosAnimator->to = isContentFlowReversed()
? -listItem->itemPosition()-listItem->itemSize()
: listItem->itemPosition();
- highlightSizeAnimator->to = listItem->itemSize();
+ highlightWidthAnimator->to = listItem->item->width();
+ highlightHeightAnimator->to = listItem->item->height();
if (orient == QQuickListView::Vertical) {
if (highlight->item->width() == 0)
highlight->item->setWidth(currentItem->item->width());
@@ -915,7 +924,8 @@ void QQuickListViewPrivate::updateHighlight()
}
highlightPosAnimator->restart();
- highlightSizeAnimator->restart();
+ highlightWidthAnimator->restart();
+ highlightHeightAnimator->restart();
}
updateTrackedItem();
}
@@ -1968,8 +1978,10 @@ void QQuickListView::setHighlightFollowsCurrentItem(bool autoHighlight)
if (!autoHighlight) {
if (d->highlightPosAnimator)
d->highlightPosAnimator->stop();
- if (d->highlightSizeAnimator)
- d->highlightSizeAnimator->stop();
+ if (d->highlightWidthAnimator)
+ d->highlightWidthAnimator->stop();
+ if (d->highlightHeightAnimator)
+ d->highlightHeightAnimator->stop();
}
QQuickItemView::setHighlightFollowsCurrentItem(autoHighlight);
}
@@ -2271,8 +2283,10 @@ void QQuickListView::setHighlightResizeVelocity(qreal speed)
Q_D(QQuickListView);
if (d->highlightResizeVelocity != speed) {
d->highlightResizeVelocity = speed;
- if (d->highlightSizeAnimator)
- d->highlightSizeAnimator->velocity = d->highlightResizeVelocity;
+ if (d->highlightWidthAnimator)
+ d->highlightWidthAnimator->velocity = d->highlightResizeVelocity;
+ if (d->highlightHeightAnimator)
+ d->highlightHeightAnimator->velocity = d->highlightResizeVelocity;
emit highlightResizeVelocityChanged();
}
}
@@ -2288,8 +2302,10 @@ void QQuickListView::setHighlightResizeDuration(int duration)
Q_D(QQuickListView);
if (d->highlightResizeDuration != duration) {
d->highlightResizeDuration = duration;
- if (d->highlightSizeAnimator)
- d->highlightSizeAnimator->userDuration = d->highlightResizeDuration;
+ if (d->highlightWidthAnimator)
+ d->highlightWidthAnimator->userDuration = d->highlightResizeDuration;
+ if (d->highlightHeightAnimator)
+ d->highlightHeightAnimator->userDuration = d->highlightResizeDuration;
emit highlightResizeDurationChanged();
}
}
diff --git a/src/quick/items/qquickloader.cpp b/src/quick/items/qquickloader.cpp
index 7d04be2393..b83c21428c 100644
--- a/src/quick/items/qquickloader.cpp
+++ b/src/quick/items/qquickloader.cpp
@@ -106,6 +106,7 @@ void QQuickLoaderPrivate::clear()
component->deleteLater();
component = 0;
}
+ componentStrongReference.clear();
source = QUrl();
if (item) {
@@ -472,6 +473,10 @@ void QQuickLoader::setSourceComponent(QQmlComponent *comp)
d->clear();
d->component = comp;
+ if (comp) {
+ if (QQmlData *ddata = QQmlData::get(comp))
+ d->componentStrongReference = ddata->jsWrapper.value();
+ }
d->loadingFromSource = false;
if (d->active)
diff --git a/src/quick/items/qquickloader_p_p.h b/src/quick/items/qquickloader_p_p.h
index 9c94b4ce38..32c271222d 100644
--- a/src/quick/items/qquickloader_p_p.h
+++ b/src/quick/items/qquickloader_p_p.h
@@ -106,6 +106,7 @@ public:
QQuickItem *item;
QObject *object;
QQmlComponent *component;
+ QV4::PersistentValue componentStrongReference; // To ensure GC doesn't delete components created by Qt.createComponent
QQmlContext *itemContext;
QQuickLoaderIncubator *incubator;
QV4::PersistentValue initialPropertyValues;
diff --git a/src/quick/items/qquickmousearea.cpp b/src/quick/items/qquickmousearea.cpp
index ca64ebb6e3..2467d7252a 100644
--- a/src/quick/items/qquickmousearea.cpp
+++ b/src/quick/items/qquickmousearea.cpp
@@ -823,6 +823,12 @@ void QQuickMouseArea::ungrabMouse()
d->pressed = 0;
d->stealMouse = false;
setKeepMouseGrab(false);
+
+#ifndef QT_NO_DRAGANDDROP
+ if (d->drag)
+ d->drag->setActive(false);
+#endif
+
emit canceled();
emit pressedChanged();
emit pressedButtonsChanged();
diff --git a/src/quick/items/qquickpathview.cpp b/src/quick/items/qquickpathview.cpp
index 1f41fe04e5..0080f54d20 100644
--- a/src/quick/items/qquickpathview.cpp
+++ b/src/quick/items/qquickpathview.cpp
@@ -42,6 +42,7 @@
#include "qquickpathview_p.h"
#include "qquickpathview_p_p.h"
#include "qquickwindow.h"
+#include "qquickflickablebehavior_p.h" //Contains flicking behavior defines
#include <QtQuick/private/qquickstate_p.h>
#include <private/qqmlglobal_p.h>
@@ -56,22 +57,6 @@
#include <QtCore/qmath.h>
#include <math.h>
-// The number of samples to use in calculating the velocity of a flick
-#ifndef QML_FLICK_SAMPLEBUFFER
-#define QML_FLICK_SAMPLEBUFFER 1
-#endif
-
-// The number of samples to discard when calculating the flick velocity.
-// Touch panels often produce inaccurate results as the finger is lifted.
-#ifndef QML_FLICK_DISCARDSAMPLES
-#define QML_FLICK_DISCARDSAMPLES 0
-#endif
-
-// The default maximum velocity of a flick.
-#ifndef QML_FLICK_DEFAULTMAXVELOCITY
-#define QML_FLICK_DEFAULTMAXVELOCITY 2500
-#endif
-
QT_BEGIN_NAMESPACE
diff --git a/src/quick/items/qquickshadereffect.cpp b/src/quick/items/qquickshadereffect.cpp
index 9c766a1622..9a20703f18 100644
--- a/src/quick/items/qquickshadereffect.cpp
+++ b/src/quick/items/qquickshadereffect.cpp
@@ -559,6 +559,7 @@ void QQuickShaderEffectCommon::propertyChanged(QQuickItem *item, int mappedId,
\li QVector4D -> vec4
\li QTransform -> mat3
\li QMatrix4x4 -> mat4
+ \li QQuaternion -> vec4, scalar value is \c w.
\li \l Image, \l ShaderEffectSource -> sampler2D - Origin is in the top-left
corner, and the color values are premultiplied.
\endlist
diff --git a/src/quick/items/qquickshadereffectnode.cpp b/src/quick/items/qquickshadereffectnode.cpp
index 8788fa8362..a615cb6f91 100644
--- a/src/quick/items/qquickshadereffectnode.cpp
+++ b/src/quick/items/qquickshadereffectnode.cpp
@@ -146,7 +146,6 @@ void QQuickCustomMaterialShader::updateState(const RenderState &state, QSGMateri
continue;
}
}
- qWarning("ShaderEffect: source or provider missing when binding textures");
glBindTexture(GL_TEXTURE_2D, 0);
} else if (d.specialType == UniformData::Opacity) {
program()->setUniformValue(loc, state.opacity());
@@ -197,6 +196,12 @@ void QQuickCustomMaterialShader::updateState(const RenderState &state, QSGMateri
case QMetaType::QVector4D:
program()->setUniformValue(loc, qvariant_cast<QVector4D>(d.value));
break;
+ case QMetaType::QQuaternion:
+ {
+ QQuaternion q = qvariant_cast<QQuaternion>(d.value);
+ program()->setUniformValue(loc, q.x(), q.y(), q.z(), q.scalar());
+ }
+ break;
case QMetaType::QMatrix4x4:
program()->setUniformValue(loc, qvariant_cast<QMatrix4x4>(d.value));
break;
diff --git a/src/quick/items/qquicktextinput.cpp b/src/quick/items/qquicktextinput.cpp
index b46387ba47..1dd1dfa57e 100644
--- a/src/quick/items/qquicktextinput.cpp
+++ b/src/quick/items/qquicktextinput.cpp
@@ -1679,6 +1679,7 @@ bool QQuickTextInput::event(QEvent* ev)
|| ke == QKeySequence::SelectAll
|| ke == QKeySequence::SelectEndOfDocument) {
ke->accept();
+ return true;
} else if (ke->modifiers() == Qt::NoModifier || ke->modifiers() == Qt::ShiftModifier
|| ke->modifiers() == Qt::KeypadModifier) {
if (ke->key() < Qt::Key_Escape) {
@@ -1692,6 +1693,7 @@ bool QQuickTextInput::event(QEvent* ev)
case Qt::Key_Backspace:
case Qt::Key_Left:
case Qt::Key_Right:
+ ke->accept();
return true;
default:
break;
@@ -2533,7 +2535,7 @@ void QQuickTextInputPrivate::handleFocusEvent(QFocusEvent *event)
&& !persistentSelection)
deselect();
- if (hasAcceptableInput(m_text) || fixup())
+ if (q->hasAcceptableInput() || fixup())
emit q->editingFinished();
#ifndef QT_NO_IM
@@ -3392,7 +3394,6 @@ bool QQuickTextInputPrivate::finishChange(int validateFromState, bool update, bo
*/
void QQuickTextInputPrivate::internalSetText(const QString &txt, int pos, bool edited)
{
- Q_Q(QQuickTextInput);
internalDeselect();
QString oldText = m_text;
if (m_maskData) {
@@ -3410,6 +3411,7 @@ void QQuickTextInputPrivate::internalSetText(const QString &txt, int pos, bool e
#ifdef QT_NO_ACCESSIBILITY
Q_UNUSED(changed)
#else
+ Q_Q(QQuickTextInput);
if (changed && QAccessible::isActive()) {
if (QObject *acc = QQuickAccessibleAttached::findAccessible(q, QAccessible::EditableText)) {
QAccessibleTextUpdateEvent ev(acc, 0, oldText, m_text);
@@ -4117,7 +4119,7 @@ void QQuickTextInputPrivate::processKeyEvent(QKeyEvent* event)
Q_Q(QQuickTextInput);
if (event->key() == Qt::Key_Enter || event->key() == Qt::Key_Return) {
- if (hasAcceptableInput(m_text) || fixup()) {
+ if (q->hasAcceptableInput() || fixup()) {
emit q->accepted();
emit q->editingFinished();
}
diff --git a/src/quick/items/qquickwindow.cpp b/src/quick/items/qquickwindow.cpp
index 848eeca2a6..dfc70d7e68 100644
--- a/src/quick/items/qquickwindow.cpp
+++ b/src/quick/items/qquickwindow.cpp
@@ -660,19 +660,24 @@ void QQuickWindowPrivate::setFocusInScope(QQuickItem *scope, QQuickItem *item, Q
QQuickItemPrivate *scopePrivate = scope ? QQuickItemPrivate::get(scope) : 0;
QQuickItemPrivate *itemPrivate = QQuickItemPrivate::get(item);
+ QQuickItem *currentActiveFocusItem = activeFocusItem;
QQuickItem *newActiveFocusItem = 0;
QVarLengthArray<QQuickItem *, 20> changed;
// Does this change the active focus?
- if (item == contentItem || (scopePrivate->activeFocus && item->isEnabled())) {
+ if (item == contentItem || scopePrivate->activeFocus) {
QQuickItem *oldActiveFocusItem = 0;
oldActiveFocusItem = activeFocusItem;
- newActiveFocusItem = item;
- while (newActiveFocusItem->isFocusScope()
- && newActiveFocusItem->scopedFocusItem()
- && newActiveFocusItem->scopedFocusItem()->isEnabled()) {
- newActiveFocusItem = newActiveFocusItem->scopedFocusItem();
+ if (item->isEnabled()) {
+ newActiveFocusItem = item;
+ while (newActiveFocusItem->isFocusScope()
+ && newActiveFocusItem->scopedFocusItem()
+ && newActiveFocusItem->scopedFocusItem()->isEnabled()) {
+ newActiveFocusItem = newActiveFocusItem->scopedFocusItem();
+ }
+ } else {
+ newActiveFocusItem = scope;
}
if (oldActiveFocusItem) {
@@ -732,7 +737,8 @@ void QQuickWindowPrivate::setFocusInScope(QQuickItem *scope, QQuickItem *item, Q
q->sendEvent(newActiveFocusItem, &event);
}
- emit q->focusObjectChanged(activeFocusItem);
+ if (activeFocusItem != currentActiveFocusItem)
+ emit q->focusObjectChanged(activeFocusItem);
if (!changed.isEmpty())
notifyFocusChangesRecur(changed.data(), changed.count() - 1);
@@ -759,6 +765,7 @@ void QQuickWindowPrivate::clearFocusInScope(QQuickItem *scope, QQuickItem *item,
return;//No focus, nothing to do.
}
+ QQuickItem *currentActiveFocusItem = activeFocusItem;
QQuickItem *oldActiveFocusItem = 0;
QQuickItem *newActiveFocusItem = 0;
@@ -815,7 +822,8 @@ void QQuickWindowPrivate::clearFocusInScope(QQuickItem *scope, QQuickItem *item,
q->sendEvent(newActiveFocusItem, &event);
}
- emit q->focusObjectChanged(activeFocusItem);
+ if (activeFocusItem != currentActiveFocusItem)
+ emit q->focusObjectChanged(activeFocusItem);
if (!changed.isEmpty())
notifyFocusChangesRecur(changed.data(), changed.count() - 1);
@@ -2281,6 +2289,8 @@ void QQuickWindowPrivate::cleanupNodesOnShutdown(QQuickItem *item)
p->groupNode = 0;
p->paintNode = 0;
+
+ p->dirty(QQuickItemPrivate::Window);
}
for (int ii = 0; ii < p->childItems.count(); ++ii)
@@ -2795,6 +2805,7 @@ QImage QQuickWindow::grabWindow()
QOpenGLContext context;
context.setFormat(requestedFormat());
+ context.setShareContext(QSGContext::sharedOpenGLContext());
context.create();
context.makeCurrent(this);
d->context->initialize(&context);
diff --git a/src/quick/scenegraph/coreapi/qsgbatchrenderer.cpp b/src/quick/scenegraph/coreapi/qsgbatchrenderer.cpp
index 676efe84bc..8ff68e20bc 100644
--- a/src/quick/scenegraph/coreapi/qsgbatchrenderer.cpp
+++ b/src/quick/scenegraph/coreapi/qsgbatchrenderer.cpp
@@ -2115,6 +2115,9 @@ void Renderer::renderUnmergedBatch(const Batch *batch)
offset += a.tupleSize * size_of_type(a.type);
}
+ if (g->drawingMode() == GL_LINE_STRIP || g->drawingMode() == GL_LINE_LOOP || g->drawingMode() == GL_LINES)
+ glLineWidth(g->lineWidth());
+
if (g->indexCount())
glDrawElements(g->drawingMode(), g->indexCount(), g->indexType(), iOffset);
else
diff --git a/src/quick/scenegraph/coreapi/qsgrenderer.cpp b/src/quick/scenegraph/coreapi/qsgrenderer.cpp
index 3c9c353bd8..df70b5c5eb 100644
--- a/src/quick/scenegraph/coreapi/qsgrenderer.cpp
+++ b/src/quick/scenegraph/coreapi/qsgrenderer.cpp
@@ -61,7 +61,7 @@ QT_BEGIN_NAMESPACE
//#define RENDERER_DEBUG
//#define QT_GL_NO_SCISSOR_TEST
-
+static bool qsg_sanity_check = qgetenv("QSG_SANITY_CHECK").toInt();
#ifndef QSG_NO_RENDER_TIMING
static bool qsg_render_timing = !qgetenv("QSG_RENDER_TIMING").isEmpty();
@@ -243,9 +243,8 @@ void QSGRenderer::renderScene(const QSGBindable &bindable)
bindTime = frameTimer.nsecsElapsed();
#endif
-#ifndef QT_NO_DEBUG
// Sanity check that attribute registers are disabled
- {
+ if (qsg_sanity_check) {
GLint count = 0;
glGetIntegerv(GL_MAX_VERTEX_ATTRIBS, &count);
GLint enabled;
@@ -256,7 +255,6 @@ void QSGRenderer::renderScene(const QSGBindable &bindable)
}
}
}
-#endif
render();
#ifndef QSG_NO_RENDER_TIMING
diff --git a/src/quick/scenegraph/qsgcontext.cpp b/src/quick/scenegraph/qsgcontext.cpp
index afde7939f2..90803db9fe 100644
--- a/src/quick/scenegraph/qsgcontext.cpp
+++ b/src/quick/scenegraph/qsgcontext.cpp
@@ -454,6 +454,8 @@ void QSGRenderContext::initialize(QOpenGLContext *context)
const char *renderer = (const char *) glGetString(GL_RENDERER);
if (strstr(renderer, "llvmpipe"))
m_serializedRender = true;
+ if (strstr(vendor, "Hisilicon Technologies") && strstr(renderer, "Immersion.16"))
+ m_brokenIBOs = true;
#endif
emit initialized();
diff --git a/src/quick/scenegraph/qsgrenderloop.cpp b/src/quick/scenegraph/qsgrenderloop.cpp
index aa0d7b5a6c..ac1bdb7841 100644
--- a/src/quick/scenegraph/qsgrenderloop.cpp
+++ b/src/quick/scenegraph/qsgrenderloop.cpp
@@ -122,6 +122,7 @@ public:
QSGRenderContext *rc;
QImage grabContent;
+ int m_update_timer;
bool eventPending;
};
@@ -237,6 +238,8 @@ void QSGGuiThreadRenderLoop::hide(QQuickWindow *window)
m_windows.remove(window);
QQuickWindowPrivate *cd = QQuickWindowPrivate::get(window);
+ if (gl)
+ gl->makeCurrent(window);
cd->cleanupNodesOnShutdown();
if (m_windows.size() == 0) {
@@ -384,7 +387,8 @@ void QSGGuiThreadRenderLoop::maybeUpdate(QQuickWindow *window)
m_windows[window].updatePending = true;
if (!eventPending) {
- QCoreApplication::postEvent(this, new QEvent(QEvent::User));
+ const int exhaust_delay = 5;
+ m_update_timer = startTimer(exhaust_delay, Qt::PreciseTimer);
eventPending = true;
}
}
@@ -399,8 +403,10 @@ QSGContext *QSGGuiThreadRenderLoop::sceneGraphContext() const
bool QSGGuiThreadRenderLoop::event(QEvent *e)
{
- if (e->type() == QEvent::User) {
+ if (e->type() == QEvent::Timer) {
eventPending = false;
+ killTimer(m_update_timer);
+ m_update_timer = 0;
for (QHash<QQuickWindow *, WindowData>::const_iterator it = m_windows.constBegin();
it != m_windows.constEnd(); ++it) {
const WindowData &data = it.value();
diff --git a/src/quick/scenegraph/qsgthreadedrenderloop.cpp b/src/quick/scenegraph/qsgthreadedrenderloop.cpp
index 47c2d36d2c..d779285a44 100644
--- a/src/quick/scenegraph/qsgthreadedrenderloop.cpp
+++ b/src/quick/scenegraph/qsgthreadedrenderloop.cpp
@@ -397,6 +397,7 @@ bool QSGRenderThread::event(QEvent *e)
case WM_TryRelease: {
QSG_RT_DEBUG("WM_TryRelease");
mutex.lock();
+ wm->m_locked = true;
WMTryReleaseEvent *wme = static_cast<WMTryReleaseEvent *>(e);
if (!window || wme->inDestructor) {
QSG_RT_DEBUG(" - setting exit flag and invalidating GL");
@@ -408,6 +409,7 @@ bool QSGRenderThread::event(QEvent *e)
QSG_RT_DEBUG(" - not releasing anything because we have active windows...");
}
waitCondition.wakeOne();
+ wm->m_locked = false;
mutex.unlock();
return true;
}
@@ -690,7 +692,7 @@ QSGThreadedRenderLoop::QSGThreadedRenderLoop()
: sg(QSGContext::createDefaultContext())
, m_animation_timer(0)
{
-#if defined(QSG_RENDER_LOOP_DEBUG_BASIC) || defined (QSG_RENDER_LOOP_DEBUG_FULL)
+#if defined(QSG_RENDER_LOOP_DEBUG)
qsgrl_timer.start();
#endif
@@ -978,6 +980,9 @@ void QSGThreadedRenderLoop::maybeUpdate(QQuickWindow *window)
*/
void QSGThreadedRenderLoop::maybeUpdate(Window *w)
{
+ if (!QCoreApplication::instance())
+ return;
+
Q_ASSERT_X(QThread::currentThread() == QCoreApplication::instance()->thread() || m_locked,
"QQuickItem::update()",
"Function can only be called from GUI thread or during QQuickItem::updatePaintNode()");
diff --git a/src/quick/scenegraph/qsgwindowsrenderloop.cpp b/src/quick/scenegraph/qsgwindowsrenderloop.cpp
index 0c128d5cae..0b6d42aca6 100644
--- a/src/quick/scenegraph/qsgwindowsrenderloop.cpp
+++ b/src/quick/scenegraph/qsgwindowsrenderloop.cpp
@@ -240,7 +240,11 @@ void QSGWindowsRenderLoop::hide(QQuickWindow *window)
if (window->isExposed())
handleObscurity();
+ if (!m_gl)
+ return;
+
QQuickWindowPrivate *cd = QQuickWindowPrivate::get(window);
+ m_gl->makeCurrent(window);
cd->cleanupNodesOnShutdown();
// If this is the last tracked window, check for persistent SG and GL and
diff --git a/src/quick/scenegraph/shaders/distancefieldshiftedtext.frag b/src/quick/scenegraph/shaders/distancefieldshiftedtext.frag
index 60c1c7468b..42fead8713 100644
--- a/src/quick/scenegraph/shaders/distancefieldshiftedtext.frag
+++ b/src/quick/scenegraph/shaders/distancefieldshiftedtext.frag
@@ -1,7 +1,7 @@
varying highp vec2 sampleCoord;
varying highp vec2 shiftedSampleCoord;
-uniform sampler2D _qt_texture;
+uniform mediump sampler2D _qt_texture;
uniform lowp vec4 color;
uniform lowp vec4 styleColor;
uniform mediump float alphaMin;
diff --git a/src/quick/scenegraph/util/qsgatlastexture.cpp b/src/quick/scenegraph/util/qsgatlastexture.cpp
index 8678d106ff..75bf0b6e3c 100644
--- a/src/quick/scenegraph/util/qsgatlastexture.cpp
+++ b/src/quick/scenegraph/util/qsgatlastexture.cpp
@@ -448,6 +448,7 @@ QSGTexture *Texture::removedFromAtlas() const
if (!m_nonatlas_texture) {
m_nonatlas_texture = new QSGPlainTexture();
m_nonatlas_texture->setImage(m_image);
+ m_nonatlas_texture->setFiltering(filtering());
}
return m_nonatlas_texture;
}
diff --git a/src/quick/util/qquickapplication.cpp b/src/quick/util/qquickapplication.cpp
index 244e13888c..fb7c900252 100644
--- a/src/quick/util/qquickapplication.cpp
+++ b/src/quick/util/qquickapplication.cpp
@@ -123,7 +123,7 @@ bool QQuickApplication::eventFilter(QObject *, QEvent *event)
if (d->isActive != wasActive) {
emit activeChanged();
}
- } else if (event->type() == QEvent::LayoutDirectionChange) {
+ } else if (event->type() == QEvent::ApplicationLayoutDirectionChange) {
Qt::LayoutDirection newDirection = QGuiApplication::layoutDirection();
if (d->direction != newDirection) {
d->direction = newDirection;
diff --git a/src/quick/util/qquickpixmapcache.cpp b/src/quick/util/qquickpixmapcache.cpp
index 082d640ab9..055d6b7e29 100644
--- a/src/quick/util/qquickpixmapcache.cpp
+++ b/src/quick/util/qquickpixmapcache.cpp
@@ -519,6 +519,9 @@ void QQuickPixmapReader::processJobs()
runningJob->loading = true;
QUrl url = runningJob->url;
+ QQmlPixmapProfiler pixmapProfiler;
+ pixmapProfiler.startLoading(url);
+
QSize requestSize = runningJob->requestSize;
locker.unlock();
processJob(runningJob, url, requestSize);
@@ -897,8 +900,7 @@ bool QQuickPixmapReply::event(QEvent *event)
pixmapProfiler.finishLoading(data->url);
data->textureFactory = de->textureFactory;
data->implicitSize = de->implicitSize;
- if (data->implicitSize.width() > 0)
- pixmapProfiler.setSize(url, data->implicitSize.width(), data->implicitSize.height());
+ pixmapProfiler.setSize(url, data->requestSize.width() > 0 ? data->requestSize : data->implicitSize);
} else {
pixmapProfiler.errorLoading(data->url);
data->errorString = de->errorString;
@@ -968,8 +970,6 @@ void QQuickPixmapData::addToCache()
inCache = true;
QQmlPixmapProfiler pixmapProfiler;
pixmapProfiler.cacheCountChanged(url, pixmapStore()->m_cache.count());
- if (implicitSize.width() > 0)
- pixmapProfiler.setSize(url, implicitSize.width(), implicitSize.height());
}
}
@@ -1245,8 +1245,7 @@ void QQuickPixmap::load(QQmlEngine *engine, const QUrl &url, const QSize &reques
d = createPixmapDataSync(this, engine, url, requestSize, &ok);
if (ok) {
pixmapProfiler.finishLoading(url);
- if (d->implicitSize.width() > 0)
- QQmlPixmapProfiler().setSize(url, d->implicitSize.width(), d->implicitSize.height());
+ pixmapProfiler.setSize(url, d->requestSize.width() > 0 ? d->requestSize : d->implicitSize);
if (options & QQuickPixmap::Cache)
d->addToCache();
return;
diff --git a/src/quick/util/qquicksmoothedanimation.cpp b/src/quick/util/qquicksmoothedanimation.cpp
index 017fe39003..9e9e6cb419 100644
--- a/src/quick/util/qquicksmoothedanimation.cpp
+++ b/src/quick/util/qquicksmoothedanimation.cpp
@@ -242,6 +242,9 @@ qreal QSmoothedAnimation::easeFollow(qreal time_seconds)
void QSmoothedAnimation::updateCurrentTime(int t)
{
+ if (!isRunning() && !isPaused()) // This can happen if init() stops the animation in some cases
+ return;
+
qreal time_seconds = useDelta ? qreal(QQmlAnimationTimer::instance()->currentDelta()) / 1000. : qreal(t - lastTime) / 1000.;
if (useDelta)
useDelta = false;
diff --git a/src/quick/util/qquickvaluetypes_p.h b/src/quick/util/qquickvaluetypes_p.h
index 88570f3b6e..94db7a8729 100644
--- a/src/quick/util/qquickvaluetypes_p.h
+++ b/src/quick/util/qquickvaluetypes_p.h
@@ -64,10 +64,10 @@ void registerValueTypes();
class Q_AUTOTEST_EXPORT QQuickColorValueType : public QQmlValueTypeBase<QColor>
{
- Q_PROPERTY(qreal r READ r WRITE setR)
- Q_PROPERTY(qreal g READ g WRITE setG)
- Q_PROPERTY(qreal b READ b WRITE setB)
- Q_PROPERTY(qreal a READ a WRITE setA)
+ Q_PROPERTY(qreal r READ r WRITE setR FINAL)
+ Q_PROPERTY(qreal g READ g WRITE setG FINAL)
+ Q_PROPERTY(qreal b READ b WRITE setB FINAL)
+ Q_PROPERTY(qreal a READ a WRITE setA FINAL)
Q_OBJECT
public:
QQuickColorValueType(QObject *parent = 0);
@@ -86,8 +86,8 @@ public:
class Q_AUTOTEST_EXPORT QQuickVector2DValueType : public QQmlValueTypeBase<QVector2D>
{
- Q_PROPERTY(qreal x READ x WRITE setX)
- Q_PROPERTY(qreal y READ y WRITE setY)
+ Q_PROPERTY(qreal x READ x WRITE setX FINAL)
+ Q_PROPERTY(qreal y READ y WRITE setY FINAL)
Q_OBJECT
public:
QQuickVector2DValueType(QObject *parent = 0);
@@ -115,9 +115,9 @@ public:
class Q_AUTOTEST_EXPORT QQuickVector3DValueType : public QQmlValueTypeBase<QVector3D>
{
- Q_PROPERTY(qreal x READ x WRITE setX)
- Q_PROPERTY(qreal y READ y WRITE setY)
- Q_PROPERTY(qreal z READ z WRITE setZ)
+ Q_PROPERTY(qreal x READ x WRITE setX FINAL)
+ Q_PROPERTY(qreal y READ y WRITE setY FINAL)
+ Q_PROPERTY(qreal z READ z WRITE setZ FINAL)
Q_OBJECT
public:
QQuickVector3DValueType(QObject *parent = 0);
@@ -149,10 +149,10 @@ public:
class Q_AUTOTEST_EXPORT QQuickVector4DValueType : public QQmlValueTypeBase<QVector4D>
{
- Q_PROPERTY(qreal x READ x WRITE setX)
- Q_PROPERTY(qreal y READ y WRITE setY)
- Q_PROPERTY(qreal z READ z WRITE setZ)
- Q_PROPERTY(qreal w READ w WRITE setW)
+ Q_PROPERTY(qreal x READ x WRITE setX FINAL)
+ Q_PROPERTY(qreal y READ y WRITE setY FINAL)
+ Q_PROPERTY(qreal z READ z WRITE setZ FINAL)
+ Q_PROPERTY(qreal w READ w WRITE setW FINAL)
Q_OBJECT
public:
QQuickVector4DValueType(QObject *parent = 0);
@@ -207,22 +207,22 @@ public:
class Q_AUTOTEST_EXPORT QQuickMatrix4x4ValueType : public QQmlValueTypeBase<QMatrix4x4>
{
- Q_PROPERTY(qreal m11 READ m11 WRITE setM11)
- Q_PROPERTY(qreal m12 READ m12 WRITE setM12)
- Q_PROPERTY(qreal m13 READ m13 WRITE setM13)
- Q_PROPERTY(qreal m14 READ m14 WRITE setM14)
- Q_PROPERTY(qreal m21 READ m21 WRITE setM21)
- Q_PROPERTY(qreal m22 READ m22 WRITE setM22)
- Q_PROPERTY(qreal m23 READ m23 WRITE setM23)
- Q_PROPERTY(qreal m24 READ m24 WRITE setM24)
- Q_PROPERTY(qreal m31 READ m31 WRITE setM31)
- Q_PROPERTY(qreal m32 READ m32 WRITE setM32)
- Q_PROPERTY(qreal m33 READ m33 WRITE setM33)
- Q_PROPERTY(qreal m34 READ m34 WRITE setM34)
- Q_PROPERTY(qreal m41 READ m41 WRITE setM41)
- Q_PROPERTY(qreal m42 READ m42 WRITE setM42)
- Q_PROPERTY(qreal m43 READ m43 WRITE setM43)
- Q_PROPERTY(qreal m44 READ m44 WRITE setM44)
+ Q_PROPERTY(qreal m11 READ m11 WRITE setM11 FINAL)
+ Q_PROPERTY(qreal m12 READ m12 WRITE setM12 FINAL)
+ Q_PROPERTY(qreal m13 READ m13 WRITE setM13 FINAL)
+ Q_PROPERTY(qreal m14 READ m14 WRITE setM14 FINAL)
+ Q_PROPERTY(qreal m21 READ m21 WRITE setM21 FINAL)
+ Q_PROPERTY(qreal m22 READ m22 WRITE setM22 FINAL)
+ Q_PROPERTY(qreal m23 READ m23 WRITE setM23 FINAL)
+ Q_PROPERTY(qreal m24 READ m24 WRITE setM24 FINAL)
+ Q_PROPERTY(qreal m31 READ m31 WRITE setM31 FINAL)
+ Q_PROPERTY(qreal m32 READ m32 WRITE setM32 FINAL)
+ Q_PROPERTY(qreal m33 READ m33 WRITE setM33 FINAL)
+ Q_PROPERTY(qreal m34 READ m34 WRITE setM34 FINAL)
+ Q_PROPERTY(qreal m41 READ m41 WRITE setM41 FINAL)
+ Q_PROPERTY(qreal m42 READ m42 WRITE setM42 FINAL)
+ Q_PROPERTY(qreal m43 READ m43 WRITE setM43 FINAL)
+ Q_PROPERTY(qreal m44 READ m44 WRITE setM44 FINAL)
Q_OBJECT
public:
QQuickMatrix4x4ValueType(QObject *parent = 0);
@@ -288,18 +288,18 @@ class Q_AUTOTEST_EXPORT QQuickFontValueType : public QQmlValueTypeBase<QFont>
Q_ENUMS(FontWeight)
Q_ENUMS(Capitalization)
- Q_PROPERTY(QString family READ family WRITE setFamily)
- Q_PROPERTY(bool bold READ bold WRITE setBold)
- Q_PROPERTY(FontWeight weight READ weight WRITE setWeight)
- Q_PROPERTY(bool italic READ italic WRITE setItalic)
- Q_PROPERTY(bool underline READ underline WRITE setUnderline)
- Q_PROPERTY(bool overline READ overline WRITE setOverline)
- Q_PROPERTY(bool strikeout READ strikeout WRITE setStrikeout)
- Q_PROPERTY(qreal pointSize READ pointSize WRITE setPointSize)
- Q_PROPERTY(int pixelSize READ pixelSize WRITE setPixelSize)
- Q_PROPERTY(Capitalization capitalization READ capitalization WRITE setCapitalization)
- Q_PROPERTY(qreal letterSpacing READ letterSpacing WRITE setLetterSpacing)
- Q_PROPERTY(qreal wordSpacing READ wordSpacing WRITE setWordSpacing)
+ Q_PROPERTY(QString family READ family WRITE setFamily FINAL)
+ Q_PROPERTY(bool bold READ bold WRITE setBold FINAL)
+ Q_PROPERTY(FontWeight weight READ weight WRITE setWeight FINAL)
+ Q_PROPERTY(bool italic READ italic WRITE setItalic FINAL)
+ Q_PROPERTY(bool underline READ underline WRITE setUnderline FINAL)
+ Q_PROPERTY(bool overline READ overline WRITE setOverline FINAL)
+ Q_PROPERTY(bool strikeout READ strikeout WRITE setStrikeout FINAL)
+ Q_PROPERTY(qreal pointSize READ pointSize WRITE setPointSize FINAL)
+ Q_PROPERTY(int pixelSize READ pixelSize WRITE setPixelSize FINAL)
+ Q_PROPERTY(Capitalization capitalization READ capitalization WRITE setCapitalization FINAL)
+ Q_PROPERTY(qreal letterSpacing READ letterSpacing WRITE setLetterSpacing FINAL)
+ Q_PROPERTY(qreal wordSpacing READ wordSpacing WRITE setWordSpacing FINAL)
public:
enum FontWeight { Light = QFont::Light,
diff --git a/tests/auto/particles/qquicktrailemitter/tst_qquicktrailemitter.cpp b/tests/auto/particles/qquicktrailemitter/tst_qquicktrailemitter.cpp
index 98209e218c..43600e226e 100644
--- a/tests/auto/particles/qquicktrailemitter/tst_qquicktrailemitter.cpp
+++ b/tests/auto/particles/qquicktrailemitter/tst_qquicktrailemitter.cpp
@@ -86,7 +86,7 @@ void tst_qquicktrailemitter::test_basic()
QVERIFY(myFuzzyLEQ(d->t, ((qreal)system->timeInt/1000.0)));
}
- QCOMPARE(system->groupData[1]->size(), 500);
+ QVERIFY(extremelyFuzzyCompare(system->groupData[1]->size(), 500, 10));
foreach (QQuickParticleData *d, system->groupData[1]->data) {
if (d->t == -1)
continue; //Particle data unused
diff --git a/tests/auto/qml/animation/qpauseanimationjob/tst_qpauseanimationjob.cpp b/tests/auto/qml/animation/qpauseanimationjob/tst_qpauseanimationjob.cpp
index a832c58ae3..5a1148e92e 100644
--- a/tests/auto/qml/animation/qpauseanimationjob/tst_qpauseanimationjob.cpp
+++ b/tests/auto/qml/animation/qpauseanimationjob/tst_qpauseanimationjob.cpp
@@ -211,19 +211,8 @@ void tst_QPauseAnimationJob::multiplePauseAnimations()
#endif
QCOMPARE(animation2.m_updateCurrentTimeCount, 2);
- QTest::qWait(550);
-
-#ifdef Q_OS_WIN
- if (animation2.state() != QAbstractAnimationJob::Stopped)
- QEXPECT_FAIL("", winTimerError, Abort);
-#endif
- QVERIFY(animation2.state() == QAbstractAnimationJob::Stopped);
-
-#ifdef Q_OS_WIN
- if (animation2.m_updateCurrentTimeCount != 3)
- QEXPECT_FAIL("", winTimerError, Abort);
-#endif
- QCOMPARE(animation2.m_updateCurrentTimeCount, 3);
+ QTRY_COMPARE(animation2.state(), QAbstractAnimationJob::Stopped);
+ QVERIFY(animation2.m_updateCurrentTimeCount >= 3);
}
void tst_QPauseAnimationJob::pauseAndPropertyAnimations()
@@ -240,19 +229,17 @@ void tst_QPauseAnimationJob::pauseAndPropertyAnimations()
QTest::qWait(100);
animation.start();
- QVERIFY(animation.state() == QAbstractAnimationJob::Running);
- QVERIFY(pause.state() == QAbstractAnimationJob::Running);
- QCOMPARE(pause.m_updateCurrentTimeCount, 2);
+ QCOMPARE(animation.state(), QAbstractAnimationJob::Running);
- QTest::qWait(animation.totalDuration() + 100);
+ QTRY_COMPARE(animation.state(), QAbstractAnimationJob::Running);
+ QVERIFY(pause.state() == QAbstractAnimationJob::Running);
+ QVERIFY2(pause.m_updateCurrentTimeCount >= 2,
+ QByteArrayLiteral("pause.m_updateCurrentTimeCount=") + QByteArray::number(pause.m_updateCurrentTimeCount));
-#ifdef Q_OS_WIN
- if (animation.state() != QAbstractAnimationJob::Stopped)
- QEXPECT_FAIL("", winTimerError, Abort);
-#endif
- QVERIFY(animation.state() == QAbstractAnimationJob::Stopped);
- QVERIFY(pause.state() == QAbstractAnimationJob::Stopped);
- QVERIFY(pause.m_updateCurrentTimeCount > 3);
+ QTRY_COMPARE(animation.state(), QAbstractAnimationJob::Stopped);
+ QCOMPARE(pause.state(), QAbstractAnimationJob::Stopped);
+ QVERIFY2(pause.m_updateCurrentTimeCount > 3,
+ QByteArrayLiteral("pause.m_updateCurrentTimeCount=") + QByteArray::number(pause.m_updateCurrentTimeCount));
}
void tst_QPauseAnimationJob::pauseResume()
@@ -260,19 +247,15 @@ void tst_QPauseAnimationJob::pauseResume()
TestablePauseAnimation animation;
animation.setDuration(400);
animation.start();
- QVERIFY(animation.state() == QAbstractAnimationJob::Running);
+ QCOMPARE(animation.state(), QAbstractAnimationJob::Running);
QTest::qWait(200);
animation.pause();
- QVERIFY(animation.state() == QAbstractAnimationJob::Paused);
+ QCOMPARE(animation.state(), QAbstractAnimationJob::Paused);
animation.start();
QTest::qWait(300);
- QVERIFY(animation.state() == QAbstractAnimationJob::Stopped);
-
-#ifdef Q_OS_WIN
- if (animation.m_updateCurrentTimeCount != 3)
- QEXPECT_FAIL("", winTimerError, Abort);
-#endif
- QCOMPARE(animation.m_updateCurrentTimeCount, 3);
+ QTRY_VERIFY(animation.state() == QAbstractAnimationJob::Stopped);
+ QVERIFY2(animation.m_updateCurrentTimeCount >= 3,
+ QByteArrayLiteral("animation.m_updateCurrentTimeCount=") + QByteArray::number(animation.m_updateCurrentTimeCount));
}
void tst_QPauseAnimationJob::sequentialPauseGroup()
@@ -423,7 +406,7 @@ void tst_QPauseAnimationJob::multipleSequentialGroups()
if (group.state() != QAbstractAnimationJob::Stopped)
QEXPECT_FAIL("", winTimerError, Abort);
#endif
- QVERIFY(group.state() == QAbstractAnimationJob::Stopped);
+ QTRY_VERIFY(group.state() == QAbstractAnimationJob::Stopped);
#ifdef Q_OS_WIN
if (subgroup1.state() != QAbstractAnimationJob::Stopped)
diff --git a/tests/auto/qml/debugger/qqmlprofilerservice/tst_qqmlprofilerservice.cpp b/tests/auto/qml/debugger/qqmlprofilerservice/tst_qqmlprofilerservice.cpp
index f2b82db630..929b079a51 100644
--- a/tests/auto/qml/debugger/qqmlprofilerservice/tst_qqmlprofilerservice.cpp
+++ b/tests/auto/qml/debugger/qqmlprofilerservice/tst_qqmlprofilerservice.cpp
@@ -418,22 +418,22 @@ void tst_QQmlProfilerService::pixmapCacheData()
QCOMPARE(m_client->traceMessages.first().detailType, (int)QQmlProfilerClient::StartTrace);
// image starting to load
- QCOMPARE(m_client->traceMessages[8].messageType, (int)QQmlProfilerClient::PixmapCacheEvent);
- QCOMPARE(m_client->traceMessages[8].detailType, (int)QQmlProfilerClient::PixmapLoadingStarted);
+ QCOMPARE(m_client->traceMessages[16].messageType, (int)QQmlProfilerClient::PixmapCacheEvent);
+ QCOMPARE(m_client->traceMessages[16].detailType, (int)QQmlProfilerClient::PixmapLoadingStarted);
// image loaded
- QCOMPARE(m_client->traceMessages[9].messageType, (int)QQmlProfilerClient::PixmapCacheEvent);
- QCOMPARE(m_client->traceMessages[9].detailType, (int)QQmlProfilerClient::PixmapLoadingFinished);
+ QCOMPARE(m_client->traceMessages[17].messageType, (int)QQmlProfilerClient::PixmapCacheEvent);
+ QCOMPARE(m_client->traceMessages[17].detailType, (int)QQmlProfilerClient::PixmapLoadingFinished);
// image size
- QCOMPARE(m_client->traceMessages[10].messageType, (int)QQmlProfilerClient::PixmapCacheEvent);
- QCOMPARE(m_client->traceMessages[10].detailType, (int)QQmlProfilerClient::PixmapSizeKnown);
- QCOMPARE(m_client->traceMessages[10].line, 2); // width
- QCOMPARE(m_client->traceMessages[10].column, 2); // height
+ QCOMPARE(m_client->traceMessages[18].messageType, (int)QQmlProfilerClient::PixmapCacheEvent);
+ QCOMPARE(m_client->traceMessages[18].detailType, (int)QQmlProfilerClient::PixmapSizeKnown);
+ QCOMPARE(m_client->traceMessages[18].line, 2); // width
+ QCOMPARE(m_client->traceMessages[18].column, 2); // height
// cache size
- QCOMPARE(m_client->traceMessages[11].messageType, (int)QQmlProfilerClient::PixmapCacheEvent);
- QCOMPARE(m_client->traceMessages[11].detailType, (int)QQmlProfilerClient::PixmapCacheCountChanged);
+ QCOMPARE(m_client->traceMessages[19].messageType, (int)QQmlProfilerClient::PixmapCacheEvent);
+ QCOMPARE(m_client->traceMessages[19].detailType, (int)QQmlProfilerClient::PixmapCacheCountChanged);
// must end with "EndTrace"
QCOMPARE(m_client->traceMessages.last().messageType, (int)QQmlProfilerClient::Event);
diff --git a/tests/auto/qml/debugger/shared/qqmldebugclient.cpp b/tests/auto/qml/debugger/shared/qqmldebugclient.cpp
index 95674ce6d7..6474a04796 100644
--- a/tests/auto/qml/debugger/shared/qqmldebugclient.cpp
+++ b/tests/auto/qml/debugger/shared/qqmldebugclient.cpp
@@ -449,6 +449,7 @@ QString QQmlDebugClient::stateString() const
case Unavailable: return QLatin1String("Unavailable");
case Enabled: return QLatin1String("Enabled");
}
+ return QLatin1String("Invalid");
}
void QQmlDebugClient::sendMessage(const QByteArray &message)
diff --git a/tests/auto/qml/qqmlecmascript/data/misctypetest.qml b/tests/auto/qml/qqmlecmascript/data/misctypetest.qml
index 60ff53a2b4..088ede67ec 100644
--- a/tests/auto/qml/qqmlecmascript/data/misctypetest.qml
+++ b/tests/auto/qml/qqmlecmascript/data/misctypetest.qml
@@ -11,7 +11,7 @@ Item {
return mtt.invalidUrl() == mtt.invalidUrl();
}
- function test_invalid_url_refequal()
+ function test_invalid_url_strictequal()
{
return mtt.invalidUrl() === mtt.invalidUrl();
}
@@ -21,7 +21,7 @@ Item {
return mtt.validUrl() == mtt.validUrl();
}
- function test_valid_url_refequal()
+ function test_valid_url_strictequal()
{
return mtt.validUrl() === mtt.validUrl();
}
diff --git a/tests/auto/qml/qqmlecmascript/data/noCaptureWhenWritingProperty.qml b/tests/auto/qml/qqmlecmascript/data/noCaptureWhenWritingProperty.qml
new file mode 100644
index 0000000000..8b8601692d
--- /dev/null
+++ b/tests/auto/qml/qqmlecmascript/data/noCaptureWhenWritingProperty.qml
@@ -0,0 +1,14 @@
+import QtQml 2.0
+QtObject {
+ property bool somePropertyEvaluated: false;
+
+ property int someProperty: {
+ // It's sort of evil to set the property here, but that doesn't mean that
+ // this expression should get re-evaluated when unrelatedProperty changes later.
+ somePropertyEvaluated = true
+ return 20;
+ }
+ Component.onCompleted: {
+ somePropertyEvaluated = false
+ }
+}
diff --git a/tests/auto/qml/qqmlecmascript/data/sequenceConversion.array.qml b/tests/auto/qml/qqmlecmascript/data/sequenceConversion.array.qml
index 52abda1e55..8d08cc5559 100644
--- a/tests/auto/qml/qqmlecmascript/data/sequenceConversion.array.qml
+++ b/tests/auto/qml/qqmlecmascript/data/sequenceConversion.array.qml
@@ -140,6 +140,22 @@ Item {
if (msco.intListProperty.toString() != expected.toString()) success = false;
expected = 7;
if (poppedVal != expected) success = false;
+
+ // concat
+ msco.stringListProperty = [ "one", "two" ]
+ stringList = [ "hello", "world" ]
+ stringList = stringList.concat(msco.stringListProperty)
+ expected = [ "hello", "world", "one", "two" ]
+ if (stringList.length != expected.length) {
+ success = false;
+ } else {
+ for (var i = 0; i < stringList.length; ++i) {
+ if (stringList[i] != expected[i]) {
+ success = false;
+ break;
+ }
+ }
+ }
}
property variant variantList: [ 1, 2, 3, 4, 5 ];
diff --git a/tests/auto/qml/qqmlecmascript/data/signalHandlers.qml b/tests/auto/qml/qqmlecmascript/data/signalHandlers.qml
index 975be1b2ad..7e85312692 100644
--- a/tests/auto/qml/qqmlecmascript/data/signalHandlers.qml
+++ b/tests/auto/qml/qqmlecmascript/data/signalHandlers.qml
@@ -57,4 +57,38 @@ QtObject {
if (onTestSignal !== undefined)
definedHandlerResult = true;
}
+
+ property QtObject objWithAlias: QtObject {
+ id: testObjectWithAlias
+
+ property int count: 0;
+ property alias countAlias: testObjectWithAlias.count
+ }
+
+ function testConnectionOnAlias() {
+ var called = false;
+
+ testObjectWithAlias.onCountAliasChanged.connect(function() {
+ called = true
+ })
+
+ testObjectWithAlias.count++;
+ return called;
+ }
+
+ property QtObject objWithAliasHandler: QtObject {
+ id: testObjectWithAliasHandler
+
+ property bool testSuccess: false
+
+ property int count: 0
+ property alias countAlias: testObjectWithAliasHandler.count
+ onCountAliasChanged: testSuccess = true
+ }
+
+ function testAliasSignalHandler() {
+ testObjectWithAliasHandler.testSuccess = false
+ testObjectWithAliasHandler.count++
+ return testObjectWithAliasHandler.testSuccess
+ }
}
diff --git a/tests/auto/qml/qqmlecmascript/testtypes.cpp b/tests/auto/qml/qqmlecmascript/testtypes.cpp
index 41fa3672bd..22fac2013e 100644
--- a/tests/auto/qml/qqmlecmascript/testtypes.cpp
+++ b/tests/auto/qml/qqmlecmascript/testtypes.cpp
@@ -106,7 +106,7 @@ public:
void MyQmlObject::v8function(QQmlV4Function *function)
{
- QV8Engine::getV4(function->engine())->current->throwError(QStringLiteral("Exception thrown from within QObject slot"));
+ QV8Engine::getV4(function->engine())->currentContext()->throwError(QStringLiteral("Exception thrown from within QObject slot"));
}
static QJSValue script_api(QQmlEngine *engine, QJSEngine *scriptEngine)
diff --git a/tests/auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp b/tests/auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp
index 6b19c13109..7b89709923 100644
--- a/tests/auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp
+++ b/tests/auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp
@@ -319,6 +319,7 @@ private slots:
void stackLimits();
void idsAsLValues();
void qtbug_34792();
+ void noCaptureWhenWritingProperty();
private:
// static void propertyVarWeakRefCallback(v8::Persistent<v8::Value> object, void* parameter);
@@ -2267,7 +2268,7 @@ static inline bool evaluate_error(QV8Engine *engine, const QV4::ValueRef o, cons
QV4::Script program(QV8Engine::getV4(engine)->rootContext, functionSource);
program.inheritContext = true;
- QV4::ExecutionContext *ctx = QV8Engine::getV4(engine)->current;
+ QV4::ExecutionContext *ctx = QV8Engine::getV4(engine)->currentContext();
QV4::Scope scope(ctx);
QV4::Scoped<QV4::FunctionObject> function(scope, program.run());
@@ -2295,7 +2296,7 @@ static inline bool evaluate_value(QV8Engine *engine, const QV4::ValueRef o,
QV4::Script program(QV8Engine::getV4(engine)->rootContext, functionSource);
program.inheritContext = true;
- QV4::ExecutionContext *ctx = QV8Engine::getV4(engine)->current;
+ QV4::ExecutionContext *ctx = QV8Engine::getV4(engine)->currentContext();
QV4::Scope scope(ctx);
QV4::Scoped<QV4::FunctionObject> function(scope, program.run());
@@ -2324,7 +2325,7 @@ static inline QV4::ReturnedValue evaluate(QV8Engine *engine, const QV4::ValueRef
QString functionSource = QLatin1String("(function(object) { return ") +
QLatin1String(source) + QLatin1String(" })");
- QV4::ExecutionContext *ctx = QV8Engine::getV4(engine)->current;
+ QV4::ExecutionContext *ctx = QV8Engine::getV4(engine)->currentContext();
QV4::Scope scope(ctx);
QV4::Script program(QV8Engine::getV4(engine)->rootContext, functionSource);
@@ -6060,6 +6061,13 @@ void tst_qqmlecmascript::signalHandlers()
QMetaObject::invokeMethod(o, "testSignalHandlerDefined");
QCOMPARE(o->property("definedHandlerResult").toBool(), true);
+ QVariant result;
+ QMetaObject::invokeMethod(o, "testConnectionOnAlias", Q_RETURN_ARG(QVariant, result));
+ QCOMPARE(result.toBool(), true);
+
+ QMetaObject::invokeMethod(o, "testAliasSignalHandler", Q_RETURN_ARG(QVariant, result));
+ QCOMPARE(result.toBool(), true);
+
delete o;
}
@@ -7491,6 +7499,14 @@ void tst_qqmlecmascript::qtbug_34792()
delete object;
}
+void tst_qqmlecmascript::noCaptureWhenWritingProperty()
+{
+ QQmlComponent component(&engine, testFileUrl("noCaptureWhenWritingProperty.qml"));
+ QScopedPointer<QObject> obj(component.create());
+ QVERIFY(!obj.isNull());
+ QCOMPARE(obj->property("somePropertyEvaluated").toBool(), false);
+}
+
QTEST_MAIN(tst_qqmlecmascript)
#include "tst_qqmlecmascript.moc"
diff --git a/tests/auto/qml/qqmllanguage/data/customParserBindingScopes.qml b/tests/auto/qml/qqmllanguage/data/customParserBindingScopes.qml
new file mode 100644
index 0000000000..2efc199f32
--- /dev/null
+++ b/tests/auto/qml/qqmllanguage/data/customParserBindingScopes.qml
@@ -0,0 +1,19 @@
+import Test 1.0
+import QtQml 2.0
+QtObject {
+ id: root
+
+ property int otherProperty: 10
+
+ property QtObject child: QtObject {
+ id: child
+
+ property int testProperty;
+ property int otherProperty: 41
+
+ property QtObject customBinder: CustomBinding {
+ target: child
+ testProperty: otherProperty + 1
+ }
+ }
+}
diff --git a/tests/auto/qml/qqmllanguage/testtypes.cpp b/tests/auto/qml/qqmllanguage/testtypes.cpp
index 3957f9d872..4a4ab3b81a 100644
--- a/tests/auto/qml/qqmllanguage/testtypes.cpp
+++ b/tests/auto/qml/qqmllanguage/testtypes.cpp
@@ -89,6 +89,8 @@ void registerTypes()
qmlRegisterUncreatableType<MyUncreateableBaseClass,1>("Test", 1, 1, "MyUncreateableBaseClass", "Cannot create MyUncreateableBaseClass");
qmlRegisterType<MyCreateableDerivedClass,1>("Test", 1, 1, "MyCreateableDerivedClass");
+
+ qmlRegisterCustomType<CustomBinding>("Test", 1, 0, "CustomBinding", new CustomBindingParser);
}
QVariant myCustomVariantTypeConverter(const QString &data)
@@ -97,3 +99,61 @@ QVariant myCustomVariantTypeConverter(const QString &data)
rv.a = data.toInt();
return QVariant::fromValue(rv);
}
+
+
+QByteArray CustomBindingParser::compile(const QList<QQmlCustomParserProperty> &properties)
+{
+ QByteArray result;
+ QDataStream ds(&result, QIODevice::WriteOnly);
+
+ ds << properties.count();
+ for (int i = 0; i < properties.count(); ++i) {
+ const QQmlCustomParserProperty &prop = properties.at(i);
+ ds << prop.name();
+
+ Q_ASSERT(prop.assignedValues().count() == 1);
+ QVariant value = prop.assignedValues().first();
+
+ Q_ASSERT(value.userType() == qMetaTypeId<QQmlScript::Variant>());
+ QQmlScript::Variant v = qvariant_cast<QQmlScript::Variant>(value);
+ Q_ASSERT(v.type() == QQmlScript::Variant::Script);
+ int bindingId = bindingIdentifier(v, prop.name());
+ ds << bindingId;
+
+ ds << prop.location().line;
+ }
+
+ return result;
+}
+
+void CustomBindingParser::setCustomData(QObject *object, const QByteArray &data)
+{
+ CustomBinding *customBinding = qobject_cast<CustomBinding*>(object);
+ Q_ASSERT(customBinding);
+ customBinding->m_bindingData = data;
+}
+
+void CustomBinding::componentComplete()
+{
+ Q_ASSERT(m_target);
+
+ QDataStream ds(m_bindingData);
+ int count;
+ ds >> count;
+ for (int i = 0; i < count; ++i) {
+ QString name;
+ ds >> name;
+
+ int bindingId;
+ ds >> bindingId;
+
+ int line;
+ ds >> line;
+
+ QQmlBinding *binding = QQmlBinding::createBinding(QQmlBinding::Identifier(bindingId), m_target, qmlContext(this), QString(), line);
+
+ QQmlProperty property(m_target, name, qmlContext(this));
+ binding->setTarget(property);
+ QQmlPropertyPrivate::setBinding(property, binding);
+ }
+}
diff --git a/tests/auto/qml/qqmllanguage/testtypes.h b/tests/auto/qml/qqmllanguage/testtypes.h
index 703b26a73c..a968d9a25a 100644
--- a/tests/auto/qml/qqmllanguage/testtypes.h
+++ b/tests/auto/qml/qqmllanguage/testtypes.h
@@ -1070,6 +1070,29 @@ QML_DECLARE_TYPE(MyRevisionedSubclass)
QML_DECLARE_TYPE(MySubclass)
QML_DECLARE_TYPE(MyReceiversTestObject)
+class CustomBinding : public QObject, public QQmlParserStatus
+{
+ Q_OBJECT
+ Q_INTERFACES(QQmlParserStatus)
+ Q_PROPERTY(QObject* target READ target WRITE setTarget)
+public:
+
+ virtual void classBegin() {}
+ virtual void componentComplete();
+
+ QObject *target() const { return m_target; }
+ void setTarget(QObject *newTarget) { m_target = newTarget; }
+
+ QPointer<QObject> m_target;
+ QByteArray m_bindingData;
+};
+
+class CustomBindingParser : public QQmlCustomParser
+{
+ virtual QByteArray compile(const QList<QQmlCustomParserProperty> &properties);
+ virtual void setCustomData(QObject *object, const QByteArray &data);
+};
+
void registerTypes();
#endif // TESTTYPES_H
diff --git a/tests/auto/qml/qqmllanguage/tst_qqmllanguage.cpp b/tests/auto/qml/qqmllanguage/tst_qqmllanguage.cpp
index 621061ab6a..6a577ec91c 100644
--- a/tests/auto/qml/qqmllanguage/tst_qqmllanguage.cpp
+++ b/tests/auto/qml/qqmllanguage/tst_qqmllanguage.cpp
@@ -214,6 +214,8 @@ private slots:
void compositeSingletonSelectors();
void compositeSingletonRegistered();
+ void customParserBindingScopes();
+
private:
QQmlEngine engine;
QStringList defaultImportPathList;
@@ -3534,6 +3536,17 @@ void tst_qqmllanguage::compositeSingletonRegistered()
verifyCompositeSingletonPropertyValues(o, "value1", 925, "value2", 755);
}
+void tst_qqmllanguage::customParserBindingScopes()
+{
+ QQmlComponent component(&engine, testFile("customParserBindingScopes.qml"));
+ VERIFY_ERRORS(0);
+ QScopedPointer<QObject> o(component.create());
+ QVERIFY(!o.isNull());
+ QPointer<QObject> child = qvariant_cast<QObject*>(o->property("child"));
+ QVERIFY(!child.isNull());
+ QCOMPARE(child->property("testProperty").toInt(), 42);
+}
+
QTEST_MAIN(tst_qqmllanguage)
#include "tst_qqmllanguage.moc"
diff --git a/tests/auto/qml/qqmlpropertymap/tst_qqmlpropertymap.cpp b/tests/auto/qml/qqmlpropertymap/tst_qqmlpropertymap.cpp
index ca212d333b..17f54508a3 100644
--- a/tests/auto/qml/qqmlpropertymap/tst_qqmlpropertymap.cpp
+++ b/tests/auto/qml/qqmlpropertymap/tst_qqmlpropertymap.cpp
@@ -55,6 +55,8 @@ public:
tst_QQmlPropertyMap() {}
private slots:
+ void initTestCase();
+
void insert();
void operatorInsert();
void operatorValue();
@@ -68,8 +70,39 @@ private slots:
void metaObjectAccessibility();
void QTBUG_31226();
void QTBUG_29836();
+ void QTBUG_35233();
+ void disallowExtending();
+};
+
+class LazyPropertyMap : public QQmlPropertyMap, public QQmlParserStatus
+{
+ Q_OBJECT
+ Q_INTERFACES(QQmlParserStatus)
+
+ Q_PROPERTY(int someFixedProperty READ someFixedProperty WRITE setSomeFixedProperty)
+public:
+ LazyPropertyMap()
+ : QQmlPropertyMap(this, /*parent*/0)
+ , value(0)
+ {}
+
+ virtual void classBegin() {}
+ virtual void componentComplete() {
+ insert(QStringLiteral("lateProperty"), QStringLiteral("lateValue"));
+ }
+
+ int someFixedProperty() const { return value; }
+ void setSomeFixedProperty(int v) { value = v; }
+
+private:
+ int value;
};
+void tst_QQmlPropertyMap::initTestCase()
+{
+ qmlRegisterType<LazyPropertyMap>("QTBUG_35233", 1, 0, "LazyPropertyMap");
+}
+
void tst_QQmlPropertyMap::insert()
{
QQmlPropertyMap map;
@@ -369,6 +402,54 @@ void tst_QQmlPropertyMap::QTBUG_29836()
}
+void tst_QQmlPropertyMap::QTBUG_35233()
+{
+ QQmlEngine engine;
+ QQmlComponent component(&engine);
+ component.setData("import QtQml 2.0\n"
+ "import QTBUG_35233 1.0\n"
+ "QtObject {\n"
+ " property QtObject testMap: LazyPropertyMap {\n"
+ " id: map\n"
+ " }\n"
+ " property QtObject sibling: QtObject {\n"
+ " objectName: \"sibling\"\n"
+ " property string testValue: map.lateProperty\n"
+ " }\n"
+ "}", QUrl());
+ QScopedPointer<QObject> obj(component.create());
+ QVERIFY(!obj.isNull());
+
+ QObject *sibling = obj->findChild<QObject*>("sibling");
+ QVERIFY(sibling);
+ QCOMPARE(sibling->property("testValue").toString(), QString("lateValue"));
+}
+
+void tst_QQmlPropertyMap::disallowExtending()
+{
+ QQmlEngine engine;
+ QQmlComponent component(&engine);
+ component.setData("import QtQml 2.0\n"
+ "import QTBUG_35233 1.0\n"
+ "LazyPropertyMap {\n"
+ " id: blah\n"
+ " someFixedProperty: 42\n"
+ "}\n", QUrl());
+ QScopedPointer<QObject> obj(component.create());
+ QVERIFY(!obj.isNull());
+
+ component.setData("import QtQml 2.0\n"
+ "import QTBUG_35233 1.0\n"
+ "LazyPropertyMap {\n"
+ " id: blah\n"
+ " property int someNewProperty;\n"
+ "}\n", QUrl());
+ obj.reset(component.create());
+ QVERIFY(obj.isNull());
+ QCOMPARE(component.errors().count(), 1);
+ QCOMPARE(component.errors().at(0).toString(), QStringLiteral("<Unknown File>: Fully dynamic types cannot declare new properties."));
+}
+
QTEST_MAIN(tst_QQmlPropertyMap)
#include "tst_qqmlpropertymap.moc"
diff --git a/tests/auto/qml/qqmltranslation/data/jstranslation.qml b/tests/auto/qml/qqmltranslation/data/jstranslation.qml
new file mode 100644
index 0000000000..7adde019fa
--- /dev/null
+++ b/tests/auto/qml/qqmltranslation/data/jstranslation.qml
@@ -0,0 +1,20 @@
+import QtQuick 2.0
+import "translation.js" as Js
+
+QtObject {
+ property string basic: Js.basic()
+ property string basic2: Js.basic2()
+ property string basic3: Js.basic3()
+
+ property string disambiguation: Js.disambiguation()
+ property string disambiguation2: Js.disambiguation2()
+ property string disambiguation3: Js.disambiguation3()
+
+ property string noop: Js.noop()
+ property string noop2: Js.noop2()
+
+ property string singular: Js.singular()
+ property string singular2: Js.singular2()
+ property string plural: Js.plural()
+ property string plural2: Js.plural2()
+}
diff --git a/tests/auto/qml/qqmltranslation/data/translation.js b/tests/auto/qml/qqmltranslation/data/translation.js
new file mode 100644
index 0000000000..c1e25dcd2f
--- /dev/null
+++ b/tests/auto/qml/qqmltranslation/data/translation.js
@@ -0,0 +1,98 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the test suite of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+function basic() {
+ return qsTr("hello")
+}
+
+function basic2() {
+ return qsTranslate("CustomContext", "goodbye")
+}
+
+function basic3() {
+ if (1)
+ return qsTr("hello")
+ return "";
+}
+
+function disambiguation() {
+ return qsTr("hi", "informal 'hello'")
+}
+
+function disambiguation2() {
+ return qsTranslate("CustomContext", "see ya", "informal 'goodbye'")
+}
+
+function disambiguation3() {
+ if (1)
+ return qsTr("hi", "informal 'hello'")
+ return "";
+}
+
+function noop() {
+ var _noop = QT_TR_NOOP("hello")
+ return qsTr(_noop)
+}
+
+function noop2() {
+ var _noop2 = QT_TRANSLATE_NOOP("CustomContext", "goodbye")
+ return qsTranslate("CustomContext", _noop2)
+}
+
+function singular() {
+ return qsTr("%n duck(s)", "", 1)
+}
+
+function singular2() {
+ if (1)
+ return qsTr("%n duck(s)", "", 1)
+ return "";
+}
+
+function plural() {
+ return qsTr("%n duck(s)", "", 2)
+}
+
+function plural2() {
+ if (1)
+ return qsTr("%n duck(s)", "", 2)
+ return "";
+}
diff --git a/tests/auto/qml/qqmltranslation/tst_qqmltranslation.cpp b/tests/auto/qml/qqmltranslation/tst_qqmltranslation.cpp
index 0e22d3cfca..01e1cf85fb 100644
--- a/tests/auto/qml/qqmltranslation/tst_qqmltranslation.cpp
+++ b/tests/auto/qml/qqmltranslation/tst_qqmltranslation.cpp
@@ -52,19 +52,32 @@ public:
tst_qqmltranslation() {}
private slots:
+ void translation_data();
void translation();
void idTranslation();
- void translationInQrc();
};
+void tst_qqmltranslation::translation_data()
+{
+ QTest::addColumn<QString>("translation");
+ QTest::addColumn<QUrl>("testFile");
+
+ QTest::newRow("qml") << QStringLiteral("qml_fr") << testFileUrl("translation.qml");
+ QTest::newRow("qrc") << QStringLiteral(":/qml_fr.qm") << QUrl("qrc:/translation.qml");
+ QTest::newRow("js") << QStringLiteral("qml_fr") << testFileUrl("jstranslation.qml");
+}
+
void tst_qqmltranslation::translation()
{
+ QFETCH(QString, translation);
+ QFETCH(QUrl, testFile);
+
QTranslator translator;
- translator.load(QLatin1String("qml_fr"), dataDirectory());
+ translator.load(translation, dataDirectory());
QCoreApplication::installTranslator(&translator);
QQmlEngine engine;
- QQmlComponent component(&engine, testFileUrl("translation.qml"));
+ QQmlComponent component(&engine, testFile);
QObject *object = component.create();
QVERIFY(object != 0);
@@ -104,34 +117,6 @@ void tst_qqmltranslation::idTranslation()
delete object;
}
-void tst_qqmltranslation::translationInQrc()
-{
- QTranslator translator;
- translator.load(":/qml_fr.qm");
- QCoreApplication::installTranslator(&translator);
-
- QQmlEngine engine;
- QQmlComponent component(&engine, QUrl("qrc:/translation.qml"));
- QObject *object = component.create();
- QVERIFY(object != 0);
-
- QCOMPARE(object->property("basic").toString(), QLatin1String("bonjour"));
- QCOMPARE(object->property("basic2").toString(), QLatin1String("au revoir"));
- QCOMPARE(object->property("basic3").toString(), QLatin1String("bonjour"));
- QCOMPARE(object->property("disambiguation").toString(), QLatin1String("salut"));
- QCOMPARE(object->property("disambiguation2").toString(), QString::fromUtf8("\xc3\xa0 plus tard"));
- QCOMPARE(object->property("disambiguation3").toString(), QLatin1String("salut"));
- QCOMPARE(object->property("noop").toString(), QLatin1String("bonjour"));
- QCOMPARE(object->property("noop2").toString(), QLatin1String("au revoir"));
- QCOMPARE(object->property("singular").toString(), QLatin1String("1 canard"));
- QCOMPARE(object->property("singular2").toString(), QLatin1String("1 canard"));
- QCOMPARE(object->property("plural").toString(), QLatin1String("2 canards"));
- QCOMPARE(object->property("plural2").toString(), QLatin1String("2 canards"));
-
- QCoreApplication::removeTranslator(&translator);
- delete object;
-}
-
QTEST_MAIN(tst_qqmltranslation)
#include "tst_qqmltranslation.moc"
diff --git a/tests/auto/qml/qqmlxmlhttprequest/tst_qqmlxmlhttprequest.cpp b/tests/auto/qml/qqmlxmlhttprequest/tst_qqmlxmlhttprequest.cpp
index 3ae27fe9c3..9c67e6e2e9 100644
--- a/tests/auto/qml/qqmlxmlhttprequest/tst_qqmlxmlhttprequest.cpp
+++ b/tests/auto/qml/qqmlxmlhttprequest/tst_qqmlxmlhttprequest.cpp
@@ -127,8 +127,8 @@ private:
void tst_qqmlxmlhttprequest::domExceptionCodes()
{
QQmlComponent component(&engine, testFileUrl("domExceptionCodes.qml"));
- QObject *object = component.create();
- QVERIFY(object != 0);
+ QScopedPointer<QObject> object(component.create());
+ QVERIFY(!object.isNull());
QCOMPARE(object->property("index_size_err").toInt(), 1);
QCOMPARE(object->property("domstring_size_err").toInt(), 2);
@@ -147,8 +147,6 @@ void tst_qqmlxmlhttprequest::domExceptionCodes()
QCOMPARE(object->property("invalid_access_err").toInt(), 15);
QCOMPARE(object->property("validation_err").toInt(), 16);
QCOMPARE(object->property("type_mismatch_err").toInt(), 17);
-
- delete object;
}
void tst_qqmlxmlhttprequest::callbackException_data()
@@ -172,15 +170,13 @@ void tst_qqmlxmlhttprequest::callbackException()
QTest::ignoreMessage(QtWarningMsg, expect.toLatin1());
QQmlComponent component(&engine, testFileUrl("callbackException.qml"));
- QObject *object = component.beginCreate(engine.rootContext());
- QVERIFY(object != 0);
+ QScopedPointer<QObject> object(component.beginCreate(engine.rootContext()));
+ QVERIFY(!object.isNull());
object->setProperty("url", "testdocument.html");
object->setProperty("which", which);
component.completeCreate();
QTRY_VERIFY(object->property("threw").toBool() == true);
-
- delete object;
}
// Test that the state value properties on the XMLHttpRequest constructor have the correct values.
@@ -188,61 +184,53 @@ void tst_qqmlxmlhttprequest::callbackException()
void tst_qqmlxmlhttprequest::staticStateValues()
{
QQmlComponent component(&engine, testFileUrl("staticStateValues.qml"));
- QObject *object = component.create();
- QVERIFY(object != 0);
+ QScopedPointer<QObject> object(component.create());
+ QVERIFY(!object.isNull());
QCOMPARE(object->property("unsent").toInt(), 0);
QCOMPARE(object->property("opened").toInt(), 1);
QCOMPARE(object->property("headers_received").toInt(), 2);
QCOMPARE(object->property("loading").toInt(), 3);
QCOMPARE(object->property("done").toInt(), 4);
-
- delete object;
}
// Test that the state value properties on instances have the correct values.
void tst_qqmlxmlhttprequest::instanceStateValues()
{
QQmlComponent component(&engine, testFileUrl("instanceStateValues.qml"));
- QObject *object = component.create();
- QVERIFY(object != 0);
+ QScopedPointer<QObject> object(component.create());
+ QVERIFY(!object.isNull());
QCOMPARE(object->property("unsent").toInt(), 0);
QCOMPARE(object->property("opened").toInt(), 1);
QCOMPARE(object->property("headers_received").toInt(), 2);
QCOMPARE(object->property("loading").toInt(), 3);
QCOMPARE(object->property("done").toInt(), 4);
-
- delete object;
}
// Test calling constructor
void tst_qqmlxmlhttprequest::constructor()
{
QQmlComponent component(&engine, testFileUrl("constructor.qml"));
- QObject *object = component.create();
- QVERIFY(object != 0);
+ QScopedPointer<QObject> object(component.create());
+ QVERIFY(!object.isNull());
QCOMPARE(object->property("calledAsConstructor").toBool(), true);
QCOMPARE(object->property("calledAsFunction").toBool(), true);
-
- delete object;
}
// Test that all the properties are set correctly before any request is sent
void tst_qqmlxmlhttprequest::defaultState()
{
QQmlComponent component(&engine, testFileUrl("defaultState.qml"));
- QObject *object = component.create();
- QVERIFY(object != 0);
+ QScopedPointer<QObject> object(component.create());
+ QVERIFY(!object.isNull());
QCOMPARE(object->property("readState").toInt(), 0);
QCOMPARE(object->property("statusIsException").toBool(), true);
QCOMPARE(object->property("statusTextIsException").toBool(), true);
QCOMPARE(object->property("responseText").toString(), QString());
QCOMPARE(object->property("responseXMLIsNull").toBool(), true);
-
- delete object;
}
// Test valid XMLHttpRequest.open() calls
@@ -262,8 +250,8 @@ void tst_qqmlxmlhttprequest::open()
}
QQmlComponent component(&engine, qmlFile);
- QObject *object = component.beginCreate(engine.rootContext());
- QVERIFY(object != 0);
+ QScopedPointer<QObject> object(component.beginCreate(engine.rootContext()));
+ QVERIFY(!object.isNull());
object->setProperty("url", url);
component.completeCreate();
@@ -275,8 +263,6 @@ void tst_qqmlxmlhttprequest::open()
QCOMPARE(object->property("responseXML").toBool(), true);
QTRY_VERIFY(object->property("dataOK").toBool() == true);
-
- delete object;
}
void tst_qqmlxmlhttprequest::open_data()
@@ -297,24 +283,20 @@ void tst_qqmlxmlhttprequest::open_data()
void tst_qqmlxmlhttprequest::open_invalid_method()
{
QQmlComponent component(&engine, testFileUrl("open_invalid_method.qml"));
- QObject *object = component.create();
- QVERIFY(object != 0);
+ QScopedPointer<QObject> object(component.create());
+ QVERIFY(!object.isNull());
QCOMPARE(object->property("exceptionThrown").toBool(), true);
-
- delete object;
}
// Test that calling XMLHttpRequest.open() with sync raises an exception
void tst_qqmlxmlhttprequest::open_sync()
{
QQmlComponent component(&engine, testFileUrl("open_sync.qml"));
- QObject *object = component.create();
- QVERIFY(object != 0);
+ QScopedPointer<QObject> object(component.create());
+ QVERIFY(!object.isNull());
QCOMPARE(object->property("exceptionThrown").toBool(), true);
-
- delete object;
}
// Calling with incorrect arg count raises an exception
@@ -322,22 +304,18 @@ void tst_qqmlxmlhttprequest::open_arg_count()
{
{
QQmlComponent component(&engine, testFileUrl("open_arg_count.1.qml"));
- QObject *object = component.create();
- QVERIFY(object != 0);
+ QScopedPointer<QObject> object(component.create());
+ QVERIFY(!object.isNull());
QCOMPARE(object->property("exceptionThrown").toBool(), true);
-
- delete object;
}
{
QQmlComponent component(&engine, testFileUrl("open_arg_count.2.qml"));
- QObject *object = component.create();
- QVERIFY(object != 0);
+ QScopedPointer<QObject> object(component.create());
+ QVERIFY(!object.isNull());
QCOMPARE(object->property("exceptionThrown").toBool(), true);
-
- delete object;
}
}
@@ -351,14 +329,12 @@ void tst_qqmlxmlhttprequest::setRequestHeader()
testFileUrl("testdocument.html")));
QQmlComponent component(&engine, testFileUrl("setRequestHeader.qml"));
- QObject *object = component.beginCreate(engine.rootContext());
- QVERIFY(object != 0);
+ QScopedPointer<QObject> object(component.beginCreate(engine.rootContext()));
+ QVERIFY(!object.isNull());
object->setProperty("url", "http://127.0.0.1:14445/testdocument.html");
component.completeCreate();
QTRY_VERIFY(object->property("dataOK").toBool() == true);
-
- delete object;
}
// Test valid setRequestHeader() calls with different header cases
@@ -371,25 +347,21 @@ void tst_qqmlxmlhttprequest::setRequestHeader_caseInsensitive()
testFileUrl("testdocument.html")));
QQmlComponent component(&engine, testFileUrl("setRequestHeader_caseInsensitive.qml"));
- QObject *object = component.beginCreate(engine.rootContext());
- QVERIFY(object != 0);
+ QScopedPointer<QObject> object(component.beginCreate(engine.rootContext()));
+ QVERIFY(!object.isNull());
object->setProperty("url", "http://127.0.0.1:14445/testdocument.html");
component.completeCreate();
QTRY_VERIFY(object->property("dataOK").toBool() == true);
-
- delete object;
}
// Test setting headers before open() throws exception
void tst_qqmlxmlhttprequest::setRequestHeader_unsent()
{
QQmlComponent component(&engine, testFileUrl("setRequestHeader_unsent.qml"));
- QObject *object = component.create();
- QVERIFY(object != 0);
+ QScopedPointer<QObject> object(component.create());
+ QVERIFY(!object.isNull());
QCOMPARE(object->property("test").toBool(), true);
-
- delete object;
}
void tst_qqmlxmlhttprequest::setRequestHeader_illegalName_data()
@@ -432,8 +404,8 @@ void tst_qqmlxmlhttprequest::setRequestHeader_illegalName()
testFileUrl("testdocument.html")));
QQmlComponent component(&engine, testFileUrl("setRequestHeader_illegalName.qml"));
- QObject *object = component.beginCreate(engine.rootContext());
- QVERIFY(object != 0);
+ QScopedPointer<QObject> object(component.beginCreate(engine.rootContext()));
+ QVERIFY(!object.isNull());
object->setProperty("url", "http://127.0.0.1:14445/testdocument.html");
object->setProperty("header", name);
component.completeCreate();
@@ -446,8 +418,6 @@ void tst_qqmlxmlhttprequest::setRequestHeader_illegalName()
QCOMPARE(object->property("responseXML").toBool(), true);
QTRY_VERIFY(object->property("dataOK").toBool() == true);
-
- delete object;
}
// Test that attempting to set a header after a request is sent throws an exception
@@ -460,53 +430,45 @@ void tst_qqmlxmlhttprequest::setRequestHeader_sent()
testFileUrl("testdocument.html")));
QQmlComponent component(&engine, testFileUrl("setRequestHeader_sent.qml"));
- QObject *object = component.beginCreate(engine.rootContext());
- QVERIFY(object != 0);
+ QScopedPointer<QObject> object(component.beginCreate(engine.rootContext()));
+ QVERIFY(!object.isNull());
object->setProperty("url", "http://127.0.0.1:14445/testdocument.html");
component.completeCreate();
QCOMPARE(object->property("test").toBool(), true);
QTRY_VERIFY(object->property("dataOK").toBool() == true);
-
- delete object;
}
// Invalid arg count throws exception
void tst_qqmlxmlhttprequest::setRequestHeader_args()
{
QQmlComponent component(&engine, testFileUrl("setRequestHeader_args.qml"));
- QObject *object = component.create();
- QVERIFY(object != 0);
+ QScopedPointer<QObject> object(component.create());
+ QVERIFY(!object.isNull());
QCOMPARE(object->property("exceptionThrown").toBool(), true);
-
- delete object;
}
// Test that calling send() in UNSENT state throws an exception
void tst_qqmlxmlhttprequest::send_unsent()
{
QQmlComponent component(&engine, testFileUrl("send_unsent.qml"));
- QObject *object = component.create();
- QVERIFY(object != 0);
+ QScopedPointer<QObject> object(component.create());
+ QVERIFY(!object.isNull());
QCOMPARE(object->property("test").toBool(), true);
-
- delete object;
}
// Test attempting to resend a sent request throws an exception
void tst_qqmlxmlhttprequest::send_alreadySent()
{
QQmlComponent component(&engine, testFileUrl("send_alreadySent.qml"));
- QObject *object = component.create();
- QVERIFY(object != 0);
+ QScopedPointer<QObject> object(component.create());
+ QVERIFY(!object.isNull());
QCOMPARE(object->property("test").toBool(), true);
QTRY_VERIFY(object->property("dataOK").toBool() == true);
-
- delete object;
}
// Test that sends for GET, HEAD and DELETE ignore data
@@ -520,15 +482,13 @@ void tst_qqmlxmlhttprequest::send_ignoreData()
testFileUrl("testdocument.html")));
QQmlComponent component(&engine, testFileUrl("send_ignoreData.qml"));
- QObject *object = component.beginCreate(engine.rootContext());
- QVERIFY(object != 0);
+ QScopedPointer<QObject> object(component.beginCreate(engine.rootContext()));
+ QVERIFY(!object.isNull());
object->setProperty("reqType", "GET");
object->setProperty("url", "http://127.0.0.1:14445/testdocument.html");
component.completeCreate();
QTRY_VERIFY(object->property("dataOK").toBool() == true);
-
- delete object;
}
{
@@ -539,15 +499,13 @@ void tst_qqmlxmlhttprequest::send_ignoreData()
QUrl()));
QQmlComponent component(&engine, testFileUrl("send_ignoreData.qml"));
- QObject *object = component.beginCreate(engine.rootContext());
- QVERIFY(object != 0);
+ QScopedPointer<QObject> object(component.beginCreate(engine.rootContext()));
+ QVERIFY(!object.isNull());
object->setProperty("reqType", "HEAD");
object->setProperty("url", "http://127.0.0.1:14445/testdocument.html");
component.completeCreate();
QTRY_VERIFY(object->property("dataOK").toBool() == true);
-
- delete object;
}
{
@@ -558,15 +516,13 @@ void tst_qqmlxmlhttprequest::send_ignoreData()
QUrl()));
QQmlComponent component(&engine, testFileUrl("send_ignoreData.qml"));
- QObject *object = component.beginCreate(engine.rootContext());
- QVERIFY(object != 0);
+ QScopedPointer<QObject> object(component.beginCreate(engine.rootContext()));
+ QVERIFY(!object.isNull());
object->setProperty("reqType", "DELETE");
object->setProperty("url", "http://127.0.0.1:14445/testdocument.html");
component.completeCreate();
QTRY_VERIFY(object->property("dataOK").toBool() == true);
-
- delete object;
}
}
@@ -583,14 +539,12 @@ void tst_qqmlxmlhttprequest::send_withdata()
testFileUrl("testdocument.html")));
QQmlComponent component(&engine, testFileUrl(file_qml));
- QObject *object = component.beginCreate(engine.rootContext());
- QVERIFY(object != 0);
+ QScopedPointer<QObject> object(component.beginCreate(engine.rootContext()));
+ QVERIFY(!object.isNull());
object->setProperty("url", "http://127.0.0.1:14445/testdocument.html");
component.completeCreate();
QTRY_VERIFY(object->property("dataOK").toBool() == true);
-
- delete object;
}
void tst_qqmlxmlhttprequest::send_withdata_data()
@@ -611,8 +565,8 @@ void tst_qqmlxmlhttprequest::send_withdata_data()
void tst_qqmlxmlhttprequest::abort_unsent()
{
QQmlComponent component(&engine, testFileUrl("abort_unsent.qml"));
- QObject *object = component.beginCreate(engine.rootContext());
- QVERIFY(object != 0);
+ QScopedPointer<QObject> object(component.beginCreate(engine.rootContext()));
+ QVERIFY(!object.isNull());
object->setProperty("url", "testdocument.html");
component.completeCreate();
@@ -624,16 +578,14 @@ void tst_qqmlxmlhttprequest::abort_unsent()
QCOMPARE(object->property("responseXML").toBool(), true);
QTRY_VERIFY(object->property("dataOK").toBool() == true);
-
- delete object;
}
// Test abort() cancels an open (but unsent) request
void tst_qqmlxmlhttprequest::abort_opened()
{
QQmlComponent component(&engine, testFileUrl("abort_opened.qml"));
- QObject *object = component.beginCreate(engine.rootContext());
- QVERIFY(object != 0);
+ QScopedPointer<QObject> object(component.beginCreate(engine.rootContext()));
+ QVERIFY(!object.isNull());
object->setProperty("url", "testdocument.html");
component.completeCreate();
@@ -645,8 +597,6 @@ void tst_qqmlxmlhttprequest::abort_opened()
QCOMPARE(object->property("responseXML").toBool(), true);
QTRY_VERIFY(object->property("dataOK").toBool() == true);
-
- delete object;
}
// Test abort() aborts in progress send
@@ -659,8 +609,8 @@ void tst_qqmlxmlhttprequest::abort()
testFileUrl("testdocument.html")));
QQmlComponent component(&engine, testFileUrl("abort.qml"));
- QObject *object = component.beginCreate(engine.rootContext());
- QVERIFY(object != 0);
+ QScopedPointer<QObject> object(component.beginCreate(engine.rootContext()));
+ QVERIFY(!object.isNull());
object->setProperty("urlDummy", "http://127.0.0.1:14449/testdocument.html");
object->setProperty("url", "http://127.0.0.1:14445/testdocument.html");
component.completeCreate();
@@ -670,8 +620,6 @@ void tst_qqmlxmlhttprequest::abort()
QCOMPARE(object->property("endStateUnsent").toBool(), true);
QTRY_VERIFY(object->property("dataOK").toBool() == true);
-
- delete object;
}
void tst_qqmlxmlhttprequest::getResponseHeader()
@@ -686,8 +634,8 @@ void tst_qqmlxmlhttprequest::getResponseHeader()
QQmlComponent component(&engine, testFileUrl("getResponseHeader.qml"));
- QObject *object = component.beginCreate(engine.rootContext());
- QVERIFY(object != 0);
+ QScopedPointer<QObject> object(component.beginCreate(engine.rootContext()));
+ QVERIFY(!object.isNull());
object->setProperty("url", "http://127.0.0.1:14445/testdocument.html");
component.completeCreate();
@@ -709,44 +657,36 @@ void tst_qqmlxmlhttprequest::getResponseHeader()
QCOMPARE(object->property("doneValidHeader").toBool(), true);
QCOMPARE(object->property("doneMultiValidHeader").toBool(), true);
QCOMPARE(object->property("doneCookieHeader").toBool(), true);
-
- delete object;
}
// Test getResponseHeader throws an exception in an invalid state
void tst_qqmlxmlhttprequest::getResponseHeader_unsent()
{
QQmlComponent component(&engine, testFileUrl("getResponseHeader_unsent.qml"));
- QObject *object = component.create();
- QVERIFY(object != 0);
+ QScopedPointer<QObject> object(component.create());
+ QVERIFY(!object.isNull());
QCOMPARE(object->property("test").toBool(), true);
-
- delete object;
}
// Test getResponseHeader throws an exception in an invalid state
void tst_qqmlxmlhttprequest::getResponseHeader_sent()
{
QQmlComponent component(&engine, testFileUrl("getResponseHeader_sent.qml"));
- QObject *object = component.create();
- QVERIFY(object != 0);
+ QScopedPointer<QObject> object(component.create());
+ QVERIFY(!object.isNull());
QCOMPARE(object->property("test").toBool(), true);
-
- delete object;
}
// Invalid arg count throws exception
void tst_qqmlxmlhttprequest::getResponseHeader_args()
{
QQmlComponent component(&engine, testFileUrl("getResponseHeader_args.qml"));
- QObject *object = component.create();
- QVERIFY(object != 0);
+ QScopedPointer<QObject> object(component.create());
+ QVERIFY(!object.isNull());
QTRY_VERIFY(object->property("exceptionThrown").toBool() == true);
-
- delete object;
}
void tst_qqmlxmlhttprequest::getAllResponseHeaders()
@@ -760,8 +700,8 @@ void tst_qqmlxmlhttprequest::getAllResponseHeaders()
testFileUrl("testdocument.html")));
QQmlComponent component(&engine, testFileUrl("getAllResponseHeaders.qml"));
- QObject *object = component.beginCreate(engine.rootContext());
- QVERIFY(object != 0);
+ QScopedPointer<QObject> object(component.beginCreate(engine.rootContext()));
+ QVERIFY(!object.isNull());
object->setProperty("url", "http://127.0.0.1:14445/testdocument.html");
component.completeCreate();
@@ -777,44 +717,36 @@ void tst_qqmlxmlhttprequest::getAllResponseHeaders()
QCOMPARE(object->property("doneState").toBool(), true);
QCOMPARE(object->property("doneHeader").toBool(), true);
-
- delete object;
}
// Test getAllResponseHeaders throws an exception in an invalid state
void tst_qqmlxmlhttprequest::getAllResponseHeaders_unsent()
{
QQmlComponent component(&engine, testFileUrl("getAllResponseHeaders_unsent.qml"));
- QObject *object = component.create();
- QVERIFY(object != 0);
+ QScopedPointer<QObject> object(component.create());
+ QVERIFY(!object.isNull());
QCOMPARE(object->property("test").toBool(), true);
-
- delete object;
}
// Test getAllResponseHeaders throws an exception in an invalid state
void tst_qqmlxmlhttprequest::getAllResponseHeaders_sent()
{
QQmlComponent component(&engine, testFileUrl("getAllResponseHeaders_sent.qml"));
- QObject *object = component.create();
- QVERIFY(object != 0);
+ QScopedPointer<QObject> object(component.create());
+ QVERIFY(!object.isNull());
QCOMPARE(object->property("test").toBool(), true);
-
- delete object;
}
// Invalid arg count throws exception
void tst_qqmlxmlhttprequest::getAllResponseHeaders_args()
{
QQmlComponent component(&engine, testFileUrl("getAllResponseHeaders_args.qml"));
- QObject *object = component.create();
- QVERIFY(object != 0);
+ QScopedPointer<QObject> object(component.create());
+ QVERIFY(!object.isNull());
QTRY_VERIFY(object->property("exceptionThrown").toBool() == true);
-
- delete object;
}
void tst_qqmlxmlhttprequest::status()
@@ -829,8 +761,8 @@ void tst_qqmlxmlhttprequest::status()
testFileUrl("testdocument.html")));
QQmlComponent component(&engine, testFileUrl("status.qml"));
- QObject *object = component.beginCreate(engine.rootContext());
- QVERIFY(object != 0);
+ QScopedPointer<QObject> object(component.beginCreate(engine.rootContext()));
+ QVERIFY(!object.isNull());
object->setProperty("url", "http://127.0.0.1:14445/testdocument.html");
object->setProperty("expectedStatus", status);
component.completeCreate();
@@ -844,8 +776,6 @@ void tst_qqmlxmlhttprequest::status()
QCOMPARE(object->property("loading").toBool(), true);
QCOMPARE(object->property("done").toBool(), true);
QCOMPARE(object->property("resetException").toBool(), true);
-
- delete object;
}
void tst_qqmlxmlhttprequest::status_data()
@@ -870,8 +800,8 @@ void tst_qqmlxmlhttprequest::statusText()
testFileUrl("testdocument.html")));
QQmlComponent component(&engine, testFileUrl("statusText.qml"));
- QObject *object = component.beginCreate(engine.rootContext());
- QVERIFY(object != 0);
+ QScopedPointer<QObject> object(component.beginCreate(engine.rootContext()));
+ QVERIFY(!object.isNull());
object->setProperty("url", "http://127.0.0.1:14445/testdocument.html");
object->setProperty("expectedStatus", statusText);
component.completeCreate();
@@ -885,8 +815,6 @@ void tst_qqmlxmlhttprequest::statusText()
QCOMPARE(object->property("loading").toBool(), true);
QCOMPARE(object->property("done").toBool(), true);
QCOMPARE(object->property("resetException").toBool(), true);
-
- delete object;
}
void tst_qqmlxmlhttprequest::statusText_data()
@@ -912,8 +840,8 @@ void tst_qqmlxmlhttprequest::responseText()
bodyUrl));
QQmlComponent component(&engine, testFileUrl("responseText.qml"));
- QObject *object = component.beginCreate(engine.rootContext());
- QVERIFY(object != 0);
+ QScopedPointer<QObject> object(component.beginCreate(engine.rootContext()));
+ QVERIFY(!object.isNull());
object->setProperty("url", "http://127.0.0.1:14445/testdocument.html");
object->setProperty("expectedText", responseText);
component.completeCreate();
@@ -927,8 +855,6 @@ void tst_qqmlxmlhttprequest::responseText()
QCOMPARE(object->property("loading").toBool(), true);
QCOMPARE(object->property("done").toBool(), true);
QCOMPARE(object->property("reset").toBool(), true);
-
- delete object;
}
void tst_qqmlxmlhttprequest::responseText_data()
@@ -950,11 +876,11 @@ void tst_qqmlxmlhttprequest::nonUtf8()
QFETCH(QString, xmlRootNodeValue);
QQmlComponent component(&engine, testFileUrl("utf16.qml"));
- QObject *object = component.create();
- QVERIFY(object != 0);
+ QScopedPointer<QObject> object(component.create());
+ QVERIFY(!object.isNull());
object->setProperty("fileName", fileName);
- QMetaObject::invokeMethod(object, "startRequest");
+ QMetaObject::invokeMethod(object.data(), "startRequest");
QTRY_VERIFY(object->property("dataOK").toBool() == true);
@@ -964,8 +890,6 @@ void tst_qqmlxmlhttprequest::nonUtf8()
QString rootNodeValue = object->property("responseXmlRootNodeValue").toString();
QCOMPARE(rootNodeValue, xmlRootNodeValue);
}
-
- delete object;
}
void tst_qqmlxmlhttprequest::nonUtf8_data()
@@ -989,8 +913,8 @@ void tst_qqmlxmlhttprequest::nonUtf8_data()
void tst_qqmlxmlhttprequest::invalidMethodUsage()
{
QQmlComponent component(&engine, testFileUrl("invalidMethodUsage.qml"));
- QObject *object = component.create();
- QVERIFY(object != 0);
+ QScopedPointer<QObject> object(component.create());
+ QVERIFY(!object.isNull());
QCOMPARE(object->property("readyState").toBool(), true);
QCOMPARE(object->property("status").toBool(), true);
@@ -1004,8 +928,6 @@ void tst_qqmlxmlhttprequest::invalidMethodUsage()
QCOMPARE(object->property("abort").toBool(), true);
QCOMPARE(object->property("getResponseHeader").toBool(), true);
QCOMPARE(object->property("getAllResponseHeaders").toBool(), true);
-
- delete object;
}
// Test that XMLHttpRequest transparently redirects
@@ -1018,16 +940,14 @@ void tst_qqmlxmlhttprequest::redirects()
server.serveDirectory(dataDirectory());
QQmlComponent component(&engine, testFileUrl("redirects.qml"));
- QObject *object = component.beginCreate(engine.rootContext());
- QVERIFY(object != 0);
+ QScopedPointer<QObject> object(component.beginCreate(engine.rootContext()));
+ QVERIFY(!object.isNull());
object->setProperty("url", "http://127.0.0.1:14445/redirect.html");
object->setProperty("expectedText", "");
component.completeCreate();
QTRY_VERIFY(object->property("done").toBool() == true);
QCOMPARE(object->property("dataOK").toBool(), true);
-
- delete object;
}
{
@@ -1037,16 +957,14 @@ void tst_qqmlxmlhttprequest::redirects()
server.serveDirectory(dataDirectory());
QQmlComponent component(&engine, testFileUrl("redirectError.qml"));
- QObject *object = component.beginCreate(engine.rootContext());
- QVERIFY(object != 0);
+ QScopedPointer<QObject> object(component.beginCreate(engine.rootContext()));
+ QVERIFY(!object.isNull());
object->setProperty("url", "http://127.0.0.1:14445/redirect.html");
object->setProperty("expectedText", "");
component.completeCreate();
QTRY_VERIFY(object->property("done").toBool() == true);
QCOMPARE(object->property("dataOK").toBool(), true);
-
- delete object;
}
{
@@ -1056,8 +974,8 @@ void tst_qqmlxmlhttprequest::redirects()
server.serveDirectory(dataDirectory());
QQmlComponent component(&engine, testFileUrl("redirectRecur.qml"));
- QObject *object = component.beginCreate(engine.rootContext());
- QVERIFY(object != 0);
+ QScopedPointer<QObject> object(component.beginCreate(engine.rootContext()));
+ QVERIFY(!object.isNull());
object->setProperty("url", "http://127.0.0.1:14445/redirect.html");
object->setProperty("expectedText", "");
component.completeCreate();
@@ -1069,92 +987,78 @@ void tst_qqmlxmlhttprequest::redirects()
QVERIFY(object->property("done").toBool() == true);
QCOMPARE(object->property("dataOK").toBool(), true);
-
- delete object;
}
}
void tst_qqmlxmlhttprequest::responseXML_invalid()
{
QQmlComponent component(&engine, testFileUrl("responseXML_invalid.qml"));
- QObject *object = component.create();
- QVERIFY(object != 0);
+ QScopedPointer<QObject> object(component.create());
+ QVERIFY(!object.isNull());
QTRY_VERIFY(object->property("dataOK").toBool() == true);
QCOMPARE(object->property("xmlNull").toBool(), true);
-
- delete object;
}
// Test the Document DOM element
void tst_qqmlxmlhttprequest::document()
{
QQmlComponent component(&engine, testFileUrl("document.qml"));
- QObject *object = component.create();
- QVERIFY(object != 0);
+ QScopedPointer<QObject> object(component.create());
+ QVERIFY(!object.isNull());
QTRY_VERIFY(object->property("dataOK").toBool() == true);
QCOMPARE(object->property("xmlTest").toBool(), true);
-
- delete object;
}
// Test the Element DOM element
void tst_qqmlxmlhttprequest::element()
{
QQmlComponent component(&engine, testFileUrl("element.qml"));
- QObject *object = component.create();
- QVERIFY(object != 0);
+ QScopedPointer<QObject> object(component.create());
+ QVERIFY(!object.isNull());
QTRY_VERIFY(object->property("dataOK").toBool() == true);
QCOMPARE(object->property("xmlTest").toBool(), true);
-
- delete object;
}
// Test the Attr DOM element
void tst_qqmlxmlhttprequest::attr()
{
QQmlComponent component(&engine, testFileUrl("attr.qml"));
- QObject *object = component.create();
- QVERIFY(object != 0);
+ QScopedPointer<QObject> object(component.create());
+ QVERIFY(!object.isNull());
QTRY_VERIFY(object->property("dataOK").toBool() == true);
QCOMPARE(object->property("xmlTest").toBool(), true);
-
- delete object;
}
// Test the Text DOM element
void tst_qqmlxmlhttprequest::text()
{
QQmlComponent component(&engine, testFileUrl("text.qml"));
- QObject *object = component.create();
- QVERIFY(object != 0);
+ QScopedPointer<QObject> object(component.create());
+ QVERIFY(!object.isNull());
QTRY_VERIFY(object->property("dataOK").toBool() == true);
QCOMPARE(object->property("xmlTest").toBool(), true);
-
- delete object;
}
// Test the CDataSection DOM element
void tst_qqmlxmlhttprequest::cdata()
{
QQmlComponent component(&engine, testFileUrl("cdata.qml"));
- QObject *object = component.create();
- QVERIFY(object != 0);
+ QScopedPointer<QObject> object(component.create());
+ QVERIFY(!object.isNull());
QTRY_VERIFY(object->property("dataOK").toBool() == true);
QCOMPARE(object->property("xmlTest").toBool(), true);
-
- delete object;
}
void tst_qqmlxmlhttprequest::stateChangeCallingContext()
@@ -1171,11 +1075,10 @@ void tst_qqmlxmlhttprequest::stateChangeCallingContext()
server.serveDirectory(dataDirectory(), TestHTTPServer::Delay);
QQmlComponent component(&engine, testFileUrl("stateChangeCallingContext.qml"));
- QObject *object = component.create();
- QVERIFY(object != 0);
+ QScopedPointer<QObject> object(component.create());
+ QVERIFY(!object.isNull());
server.sendDelayedItem();
QTRY_VERIFY(object->property("success").toBool() == true);
- delete object;
}
QTEST_MAIN(tst_qqmlxmlhttprequest)
diff --git a/tests/auto/quick/qquickapplication/tst_qquickapplication.cpp b/tests/auto/quick/qquickapplication/tst_qquickapplication.cpp
index ef27445920..dfcef43a7e 100644
--- a/tests/auto/quick/qquickapplication/tst_qquickapplication.cpp
+++ b/tests/auto/quick/qquickapplication/tst_qquickapplication.cpp
@@ -184,7 +184,6 @@ void tst_qquickapplication::layoutDirection()
// mirrored
QGuiApplication::setLayoutDirection(Qt::RightToLeft);
- QEXPECT_FAIL("", "QTBUG-21573", Abort);
QCOMPARE(Qt::LayoutDirection(item->property("layoutDirection").toInt()), Qt::RightToLeft);
// not mirrored again
diff --git a/tests/auto/quick/qquickflickable/data/stopAtBounds.qml b/tests/auto/quick/qquickflickable/data/stopAtBounds.qml
new file mode 100644
index 0000000000..d8661f3e45
--- /dev/null
+++ b/tests/auto/quick/qquickflickable/data/stopAtBounds.qml
@@ -0,0 +1,22 @@
+import QtQuick 2.0
+
+Flickable {
+ id: outer
+ objectName: "flickable"
+ width: 400
+ height: 400
+ contentX: 50
+ contentY: 50
+ contentWidth: 500
+ contentHeight: 500
+ boundsBehavior: Flickable.StopAtBounds
+
+ Rectangle {
+ x: 100
+ y: 100
+ width: 300
+ height: 300
+
+ color: "yellow"
+ }
+}
diff --git a/tests/auto/quick/qquickflickable/qquickflickable.pro b/tests/auto/quick/qquickflickable/qquickflickable.pro
index dfc8d7541b..88dc2fbc2a 100644
--- a/tests/auto/quick/qquickflickable/qquickflickable.pro
+++ b/tests/auto/quick/qquickflickable/qquickflickable.pro
@@ -11,4 +11,3 @@ TESTDATA = data/*
QT += core-private gui-private qml-private quick-private testlib
DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0
-CONFIG+=insignificant_test
diff --git a/tests/auto/quick/qquickflickable/tst_qquickflickable.cpp b/tests/auto/quick/qquickflickable/tst_qquickflickable.cpp
index 3c518c509b..794f9a8af6 100644
--- a/tests/auto/quick/qquickflickable/tst_qquickflickable.cpp
+++ b/tests/auto/quick/qquickflickable/tst_qquickflickable.cpp
@@ -94,6 +94,8 @@ private slots:
void flickTwiceUsingTouches();
void nestedStopAtBounds();
void nestedStopAtBounds_data();
+ void stopAtBounds();
+ void stopAtBounds_data();
void nestedMouseAreaUsingTouch();
private:
@@ -285,11 +287,6 @@ void tst_qquickflickable::rebound()
window->rootObject()->setProperty("transitionsStarted", 0);
window->rootObject()->setProperty("transitionsFinished", 0);
-#ifdef Q_OS_MAC
- QSKIP("QTBUG-26696 - sometimes fails on Mac");
- return;
-#endif
-
// flick and trigger the transition multiple times
// (moving signals are emitted as soon as the first transition starts)
flick(window.data(), QPoint(20,20), QPoint(120,120), 200); // both x and y will bounce back
@@ -425,8 +422,7 @@ void tst_qquickflickable::pressDelay()
// As we moved pass the drag threshold, we should never receive the press
QVERIFY(mouseArea->property("pressed").toBool() == false);
- QTest::qWait(200);
- QVERIFY(mouseArea->property("pressed").toBool() == false);
+ QTRY_VERIFY(mouseArea->property("pressed").toBool() == false);
// On release the clicked signal should *not* be emitted
QTest::mouseRelease(window.data(), Qt::LeftButton, 0, QPoint(150, 190));
@@ -1180,8 +1176,7 @@ void tst_qquickflickable::margins()
// position to the far right, including margin
obj->setContentX(1600 + 50 - obj->width());
obj->returnToBounds();
- QTest::qWait(200);
- QCOMPARE(obj->contentX(), 1600. + 50. - obj->width());
+ QTRY_COMPARE(obj->contentX(), 1600. + 50. - obj->width());
// position beyond the far right, including margin
obj->setContentX(1600 + 50 - obj->width() + 1.);
@@ -1196,8 +1191,7 @@ void tst_qquickflickable::margins()
// position to the far bottom, including margin
obj->setContentY(600 + 30 - obj->height());
obj->returnToBounds();
- QTest::qWait(200);
- QCOMPARE(obj->contentY(), 600. + 30. - obj->height());
+ QTRY_COMPARE(obj->contentY(), 600. + 30. - obj->height());
// position beyond the far bottom, including margin
obj->setContentY(600 + 30 - obj->height() + 1.);
@@ -1266,14 +1260,12 @@ void tst_qquickflickable::clickAndDragWhenTransformed()
// click outside child rect
QTest::mousePress(view.data(), Qt::LeftButton, 0, QPoint(190, 190));
- QTest::qWait(10);
- QCOMPARE(flickable->property("itemPressed").toBool(), false);
+ QTRY_COMPARE(flickable->property("itemPressed").toBool(), false);
QTest::mouseRelease(view.data(), Qt::LeftButton, 0, QPoint(190, 190));
// click inside child rect
QTest::mousePress(view.data(), Qt::LeftButton, 0, QPoint(200, 200));
- QTest::qWait(10);
- QCOMPARE(flickable->property("itemPressed").toBool(), true);
+ QTRY_COMPARE(flickable->property("itemPressed").toBool(), true);
QTest::mouseRelease(view.data(), Qt::LeftButton, 0, QPoint(200, 200));
const int threshold = qApp->styleHints()->startDragDistance();
@@ -1322,13 +1314,15 @@ void tst_qquickflickable::flickTwiceUsingTouches()
qreal contentYAfterFirstFlick = flickable->contentY();
qDebug() << "contentYAfterFirstFlick " << contentYAfterFirstFlick;
QVERIFY(contentYAfterFirstFlick > 50.0f);
+ // Wait until view stops moving
+ QTRY_VERIFY(!flickable->isMoving());
flickWithTouch(window.data(), touchDevice, QPoint(100, 400), QPoint(100, 240));
// In the original bug, that second flick would cause Flickable to halt immediately
qreal contentYAfterSecondFlick = flickable->contentY();
qDebug() << "contentYAfterSecondFlick " << contentYAfterSecondFlick;
- QVERIFY(contentYAfterSecondFlick > (contentYAfterFirstFlick + 80.0f));
+ QTRY_VERIFY(contentYAfterSecondFlick > (contentYAfterFirstFlick + 80.0f));
}
void tst_qquickflickable::flickWithTouch(QWindow *window, QTouchDevice *touchDevice, const QPoint &from, const QPoint &to)
@@ -1419,6 +1413,90 @@ void tst_qquickflickable::nestedStopAtBounds()
QTRY_VERIFY(!outer->isMoving());
}
+void tst_qquickflickable::stopAtBounds_data()
+{
+ QTest::addColumn<bool>("transpose");
+ QTest::addColumn<bool>("invert");
+
+ QTest::newRow("left") << false << false;
+ QTest::newRow("right") << false << true;
+ QTest::newRow("top") << true << false;
+ QTest::newRow("bottom") << true << true;
+}
+
+void tst_qquickflickable::stopAtBounds()
+{
+ QFETCH(bool, transpose);
+ QFETCH(bool, invert);
+
+ QQuickView view;
+ view.setSource(testFileUrl("stopAtBounds.qml"));
+ QTRY_COMPARE(view.status(), QQuickView::Ready);
+ QQuickViewTestUtil::centerOnScreen(&view);
+ QQuickViewTestUtil::moveMouseAway(&view);
+ view.show();
+ view.requestActivate();
+ QVERIFY(QTest::qWaitForWindowExposed(&view));
+ QVERIFY(view.rootObject());
+
+ QQuickFlickable *flickable = qobject_cast<QQuickFlickable*>(view.rootObject());
+ QVERIFY(flickable);
+
+ if (transpose)
+ flickable->setContentY(invert ? 100 : 0);
+ else
+ flickable->setContentX(invert ? 100 : 0);
+
+ const int threshold = qApp->styleHints()->startDragDistance();
+
+ QPoint position(200, 200);
+ int &axis = transpose ? position.ry() : position.rx();
+
+ // drag away from the aligned boundary. View should not move
+ QTest::mousePress(&view, Qt::LeftButton, 0, position);
+ QTest::qWait(10);
+ for (int i = 0; i < 3; ++i) {
+ axis += invert ? -threshold : threshold;
+ QTest::mouseMove(&view, position);
+ }
+ QCOMPARE(flickable->isDragging(), false);
+ if (invert)
+ QCOMPARE(transpose ? flickable->isAtYEnd() : flickable->isAtXEnd(), true);
+ else
+ QCOMPARE(transpose ? flickable->isAtYBeginning() : flickable->isAtXBeginning(), true);
+
+ // drag back towards boundary
+ for (int i = 0; i < 24; ++i) {
+ axis += invert ? threshold / 3 : -threshold / 3;
+ QTest::mouseMove(&view, position);
+ }
+ QTRY_COMPARE(flickable->isDragging(), true);
+ if (invert)
+ QCOMPARE(transpose ? flickable->isAtYEnd() : flickable->isAtXEnd(), false);
+ else
+ QCOMPARE(transpose ? flickable->isAtYBeginning() : flickable->isAtXBeginning(), false);
+
+ // Drag away from the aligned boundary again.
+ // None of the mouse movements will position the view at the boundary exactly,
+ // but the view should end up aligned on the boundary
+ for (int i = 0; i < 5; ++i) {
+ axis += invert ? -threshold * 2 : threshold * 2;
+ QTest::mouseMove(&view, position);
+ }
+ QCOMPARE(flickable->isDragging(), true);
+
+ // we should have hit the boundary and stopped
+ if (invert) {
+ QCOMPARE(transpose ? flickable->isAtYEnd() : flickable->isAtXEnd(), true);
+ QCOMPARE(transpose ? flickable->contentY() : flickable->contentX(), 100.0);
+ } else {
+ QCOMPARE(transpose ? flickable->isAtYBeginning() : flickable->isAtXBeginning(), true);
+ QCOMPARE(transpose ? flickable->contentY() : flickable->contentX(), 0.0);
+ }
+
+ QTest::mouseRelease(&view, Qt::LeftButton, 0, position);
+}
+
void tst_qquickflickable::nestedMouseAreaUsingTouch()
{
QTouchDevice *touchDevice = new QTouchDevice;
diff --git a/tests/auto/quick/qquickitem/tst_qquickitem.cpp b/tests/auto/quick/qquickitem/tst_qquickitem.cpp
index 97e002361b..2c6dcd72ba 100644
--- a/tests/auto/quick/qquickitem/tst_qquickitem.cpp
+++ b/tests/auto/quick/qquickitem/tst_qquickitem.cpp
@@ -44,7 +44,6 @@
#include <QtQuick/qquickitem.h>
#include <QtQuick/qquickwindow.h>
#include <QtQuick/qquickview.h>
-#include <QtWidgets/QGraphicsSceneMouseEvent>
#include "private/qquickfocusscope_p.h"
#include "private/qquickitem_p.h"
#include <qpa/qwindowsysteminterface.h>
@@ -1151,6 +1150,30 @@ void tst_qquickitem::enabledFocus()
QCOMPARE(child2.hasFocus(), false);
QCOMPARE(child2.hasActiveFocus(), false);
QCOMPARE(window.activeFocusItem(), static_cast<QQuickItem *>(&child1));
+
+ child2.setFocus(true);
+ QCOMPARE(root.isEnabled(), true);
+ QCOMPARE(root.hasFocus(), true);
+ QCOMPARE(root.hasActiveFocus(), true);
+ QCOMPARE(child1.isEnabled(), true);
+ QCOMPARE(child1.hasFocus(), false);
+ QCOMPARE(child1.hasActiveFocus(), false);
+ QCOMPARE(child2.isEnabled(), false);
+ QCOMPARE(child2.hasFocus(), true);
+ QCOMPARE(child2.hasActiveFocus(), false);
+ QCOMPARE(window.activeFocusItem(), static_cast<QQuickItem *>(&root));
+
+ root.setEnabled(false);
+ QCOMPARE(root.isEnabled(), false);
+ QCOMPARE(root.hasFocus(), true);
+ QCOMPARE(root.hasActiveFocus(), false);
+ QCOMPARE(child1.isEnabled(), false);
+ QCOMPARE(child1.hasFocus(), false);
+ QCOMPARE(child1.hasActiveFocus(), false);
+ QCOMPARE(child2.isEnabled(), false);
+ QCOMPARE(child2.hasFocus(), true);
+ QCOMPARE(child2.hasActiveFocus(), false);
+ QCOMPARE(window.activeFocusItem(), window.contentItem());
}
static inline QByteArray msgItem(const QQuickItem *item)
diff --git a/tests/auto/quick/qquicklistview/data/HighlightResize.qml b/tests/auto/quick/qquicklistview/data/HighlightResize.qml
new file mode 100644
index 0000000000..2b07b39d20
--- /dev/null
+++ b/tests/auto/quick/qquicklistview/data/HighlightResize.qml
@@ -0,0 +1,23 @@
+import QtQuick 2.0
+
+ListView {
+ id: view
+
+ width: 400
+ height: 400
+ model: 5
+
+ highlight: Rectangle {
+ color: "skyblue"
+ }
+
+ delegate: Item {
+ width: 100 + index * 20
+ height: 100 + index * 10
+
+ Text {
+ anchors.centerIn: parent
+ text: model.index
+ }
+ }
+}
diff --git a/tests/auto/quick/qquicklistview/data/headerchangesviewport.qml b/tests/auto/quick/qquicklistview/data/headerchangesviewport.qml
new file mode 100644
index 0000000000..b32f7a1236
--- /dev/null
+++ b/tests/auto/quick/qquicklistview/data/headerchangesviewport.qml
@@ -0,0 +1,19 @@
+import QtQuick 2.0
+
+Rectangle {
+ width: 240
+ height: 320
+ color: "#ffffff"
+ ListView {
+ id: list
+ anchors.fill: parent
+ objectName: "list"
+ delegate: Text {}
+ header: Text {
+ objectName: "header"
+ text: "ninjas"
+ height: headerHeight
+ width: headerWidth
+ }
+ }
+}
diff --git a/tests/auto/quick/qquicklistview/data/listview-sections.qml b/tests/auto/quick/qquicklistview/data/listview-sections.qml
index d5b8a4400d..e9fb83910a 100644
--- a/tests/auto/quick/qquicklistview/data/listview-sections.qml
+++ b/tests/auto/quick/qquicklistview/data/listview-sections.qml
@@ -1,6 +1,7 @@
import QtQuick 2.0
Rectangle {
+ property bool sectionsInvalidOnCompletion
width: 240
height: 320
color: "#ffffff"
@@ -9,6 +10,26 @@ Rectangle {
id: myDelegate
Item {
id: wrapper
+
+ function validateInitialSections() {
+ var invalid = false
+ if (index == 0) {
+ invalid |= wrapper.ListView.previousSection != ""
+ }
+ if (index == model.count - 1) {
+ invalid |= wrapper.ListView.nextSection != ""
+ }
+ if (index % 5 == 0 && index > 0) {
+ invalid |= wrapper.ListView.previousSection != Number(wrapper.ListView.section) - 1
+ } else if ((index + 1) % 5 == 0 && index < model.count - 1) {
+ invalid |= wrapper.ListView.nextSection != Number(wrapper.ListView.section) + 1
+ } else if (index > 0 && index < model.count - 1) {
+ invalid |= wrapper.ListView.previousSection != wrapper.ListView.section
+ invalid |= wrapper.ListView.nextSection != wrapper.ListView.section
+ }
+ sectionsInvalidOnCompletion |= invalid
+ }
+
objectName: "wrapper"
height: ListView.previousSection != ListView.section ? 40 : 20;
width: 240
@@ -49,6 +70,10 @@ Rectangle {
visible: wrapper.ListView.previousSection != wrapper.ListView.section ? true : false
Text { text: wrapper.ListView.section }
}
+ ListView.onPreviousSectionChanged: validateInitialSections()
+ ListView.onNextSectionChanged: validateInitialSections()
+ ListView.onSectionChanged: validateInitialSections()
+ Component.onCompleted: validateInitialSections()
}
}
]
diff --git a/tests/auto/quick/qquicklistview/data/typedModel.qml b/tests/auto/quick/qquicklistview/data/typedModel.qml
new file mode 100644
index 0000000000..d2b3f7e42f
--- /dev/null
+++ b/tests/auto/quick/qquicklistview/data/typedModel.qml
@@ -0,0 +1,23 @@
+import QtQuick 2.0
+
+ListView {
+ width: 100
+ height: 100
+
+ delegate: Item {
+ width: 100
+ height: 10
+ }
+ model: listModel
+
+ ListModel {
+ id: listModel
+
+ ListElement { label: "a" }
+ ListElement { label: "b" }
+ ListElement { label: "c" }
+ ListElement { label: "d" }
+ ListElement { label: "e" }
+ ListElement { label: "f" }
+ }
+}
diff --git a/tests/auto/quick/qquicklistview/tst_qquicklistview.cpp b/tests/auto/quick/qquicklistview/tst_qquicklistview.cpp
index f62151c2d8..d207a7eadc 100644
--- a/tests/auto/quick/qquicklistview/tst_qquicklistview.cpp
+++ b/tests/auto/quick/qquicklistview/tst_qquicklistview.cpp
@@ -150,6 +150,7 @@ private slots:
void header();
void header_data();
void header_delayItemCreation();
+ void headerChangesViewport();
void footer();
void footer_data();
void extents();
@@ -213,6 +214,10 @@ private slots:
void outsideViewportChangeNotAffectingView();
void testProxyModelChangedAfterMove();
+ void typedModel();
+
+ void highlightItemGeometryChanges();
+
private:
template <class T> void items(const QUrl &source);
template <class T> void changed(const QUrl &source);
@@ -1953,6 +1958,8 @@ void tst_QQuickListView::sections(const QUrl &source)
QCOMPARE(next->text().toInt(), (i+1)/5);
}
+ QVERIFY(!listview->property("sectionsInvalidOnCompletion").toBool());
+
QSignalSpy currentSectionChangedSpy(listview, SIGNAL(currentSectionChanged()));
// Remove section boundary
@@ -3655,6 +3662,35 @@ void tst_QQuickListView::header_delayItemCreation()
delete window;
}
+void tst_QQuickListView::headerChangesViewport()
+{
+ QQuickView *window = getView();
+ window->rootContext()->setContextProperty("headerHeight", 20);
+ window->rootContext()->setContextProperty("headerWidth", 240);
+ window->setSource(testFileUrl("headerchangesviewport.qml"));
+
+ QQuickListView *listview = findItem<QQuickListView>(window->rootObject(), "list");
+ QTRY_VERIFY(listview != 0);
+ QTRY_COMPARE(QQuickItemPrivate::get(listview)->polishScheduled, false);
+
+ QQuickItem *contentItem = listview->contentItem();
+ QTRY_VERIFY(contentItem != 0);
+
+ QQuickText *header = 0;
+ QTRY_VERIFY(header = findItem<QQuickText>(contentItem, "header"));
+ QVERIFY(header == listview->headerItem());
+
+ QCOMPARE(header->height(), 20.);
+ QCOMPARE(listview->contentHeight(), 20.);
+
+ // change height
+ window->rootContext()->setContextProperty("headerHeight", 50);
+
+ // verify that list content height updates also
+ QCOMPARE(header->height(), 50.);
+ QCOMPARE(listview->contentHeight(), 50.);
+}
+
void tst_QQuickListView::footer()
{
QFETCH(QQuickListView::Orientation, orientation);
@@ -6960,6 +6996,43 @@ void tst_QQuickListView::testProxyModelChangedAfterMove()
delete window;
}
+void tst_QQuickListView::typedModel()
+{
+ QQmlEngine engine;
+ QQmlComponent component(&engine, testFileUrl("typedModel.qml"));
+
+ QScopedPointer<QObject> object(component.create());
+
+ QQuickListView *listview = qobject_cast<QQuickListView *>(object.data());
+ QVERIFY(listview);
+
+ QCOMPARE(listview->count(), 6);
+
+ QQmlListModel *listModel = 0;
+
+ listview->setModel(QVariant::fromValue(listModel));
+ QCOMPARE(listview->count(), 0);
+}
+
+void tst_QQuickListView::highlightItemGeometryChanges()
+{
+ QQmlEngine engine;
+ QQmlComponent component(&engine, testFileUrl("HighlightResize.qml"));
+
+ QScopedPointer<QObject> object(component.create());
+
+ QQuickListView *listview = qobject_cast<QQuickListView *>(object.data());
+ QVERIFY(listview);
+
+ QCOMPARE(listview->count(), 5);
+
+ for (int i = 0; i < listview->count(); ++i) {
+ listview->setCurrentIndex(i);
+ QTRY_COMPARE(listview->highlightItem()->width(), qreal(100 + i * 20));
+ QTRY_COMPARE(listview->highlightItem()->height(), qreal(100 + i * 10));
+ }
+}
+
QTEST_MAIN(tst_QQuickListView)
#include "tst_qquicklistview.moc"
diff --git a/tests/auto/quick/qquickloader/data/SimpleTestComponent.qml b/tests/auto/quick/qquickloader/data/SimpleTestComponent.qml
new file mode 100644
index 0000000000..0e69012662
--- /dev/null
+++ b/tests/auto/quick/qquickloader/data/SimpleTestComponent.qml
@@ -0,0 +1,2 @@
+import QtQml 2.0
+QtObject {}
diff --git a/tests/auto/quick/qquickloader/data/sourceComponentGarbageCollection.qml b/tests/auto/quick/qquickloader/data/sourceComponentGarbageCollection.qml
new file mode 100644
index 0000000000..ab86883af5
--- /dev/null
+++ b/tests/auto/quick/qquickloader/data/sourceComponentGarbageCollection.qml
@@ -0,0 +1,8 @@
+import QtQuick 2.0
+
+Loader {
+ active: false
+ function setSourceComponent() {
+ sourceComponent = Qt.createComponent("SimpleTestComponent.qml");
+ }
+}
diff --git a/tests/auto/quick/qquickloader/tst_qquickloader.cpp b/tests/auto/quick/qquickloader/tst_qquickloader.cpp
index 50ded4d95a..1e23d689ff 100644
--- a/tests/auto/quick/qquickloader/tst_qquickloader.cpp
+++ b/tests/auto/quick/qquickloader/tst_qquickloader.cpp
@@ -128,6 +128,8 @@ private slots:
void sizeBound();
void QTBUG_30183();
+ void sourceComponentGarbageCollection();
+
private:
QQmlEngine engine;
};
@@ -1144,6 +1146,26 @@ void tst_QQuickLoader::QTBUG_30183()
delete loader;
}
+void tst_QQuickLoader::sourceComponentGarbageCollection()
+{
+ QQmlComponent component(&engine, testFileUrl("sourceComponentGarbageCollection.qml"));
+ QScopedPointer<QObject> obj(component.create());
+ QVERIFY(!obj.isNull());
+
+ QMetaObject::invokeMethod(obj.data(), "setSourceComponent");
+ engine.collectGarbage();
+ QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete);
+
+ QSignalSpy spy(obj.data(), SIGNAL(loaded()));
+
+ obj->setProperty("active", true);
+
+ if (spy.isEmpty())
+ QVERIFY(spy.wait());
+
+ QCOMPARE(spy.count(), 1);
+}
+
QTEST_MAIN(tst_QQuickLoader)
#include "tst_qquickloader.moc"
diff --git a/tests/auto/quick/qquickmousearea/tst_qquickmousearea.cpp b/tests/auto/quick/qquickmousearea/tst_qquickmousearea.cpp
index 72639556ec..31b323af5d 100644
--- a/tests/auto/quick/qquickmousearea/tst_qquickmousearea.cpp
+++ b/tests/auto/quick/qquickmousearea/tst_qquickmousearea.cpp
@@ -89,6 +89,7 @@ private slots:
void dragThreshold();
void invalidDrag_data() { rejectedButton_data(); }
void invalidDrag();
+ void cancelDragging();
void setDragOnPressed();
void updateMouseAreaPosOnClick();
void updateMouseAreaPosOnResize();
@@ -440,6 +441,57 @@ void tst_QQuickMouseArea::invalidDrag()
QCOMPARE(blackRect->y(), 50.0);
}
+void tst_QQuickMouseArea::cancelDragging()
+{
+ QQuickView window;
+ QByteArray errorMessage;
+ QVERIFY2(initView(window, testFileUrl("dragging.qml"), true, &errorMessage), errorMessage.constData());
+
+ window.show();
+ QVERIFY(QTest::qWaitForWindowExposed(&window));
+ QVERIFY(window.rootObject() != 0);
+
+ QQuickMouseArea *mouseRegion = window.rootObject()->findChild<QQuickMouseArea*>("mouseregion");
+ QQuickDrag *drag = mouseRegion->drag();
+ QVERIFY(mouseRegion != 0);
+ QVERIFY(drag != 0);
+
+ mouseRegion->setAcceptedButtons(Qt::LeftButton);
+
+ // target
+ QQuickItem *blackRect = window.rootObject()->findChild<QQuickItem*>("blackrect");
+ QVERIFY(blackRect != 0);
+ QVERIFY(blackRect == drag->target());
+
+ QVERIFY(!drag->active());
+
+ QTest::mousePress(&window, Qt::LeftButton, 0, QPoint(100,100));
+
+ QVERIFY(!drag->active());
+ QCOMPARE(blackRect->x(), 50.0);
+ QCOMPARE(blackRect->y(), 50.0);
+
+ QTest::mouseMove(&window, QPoint(111,111), 50);
+ QTest::mouseMove(&window, QPoint(116,116), 50);
+ QTest::mouseMove(&window, QPoint(122,122), 50);
+
+ QTRY_VERIFY(drag->active());
+ QTRY_COMPARE(blackRect->x(), 61.0);
+ QCOMPARE(blackRect->y(), 61.0);
+
+ mouseRegion->QQuickItem::ungrabMouse();
+ QTRY_VERIFY(!drag->active());
+ QCOMPARE(blackRect->x(), 61.0);
+ QCOMPARE(blackRect->y(), 61.0);
+
+ QTest::mouseMove(&window, QPoint(132,132), 50);
+ QTRY_VERIFY(!drag->active());
+ QCOMPARE(blackRect->x(), 61.0);
+ QCOMPARE(blackRect->y(), 61.0);
+
+ QTest::mouseRelease(&window, Qt::LeftButton, 0, QPoint(122,122));
+}
+
void tst_QQuickMouseArea::setDragOnPressed()
{
QQuickView window;
diff --git a/tests/auto/quick/qquicktextinput/data/signal_accepted.qml b/tests/auto/quick/qquicktextinput/data/signal_accepted.qml
new file mode 100644
index 0000000000..94c113dd9f
--- /dev/null
+++ b/tests/auto/quick/qquicktextinput/data/signal_accepted.qml
@@ -0,0 +1,14 @@
+import QtQuick 2.2
+
+Item {
+ property QtObject input: input
+
+ width: 800; height: 600;
+
+ Column{
+ TextInput { id: input;
+ property bool acceptable: acceptableInput
+ validator: RegExpValidator { regExp: /[a-zA-z]{2,4}/ }
+ }
+ }
+}
diff --git a/tests/auto/quick/qquicktextinput/data/signal_editingfinished.qml b/tests/auto/quick/qquicktextinput/data/signal_editingfinished.qml
index 2ec5ce6676..dba186e765 100644
--- a/tests/auto/quick/qquicktextinput/data/signal_editingfinished.qml
+++ b/tests/auto/quick/qquicktextinput/data/signal_editingfinished.qml
@@ -1,13 +1,19 @@
import QtQuick 2.2
Item {
- property variant input1: input1
- property variant input2: input2
+ property QtObject input1: input1
+ property QtObject input2: input2
width: 800; height: 600;
Column{
- TextInput { id: input1; }
- TextInput { id: input2; }
+ TextInput { id: input1;
+ property bool acceptable: acceptableInput
+ validator: RegExpValidator { regExp: /[a-zA-z]{2,4}/ }
+ }
+ TextInput { id: input2;
+ property bool acceptable: acceptableInput
+ validator: RegExpValidator { regExp: /[a-zA-z]{2,4}/ }
+ }
}
}
diff --git a/tests/auto/quick/qquicktextinput/tst_qquicktextinput.cpp b/tests/auto/quick/qquicktextinput/tst_qquicktextinput.cpp
index 80726720e4..697dba182c 100644
--- a/tests/auto/quick/qquicktextinput/tst_qquicktextinput.cpp
+++ b/tests/auto/quick/qquicktextinput/tst_qquicktextinput.cpp
@@ -49,6 +49,7 @@
#include <QtQuick/qquickview.h>
#include <QtGui/qguiapplication.h>
#include <QtGui/qstylehints.h>
+#include <QtGui/qvalidator.h>
#include <QInputMethod>
#include <private/qquicktextinput_p.h>
#include <private/qquicktextinput_p_p.h>
@@ -146,6 +147,7 @@ private slots:
void validators();
void inputMethods();
+ void signal_accepted();
void signal_editingfinished();
void passwordCharacter();
@@ -226,6 +228,7 @@ private slots:
void hasAcceptableInputMask();
void maskCharacter_data();
void maskCharacter();
+ void fixup();
private:
void simulateKey(QWindow *, int key);
@@ -1271,10 +1274,9 @@ void tst_qquicktextinput::dragMouseSelection()
QTest::mousePress(&window, Qt::LeftButton, 0, QPoint(x1,y));
QTest::mouseMove(&window, QPoint(x2, y));
QTest::mouseRelease(&window, Qt::LeftButton, 0, QPoint(x2,y));
- QTest::qWait(100);
QString str1;
- QVERIFY((str1 = textInputObject->selectedText()).length() > 3);
- QVERIFY(str1.length() > 3);
+ QTRY_VERIFY((str1 = textInputObject->selectedText()).length() > 3);
+ QTRY_VERIFY(str1.length() > 3);
// press and drag the current selection.
x1 = 40;
@@ -1282,11 +1284,10 @@ void tst_qquicktextinput::dragMouseSelection()
QTest::mousePress(&window, Qt::LeftButton, 0, QPoint(x1,y));
QTest::mouseMove(&window, QPoint(x2, y));
QTest::mouseRelease(&window, Qt::LeftButton, 0, QPoint(x2,y));
- QTest::qWait(300);
QString str2 = textInputObject->selectedText();
- QVERIFY(str2.length() > 3);
+ QTRY_VERIFY(str2.length() > 3);
- QVERIFY(str1 != str2);
+ QTRY_VERIFY(str1 != str2);
}
void tst_qquicktextinput::mouseSelectionMode_data()
@@ -1337,7 +1338,6 @@ void tst_qquicktextinput::mouseSelectionMode()
QTest::mousePress(&window, Qt::LeftButton, 0, QPoint(x1,y));
QTest::mouseMove(&window, QPoint(x2,y)); // doesn't work
QTest::mouseRelease(&window, Qt::LeftButton, 0, QPoint(x2,y));
- QTest::qWait(300);
if (selectWords) {
QTRY_COMPARE(textInputObject->selectedText(), text);
} else {
@@ -1873,8 +1873,7 @@ void tst_qquicktextinput::maxLength()
QTRY_COMPARE(textinputObject->text().length(), qMin(i,10));
//simulateKey(&window, Qt::Key_A);
QTest::keyPress(&window, Qt::Key_A);
- QTest::keyRelease(&window, Qt::Key_A, Qt::NoModifier ,10);
- QTest::qWait(50);
+ QTest::keyRelease(&window, Qt::Key_A, Qt::NoModifier);
}
}
@@ -1900,8 +1899,7 @@ void tst_qquicktextinput::masks()
QCOMPARE(i>=4, textinputObject->hasAcceptableInput());
//simulateKey(&window, Qt::Key_A);
QTest::keyPress(&window, Qt::Key_A);
- QTest::keyRelease(&window, Qt::Key_A, Qt::NoModifier ,10);
- QTest::qWait(50);
+ QTest::keyRelease(&window, Qt::Key_A, Qt::NoModifier);
}
}
@@ -1944,56 +1942,47 @@ void tst_qquicktextinput::validators()
QCOMPARE(intInput->hasAcceptableInput(), false);
QCOMPARE(intInput->property("acceptable").toBool(), false);
QTest::keyPress(&window, Qt::Key_1);
- QTest::keyRelease(&window, Qt::Key_1, Qt::NoModifier ,10);
- QTest::qWait(50);
+ QTest::keyRelease(&window, Qt::Key_1, Qt::NoModifier);
QTRY_COMPARE(intInput->text(), QLatin1String("1"));
QCOMPARE(intInput->hasAcceptableInput(), false);
QCOMPARE(intInput->property("acceptable").toBool(), false);
QCOMPARE(intSpy.count(), 0);
QTest::keyPress(&window, Qt::Key_2);
- QTest::keyRelease(&window, Qt::Key_2, Qt::NoModifier ,10);
- QTest::qWait(50);
+ QTest::keyRelease(&window, Qt::Key_2, Qt::NoModifier);
QTRY_COMPARE(intInput->text(), QLatin1String("1"));
QCOMPARE(intInput->hasAcceptableInput(), false);
QCOMPARE(intInput->property("acceptable").toBool(), false);
QCOMPARE(intSpy.count(), 0);
QTest::keyPress(&window, Qt::Key_Period);
- QTest::keyRelease(&window, Qt::Key_Period, Qt::NoModifier ,10);
- QTest::qWait(50);
+ QTest::keyRelease(&window, Qt::Key_Period, Qt::NoModifier);
QTRY_COMPARE(intInput->text(), QLatin1String("1"));
QCOMPARE(intInput->hasAcceptableInput(), false);
QTest::keyPress(&window, Qt::Key_Comma);
- QTest::keyRelease(&window, Qt::Key_Comma, Qt::NoModifier ,10);
- QTest::qWait(50);
+ QTest::keyRelease(&window, Qt::Key_Comma, Qt::NoModifier);
QTRY_COMPARE(intInput->text(), QLatin1String("1,"));
QCOMPARE(intInput->hasAcceptableInput(), false);
QTest::keyPress(&window, Qt::Key_Backspace);
- QTest::keyRelease(&window, Qt::Key_Backspace, Qt::NoModifier ,10);
- QTest::qWait(50);
+ QTest::keyRelease(&window, Qt::Key_Backspace, Qt::NoModifier);
QTRY_COMPARE(intInput->text(), QLatin1String("1"));
QCOMPARE(intInput->hasAcceptableInput(), false);
intValidator->setLocaleName(deLocale.name());
QTest::keyPress(&window, Qt::Key_Period);
- QTest::keyRelease(&window, Qt::Key_Period, Qt::NoModifier ,10);
- QTest::qWait(50);
+ QTest::keyRelease(&window, Qt::Key_Period, Qt::NoModifier);
QTRY_COMPARE(intInput->text(), QLatin1String("1."));
QCOMPARE(intInput->hasAcceptableInput(), false);
QTest::keyPress(&window, Qt::Key_Backspace);
- QTest::keyRelease(&window, Qt::Key_Backspace, Qt::NoModifier ,10);
- QTest::qWait(50);
+ QTest::keyRelease(&window, Qt::Key_Backspace, Qt::NoModifier);
QTRY_COMPARE(intInput->text(), QLatin1String("1"));
QCOMPARE(intInput->hasAcceptableInput(), false);
intValidator->resetLocaleName();
QTest::keyPress(&window, Qt::Key_1);
- QTest::keyRelease(&window, Qt::Key_1, Qt::NoModifier ,10);
- QTest::qWait(50);
+ QTest::keyRelease(&window, Qt::Key_1, Qt::NoModifier);
QCOMPARE(intInput->text(), QLatin1String("11"));
QCOMPARE(intInput->hasAcceptableInput(), true);
QCOMPARE(intInput->property("acceptable").toBool(), true);
QCOMPARE(intSpy.count(), 1);
QTest::keyPress(&window, Qt::Key_0);
- QTest::keyRelease(&window, Qt::Key_0, Qt::NoModifier ,10);
- QTest::qWait(50);
+ QTest::keyRelease(&window, Qt::Key_0, Qt::NoModifier);
QCOMPARE(intInput->text(), QLatin1String("11"));
QCOMPARE(intInput->hasAcceptableInput(), true);
QCOMPARE(intInput->property("acceptable").toBool(), true);
@@ -2019,81 +2008,68 @@ void tst_qquicktextinput::validators()
QCOMPARE(dblInput->hasAcceptableInput(), false);
QCOMPARE(dblInput->property("acceptable").toBool(), false);
QTest::keyPress(&window, Qt::Key_1);
- QTest::keyRelease(&window, Qt::Key_1, Qt::NoModifier ,10);
- QTest::qWait(50);
+ QTest::keyRelease(&window, Qt::Key_1, Qt::NoModifier);
QTRY_COMPARE(dblInput->text(), QLatin1String("1"));
QCOMPARE(dblInput->hasAcceptableInput(), false);
QCOMPARE(dblInput->property("acceptable").toBool(), false);
QCOMPARE(dblSpy.count(), 0);
QTest::keyPress(&window, Qt::Key_2);
- QTest::keyRelease(&window, Qt::Key_2, Qt::NoModifier ,10);
- QTest::qWait(50);
+ QTest::keyRelease(&window, Qt::Key_2, Qt::NoModifier);
QTRY_COMPARE(dblInput->text(), QLatin1String("12"));
QCOMPARE(dblInput->hasAcceptableInput(), true);
QCOMPARE(dblInput->property("acceptable").toBool(), true);
QCOMPARE(dblSpy.count(), 1);
QTest::keyPress(&window, Qt::Key_Comma);
- QTest::keyRelease(&window, Qt::Key_Comma, Qt::NoModifier ,10);
- QTest::qWait(50);
+ QTest::keyRelease(&window, Qt::Key_Comma, Qt::NoModifier);
QTRY_COMPARE(dblInput->text(), QLatin1String("12,"));
QCOMPARE(dblInput->hasAcceptableInput(), true);
QTest::keyPress(&window, Qt::Key_1);
- QTest::keyRelease(&window, Qt::Key_1, Qt::NoModifier ,10);
- QTest::qWait(50);
+ QTest::keyRelease(&window, Qt::Key_1, Qt::NoModifier);
QTRY_COMPARE(dblInput->text(), QLatin1String("12,"));
QCOMPARE(dblInput->hasAcceptableInput(), true);
dblValidator->setLocaleName(deLocale.name());
QCOMPARE(dblInput->hasAcceptableInput(), true);
QTest::keyPress(&window, Qt::Key_1);
- QTest::keyRelease(&window, Qt::Key_1, Qt::NoModifier ,10);
- QTest::qWait(50);
+ QTest::keyRelease(&window, Qt::Key_1, Qt::NoModifier);
QTRY_COMPARE(dblInput->text(), QLatin1String("12,1"));
QCOMPARE(dblInput->hasAcceptableInput(), true);
QTest::keyPress(&window, Qt::Key_1);
- QTest::keyRelease(&window, Qt::Key_1, Qt::NoModifier ,10);
- QTest::qWait(50);
+ QTest::keyRelease(&window, Qt::Key_1, Qt::NoModifier);
QTRY_COMPARE(dblInput->text(), QLatin1String("12,11"));
QCOMPARE(dblInput->hasAcceptableInput(), true);
QTest::keyPress(&window, Qt::Key_Backspace);
- QTest::keyRelease(&window, Qt::Key_Backspace, Qt::NoModifier ,10);
- QTest::qWait(50);
+ QTest::keyRelease(&window, Qt::Key_Backspace, Qt::NoModifier);
QTRY_COMPARE(dblInput->text(), QLatin1String("12,1"));
QCOMPARE(dblInput->hasAcceptableInput(), true);
QTest::keyPress(&window, Qt::Key_Backspace);
- QTest::keyRelease(&window, Qt::Key_Backspace, Qt::NoModifier ,10);
- QTest::qWait(50);
+ QTest::keyRelease(&window, Qt::Key_Backspace, Qt::NoModifier);
QTRY_COMPARE(dblInput->text(), QLatin1String("12,"));
QCOMPARE(dblInput->hasAcceptableInput(), true);
QTest::keyPress(&window, Qt::Key_Backspace);
- QTest::keyRelease(&window, Qt::Key_Backspace, Qt::NoModifier ,10);
- QTest::qWait(50);
+ QTest::keyRelease(&window, Qt::Key_Backspace, Qt::NoModifier);
QTRY_COMPARE(dblInput->text(), QLatin1String("12"));
QCOMPARE(dblInput->hasAcceptableInput(), true);
dblValidator->resetLocaleName();
QTest::keyPress(&window, Qt::Key_Period);
- QTest::keyRelease(&window, Qt::Key_Period, Qt::NoModifier ,10);
- QTest::qWait(50);
+ QTest::keyRelease(&window, Qt::Key_Period, Qt::NoModifier);
QTRY_COMPARE(dblInput->text(), QLatin1String("12."));
QCOMPARE(dblInput->hasAcceptableInput(), true);
QCOMPARE(dblInput->property("acceptable").toBool(), true);
QCOMPARE(dblSpy.count(), 1);
QTest::keyPress(&window, Qt::Key_1);
- QTest::keyRelease(&window, Qt::Key_1, Qt::NoModifier ,10);
- QTest::qWait(50);
+ QTest::keyRelease(&window, Qt::Key_1, Qt::NoModifier);
QTRY_COMPARE(dblInput->text(), QLatin1String("12.1"));
QCOMPARE(dblInput->hasAcceptableInput(), true);
QCOMPARE(dblInput->property("acceptable").toBool(), true);
QCOMPARE(dblSpy.count(), 1);
QTest::keyPress(&window, Qt::Key_1);
- QTest::keyRelease(&window, Qt::Key_1, Qt::NoModifier ,10);
- QTest::qWait(50);
+ QTest::keyRelease(&window, Qt::Key_1, Qt::NoModifier);
QTRY_COMPARE(dblInput->text(), QLatin1String("12.11"));
QCOMPARE(dblInput->hasAcceptableInput(), true);
QCOMPARE(dblInput->property("acceptable").toBool(), true);
QCOMPARE(dblSpy.count(), 1);
QTest::keyPress(&window, Qt::Key_1);
- QTest::keyRelease(&window, Qt::Key_1, Qt::NoModifier ,10);
- QTest::qWait(50);
+ QTest::keyRelease(&window, Qt::Key_1, Qt::NoModifier);
QTRY_COMPARE(dblInput->text(), QLatin1String("12.11"));
QCOMPARE(dblInput->hasAcceptableInput(), true);
QCOMPARE(dblInput->property("acceptable").toBool(), true);
@@ -2106,50 +2082,43 @@ void tst_qquicktextinput::validators()
QCOMPARE(dblInput->property("acceptable").toBool(), false);
QCOMPARE(dblSpy.count(), 2);
QTest::keyPress(&window, Qt::Key_Backspace);
- QTest::keyRelease(&window, Qt::Key_Backspace, Qt::NoModifier ,10);
- QTest::qWait(50);
+ QTest::keyRelease(&window, Qt::Key_Backspace, Qt::NoModifier);
QTRY_COMPARE(dblInput->text(), QLatin1String("12.1"));
QCOMPARE(dblInput->hasAcceptableInput(), false);
QCOMPARE(dblInput->property("acceptable").toBool(), false);
QCOMPARE(dblSpy.count(), 2);
// Once unacceptable input is in anything goes until it reaches an acceptable state again.
QTest::keyPress(&window, Qt::Key_1);
- QTest::keyRelease(&window, Qt::Key_1, Qt::NoModifier ,10);
- QTest::qWait(50);
+ QTest::keyRelease(&window, Qt::Key_1, Qt::NoModifier);
QTRY_COMPARE(dblInput->text(), QLatin1String("12.11"));
QCOMPARE(dblInput->hasAcceptableInput(), false);
QCOMPARE(dblSpy.count(), 2);
QTest::keyPress(&window, Qt::Key_Backspace);
- QTest::keyRelease(&window, Qt::Key_Backspace, Qt::NoModifier ,10);
- QTest::qWait(50);
+ QTest::keyRelease(&window, Qt::Key_Backspace, Qt::NoModifier);
QTRY_COMPARE(dblInput->text(), QLatin1String("12.1"));
QCOMPARE(dblInput->hasAcceptableInput(), false);
QCOMPARE(dblInput->property("acceptable").toBool(), false);
QCOMPARE(dblSpy.count(), 2);
QTest::keyPress(&window, Qt::Key_Backspace);
- QTest::keyRelease(&window, Qt::Key_Backspace, Qt::NoModifier ,10);
- QTest::qWait(50);
+ QTest::keyRelease(&window, Qt::Key_Backspace, Qt::NoModifier);
QTRY_COMPARE(dblInput->text(), QLatin1String("12."));
QCOMPARE(dblInput->hasAcceptableInput(), false);
QCOMPARE(dblInput->property("acceptable").toBool(), false);
QCOMPARE(dblSpy.count(), 2);
QTest::keyPress(&window, Qt::Key_Backspace);
- QTest::keyRelease(&window, Qt::Key_Backspace, Qt::NoModifier ,10);
- QTest::qWait(50);
+ QTest::keyRelease(&window, Qt::Key_Backspace, Qt::NoModifier);
QTRY_COMPARE(dblInput->text(), QLatin1String("12"));
QCOMPARE(dblInput->hasAcceptableInput(), false);
QCOMPARE(dblInput->property("acceptable").toBool(), false);
QCOMPARE(dblSpy.count(), 2);
QTest::keyPress(&window, Qt::Key_Backspace);
- QTest::keyRelease(&window, Qt::Key_Backspace, Qt::NoModifier ,10);
- QTest::qWait(50);
+ QTest::keyRelease(&window, Qt::Key_Backspace, Qt::NoModifier);
QTRY_COMPARE(dblInput->text(), QLatin1String("1"));
QCOMPARE(dblInput->hasAcceptableInput(), false);
QCOMPARE(dblInput->property("acceptable").toBool(), false);
QCOMPARE(dblSpy.count(), 2);
QTest::keyPress(&window, Qt::Key_1);
- QTest::keyRelease(&window, Qt::Key_1, Qt::NoModifier ,10);
- QTest::qWait(50);
+ QTest::keyRelease(&window, Qt::Key_1, Qt::NoModifier);
QCOMPARE(dblInput->text(), QLatin1String("11"));
QCOMPARE(dblInput->property("acceptable").toBool(), true);
QCOMPARE(dblInput->hasAcceptableInput(), true);
@@ -2173,43 +2142,37 @@ void tst_qquicktextinput::validators()
QCOMPARE(strInput->hasAcceptableInput(), false);
QCOMPARE(strInput->property("acceptable").toBool(), false);
QTest::keyPress(&window, Qt::Key_1);
- QTest::keyRelease(&window, Qt::Key_1, Qt::NoModifier ,10);
- QTest::qWait(50);
+ QTest::keyRelease(&window, Qt::Key_1, Qt::NoModifier);
QTRY_COMPARE(strInput->text(), QLatin1String(""));
QCOMPARE(strInput->hasAcceptableInput(), false);
QCOMPARE(strInput->property("acceptable").toBool(), false);
QCOMPARE(strSpy.count(), 0);
QTest::keyPress(&window, Qt::Key_A);
- QTest::keyRelease(&window, Qt::Key_A, Qt::NoModifier ,10);
- QTest::qWait(50);
+ QTest::keyRelease(&window, Qt::Key_A, Qt::NoModifier);
QTRY_COMPARE(strInput->text(), QLatin1String("a"));
QCOMPARE(strInput->hasAcceptableInput(), false);
QCOMPARE(strInput->property("acceptable").toBool(), false);
QCOMPARE(strSpy.count(), 0);
QTest::keyPress(&window, Qt::Key_A);
- QTest::keyRelease(&window, Qt::Key_A, Qt::NoModifier ,10);
- QTest::qWait(50);
+ QTest::keyRelease(&window, Qt::Key_A, Qt::NoModifier);
QTRY_COMPARE(strInput->text(), QLatin1String("aa"));
QCOMPARE(strInput->hasAcceptableInput(), true);
QCOMPARE(strInput->property("acceptable").toBool(), true);
QCOMPARE(strSpy.count(), 1);
QTest::keyPress(&window, Qt::Key_A);
- QTest::keyRelease(&window, Qt::Key_A, Qt::NoModifier ,10);
- QTest::qWait(50);
+ QTest::keyRelease(&window, Qt::Key_A, Qt::NoModifier);
QTRY_COMPARE(strInput->text(), QLatin1String("aaa"));
QCOMPARE(strInput->hasAcceptableInput(), true);
QCOMPARE(strInput->property("acceptable").toBool(), true);
QCOMPARE(strSpy.count(), 1);
QTest::keyPress(&window, Qt::Key_A);
- QTest::keyRelease(&window, Qt::Key_A, Qt::NoModifier ,10);
- QTest::qWait(50);
+ QTest::keyRelease(&window, Qt::Key_A, Qt::NoModifier);
QTRY_COMPARE(strInput->text(), QLatin1String("aaaa"));
QCOMPARE(strInput->hasAcceptableInput(), true);
QCOMPARE(strInput->property("acceptable").toBool(), true);
QCOMPARE(strSpy.count(), 1);
QTest::keyPress(&window, Qt::Key_A);
- QTest::keyRelease(&window, Qt::Key_A, Qt::NoModifier ,10);
- QTest::qWait(50);
+ QTest::keyRelease(&window, Qt::Key_A, Qt::NoModifier);
QTRY_COMPARE(strInput->text(), QLatin1String("aaaa"));
QCOMPARE(strInput->hasAcceptableInput(), true);
QCOMPARE(strInput->property("acceptable").toBool(), true);
@@ -2223,15 +2186,13 @@ void tst_qquicktextinput::validators()
QCOMPARE(unvalidatedInput->hasAcceptableInput(), true);
QCOMPARE(unvalidatedInput->property("acceptable").toBool(), true);
QTest::keyPress(&window, Qt::Key_1);
- QTest::keyRelease(&window, Qt::Key_1, Qt::NoModifier ,10);
- QTest::qWait(50);
+ QTest::keyRelease(&window, Qt::Key_1, Qt::NoModifier);
QTRY_COMPARE(unvalidatedInput->text(), QLatin1String("1"));
QCOMPARE(unvalidatedInput->hasAcceptableInput(), true);
QCOMPARE(unvalidatedInput->property("acceptable").toBool(), true);
QCOMPARE(unvalidatedSpy.count(), 0);
QTest::keyPress(&window, Qt::Key_A);
- QTest::keyRelease(&window, Qt::Key_A, Qt::NoModifier ,10);
- QTest::qWait(50);
+ QTest::keyRelease(&window, Qt::Key_A, Qt::NoModifier);
QTRY_COMPARE(unvalidatedInput->text(), QLatin1String("1a"));
QCOMPARE(unvalidatedInput->hasAcceptableInput(), true);
QCOMPARE(unvalidatedInput->property("acceptable").toBool(), true);
@@ -2305,6 +2266,48 @@ void tst_qquicktextinput::inputMethods()
QCOMPARE(enabledQueryEvent.value(Qt::ImEnabled).toBool(), false);
}
+void tst_qquicktextinput::signal_accepted()
+{
+ QQuickView window(testFileUrl("signal_accepted.qml"));
+ window.show();
+ window.requestActivate();
+ QTest::qWaitForWindowActive(&window);
+
+ QVERIFY(window.rootObject() != 0);
+
+ QQuickTextInput *input = qobject_cast<QQuickTextInput *>(qvariant_cast<QObject *>(window.rootObject()->property("input")));
+ QVERIFY(input);
+ QSignalSpy acceptedSpy(input, SIGNAL(accepted()));
+ QSignalSpy inputSpy(input, SIGNAL(acceptableInputChanged()));
+
+ input->setFocus(true);
+ QTRY_VERIFY(input->hasActiveFocus());
+ QCOMPARE(input->hasAcceptableInput(), false);
+ QCOMPARE(input->property("acceptable").toBool(), false);
+
+ QTest::keyPress(&window, Qt::Key_A);
+ QTest::keyRelease(&window, Qt::Key_A, Qt::NoModifier);
+ QTRY_COMPARE(input->text(), QLatin1String("a"));
+ QCOMPARE(input->hasAcceptableInput(), false);
+ QCOMPARE(input->property("acceptable").toBool(), false);
+ QTRY_COMPARE(inputSpy.count(), 0);
+
+ QTest::keyPress(&window, Qt::Key_Enter);
+ QTest::keyRelease(&window, Qt::Key_Enter, Qt::NoModifier);
+ QTRY_COMPARE(acceptedSpy.count(), 0);
+
+ QTest::keyPress(&window, Qt::Key_A);
+ QTest::keyRelease(&window, Qt::Key_A, Qt::NoModifier);
+ QTRY_COMPARE(input->text(), QLatin1String("aa"));
+ QCOMPARE(input->hasAcceptableInput(), true);
+ QCOMPARE(input->property("acceptable").toBool(), true);
+ QTRY_COMPARE(inputSpy.count(), 1);
+
+ QTest::keyPress(&window, Qt::Key_Enter);
+ QTest::keyRelease(&window, Qt::Key_Enter, Qt::NoModifier);
+ QTRY_COMPARE(acceptedSpy.count(), 1);
+}
+
void tst_qquicktextinput::signal_editingfinished()
{
QQuickView window(testFileUrl("signal_editingfinished.qml"));
@@ -2318,7 +2321,8 @@ void tst_qquicktextinput::signal_editingfinished()
QVERIFY(input1);
QQuickTextInput *input2 = qobject_cast<QQuickTextInput *>(qvariant_cast<QObject *>(window.rootObject()->property("input2")));
QVERIFY(input2);
- QSignalSpy input1Spy(input1, SIGNAL(editingFinished()));
+ QSignalSpy editingFinished1Spy(input1, SIGNAL(editingFinished()));
+ QSignalSpy input1Spy(input1, SIGNAL(acceptableInputChanged()));
input1->setFocus(true);
QTRY_VERIFY(input1->hasActiveFocus());
@@ -2327,12 +2331,28 @@ void tst_qquicktextinput::signal_editingfinished()
QTest::keyPress(&window, Qt::Key_A);
QTest::keyRelease(&window, Qt::Key_A, Qt::NoModifier);
QTRY_COMPARE(input1->text(), QLatin1String("a"));
+ QCOMPARE(input1->hasAcceptableInput(), false);
+ QCOMPARE(input1->property("acceptable").toBool(), false);
+ QTRY_COMPARE(input1Spy.count(), 0);
+
+ QTest::keyPress(&window, Qt::Key_Enter);
+ QTest::keyRelease(&window, Qt::Key_Enter, Qt::NoModifier);
+ QTRY_COMPARE(editingFinished1Spy.count(), 0);
+
+ QTest::keyPress(&window, Qt::Key_A);
+ QTest::keyRelease(&window, Qt::Key_A, Qt::NoModifier);
+ QTRY_COMPARE(input1->text(), QLatin1String("aa"));
+ QCOMPARE(input1->hasAcceptableInput(), true);
+ QCOMPARE(input1->property("acceptable").toBool(), true);
+ QTRY_COMPARE(input1Spy.count(), 1);
QTest::keyPress(&window, Qt::Key_Enter);
QTest::keyRelease(&window, Qt::Key_Enter, Qt::NoModifier);
+ QTRY_COMPARE(editingFinished1Spy.count(), 1);
QTRY_COMPARE(input1Spy.count(), 1);
- QSignalSpy input2Spy(input2, SIGNAL(editingFinished()));
+ QSignalSpy editingFinished2Spy(input2, SIGNAL(editingFinished()));
+ QSignalSpy input2Spy(input2, SIGNAL(acceptableInputChanged()));
input2->setFocus(true);
QTRY_VERIFY(!input1->hasActiveFocus());
@@ -2341,11 +2361,21 @@ void tst_qquicktextinput::signal_editingfinished()
QTest::keyPress(&window, Qt::Key_A);
QTest::keyRelease(&window, Qt::Key_A, Qt::NoModifier);
QTRY_COMPARE(input2->text(), QLatin1String("a"));
+ QCOMPARE(input2->hasAcceptableInput(), false);
+ QCOMPARE(input2->property("acceptable").toBool(), false);
+ QTRY_COMPARE(input2Spy.count(), 0);
+
+ QTest::keyPress(&window, Qt::Key_A);
+ QTest::keyRelease(&window, Qt::Key_A, Qt::NoModifier);
+ QTRY_COMPARE(input2->text(), QLatin1String("aa"));
+ QCOMPARE(input2->hasAcceptableInput(), true);
+ QCOMPARE(input2->property("acceptable").toBool(), true);
+ QTRY_COMPARE(input2Spy.count(), 1);
input1->setFocus(true);
QTRY_VERIFY(input1->hasActiveFocus());
QTRY_VERIFY(!input2->hasActiveFocus());
- QTRY_COMPARE(input2Spy.count(), 1);
+ QTRY_COMPARE(editingFinished2Spy.count(), 1);
}
/*
@@ -6296,6 +6326,38 @@ void tst_qquicktextinput::maskCharacter()
}
}
+class TestValidator : public QValidator
+{
+public:
+ TestValidator(QObject *parent = 0) : QValidator(parent) { }
+
+ State validate(QString &input, int &) const { return input == QStringLiteral("ok") ? Acceptable : Intermediate; }
+ void fixup(QString &input) const { input = QStringLiteral("ok"); }
+};
+
+void tst_qquicktextinput::fixup()
+{
+ QQuickWindow window;
+ window.show();
+ window.requestActivate();
+ QTest::qWaitForWindowActive(&window);
+
+ QQuickTextInput *input = new QQuickTextInput(window.contentItem());
+ input->setValidator(new TestValidator(input));
+
+ // fixup() on accept
+ input->setFocus(true);
+ QVERIFY(input->hasActiveFocus());
+ QTest::keyClick(&window, Qt::Key_Enter);
+ QCOMPARE(input->text(), QStringLiteral("ok"));
+
+ // fixup() on defocus
+ input->setText(QString());
+ input->setFocus(false);
+ QVERIFY(!input->hasActiveFocus());
+ QCOMPARE(input->text(), QStringLiteral("ok"));
+}
+
QTEST_MAIN(tst_qquicktextinput)
#include "tst_qquicktextinput.moc"
diff --git a/tests/auto/quick/qquickwindow/data/focus.qml b/tests/auto/quick/qquickwindow/data/focus.qml
index 899b999cdc..fa8ae9dc69 100644
--- a/tests/auto/quick/qquickwindow/data/focus.qml
+++ b/tests/auto/quick/qquickwindow/data/focus.qml
@@ -12,4 +12,8 @@ Window.Window {
Item {
objectName: "item2"
}
+
+ FocusScope {
+ Item { objectName: "item3" }
+ }
}
diff --git a/tests/auto/quick/qquickwindow/tst_qquickwindow.cpp b/tests/auto/quick/qquickwindow/tst_qquickwindow.cpp
index b09f80a634..107d1d71f7 100644
--- a/tests/auto/quick/qquickwindow/tst_qquickwindow.cpp
+++ b/tests/auto/quick/qquickwindow/tst_qquickwindow.cpp
@@ -1145,20 +1145,35 @@ void tst_qquickwindow::focusObject()
QQuickWindow *window = qobject_cast<QQuickWindow*>(created);
QVERIFY(window);
+ QSignalSpy focusObjectSpy(window, SIGNAL(focusObjectChanged(QObject*)));
+
window->show();
QVERIFY(QTest::qWaitForWindowExposed(window));
window->requestActivate();
QVERIFY(QTest::qWaitForWindowActive(window));
+ QCOMPARE(window->contentItem(), window->focusObject());
+ QCOMPARE(focusObjectSpy.count(), 1);
+
QQuickItem *item1 = window->findChild<QQuickItem*>("item1");
QVERIFY(item1);
item1->setFocus(true);
QCOMPARE(item1, window->focusObject());
+ QCOMPARE(focusObjectSpy.count(), 2);
QQuickItem *item2 = window->findChild<QQuickItem*>("item2");
QVERIFY(item2);
item2->setFocus(true);
QCOMPARE(item2, window->focusObject());
+ QCOMPARE(focusObjectSpy.count(), 3);
+
+ // set focus for item in non-focused focus scope and
+ // ensure focusObject does not change and signal is not emitted
+ QQuickItem *item3 = window->findChild<QQuickItem*>("item3");
+ QVERIFY(item3);
+ item3->setFocus(true);
+ QCOMPARE(item2, window->focusObject());
+ QCOMPARE(focusObjectSpy.count(), 3);
}
void tst_qquickwindow::ignoreUnhandledMouseEvents()
diff --git a/tests/auto/quick/scenegraph/data/simple.qml b/tests/auto/quick/scenegraph/data/simple.qml
new file mode 100644
index 0000000000..b2924f135e
--- /dev/null
+++ b/tests/auto/quick/scenegraph/data/simple.qml
@@ -0,0 +1,60 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the test suite of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick 2.2
+
+Rectangle {
+ width: 200
+ height: 200
+ color: "steelblue"
+ Rectangle {
+ width: 150
+ height: 150
+ anchors.centerIn: parent
+ color: "palegreen"
+ rotation: 45
+ Text {
+ rotation: -45
+ text: "Simple QML.."
+ anchors.centerIn: parent
+ }
+ }
+}
diff --git a/tests/auto/quick/scenegraph/scenegraph.pro b/tests/auto/quick/scenegraph/scenegraph.pro
index 105221b7f4..1aa73ca60a 100644
--- a/tests/auto/quick/scenegraph/scenegraph.pro
+++ b/tests/auto/quick/scenegraph/scenegraph.pro
@@ -11,4 +11,5 @@ QT += core-private gui-private qml-private quick-private testlib
DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0
OTHER_FILES += \
- data/render_OutOfFloatRange.qml
+ data/render_OutOfFloatRange.qml \
+ data/simple.qml
diff --git a/tests/auto/quick/scenegraph/tst_scenegraph.cpp b/tests/auto/quick/scenegraph/tst_scenegraph.cpp
index 3b79f01f12..780d5a97db 100644
--- a/tests/auto/quick/scenegraph/tst_scenegraph.cpp
+++ b/tests/auto/quick/scenegraph/tst_scenegraph.cpp
@@ -58,6 +58,8 @@ private slots:
void render_data();
void render();
+
+ void hideWithOtherContext();
};
template <typename T> class ScopedList : public QList<T> {
@@ -401,6 +403,40 @@ void tst_SceneGraph::render()
}
}
+// Testcase for QTBUG-34898. We make another context current on another surface
+// in the GUI thread and hide the QQuickWindow while the other context is
+// current on the other window.
+void tst_SceneGraph::hideWithOtherContext()
+{
+ QWindow window;
+ window.setSurfaceType(QWindow::OpenGLSurface);
+ window.resize(100, 100);
+ window.create();
+ QOpenGLContext context;
+ context.create();
+ bool renderingOnMainThread = false;
+
+ {
+ QQuickView view;
+ view.setSource(QUrl::fromLocalFile("data/simple.qml"));
+ view.setResizeMode(QQuickView::SizeViewToRootObject);
+ view.show();
+ QVERIFY(QTest::qWaitForWindowExposed(&view));
+
+ renderingOnMainThread = view.openglContext()->thread() == QGuiApplication::instance()->thread();
+
+ // Make the local context current on the local window...
+ context.makeCurrent(&window);
+ }
+
+ // The local context should no longer be the current one. It is not
+ // rebound because all well behaving Qt/OpenGL applications are
+ // required to makeCurrent their context again before making any
+ // GL calls to a new frame (see QOpenGLContext docs).
+ QVERIFY(!renderingOnMainThread || QOpenGLContext::currentContext() != &context);
+}
+
+
#include "tst_scenegraph.moc"
QTEST_MAIN(tst_SceneGraph)
diff --git a/tests/auto/shared/testhttpserver.cpp b/tests/auto/shared/testhttpserver.cpp
index fd681710de..20df0c12f5 100644
--- a/tests/auto/shared/testhttpserver.cpp
+++ b/tests/auto/shared/testhttpserver.cpp
@@ -88,7 +88,7 @@ The following request urls will then result in the appropriate action:
\endtable
*/
TestHTTPServer::TestHTTPServer(quint16 port)
-: m_hasFailed(false)
+: m_state(AwaitingHeader)
{
QObject::connect(&server, SIGNAL(newConnection()), this, SLOT(newConnection()));
@@ -122,7 +122,8 @@ void TestHTTPServer::addRedirect(const QString &filename, const QString &redirec
bool TestHTTPServer::wait(const QUrl &expect, const QUrl &reply, const QUrl &body)
{
- m_hasFailed = false;
+ m_state = AwaitingHeader;
+ m_data.clear();
QFile expectFile(expect.toLocalFile());
if (!expectFile.open(QIODevice::ReadOnly)) return false;
@@ -175,7 +176,7 @@ bool TestHTTPServer::wait(const QUrl &expect, const QUrl &reply, const QUrl &bod
bool TestHTTPServer::hasFailed() const
{
- return m_hasFailed;
+ return m_state == Failed;
}
void TestHTTPServer::newConnection()
@@ -216,33 +217,41 @@ void TestHTTPServer::readyRead()
return;
}
- if (m_hasFailed || (waitData.body.isEmpty() && waitData.headers.count() == 0)) {
+ if (m_state == Failed || (waitData.body.isEmpty() && waitData.headers.count() == 0)) {
qWarning() << "TestHTTPServer: Unexpected data" << socket->readAll();
return;
}
- QByteArray line;
- while (!(line = socket->readLine()).isEmpty()) {
- line.replace('\r', "");
- if (line.at(0) == '\n') {
- QByteArray data = socket->readAll();
- if (waitData.body != data) {
- qWarning() << "TestHTTPServer: Unexpected data" << data << "\nExpected: " << waitData.body;
- m_hasFailed = true;
- socket->disconnectFromHost();
- return;
+ if (m_state == AwaitingHeader) {
+ QByteArray line;
+ while (!(line = socket->readLine()).isEmpty()) {
+ line.replace('\r', "");
+ if (line.at(0) == '\n') {
+ m_state = AwaitingData;
+ m_data += socket->readAll();
+ break;
+ } else {
+ if (!waitData.headers.contains(line)) {
+ qWarning() << "TestHTTPServer: Unexpected header:" << line << "\nExpected headers: " << waitData.headers;
+ m_state = Failed;
+ socket->disconnectFromHost();
+ return;
+ }
}
}
- else if (!waitData.headers.contains(line)) {
- qWarning() << "TestHTTPServer: Unexpected header:" << line << "\nExpected headers: " << waitData.headers;
- m_hasFailed = true;
- socket->disconnectFromHost();
- return;
- }
+ } else {
+ m_data += socket->readAll();
}
- socket->write(replyData);
- socket->disconnectFromHost();
+ if (!m_data.isEmpty() || waitData.body.isEmpty()) {
+ if (waitData.body != m_data) {
+ qWarning() << "TestHTTPServer: Unexpected data" << m_data << "\nExpected: " << waitData.body;
+ m_state = Failed;
+ } else {
+ socket->write(replyData);
+ }
+ socket->disconnectFromHost();
+ }
}
bool TestHTTPServer::reply(QTcpSocket *socket, const QByteArray &fileName)
diff --git a/tests/auto/shared/testhttpserver.h b/tests/auto/shared/testhttpserver.h
index ce0501f170..ae7d137143 100644
--- a/tests/auto/shared/testhttpserver.h
+++ b/tests/auto/shared/testhttpserver.h
@@ -74,6 +74,12 @@ private slots:
void sendOne();
private:
+ enum State {
+ AwaitingHeader,
+ AwaitingData,
+ Failed
+ };
+
void serveGET(QTcpSocket *, const QByteArray &);
bool reply(QTcpSocket *, const QByteArray &);
@@ -87,7 +93,8 @@ private:
} waitData;
QByteArray replyData;
QByteArray bodyData;
- bool m_hasFailed;
+ QByteArray m_data;
+ State m_state;
QHash<QString,QString> aliases;
QHash<QString,QString> redirects;
diff --git a/tools/qmljs/main.cpp b/tools/qmljs/main.cpp
index 32a45d9289..9c10851b21 100644
--- a/tools/qmljs/main.cpp
+++ b/tools/qmljs/main.cpp
@@ -72,7 +72,7 @@ using namespace QV4;
struct Print: FunctionObject
{
Print(ExecutionContext *scope): FunctionObject(scope, QStringLiteral("print")) {
- vtbl = &static_vtbl;
+ setVTable(&static_vtbl);
}
static ReturnedValue call(Managed *, CallData *callData)
@@ -97,7 +97,7 @@ struct GC: public FunctionObject
GC(ExecutionContext* scope)
: FunctionObject(scope, QStringLiteral("gc"))
{
- vtbl = &static_vtbl;
+ setVTable(&static_vtbl);
}
static ReturnedValue call(Managed *m, CallData *)
{