From caa5358fe97becafeba9631f4c4d2fc69469afb1 Mon Sep 17 00:00:00 2001 From: Andy Shaw Date: Wed, 26 Apr 2017 00:16:16 +0200 Subject: Fix concurrent loading of the same qmldir from different scripts QQmlQmldirData keeps a pointer to a QQmlScript::Import, and an integer priority. Each Blob that is waiting on it was setting its own import and priority even though the QQmlQmldirData itself was shared. This resulted in whichever one began loading last succeeding to load, and the rest failing. This change instead stores the import and priority data per-dependent Blob Fix was originally done by Josh Faust . I added the test. Task-number: QTBUG-30469 Change-Id: Id3d15569a999a7c22eeb12b431e5daf1ddae51dc Reviewed-by: Simon Hausmann --- src/qml/qml/qqmltypeloader.cpp | 41 ++++++++++++++++++++++++----------------- src/qml/qml/qqmltypeloader_p.h | 12 ++++++------ 2 files changed, 30 insertions(+), 23 deletions(-) (limited to 'src') diff --git a/src/qml/qml/qqmltypeloader.cpp b/src/qml/qml/qqmltypeloader.cpp index 40bd2e5020..e4293596d8 100644 --- a/src/qml/qml/qqmltypeloader.cpp +++ b/src/qml/qml/qqmltypeloader.cpp @@ -1320,8 +1320,8 @@ bool QQmlTypeLoader::Blob::fetchQmldir(const QUrl &url, const QV4::CompiledData: { QQmlQmldirData *data = typeLoader()->getQmldir(url); - data->setImport(import); - data->setPriority(priority); + data->setImport(this, import); + data->setPriority(this, priority); if (data->status() == Error) { // This qmldir must not exist - which is not an error @@ -1349,7 +1349,7 @@ bool QQmlTypeLoader::Blob::updateQmldir(QQmlQmldirData *data, const QV4::Compile QHash::iterator it = m_unresolvedImports.find(import); if (it != m_unresolvedImports.end()) { - *it = data->priority(); + *it = data->priority(this); } // Release this reference at destruction @@ -1482,7 +1482,7 @@ void QQmlTypeLoader::Blob::dependencyComplete(QQmlDataBlob *blob) if (blob->type() == QQmlDataBlob::QmldirFile) { QQmlQmldirData *data = static_cast(blob); - const QV4::CompiledData::Import *import = data->import(); + const QV4::CompiledData::Import *import = data->import(this); QList errors; if (!qmldirDataAvailable(data, &errors)) { @@ -1506,11 +1506,11 @@ bool QQmlTypeLoader::Blob::qmldirDataAvailable(QQmlQmldirData *data, QListimport(); - data->setImport(0); + const QV4::CompiledData::Import *import = data->import(this); + data->setImport(this, 0); - int priority = data->priority(); - data->setPriority(0); + int priority = data->priority(this); + data->setPriority(this, 0); if (import) { // Do we need to resolve this import? @@ -3069,7 +3069,7 @@ void QQmlScriptBlob::initializeFromCompilationUnit(QV4::CompiledData::Compilatio } QQmlQmldirData::QQmlQmldirData(const QUrl &url, QQmlTypeLoader *loader) -: QQmlTypeLoader::Blob(url, QmldirFile, loader), m_import(0), m_priority(0) +: QQmlTypeLoader::Blob(url, QmldirFile, loader) { } @@ -3078,24 +3078,31 @@ const QString &QQmlQmldirData::content() const return m_content; } -const QV4::CompiledData::Import *QQmlQmldirData::import() const +const QV4::CompiledData::Import *QQmlQmldirData::import(QQmlTypeLoader::Blob *blob) const { - return m_import; + QHash::const_iterator it = + m_imports.find(blob); + if (it == m_imports.end()) + return 0; + return *it; } -void QQmlQmldirData::setImport(const QV4::CompiledData::Import *import) +void QQmlQmldirData::setImport(QQmlTypeLoader::Blob *blob, const QV4::CompiledData::Import *import) { - m_import = import; + m_imports[blob] = import; } -int QQmlQmldirData::priority() const +int QQmlQmldirData::priority(QQmlTypeLoader::Blob *blob) const { - return m_priority; + QHash::const_iterator it = m_priorities.find(blob); + if (it == m_priorities.end()) + return 0; + return *it; } -void QQmlQmldirData::setPriority(int priority) +void QQmlQmldirData::setPriority(QQmlTypeLoader::Blob *blob, int priority) { - m_priority = priority; + m_priorities[blob] = priority; } void QQmlQmldirData::dataReceived(const SourceCodeData &data) diff --git a/src/qml/qml/qqmltypeloader_p.h b/src/qml/qml/qqmltypeloader_p.h index 48e7d5cba4..f367fa6f58 100644 --- a/src/qml/qml/qqmltypeloader_p.h +++ b/src/qml/qml/qqmltypeloader_p.h @@ -572,11 +572,11 @@ private: public: const QString &content() const; - const QV4::CompiledData::Import *import() const; - void setImport(const QV4::CompiledData::Import *); + const QV4::CompiledData::Import *import(QQmlTypeLoader::Blob *) const; + void setImport(QQmlTypeLoader::Blob *, const QV4::CompiledData::Import *); - int priority() const; - void setPriority(int); + int priority(QQmlTypeLoader::Blob *) const; + void setPriority(QQmlTypeLoader::Blob *, int); protected: void dataReceived(const SourceCodeData &) override; @@ -584,8 +584,8 @@ protected: private: QString m_content; - const QV4::CompiledData::Import *m_import; - int m_priority; + QHash m_imports; + QHash m_priorities; }; -- cgit v1.2.3 From 4f3bb75d2271717d932eb63a1193494d44eafb4f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=BCri=20Valdmann?= Date: Wed, 3 May 2017 11:30:27 +0200 Subject: Doc: fix 'adpatation' -> 'adaptation' Change-Id: Ia852d86d9b9585a1d3d9b07eb8b48361d61c5671 Reviewed-by: Leena Miettinen --- src/quick/doc/src/concepts/visualcanvas/adaptations.qdoc | 2 +- src/quick/doc/src/concepts/visualcanvas/scenegraph.qdoc | 2 +- src/quick/doc/src/concepts/visualcanvas/topic.qdoc | 2 +- src/quick/items/qquickwindow.cpp | 4 ++-- 4 files changed, 5 insertions(+), 5 deletions(-) (limited to 'src') diff --git a/src/quick/doc/src/concepts/visualcanvas/adaptations.qdoc b/src/quick/doc/src/concepts/visualcanvas/adaptations.qdoc index 76f863d07f..bcfdf311af 100644 --- a/src/quick/doc/src/concepts/visualcanvas/adaptations.qdoc +++ b/src/quick/doc/src/concepts/visualcanvas/adaptations.qdoc @@ -73,7 +73,7 @@ adaptations. The default adaptation capable of providing the full Qt Quick 2 feature set is the OpenGL adaptation. All of the details of the OpenGL -adpatation can are available here: +adaptation can are available here: \l{qtquick-visualcanvas-scenegraph-renderer.html}{OpenGL Adaptation} \section1 Software Adaptation diff --git a/src/quick/doc/src/concepts/visualcanvas/scenegraph.qdoc b/src/quick/doc/src/concepts/visualcanvas/scenegraph.qdoc index 2e41c85873..cb14c72b04 100644 --- a/src/quick/doc/src/concepts/visualcanvas/scenegraph.qdoc +++ b/src/quick/doc/src/concepts/visualcanvas/scenegraph.qdoc @@ -32,7 +32,7 @@ \section1 The Scene Graph in Qt Quick Qt Quick 2 makes use of a dedicated scene graph based and a series of -adpatations of which the default uses OpenGL ES 2.0 or OpenGL 2.0 for +adaptations of which the default uses OpenGL ES 2.0 or OpenGL 2.0 for its rendering. Using a scene graph for graphics rather than the traditional imperative painting systems (QPainter and similar), means the scene to be rendered can be retained between diff --git a/src/quick/doc/src/concepts/visualcanvas/topic.qdoc b/src/quick/doc/src/concepts/visualcanvas/topic.qdoc index 168c616d06..f6b4024f7a 100644 --- a/src/quick/doc/src/concepts/visualcanvas/topic.qdoc +++ b/src/quick/doc/src/concepts/visualcanvas/topic.qdoc @@ -57,7 +57,7 @@ See the documentation about the \l{qtquick-visualcanvas-visualparent.html} Modern computer systems and devices use graphics processing units or GPUs to render graphics. Qt Quick can leverage this graphics hardware by using graphics -APIs like OpenGL. The default graphics adpatation for Qt Quick requires OpenGL and +APIs like OpenGL. The default graphics adaptation for Qt Quick requires OpenGL and it is used to display applications developed with Qt Quick in QML. In particular, Qt Quick defines a scene graph which is then rendered. See the documentation about the \l{qtquick-visualcanvas-scenegraph.html}{Scene Graph} for in-depth information about diff --git a/src/quick/items/qquickwindow.cpp b/src/quick/items/qquickwindow.cpp index 8e78586697..90bdfd41e2 100644 --- a/src/quick/items/qquickwindow.cpp +++ b/src/quick/items/qquickwindow.cpp @@ -3853,7 +3853,7 @@ QSGTexture *QQuickWindow::createTextureFromImage(const QImage &image, CreateText initialized or OpenGL is not in use. \note This function only has an effect when using the default OpenGL scene graph - adpation. + adaptation. \sa sceneGraphInitialized(), QSGTexture */ @@ -3961,7 +3961,7 @@ void QQuickWindow::setDefaultAlphaBuffer(bool useAlpha) graph renderer. Clear these manually on demand. \note This function only has an effect when using the default OpenGL scene graph - adpation. + adaptation. \sa QQuickWindow::beforeRendering() */ -- cgit v1.2.3 From 30dbe57521c9b1f4cac74db8f5f15a3c466c20d0 Mon Sep 17 00:00:00 2001 From: Peter Hartmann Date: Wed, 15 Mar 2017 11:59:14 +0100 Subject: QQmlComponent: Fix heap buffer overflow with bogus input Change-Id: I8a725018a5aeb39df370f856cd77d887faa511e3 Reviewed-by: Simon Hausmann --- src/qml/parser/qqmljslexer.cpp | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'src') diff --git a/src/qml/parser/qqmljslexer.cpp b/src/qml/parser/qqmljslexer.cpp index 66f9eac126..53e67fde03 100644 --- a/src/qml/parser/qqmljslexer.cpp +++ b/src/qml/parser/qqmljslexer.cpp @@ -724,6 +724,11 @@ again: return multilineStringLiteral ? T_MULTILINE_STRING_LITERAL : T_STRING_LITERAL; } else if (_char == QLatin1Char('\\')) { scanChar(); + if (_codePtr > _endPtr) { + _errorCode = IllegalEscapeSequence; + _errorMessage = QCoreApplication::translate("QQmlParser", "End of file reached at escape sequence"); + return T_ERROR; + } QChar u; -- cgit v1.2.3 From 0da6de65468d3b8cc1ca7ee0af10f254ae3d4dd6 Mon Sep 17 00:00:00 2001 From: Simon Hausmann Date: Wed, 3 May 2017 16:58:44 +0200 Subject: Fix ARM64 code generation When generating instructions for pointer arithmetic, do use the 64-bit registers, otherwise for example when loading pointers we'll end up only loading the lower 32 bits. Task-number: QTBUG-60441 Change-Id: I2c7c82964029e383afcadabc078842690d2d637a Reviewed-by: Robin Burchell --- src/3rdparty/masm/assembler/MacroAssemblerARM64.h | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'src') diff --git a/src/3rdparty/masm/assembler/MacroAssemblerARM64.h b/src/3rdparty/masm/assembler/MacroAssemblerARM64.h index 11f1672e15..d5f4acb3ca 100644 --- a/src/3rdparty/masm/assembler/MacroAssemblerARM64.h +++ b/src/3rdparty/masm/assembler/MacroAssemblerARM64.h @@ -214,27 +214,27 @@ public: #if defined(V4_BOOTSTRAP) void loadPtr(ImplicitAddress address, RegisterID dest) { - load32(address, dest); + load64(address, dest); } void subPtr(TrustedImm32 imm, RegisterID dest) { - sub32(imm, dest); + sub64(imm, dest); } void addPtr(TrustedImm32 imm, RegisterID dest) { - add32(imm, dest); + add64(imm, dest); } void addPtr(TrustedImm32 imm, RegisterID src, RegisterID dest) { - add32(imm, src, dest); + add64(imm, src, dest); } void storePtr(RegisterID src, ImplicitAddress address) { - store32(src, address); + store64(src, address); } #endif -- cgit v1.2.3 From 566eea09a851c221c557fc5c386ba3d0613e3b05 Mon Sep 17 00:00:00 2001 From: Robin Burchell Date: Tue, 2 May 2017 23:17:51 +0200 Subject: QV4BooleanObject: Avoid GC'd allocations when calling toString() Use the global strings instead. Change-Id: Ia43045ca3f40e80d44956cf8e38511cfc4c8a8bb Reviewed-by: Simon Hausmann --- src/qml/jsruntime/qv4booleanobject.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/qml/jsruntime/qv4booleanobject.cpp b/src/qml/jsruntime/qv4booleanobject.cpp index 601066110f..c8e9ebb2dd 100644 --- a/src/qml/jsruntime/qv4booleanobject.cpp +++ b/src/qml/jsruntime/qv4booleanobject.cpp @@ -85,7 +85,7 @@ void BooleanPrototype::method_toString(const BuiltinFunction *, Scope &scope, Ca result = thisObject->value(); } - scope.result = scope.engine->newString(QLatin1String(result ? "true" : "false")); + scope.result = result ? scope.engine->id_true() : scope.engine->id_false(); } void BooleanPrototype::method_valueOf(const BuiltinFunction *, Scope &scope, CallData *callData) -- cgit v1.2.3 From a69edf01cb0a2a06282dc7b89724ffa542f6546d Mon Sep 17 00:00:00 2001 From: Kimmo Ollila Date: Wed, 3 May 2017 12:45:45 +0300 Subject: Add qtConfig(dlopen) check before adding libdl Change-Id: Iad67b9719fe6336b8dfc28de2e88463c588a0849 Reviewed-by: Simon Hausmann --- src/qml/compiler/compiler.pri | 2 +- src/qml/compiler/qv4compileddata.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/qml/compiler/compiler.pri b/src/qml/compiler/compiler.pri index 31ee917b39..60f548a2b0 100644 --- a/src/qml/compiler/compiler.pri +++ b/src/qml/compiler/compiler.pri @@ -41,7 +41,7 @@ SOURCES += \ unix: SOURCES += $$PWD/qv4compilationunitmapper_unix.cpp else: SOURCES += $$PWD/qv4compilationunitmapper_win.cpp -qtConfig(private_tests):unix: QMAKE_USE_PRIVATE += libdl +qtConfig(private_tests):qtConfig(dlopen): QMAKE_USE_PRIVATE += libdl } qmldevtools_build|qtConfig(qml-interpreter) { diff --git a/src/qml/compiler/qv4compileddata.cpp b/src/qml/compiler/qv4compileddata.cpp index 71546cc22e..d59a72cde2 100644 --- a/src/qml/compiler/qv4compileddata.cpp +++ b/src/qml/compiler/qv4compileddata.cpp @@ -734,7 +734,7 @@ static QByteArray ownLibraryChecksum() if (checksumInitialized) return libraryChecksum; checksumInitialized = true; -#if defined(Q_OS_UNIX) && !defined(QT_NO_DYNAMIC_CAST) && !defined(Q_OS_INTEGRITY) +#if !defined(QT_NO_DYNAMIC_CAST) && QT_CONFIG(dlopen) Dl_info libInfo; if (dladdr(reinterpret_cast(&ownLibraryChecksum), &libInfo) != 0) { QFile library(QFile::decodeName(libInfo.dli_fname)); -- cgit v1.2.3 From 0b403a9e3f81b63855e7285f5f7ec6bb497beb2e Mon Sep 17 00:00:00 2001 From: Shawn Rutledge Date: Thu, 20 Apr 2017 10:08:11 +0200 Subject: Fix remaining QQWindow qCDebugs to show eventpoint IDs in hex MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Change-Id: I04122218499733856136f5a49b72707a0e8885e5 Reviewed-by: Jan Arve Sæther --- src/quick/items/qquickwindow.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/quick/items/qquickwindow.cpp b/src/quick/items/qquickwindow.cpp index 90bdfd41e2..98901ab818 100644 --- a/src/quick/items/qquickwindow.cpp +++ b/src/quick/items/qquickwindow.cpp @@ -751,7 +751,7 @@ void QQuickWindowPrivate::setMouseGrabber(QQuickItem *grabber) if (grabber && touchMouseId != -1 && touchMouseDevice) { // update the touch item for mouse touch id to the new grabber - qCDebug(DBG_TOUCH_TARGET) << "TP (mouse)" << touchMouseId << "->" << q->mouseGrabberItem(); + qCDebug(DBG_TOUCH_TARGET) << "TP (mouse)" << hex << touchMouseId << "->" << q->mouseGrabberItem(); auto point = touchMouseDevice->pointerEvent()->pointById(touchMouseId); if (point) point->setGrabber(grabber); @@ -2227,7 +2227,7 @@ void QQuickWindowPrivate::deliverTouchEvent(QQuickPointerTouchEvent *event) QQuickEventPoint *point = event->point(i); if (point->state() == QQuickEventPoint::Released) { int id = point->pointId(); - qCDebug(DBG_TOUCH_TARGET) << "TP" << id << "released"; + qCDebug(DBG_TOUCH_TARGET) << "TP" << hex << id << "released"; point->setGrabber(nullptr); if (id == touchMouseId) { touchMouseId = -1; -- cgit v1.2.3 From 66724f59910a87f924f0fd7d9954ced9413676b1 Mon Sep 17 00:00:00 2001 From: Thiago Macieira Date: Wed, 3 May 2017 14:30:05 -0700 Subject: Add missing break Commit 2a812493bc97983b85110f853d3dbe57b54667d8 added the VariantMap case but forgot to add the break before it (there wasn't a break because it fell through to default: break). This is a 6.5 year old issue, though it affected no one because setVariantMapProperty checks the destination's type again. Found by GCC 7: qqmllistmodel.cpp:1075:62: warning: this statement may fall through [-Wimplicit-fallthrough=] target->setVariantProperty(targetRole, v); ^ qqmllistmodel.cpp:1077:13: note: here case ListLayout::Role::VariantMap: ^~~~ Change-Id: Ica9894dc9b5e48278fd4fffd14bb35efd18a8a6e Reviewed-by: Simon Hausmann --- src/qml/types/qqmllistmodel.cpp | 1 + 1 file changed, 1 insertion(+) (limited to 'src') diff --git a/src/qml/types/qqmllistmodel.cpp b/src/qml/types/qqmllistmodel.cpp index 2011fcc4d6..4d8f213284 100644 --- a/src/qml/types/qqmllistmodel.cpp +++ b/src/qml/types/qqmllistmodel.cpp @@ -1071,6 +1071,7 @@ void ListElement::sync(ListElement *src, ListLayout *srcLayout, ListElement *tar QVariant v = src->getProperty(srcRole, 0, 0); target->setVariantProperty(targetRole, v); } + break; case ListLayout::Role::VariantMap: { QVariantMap *map = src->getVariantMapProperty(srcRole); -- cgit v1.2.3 From 81785d3eb8768ba9f932dd7105eee61ce39a2a5e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=BCri=20Valdmann?= Date: Thu, 4 May 2017 15:53:41 +0200 Subject: Doc: fix some typos in qsgnode.cpp Change-Id: I9ce8f7e9dffbf7fd5280841bbe46d07eaaf9e235 Reviewed-by: Leena Miettinen --- src/quick/scenegraph/coreapi/qsgnode.cpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'src') diff --git a/src/quick/scenegraph/coreapi/qsgnode.cpp b/src/quick/scenegraph/coreapi/qsgnode.cpp index 7ac3914023..e400928d4e 100644 --- a/src/quick/scenegraph/coreapi/qsgnode.cpp +++ b/src/quick/scenegraph/coreapi/qsgnode.cpp @@ -792,7 +792,7 @@ QSGBasicGeometryNode::~QSGBasicGeometryNode() If the node has the flag QSGNode::OwnsGeometry set, it will also delete the geometry object it is pointing to. This flag is not set by default. - If the geometry is changed whitout calling setGeometry() again, the user + If the geometry is changed without calling setGeometry() again, the user must also mark the geometry as dirty using QSGNode::markDirty(). \sa markDirty() @@ -845,7 +845,7 @@ void QSGBasicGeometryNode::setGeometry(QSGGeometry *geometry) The geometry node supports two types of materials, the opaqueMaterial and the normal material. The opaqueMaterial is used when the accumulated scene graph opacity at the - time of rendering is 1. The primary usecase is to special case opaque rendering + time of rendering is 1. The primary use case is to special case opaque rendering to avoid an extra operation in the fragment shader can have significant performance impact on embedded graphics chips. The opaque material is optional. @@ -887,7 +887,7 @@ QSGGeometryNode::QSGGeometryNode(QSGGeometryNodePrivate &dd) Deletes this geometry node. The flags QSGNode::OwnsMaterial, QSGNode::OwnsOpaqueMaterial and - QSGNode::OwnsGeometry decides weither the geometry node should also + QSGNode::OwnsGeometry decides whether the geometry node should also delete the materials and geometry. By default, these flags are disabled. */ @@ -961,7 +961,7 @@ void QSGGeometryNode::setRenderOrder(int order) Geometry nodes must have a material before they can be added to the scene graph. - If the material is changed whitout calling setMaterial() again, the user + If the material is changed without calling setMaterial() again, the user must also mark the material as dirty using QSGNode::markDirty(). */ @@ -991,7 +991,7 @@ void QSGGeometryNode::setMaterial(QSGMaterial *material) allowed to set QSGMaterial::Blending to true and draw transparent pixels. - If the material is changed whitout calling setOpaqueMaterial() + If the material is changed without calling setOpaqueMaterial() again, the user must also mark the opaque material as dirty using QSGNode::markDirty(). @@ -1371,7 +1371,7 @@ void QSGOpacityNode::setOpacity(qreal opacity) Returns this node's accumulated opacity. - This vaule is calculated during rendering and only stored + This value is calculated during rendering and only stored in the opacity node temporarily. \internal -- cgit v1.2.3 From 1af055c68544d86a1beb2dda1fb9be6eeffe0a7f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=BCri=20Valdmann?= Date: Thu, 4 May 2017 15:55:23 +0200 Subject: Doc: fix some typos in qsgrenderer.cpp Change-Id: I140e4e35d7841813df6425d0e418aa52660ed03b Reviewed-by: Leena Miettinen --- src/quick/scenegraph/coreapi/qsgrenderer.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/quick/scenegraph/coreapi/qsgrenderer.cpp b/src/quick/scenegraph/coreapi/qsgrenderer.cpp index e5d464930c..0458e2dead 100644 --- a/src/quick/scenegraph/coreapi/qsgrenderer.cpp +++ b/src/quick/scenegraph/coreapi/qsgrenderer.cpp @@ -99,7 +99,7 @@ void QSGBindableFboId::bind() const #endif /*! \class QSGRenderer - \brief The renderer class is the abstract baseclass use for rendering the + \brief The renderer class is the abstract baseclass used for rendering the QML scene graph. The renderer is not tied to any particular surface. It expects a context to @@ -292,7 +292,7 @@ void QSGRenderer::preprocess() // We need to take a copy here, in case any of the preprocess calls deletes a node that // is in the preprocess list and thus, changes the m_nodes_to_preprocess behind our backs - // For the default case, when this does not happen, the cost is neglishible. + // For the default case, when this does not happen, the cost is negligible. QSet items = m_nodes_to_preprocess; for (QSet::const_iterator it = items.constBegin(); -- cgit v1.2.3 From 8696993c4c3a92f2099e6160d516007a543f0116 Mon Sep 17 00:00:00 2001 From: Simon Hausmann Date: Thu, 4 May 2017 16:21:27 +0200 Subject: Fix crash in pre-cross-compiled ARMv7 code when host was 64-bit When encoding negative offsets for relative jumps, we must stay within signed 32-bit range to correctly perform all the different thumb offset encodings correctly. Task-number: QTBUG-60441 Change-Id: I0a7243debbcbc4d557710dddbd39cb97bd702da4 Reviewed-by: Lars Knoll --- src/3rdparty/masm/assembler/ARMv7Assembler.h | 22 ++++++++++++++-------- 1 file changed, 14 insertions(+), 8 deletions(-) (limited to 'src') diff --git a/src/3rdparty/masm/assembler/ARMv7Assembler.h b/src/3rdparty/masm/assembler/ARMv7Assembler.h index 615c72fc15..d57e5a7c78 100644 --- a/src/3rdparty/masm/assembler/ARMv7Assembler.h +++ b/src/3rdparty/masm/assembler/ARMv7Assembler.h @@ -2531,12 +2531,18 @@ private: return (instruction[0] == OP_NOP_T2a) && (instruction[1] == OP_NOP_T2b); } + static int32_t makeRelative(const void *target, const void *source) + { + intptr_t difference = reinterpret_cast(target) - reinterpret_cast(source); + return static_cast(difference); + } + static bool canBeJumpT1(const uint16_t* instruction, const void* target) { ASSERT(!(reinterpret_cast(instruction) & 1)); ASSERT(!(reinterpret_cast(target) & 1)); - intptr_t relative = reinterpret_cast(target) - (reinterpret_cast(instruction)); + auto relative = makeRelative(target, instruction); // It does not appear to be documented in the ARM ARM (big surprise), but // for OP_B_T1 the branch displacement encoded in the instruction is 2 // less than the actual displacement. @@ -2549,7 +2555,7 @@ private: ASSERT(!(reinterpret_cast(instruction) & 1)); ASSERT(!(reinterpret_cast(target) & 1)); - intptr_t relative = reinterpret_cast(target) - (reinterpret_cast(instruction)); + auto relative = makeRelative(target, instruction); // It does not appear to be documented in the ARM ARM (big surprise), but // for OP_B_T2 the branch displacement encoded in the instruction is 2 // less than the actual displacement. @@ -2562,7 +2568,7 @@ private: ASSERT(!(reinterpret_cast(instruction) & 1)); ASSERT(!(reinterpret_cast(target) & 1)); - intptr_t relative = reinterpret_cast(target) - (reinterpret_cast(instruction)); + auto relative = makeRelative(target, instruction); return ((relative << 11) >> 11) == relative; } @@ -2571,7 +2577,7 @@ private: ASSERT(!(reinterpret_cast(instruction) & 1)); ASSERT(!(reinterpret_cast(target) & 1)); - intptr_t relative = reinterpret_cast(target) - (reinterpret_cast(instruction)); + auto relative = makeRelative(target, instruction); return ((relative << 7) >> 7) == relative; } @@ -2582,7 +2588,7 @@ private: ASSERT(!(reinterpret_cast(target) & 1)); ASSERT(canBeJumpT1(instruction, target)); - intptr_t relative = reinterpret_cast(target) - (reinterpret_cast(instruction)); + auto relative = makeRelative(target, instruction); // It does not appear to be documented in the ARM ARM (big surprise), but // for OP_B_T1 the branch displacement encoded in the instruction is 2 // less than the actual displacement. @@ -2600,7 +2606,7 @@ private: ASSERT(!(reinterpret_cast(target) & 1)); ASSERT(canBeJumpT2(instruction, target)); - intptr_t relative = reinterpret_cast(target) - (reinterpret_cast(instruction)); + auto relative = makeRelative(target, instruction); // It does not appear to be documented in the ARM ARM (big surprise), but // for OP_B_T2 the branch displacement encoded in the instruction is 2 // less than the actual displacement. @@ -2618,7 +2624,7 @@ private: ASSERT(!(reinterpret_cast(target) & 1)); ASSERT(canBeJumpT3(instruction, target)); - intptr_t relative = reinterpret_cast(target) - (reinterpret_cast(instruction)); + auto relative = makeRelative(target, instruction); // All branch offsets should be an even distance. ASSERT(!(relative & 1)); @@ -2633,7 +2639,7 @@ private: ASSERT(!(reinterpret_cast(target) & 1)); ASSERT(canBeJumpT4(instruction, target)); - intptr_t relative = reinterpret_cast(target) - (reinterpret_cast(instruction)); + auto relative = makeRelative(target, instruction); // ARM encoding for the top two bits below the sign bit is 'peculiar'. if (relative >= 0) relative ^= 0xC00000; -- cgit v1.2.3 From f4c0ea2554253bf5055be61e8f94078227b07298 Mon Sep 17 00:00:00 2001 From: Andy Nichols Date: Thu, 4 May 2017 16:32:56 +0300 Subject: Software: Fix leaking of SGTextures Task-number: QTBUG-59865 Change-Id: I18911734b34e535c2c77d5a860bd776105617663 Reviewed-by: Laszlo Agocs --- src/quick/scenegraph/adaptations/software/qsgsoftwarepublicnodes.cpp | 3 +++ 1 file changed, 3 insertions(+) (limited to 'src') diff --git a/src/quick/scenegraph/adaptations/software/qsgsoftwarepublicnodes.cpp b/src/quick/scenegraph/adaptations/software/qsgsoftwarepublicnodes.cpp index 1fa5234377..384c124a02 100644 --- a/src/quick/scenegraph/adaptations/software/qsgsoftwarepublicnodes.cpp +++ b/src/quick/scenegraph/adaptations/software/qsgsoftwarepublicnodes.cpp @@ -74,6 +74,9 @@ QSGSoftwareImageNode::~QSGSoftwareImageNode() void QSGSoftwareImageNode::setTexture(QSGTexture *texture) { + if (m_owns) + delete m_texture; + m_texture = texture; markDirty(DirtyMaterial); m_cachedMirroredPixmapIsDirty = true; } -- cgit v1.2.3 From 7bf3f99ceca5818596c7dd03d6053ea40aa262b3 Mon Sep 17 00:00:00 2001 From: Arnaud Vrac Date: Thu, 27 Apr 2017 18:56:02 +0200 Subject: qquickpixmapcache: fix crash when loading images asynchronously Use copied data instead of data that might be destroyed. This was already fixed in most places in commit 22c39eda8ab316c. Change-Id: Ie31ebb2e53945dd66ce3d0114629c284407ff26c Reviewed-by: Albert Astals Cid Reviewed-by: Shawn Rutledge Reviewed-by: Robin Burchell --- src/quick/util/qquickpixmapcache.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/quick/util/qquickpixmapcache.cpp b/src/quick/util/qquickpixmapcache.cpp index 402897ca7a..882482ad31 100644 --- a/src/quick/util/qquickpixmapcache.cpp +++ b/src/quick/util/qquickpixmapcache.cpp @@ -497,7 +497,7 @@ void QQuickPixmapReader::networkRequestDone(QNetworkReply *reply) QByteArray all = reply->readAll(); QBuffer buff(&all); buff.open(QIODevice::ReadOnly); - if (!readImage(reply->url(), &buff, &image, &errorString, &readSize, job->requestSize, job->data->providerOptions)) + if (!readImage(reply->url(), &buff, &image, &errorString, &readSize, job->requestSize, job->providerOptions)) error = QQuickPixmapReply::Decoding; } // send completion event to the QQuickPixmapReply -- cgit v1.2.3 From 7730affa0dd50960da90f30d41b694a9e9ddd52b Mon Sep 17 00:00:00 2001 From: Simon Hausmann Date: Fri, 5 May 2017 15:21:40 +0200 Subject: Prospective build fix for architectures where we don't support the JIT Always export the isel factory method for qmlcachegen, so that we can link. Task-number: QTBUG-60597 Change-Id: Ia348ee5dfe0892878e8fce6c8afd30bb8eb54a51 Reviewed-by: Dmitry Shachnev Reviewed-by: Robin Burchell --- src/qml/jit/qv4isel_masm.cpp | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/qml/jit/qv4isel_masm.cpp b/src/qml/jit/qv4isel_masm.cpp index 4afcd1517f..ac72d2e8f5 100644 --- a/src/qml/jit/qv4isel_masm.cpp +++ b/src/qml/jit/qv4isel_masm.cpp @@ -1631,14 +1631,20 @@ QQmlRefPointer ISelFactory::createU return result; } +#endif // ENABLE(ASSEMBLER) + QT_BEGIN_NAMESPACE namespace QV4 { namespace JIT { +#if ENABLE(ASSEMBLER) template class Q_QML_EXPORT InstructionSelection<>; template class Q_QML_EXPORT ISelFactory<>; +#endif + #if defined(V4_BOOTSTRAP) Q_QML_EXPORT QV4::EvalISelFactory *createISelForArchitecture(const QString &architecture) { +#if ENABLE(ASSEMBLER) using ARMv7CrossAssembler = QV4::JIT::Assembler>; using ARM64CrossAssembler = QV4::JIT::Assembler>; @@ -1659,6 +1665,7 @@ Q_QML_EXPORT QV4::EvalISelFactory *createISelForArchitecture(const QString &arch #endif if (!hostArch.isEmpty() && architecture == hostArch) return new ISelFactory<>; +#endif // ENABLE(ASSEMBLER) return nullptr; } @@ -1667,4 +1674,3 @@ Q_QML_EXPORT QV4::EvalISelFactory *createISelForArchitecture(const QString &arch } } QT_END_NAMESPACE -#endif // ENABLE(ASSEMBLER) -- cgit v1.2.3 From 7286b296f97d3394f3c2a716116bd483c9874931 Mon Sep 17 00:00:00 2001 From: Frederik Gladhorn Date: Thu, 4 May 2017 16:17:05 +0200 Subject: Touch child mouse filtering: pass not grabbed points inside item bounds c2ca2cbf04071ffb3aee6af8d5ab9084dfa1c091 started to restrict delivery of items in childMouseEventFilter by checking that we wouldn't deliver completely random points outside the item that were not grabbed by child items. That is generally correct. It did no longer send along touch points that had any other state but pressed but were inside when they had no grabber. That part was wrong, points must be sent along if they are not grabbed and inside the item. Task-number: QTBUG-60368 Change-Id: Ida24f5d2310d3b71db79ae5f95da2c57dcd3f150 Reviewed-by: Shawn Rutledge --- src/quick/items/qquickevents.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/quick/items/qquickevents.cpp b/src/quick/items/qquickevents.cpp index ac0505da82..448b63c347 100644 --- a/src/quick/items/qquickevents.cpp +++ b/src/quick/items/qquickevents.cpp @@ -861,8 +861,9 @@ QTouchEvent *QQuickPointerTouchEvent::touchEventForItem(QQuickItem *item, bool i } parent = parent->parentItem(); } - bool filterRelevant = isFiltering && grabberIsChild; + // when filtering, send points that are grabbed by a child and points that are not grabbed but inside + bool filterRelevant = isFiltering && (grabberIsChild || (!p->grabber() && item->contains(item->mapFromScene(p->scenePos())))); if (!(isGrabber || isPressInside || filterRelevant)) continue; -- cgit v1.2.3 From 02830aae1f3e9aaf89ca37637d40313babbff7b8 Mon Sep 17 00:00:00 2001 From: Shawn Rutledge Date: Wed, 16 Nov 2016 16:30:39 +0100 Subject: Don't crash: Connections with a signal on a nonexistent object MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Task-number: QTBUG-56551 Change-Id: Ide09f177d3f6a3e9902f8ea904b3e6e4b998bd39 Reviewed-by: Jan Arve Sæther --- src/qml/qml/qqmlpropertycache.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/qml/qml/qqmlpropertycache.cpp b/src/qml/qml/qqmlpropertycache.cpp index 88ce2fa1b9..d18159841c 100644 --- a/src/qml/qml/qqmlpropertycache.cpp +++ b/src/qml/qml/qqmlpropertycache.cpp @@ -970,8 +970,11 @@ int QQmlPropertyCache::originalClone(QObject *object, int index) QQmlData *data = QQmlData::get(object, false); if (data && data->propertyCache) { QQmlPropertyCache *cache = data->propertyCache; - while (cache->signal(index)->isCloned()) + QQmlPropertyData *sig = cache->signal(index); + while (sig && sig->isCloned()) { --index; + sig = cache->signal(index); + } } else { while (QMetaObjectPrivate::signal(object->metaObject(), index).attributes() & QMetaMethod::Cloned) --index; -- cgit v1.2.3 From 99594f518a5fb657b75f68bba73537c4e9208e46 Mon Sep 17 00:00:00 2001 From: Lars Knoll Date: Wed, 3 May 2017 08:45:28 +0200 Subject: Re-add some inline property storage It turns out that not using any inline property storage comes at a relatively high price in terms of memory consumption, as we always need to also create a memberData for any object. This avoids the memberData creation in quite a few cases, as we use the additional padding we have up to the 32 byte boundary given by the memory manager to store some property data. This complicates property access somewhat. To avoid performance regressions because of this, add specialized QV4::Lookup functions that optimize for properties that are inline or in the memberData struct. Change seems to be performance neutral on v8-bench on x86_64, but reduces peak memory usage when running the benchmark by around 20%. Change-Id: I0127d31a2d6038aaa540c4c4a1156f45ca3b7464 Reviewed-by: Simon Hausmann Reviewed-by: Robin Burchell --- src/qml/jsruntime/qv4arraydata.cpp | 2 + src/qml/jsruntime/qv4internalclass.cpp | 33 ++++++++- src/qml/jsruntime/qv4lookup.cpp | 128 ++++++++++++++++++++++++++++----- src/qml/jsruntime/qv4lookup_p.h | 13 ++-- src/qml/jsruntime/qv4managed.cpp | 2 + src/qml/jsruntime/qv4managed_p.h | 3 + src/qml/jsruntime/qv4object.cpp | 26 +++++-- src/qml/jsruntime/qv4object_p.h | 21 +++++- src/qml/memory/qv4heap_p.h | 2 + src/qml/memory/qv4mm.cpp | 7 +- src/qml/memory/qv4mm_p.h | 6 +- 11 files changed, 206 insertions(+), 37 deletions(-) (limited to 'src') diff --git a/src/qml/jsruntime/qv4arraydata.cpp b/src/qml/jsruntime/qv4arraydata.cpp index c29cedaa9b..6d1fb62e0a 100644 --- a/src/qml/jsruntime/qv4arraydata.cpp +++ b/src/qml/jsruntime/qv4arraydata.cpp @@ -49,6 +49,8 @@ using namespace QV4; QT_WARNING_SUPPRESS_GCC_TAUTOLOGICAL_COMPARE_ON const QV4::VTable QV4::ArrayData::static_vtbl = { + 0, + 0, 0, QV4::ArrayData::IsExecutionContext, QV4::ArrayData::IsString, diff --git a/src/qml/jsruntime/qv4internalclass.cpp b/src/qml/jsruntime/qv4internalclass.cpp index bac71b4537..7e3fd7dc12 100644 --- a/src/qml/jsruntime/qv4internalclass.cpp +++ b/src/qml/jsruntime/qv4internalclass.cpp @@ -43,6 +43,7 @@ #include #include "qv4object_p.h" #include "qv4identifiertable_p.h" +#include "qv4value_p.h" QT_BEGIN_NAMESPACE @@ -128,22 +129,48 @@ InternalClass::InternalClass(const QV4::InternalClass &other) static void insertHoleIntoPropertyData(Object *object, int idx) { + int inlineSize = object->d()->vt->nInlineProperties; int icSize = object->internalClass()->size; - int from = idx; + int from = qMax(idx, inlineSize); int to = from + 1; - if (from < icSize) + if (from < icSize) { memmove(object->propertyData(to), object->propertyData(from), (icSize - from - 1) * sizeof(Value)); + } + if (from == idx) + return; + if (inlineSize < icSize) + *object->propertyData(inlineSize) = *object->propertyData(inlineSize - 1); + from = idx; + to = from + 1; + if (from < inlineSize - 1) { + memmove(object->propertyData(to), object->propertyData(from), + (inlineSize - from - 1) * sizeof(Value)); + } } static void removeFromPropertyData(Object *object, int idx, bool accessor = false) { + int inlineSize = object->d()->vt->nInlineProperties; int delta = (accessor ? 2 : 1); int oldSize = object->internalClass()->size + delta; int to = idx; int from = to + delta; - if (from < oldSize) + if (from < inlineSize) { + memmove(object->propertyData(to), object->d()->propertyData(from), (inlineSize - from)*sizeof(Value)); + to = inlineSize - delta; + from = inlineSize; + } + if (to < inlineSize && from < oldSize) { + Q_ASSERT(from >= inlineSize); + memcpy(object->propertyData(to), object->d()->propertyData(from), (inlineSize - to)*sizeof(Value)); + to = inlineSize; + from = inlineSize + delta; + } + if (from < oldSize) { + Q_ASSERT(to >= inlineSize && from > to); memmove(object->propertyData(to), object->d()->propertyData(from), (oldSize - to)*sizeof(Value)); + } } void InternalClass::changeMember(Object *object, String *string, PropertyAttributes data, uint *index) diff --git a/src/qml/jsruntime/qv4lookup.cpp b/src/qml/jsruntime/qv4lookup.cpp index 52ed449664..80a24cdde7 100644 --- a/src/qml/jsruntime/qv4lookup.cpp +++ b/src/qml/jsruntime/qv4lookup.cpp @@ -307,15 +307,18 @@ ReturnedValue Lookup::getterTwoClasses(Lookup *l, ExecutionEngine *engine, const { Lookup l1 = *l; - if (l1.getter == Lookup::getter0 || l1.getter == Lookup::getter1) { + if (l1.getter == Lookup::getter0MemberData || l1.getter == Lookup::getter0Inline || l1.getter == Lookup::getter1) { if (const Object *o = object.as()) { ReturnedValue v = o->getLookup(l); Lookup l2 = *l; - if (l->index != UINT_MAX && (l2.getter == Lookup::getter0 || l2.getter == Lookup::getter1)) { - // if we have a getter0, make sure it comes first - if (l2.getter == Lookup::getter0) - qSwap(l1, l2); + if (l2.index != UINT_MAX) { + if (l1.getter != Lookup::getter0Inline) { + if (l2.getter == Lookup::getter0Inline || + (l1.getter != Lookup::getter0MemberData && l2.getter == Lookup::getter0MemberData)) + // sort the better getter first + qSwap(l1, l2); + } l->classList[0] = l1.classList[0]; l->classList[1] = l1.classList[1]; @@ -324,8 +327,22 @@ ReturnedValue Lookup::getterTwoClasses(Lookup *l, ExecutionEngine *engine, const l->index = l1.index; l->index2 = l2.index; - if (l1.getter == Lookup::getter0) { - l->getter = (l2.getter == Lookup::getter0) ? Lookup::getter0getter0 : Lookup::getter0getter1; + if (l1.getter == Lookup::getter0Inline) { + if (l2.getter == Lookup::getter0Inline) + l->getter = Lookup::getter0Inlinegetter0Inline; + else if (l2.getter == Lookup::getter0MemberData) + l->getter = Lookup::getter0Inlinegetter0MemberData; + else if (l2.getter == Lookup::getter1) + l->getter = Lookup::getter0Inlinegetter1; + else + Q_UNREACHABLE(); + } else if (l1.getter == Lookup::getter0MemberData) { + if (l2.getter == Lookup::getter0MemberData) + l->getter = Lookup::getter0MemberDatagetter0MemberData; + else if (l2.getter == Lookup::getter1) + l->getter = Lookup::getter0MemberDatagetter1; + else + Q_UNREACHABLE(); } else { Q_ASSERT(l1.getter == Lookup::getter1 && l2.getter == Lookup::getter1); l->getter = Lookup::getter1getter1; @@ -349,14 +366,26 @@ ReturnedValue Lookup::getterFallback(Lookup *l, ExecutionEngine *engine, const V return o->get(name); } -ReturnedValue Lookup::getter0(Lookup *l, ExecutionEngine *engine, const Value &object) +ReturnedValue Lookup::getter0MemberData(Lookup *l, ExecutionEngine *engine, const Value &object) { // we can safely cast to a QV4::Object here. If object is actually a string, // the internal class won't match Heap::Object *o = static_cast(object.heapObject()); if (o) { if (l->classList[0] == o->internalClass) - return o->propertyData(l->index)->asReturnedValue(); + return o->memberData->data[l->index].asReturnedValue(); + } + return getterTwoClasses(l, engine, object); +} + +ReturnedValue Lookup::getter0Inline(Lookup *l, ExecutionEngine *engine, const Value &object) +{ + // we can safely cast to a QV4::Object here. If object is actually a string, + // the internal class won't match + Heap::Object *o = static_cast(object.heapObject()); + if (o) { + if (l->classList[0] == o->internalClass) + return o->inlinePropertyData(l->index)->asReturnedValue(); } return getterTwoClasses(l, engine, object); } @@ -392,29 +421,74 @@ ReturnedValue Lookup::getter2(Lookup *l, ExecutionEngine *engine, const Value &o return getterFallback(l, engine, object); } -ReturnedValue Lookup::getter0getter0(Lookup *l, ExecutionEngine *engine, const Value &object) +ReturnedValue Lookup::getter0Inlinegetter0Inline(Lookup *l, ExecutionEngine *engine, const Value &object) { // we can safely cast to a QV4::Object here. If object is actually a string, // the internal class won't match Heap::Object *o = static_cast(object.heapObject()); if (o) { if (l->classList[0] == o->internalClass) - return o->propertyData(l->index)->asReturnedValue(); + return o->inlinePropertyData(l->index)->asReturnedValue(); if (l->classList[2] == o->internalClass) - return o->propertyData(l->index2)->asReturnedValue(); + return o->inlinePropertyData(l->index2)->asReturnedValue(); } l->getter = getterFallback; return getterFallback(l, engine, object); } -ReturnedValue Lookup::getter0getter1(Lookup *l, ExecutionEngine *engine, const Value &object) +ReturnedValue Lookup::getter0Inlinegetter0MemberData(Lookup *l, ExecutionEngine *engine, const Value &object) { // we can safely cast to a QV4::Object here. If object is actually a string, // the internal class won't match Heap::Object *o = static_cast(object.heapObject()); if (o) { if (l->classList[0] == o->internalClass) - return o->propertyData(l->index)->asReturnedValue(); + return o->inlinePropertyData(l->index)->asReturnedValue(); + if (l->classList[2] == o->internalClass) + return o->memberData->data[l->index2].asReturnedValue(); + } + l->getter = getterFallback; + return getterFallback(l, engine, object); +} + +ReturnedValue Lookup::getter0MemberDatagetter0MemberData(Lookup *l, ExecutionEngine *engine, const Value &object) +{ + // we can safely cast to a QV4::Object here. If object is actually a string, + // the internal class won't match + Heap::Object *o = static_cast(object.heapObject()); + if (o) { + if (l->classList[0] == o->internalClass) + return o->memberData->data[l->index].asReturnedValue(); + if (l->classList[2] == o->internalClass) + return o->memberData->data[l->index2].asReturnedValue(); + } + l->getter = getterFallback; + return getterFallback(l, engine, object); +} + +ReturnedValue Lookup::getter0Inlinegetter1(Lookup *l, ExecutionEngine *engine, const Value &object) +{ + // we can safely cast to a QV4::Object here. If object is actually a string, + // the internal class won't match + Heap::Object *o = static_cast(object.heapObject()); + if (o) { + if (l->classList[0] == o->internalClass) + return o->inlinePropertyData(l->index)->asReturnedValue(); + if (l->classList[2] == o->internalClass && l->classList[3] == o->prototype->internalClass) + return o->prototype->propertyData(l->index2)->asReturnedValue(); + } + l->getter = getterFallback; + return getterFallback(l, engine, object); +} + +ReturnedValue Lookup::getter0MemberDatagetter1(Lookup *l, ExecutionEngine *engine, const Value &object) +{ + // we can safely cast to a QV4::Object here. If object is actually a string, + // the internal class won't match + Heap::Object *o = static_cast(object.heapObject()); + if (o) { + if (l->classList[0] == o->internalClass) + return o->memberData->data[l->index].asReturnedValue(); if (l->classList[2] == o->internalClass && l->classList[3] == o->prototype->internalClass) return o->prototype->propertyData(l->index2)->asReturnedValue(); } @@ -604,9 +678,15 @@ ReturnedValue Lookup::globalGetterGeneric(Lookup *l, ExecutionEngine *engine) ReturnedValue v = l->lookup(o, &attrs); if (v != Primitive::emptyValue().asReturnedValue()) { if (attrs.isData()) { - if (l->level == 0) - l->globalGetter = globalGetter0; - else if (l->level == 1) + if (l->level == 0) { + uint nInline = o->d()->vt->nInlineProperties; + if (l->index < nInline) + l->globalGetter = globalGetter0Inline; + else { + l->index -= nInline; + l->globalGetter = globalGetter0MemberData; + } + } else if (l->level == 1) l->globalGetter = globalGetter1; else if (l->level == 2) l->globalGetter = globalGetter2; @@ -626,11 +706,21 @@ ReturnedValue Lookup::globalGetterGeneric(Lookup *l, ExecutionEngine *engine) return engine->throwReferenceError(n); } -ReturnedValue Lookup::globalGetter0(Lookup *l, ExecutionEngine *engine) +ReturnedValue Lookup::globalGetter0Inline(Lookup *l, ExecutionEngine *engine) +{ + Object *o = engine->globalObject; + if (l->classList[0] == o->internalClass()) + return o->d()->inlinePropertyData(l->index)->asReturnedValue(); + + l->globalGetter = globalGetterGeneric; + return globalGetterGeneric(l, engine); +} + +ReturnedValue Lookup::globalGetter0MemberData(Lookup *l, ExecutionEngine *engine) { Object *o = engine->globalObject; if (l->classList[0] == o->internalClass()) - return o->propertyData(l->index)->asReturnedValue(); + return o->d()->memberData->data[l->index].asReturnedValue(); l->globalGetter = globalGetterGeneric; return globalGetterGeneric(l, engine); diff --git a/src/qml/jsruntime/qv4lookup_p.h b/src/qml/jsruntime/qv4lookup_p.h index 2ffb43cce9..5a67c203ce 100644 --- a/src/qml/jsruntime/qv4lookup_p.h +++ b/src/qml/jsruntime/qv4lookup_p.h @@ -102,11 +102,15 @@ struct Lookup { static ReturnedValue getterTwoClasses(Lookup *l, ExecutionEngine *engine, const Value &object); static ReturnedValue getterFallback(Lookup *l, ExecutionEngine *engine, const Value &object); - static ReturnedValue getter0(Lookup *l, ExecutionEngine *engine, const Value &object); + static ReturnedValue getter0MemberData(Lookup *l, ExecutionEngine *engine, const Value &object); + static ReturnedValue getter0Inline(Lookup *l, ExecutionEngine *engine, const Value &object); static ReturnedValue getter1(Lookup *l, ExecutionEngine *engine, const Value &object); static ReturnedValue getter2(Lookup *l, ExecutionEngine *engine, const Value &object); - static ReturnedValue getter0getter0(Lookup *l, ExecutionEngine *engine, const Value &object); - static ReturnedValue getter0getter1(Lookup *l, ExecutionEngine *engine, const Value &object); + static ReturnedValue getter0Inlinegetter0Inline(Lookup *l, ExecutionEngine *engine, const Value &object); + static ReturnedValue getter0Inlinegetter0MemberData(Lookup *l, ExecutionEngine *engine, const Value &object); + static ReturnedValue getter0MemberDatagetter0MemberData(Lookup *l, ExecutionEngine *engine, const Value &object); + static ReturnedValue getter0Inlinegetter1(Lookup *l, ExecutionEngine *engine, const Value &object); + static ReturnedValue getter0MemberDatagetter1(Lookup *l, ExecutionEngine *engine, const Value &object); static ReturnedValue getter1getter1(Lookup *l, ExecutionEngine *engine, const Value &object); static ReturnedValue getterAccessor0(Lookup *l, ExecutionEngine *engine, const Value &object); static ReturnedValue getterAccessor1(Lookup *l, ExecutionEngine *engine, const Value &object); @@ -120,7 +124,8 @@ struct Lookup { static ReturnedValue arrayLengthGetter(Lookup *l, ExecutionEngine *engine, const Value &object); static ReturnedValue globalGetterGeneric(Lookup *l, ExecutionEngine *engine); - static ReturnedValue globalGetter0(Lookup *l, ExecutionEngine *engine); + static ReturnedValue globalGetter0Inline(Lookup *l, ExecutionEngine *engine); + static ReturnedValue globalGetter0MemberData(Lookup *l, ExecutionEngine *engine); static ReturnedValue globalGetter1(Lookup *l, ExecutionEngine *engine); static ReturnedValue globalGetter2(Lookup *l, ExecutionEngine *engine); static ReturnedValue globalGetterAccessor0(Lookup *l, ExecutionEngine *engine); diff --git a/src/qml/jsruntime/qv4managed.cpp b/src/qml/jsruntime/qv4managed.cpp index 3a84a83b9c..200380eda0 100644 --- a/src/qml/jsruntime/qv4managed.cpp +++ b/src/qml/jsruntime/qv4managed.cpp @@ -46,6 +46,8 @@ using namespace QV4; const VTable Managed::static_vtbl = { + 0, + 0, 0, Managed::IsExecutionContext, Managed::IsString, diff --git a/src/qml/jsruntime/qv4managed_p.h b/src/qml/jsruntime/qv4managed_p.h index 5c764e7ff0..7e674c6ec7 100644 --- a/src/qml/jsruntime/qv4managed_p.h +++ b/src/qml/jsruntime/qv4managed_p.h @@ -129,6 +129,9 @@ inline void qYouForgotTheQ_MANAGED_Macro(T1, T2) {} #define DEFINE_MANAGED_VTABLE_INT(classname, parentVTable) \ { \ parentVTable, \ + (sizeof(classname::Data) + sizeof(QV4::Value) - 1)/sizeof(QV4::Value), \ + (sizeof(classname::Data) + QV4::Chunk::SlotSize - 1)/QV4::Chunk::SlotSize*QV4::Chunk::SlotSize/sizeof(QV4::Value) \ + - (sizeof(classname::Data) + sizeof(QV4::Value) - 1)/sizeof(QV4::Value), \ classname::IsExecutionContext, \ classname::IsString, \ classname::IsObject, \ diff --git a/src/qml/jsruntime/qv4object.cpp b/src/qml/jsruntime/qv4object.cpp index 12157af728..9595158ce9 100644 --- a/src/qml/jsruntime/qv4object.cpp +++ b/src/qml/jsruntime/qv4object.cpp @@ -61,9 +61,13 @@ DEFINE_OBJECT_VTABLE(Object); void Object::setInternalClass(InternalClass *ic) { d()->internalClass = ic; + uint nInline = d()->vtable()->nInlineProperties; + if (ic->size <= nInline) + return; bool hasMD = d()->memberData != nullptr; - if ((!hasMD && ic->size) || (hasMD && d()->memberData->size < ic->size)) - d()->memberData = MemberData::allocate(ic->engine, ic->size, d()->memberData); + uint requiredSize = ic->size - nInline; + if (!hasMD || (hasMD && d()->memberData->size < requiredSize)) + d()->memberData = MemberData::allocate(ic->engine, requiredSize, d()->memberData); } void Object::getProperty(uint index, Property *p, PropertyAttributes *attrs) const @@ -261,6 +265,13 @@ void Object::markObjects(Heap::Base *that, ExecutionEngine *e) o->arrayData->mark(e); if (o->prototype) o->prototype->mark(e); + uint nInline = o->vtable()->nInlineProperties; + Value *v = reinterpret_cast(o) + o->vt->inlinePropertyOffset; + const Value *end = v + nInline; + while (v < end) { + v->mark(e); + ++v; + } } void Object::insertMember(String *s, const Property *p, PropertyAttributes attributes) @@ -495,8 +506,15 @@ ReturnedValue Object::getLookup(const Managed *m, Lookup *l) ReturnedValue v = l->lookup(o, &attrs); if (v != Primitive::emptyValue().asReturnedValue()) { if (attrs.isData()) { - if (l->level == 0) - l->getter = Lookup::getter0; + if (l->level == 0) { + uint nInline = o->d()->vt->nInlineProperties; + if (l->index < nInline) + l->getter = Lookup::getter0Inline; + else { + l->index -= nInline; + l->getter = Lookup::getter0MemberData; + } + } else if (l->level == 1) l->getter = Lookup::getter1; else if (l->level == 2) diff --git a/src/qml/jsruntime/qv4object_p.h b/src/qml/jsruntime/qv4object_p.h index 6a543ae1a8..c1d5fd66b2 100644 --- a/src/qml/jsruntime/qv4object_p.h +++ b/src/qml/jsruntime/qv4object_p.h @@ -71,8 +71,25 @@ struct Object : Base { void init() { Base::init(); } void destroy() { Base::destroy(); } - const Value *propertyData(uint index) const { return memberData->data + index; } - Value *propertyData(uint index) { return memberData->data + index; } + const Value *inlinePropertyData(uint index) const { + Q_ASSERT(index < vt->nInlineProperties); + return reinterpret_cast(this) + vt->inlinePropertyOffset + index; + } + + const Value *propertyData(uint index) const { + uint nInline = vt->nInlineProperties; + if (index < nInline) + return reinterpret_cast(this) + vt->inlinePropertyOffset + index; + index -= nInline; + return memberData->data + index; + } + Value *propertyData(uint index) { + uint nInline = vt->nInlineProperties; + if (index < nInline) + return reinterpret_cast(this) + vt->inlinePropertyOffset + index; + index -= nInline; + return memberData->data + index; + } InternalClass *internalClass; Pointer prototype; diff --git a/src/qml/memory/qv4heap_p.h b/src/qml/memory/qv4heap_p.h index 173c0a3e20..cd0a6d9a81 100644 --- a/src/qml/memory/qv4heap_p.h +++ b/src/qml/memory/qv4heap_p.h @@ -72,6 +72,8 @@ namespace QV4 { struct VTable { const VTable * const parent; + uint inlinePropertyOffset : 16; + uint nInlineProperties : 16; uint isExecutionContext : 1; uint isString : 1; uint isObject : 1; diff --git a/src/qml/memory/qv4mm.cpp b/src/qml/memory/qv4mm.cpp index 7aa8f91503..0a6dfb9170 100644 --- a/src/qml/memory/qv4mm.cpp +++ b/src/qml/memory/qv4mm.cpp @@ -757,12 +757,15 @@ Heap::Base *MemoryManager::allocData(std::size_t size) return *m; } -Heap::Object *MemoryManager::allocObjectWithMemberData(std::size_t size, uint nMembers) +Heap::Object *MemoryManager::allocObjectWithMemberData(const QV4::VTable *vtable, uint nMembers) { + uint size = (vtable->nInlineProperties + vtable->inlinePropertyOffset)*sizeof(Value); + Q_ASSERT(!(size % sizeof(HeapItem))); Heap::Object *o = static_cast(allocData(size)); // ### Could optimize this and allocate both in one go through the block allocator - if (nMembers) { + if (nMembers > vtable->nInlineProperties) { + nMembers -= vtable->nInlineProperties; std::size_t memberSize = align(sizeof(Heap::MemberData) + (nMembers - 1)*sizeof(Value)); // qDebug() << "allocating member data for" << o << nMembers << memberSize; Heap::Base *m; diff --git a/src/qml/memory/qv4mm_p.h b/src/qml/memory/qv4mm_p.h index 00daf8a622..9b4c2cd8df 100644 --- a/src/qml/memory/qv4mm_p.h +++ b/src/qml/memory/qv4mm_p.h @@ -231,7 +231,7 @@ public: template typename ObjectType::Data *allocateObject(InternalClass *ic) { - Heap::Object *o = allocObjectWithMemberData(align(sizeof(typename ObjectType::Data)), ic->size); + Heap::Object *o = allocObjectWithMemberData(ObjectType::staticVTable(), ic->size); o->setVtable(ObjectType::staticVTable()); o->internalClass = ic; return static_cast(o); @@ -241,7 +241,7 @@ public: typename ObjectType::Data *allocateObject() { InternalClass *ic = ObjectType::defaultInternalClass(engine); - Heap::Object *o = allocObjectWithMemberData(align(sizeof(typename ObjectType::Data)), ic->size); + Heap::Object *o = allocObjectWithMemberData(ObjectType::staticVTable(), ic->size); o->setVtable(ObjectType::staticVTable()); Object *prototype = ObjectType::defaultPrototype(engine); o->internalClass = ic; @@ -433,7 +433,7 @@ protected: /// expects size to be aligned Heap::Base *allocString(std::size_t unmanagedSize); Heap::Base *allocData(std::size_t size); - Heap::Object *allocObjectWithMemberData(std::size_t size, uint nMembers); + Heap::Object *allocObjectWithMemberData(const QV4::VTable *vtable, uint nMembers); #ifdef DETAILED_MM_STATS void willAllocate(std::size_t size); -- cgit v1.2.3 From 799f4a526375701d2b68d2ca1c85648994468394 Mon Sep 17 00:00:00 2001 From: Lars Knoll Date: Wed, 3 May 2017 15:11:55 +0200 Subject: Optimize other lookups Add some more optimized lookups for accessing properties stored inline or in the memberData. Change-Id: Id74901d1dd91fd60933bf164c2bf90fed86232e3 Reviewed-by: Simon Hausmann Reviewed-by: Robin Burchell --- src/qml/jsruntime/qv4lookup.cpp | 70 ++++++++++++++++++++++++++++------------- src/qml/jsruntime/qv4lookup_p.h | 6 ++-- src/qml/jsruntime/qv4object.cpp | 2 +- src/qml/jsruntime/qv4object_p.h | 4 +++ 4 files changed, 58 insertions(+), 24 deletions(-) (limited to 'src') diff --git a/src/qml/jsruntime/qv4lookup.cpp b/src/qml/jsruntime/qv4lookup.cpp index 80a24cdde7..0d467098fe 100644 --- a/src/qml/jsruntime/qv4lookup.cpp +++ b/src/qml/jsruntime/qv4lookup.cpp @@ -284,11 +284,17 @@ ReturnedValue Lookup::getterGeneric(Lookup *l, ExecutionEngine *engine, const Va ReturnedValue v = l->lookup(object, proto, &attrs); if (v != Primitive::emptyValue().asReturnedValue()) { l->type = object.type(); - l->proto = proto; + l->proto = proto->d(); if (attrs.isData()) { - if (l->level == 0) - l->getter = Lookup::primitiveGetter0; - else if (l->level == 1) + if (l->level == 0) { + uint nInline = l->proto->vt->nInlineProperties; + if (l->index < nInline) + l->getter = Lookup::primitiveGetter0Inline; + else { + l->index -= nInline; + l->getter = Lookup::primitiveGetter0MemberData; + } + } else if (l->level == 1) l->getter = Lookup::primitiveGetter1; return v; } else { @@ -588,12 +594,23 @@ ReturnedValue Lookup::getterAccessor2(Lookup *l, ExecutionEngine *engine, const return getterFallback(l, engine, object); } -ReturnedValue Lookup::primitiveGetter0(Lookup *l, ExecutionEngine *engine, const Value &object) +ReturnedValue Lookup::primitiveGetter0Inline(Lookup *l, ExecutionEngine *engine, const Value &object) { if (object.type() == l->type) { - Object *o = l->proto; - if (l->classList[0] == o->internalClass()) - return o->propertyData(l->index)->asReturnedValue(); + Heap::Object *o = l->proto; + if (l->classList[0] == o->internalClass) + return o->inlinePropertyData(l->index)->asReturnedValue(); + } + l->getter = getterGeneric; + return getterGeneric(l, engine, object); +} + +ReturnedValue Lookup::primitiveGetter0MemberData(Lookup *l, ExecutionEngine *engine, const Value &object) +{ + if (object.type() == l->type) { + Heap::Object *o = l->proto; + if (l->classList[0] == o->internalClass) + return o->memberData->data[l->index].asReturnedValue(); } l->getter = getterGeneric; return getterGeneric(l, engine, object); @@ -602,10 +619,10 @@ ReturnedValue Lookup::primitiveGetter0(Lookup *l, ExecutionEngine *engine, const ReturnedValue Lookup::primitiveGetter1(Lookup *l, ExecutionEngine *engine, const Value &object) { if (object.type() == l->type) { - Object *o = l->proto; - if (l->classList[0] == o->internalClass() && - l->classList[1] == o->prototype()->internalClass) - return o->prototype()->propertyData(l->index)->asReturnedValue(); + Heap::Object *o = l->proto; + if (l->classList[0] == o->internalClass && + l->classList[1] == o->prototype->internalClass) + return o->prototype->propertyData(l->index)->asReturnedValue(); } l->getter = getterGeneric; return getterGeneric(l, engine, object); @@ -614,9 +631,9 @@ ReturnedValue Lookup::primitiveGetter1(Lookup *l, ExecutionEngine *engine, const ReturnedValue Lookup::primitiveGetterAccessor0(Lookup *l, ExecutionEngine *engine, const Value &object) { if (object.type() == l->type) { - Object *o = l->proto; - if (l->classList[0] == o->internalClass()) { - Scope scope(o->engine()); + Heap::Object *o = l->proto; + if (l->classList[0] == o->internalClass) { + Scope scope(o->internalClass->engine); ScopedFunctionObject getter(scope, o->propertyData(l->index + Object::GetterOffset)); if (!getter) return Encode::undefined(); @@ -634,11 +651,11 @@ ReturnedValue Lookup::primitiveGetterAccessor0(Lookup *l, ExecutionEngine *engin ReturnedValue Lookup::primitiveGetterAccessor1(Lookup *l, ExecutionEngine *engine, const Value &object) { if (object.type() == l->type) { - Object *o = l->proto; - if (l->classList[0] == o->internalClass() && - l->classList[1] == o->prototype()->internalClass) { - Scope scope(o->engine()); - ScopedFunctionObject getter(scope, o->prototype()->propertyData(l->index + Object::GetterOffset)); + Heap::Object *o = l->proto; + if (l->classList[0] == o->internalClass && + l->classList[1] == o->prototype->internalClass) { + Scope scope(o->internalClass->engine); + ScopedFunctionObject getter(scope, o->prototype->propertyData(l->index + Object::GetterOffset)); if (!getter) return Encode::undefined(); @@ -836,7 +853,7 @@ void Lookup::setterTwoClasses(Lookup *l, ExecutionEngine *engine, Value &object, if (Object *o = object.as()) { o->setLookup(l, value); - if (l->setter == Lookup::setter0) { + if (l->setter == Lookup::setter0 || l->setter == Lookup::setter0Inline) { l->setter = setter0setter0; l->classList[1] = l1.classList[0]; l->index2 = l1.index; @@ -869,6 +886,17 @@ void Lookup::setter0(Lookup *l, ExecutionEngine *engine, Value &object, const Va setterTwoClasses(l, engine, object, value); } +void Lookup::setter0Inline(Lookup *l, ExecutionEngine *engine, Value &object, const Value &value) +{ + Object *o = object.as(); + if (o && o->internalClass() == l->classList[0]) { + *o->d()->inlinePropertyData(l->index) = value; + return; + } + + setterTwoClasses(l, engine, object, value); +} + void Lookup::setterInsert0(Lookup *l, ExecutionEngine *engine, Value &object, const Value &value) { Object *o = object.as(); diff --git a/src/qml/jsruntime/qv4lookup_p.h b/src/qml/jsruntime/qv4lookup_p.h index 5a67c203ce..9e50235b73 100644 --- a/src/qml/jsruntime/qv4lookup_p.h +++ b/src/qml/jsruntime/qv4lookup_p.h @@ -79,7 +79,7 @@ struct Lookup { struct { void *dummy0; void *dummy1; - Object *proto; + Heap::Object *proto; unsigned type; }; }; @@ -116,7 +116,8 @@ struct Lookup { static ReturnedValue getterAccessor1(Lookup *l, ExecutionEngine *engine, const Value &object); static ReturnedValue getterAccessor2(Lookup *l, ExecutionEngine *engine, const Value &object); - static ReturnedValue primitiveGetter0(Lookup *l, ExecutionEngine *engine, const Value &object); + static ReturnedValue primitiveGetter0Inline(Lookup *l, ExecutionEngine *engine, const Value &object); + static ReturnedValue primitiveGetter0MemberData(Lookup *l, ExecutionEngine *engine, const Value &object); static ReturnedValue primitiveGetter1(Lookup *l, ExecutionEngine *engine, const Value &object); static ReturnedValue primitiveGetterAccessor0(Lookup *l, ExecutionEngine *engine, const Value &object); static ReturnedValue primitiveGetterAccessor1(Lookup *l, ExecutionEngine *engine, const Value &object); @@ -136,6 +137,7 @@ struct Lookup { static void setterTwoClasses(Lookup *l, ExecutionEngine *engine, Value &object, const Value &value); static void setterFallback(Lookup *l, ExecutionEngine *engine, Value &object, const Value &value); static void setter0(Lookup *l, ExecutionEngine *engine, Value &object, const Value &value); + static void setter0Inline(Lookup *l, ExecutionEngine *engine, Value &object, const Value &value); static void setterInsert0(Lookup *l, ExecutionEngine *engine, Value &object, const Value &value); static void setterInsert1(Lookup *l, ExecutionEngine *engine, Value &object, const Value &value); static void setterInsert2(Lookup *l, ExecutionEngine *engine, Value &object, const Value &value); diff --git a/src/qml/jsruntime/qv4object.cpp b/src/qml/jsruntime/qv4object.cpp index 9595158ce9..3d8e8f3ddf 100644 --- a/src/qml/jsruntime/qv4object.cpp +++ b/src/qml/jsruntime/qv4object.cpp @@ -549,7 +549,7 @@ void Object::setLookup(Managed *m, Lookup *l, const Value &value) if (idx != UINT_MAX && o->internalClass()->propertyData[idx].isData() && o->internalClass()->propertyData[idx].isWritable()) { l->classList[0] = o->internalClass(); l->index = idx; - l->setter = Lookup::setter0; + l->setter = idx < o->d()->vt->nInlineProperties ? Lookup::setter0Inline : Lookup::setter0; *o->propertyData(idx) = value; return; } diff --git a/src/qml/jsruntime/qv4object_p.h b/src/qml/jsruntime/qv4object_p.h index c1d5fd66b2..45392c0486 100644 --- a/src/qml/jsruntime/qv4object_p.h +++ b/src/qml/jsruntime/qv4object_p.h @@ -75,6 +75,10 @@ struct Object : Base { Q_ASSERT(index < vt->nInlineProperties); return reinterpret_cast(this) + vt->inlinePropertyOffset + index; } + Value *inlinePropertyData(uint index) { + Q_ASSERT(index < vt->nInlineProperties); + return reinterpret_cast(this) + vt->inlinePropertyOffset + index; + } const Value *propertyData(uint index) const { uint nInline = vt->nInlineProperties; -- cgit v1.2.3 From 5346da3f11f52530ef3c14d4ff16124b86f922e1 Mon Sep 17 00:00:00 2001 From: Ulf Hermann Date: Fri, 5 May 2017 14:20:37 +0200 Subject: Remove the qqmldebugtrace benchmark It benchmarks QElapsedTimer and QDataStream. We should do this in qtbase if we need to do it. The test was not in the parent qml.pro, but it was mentioned in some outdated comments in the QML profiler plugins. Remove those comments, too. Change-Id: I0d1341c32f4a2e02a04a958f76be015fe8d927fb Reviewed-by: Erik Verbruggen Reviewed-by: Lars Knoll --- src/plugins/qmltooling/qmldbg_profiler/qqmlprofileradapter.cpp | 2 -- src/plugins/qmltooling/qmldbg_quickprofiler/qquickprofileradapter.cpp | 2 -- 2 files changed, 4 deletions(-) (limited to 'src') diff --git a/src/plugins/qmltooling/qmldbg_profiler/qqmlprofileradapter.cpp b/src/plugins/qmltooling/qmldbg_profiler/qqmlprofileradapter.cpp index 90e817e2fc..510c745d4e 100644 --- a/src/plugins/qmltooling/qmldbg_profiler/qqmlprofileradapter.cpp +++ b/src/plugins/qmltooling/qmldbg_profiler/qqmlprofileradapter.cpp @@ -66,8 +66,6 @@ QQmlProfilerAdapter::QQmlProfilerAdapter(QQmlProfilerService *service, QQmlEngin } // convert to QByteArrays that can be sent to the debug client -// use of QDataStream can skew results -// (see tst_qqmldebugtrace::trace() benchmark) static void qQmlProfilerDataToByteArrays(const QQmlProfilerData &d, QQmlProfiler::LocationHash &locations, QList &messages, diff --git a/src/plugins/qmltooling/qmldbg_quickprofiler/qquickprofileradapter.cpp b/src/plugins/qmltooling/qmldbg_quickprofiler/qquickprofileradapter.cpp index 0c9fc36463..35beb0ee0d 100644 --- a/src/plugins/qmltooling/qmldbg_quickprofiler/qquickprofileradapter.cpp +++ b/src/plugins/qmltooling/qmldbg_quickprofiler/qquickprofileradapter.cpp @@ -74,8 +74,6 @@ QQuickProfilerAdapter::~QQuickProfilerAdapter() } // convert to QByteArrays that can be sent to the debug client -// use of QDataStream can skew results -// (see tst_qqmldebugtrace::trace() benchmark) static void qQuickProfilerDataToByteArrays(const QQuickProfilerData &data, QList &messages) { -- cgit v1.2.3 From 802a5be531a9f2b1396f4ea4715c9a1dc593f778 Mon Sep 17 00:00:00 2001 From: Frederik Gladhorn Date: Wed, 10 May 2017 10:09:56 +0200 Subject: Fix hover delivery in case of touch release events This fixes tst_TouchMouse::hoverEnabled. It turns out that the problem is that QQuickWindowPrivate::flushFrameSynchronousEvents would deliver artificial hover events which (due to the nature of the function) would arrive without being synchronized with the test. This should not be a problem as such, but there was one bug: the hover event would also be sent in case of a touch release event. The definition of when to "pretend hover" is a bit shaky, but we should definitely not send hover events after touch releases. By clearing lastMousePosition instead of setting it to where the touch point is released we no longer receive bogus events. Task-number: QTBUG-55350 Change-Id: I4dea54740e37182f66c4a729d7b06a1c770c34a9 Reviewed-by: Robin Burchell Reviewed-by: Simon Hausmann --- src/quick/items/qquickwindow.cpp | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/quick/items/qquickwindow.cpp b/src/quick/items/qquickwindow.cpp index 98901ab818..bdb362e1ff 100644 --- a/src/quick/items/qquickwindow.cpp +++ b/src/quick/items/qquickwindow.cpp @@ -1979,8 +1979,14 @@ bool QQuickWindowPrivate::compressTouchEvent(QTouchEvent *event) void QQuickWindowPrivate::handleTouchEvent(QTouchEvent *event) { translateTouchEvent(event); - if (event->touchPoints().size()) - lastMousePosition = event->touchPoints().at(0).pos(); + if (event->touchPoints().size()) { + auto point = event->touchPoints().at(0); + if (point.state() == Qt::TouchPointReleased) { + lastMousePosition = QPointF(); + } else { + lastMousePosition = point.pos(); + } + } qCDebug(DBG_TOUCH) << event; -- cgit v1.2.3 From e0c30279ec1fad88346ed3fb483bc3c672fdd01b Mon Sep 17 00:00:00 2001 From: Jan Arve Saether Date: Mon, 8 May 2017 11:25:10 +0200 Subject: Move pointerEvent instance to QQuickWindow With two or more windows, if events are being delivered to each, the grabbers can be different in each. We need unique instances of the QQuickPointerEvent objects for each window to avoid losing the grab state in the parent window while delivering a synthesized event to a subwindow, for example. Change-Id: I51da1212d573853969e32ad78f5b219d979a8a5c Task-number: QTBUG-57253 Reviewed-by: Shawn Rutledge --- src/quick/items/qquickevents_p_p.h | 25 +++++------------- src/quick/items/qquickwindow.cpp | 52 ++++++++++++++++++++++++++++++-------- src/quick/items/qquickwindow_p.h | 4 +++ 3 files changed, 52 insertions(+), 29 deletions(-) (limited to 'src') diff --git a/src/quick/items/qquickevents_p_p.h b/src/quick/items/qquickevents_p_p.h index cf6f83e5b1..3735d68a85 100644 --- a/src/quick/items/qquickevents_p_p.h +++ b/src/quick/items/qquickevents_p_p.h @@ -332,9 +332,9 @@ class Q_QUICK_PRIVATE_EXPORT QQuickPointerEvent : public QObject Q_PROPERTY(Qt::MouseButtons buttons READ buttons) public: - QQuickPointerEvent(QObject *parent = nullptr) + QQuickPointerEvent(QObject *parent = nullptr, QQuickPointerDevice *device = nullptr) : QObject(parent) - , m_device(nullptr) + , m_device(device) , m_event(nullptr) , m_button(Qt::NoButton) , m_pressedButtons(Qt::NoButton) @@ -385,8 +385,8 @@ class Q_QUICK_PRIVATE_EXPORT QQuickPointerMouseEvent : public QQuickPointerEvent { Q_OBJECT public: - QQuickPointerMouseEvent(QObject *parent = nullptr) - : QQuickPointerEvent(parent), m_mousePoint(new QQuickEventPoint(this)) { } + QQuickPointerMouseEvent(QObject *parent = nullptr, QQuickPointerDevice *device = nullptr) + : QQuickPointerEvent(parent, device), m_mousePoint(new QQuickEventPoint(this)) { } QQuickPointerEvent *reset(QEvent *) override; bool isPressEvent() const override; @@ -411,8 +411,8 @@ class Q_QUICK_PRIVATE_EXPORT QQuickPointerTouchEvent : public QQuickPointerEvent { Q_OBJECT public: - QQuickPointerTouchEvent(QObject *parent = nullptr) - : QQuickPointerEvent(parent) + QQuickPointerTouchEvent(QObject *parent = nullptr, QQuickPointerDevice *device = nullptr) + : QQuickPointerEvent(parent, device) , m_pointCount(0) , m_synthMouseEvent(QEvent::MouseMove, QPointF(), Qt::NoButton, Qt::NoButton, Qt::NoModifier) { } @@ -500,18 +500,10 @@ public: QQuickPointerDevice(DeviceType devType, PointerType pType, Capabilities caps, int maxPoints, int buttonCount, const QString &name, qint64 uniqueId = 0) : m_deviceType(devType), m_pointerType(pType), m_capabilities(caps) , m_maximumTouchPoints(maxPoints), m_buttonCount(buttonCount), m_name(name) - , m_uniqueId(QPointingDeviceUniqueId::fromNumericId(uniqueId)), m_event(nullptr) + , m_uniqueId(QPointingDeviceUniqueId::fromNumericId(uniqueId)) { - if (m_deviceType == Mouse) { - m_event = new QQuickPointerMouseEvent; - } else if (m_deviceType == TouchScreen || m_deviceType == TouchPad) { - m_event = new QQuickPointerTouchEvent; - } else { - Q_ASSERT(false); - } } - ~QQuickPointerDevice() { delete m_event; } DeviceType type() const { return m_deviceType; } PointerType pointerType() const { return m_pointerType; } Capabilities capabilities() const { return m_capabilities; } @@ -520,7 +512,6 @@ public: int buttonCount() const { return m_buttonCount; } QString name() const { return m_name; } QPointingDeviceUniqueId uniqueId() const { return m_uniqueId; } - QQuickPointerEvent *pointerEvent() const { return m_event; } static QQuickPointerDevice *touchDevice(QTouchDevice *d); static QList touchDevices(); @@ -535,8 +526,6 @@ private: int m_buttonCount; QString m_name; QPointingDeviceUniqueId m_uniqueId; - // the device-specific event instance which is reused during event delivery - QQuickPointerEvent *m_event; Q_DISABLE_COPY(QQuickPointerDevice) }; diff --git a/src/quick/items/qquickwindow.cpp b/src/quick/items/qquickwindow.cpp index bdb362e1ff..c441cfc357 100644 --- a/src/quick/items/qquickwindow.cpp +++ b/src/quick/items/qquickwindow.cpp @@ -752,12 +752,12 @@ void QQuickWindowPrivate::setMouseGrabber(QQuickItem *grabber) if (grabber && touchMouseId != -1 && touchMouseDevice) { // update the touch item for mouse touch id to the new grabber qCDebug(DBG_TOUCH_TARGET) << "TP (mouse)" << hex << touchMouseId << "->" << q->mouseGrabberItem(); - auto point = touchMouseDevice->pointerEvent()->pointById(touchMouseId); + auto point = pointerEventInstance(touchMouseDevice)->pointById(touchMouseId); if (point) point->setGrabber(grabber); fromTouch = true; } else { - QQuickPointerEvent *event = QQuickPointerDevice::genericMouseDevice()->pointerEvent(); + QQuickPointerEvent *event = pointerEventInstance(QQuickPointerDevice::genericMouseDevice()); Q_ASSERT(event->pointCount() == 1); event->point(0)->setGrabber(grabber); } @@ -784,7 +784,7 @@ void QQuickWindowPrivate::grabTouchPoints(QQuickItem *grabber, const QVectorpointerEvent()->pointById(id); + auto point = pointerEventInstance(touchMouseDevice)->pointById(id); auto touchMouseGrabber = point->grabber(); if (touchMouseGrabber) { point->setGrabber(nullptr); @@ -798,7 +798,7 @@ void QQuickWindowPrivate::grabTouchPoints(QQuickItem *grabber, const QVectorpointerEvent()->pointById(id); + auto point = pointerEventInstance(device)->pointById(id); if (!point) continue; QQuickItem *oldGrabber = point->grabber(); @@ -824,7 +824,7 @@ void QQuickWindowPrivate::removeGrabber(QQuickItem *grabber, bool mouse, bool to if (Q_LIKELY(touch)) { const auto touchDevices = QQuickPointerDevice::touchDevices(); for (auto device : touchDevices) { - auto pointerEvent = device->pointerEvent(); + auto pointerEvent = pointerEventInstance(device); for (int i = 0; i < pointerEvent->pointCount(); ++i) { if (pointerEvent->point(i)->grabber() == grabber) { pointerEvent->point(i)->setGrabber(nullptr); @@ -1493,13 +1493,13 @@ QQuickItem *QQuickWindow::mouseGrabberItem() const Q_D(const QQuickWindow); if (d->touchMouseId != -1 && d->touchMouseDevice) { - QQuickPointerEvent *event = d->touchMouseDevice->pointerEvent(); + QQuickPointerEvent *event = d->pointerEventInstance(d->touchMouseDevice); auto point = event->pointById(d->touchMouseId); Q_ASSERT(point); return point->grabber(); } - QQuickPointerEvent *event = QQuickPointerDevice::genericMouseDevice()->pointerEvent(); + QQuickPointerEvent *event = d->pointerEventInstance(QQuickPointerDevice::genericMouseDevice()); Q_ASSERT(event->pointCount()); return event->point(0)->grabber(); } @@ -1883,7 +1883,7 @@ bool QQuickWindowPrivate::deliverTouchCancelEvent(QTouchEvent *event) // A TouchCancel event will typically not contain any points. // Deliver it to all items that have active touches. - QQuickPointerEvent *pointerEvent = QQuickPointerDevice::touchDevice(event->device())->pointerEvent(); + QQuickPointerEvent *pointerEvent = pointerEventInstance(QQuickPointerDevice::touchDevice(event->device())); QVector grabbers = pointerEvent->grabbers(); for (QQuickItem *grabber: qAsConst(grabbers)) { @@ -2113,6 +2113,32 @@ void QQuickWindowPrivate::flushFrameSynchronousEvents() } } +QQuickPointerEvent *QQuickWindowPrivate::pointerEventInstance(QQuickPointerDevice *device) const +{ + // the list of devices should be very small so a linear search should be ok + for (QQuickPointerEvent *e: pointerEventInstances) { + if (e->device() == device) + return e; + } + + QQuickPointerEvent *ev = nullptr; + QQuickWindow *q = const_cast(q_func()); + switch (device->type()) { + case QQuickPointerDevice::Mouse: + ev = new QQuickPointerMouseEvent(q, device); + break; + case QQuickPointerDevice::TouchPad: + case QQuickPointerDevice::TouchScreen: + ev = new QQuickPointerTouchEvent(q, device); + break; + default: + // TODO tablet event types + break; + } + pointerEventInstances << ev; + return ev; +} + /*! \internal Returns a QQuickPointerEvent instance suitable for wrapping and delivering \a event. @@ -2123,25 +2149,29 @@ void QQuickWindowPrivate::flushFrameSynchronousEvents() QQuickPointerEvent *QQuickWindowPrivate::pointerEventInstance(QEvent *event) const { QQuickPointerDevice *dev = nullptr; + QQuickPointerEvent *ev = nullptr; switch (event->type()) { case QEvent::MouseButtonPress: case QEvent::MouseButtonRelease: case QEvent::MouseButtonDblClick: case QEvent::MouseMove: dev = QQuickPointerDevice::genericMouseDevice(); + ev = pointerEventInstance(dev); break; case QEvent::TouchBegin: case QEvent::TouchUpdate: case QEvent::TouchEnd: case QEvent::TouchCancel: dev = QQuickPointerDevice::touchDevice(static_cast(event)->device()); + ev = pointerEventInstance(dev); break; // TODO tablet event types default: break; } - Q_ASSERT(dev); - return dev->pointerEvent()->reset(event); + + Q_ASSERT(ev); + return ev->reset(event); } void QQuickWindowPrivate::deliverPointerEvent(QQuickPointerEvent *event) @@ -2616,7 +2646,7 @@ bool QQuickWindowPrivate::sendFilteredTouchEvent(QQuickItem *target, QQuickItem if (touchMouseUnset) { // the point was grabbed as a pure touch point before, now it will be treated as mouse // but the old receiver still needs to be informed - if (auto oldGrabber = touchMouseDevice->pointerEvent()->pointById(tp.id())->grabber()) + if (auto oldGrabber = pointerEventInstance(touchMouseDevice)->pointById(tp.id())->grabber()) oldGrabber->touchUngrabEvent(); } touchMouseUnset = false; // We want to leave touchMouseId and touchMouseDevice set diff --git a/src/quick/items/qquickwindow_p.h b/src/quick/items/qquickwindow_p.h index be915903c6..b3ff5a2b35 100644 --- a/src/quick/items/qquickwindow_p.h +++ b/src/quick/items/qquickwindow_p.h @@ -162,6 +162,10 @@ public: void flushFrameSynchronousEvents(); void deliverDelayedTouchEvent(); + // the device-specific event instances which are reused during event delivery + mutable QVector pointerEventInstances; + QQuickPointerEvent *pointerEventInstance(QQuickPointerDevice *device) const; + // delivery of pointer events: QQuickPointerEvent *pointerEventInstance(QEvent *ev) const; void deliverPointerEvent(QQuickPointerEvent *); -- cgit v1.2.3 From 9921b48c83490b450241d6c172f1375ab4efb6b1 Mon Sep 17 00:00:00 2001 From: Michael Brasser Date: Tue, 9 May 2017 09:21:58 -0500 Subject: Ensure same glyph cache is used for same font at different sizes Change-Id: I46b62616fd8141f65786e9e7bcb1068bed460732 Task-number: QTBUG-60696 Reviewed-by: Eskil Abrahamsen Blomfeldt --- src/quick/scenegraph/util/qsgdistancefieldutil.cpp | 24 ++++++++++++++++++++-- src/quick/scenegraph/util/qsgdistancefieldutil_p.h | 4 +++- 2 files changed, 25 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/src/quick/scenegraph/util/qsgdistancefieldutil.cpp b/src/quick/scenegraph/util/qsgdistancefieldutil.cpp index 9ca9cdb107..84df7f3393 100644 --- a/src/quick/scenegraph/util/qsgdistancefieldutil.cpp +++ b/src/quick/scenegraph/util/qsgdistancefieldutil.cpp @@ -84,12 +84,32 @@ QSGDistanceFieldGlyphCacheManager::~QSGDistanceFieldGlyphCacheManager() QSGDistanceFieldGlyphCache *QSGDistanceFieldGlyphCacheManager::cache(const QRawFont &font) { - return m_caches.value(font, 0); + return m_caches.value(fontKey(font), 0); } void QSGDistanceFieldGlyphCacheManager::insertCache(const QRawFont &font, QSGDistanceFieldGlyphCache *cache) { - m_caches.insert(font, cache); + m_caches.insert(fontKey(font), cache); +} + +QString QSGDistanceFieldGlyphCacheManager::fontKey(const QRawFont &font) +{ + QFontEngine *fe = QRawFontPrivate::get(font)->fontEngine; + if (!fe->faceId().filename.isEmpty()) { + QByteArray keyName = fe->faceId().filename; + if (font.style() != QFont::StyleNormal) + keyName += QByteArray(" I"); + if (font.weight() != QFont::Normal) + keyName += ' ' + QByteArray::number(font.weight()); + keyName += QByteArray(" DF"); + return QString::fromUtf8(keyName); + } else { + return QString::fromLatin1("%1_%2_%3_%4") + .arg(font.familyName()) + .arg(font.styleName()) + .arg(font.weight()) + .arg(font.style()); + } } QT_END_NAMESPACE diff --git a/src/quick/scenegraph/util/qsgdistancefieldutil_p.h b/src/quick/scenegraph/util/qsgdistancefieldutil_p.h index ad366cb4d4..354a48a81e 100644 --- a/src/quick/scenegraph/util/qsgdistancefieldutil_p.h +++ b/src/quick/scenegraph/util/qsgdistancefieldutil_p.h @@ -80,7 +80,9 @@ public: void setAntialiasingSpreadFunc(AntialiasingSpreadFunc func) { m_antialiasingSpread_func = func; } private: - QHash m_caches; + static QString fontKey(const QRawFont &font); + + QHash m_caches; ThresholdFunc m_threshold_func; AntialiasingSpreadFunc m_antialiasingSpread_func; -- cgit v1.2.3 From a225bddf67f4786c845193630d4ab20b99a2fc3a Mon Sep 17 00:00:00 2001 From: Oswald Buddenhagen Date: Fri, 28 Apr 2017 13:25:50 +0200 Subject: Update the alloca() support in QtQml qv4alloca_p.h dates from April 2013 and contained just the #includes, whereas the code in qtqmlglobal_p.h was introduced earlier this year in commit 87f016ea9eddc874d5cba7d79d0a487d5ef61761. This commit moves the macros to qv4alloca_p.h and centralizes the support there. This also updates the #include detection mechanism, by using QT_CONFIG(alloca_h) to determine which #include to use. See commit 98c1d516b7f7624f7fcd7b9046783e3903a6a42b in qtbase for more details. Task-number: QTBUG-59700 Started-by: Thiago Macieira Change-Id: Icd0e0d4b27cb4e5eb892fffd14b4b38005ce2ecb Reviewed-by: Thiago Macieira Reviewed-by: Lars Knoll --- src/qml/jsruntime/jsruntime.pri | 1 + src/qml/jsruntime/qv4alloca_p.h | 53 +++++++++++++++++++++++++++++++++++++---- src/qml/qtqmlglobal_p.h | 40 ------------------------------- 3 files changed, 49 insertions(+), 45 deletions(-) (limited to 'src') diff --git a/src/qml/jsruntime/jsruntime.pri b/src/qml/jsruntime/jsruntime.pri index 955cf585e4..76ac8d4a91 100644 --- a/src/qml/jsruntime/jsruntime.pri +++ b/src/qml/jsruntime/jsruntime.pri @@ -46,6 +46,7 @@ SOURCES += \ HEADERS += \ $$PWD/qv4global_p.h \ + $$PWD/qv4alloca_p.h \ $$PWD/qv4engine_p.h \ $$PWD/qv4context_p.h \ $$PWD/qv4math_p.h \ diff --git a/src/qml/jsruntime/qv4alloca_p.h b/src/qml/jsruntime/qv4alloca_p.h index 2f486988c1..c21878fa42 100644 --- a/src/qml/jsruntime/qv4alloca_p.h +++ b/src/qml/jsruntime/qv4alloca_p.h @@ -51,15 +51,58 @@ // We mean it. // -#include +#include -#if defined(Q_OS_WIN) +#if QT_CONFIG(alloca_h) +# include +#elif QT_CONFIG(alloca_malloc_h) # include -# ifndef __GNUC__ +// This does not matter unless compiling in strict standard mode. +# ifdef Q_OS_WIN # define alloca _alloca # endif -#elif !defined(Q_OS_BSD4) || defined(Q_OS_DARWIN) -# include +#else +# include +#endif + +// Define Q_ALLOCA_VAR macro to be used instead of #ifdeffing +// the occurrences of alloca() in case it's not supported. +// Q_ALLOCA_DECLARE and Q_ALLOCA_ASSIGN macros separate +// memory allocation from the declaration and RAII. +#define Q_ALLOCA_VAR(type, name, size) \ + Q_ALLOCA_DECLARE(type, name); \ + Q_ALLOCA_ASSIGN(type, name, size) + +#if QT_CONFIG(alloca) + +#define Q_ALLOCA_DECLARE(type, name) \ + type *name = 0 + +#define Q_ALLOCA_ASSIGN(type, name, size) \ + name = static_cast(alloca(size)) + +#else +QT_BEGIN_NAMESPACE +class Qt_AllocaWrapper +{ +public: + Qt_AllocaWrapper() { m_data = 0; } + ~Qt_AllocaWrapper() { free(m_data); } + void *data() { return m_data; } + void allocate(int size) { m_data = malloc(size); } +private: + void *m_data; +}; +QT_END_NAMESPACE + +#define Q_ALLOCA_DECLARE(type, name) \ + Qt_AllocaWrapper _qt_alloca_##name; \ + type *name = nullptr + +#define Q_ALLOCA_ASSIGN(type, name, size) \ + _qt_alloca_##name.allocate(size); \ + name = static_cast(_qt_alloca_##name.data()) + #endif #endif diff --git a/src/qml/qtqmlglobal_p.h b/src/qml/qtqmlglobal_p.h index 6547274d09..e9834ffc4c 100644 --- a/src/qml/qtqmlglobal_p.h +++ b/src/qml/qtqmlglobal_p.h @@ -55,46 +55,6 @@ #include #include -// Define Q_ALLOCA_VAR macro to be used instead of #ifdeffing -// the occurrences of alloca() in case it's not supported. -// Q_ALLOCA_DECLARE and Q_ALLOCA_ASSIGN macros separate -// memory allocation from the declaration and RAII. -#define Q_ALLOCA_VAR(type, name, size) \ - Q_ALLOCA_DECLARE(type, name); \ - Q_ALLOCA_ASSIGN(type, name, size) - -#if defined(QT_BOOTSTRAPPED) || QT_CONFIG(alloca) - -#define Q_ALLOCA_DECLARE(type, name) \ - type *name = 0 - -#define Q_ALLOCA_ASSIGN(type, name, size) \ - name = static_cast(alloca(size)) - -#else -QT_BEGIN_NAMESPACE -class Qt_AllocaWrapper -{ -public: - Qt_AllocaWrapper() { m_data = 0; } - ~Qt_AllocaWrapper() { free(m_data); } - void *data() { return m_data; } - void allocate(int size) { m_data = malloc(size); } -private: - void *m_data; -}; -QT_END_NAMESPACE - -#define Q_ALLOCA_DECLARE(type, name) \ - Qt_AllocaWrapper _qt_alloca_##name; \ - type *name = 0 - -#define Q_ALLOCA_ASSIGN(type, name, size) \ - _qt_alloca_##name.allocate(size); \ - name = static_cast(_qt_alloca_##name.data()) - -#endif - #define Q_QML_PRIVATE_EXPORT Q_QML_EXPORT #endif // QTQMLGLOBAL_P_H -- cgit v1.2.3 From 7434d05cc102f27d36b8efccb4e37f20a4886ea9 Mon Sep 17 00:00:00 2001 From: Simon Hausmann Date: Tue, 9 May 2017 11:30:03 +0200 Subject: Fix build on MIPS32 Remove stack handling function that's dead code that doesn't compile. Task-number: QTBUG-58567 Change-Id: I704b0323522ce2a313d6cc85112f782872c3bf68 Reviewed-by: Lars Knoll --- src/3rdparty/masm/assembler/MacroAssembler.h | 8 -------- 1 file changed, 8 deletions(-) (limited to 'src') diff --git a/src/3rdparty/masm/assembler/MacroAssembler.h b/src/3rdparty/masm/assembler/MacroAssembler.h index f37861eb66..6e77a9ffb7 100644 --- a/src/3rdparty/masm/assembler/MacroAssembler.h +++ b/src/3rdparty/masm/assembler/MacroAssembler.h @@ -248,14 +248,6 @@ public: } #endif -#if CPU(MIPS) - void poke(FPRegisterID src, int index = 0) - { - ASSERT(!(index & 1)); - storeDouble(src, addressForPoke(index)); - } -#endif - // Backwards banches, these are currently all implemented using existing forwards branch mechanisms. void branchPtr(RelationalCondition cond, RegisterID op1, TrustedImmPtr imm, Label target) { -- cgit v1.2.3 From 095e7d378ee17838d9ba5d7a503da0608bb2fd0c Mon Sep 17 00:00:00 2001 From: Lars Knoll Date: Tue, 9 May 2017 08:24:01 +0200 Subject: Optimize Runtime::method_get/setElement This is now actually just as fast as the lookup code, so disable the generation of lookups for indexed accesses for now. This saves some runtime memory, as we don't need the data structures for the lookup. We can reintroduce lookups, once they offer a real performance benefit. Change-Id: Idc3fa7b248e2e25b4b2cd60d5053e2815634c8b7 Reviewed-by: Simon Hausmann --- src/qml/compiler/qv4isel_moth.cpp | 4 +- src/qml/jit/qv4isel_masm.cpp | 4 +- src/qml/jsruntime/qv4runtime.cpp | 104 +++++++++++++++++++++++++++++--------- 3 files changed, 83 insertions(+), 29 deletions(-) (limited to 'src') diff --git a/src/qml/compiler/qv4isel_moth.cpp b/src/qml/compiler/qv4isel_moth.cpp index aefb084971..dc6fe317e5 100644 --- a/src/qml/compiler/qv4isel_moth.cpp +++ b/src/qml/compiler/qv4isel_moth.cpp @@ -638,7 +638,7 @@ void InstructionSelection::getQObjectProperty(IR::Expr *base, int propertyIndex, void InstructionSelection::getElement(IR::Expr *base, IR::Expr *index, IR::Expr *target) { - if (useFastLookups) { + if (0 && useFastLookups) { Instruction::LoadElementLookup load; load.lookup = registerIndexedGetterLookup(); load.base = getParam(base); @@ -657,7 +657,7 @@ void InstructionSelection::getElement(IR::Expr *base, IR::Expr *index, IR::Expr void InstructionSelection::setElement(IR::Expr *source, IR::Expr *targetBase, IR::Expr *targetIndex) { - if (useFastLookups) { + if (0 && useFastLookups) { Instruction::StoreElementLookup store; store.lookup = registerIndexedSetterLookup(); store.base = getParam(targetBase); diff --git a/src/qml/jit/qv4isel_masm.cpp b/src/qml/jit/qv4isel_masm.cpp index ac72d2e8f5..50d40f6f98 100644 --- a/src/qml/jit/qv4isel_masm.cpp +++ b/src/qml/jit/qv4isel_masm.cpp @@ -618,7 +618,7 @@ void InstructionSelection::setQObjectProperty(IR::Expr *source, IR template void InstructionSelection::getElement(IR::Expr *base, IR::Expr *index, IR::Expr *target) { - if (useFastLookups) { + if (0 && useFastLookups) { uint lookup = registerIndexedGetterLookup(); generateLookupCall(target, lookup, offsetof(QV4::Lookup, indexedGetter), PointerToValue(base), @@ -633,7 +633,7 @@ void InstructionSelection::getElement(IR::Expr *base, IR::Expr *in template void InstructionSelection::setElement(IR::Expr *source, IR::Expr *targetBase, IR::Expr *targetIndex) { - if (useFastLookups) { + if (0 && useFastLookups) { uint lookup = registerIndexedSetterLookup(); generateLookupCall(JITAssembler::Void, lookup, offsetof(QV4::Lookup, indexedSetter), PointerToValue(targetBase), PointerToValue(targetIndex), diff --git a/src/qml/jsruntime/qv4runtime.cpp b/src/qml/jsruntime/qv4runtime.cpp index 42bf24d7f3..4b440f5335 100644 --- a/src/qml/jsruntime/qv4runtime.cpp +++ b/src/qml/jsruntime/qv4runtime.cpp @@ -599,41 +599,53 @@ void Runtime::method_setProperty(ExecutionEngine *engine, const Value &object, i o->put(name, value); } -ReturnedValue Runtime::method_getElement(ExecutionEngine *engine, const Value &object, const Value &index) +static Q_NEVER_INLINE ReturnedValue getElementIntFallback(ExecutionEngine *engine, const Value &object, uint idx) { + Q_ASSERT(idx < UINT_MAX); Scope scope(engine); - uint idx = index.asArrayIndex(); ScopedObject o(scope, object); if (!o) { - if (idx < UINT_MAX) { - if (const String *str = object.as()) { - if (idx >= (uint)str->toQString().length()) { - return Encode::undefined(); - } - const QString s = str->toQString().mid(idx, 1); - return scope.engine->newString(s)->asReturnedValue(); + if (const String *str = object.as()) { + if (idx >= (uint)str->toQString().length()) { + return Encode::undefined(); } + const QString s = str->toQString().mid(idx, 1); + return scope.engine->newString(s)->asReturnedValue(); } if (object.isNullOrUndefined()) { - QString message = QStringLiteral("Cannot read property '%1' of %2").arg(index.toQStringNoThrow()).arg(object.toQStringNoThrow()); + QString message = QStringLiteral("Cannot read property '%1' of %2").arg(idx).arg(object.toQStringNoThrow()); return engine->throwTypeError(message); } o = RuntimeHelpers::convertToObject(scope.engine, object); - if (!o) // type error - return Encode::undefined(); + Q_ASSERT(!!o); // can't fail as null/undefined is covered above + } + + if (o->arrayData() && !o->arrayData()->attrs) { + ScopedValue v(scope, o->arrayData()->get(idx)); + if (!v->isEmpty()) + return v->asReturnedValue(); } - if (idx < UINT_MAX) { - if (o->arrayData() && !o->arrayData()->attrs) { - ScopedValue v(scope, o->arrayData()->get(idx)); - if (!v->isEmpty()) - return v->asReturnedValue(); + return o->getIndexed(idx); +} + +static Q_NEVER_INLINE ReturnedValue getElementFallback(ExecutionEngine *engine, const Value &object, const Value &index) +{ + Q_ASSERT(index.asArrayIndex() == UINT_MAX); + Scope scope(engine); + + ScopedObject o(scope, object); + if (!o) { + if (object.isNullOrUndefined()) { + QString message = QStringLiteral("Cannot read property '%1' of %2").arg(index.toQStringNoThrow()).arg(object.toQStringNoThrow()); + return engine->throwTypeError(message); } - return o->getIndexed(idx); + o = RuntimeHelpers::convertToObject(scope.engine, object); + Q_ASSERT(!!o); // can't fail as null/undefined is covered above } ScopedString name(scope, index.toString(engine)); @@ -642,18 +654,39 @@ ReturnedValue Runtime::method_getElement(ExecutionEngine *engine, const Value &o return o->get(name); } -void Runtime::method_setElement(ExecutionEngine *engine, const Value &object, const Value &index, const Value &value) +ReturnedValue Runtime::method_getElement(ExecutionEngine *engine, const Value &object, const Value &index) +{ + uint idx; + if (index.asArrayIndex(idx)) { + if (Heap::Base *b = object.heapObject()) { + if (b->vtable()->isObject) { + Heap::Object *o = static_cast(b); + if (o->arrayData && o->arrayData->type == Heap::ArrayData::Simple) { + Heap::SimpleArrayData *s = o->arrayData.cast(); + if (idx < s->len) + if (!s->data(idx).isEmpty()) + return s->data(idx).asReturnedValue(); + } + } + } + return getElementIntFallback(engine, object, idx); + } + + return getElementFallback(engine, object, index); +} + +static Q_NEVER_INLINE void setElementFallback(ExecutionEngine *engine, const Value &object, const Value &index, const Value &value) { Scope scope(engine); ScopedObject o(scope, object.toObject(engine)); - if (scope.engine->hasException) + if (engine->hasException) return; - uint idx = index.asArrayIndex(); - if (idx < UINT_MAX) { - if (o->arrayType() == Heap::ArrayData::Simple) { - Heap::SimpleArrayData *s = static_cast(o->arrayData()); - if (s && idx < s->len && !s->data(idx).isEmpty()) { + uint idx; + if (index.asArrayIndex(idx)) { + if (o->d()->arrayData && o->d()->arrayData->type == Heap::ArrayData::Simple) { + Heap::SimpleArrayData *s = o->d()->arrayData.cast(); + if (idx < s->len) { s->data(idx) = value; return; } @@ -666,6 +699,27 @@ void Runtime::method_setElement(ExecutionEngine *engine, const Value &object, co o->put(name, value); } +void Runtime::method_setElement(ExecutionEngine *engine, const Value &object, const Value &index, const Value &value) +{ + uint idx; + if (index.asArrayIndex(idx)) { + if (Heap::Base *b = object.heapObject()) { + if (b->vtable()->isObject) { + Heap::Object *o = static_cast(b); + if (o->arrayData && o->arrayData->type == Heap::ArrayData::Simple) { + Heap::SimpleArrayData *s = o->arrayData.cast(); + if (idx < s->len) { + s->data(idx) = value; + return; + } + } + } + } + } + + return setElementFallback(engine, object, index, value); +} + ReturnedValue Runtime::method_foreachIterator(ExecutionEngine *engine, const Value &in) { Scope scope(engine); -- cgit v1.2.3 From 59a70377683445f4355b5e3eef50869b61331cfa Mon Sep 17 00:00:00 2001 From: Berthold Krevert Date: Mon, 1 May 2017 23:03:41 +0200 Subject: Fix QSG_VISUALIZE=batches Since I362e1cb8e10 the batch renderer defaults to QSG_SEPARATE_INDEX_BUFFER which broke the batches visualization Change-Id: If1d51cabb0cc4a3a98ac2c01bd78789d08fe72f7 Reviewed-by: Gunnar Sletta Reviewed-by: Robin Burchell --- src/quick/scenegraph/coreapi/qsgbatchrenderer.cpp | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'src') diff --git a/src/quick/scenegraph/coreapi/qsgbatchrenderer.cpp b/src/quick/scenegraph/coreapi/qsgbatchrenderer.cpp index b8ebeaca63..78f2c86f6c 100644 --- a/src/quick/scenegraph/coreapi/qsgbatchrenderer.cpp +++ b/src/quick/scenegraph/coreapi/qsgbatchrenderer.cpp @@ -2966,7 +2966,11 @@ void Renderer::visualizeBatch(Batch *b) for (int ds=0; dsdrawSets.size(); ++ds) { const DrawSet &set = b->drawSets.at(ds); glVertexAttribPointer(a.position, 2, a.type, false, g->sizeOfVertex(), (void *) (qintptr) (set.vertices)); +#ifdef QSG_SEPARATE_INDEX_BUFFER + glDrawElements(g->drawingMode(), set.indexCount, GL_UNSIGNED_SHORT, (void *) (qintptr) (b->ibo.data + set.indices)); +#else glDrawElements(g->drawingMode(), set.indexCount, GL_UNSIGNED_SHORT, (void *) (qintptr) (b->vbo.data + set.indices)); +#endif } } else { Element *e = b->first; -- cgit v1.2.3 From ee6b07b3ce8ba80632868181d45d96253acb1064 Mon Sep 17 00:00:00 2001 From: Shawn Rutledge Date: Thu, 11 May 2017 20:25:47 +0200 Subject: Temporarily restore QQuickPointerDevice::pointerEvent() accessor This can be reverted as soon as the relevant qtlocation change is integrated. Task-number: QTBUG-57253 Change-Id: I72b71f61ba8fe421ac57c963801176098fe9f11c Reviewed-by: Robin Burchell --- src/quick/items/qquickevents_p_p.h | 7 +++++++ src/quick/items/qquickwindow.cpp | 5 ++++- 2 files changed, 11 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/quick/items/qquickevents_p_p.h b/src/quick/items/qquickevents_p_p.h index 3735d68a85..323ecfa4ff 100644 --- a/src/quick/items/qquickevents_p_p.h +++ b/src/quick/items/qquickevents_p_p.h @@ -501,6 +501,7 @@ public: : m_deviceType(devType), m_pointerType(pType), m_capabilities(caps) , m_maximumTouchPoints(maxPoints), m_buttonCount(buttonCount), m_name(name) , m_uniqueId(QPointingDeviceUniqueId::fromNumericId(uniqueId)) + , m_event(nullptr) { } @@ -513,6 +514,8 @@ public: QString name() const { return m_name; } QPointingDeviceUniqueId uniqueId() const { return m_uniqueId; } + QQuickPointerEvent *pointerEvent() const { return m_event; } // deprecated + static QQuickPointerDevice *touchDevice(QTouchDevice *d); static QList touchDevices(); static QQuickPointerDevice *genericMouseDevice(); @@ -527,6 +530,10 @@ private: QString m_name; QPointingDeviceUniqueId m_uniqueId; + // the event instance used last time within the context of one window + QQuickPointerEvent *m_event; // deprecated + friend class QQuickWindowPrivate; // not needed after removing the above + Q_DISABLE_COPY(QQuickPointerDevice) }; diff --git a/src/quick/items/qquickwindow.cpp b/src/quick/items/qquickwindow.cpp index c441cfc357..816c057ab0 100644 --- a/src/quick/items/qquickwindow.cpp +++ b/src/quick/items/qquickwindow.cpp @@ -2117,8 +2117,10 @@ QQuickPointerEvent *QQuickWindowPrivate::pointerEventInstance(QQuickPointerDevic { // the list of devices should be very small so a linear search should be ok for (QQuickPointerEvent *e: pointerEventInstances) { - if (e->device() == device) + if (e->device() == device) { + device->m_event = e; return e; + } } QQuickPointerEvent *ev = nullptr; @@ -2136,6 +2138,7 @@ QQuickPointerEvent *QQuickWindowPrivate::pointerEventInstance(QQuickPointerDevic break; } pointerEventInstances << ev; + device->m_event = ev; return ev; } -- cgit v1.2.3 From defa2512a9128449e30d3b2c2fc42eaab201418b Mon Sep 17 00:00:00 2001 From: Lars Knoll Date: Tue, 9 May 2017 08:58:28 +0200 Subject: Disable loop peeling Loop peeling does in our current JIT not give us any measurable performance benefits (no measurable diff in any of the v8 benchmarks), and significantly increases the size of the generated JIT code. Change-Id: Icab7887300f9c1cd5891983cbfe5885fc2b4db91 Reviewed-by: Simon Hausmann --- src/qml/compiler/qv4ssa.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/qml/compiler/qv4ssa.cpp b/src/qml/compiler/qv4ssa.cpp index 731c6ad38f..fc136b09ff 100644 --- a/src/qml/compiler/qv4ssa.cpp +++ b/src/qml/compiler/qv4ssa.cpp @@ -5417,7 +5417,11 @@ void Optimizer::run(QQmlEnginePrivate *qmlEngine, bool doTypeInference, bool pee showMeTheCode(function, "After loop detection"); // cfg2dot(function, loopDetection.allLoops()); - if (peelLoops) { + // ### disable loop peeling for now. It doesn't give any measurable performance + // improvements at this time, but significantly increases the size of the + // JIT generated code + Q_UNUSED(peelLoops); + if (0 && peelLoops) { QVector innerLoops = loopDetection.innermostLoops(); LoopPeeling(df).run(innerLoops); -- cgit v1.2.3 From e6acf80136db9f667d0d4664f6c68065355d6811 Mon Sep 17 00:00:00 2001 From: Mitch Curtis Date: Sat, 6 May 2017 22:32:57 +0200 Subject: QQuickWindow::createTextureFromImage(): return nullptr for null images Change-Id: Idf3315be104e058315d82893443e1c27d1d79f2e Reviewed-by: Laszlo Agocs --- src/quick/items/qquickwindow.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/quick/items/qquickwindow.cpp b/src/quick/items/qquickwindow.cpp index c441cfc357..ff4a357641 100644 --- a/src/quick/items/qquickwindow.cpp +++ b/src/quick/items/qquickwindow.cpp @@ -3862,7 +3862,7 @@ QSGTexture *QQuickWindow::createTextureFromImage(const QImage &image) const QSGTexture *QQuickWindow::createTextureFromImage(const QImage &image, CreateTextureOptions options) const { Q_D(const QQuickWindow); - if (!isSceneGraphInitialized()) // check both for d->context and d->context->isValid() + if (!isSceneGraphInitialized() || image.isNull()) // check both for d->context and d->context->isValid() return 0; uint flags = 0; if (options & TextureCanUseAtlas) flags |= QSGRenderContext::CreateTexture_Atlas; -- cgit v1.2.3 From d214db97edcf7a76ecb629d49ac2e9dd0e1948e8 Mon Sep 17 00:00:00 2001 From: Tim Jenssen Date: Mon, 15 May 2017 16:01:34 +0200 Subject: Make all loaders synchronous in qquickdesigner support case It could result in wrong/strange behavior if the QtQuickDesigner shows asynchronous loaded items in the FormEditor view. So keep this setting disabled in that case. Change-Id: I9bbd75f33eb009e31064744564cc4104df624c3c Reviewed-by: Robin Burchell --- src/quick/designer/qquickdesignersupportitems.cpp | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'src') diff --git a/src/quick/designer/qquickdesignersupportitems.cpp b/src/quick/designer/qquickdesignersupportitems.cpp index 2003b484ad..874faed0af 100644 --- a/src/quick/designer/qquickdesignersupportitems.cpp +++ b/src/quick/designer/qquickdesignersupportitems.cpp @@ -47,6 +47,7 @@ #include #include #include +#include #include #include @@ -79,6 +80,12 @@ static void stopAnimation(QObject *object) } } +static void makeLoaderSynchronous(QObject *object) +{ + if (QQuickLoader *loader = qobject_cast(object)) + loader->setAsynchronous(false); +} + static void allSubObjects(QObject *object, QObjectList &objectList) { // don't add null pointer and stop if the object is already in the list @@ -137,6 +144,7 @@ void QQuickDesignerSupportItems::tweakObjects(QObject *object) allSubObjects(object, objectList); for (QObject* childObject : qAsConst(objectList)) { stopAnimation(childObject); + makeLoaderSynchronous(childObject); if (fixResourcePathsForObjectCallBack) fixResourcePathsForObjectCallBack(childObject); } -- cgit v1.2.3 From 025bdeb66284c1016fb79c8ec230890542408320 Mon Sep 17 00:00:00 2001 From: Friedemann Kleint Date: Tue, 9 May 2017 09:47:53 +0200 Subject: qmlcachegen: Fix MinGW developer build MinGW was unable to link qmlcachegen due to missing symbols from the autotest-exported class QV4::ExecutableAllocator. Introduce a separate Q_QML_AUTOTEST_EXPORT macro that is defined to empty when used by qmldevtools. Change-Id: Ib7f8984dd7617fae05bb4e1e6cc1fae0745ac3bc Reviewed-by: Simon Hausmann Reviewed-by: Oswald Buddenhagen --- src/qml/jsruntime/qv4executableallocator_p.h | 2 +- src/qml/qtqmlglobal_p.h | 6 ++++++ 2 files changed, 7 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/qml/jsruntime/qv4executableallocator_p.h b/src/qml/jsruntime/qv4executableallocator_p.h index f13f70e01a..353a6eacff 100644 --- a/src/qml/jsruntime/qv4executableallocator_p.h +++ b/src/qml/jsruntime/qv4executableallocator_p.h @@ -67,7 +67,7 @@ QT_BEGIN_NAMESPACE namespace QV4 { -class Q_AUTOTEST_EXPORT ExecutableAllocator +class Q_QML_AUTOTEST_EXPORT ExecutableAllocator { public: struct ChunkOfPages; diff --git a/src/qml/qtqmlglobal_p.h b/src/qml/qtqmlglobal_p.h index e9834ffc4c..3314e73d19 100644 --- a/src/qml/qtqmlglobal_p.h +++ b/src/qml/qtqmlglobal_p.h @@ -57,4 +57,10 @@ #define Q_QML_PRIVATE_EXPORT Q_QML_EXPORT +#if !defined(QT_QMLDEVTOOLS_LIB) && !defined(QT_BUILD_QMLDEVTOOLS_LIB) +# define Q_QML_AUTOTEST_EXPORT Q_AUTOTEST_EXPORT +#else +# define Q_QML_AUTOTEST_EXPORT +#endif + #endif // QTQMLGLOBAL_P_H -- cgit v1.2.3 From accaf69fc4f1d1197adae3deb2196897aa85aa43 Mon Sep 17 00:00:00 2001 From: Thomas McGuire Date: Tue, 16 May 2017 22:04:05 +0200 Subject: Fix QML Connections element ignoring the enabled property The enabled property was ignored if it was set before componentComplete() was called. [ChangeLog][QtQml] Fixed the QML Connections element ignoring the initial state of the enabled property Change-Id: I40c92fcb30f0bb8ca406f248b3bde2fced5ab58f Reviewed-by: Simon Hausmann --- src/qml/types/qqmlconnections.cpp | 1 + 1 file changed, 1 insertion(+) (limited to 'src') diff --git a/src/qml/types/qqmlconnections.cpp b/src/qml/types/qqmlconnections.cpp index cbf0f69093..7607c19374 100644 --- a/src/qml/types/qqmlconnections.cpp +++ b/src/qml/types/qqmlconnections.cpp @@ -287,6 +287,7 @@ void QQmlConnections::connectSignals() int signalIndex = QQmlPropertyPrivate::get(prop)->signalIndex(); QQmlBoundSignal *signal = new QQmlBoundSignal(target, signalIndex, this, qmlEngine(this)); + signal->setEnabled(d->enabled); QQmlBoundSignalExpression *expression = ctxtdata ? new QQmlBoundSignalExpression(target, signalIndex, -- cgit v1.2.3 From 1e8f85dbc90da6b49fa7018ccbc35db68281d395 Mon Sep 17 00:00:00 2001 From: Oswald Buddenhagen Date: Thu, 18 May 2017 16:59:02 +0200 Subject: don't try to pull in the regular config headers when bootstrapping Task-number: QTBUG-60675 Change-Id: I7ae9ab4f442d34f6eaa770652029b5dfccef346a Reviewed-by: Simon Hausmann --- src/qml/qtqmlglobal.h | 16 +++++++++------- src/qml/qtqmlglobal_p.h | 4 +++- 2 files changed, 12 insertions(+), 8 deletions(-) (limited to 'src') diff --git a/src/qml/qtqmlglobal.h b/src/qml/qtqmlglobal.h index 6704e55b52..387c28a945 100644 --- a/src/qml/qtqmlglobal.h +++ b/src/qml/qtqmlglobal.h @@ -40,18 +40,20 @@ #ifndef QTQMLGLOBAL_H #define QTQMLGLOBAL_H +#if defined(QT_BUILD_QMLDEVTOOLS_LIB) || defined(QT_QMLDEVTOOLS_LIB) +# define QT_QML_BOOTSTRAPPED +#endif + #include -#include -#if QT_CONFIG(qml_network) -#include +#ifndef QT_QML_BOOTSTRAPPED +# include +# if QT_CONFIG(qml_network) +# include +# endif #endif QT_BEGIN_NAMESPACE -#if defined(QT_BUILD_QMLDEVTOOLS_LIB) || defined(QT_QMLDEVTOOLS_LIB) -# define QT_QML_BOOTSTRAPPED -#endif - #if !defined(QT_QML_BOOTSTRAPPED) && !defined(QT_STATIC) # if defined(QT_BUILD_QML_LIB) # define Q_QML_EXPORT Q_DECL_EXPORT diff --git a/src/qml/qtqmlglobal_p.h b/src/qml/qtqmlglobal_p.h index e9834ffc4c..0313d8e33b 100644 --- a/src/qml/qtqmlglobal_p.h +++ b/src/qml/qtqmlglobal_p.h @@ -52,8 +52,10 @@ // #include -#include #include +#ifndef QT_QML_BOOTSTRAPPED +# include +#endif #define Q_QML_PRIVATE_EXPORT Q_QML_EXPORT -- cgit v1.2.3 From b078939cb86c7fd82335f4d4a815b6f62eb7b26f Mon Sep 17 00:00:00 2001 From: Robin Burchell Date: Thu, 18 May 2017 12:01:47 +0200 Subject: Revert "QQuickItem: Port a number of manual loops to range-for" This reverts commit 8d92e595e0e8cf19f60db2fce4a543265c9130e9. This is broken in a few places, e.g. setEffectiveVisibleRecur emits, which means that it may run uncontrolled code, so we can't be sure the list isn't altered underneath us. Change-Id: I58b8b62e74581207c1b14902ea7b8b552761de8a Task-number: QTBUG-58811 Reviewed-by: Lars Knoll Reviewed-by: Simon Hausmann Reviewed-by: Shawn Rutledge --- src/quick/items/qquickitem.cpp | 90 +++++++++++++++++++++++++----------------- 1 file changed, 53 insertions(+), 37 deletions(-) (limited to 'src') diff --git a/src/quick/items/qquickitem.cpp b/src/quick/items/qquickitem.cpp index 8e90827a3d..e280b0bd61 100644 --- a/src/quick/items/qquickitem.cpp +++ b/src/quick/items/qquickitem.cpp @@ -146,8 +146,8 @@ QQuickTransform::QQuickTransform(QQuickTransformPrivate &dd, QObject *parent) QQuickTransform::~QQuickTransform() { Q_D(QQuickTransform); - for (QQuickItem *item : qAsConst(d->items)) { - QQuickItemPrivate *p = QQuickItemPrivate::get(item); + for (int ii = 0; ii < d->items.count(); ++ii) { + QQuickItemPrivate *p = QQuickItemPrivate::get(d->items.at(ii)); p->transforms.removeOne(this); p->dirty(QQuickItemPrivate::Transform); } @@ -156,8 +156,8 @@ QQuickTransform::~QQuickTransform() void QQuickTransform::update() { Q_D(QQuickTransform); - for (QQuickItem *item : qAsConst(d->items)) { - QQuickItemPrivate *p = QQuickItemPrivate::get(item); + for (int ii = 0; ii < d->items.count(); ++ii) { + QQuickItemPrivate *p = QQuickItemPrivate::get(d->items.at(ii)); p->dirty(QQuickItemPrivate::Transform); } } @@ -169,7 +169,9 @@ QQuickContents::QQuickContents(QQuickItem *item) QQuickContents::~QQuickContents() { - for (QQuickItem *child : m_item->childItems()) { + QList children = m_item->childItems(); + for (int i = 0; i < children.count(); ++i) { + QQuickItem *child = children.at(i); QQuickItemPrivate::get(child)->removeItemChangeListener(this, QQuickItemPrivate::Geometry | QQuickItemPrivate::Destroyed); } } @@ -192,8 +194,9 @@ bool QQuickContents::calcHeight(QQuickItem *changed) } else { qreal top = std::numeric_limits::max(); qreal bottom = -std::numeric_limits::max(); - const QList children = m_item->childItems(); - for (QQuickItem *child : qAsConst(children)) { + QList children = m_item->childItems(); + for (int i = 0; i < children.count(); ++i) { + QQuickItem *child = children.at(i); qreal y = child->y(); if (y + child->height() > bottom) bottom = y + child->height(); @@ -226,8 +229,9 @@ bool QQuickContents::calcWidth(QQuickItem *changed) } else { qreal left = std::numeric_limits::max(); qreal right = -std::numeric_limits::max(); - const QList children = m_item->childItems(); - for (QQuickItem *child : qAsConst(children)) { + QList children = m_item->childItems(); + for (int i = 0; i < children.count(); ++i) { + QQuickItem *child = children.at(i); qreal x = child->x(); if (x + child->width() > right) right = x + child->width(); @@ -246,7 +250,9 @@ void QQuickContents::complete() { QQuickItemPrivate::get(m_item)->addItemChangeListener(this, QQuickItemPrivate::Children); - for (QQuickItem *child : m_item->childItems()) { + QList children = m_item->childItems(); + for (int i = 0; i < children.count(); ++i) { + QQuickItem *child = children.at(i); QQuickItemPrivate::get(child)->addItemChangeListener(this, QQuickItemPrivate::Geometry | QQuickItemPrivate::Destroyed); //###what about changes to visibility? } @@ -1347,7 +1353,8 @@ void QQuickKeysAttached::componentComplete() #if QT_CONFIG(im) Q_D(QQuickKeysAttached); if (d->item) { - for (QQuickItem *targetItem : qAsConst(d->targets)) { + for (int ii = 0; ii < d->targets.count(); ++ii) { + QQuickItem *targetItem = d->targets.at(ii); if (targetItem && (targetItem->flags() & QQuickItem::ItemAcceptsInputMethod)) { d->item->setFlag(QQuickItem::ItemAcceptsInputMethod); break; @@ -1369,10 +1376,11 @@ void QQuickKeysAttached::keyPressed(QKeyEvent *event, bool post) // first process forwards if (d->item && d->item->window()) { d->inPress = true; - for (QQuickItem *targetItem : qAsConst(d->targets)) { - if (targetItem && targetItem->isVisible()) { + for (int ii = 0; ii < d->targets.count(); ++ii) { + QQuickItem *i = d->targets.at(ii); + if (i && i->isVisible()) { event->accept(); - QCoreApplication::sendEvent(targetItem, event); + QCoreApplication::sendEvent(i, event); if (event->isAccepted()) { d->inPress = false; return; @@ -1412,10 +1420,11 @@ void QQuickKeysAttached::keyReleased(QKeyEvent *event, bool post) if (d->item && d->item->window()) { d->inRelease = true; - for (QQuickItem *targetItem : qAsConst(d->targets)) { - if (targetItem && targetItem->isVisible()) { + for (int ii = 0; ii < d->targets.count(); ++ii) { + QQuickItem *i = d->targets.at(ii); + if (i && i->isVisible()) { event->accept(); - QCoreApplication::sendEvent(targetItem, event); + QCoreApplication::sendEvent(i, event); if (event->isAccepted()) { d->inRelease = false; return; @@ -1439,7 +1448,8 @@ void QQuickKeysAttached::inputMethodEvent(QInputMethodEvent *event, bool post) Q_D(QQuickKeysAttached); if (post == m_processPost && d->item && !d->inIM && d->item->window()) { d->inIM = true; - for (QQuickItem *targetItem : qAsConst(d->targets)) { + for (int ii = 0; ii < d->targets.count(); ++ii) { + QQuickItem *targetItem = d->targets.at(ii); if (targetItem && targetItem->isVisible() && (targetItem->flags() & QQuickItem::ItemAcceptsInputMethod)) { QCoreApplication::sendEvent(targetItem, event); if (event->isAccepted()) { @@ -1458,12 +1468,13 @@ QVariant QQuickKeysAttached::inputMethodQuery(Qt::InputMethodQuery query) const { Q_D(const QQuickKeysAttached); if (d->item) { - for (QQuickItem *targetItem : qAsConst(d->targets)) { - if (targetItem && targetItem->isVisible() && (targetItem->flags() & QQuickItem::ItemAcceptsInputMethod) && targetItem == d->imeItem) { - //### how robust is targetItem == d->imeItem check? - QVariant v = targetItem->inputMethodQuery(query); + for (int ii = 0; ii < d->targets.count(); ++ii) { + QQuickItem *i = d->targets.at(ii); + if (i && i->isVisible() && (i->flags() & QQuickItem::ItemAcceptsInputMethod) && i == d->imeItem) { + //### how robust is i == d->imeItem check? + QVariant v = i->inputMethodQuery(query); if (v.userType() == QVariant::RectF) - v = d->item->mapRectFromItem(targetItem, v.toRectF()); //### cost? + v = d->item->mapRectFromItem(i, v.toRectF()); //### cost? return v; } } @@ -1637,9 +1648,11 @@ void QQuickItemPrivate::setImplicitLayoutMirror(bool mirror, bool inherit) if (isMirrorImplicit) setLayoutMirror(inherit ? inheritedLayoutMirror : false); - for (QQuickItem *child : qAsConst(childItems)) { - QQuickItemPrivate *childPrivate = QQuickItemPrivate::get(child); - childPrivate->setImplicitLayoutMirror(inheritedLayoutMirror, inheritMirrorFromParent); + for (int i = 0; i < childItems.count(); ++i) { + if (QQuickItem *child = qmlobject_cast(childItems.at(i))) { + QQuickItemPrivate *childPrivate = QQuickItemPrivate::get(child); + childPrivate->setImplicitLayoutMirror(inheritedLayoutMirror, inheritMirrorFromParent); + } } } @@ -2395,7 +2408,8 @@ QQuickItem::~QQuickItem() remove themselves from our list of transforms when that list has already been destroyed after ~QQuickItem() has run. */ - for (QQuickTransform *t : qAsConst(d->transforms)) { + for (int ii = 0; ii < d->transforms.count(); ++ii) { + QQuickTransform *t = d->transforms.at(ii); QQuickTransformPrivate *tp = QQuickTransformPrivate::get(t); tp->items.removeOne(this); } @@ -2886,8 +2900,8 @@ QList QQuickItemPrivate::paintOrderChildItems() const // If none of the items have set Z then the paint order list is the same as // the childItems list. This is by far the most common case. bool haveZ = false; - for (QQuickItem *childItem : qAsConst(childItems)) { - if (QQuickItemPrivate::get(childItem)->z() != 0.) { + for (int i = 0; i < childItems.count(); ++i) { + if (QQuickItemPrivate::get(childItems.at(i))->z() != 0.) { haveZ = true; break; } @@ -2988,7 +3002,8 @@ void QQuickItemPrivate::refWindow(QQuickWindow *c) if (!parentItem) QQuickWindowPrivate::get(window)->parentlessItems.insert(q); - for (QQuickItem *child : qAsConst(childItems)) { + for (int ii = 0; ii < childItems.count(); ++ii) { + QQuickItem *child = childItems.at(ii); QQuickItemPrivate::get(child)->refWindow(c); } @@ -3040,7 +3055,8 @@ void QQuickItemPrivate::derefWindow() paintNode = 0; - for (QQuickItem *child : qAsConst(childItems)) { + for (int ii = 0; ii < childItems.count(); ++ii) { + QQuickItem *child = childItems.at(ii); QQuickItemPrivate::get(child)->derefWindow(); } @@ -3485,7 +3501,8 @@ void QQuickItemPrivate::transform_clear(QQmlListProperty *prop) QQuickItem *that = static_cast(prop->object); QQuickItemPrivate *p = QQuickItemPrivate::get(that); - for (QQuickTransform *t : qAsConst(p->transforms)) { + for (int ii = 0; ii < p->transforms.count(); ++ii) { + QQuickTransform *t = p->transforms.at(ii); QQuickTransformPrivate *tp = QQuickTransformPrivate::get(t); tp->items.removeOne(that); } @@ -5850,9 +5867,8 @@ bool QQuickItemPrivate::setEffectiveVisibleRecur(bool newEffectiveVisible) } bool childVisibilityChanged = false; - for (QQuickItem *childItem : qAsConst(childItems)) { - childVisibilityChanged |= QQuickItemPrivate::get(childItem)->setEffectiveVisibleRecur(newEffectiveVisible); - } + for (int ii = 0; ii < childItems.count(); ++ii) + childVisibilityChanged |= QQuickItemPrivate::get(childItems.at(ii))->setEffectiveVisibleRecur(newEffectiveVisible); itemChange(QQuickItem::ItemVisibleHasChanged, effectiveVisible); #if QT_CONFIG(accessibility) @@ -5901,8 +5917,8 @@ void QQuickItemPrivate::setEffectiveEnableRecur(QQuickItem *scope, bool newEffec } } - for (QQuickItem *childItem : qAsConst(childItems)) { - QQuickItemPrivate::get(childItem)->setEffectiveEnableRecur( + for (int ii = 0; ii < childItems.count(); ++ii) { + QQuickItemPrivate::get(childItems.at(ii))->setEffectiveEnableRecur( (flags & QQuickItem::ItemIsFocusScope) && scope ? q : scope, newEffectiveEnable); } -- cgit v1.2.3 From 2affe19182b99d8d1c9655fa0c58c8af3e0b9506 Mon Sep 17 00:00:00 2001 From: Lars Knoll Date: Tue, 16 May 2017 12:42:42 +0200 Subject: Free up completely empty Chunks, and return the memory to the OS Detect any Chunk that's completely empty, deallocate it and return the memory to the OS (as far as that's supported). Change-Id: I6b6a77f2cdf478cbf16aad30a9cae37c98c6500e Reviewed-by: Simon Hausmann --- src/qml/memory/qv4mm.cpp | 30 ++++++++++++++++++++++-------- src/qml/memory/qv4mmdefs_p.h | 6 +++++- 2 files changed, 27 insertions(+), 9 deletions(-) (limited to 'src') diff --git a/src/qml/memory/qv4mm.cpp b/src/qml/memory/qv4mm.cpp index 0a6dfb9170..ef36e62373 100644 --- a/src/qml/memory/qv4mm.cpp +++ b/src/qml/memory/qv4mm.cpp @@ -275,8 +275,9 @@ QString binary(quintptr) { return QString(); } #define SDUMP if (1) ; else qDebug #endif -void Chunk::sweep() +bool Chunk::sweep() { + bool hasUsedSlots = false; SDUMP() << "sweeping chunk" << this; HeapItem *o = realBase(); bool lastSlotFree = false; @@ -316,6 +317,7 @@ void Chunk::sweep() } } objectBitmap[i] = blackBitmap[i]; + hasUsedSlots |= (blackBitmap[i] != 0); blackBitmap[i] = 0; extendsBitmap[i] = e; lastSlotFree = !((objectBitmap[i]|extendsBitmap[i]) >> (sizeof(quintptr)*8 - 1)); @@ -325,6 +327,7 @@ void Chunk::sweep() o += Chunk::Bits; } // DEBUG << "swept chunk" << this << "freed" << slotsFreed << "slots."; + return hasUsedSlots; } void Chunk::freeAll() @@ -579,12 +582,21 @@ void BlockAllocator::sweep() // qDebug() << "BlockAlloc: sweep"; usedSlotsAfterLastSweep = 0; - for (auto c : chunks) { - c->sweep(); - c->sortIntoBins(freeBins, NumBins); -// qDebug() << "used slots in chunk" << c << ":" << c->nUsedSlots(); - usedSlotsAfterLastSweep += c->nUsedSlots(); - } + + auto isFree = [this] (Chunk *c) { + bool isUsed = c->sweep(); + + if (isUsed) { + c->sortIntoBins(freeBins, NumBins); + usedSlotsAfterLastSweep += c->nUsedSlots(); + } else { + chunkAllocator->free(c); + } + return !isUsed; + }; + + auto newEnd = std::remove_if(chunks.begin(), chunks.end(), isFree); + chunks.erase(newEnd, chunks.end()); } void BlockAllocator::freeAll() @@ -950,7 +962,8 @@ void MemoryManager::runGC() #ifndef QT_NO_DEBUG qDebug() << " Triggered by alloc request of" << lastAllocRequestedSlots << "slots."; #endif - qDebug() << "Allocated" << totalMem << "bytes in" << blockAllocator.chunks.size() << "chunks"; + size_t oldChunks = blockAllocator.chunks.size(); + qDebug() << "Allocated" << totalMem << "bytes in" << oldChunks << "chunks"; qDebug() << "Fragmented memory before GC" << (totalMem - usedBefore); dumpBins(&blockAllocator); @@ -975,6 +988,7 @@ void MemoryManager::runGC() qDebug() << "Used memory before GC:" << usedBefore; qDebug() << "Used memory after GC:" << usedAfter; qDebug() << "Freed up bytes:" << (usedBefore - usedAfter); + qDebug() << "Freed up chunks:" << (oldChunks - blockAllocator.chunks.size()); size_t lost = blockAllocator.allocatedMem() - memInBins - usedAfter; if (lost) qDebug() << "!!!!!!!!!!!!!!!!!!!!! LOST MEM:" << lost << "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!"; diff --git a/src/qml/memory/qv4mmdefs_p.h b/src/qml/memory/qv4mmdefs_p.h index db0ffe11a2..6e820dfc0f 100644 --- a/src/qml/memory/qv4mmdefs_p.h +++ b/src/qml/memory/qv4mmdefs_p.h @@ -59,6 +59,10 @@ QT_BEGIN_NAMESPACE namespace QV4 { +struct MarkStack; + +typedef void(*ClassDestroyStatsCallback)(const char *); + /* * Chunks are the basic structure containing GC managed objects. * @@ -175,7 +179,7 @@ struct Chunk { return usedSlots; } - void sweep(); + bool sweep(); void freeAll(); void sortIntoBins(HeapItem **bins, uint nBins); -- cgit v1.2.3 From 7ed93899e9305ccd538361ee58baa4bf15ff8a41 Mon Sep 17 00:00:00 2001 From: Lars Knoll Date: Wed, 10 May 2017 09:42:18 +0200 Subject: Optimizations to the generated byte code Cut the size of the generated byte code in half, by storing parameters in a more compact form and always storing the instruction type in the instruction. We can still used computed goto's for a fast interpreter, by looking up the jump point for the next instruction in the jump table. Another advantage is that the byte code is now platform independent (modulo endianness). The change comes with a 3% performance impact on x86_64, which is acceptable considering the size savings on the bytecode. Change-Id: I37de3e1f94611987a85e65ea86536583aa965d6d Reviewed-by: Simon Hausmann --- src/qml/compiler/qv4instr_moth_p.h | 10 +++---- src/qml/compiler/qv4isel_moth.cpp | 55 -------------------------------------- src/qml/jsruntime/qv4vme_moth.cpp | 32 +++++----------------- src/qml/jsruntime/qv4vme_moth_p.h | 10 +------ 4 files changed, 10 insertions(+), 97 deletions(-) (limited to 'src') diff --git a/src/qml/compiler/qv4instr_moth_p.h b/src/qml/compiler/qv4instr_moth_p.h index fbd6ac8f99..dabda7bae8 100644 --- a/src/qml/compiler/qv4instr_moth_p.h +++ b/src/qml/compiler/qv4instr_moth_p.h @@ -170,11 +170,7 @@ QT_BEGIN_NAMESPACE #define MOTH_INSTR_ALIGN_MASK (Q_ALIGNOF(QV4::Moth::Instr) - 1) -#ifdef MOTH_THREADED_INTERPRETER -# define MOTH_INSTR_HEADER union { quint32 instructionType; void *code; }; -#else -# define MOTH_INSTR_HEADER quint32 instructionType; -#endif +#define MOTH_INSTR_HEADER quint32 instructionType; #define MOTH_INSTR_ENUM(I, FMT) I, #define MOTH_INSTR_SIZE(I, FMT) ((sizeof(QV4::Moth::Instr::instr_##FMT) + MOTH_INSTR_ALIGN_MASK) & ~MOTH_INSTR_ALIGN_MASK) @@ -194,8 +190,8 @@ struct Param { // Arg(outer): 4 // Local(outer): 5 // ... - unsigned scope; - unsigned index; + unsigned scope : 12; + unsigned index : 20; bool isConstant() const { return !scope; } bool isArgument() const { return scope >= 2 && !(scope &1); } diff --git a/src/qml/compiler/qv4isel_moth.cpp b/src/qml/compiler/qv4isel_moth.cpp index dc6fe317e5..fb805dce02 100644 --- a/src/qml/compiler/qv4isel_moth.cpp +++ b/src/qml/compiler/qv4isel_moth.cpp @@ -1436,29 +1436,6 @@ CompilationUnit::~CompilationUnit() void CompilationUnit::linkBackendToEngine(QV4::ExecutionEngine *engine) { -#ifdef MOTH_THREADED_INTERPRETER - // link byte code against addresses of instructions - for (int i = 0; i < codeRefs.count(); ++i) { - QByteArray &codeRef = codeRefs[i]; - char *code = codeRef.data(); - int index = 0; - while (index < codeRef.size()) { - Instr *genericInstr = reinterpret_cast(code + index); - - switch (genericInstr->common.instructionType) { -#define LINK_INSTRUCTION(InstructionType, Member) \ - case Instr::InstructionType: \ - genericInstr->common.code = VME::instructionJumpTable()[static_cast(genericInstr->common.instructionType)]; \ - index += InstrMeta<(int)Instr::InstructionType>::Size; \ - break; - - FOR_EACH_MOTH_INSTR(LINK_INSTRUCTION) - - } - } - } -#endif - runtimeFunctions.resize(data->functionTableSize); runtimeFunctions.fill(0); for (int i = 0 ;i < runtimeFunctions.size(); ++i) { @@ -1516,17 +1493,6 @@ bool CompilationUnit::saveCodeToDisk(QIODevice *device, const CompiledData::Unit QByteArray padding; -#if defined(MOTH_THREADED_INTERPRETER) && !defined(V4_BOOTSTRAP) - // Map from instruction label back to instruction type. Only needed when persisting - // already linked compilation units; - QHash reverseInstructionMapping; - if (engine) { - void **instructions = VME::instructionJumpTable(); - for (int i = 0; i < Instr::LastInstruction; ++i) - reverseInstructionMapping.insert(instructions[i], i); - } -#endif - for (int i = 0; i < codeRefs.size(); ++i) { const CompiledData::Function *compiledFunction = unit->functionAt(i); @@ -1545,27 +1511,6 @@ bool CompilationUnit::saveCodeToDisk(QIODevice *device, const CompiledData::Unit QByteArray code = codeRefs.at(i); -#if defined(MOTH_THREADED_INTERPRETER) && !defined(V4_BOOTSTRAP) - if (!reverseInstructionMapping.isEmpty()) { - char *codePtr = code.data(); // detaches - int index = 0; - while (index < code.size()) { - Instr *genericInstr = reinterpret_cast(codePtr + index); - - genericInstr->common.instructionType = reverseInstructionMapping.value(genericInstr->common.code); - - switch (genericInstr->common.instructionType) { - #define REVERSE_INSTRUCTION(InstructionType, Member) \ - case Instr::InstructionType: \ - index += InstrMeta<(int)Instr::InstructionType>::Size; \ - break; - - FOR_EACH_MOTH_INSTR(REVERSE_INSTRUCTION) - } - } - } -#endif - written = device->write(code.constData(), compiledFunction->codeSize); if (written != qint64(compiledFunction->codeSize)) { *errorString = device->errorString(); diff --git a/src/qml/jsruntime/qv4vme_moth.cpp b/src/qml/jsruntime/qv4vme_moth.cpp index a74016ab0c..2288d9ef0a 100644 --- a/src/qml/jsruntime/qv4vme_moth.cpp +++ b/src/qml/jsruntime/qv4vme_moth.cpp @@ -304,7 +304,7 @@ using namespace QV4::Moth; # define MOTH_END_INSTR(I) } \ genericInstr = reinterpret_cast(code); \ - goto *genericInstr->common.code; \ + goto *jumpTable[genericInstr->common.instructionType]; \ #else @@ -356,11 +356,7 @@ Param traceParam(const Param ¶m) if (engine->hasException) \ goto catchException -QV4::ReturnedValue VME::run(ExecutionEngine *engine, const uchar *code -#ifdef MOTH_THREADED_INTERPRETER - , void ***storeJumpTable -#endif - ) +QV4::ReturnedValue VME::run(ExecutionEngine *engine, const uchar *code) { #ifdef DO_TRACE_INSTR qDebug("Starting VME with context=%p and code=%p", context, code); @@ -369,15 +365,11 @@ QV4::ReturnedValue VME::run(ExecutionEngine *engine, const uchar *code qt_v4ResolvePendingBreakpointsHook(); #ifdef MOTH_THREADED_INTERPRETER - if (storeJumpTable) { #define MOTH_INSTR_ADDR(I, FMT) &&op_##I, - static void *jumpTable[] = { - FOR_EACH_MOTH_INSTR(MOTH_INSTR_ADDR) - }; + static void *jumpTable[] = { + FOR_EACH_MOTH_INSTR(MOTH_INSTR_ADDR) + }; #undef MOTH_INSTR_ADDR - *storeJumpTable = jumpTable; - return QV4::Primitive::undefinedValue().asReturnedValue(); - } #endif QV4::Value *stack = 0; @@ -428,7 +420,7 @@ QV4::ReturnedValue VME::run(ExecutionEngine *engine, const uchar *code for (;;) { const Instr *genericInstr = reinterpret_cast(code); #ifdef MOTH_THREADED_INTERPRETER - goto *genericInstr->common.code; + goto *jumpTable[genericInstr->common.instructionType]; #else switch (genericInstr->common.instructionType) { #endif @@ -960,18 +952,6 @@ QV4::ReturnedValue VME::run(ExecutionEngine *engine, const uchar *code } } -#ifdef MOTH_THREADED_INTERPRETER -void **VME::instructionJumpTable() -{ - static void **jumpTable = 0; - if (!jumpTable) { - const uchar *code = 0; - VME().run(0, code, &jumpTable); - } - return jumpTable; -} -#endif - QV4::ReturnedValue VME::exec(ExecutionEngine *engine, const uchar *code) { VME vme; diff --git a/src/qml/jsruntime/qv4vme_moth_p.h b/src/qml/jsruntime/qv4vme_moth_p.h index f8893509d9..8d46207f2b 100644 --- a/src/qml/jsruntime/qv4vme_moth_p.h +++ b/src/qml/jsruntime/qv4vme_moth_p.h @@ -67,16 +67,8 @@ class VME public: static QV4::ReturnedValue exec(QV4::ExecutionEngine *, const uchar *); -#ifdef MOTH_THREADED_INTERPRETER - static void **instructionJumpTable(); -#endif - private: - QV4::ReturnedValue run(QV4::ExecutionEngine *, const uchar *code -#ifdef MOTH_THREADED_INTERPRETER - , void ***storeJumpTable = 0 -#endif - ); + QV4::ReturnedValue run(QV4::ExecutionEngine *, const uchar *code); }; } // namespace Moth -- cgit v1.2.3 From 31d6333fa1bdabf4711739e3399a4fa58f8291a0 Mon Sep 17 00:00:00 2001 From: Lars Knoll Date: Thu, 11 May 2017 09:12:54 +0200 Subject: Smaller cleanups Don't store the current context in Moth's run() method, instead always retrieve it through the engine. Change-Id: I9d56f2c93a02fc1e2f03839b14b3c0053d60b6b2 Reviewed-by: Simon Hausmann --- src/qml/jsruntime/qv4vme_moth.cpp | 40 ++++++++++++++++++--------------------- 1 file changed, 18 insertions(+), 22 deletions(-) (limited to 'src') diff --git a/src/qml/jsruntime/qv4vme_moth.cpp b/src/qml/jsruntime/qv4vme_moth.cpp index 2288d9ef0a..d662b1738d 100644 --- a/src/qml/jsruntime/qv4vme_moth.cpp +++ b/src/qml/jsruntime/qv4vme_moth.cpp @@ -378,7 +378,6 @@ QV4::ReturnedValue VME::run(ExecutionEngine *engine, const uchar *code) const uchar *exceptionHandler = 0; QV4::Scope scope(engine); - QV4::ExecutionContext *context = engine->currentContext; engine->current->lineNumber = -1; #ifdef DO_TRACE_INSTR @@ -388,7 +387,7 @@ QV4::ReturnedValue VME::run(ExecutionEngine *engine, const uchar *code) // setup lookup scopes int scopeDepth = 0; { - QV4::Heap::ExecutionContext *scope = context->d(); + QV4::Heap::ExecutionContext *scope = engine->current; while (scope) { ++scopeDepth; scope = scope->outer; @@ -397,10 +396,10 @@ QV4::ReturnedValue VME::run(ExecutionEngine *engine, const uchar *code) Q_ALLOCA_VAR(QV4::Value*, scopes, sizeof(QV4::Value *)*(2 + 2*scopeDepth)); { - scopes[0] = const_cast(static_cast(context->d()->compilationUnit)->constants); + scopes[0] = const_cast(static_cast(engine->current->compilationUnit)->constants); // stack gets setup in push instruction scopes[1] = 0; - QV4::Heap::ExecutionContext *scope = context->d(); + QV4::Heap::ExecutionContext *scope = engine->current; int i = 0; while (scope) { if (scope->type >= QV4::Heap::ExecutionContext::Type_SimpleCallContext) { @@ -439,12 +438,12 @@ QV4::ReturnedValue VME::run(ExecutionEngine *engine, const uchar *code) MOTH_BEGIN_INSTR(LoadRuntimeString) // TRACE(value, "%s", instr.value.toString(context)->toQString().toUtf8().constData()); - VALUE(instr.result) = context->d()->compilationUnit->runtimeStrings[instr.stringId]; + VALUE(instr.result) = engine->current->compilationUnit->runtimeStrings[instr.stringId]; MOTH_END_INSTR(LoadRuntimeString) MOTH_BEGIN_INSTR(LoadRegExp) // TRACE(value, "%s", instr.value.toString(context)->toQString().toUtf8().constData()); - VALUE(instr.result) = static_cast(context->d()->compilationUnit)->runtimeRegularExpressions[instr.regExpId]; + VALUE(instr.result) = static_cast(engine->current->compilationUnit)->runtimeRegularExpressions[instr.regExpId]; MOTH_END_INSTR(LoadRegExp) MOTH_BEGIN_INSTR(LoadClosure) @@ -457,7 +456,7 @@ QV4::ReturnedValue VME::run(ExecutionEngine *engine, const uchar *code) MOTH_END_INSTR(LoadName) MOTH_BEGIN_INSTR(GetGlobalLookup) - QV4::Lookup *l = context->d()->lookups + instr.index; + QV4::Lookup *l = engine->current->lookups + instr.index; STOREVALUE(instr.result, l->globalGetter(l, engine)); MOTH_END_INSTR(GetGlobalLookup) @@ -472,7 +471,7 @@ QV4::ReturnedValue VME::run(ExecutionEngine *engine, const uchar *code) MOTH_END_INSTR(LoadElement) MOTH_BEGIN_INSTR(LoadElementLookup) - QV4::Lookup *l = context->d()->lookups + instr.lookup; + QV4::Lookup *l = engine->current->lookups + instr.lookup; STOREVALUE(instr.result, l->indexedGetter(l, VALUE(instr.base), VALUE(instr.index))); MOTH_END_INSTR(LoadElementLookup) @@ -482,7 +481,7 @@ QV4::ReturnedValue VME::run(ExecutionEngine *engine, const uchar *code) MOTH_END_INSTR(StoreElement) MOTH_BEGIN_INSTR(StoreElementLookup) - QV4::Lookup *l = context->d()->lookups + instr.lookup; + QV4::Lookup *l = engine->current->lookups + instr.lookup; l->indexedSetter(l, VALUE(instr.base), VALUE(instr.index), VALUE(instr.source)); CHECK_EXCEPTION; MOTH_END_INSTR(StoreElementLookup) @@ -492,7 +491,7 @@ QV4::ReturnedValue VME::run(ExecutionEngine *engine, const uchar *code) MOTH_END_INSTR(LoadProperty) MOTH_BEGIN_INSTR(GetLookup) - QV4::Lookup *l = context->d()->lookups + instr.index; + QV4::Lookup *l = engine->current->lookups + instr.index; STOREVALUE(instr.result, l->getter(l, engine, VALUE(instr.base))); MOTH_END_INSTR(GetLookup) @@ -502,7 +501,7 @@ QV4::ReturnedValue VME::run(ExecutionEngine *engine, const uchar *code) MOTH_END_INSTR(StoreProperty) MOTH_BEGIN_INSTR(SetLookup) - QV4::Lookup *l = context->d()->lookups + instr.index; + QV4::Lookup *l = engine->current->lookups + instr.index; l->setter(l, engine, VALUE(instr.base), VALUE(instr.source)); CHECK_EXCEPTION; MOTH_END_INSTR(SetLookup) @@ -573,7 +572,7 @@ QV4::ReturnedValue VME::run(ExecutionEngine *engine, const uchar *code) MOTH_END_INSTR(CallValue) MOTH_BEGIN_INSTR(CallProperty) - TRACE(property name, "%s, args=%u, argc=%u, this=%s", qPrintable(runtimeStrings[instr.name]->toQString()), instr.callData, instr.argc, (VALUE(instr.base)).toString(context)->toQString().toUtf8().constData()); + TRACE(property name, "%s, args=%u, argc=%u, this=%s", qPrintable(runtimeStrings[instr.name]->toQString()), instr.callData, instr.argc, (VALUE(instr.base)).toString(engine)->toQString().toUtf8().constData()); Q_ASSERT(instr.callData + instr.argc + offsetof(QV4::CallData, args)/sizeof(QV4::Value) <= stackSize); QV4::CallData *callData = reinterpret_cast(stack + instr.callData); callData->tag = quint32(Value::ValueTypeInternal::Integer); @@ -592,7 +591,7 @@ QV4::ReturnedValue VME::run(ExecutionEngine *engine, const uchar *code) MOTH_END_INSTR(CallPropertyLookup) MOTH_BEGIN_INSTR(CallScopeObjectProperty) - TRACE(property name, "%s, args=%u, argc=%u, this=%s", qPrintable(runtimeStrings[instr.name]->toQString()), instr.callData, instr.argc, (VALUE(instr.base)).toString(context)->toQString().toUtf8().constData()); + TRACE(property name, "%s, args=%u, argc=%u, this=%s", qPrintable(runtimeStrings[instr.name]->toQString()), instr.callData, instr.argc, (VALUE(instr.base)).toString(engine)->toQString().toUtf8().constData()); Q_ASSERT(instr.callData + instr.argc + offsetof(QV4::CallData, args)/sizeof(QV4::Value) <= stackSize); QV4::CallData *callData = reinterpret_cast(stack + instr.callData); callData->tag = quint32(Value::ValueTypeInternal::Integer); @@ -602,7 +601,7 @@ QV4::ReturnedValue VME::run(ExecutionEngine *engine, const uchar *code) MOTH_END_INSTR(CallScopeObjectProperty) MOTH_BEGIN_INSTR(CallContextObjectProperty) - TRACE(property name, "%s, args=%u, argc=%u, this=%s", qPrintable(runtimeStrings[instr.name]->toQString()), instr.callData, instr.argc, (VALUE(instr.base)).toString(context)->toQString().toUtf8().constData()); + TRACE(property name, "%s, args=%u, argc=%u, this=%s", qPrintable(runtimeStrings[instr.name]->toQString()), instr.callData, instr.argc, (VALUE(instr.base)).toString(engine)->toQString().toUtf8().constData()); Q_ASSERT(instr.callData + instr.argc + offsetof(QV4::CallData, args)/sizeof(QV4::Value) <= stackSize); QV4::CallData *callData = reinterpret_cast(stack + instr.callData); callData->tag = quint32(Value::ValueTypeInternal::Integer); @@ -653,18 +652,15 @@ QV4::ReturnedValue VME::run(ExecutionEngine *engine, const uchar *code) MOTH_BEGIN_INSTR(CallBuiltinPushCatchScope) Runtime::method_pushCatchScope(static_cast(engine), instr.name); - context = engine->currentContext; MOTH_END_INSTR(CallBuiltinPushCatchScope) MOTH_BEGIN_INSTR(CallBuiltinPushScope) Runtime::method_pushWithScope(VALUE(instr.arg), static_cast(engine)); - context = engine->currentContext; CHECK_EXCEPTION; MOTH_END_INSTR(CallBuiltinPushScope) MOTH_BEGIN_INSTR(CallBuiltinPopScope) Runtime::method_popScope(static_cast(engine)); - context = engine->currentContext; MOTH_END_INSTR(CallBuiltinPopScope) MOTH_BEGIN_INSTR(CallBuiltinForeachIteratorObject) @@ -904,22 +900,22 @@ QV4::ReturnedValue VME::run(ExecutionEngine *engine, const uchar *code) #ifndef QT_NO_QML_DEBUGGER MOTH_BEGIN_INSTR(Debug) engine->current->lineNumber = instr.lineNumber; - QV4::Debugging::Debugger *debugger = context->engine()->debugger(); + QV4::Debugging::Debugger *debugger = engine->debugger(); if (debugger && debugger->pauseAtNextOpportunity()) debugger->maybeBreakAtInstruction(); if (qt_v4IsDebugging) - qt_v4CheckForBreak(context); + qt_v4CheckForBreak(engine->currentContext); MOTH_END_INSTR(Debug) MOTH_BEGIN_INSTR(Line) engine->current->lineNumber = instr.lineNumber; if (qt_v4IsDebugging) - qt_v4CheckForBreak(context); + qt_v4CheckForBreak(engine->currentContext); MOTH_END_INSTR(Line) #endif // QT_NO_QML_DEBUGGER MOTH_BEGIN_INSTR(LoadThis) - VALUE(instr.result) = context->thisObject(); + VALUE(instr.result) = engine->currentContext->thisObject(); MOTH_END_INSTR(LoadThis) MOTH_BEGIN_INSTR(LoadQmlContext) @@ -945,7 +941,7 @@ QV4::ReturnedValue VME::run(ExecutionEngine *engine, const uchar *code) Q_ASSERT(false); catchException: - Q_ASSERT(context->engine()->hasException); + Q_ASSERT(engine->hasException); if (!exceptionHandler) return QV4::Encode::undefined(); code = exceptionHandler; -- cgit v1.2.3 From fa4f49169ad9e7e4afc934b3c947936bf0fcafdc Mon Sep 17 00:00:00 2001 From: Lars Knoll Date: Fri, 12 May 2017 09:33:25 +0200 Subject: Move a few more members from ExecutionEngine to EngineBase Change-Id: I5d1e0d2251e04cc871f9c298849aafac17f23fbf Reviewed-by: Simon Hausmann --- src/qml/jsruntime/qv4engine.cpp | 4 +--- src/qml/jsruntime/qv4engine_p.h | 11 ----------- src/qml/memory/qv4mmdefs_p.h | 8 ++++++++ 3 files changed, 9 insertions(+), 14 deletions(-) (limited to 'src') diff --git a/src/qml/jsruntime/qv4engine.cpp b/src/qml/jsruntime/qv4engine.cpp index 0b61c6e7e6..b72e1d9dcf 100644 --- a/src/qml/jsruntime/qv4engine.cpp +++ b/src/qml/jsruntime/qv4engine.cpp @@ -130,10 +130,8 @@ QQmlEngine *ExecutionEngine::qmlEngine() const qint32 ExecutionEngine::maxCallDepth = -1; ExecutionEngine::ExecutionEngine(EvalISelFactory *factory) - : callDepth(0) - , executableAllocator(new QV4::ExecutableAllocator) + : executableAllocator(new QV4::ExecutableAllocator) , regExpAllocator(new QV4::ExecutableAllocator) - , currentContext(0) , bumperPointerAllocator(new WTF::BumpPointerAllocator) , jsStack(new WTF::PageAllocation) , globalCode(0) diff --git a/src/qml/jsruntime/qv4engine_p.h b/src/qml/jsruntime/qv4engine_p.h index 5182f24235..a57456c0fb 100644 --- a/src/qml/jsruntime/qv4engine_p.h +++ b/src/qml/jsruntime/qv4engine_p.h @@ -96,21 +96,14 @@ private: friend struct ExecutionContext; friend struct Heap::ExecutionContext; public: - qint32 callDepth; - ExecutableAllocator *executableAllocator; ExecutableAllocator *regExpAllocator; QScopedPointer iselFactory; - ExecutionContext *currentContext; - - Value *jsStackLimit; - WTF::BumpPointerAllocator *bumperPointerAllocator; // Used by Yarr Regex engine. enum { JSStackLimit = 4*1024*1024 }; WTF::PageAllocation *jsStack; - Value *jsStackBase; void pushForGC(Heap::Base *m) { *jsStackTop = m; @@ -129,10 +122,6 @@ public: return ptr; } - IdentifierTable *identifierTable; - - Object *globalObject; - Function *globalCode; #ifdef V4_BOOTSTRAP diff --git a/src/qml/memory/qv4mmdefs_p.h b/src/qml/memory/qv4mmdefs_p.h index 6e820dfc0f..75cf4681d6 100644 --- a/src/qml/memory/qv4mmdefs_p.h +++ b/src/qml/memory/qv4mmdefs_p.h @@ -275,6 +275,14 @@ struct EngineBase { #endif MemoryManager *memoryManager = 0; Runtime runtime; + + qint32 callDepth = 0; + Value *jsStackLimit = 0; + Value *jsStackBase = 0; + + ExecutionContext *currentContext = 0; + IdentifierTable *identifierTable = 0; + Object *globalObject = 0; }; #if defined(Q_CC_MSVC) || defined(Q_CC_GNU) #pragma pack(pop) -- cgit v1.2.3 From c83685bf3ae1c85cf204e0cbf7fc9b5db819a0f5 Mon Sep 17 00:00:00 2001 From: Lars Knoll Date: Fri, 12 May 2017 09:40:03 +0200 Subject: Move the EngineBase class into it's own header file Change-Id: Idf87618e4ebff99f3b3c269c950191d67a0182b2 Reviewed-by: Simon Hausmann --- src/qml/jsruntime/jsruntime.pri | 1 + src/qml/jsruntime/qv4engine_p.h | 1 + src/qml/jsruntime/qv4enginebase_p.h | 99 +++++++++++++++++++++++++++++++++++++ src/qml/memory/qv4mmdefs_p.h | 35 ------------- 4 files changed, 101 insertions(+), 35 deletions(-) create mode 100644 src/qml/jsruntime/qv4enginebase_p.h (limited to 'src') diff --git a/src/qml/jsruntime/jsruntime.pri b/src/qml/jsruntime/jsruntime.pri index 76ac8d4a91..9938f60aea 100644 --- a/src/qml/jsruntime/jsruntime.pri +++ b/src/qml/jsruntime/jsruntime.pri @@ -48,6 +48,7 @@ HEADERS += \ $$PWD/qv4global_p.h \ $$PWD/qv4alloca_p.h \ $$PWD/qv4engine_p.h \ + $$PWD/qv4enginebase_p.h \ $$PWD/qv4context_p.h \ $$PWD/qv4math_p.h \ $$PWD/qv4persistent_p.h \ diff --git a/src/qml/jsruntime/qv4engine_p.h b/src/qml/jsruntime/qv4engine_p.h index a57456c0fb..5cb0933e94 100644 --- a/src/qml/jsruntime/qv4engine_p.h +++ b/src/qml/jsruntime/qv4engine_p.h @@ -55,6 +55,7 @@ #include "qv4managed_p.h" #include "qv4context_p.h" #include +#include "qv4enginebase_p.h" #ifndef V4_BOOTSTRAP # include diff --git a/src/qml/jsruntime/qv4enginebase_p.h b/src/qml/jsruntime/qv4enginebase_p.h new file mode 100644 index 0000000000..c86b8bb9a0 --- /dev/null +++ b/src/qml/jsruntime/qv4enginebase_p.h @@ -0,0 +1,99 @@ +/**************************************************************************** +** +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtQml module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ +#ifndef QV4ENGINEBASE_P_H +#define QV4ENGINEBASE_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include +#include + +QT_BEGIN_NAMESPACE + +namespace QV4 { + +// Base class for the execution engine + +#if defined(Q_CC_MSVC) || defined(Q_CC_GNU) +#pragma pack(push, 1) +#endif +struct EngineBase { + Heap::ExecutionContext *current = 0; + + Value *jsStackTop = 0; + quint32 hasException = false; +#if QT_POINTER_SIZE == 8 + quint8 padding[4]; +#endif + MemoryManager *memoryManager = 0; + Runtime runtime; + + qint32 callDepth = 0; + Value *jsStackLimit = 0; + Value *jsStackBase = 0; + + ExecutionContext *currentContext = 0; + IdentifierTable *identifierTable = 0; + Object *globalObject = 0; +}; +#if defined(Q_CC_MSVC) || defined(Q_CC_GNU) +#pragma pack(pop) +#endif + +Q_STATIC_ASSERT(std::is_standard_layout::value); +Q_STATIC_ASSERT(offsetof(EngineBase, current) == 0); +Q_STATIC_ASSERT(offsetof(EngineBase, jsStackTop) == offsetof(EngineBase, current) + QT_POINTER_SIZE); +Q_STATIC_ASSERT(offsetof(EngineBase, hasException) == offsetof(EngineBase, jsStackTop) + QT_POINTER_SIZE); +Q_STATIC_ASSERT(offsetof(EngineBase, memoryManager) == offsetof(EngineBase, hasException) + QT_POINTER_SIZE); +Q_STATIC_ASSERT(offsetof(EngineBase, runtime) == offsetof(EngineBase, memoryManager) + QT_POINTER_SIZE); + +} + +QT_END_NAMESPACE + +#endif diff --git a/src/qml/memory/qv4mmdefs_p.h b/src/qml/memory/qv4mmdefs_p.h index 75cf4681d6..ef93971ab8 100644 --- a/src/qml/memory/qv4mmdefs_p.h +++ b/src/qml/memory/qv4mmdefs_p.h @@ -260,41 +260,6 @@ Q_STATIC_ASSERT(sizeof(HeapItem) == Chunk::SlotSize); Q_STATIC_ASSERT(QT_POINTER_SIZE*8 == Chunk::Bits); Q_STATIC_ASSERT((1 << Chunk::BitShift) == Chunk::Bits); -// Base class for the execution engine - -#if defined(Q_CC_MSVC) || defined(Q_CC_GNU) -#pragma pack(push, 1) -#endif -struct EngineBase { - Heap::ExecutionContext *current = 0; - - Value *jsStackTop = 0; - quint32 hasException = false; -#if QT_POINTER_SIZE == 8 - quint8 padding[4]; -#endif - MemoryManager *memoryManager = 0; - Runtime runtime; - - qint32 callDepth = 0; - Value *jsStackLimit = 0; - Value *jsStackBase = 0; - - ExecutionContext *currentContext = 0; - IdentifierTable *identifierTable = 0; - Object *globalObject = 0; -}; -#if defined(Q_CC_MSVC) || defined(Q_CC_GNU) -#pragma pack(pop) -#endif - -Q_STATIC_ASSERT(std::is_standard_layout::value); -Q_STATIC_ASSERT(offsetof(EngineBase, current) == 0); -Q_STATIC_ASSERT(offsetof(EngineBase, jsStackTop) == offsetof(EngineBase, current) + QT_POINTER_SIZE); -Q_STATIC_ASSERT(offsetof(EngineBase, hasException) == offsetof(EngineBase, jsStackTop) + QT_POINTER_SIZE); -Q_STATIC_ASSERT(offsetof(EngineBase, memoryManager) == offsetof(EngineBase, hasException) + QT_POINTER_SIZE); -Q_STATIC_ASSERT(offsetof(EngineBase, runtime) == offsetof(EngineBase, memoryManager) + QT_POINTER_SIZE); - } QT_END_NAMESPACE -- cgit v1.2.3 From 931239579d60eff13ef4f7674cc10f27d7bbdf71 Mon Sep 17 00:00:00 2001 From: Lars Knoll Date: Fri, 12 May 2017 10:16:51 +0200 Subject: Move the list of default internal classes into EngineBase And store them in an enumerated array. This will simplify upcoming changes. Change-Id: I82eac03b9f6264843ae625e36e150464fe08be9d Reviewed-by: Simon Hausmann --- src/qml/compiler/qv4compileddata.cpp | 2 +- src/qml/jsruntime/qv4engine.cpp | 90 +++++++++++++++++---------------- src/qml/jsruntime/qv4engine_p.h | 19 ------- src/qml/jsruntime/qv4enginebase_p.h | 19 +++++++ src/qml/jsruntime/qv4errorobject.cpp | 2 +- src/qml/jsruntime/qv4errorobject_p.h | 14 +++-- src/qml/jsruntime/qv4function.cpp | 4 +- src/qml/jsruntime/qv4functionobject.cpp | 6 +-- src/qml/jsruntime/qv4functionobject_p.h | 4 +- src/qml/jsruntime/qv4internalclass.cpp | 8 +-- src/qml/jsruntime/qv4object_p.h | 8 +-- src/qml/jsruntime/qv4regexpobject.cpp | 2 +- src/qml/jsruntime/qv4regexpobject_p.h | 2 +- src/qml/jsruntime/qv4runtime.cpp | 2 +- src/qml/jsruntime/qv4stringobject_p.h | 2 +- src/qml/jsruntime/qv4typedarray.cpp | 2 +- 16 files changed, 97 insertions(+), 89 deletions(-) (limited to 'src') diff --git a/src/qml/compiler/qv4compileddata.cpp b/src/qml/compiler/qv4compileddata.cpp index d59a72cde2..ac4192bc12 100644 --- a/src/qml/compiler/qv4compileddata.cpp +++ b/src/qml/compiler/qv4compileddata.cpp @@ -177,7 +177,7 @@ QV4::Function *CompilationUnit::linkToEngine(ExecutionEngine *engine) for (uint i = 0; i < data->jsClassTableSize; ++i) { int memberCount = 0; const CompiledData::JSClassMember *member = data->jsClassAt(i, &memberCount); - QV4::InternalClass *klass = engine->emptyClass; + QV4::InternalClass *klass = engine->internalClasses[QV4::ExecutionEngine::Class_Object]; for (int j = 0; j < memberCount; ++j, ++member) klass = klass->addMember(runtimeStrings[member->nameOffset]->identifier, member->isAccessor ? QV4::Attr_Accessor : QV4::Attr_Data); diff --git a/src/qml/jsruntime/qv4engine.cpp b/src/qml/jsruntime/qv4engine.cpp index b72e1d9dcf..c7b87f209a 100644 --- a/src/qml/jsruntime/qv4engine.cpp +++ b/src/qml/jsruntime/qv4engine.cpp @@ -212,7 +212,9 @@ ExecutionEngine::ExecutionEngine(EvalISelFactory *factory) classPool = new InternalClassPool; - emptyClass = new (classPool) InternalClass(this); + internalClasses[Class_Empty] = new (classPool) InternalClass(this); + internalClasses[Class_Object] = internalClasses[Class_Empty]; + jsStrings[String_Empty] = newIdentifier(QString()); jsStrings[String_undefined] = newIdentifier(QStringLiteral("undefined")); @@ -251,90 +253,90 @@ ExecutionEngine::ExecutionEngine(EvalISelFactory *factory) jsStrings[String_buffer] = newIdentifier(QStringLiteral("buffer")); jsStrings[String_lastIndex] = newIdentifier(QStringLiteral("lastIndex")); - jsObjects[ObjectProto] = memoryManager->allocObject(emptyClass); + jsObjects[ObjectProto] = memoryManager->allocObject(internalClasses[Class_Object]); - arrayClass = emptyClass->addMember(id_length(), Attr_NotConfigurable|Attr_NotEnumerable); - jsObjects[ArrayProto] = memoryManager->allocObject(arrayClass, objectPrototype()); + internalClasses[Class_ArrayObject] = internalClasses[Class_Object]->addMember(id_length(), Attr_NotConfigurable|Attr_NotEnumerable); + jsObjects[ArrayProto] = memoryManager->allocObject(internalClasses[Class_ArrayObject], objectPrototype()); jsObjects[PropertyListProto] = memoryManager->allocObject(); - InternalClass *argsClass = emptyClass->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); + InternalClass *argsClass = internalClasses[Class_Object]->addMember(id_length(), Attr_NotEnumerable); + internalClasses[EngineBase::Class_ArgumentsObject] = argsClass->addMember(id_callee(), Attr_Data|Attr_NotEnumerable); + argsClass = argsClass->addMember(id_callee(), Attr_Accessor|Attr_NotConfigurable|Attr_NotEnumerable); + internalClasses[EngineBase::Class_StrictArgumentsObject] = argsClass->addMember(id_caller(), Attr_Accessor|Attr_NotConfigurable|Attr_NotEnumerable); *static_cast(globalObject) = newObject(); Q_ASSERT(globalObject->d()->vtable()); initRootContext(); - stringClass = emptyClass->addMember(id_length(), Attr_ReadOnly); - Q_ASSERT(stringClass->find(id_length()) == Heap::StringObject::LengthPropertyIndex); - jsObjects[StringProto] = memoryManager->allocObject(stringClass, objectPrototype()); - jsObjects[NumberProto] = memoryManager->allocObject(emptyClass, objectPrototype()); - jsObjects[BooleanProto] = memoryManager->allocObject(emptyClass, objectPrototype()); - jsObjects[DateProto] = memoryManager->allocObject(emptyClass, objectPrototype()); + internalClasses[EngineBase::Class_StringObject] = internalClasses[Class_Object]->addMember(id_length(), Attr_ReadOnly); + Q_ASSERT(internalClasses[EngineBase::Class_StringObject]->find(id_length()) == Heap::StringObject::LengthPropertyIndex); + jsObjects[StringProto] = memoryManager->allocObject(internalClasses[EngineBase::Class_StringObject], objectPrototype()); + jsObjects[NumberProto] = memoryManager->allocObject(internalClasses[Class_Object], objectPrototype()); + jsObjects[BooleanProto] = memoryManager->allocObject(internalClasses[Class_Object], objectPrototype()); + jsObjects[DateProto] = memoryManager->allocObject(internalClasses[Class_Object], objectPrototype()); uint index; - InternalClass *functionProtoClass = emptyClass->addMember(id_prototype(), Attr_NotEnumerable, &index); + InternalClass *functionProtoClass = internalClasses[Class_Object]->addMember(id_prototype(), Attr_NotEnumerable, &index); Q_ASSERT(index == Heap::FunctionObject::Index_Prototype); jsObjects[FunctionProto] = memoryManager->allocObject(functionProtoClass, objectPrototype()); - functionClass = emptyClass->addMember(id_prototype(), Attr_NotEnumerable|Attr_NotConfigurable, &index); + internalClasses[EngineBase::Class_FunctionObject] = internalClasses[Class_Object]->addMember(id_prototype(), Attr_NotEnumerable|Attr_NotConfigurable, &index); Q_ASSERT(index == Heap::FunctionObject::Index_Prototype); - scriptFunctionClass = functionClass->addMember(id_name(), Attr_ReadOnly, &index); + internalClasses[EngineBase::Class_ScriptFunction] = internalClasses[EngineBase::Class_FunctionObject]->addMember(id_name(), Attr_ReadOnly, &index); Q_ASSERT(index == Heap::ScriptFunction::Index_Name); - scriptFunctionClass = scriptFunctionClass->addMember(id_length(), Attr_ReadOnly, &index); + internalClasses[EngineBase::Class_ScriptFunction] = internalClasses[EngineBase::Class_ScriptFunction]->addMember(id_length(), Attr_ReadOnly, &index); Q_ASSERT(index == Heap::ScriptFunction::Index_Length); - protoClass = emptyClass->addMember(id_constructor(), Attr_NotEnumerable, &index); + internalClasses[EngineBase::Class_ObjectProto] = internalClasses[Class_Object]->addMember(id_constructor(), Attr_NotEnumerable, &index); Q_ASSERT(index == Heap::FunctionObject::Index_ProtoConstructor); Scope scope(this); ScopedString str(scope); - regExpObjectClass = emptyClass->addMember(id_lastIndex(), Attr_NotEnumerable|Attr_NotConfigurable, &index); + internalClasses[EngineBase::Class_RegExpObject] = internalClasses[Class_Object]->addMember(id_lastIndex(), Attr_NotEnumerable|Attr_NotConfigurable, &index); Q_ASSERT(index == RegExpObject::Index_LastIndex); - regExpObjectClass = regExpObjectClass->addMember((str = newIdentifier(QStringLiteral("source"))), Attr_ReadOnly, &index); + internalClasses[EngineBase::Class_RegExpObject] = internalClasses[EngineBase::Class_RegExpObject]->addMember((str = newIdentifier(QStringLiteral("source"))), Attr_ReadOnly, &index); Q_ASSERT(index == RegExpObject::Index_Source); - regExpObjectClass = regExpObjectClass->addMember((str = newIdentifier(QStringLiteral("global"))), Attr_ReadOnly, &index); + internalClasses[EngineBase::Class_RegExpObject] = internalClasses[EngineBase::Class_RegExpObject]->addMember((str = newIdentifier(QStringLiteral("global"))), Attr_ReadOnly, &index); Q_ASSERT(index == RegExpObject::Index_Global); - regExpObjectClass = regExpObjectClass->addMember((str = newIdentifier(QStringLiteral("ignoreCase"))), Attr_ReadOnly, &index); + internalClasses[EngineBase::Class_RegExpObject] = internalClasses[EngineBase::Class_RegExpObject]->addMember((str = newIdentifier(QStringLiteral("ignoreCase"))), Attr_ReadOnly, &index); Q_ASSERT(index == RegExpObject::Index_IgnoreCase); - regExpObjectClass = regExpObjectClass->addMember((str = newIdentifier(QStringLiteral("multiline"))), Attr_ReadOnly, &index); + internalClasses[EngineBase::Class_RegExpObject] = internalClasses[EngineBase::Class_RegExpObject]->addMember((str = newIdentifier(QStringLiteral("multiline"))), Attr_ReadOnly, &index); Q_ASSERT(index == RegExpObject::Index_Multiline); - jsObjects[RegExpProto] = memoryManager->allocObject(regExpObjectClass, objectPrototype()); - regExpExecArrayClass = arrayClass->addMember(id_index(), Attr_Data, &index); + jsObjects[RegExpProto] = memoryManager->allocObject(internalClasses[EngineBase::Class_RegExpObject], objectPrototype()); + internalClasses[EngineBase::Class_RegExpExecArray] = internalClasses[Class_ArrayObject]->addMember(id_index(), Attr_Data, &index); Q_ASSERT(index == RegExpObject::Index_ArrayIndex); - regExpExecArrayClass = regExpExecArrayClass->addMember(id_input(), Attr_Data, &index); + internalClasses[EngineBase::Class_RegExpExecArray] = internalClasses[EngineBase::Class_RegExpExecArray]->addMember(id_input(), Attr_Data, &index); Q_ASSERT(index == RegExpObject::Index_ArrayInput); - errorClass = emptyClass->addMember((str = newIdentifier(QStringLiteral("stack"))), Attr_Accessor|Attr_NotConfigurable|Attr_NotEnumerable, &index); + internalClasses[EngineBase::Class_ErrorObject] = internalClasses[Class_Object]->addMember((str = newIdentifier(QStringLiteral("stack"))), Attr_Accessor|Attr_NotConfigurable|Attr_NotEnumerable, &index); Q_ASSERT(index == ErrorObject::Index_Stack); - errorClass = errorClass->addMember((str = newIdentifier(QStringLiteral("fileName"))), Attr_Data|Attr_NotEnumerable, &index); + internalClasses[EngineBase::Class_ErrorObject] = internalClasses[EngineBase::Class_ErrorObject]->addMember((str = newIdentifier(QStringLiteral("fileName"))), Attr_Data|Attr_NotEnumerable, &index); Q_ASSERT(index == ErrorObject::Index_FileName); - errorClass = errorClass->addMember((str = newIdentifier(QStringLiteral("lineNumber"))), Attr_Data|Attr_NotEnumerable, &index); + internalClasses[EngineBase::Class_ErrorObject] = internalClasses[EngineBase::Class_ErrorObject]->addMember((str = newIdentifier(QStringLiteral("lineNumber"))), Attr_Data|Attr_NotEnumerable, &index); Q_ASSERT(index == ErrorObject::Index_LineNumber); - errorClassWithMessage = errorClass->addMember((str = newIdentifier(QStringLiteral("message"))), Attr_Data|Attr_NotEnumerable, &index); + internalClasses[EngineBase::Class_ErrorObjectWithMessage] = internalClasses[EngineBase::Class_ErrorObject]->addMember((str = newIdentifier(QStringLiteral("message"))), Attr_Data|Attr_NotEnumerable, &index); Q_ASSERT(index == ErrorObject::Index_Message); - errorProtoClass = emptyClass->addMember(id_constructor(), Attr_Data|Attr_NotEnumerable, &index); + internalClasses[EngineBase::Class_ErrorProto] = internalClasses[Class_Object]->addMember(id_constructor(), Attr_Data|Attr_NotEnumerable, &index); Q_ASSERT(index == ErrorPrototype::Index_Constructor); - errorProtoClass = errorProtoClass->addMember((str = newIdentifier(QStringLiteral("message"))), Attr_Data|Attr_NotEnumerable, &index); + internalClasses[EngineBase::Class_ErrorProto] = internalClasses[EngineBase::Class_ErrorProto]->addMember((str = newIdentifier(QStringLiteral("message"))), Attr_Data|Attr_NotEnumerable, &index); Q_ASSERT(index == ErrorPrototype::Index_Message); - errorProtoClass = errorProtoClass->addMember(id_name(), Attr_Data|Attr_NotEnumerable, &index); + internalClasses[EngineBase::Class_ErrorProto] = internalClasses[EngineBase::Class_ErrorProto]->addMember(id_name(), Attr_Data|Attr_NotEnumerable, &index); Q_ASSERT(index == ErrorPrototype::Index_Name); jsObjects[GetStack_Function] = BuiltinFunction::create(rootContext(), str = newIdentifier(QStringLiteral("stack")), ErrorObject::method_get_stack); getStackFunction()->defineReadonlyProperty(id_length(), Primitive::fromInt32(0)); - jsObjects[ErrorProto] = memoryManager->allocObject(errorProtoClass, objectPrototype()); - jsObjects[EvalErrorProto] = memoryManager->allocObject(errorProtoClass, errorPrototype()); - jsObjects[RangeErrorProto] = memoryManager->allocObject(errorProtoClass, errorPrototype()); - jsObjects[ReferenceErrorProto] = memoryManager->allocObject(errorProtoClass, errorPrototype()); - jsObjects[SyntaxErrorProto] = memoryManager->allocObject(errorProtoClass, errorPrototype()); - jsObjects[TypeErrorProto] = memoryManager->allocObject(errorProtoClass, errorPrototype()); - jsObjects[URIErrorProto] = memoryManager->allocObject(errorProtoClass, errorPrototype()); + jsObjects[ErrorProto] = memoryManager->allocObject(internalClasses[EngineBase::Class_ErrorProto], objectPrototype()); + jsObjects[EvalErrorProto] = memoryManager->allocObject(internalClasses[EngineBase::Class_ErrorProto], errorPrototype()); + jsObjects[RangeErrorProto] = memoryManager->allocObject(internalClasses[EngineBase::Class_ErrorProto], errorPrototype()); + jsObjects[ReferenceErrorProto] = memoryManager->allocObject(internalClasses[EngineBase::Class_ErrorProto], errorPrototype()); + jsObjects[SyntaxErrorProto] = memoryManager->allocObject(internalClasses[EngineBase::Class_ErrorProto], errorPrototype()); + jsObjects[TypeErrorProto] = memoryManager->allocObject(internalClasses[EngineBase::Class_ErrorProto], errorPrototype()); + jsObjects[URIErrorProto] = memoryManager->allocObject(internalClasses[EngineBase::Class_ErrorProto], errorPrototype()); - jsObjects[VariantProto] = memoryManager->allocObject(emptyClass, objectPrototype()); + jsObjects[VariantProto] = memoryManager->allocObject(internalClasses[Class_Object], objectPrototype()); Q_ASSERT(variantPrototype()->prototype() == objectPrototype()->d()); - jsObjects[SequenceProto] = ScopedValue(scope, memoryManager->allocObject(arrayClass, arrayPrototype())); + jsObjects[SequenceProto] = ScopedValue(scope, memoryManager->allocObject(internalClasses[Class_ArrayObject], arrayPrototype())); ExecutionContext *global = rootContext(); jsObjects[Object_Ctor] = memoryManager->allocObject(global); @@ -464,7 +466,7 @@ ExecutionEngine::~ExecutionEngine() for (QV4::CompiledData::CompilationUnit *unit : qAsConst(remainingUnits)) unit->unlink(); - emptyClass->destroy(); + internalClasses[Class_Empty]->destroy(); delete classPool; delete bumperPointerAllocator; delete regExpCache; diff --git a/src/qml/jsruntime/qv4engine_p.h b/src/qml/jsruntime/qv4engine_p.h index 5cb0933e94..1d07196c28 100644 --- a/src/qml/jsruntime/qv4engine_p.h +++ b/src/qml/jsruntime/qv4engine_p.h @@ -233,25 +233,6 @@ public: Object *signalHandlerPrototype() const { return reinterpret_cast(jsObjects + SignalHandlerProto); } InternalClassPool *classPool; - InternalClass *emptyClass; - - InternalClass *arrayClass; - InternalClass *stringClass; - - InternalClass *functionClass; - InternalClass *scriptFunctionClass; - InternalClass *protoClass; - - InternalClass *regExpExecArrayClass; - InternalClass *regExpObjectClass; - - InternalClass *argumentsObjectClass; - InternalClass *strictArgumentsObjectClass; - - InternalClass *errorClass; - InternalClass *errorClassWithMessage; - InternalClass *errorProtoClass; - EvalFunction *evalFunction() const { return reinterpret_cast(jsObjects + Eval_Function); } FunctionObject *getStackFunction() const { return reinterpret_cast(jsObjects + GetStack_Function); } FunctionObject *thrower() const { return reinterpret_cast(jsObjects + ThrowerObject); } diff --git a/src/qml/jsruntime/qv4enginebase_p.h b/src/qml/jsruntime/qv4enginebase_p.h index c86b8bb9a0..efcd7b16d9 100644 --- a/src/qml/jsruntime/qv4enginebase_p.h +++ b/src/qml/jsruntime/qv4enginebase_p.h @@ -80,6 +80,25 @@ struct EngineBase { ExecutionContext *currentContext = 0; IdentifierTable *identifierTable = 0; Object *globalObject = 0; + + enum { + Class_Empty, + Class_Object, + Class_ArrayObject, + Class_FunctionObject, + Class_StringObject, + Class_ScriptFunction, + Class_ObjectProto, + Class_RegExpExecArray, + Class_RegExpObject, + Class_ArgumentsObject, + Class_StrictArgumentsObject, + Class_ErrorObject, + Class_ErrorObjectWithMessage, + Class_ErrorProto, + NClasses + }; + InternalClass *internalClasses[NClasses]; }; #if defined(Q_CC_MSVC) || defined(Q_CC_GNU) #pragma pack(pop) diff --git a/src/qml/jsruntime/qv4errorobject.cpp b/src/qml/jsruntime/qv4errorobject.cpp index f290bc5136..63b778b56d 100644 --- a/src/qml/jsruntime/qv4errorobject.cpp +++ b/src/qml/jsruntime/qv4errorobject.cpp @@ -75,7 +75,7 @@ void Heap::ErrorObject::init() Scope scope(internalClass->engine); Scoped e(scope, this); - if (internalClass == scope.engine->errorProtoClass) + if (internalClass == scope.engine->internalClasses[EngineBase::Class_ErrorProto]) return; *propertyData(QV4::ErrorObject::Index_Stack) = scope.engine->getStackFunction(); diff --git a/src/qml/jsruntime/qv4errorobject_p.h b/src/qml/jsruntime/qv4errorobject_p.h index 9ba9f05234..896b54da5e 100644 --- a/src/qml/jsruntime/qv4errorobject_p.h +++ b/src/qml/jsruntime/qv4errorobject_p.h @@ -157,7 +157,7 @@ struct ErrorObject: Object { V4_OBJECT2(ErrorObject, Object) Q_MANAGED_TYPE(ErrorObject) - V4_INTERNALCLASS(errorClass) + V4_INTERNALCLASS(ErrorObject) V4_PROTOTYPE(errorPrototype) V4_NEEDS_DESTROY @@ -324,19 +324,25 @@ inline SyntaxErrorObject *ErrorObject::asSyntaxError() template Heap::Object *ErrorObject::create(ExecutionEngine *e, const Value &message) { - return e->memoryManager->allocObject(message.isUndefined() ? e->errorClass : e->errorClassWithMessage, T::defaultPrototype(e), message); + return e->memoryManager->allocObject( + e->internalClasses[message.isUndefined() ? EngineBase::Class_ErrorObject : EngineBase::Class_ErrorObjectWithMessage], + T::defaultPrototype(e), message); } template Heap::Object *ErrorObject::create(ExecutionEngine *e, const QString &message) { Scope scope(e); ScopedValue v(scope, message.isEmpty() ? Encode::undefined() : e->newString(message)->asReturnedValue()); - return e->memoryManager->allocObject(v->isUndefined() ? e->errorClass : e->errorClassWithMessage, T::defaultPrototype(e), v); + return e->memoryManager->allocObject( + e->internalClasses[v->isUndefined() ? EngineBase::Class_ErrorObject : EngineBase::Class_ErrorObjectWithMessage], + T::defaultPrototype(e), v); } template Heap::Object *ErrorObject::create(ExecutionEngine *e, const QString &message, const QString &filename, int line, int column) { Scope scope(e); ScopedValue v(scope, message.isEmpty() ? Encode::undefined() : e->newString(message)->asReturnedValue()); - return e->memoryManager->allocObject(v->isUndefined() ? e->errorClass : e->errorClassWithMessage, T::defaultPrototype(e), v, filename, line, column); + return e->memoryManager->allocObject( + e->internalClasses[v->isUndefined() ? EngineBase::Class_ErrorObject : EngineBase::Class_ErrorObjectWithMessage], + T::defaultPrototype(e), v, filename, line, column); } diff --git a/src/qml/jsruntime/qv4function.cpp b/src/qml/jsruntime/qv4function.cpp index 358c2d079c..994dede26d 100644 --- a/src/qml/jsruntime/qv4function.cpp +++ b/src/qml/jsruntime/qv4function.cpp @@ -59,7 +59,7 @@ Function::Function(ExecutionEngine *engine, CompiledData::CompilationUnit *unit, { Q_UNUSED(engine); - internalClass = engine->emptyClass; + internalClass = engine->internalClasses[EngineBase::Class_Empty]; const CompiledData::LEUInt32 *formalsIndices = compiledFunction->formalsTable(); // iterate backwards, so we get the right ordering for duplicate names Scope scope(engine); @@ -95,7 +95,7 @@ Function::~Function() void Function::updateInternalClass(ExecutionEngine *engine, const QList ¶meters) { - internalClass = engine->emptyClass; + internalClass = engine->internalClasses[EngineBase::Class_Empty]; // iterate backwards, so we get the right ordering for duplicate names Scope scope(engine); diff --git a/src/qml/jsruntime/qv4functionobject.cpp b/src/qml/jsruntime/qv4functionobject.cpp index b2d89220ea..86362fa0cb 100644 --- a/src/qml/jsruntime/qv4functionobject.cpp +++ b/src/qml/jsruntime/qv4functionobject.cpp @@ -122,8 +122,8 @@ void FunctionObject::init(String *n, bool createProto) Q_ASSERT(internalClass() && internalClass()->find(s.engine->id_prototype()) == Heap::FunctionObject::Index_Prototype); if (createProto) { - ScopedObject proto(s, scope()->engine->newObject(s.engine->protoClass, s.engine->objectPrototype())); - Q_ASSERT(s.engine->protoClass->find(s.engine->id_constructor()) == Heap::FunctionObject::Index_ProtoConstructor); + ScopedObject proto(s, scope()->engine->newObject(s.engine->internalClasses[EngineBase::Class_ObjectProto], s.engine->objectPrototype())); + Q_ASSERT(s.engine->internalClasses[EngineBase::Class_ObjectProto]->find(s.engine->id_constructor()) == Heap::FunctionObject::Index_ProtoConstructor); *proto->propertyData(Heap::FunctionObject::Index_ProtoConstructor) = this->asReturnedValue(); *propertyData(Heap::FunctionObject::Index_Prototype) = proto.asReturnedValue(); } else { @@ -375,7 +375,7 @@ void ScriptFunction::construct(const Managed *that, Scope &scope, CallData *call Scoped f(scope, static_cast(that)); - InternalClass *ic = v4->emptyClass; + InternalClass *ic = v4->internalClasses[EngineBase::Class_Object]; ScopedObject proto(scope, f->protoForConstructor()); ScopedObject obj(scope, v4->newObject(ic, proto)); callData->thisObject = obj.asReturnedValue(); diff --git a/src/qml/jsruntime/qv4functionobject_p.h b/src/qml/jsruntime/qv4functionobject_p.h index f4ac37219c..bfaa1ae056 100644 --- a/src/qml/jsruntime/qv4functionobject_p.h +++ b/src/qml/jsruntime/qv4functionobject_p.h @@ -134,7 +134,7 @@ struct Q_QML_EXPORT FunctionObject: Object { }; V4_OBJECT2(FunctionObject, Object) Q_MANAGED_TYPE(FunctionObject) - V4_INTERNALCLASS(functionClass) + V4_INTERNALCLASS(FunctionObject) V4_PROTOTYPE(functionPrototype) V4_NEEDS_DESTROY @@ -236,7 +236,7 @@ void Heap::IndexedBuiltinFunction::init(QV4::ExecutionContext *scope, uint index struct ScriptFunction : FunctionObject { V4_OBJECT2(ScriptFunction, FunctionObject) - V4_INTERNALCLASS(scriptFunctionClass) + V4_INTERNALCLASS(ScriptFunction) static void construct(const Managed *, Scope &scope, CallData *callData); static void call(const Managed *that, Scope &scope, CallData *callData); diff --git a/src/qml/jsruntime/qv4internalclass.cpp b/src/qml/jsruntime/qv4internalclass.cpp index 7e3fd7dc12..162de0b9f7 100644 --- a/src/qml/jsruntime/qv4internalclass.cpp +++ b/src/qml/jsruntime/qv4internalclass.cpp @@ -220,7 +220,7 @@ InternalClass *InternalClass::changeMember(Identifier *identifier, PropertyAttri return t.lookup; // create a new class and add it to the tree - InternalClass *newClass = engine->emptyClass; + InternalClass *newClass = engine->internalClasses[EngineBase::Class_Empty]; for (uint i = 0; i < size; ++i) { if (i == idx) { newClass = newClass->addMember(nameMap.at(i), data); @@ -332,7 +332,7 @@ void InternalClass::removeMember(Object *object, Identifier *id) object->setInternalClass(t.lookup); } else { // create a new class and add it to the tree - InternalClass *newClass = oldClass->engine->emptyClass; + InternalClass *newClass = oldClass->engine->internalClasses[EngineBase::Class_Empty]; for (uint i = 0; i < oldClass->size; ++i) { if (i == propIdx) continue; @@ -365,7 +365,7 @@ InternalClass *InternalClass::sealed() if (m_sealed) return m_sealed; - m_sealed = engine->emptyClass; + m_sealed = engine->internalClasses[EngineBase::Class_Empty]; for (uint i = 0; i < size; ++i) { PropertyAttributes attrs = propertyData.at(i); if (attrs.isEmpty()) @@ -394,7 +394,7 @@ InternalClass *InternalClass::frozen() InternalClass *InternalClass::propertiesFrozen() const { - InternalClass *frozen = engine->emptyClass; + InternalClass *frozen = engine->internalClasses[EngineBase::Class_Empty]; for (uint i = 0; i < size; ++i) { PropertyAttributes attrs = propertyData.at(i); if (attrs.isEmpty()) diff --git a/src/qml/jsruntime/qv4object_p.h b/src/qml/jsruntime/qv4object_p.h index 45392c0486..80bfbe941a 100644 --- a/src/qml/jsruntime/qv4object_p.h +++ b/src/qml/jsruntime/qv4object_p.h @@ -138,8 +138,8 @@ struct Object : Base { V4_ASSERT_IS_TRIVIAL(QV4::Heap::DataClass); #define V4_INTERNALCLASS(c) \ - static QV4::InternalClass *defaultInternalClass(QV4::ExecutionEngine *e) \ - { return e->c; } + static QV4::InternalClass *defaultInternalClass(QV4::EngineBase *e) \ +{ return e->internalClasses[QV4::EngineBase::Class_##c]; } #define V4_PROTOTYPE(p) \ static QV4::Object *defaultPrototype(QV4::ExecutionEngine *e) \ { return e->p(); } @@ -198,7 +198,7 @@ QT_WARNING_SUPPRESS_GCC_TAUTOLOGICAL_COMPARE_OFF struct Q_QML_EXPORT Object: Managed { V4_OBJECT2(Object, Object) Q_MANAGED_TYPE(Object) - V4_INTERNALCLASS(emptyClass) + V4_INTERNALCLASS(Object) V4_PROTOTYPE(objectPrototype) enum { @@ -472,7 +472,7 @@ struct NumberObject: Object { struct ArrayObject: Object { V4_OBJECT2(ArrayObject, Object) Q_MANAGED_TYPE(ArrayObject) - V4_INTERNALCLASS(arrayClass) + V4_INTERNALCLASS(ArrayObject) V4_PROTOTYPE(arrayPrototype) void init(ExecutionEngine *engine); diff --git a/src/qml/jsruntime/qv4regexpobject.cpp b/src/qml/jsruntime/qv4regexpobject.cpp index 0894d0c25b..1f758e36f6 100644 --- a/src/qml/jsruntime/qv4regexpobject.cpp +++ b/src/qml/jsruntime/qv4regexpobject.cpp @@ -379,7 +379,7 @@ void RegExpPrototype::method_exec(const BuiltinFunction *, Scope &scope, CallDat } // fill in result data - ScopedArrayObject array(scope, scope.engine->newArrayObject(scope.engine->regExpExecArrayClass, scope.engine->arrayPrototype())); + ScopedArrayObject array(scope, scope.engine->newArrayObject(scope.engine->internalClasses[EngineBase::Class_RegExpExecArray], scope.engine->arrayPrototype())); int len = r->value()->captureCount(); array->arrayReserve(len); ScopedValue v(scope); diff --git a/src/qml/jsruntime/qv4regexpobject_p.h b/src/qml/jsruntime/qv4regexpobject_p.h index c0c7dfa78a..54731cef14 100644 --- a/src/qml/jsruntime/qv4regexpobject_p.h +++ b/src/qml/jsruntime/qv4regexpobject_p.h @@ -96,7 +96,7 @@ struct RegExpCtor : FunctionObject { struct RegExpObject: Object { V4_OBJECT2(RegExpObject, Object) Q_MANAGED_TYPE(RegExpObject) - V4_INTERNALCLASS(regExpObjectClass) + V4_INTERNALCLASS(RegExpObject) V4_PROTOTYPE(regExpPrototype) // needs to be compatible with the flags in qv4jsir_p.h diff --git a/src/qml/jsruntime/qv4runtime.cpp b/src/qml/jsruntime/qv4runtime.cpp index 4b440f5335..a79eab3778 100644 --- a/src/qml/jsruntime/qv4runtime.cpp +++ b/src/qml/jsruntime/qv4runtime.cpp @@ -1408,7 +1408,7 @@ QV4::ReturnedValue Runtime::method_setupArgumentsObject(ExecutionEngine *engine) { Q_ASSERT(engine->current->type == Heap::ExecutionContext::Type_CallContext); QV4::CallContext *c = static_cast(engine->currentContext); - QV4::InternalClass *ic = c->d()->strictMode ? engine->strictArgumentsObjectClass : engine->argumentsObjectClass; + QV4::InternalClass *ic = engine->internalClasses[c->d()->strictMode ? EngineBase::Class_StrictArgumentsObject : EngineBase::Class_ArgumentsObject]; return engine->memoryManager->allocObject(ic, engine->objectPrototype(), c)->asReturnedValue(); } diff --git a/src/qml/jsruntime/qv4stringobject_p.h b/src/qml/jsruntime/qv4stringobject_p.h index 0ee7a6ece9..b8fb80546f 100644 --- a/src/qml/jsruntime/qv4stringobject_p.h +++ b/src/qml/jsruntime/qv4stringobject_p.h @@ -82,7 +82,7 @@ struct StringCtor : FunctionObject { struct StringObject: Object { V4_OBJECT2(StringObject, Object) Q_MANAGED_TYPE(StringObject) - V4_INTERNALCLASS(stringClass) + V4_INTERNALCLASS(StringObject) V4_PROTOTYPE(stringPrototype) Heap::String *getIndex(uint index) const { diff --git a/src/qml/jsruntime/qv4typedarray.cpp b/src/qml/jsruntime/qv4typedarray.cpp index cecd1e6958..542460ee81 100644 --- a/src/qml/jsruntime/qv4typedarray.cpp +++ b/src/qml/jsruntime/qv4typedarray.cpp @@ -372,7 +372,7 @@ void Heap::TypedArray::init(Type t) Heap::TypedArray *TypedArray::create(ExecutionEngine *e, Heap::TypedArray::Type t) { - return e->memoryManager->allocObject(e->emptyClass, e->typedArrayPrototype + t, t); + return e->memoryManager->allocObject(e->internalClasses[EngineBase::Class_Object], e->typedArrayPrototype + t, t); } void TypedArray::markObjects(Heap::Base *that, ExecutionEngine *e) -- cgit v1.2.3 From 70a49fe042dd244926cc4a9cb6affb8b4f3d9b7f Mon Sep 17 00:00:00 2001 From: Lars Knoll Date: Fri, 12 May 2017 10:29:23 +0200 Subject: Add ICs for String, MemberData and ArrayData Change-Id: I43ddcb4842e501cbea8a950ab6ffa2d906014efd Reviewed-by: Simon Hausmann --- src/qml/jsruntime/qv4arraydata_p.h | 2 ++ src/qml/jsruntime/qv4engine.cpp | 4 ++++ src/qml/jsruntime/qv4enginebase_p.h | 4 ++++ src/qml/jsruntime/qv4managed_p.h | 5 +++++ src/qml/jsruntime/qv4memberdata_p.h | 1 + src/qml/jsruntime/qv4object_p.h | 3 --- src/qml/jsruntime/qv4string_p.h | 2 ++ 7 files changed, 18 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/src/qml/jsruntime/qv4arraydata_p.h b/src/qml/jsruntime/qv4arraydata_p.h index 24b948f01e..daf8c36814 100644 --- a/src/qml/jsruntime/qv4arraydata_p.h +++ b/src/qml/jsruntime/qv4arraydata_p.h @@ -236,6 +236,7 @@ struct Q_QML_EXPORT ArrayData : public Managed struct Q_QML_EXPORT SimpleArrayData : public ArrayData { V4_ARRAYDATA(SimpleArrayData) + V4_INTERNALCLASS(SimpleArrayData) uint mappedIndex(uint index) const { return d()->mappedIndex(index); } Value data(uint index) const { return d()->data(index); } @@ -262,6 +263,7 @@ struct Q_QML_EXPORT SimpleArrayData : public ArrayData struct Q_QML_EXPORT SparseArrayData : public ArrayData { V4_ARRAYDATA(SparseArrayData) + V4_INTERNALCLASS(SparseArrayData) V4_NEEDS_DESTROY ReturnedValue &freeList() { return d()->freeList; } diff --git a/src/qml/jsruntime/qv4engine.cpp b/src/qml/jsruntime/qv4engine.cpp index c7b87f209a..982db33092 100644 --- a/src/qml/jsruntime/qv4engine.cpp +++ b/src/qml/jsruntime/qv4engine.cpp @@ -215,6 +215,10 @@ ExecutionEngine::ExecutionEngine(EvalISelFactory *factory) internalClasses[Class_Empty] = new (classPool) InternalClass(this); internalClasses[Class_Object] = internalClasses[Class_Empty]; + internalClasses[Class_String] = internalClasses[EngineBase::Class_Empty]->changeVTable(QV4::String::staticVTable()); + internalClasses[Class_MemberData] = internalClasses[EngineBase::Class_Empty]->changeVTable(QV4::MemberData::staticVTable()); + internalClasses[Class_SimpleArrayData] = internalClasses[EngineBase::Class_Empty]->changeVTable(QV4::SimpleArrayData::staticVTable()); + internalClasses[Class_SparseArrayData] = internalClasses[EngineBase::Class_Empty]->changeVTable(QV4::SparseArrayData::staticVTable()); jsStrings[String_Empty] = newIdentifier(QString()); jsStrings[String_undefined] = newIdentifier(QStringLiteral("undefined")); diff --git a/src/qml/jsruntime/qv4enginebase_p.h b/src/qml/jsruntime/qv4enginebase_p.h index efcd7b16d9..783ddc5bd3 100644 --- a/src/qml/jsruntime/qv4enginebase_p.h +++ b/src/qml/jsruntime/qv4enginebase_p.h @@ -83,6 +83,10 @@ struct EngineBase { enum { Class_Empty, + Class_String, + Class_MemberData, + Class_SimpleArrayData, + Class_SparseArrayData, Class_Object, Class_ArrayObject, Class_FunctionObject, diff --git a/src/qml/jsruntime/qv4managed_p.h b/src/qml/jsruntime/qv4managed_p.h index 7e674c6ec7..00bfad78dd 100644 --- a/src/qml/jsruntime/qv4managed_p.h +++ b/src/qml/jsruntime/qv4managed_p.h @@ -52,6 +52,7 @@ #include "qv4global_p.h" #include "qv4value_p.h" +#include "qv4enginebase_p.h" #include QT_BEGIN_NAMESPACE @@ -151,6 +152,10 @@ QT_WARNING_SUPPRESS_GCC_TAUTOLOGICAL_COMPARE_ON \ const QV4::VTable classname::static_vtbl = DEFINE_MANAGED_VTABLE_INT(classname, 0) \ QT_WARNING_SUPPRESS_GCC_TAUTOLOGICAL_COMPARE_OFF +#define V4_INTERNALCLASS(c) \ + static QV4::InternalClass *defaultInternalClass(QV4::EngineBase *e) \ + { return e->internalClasses[QV4::EngineBase::Class_##c]; } + struct Q_QML_PRIVATE_EXPORT Managed : Value { V4_MANAGED_ITSELF(Base, Managed) diff --git a/src/qml/jsruntime/qv4memberdata_p.h b/src/qml/jsruntime/qv4memberdata_p.h index 5c89dfe8ec..e239458849 100644 --- a/src/qml/jsruntime/qv4memberdata_p.h +++ b/src/qml/jsruntime/qv4memberdata_p.h @@ -73,6 +73,7 @@ V4_ASSERT_IS_TRIVIAL(MemberData) struct MemberData : Managed { V4_MANAGED(MemberData, Managed) + V4_INTERNALCLASS(MemberData) Value &operator[] (uint idx) { return d()->data[idx]; } const Value *data() const { return d()->data; } diff --git a/src/qml/jsruntime/qv4object_p.h b/src/qml/jsruntime/qv4object_p.h index 80bfbe941a..e1b2a40b94 100644 --- a/src/qml/jsruntime/qv4object_p.h +++ b/src/qml/jsruntime/qv4object_p.h @@ -137,9 +137,6 @@ struct Object : Base { } \ V4_ASSERT_IS_TRIVIAL(QV4::Heap::DataClass); -#define V4_INTERNALCLASS(c) \ - static QV4::InternalClass *defaultInternalClass(QV4::EngineBase *e) \ -{ return e->internalClasses[QV4::EngineBase::Class_##c]; } #define V4_PROTOTYPE(p) \ static QV4::Object *defaultPrototype(QV4::ExecutionEngine *e) \ { return e->p(); } diff --git a/src/qml/jsruntime/qv4string_p.h b/src/qml/jsruntime/qv4string_p.h index 5b0fd292d6..bf8c48ceee 100644 --- a/src/qml/jsruntime/qv4string_p.h +++ b/src/qml/jsruntime/qv4string_p.h @@ -53,6 +53,7 @@ #include #include "qv4managed_p.h" #include +#include "qv4enginebase_p.h" QT_BEGIN_NAMESPACE @@ -71,6 +72,7 @@ struct Q_QML_PRIVATE_EXPORT String : Base { }; #ifndef V4_BOOTSTRAP + V4_INTERNALCLASS(String) void init(MemoryManager *mm, const QString &text); void init(MemoryManager *mm, String *l, String *n); void destroy(); -- cgit v1.2.3 From cdbc4b83d59e08189d6ece9ccd88a646be155c08 Mon Sep 17 00:00:00 2001 From: Lars Knoll Date: Fri, 12 May 2017 15:01:07 +0200 Subject: Properly encapsulate all accesses to the vtable Change-Id: I3f6ae59d01c7b6c898e98d3b6f65b84a19b8851a Reviewed-by: Simon Hausmann --- src/qml/jsruntime/qv4internalclass.cpp | 4 ++-- src/qml/jsruntime/qv4lookup.cpp | 4 ++-- src/qml/jsruntime/qv4object.cpp | 6 +++--- src/qml/jsruntime/qv4object_p.h | 16 ++++++++-------- 4 files changed, 15 insertions(+), 15 deletions(-) (limited to 'src') diff --git a/src/qml/jsruntime/qv4internalclass.cpp b/src/qml/jsruntime/qv4internalclass.cpp index 162de0b9f7..f310b6f551 100644 --- a/src/qml/jsruntime/qv4internalclass.cpp +++ b/src/qml/jsruntime/qv4internalclass.cpp @@ -129,7 +129,7 @@ InternalClass::InternalClass(const QV4::InternalClass &other) static void insertHoleIntoPropertyData(Object *object, int idx) { - int inlineSize = object->d()->vt->nInlineProperties; + int inlineSize = object->d()->vtable()->nInlineProperties; int icSize = object->internalClass()->size; int from = qMax(idx, inlineSize); int to = from + 1; @@ -151,7 +151,7 @@ static void insertHoleIntoPropertyData(Object *object, int idx) static void removeFromPropertyData(Object *object, int idx, bool accessor = false) { - int inlineSize = object->d()->vt->nInlineProperties; + int inlineSize = object->d()->vtable()->nInlineProperties; int delta = (accessor ? 2 : 1); int oldSize = object->internalClass()->size + delta; int to = idx; diff --git a/src/qml/jsruntime/qv4lookup.cpp b/src/qml/jsruntime/qv4lookup.cpp index 0d467098fe..f8ac0cb650 100644 --- a/src/qml/jsruntime/qv4lookup.cpp +++ b/src/qml/jsruntime/qv4lookup.cpp @@ -287,7 +287,7 @@ ReturnedValue Lookup::getterGeneric(Lookup *l, ExecutionEngine *engine, const Va l->proto = proto->d(); if (attrs.isData()) { if (l->level == 0) { - uint nInline = l->proto->vt->nInlineProperties; + uint nInline = l->proto->vtable()->nInlineProperties; if (l->index < nInline) l->getter = Lookup::primitiveGetter0Inline; else { @@ -696,7 +696,7 @@ ReturnedValue Lookup::globalGetterGeneric(Lookup *l, ExecutionEngine *engine) if (v != Primitive::emptyValue().asReturnedValue()) { if (attrs.isData()) { if (l->level == 0) { - uint nInline = o->d()->vt->nInlineProperties; + uint nInline = o->d()->vtable()->nInlineProperties; if (l->index < nInline) l->globalGetter = globalGetter0Inline; else { diff --git a/src/qml/jsruntime/qv4object.cpp b/src/qml/jsruntime/qv4object.cpp index 3d8e8f3ddf..f5dafa7914 100644 --- a/src/qml/jsruntime/qv4object.cpp +++ b/src/qml/jsruntime/qv4object.cpp @@ -266,7 +266,7 @@ void Object::markObjects(Heap::Base *that, ExecutionEngine *e) if (o->prototype) o->prototype->mark(e); uint nInline = o->vtable()->nInlineProperties; - Value *v = reinterpret_cast(o) + o->vt->inlinePropertyOffset; + Value *v = reinterpret_cast(o) + o->vtable()->inlinePropertyOffset; const Value *end = v + nInline; while (v < end) { v->mark(e); @@ -507,7 +507,7 @@ ReturnedValue Object::getLookup(const Managed *m, Lookup *l) if (v != Primitive::emptyValue().asReturnedValue()) { if (attrs.isData()) { if (l->level == 0) { - uint nInline = o->d()->vt->nInlineProperties; + uint nInline = o->d()->vtable()->nInlineProperties; if (l->index < nInline) l->getter = Lookup::getter0Inline; else { @@ -549,7 +549,7 @@ void Object::setLookup(Managed *m, Lookup *l, const Value &value) if (idx != UINT_MAX && o->internalClass()->propertyData[idx].isData() && o->internalClass()->propertyData[idx].isWritable()) { l->classList[0] = o->internalClass(); l->index = idx; - l->setter = idx < o->d()->vt->nInlineProperties ? Lookup::setter0Inline : Lookup::setter0; + l->setter = idx < o->d()->vtable()->nInlineProperties ? Lookup::setter0Inline : Lookup::setter0; *o->propertyData(idx) = value; return; } diff --git a/src/qml/jsruntime/qv4object_p.h b/src/qml/jsruntime/qv4object_p.h index e1b2a40b94..78ee263c80 100644 --- a/src/qml/jsruntime/qv4object_p.h +++ b/src/qml/jsruntime/qv4object_p.h @@ -72,25 +72,25 @@ struct Object : Base { void destroy() { Base::destroy(); } const Value *inlinePropertyData(uint index) const { - Q_ASSERT(index < vt->nInlineProperties); - return reinterpret_cast(this) + vt->inlinePropertyOffset + index; + Q_ASSERT(index < vtable()->nInlineProperties); + return reinterpret_cast(this) + vtable()->inlinePropertyOffset + index; } Value *inlinePropertyData(uint index) { - Q_ASSERT(index < vt->nInlineProperties); - return reinterpret_cast(this) + vt->inlinePropertyOffset + index; + Q_ASSERT(index < vtable()->nInlineProperties); + return reinterpret_cast(this) + vtable()->inlinePropertyOffset + index; } const Value *propertyData(uint index) const { - uint nInline = vt->nInlineProperties; + uint nInline = vtable()->nInlineProperties; if (index < nInline) - return reinterpret_cast(this) + vt->inlinePropertyOffset + index; + return reinterpret_cast(this) + vtable()->inlinePropertyOffset + index; index -= nInline; return memberData->data + index; } Value *propertyData(uint index) { - uint nInline = vt->nInlineProperties; + uint nInline = vtable()->nInlineProperties; if (index < nInline) - return reinterpret_cast(this) + vt->inlinePropertyOffset + index; + return reinterpret_cast(this) + vtable()->inlinePropertyOffset + index; index -= nInline; return memberData->data + index; } -- cgit v1.2.3 From 0cdea188727e203ecc529ef8e4e8859cca0be232 Mon Sep 17 00:00:00 2001 From: Lars Knoll Date: Fri, 12 May 2017 15:04:53 +0200 Subject: Add support for storing the Vtable in the InternalClass Prepare for moving the vtable pointer into the internalClass. This adds the required infrastructure to InternalClass, so it can store a vtable pointer and properly handles vtable changes. Change-Id: I688fee1647268dd185d0f9636ab5b3390465daca Reviewed-by: Simon Hausmann --- src/qml/jsruntime/qv4internalclass.cpp | 52 ++++++++++++++++++++++++++++------ src/qml/jsruntime/qv4internalclass_p.h | 32 ++++++++++----------- 2 files changed, 59 insertions(+), 25 deletions(-) (limited to 'src') diff --git a/src/qml/jsruntime/qv4internalclass.cpp b/src/qml/jsruntime/qv4internalclass.cpp index f310b6f551..e117da1a04 100644 --- a/src/qml/jsruntime/qv4internalclass.cpp +++ b/src/qml/jsruntime/qv4internalclass.cpp @@ -105,6 +105,7 @@ void PropertyHash::addEntry(const PropertyHash::Entry &entry, int classSize) InternalClass::InternalClass(ExecutionEngine *engine) : engine(engine) + , vtable(0) , m_sealed(0) , m_frozen(0) , size(0) @@ -116,6 +117,7 @@ InternalClass::InternalClass(ExecutionEngine *engine) InternalClass::InternalClass(const QV4::InternalClass &other) : QQmlJS::Managed() , engine(other.engine) + , vtable(other.vtable) , propertyTable(other.propertyTable) , nameMap(other.nameMap) , propertyData(other.propertyData) @@ -214,13 +216,13 @@ InternalClass *InternalClass::changeMember(Identifier *identifier, PropertyAttri if (data == propertyData.at(idx)) return this; - Transition temp = { identifier, 0, (int)data.flags() }; + Transition temp = { { identifier }, nullptr, (int)data.flags() }; Transition &t = lookupOrInsertTransition(temp); if (t.lookup) return t.lookup; // create a new class and add it to the tree - InternalClass *newClass = engine->internalClasses[EngineBase::Class_Empty]; + InternalClass *newClass = engine->internalClasses[EngineBase::Class_Empty]->changeVTable(vtable); for (uint i = 0; i < size; ++i) { if (i == idx) { newClass = newClass->addMember(nameMap.at(i), data); @@ -234,12 +236,34 @@ InternalClass *InternalClass::changeMember(Identifier *identifier, PropertyAttri return newClass; } +InternalClass *InternalClass::changeVTableImpl(const VTable *vt) +{ + Q_ASSERT(vtable != vt); + + Transition temp = { { nullptr }, nullptr, Transition::VTableChange }; + temp.vtable = vt; + + Transition &t = lookupOrInsertTransition(temp); + if (t.lookup) + return t.lookup; + + // create a new class and add it to the tree + InternalClass *newClass; + newClass = engine->newClass(*this); + newClass->vtable = vt; + + t.lookup = newClass; + Q_ASSERT(t.lookup); + Q_ASSERT(newClass->vtable); + return newClass; +} + InternalClass *InternalClass::nonExtensible() { if (!extensible) return this; - Transition temp = { Q_NULLPTR, Q_NULLPTR, Transition::NotExtensible}; + Transition temp = { { nullptr }, nullptr, Transition::NotExtensible}; Transition &t = lookupOrInsertTransition(temp); if (t.lookup) return t.lookup; @@ -287,7 +311,7 @@ InternalClass *InternalClass::addMember(Identifier *identifier, PropertyAttribut InternalClass *InternalClass::addMemberImpl(Identifier *identifier, PropertyAttributes data, uint *index) { - Transition temp = { identifier, 0, (int)data.flags() }; + Transition temp = { { identifier }, nullptr, (int)data.flags() }; Transition &t = lookupOrInsertTransition(temp); if (index) @@ -323,7 +347,7 @@ void InternalClass::removeMember(Object *object, Identifier *id) uint propIdx = oldClass->propertyTable.lookup(id); Q_ASSERT(propIdx < oldClass->size); - Transition temp = { id, 0, -1 }; + Transition temp = { { id }, nullptr, -1 }; Transition &t = object->internalClass()->lookupOrInsertTransition(temp); bool accessor = oldClass->propertyData.at(propIdx).isAccessor(); @@ -332,7 +356,7 @@ void InternalClass::removeMember(Object *object, Identifier *id) object->setInternalClass(t.lookup); } else { // create a new class and add it to the tree - InternalClass *newClass = oldClass->engine->internalClasses[EngineBase::Class_Empty]; + InternalClass *newClass = oldClass->engine->internalClasses[EngineBase::Class_Empty]->changeVTable(oldClass->vtable); for (uint i = 0; i < oldClass->size; ++i) { if (i == propIdx) continue; @@ -351,6 +375,18 @@ void InternalClass::removeMember(Object *object, Identifier *id) Q_ASSERT(t.lookup); } +uint QV4::InternalClass::find(const String *string) +{ + engine->identifierTable->identifier(string); + const Identifier *id = string->d()->identifier; + + uint index = propertyTable.lookup(id); + if (index < size) + return index; + + return UINT_MAX; +} + uint InternalClass::find(const Identifier *id) { uint index = propertyTable.lookup(id); @@ -365,7 +401,7 @@ InternalClass *InternalClass::sealed() if (m_sealed) return m_sealed; - m_sealed = engine->internalClasses[EngineBase::Class_Empty]; + m_sealed = engine->internalClasses[EngineBase::Class_Empty]->changeVTable(vtable); for (uint i = 0; i < size; ++i) { PropertyAttributes attrs = propertyData.at(i); if (attrs.isEmpty()) @@ -394,7 +430,7 @@ InternalClass *InternalClass::frozen() InternalClass *InternalClass::propertiesFrozen() const { - InternalClass *frozen = engine->internalClasses[EngineBase::Class_Empty]; + InternalClass *frozen = engine->internalClasses[EngineBase::Class_Empty]->changeVTable(vtable); for (uint i = 0; i < size; ++i) { PropertyAttributes attrs = propertyData.at(i); if (attrs.isEmpty()) diff --git a/src/qml/jsruntime/qv4internalclass_p.h b/src/qml/jsruntime/qv4internalclass_p.h index 1d8ef4b0fb..c68a6638e7 100644 --- a/src/qml/jsruntime/qv4internalclass_p.h +++ b/src/qml/jsruntime/qv4internalclass_p.h @@ -54,15 +54,13 @@ #include #include -#include -#include +#include QT_BEGIN_NAMESPACE namespace QV4 { struct String; -struct ExecutionEngine; struct Object; struct Identifier; struct VTable; @@ -222,12 +220,16 @@ private: struct InternalClassTransition { - Identifier *id; + union { + Identifier *id; + const VTable *vtable; + }; InternalClass *lookup; int flags; enum { // range 0-0xff is reserved for attribute changes - NotExtensible = 0x100 + NotExtensible = 0x100, + VTableChange = 0x200, }; bool operator==(const InternalClassTransition &other) const @@ -239,6 +241,7 @@ struct InternalClassTransition struct InternalClass : public QQmlJS::Managed { ExecutionEngine *engine; + const VTable *vtable; PropertyHash propertyTable; // id to valueIndex SharedInternalClassData nameMap; @@ -255,6 +258,12 @@ struct InternalClass : public QQmlJS::Managed { bool extensible; InternalClass *nonExtensible(); + InternalClass *changeVTable(const VTable *vt) { + if (vtable == vt) + return this; + return changeVTableImpl(vt); + } + static void addMember(Object *object, String *string, PropertyAttributes data, uint *index); InternalClass *addMember(String *string, PropertyAttributes data, uint *index = 0); InternalClass *addMember(Identifier *identifier, PropertyAttributes data, uint *index = 0); @@ -271,24 +280,13 @@ struct InternalClass : public QQmlJS::Managed { void destroy(); private: + InternalClass *changeVTableImpl(const VTable *vt); InternalClass *addMemberImpl(Identifier *identifier, PropertyAttributes data, uint *index); friend struct ExecutionEngine; InternalClass(ExecutionEngine *engine); InternalClass(const InternalClass &other); }; -inline uint InternalClass::find(const String *string) -{ - engine->identifierTable->identifier(string); - const Identifier *id = string->d()->identifier; - - uint index = propertyTable.lookup(id); - if (index < size) - return index; - - return UINT_MAX; -} - struct InternalClassPool : public QQmlJS::MemoryPool { void markObjects(ExecutionEngine *engine); -- cgit v1.2.3 From cae7975a036352ca4bbcf1381a445362f8e01367 Mon Sep 17 00:00:00 2001 From: Lars Knoll Date: Fri, 12 May 2017 15:12:45 +0200 Subject: Move the internalClass field from Heap::Object to Heap::Base And do not store the vtable in Heap::Base anymore. This change makes the internal class the main distinguishing feature of all garbage collected objects. It also saves one pointer on all Objects. No measurable impact on runtime performance. Change-Id: I040a28b7581b993f1886b5219e279173dfa567e8 Reviewed-by: Simon Hausmann --- src/qml/jsruntime/qv4booleanobject_p.h | 1 + src/qml/jsruntime/qv4context_p.h | 1 + src/qml/jsruntime/qv4dateobject_p.h | 2 ++ src/qml/jsruntime/qv4engine.cpp | 40 +++++++++++++++++++++------------ src/qml/jsruntime/qv4enginebase_p.h | 4 +++- src/qml/jsruntime/qv4errorobject.cpp | 2 -- src/qml/jsruntime/qv4errorobject_p.h | 4 +++- src/qml/jsruntime/qv4internalclass.cpp | 13 +++++++++-- src/qml/jsruntime/qv4internalclass_p.h | 2 +- src/qml/jsruntime/qv4managed_p.h | 2 ++ src/qml/jsruntime/qv4numberobject_p.h | 1 + src/qml/jsruntime/qv4object.cpp | 1 + src/qml/jsruntime/qv4object_p.h | 2 -- src/qml/jsruntime/qv4qmlcontext.cpp | 2 ++ src/qml/jsruntime/qv4qobjectwrapper.cpp | 1 - src/qml/jsruntime/qv4regexp_p.h | 1 + src/qml/jsruntime/qv4sequenceobject_p.h | 1 + src/qml/jsruntime/qv4string_p.h | 2 +- src/qml/jsruntime/qv4typedarray.cpp | 3 ++- src/qml/jsruntime/qv4typedarray_p.h | 1 + src/qml/jsruntime/qv4variantobject_p.h | 1 + src/qml/memory/qv4heap_p.h | 10 +++++---- src/qml/memory/qv4mm.cpp | 3 ++- src/qml/memory/qv4mm_p.h | 17 +++++++++----- 24 files changed, 81 insertions(+), 36 deletions(-) (limited to 'src') diff --git a/src/qml/jsruntime/qv4booleanobject_p.h b/src/qml/jsruntime/qv4booleanobject_p.h index 9c8b1d67f1..ca2cf7d17a 100644 --- a/src/qml/jsruntime/qv4booleanobject_p.h +++ b/src/qml/jsruntime/qv4booleanobject_p.h @@ -76,6 +76,7 @@ struct BooleanCtor: FunctionObject struct BooleanPrototype: BooleanObject { + V4_PROTOTYPE(objectPrototype) void init(ExecutionEngine *engine, Object *ctor); static void method_toString(const BuiltinFunction *, Scope &scope, CallData *callData); diff --git a/src/qml/jsruntime/qv4context_p.h b/src/qml/jsruntime/qv4context_p.h index c769dcd142..c742df7b97 100644 --- a/src/qml/jsruntime/qv4context_p.h +++ b/src/qml/jsruntime/qv4context_p.h @@ -228,6 +228,7 @@ struct Q_QML_EXPORT ExecutionContext : public Managed V4_MANAGED(ExecutionContext, Managed) Q_MANAGED_TYPE(ExecutionContext) + V4_INTERNALCLASS(ExecutionContext) ExecutionEngine *engine() const { return d()->engine; } diff --git a/src/qml/jsruntime/qv4dateobject_p.h b/src/qml/jsruntime/qv4dateobject_p.h index a56d17f9b1..ecd57bcd8d 100644 --- a/src/qml/jsruntime/qv4dateobject_p.h +++ b/src/qml/jsruntime/qv4dateobject_p.h @@ -114,6 +114,8 @@ struct DateCtor: FunctionObject struct DatePrototype: DateObject { + V4_PROTOTYPE(objectPrototype) + void init(ExecutionEngine *engine, Object *ctor); static double getThisDate(Scope &scope, CallData *callData); diff --git a/src/qml/jsruntime/qv4engine.cpp b/src/qml/jsruntime/qv4engine.cpp index 982db33092..6b05d9a05c 100644 --- a/src/qml/jsruntime/qv4engine.cpp +++ b/src/qml/jsruntime/qv4engine.cpp @@ -213,12 +213,12 @@ ExecutionEngine::ExecutionEngine(EvalISelFactory *factory) classPool = new InternalClassPool; internalClasses[Class_Empty] = new (classPool) InternalClass(this); - internalClasses[Class_Object] = internalClasses[Class_Empty]; - + internalClasses[Class_Object] = internalClasses[Class_Empty]->changeVTable(QV4::Object::staticVTable()); internalClasses[Class_String] = internalClasses[EngineBase::Class_Empty]->changeVTable(QV4::String::staticVTable()); internalClasses[Class_MemberData] = internalClasses[EngineBase::Class_Empty]->changeVTable(QV4::MemberData::staticVTable()); internalClasses[Class_SimpleArrayData] = internalClasses[EngineBase::Class_Empty]->changeVTable(QV4::SimpleArrayData::staticVTable()); internalClasses[Class_SparseArrayData] = internalClasses[EngineBase::Class_Empty]->changeVTable(QV4::SparseArrayData::staticVTable()); + internalClasses[Class_ExecutionContext] = internalClasses[EngineBase::Class_Empty]->changeVTable(QV4::ExecutionContext::staticVTable()); jsStrings[String_Empty] = newIdentifier(QString()); jsStrings[String_undefined] = newIdentifier(QStringLiteral("undefined")); @@ -259,11 +259,13 @@ ExecutionEngine::ExecutionEngine(EvalISelFactory *factory) jsObjects[ObjectProto] = memoryManager->allocObject(internalClasses[Class_Object]); - internalClasses[Class_ArrayObject] = internalClasses[Class_Object]->addMember(id_length(), Attr_NotConfigurable|Attr_NotEnumerable); + internalClasses[Class_ArrayObject] = internalClasses[Class_Empty]->changeVTable(QV4::ArrayObject::staticVTable()); + internalClasses[Class_ArrayObject] = internalClasses[Class_ArrayObject]->addMember(id_length(), Attr_NotConfigurable|Attr_NotEnumerable); jsObjects[ArrayProto] = memoryManager->allocObject(internalClasses[Class_ArrayObject], objectPrototype()); jsObjects[PropertyListProto] = memoryManager->allocObject(); - InternalClass *argsClass = internalClasses[Class_Object]->addMember(id_length(), Attr_NotEnumerable); + InternalClass *argsClass = internalClasses[Class_Empty]->changeVTable(QV4::ArgumentsObject::staticVTable()) + ->addMember(id_length(), Attr_NotEnumerable); internalClasses[EngineBase::Class_ArgumentsObject] = argsClass->addMember(id_callee(), Attr_Data|Attr_NotEnumerable); argsClass = argsClass->addMember(id_callee(), Attr_Accessor|Attr_NotConfigurable|Attr_NotEnumerable); internalClasses[EngineBase::Class_StrictArgumentsObject] = argsClass->addMember(id_caller(), Attr_Accessor|Attr_NotConfigurable|Attr_NotEnumerable); @@ -272,15 +274,18 @@ ExecutionEngine::ExecutionEngine(EvalISelFactory *factory) Q_ASSERT(globalObject->d()->vtable()); initRootContext(); - internalClasses[EngineBase::Class_StringObject] = internalClasses[Class_Object]->addMember(id_length(), Attr_ReadOnly); + internalClasses[Class_StringObject] = internalClasses[Class_Empty]->changeVTable(QV4::StringObject::staticVTable()); + internalClasses[EngineBase::Class_StringObject] = internalClasses[Class_StringObject]->addMember(id_length(), Attr_ReadOnly); Q_ASSERT(internalClasses[EngineBase::Class_StringObject]->find(id_length()) == Heap::StringObject::LengthPropertyIndex); jsObjects[StringProto] = memoryManager->allocObject(internalClasses[EngineBase::Class_StringObject], objectPrototype()); - jsObjects[NumberProto] = memoryManager->allocObject(internalClasses[Class_Object], objectPrototype()); - jsObjects[BooleanProto] = memoryManager->allocObject(internalClasses[Class_Object], objectPrototype()); - jsObjects[DateProto] = memoryManager->allocObject(internalClasses[Class_Object], objectPrototype()); + jsObjects[NumberProto] = memoryManager->allocObject(); + jsObjects[BooleanProto] = memoryManager->allocObject(); + jsObjects[DateProto] = memoryManager->allocObject(); uint index; - InternalClass *functionProtoClass = internalClasses[Class_Object]->addMember(id_prototype(), Attr_NotEnumerable, &index); + InternalClass *functionProtoClass = + internalClasses[Class_Empty]->changeVTable(QV4::FunctionPrototype::staticVTable()) + ->addMember(id_prototype(), Attr_NotEnumerable, &index); Q_ASSERT(index == Heap::FunctionObject::Index_Prototype); jsObjects[FunctionProto] = memoryManager->allocObject(functionProtoClass, objectPrototype()); internalClasses[EngineBase::Class_FunctionObject] = internalClasses[Class_Object]->addMember(id_prototype(), Attr_NotEnumerable|Attr_NotConfigurable, &index); @@ -294,7 +299,10 @@ ExecutionEngine::ExecutionEngine(EvalISelFactory *factory) Scope scope(this); ScopedString str(scope); - internalClasses[EngineBase::Class_RegExpObject] = internalClasses[Class_Object]->addMember(id_lastIndex(), Attr_NotEnumerable|Attr_NotConfigurable, &index); + internalClasses[Class_RegExp] = internalClasses[EngineBase::Class_Empty]->changeVTable(QV4::RegExp::staticVTable()); + internalClasses[EngineBase::Class_RegExpObject] = + internalClasses[Class_Empty]->changeVTable(QV4::RegExpObject::staticVTable()) + ->addMember(id_lastIndex(), Attr_NotEnumerable|Attr_NotConfigurable, &index); Q_ASSERT(index == RegExpObject::Index_LastIndex); internalClasses[EngineBase::Class_RegExpObject] = internalClasses[EngineBase::Class_RegExpObject]->addMember((str = newIdentifier(QStringLiteral("source"))), Attr_ReadOnly, &index); Q_ASSERT(index == RegExpObject::Index_Source); @@ -311,7 +319,9 @@ ExecutionEngine::ExecutionEngine(EvalISelFactory *factory) internalClasses[EngineBase::Class_RegExpExecArray] = internalClasses[EngineBase::Class_RegExpExecArray]->addMember(id_input(), Attr_Data, &index); Q_ASSERT(index == RegExpObject::Index_ArrayInput); - internalClasses[EngineBase::Class_ErrorObject] = internalClasses[Class_Object]->addMember((str = newIdentifier(QStringLiteral("stack"))), Attr_Accessor|Attr_NotConfigurable|Attr_NotEnumerable, &index); + internalClasses[EngineBase::Class_ErrorObject] = + internalClasses[Class_Empty]->changeVTable(QV4::ErrorObject::staticVTable()) + ->addMember((str = newIdentifier(QStringLiteral("stack"))), Attr_Accessor|Attr_NotConfigurable|Attr_NotEnumerable, &index); Q_ASSERT(index == ErrorObject::Index_Stack); internalClasses[EngineBase::Class_ErrorObject] = internalClasses[EngineBase::Class_ErrorObject]->addMember((str = newIdentifier(QStringLiteral("fileName"))), Attr_Data|Attr_NotEnumerable, &index); Q_ASSERT(index == ErrorObject::Index_FileName); @@ -319,7 +329,9 @@ ExecutionEngine::ExecutionEngine(EvalISelFactory *factory) Q_ASSERT(index == ErrorObject::Index_LineNumber); internalClasses[EngineBase::Class_ErrorObjectWithMessage] = internalClasses[EngineBase::Class_ErrorObject]->addMember((str = newIdentifier(QStringLiteral("message"))), Attr_Data|Attr_NotEnumerable, &index); Q_ASSERT(index == ErrorObject::Index_Message); - internalClasses[EngineBase::Class_ErrorProto] = internalClasses[Class_Object]->addMember(id_constructor(), Attr_Data|Attr_NotEnumerable, &index); + internalClasses[EngineBase::Class_ErrorProto] = + internalClasses[Class_Empty]->changeVTable(QV4::ErrorPrototype::staticVTable()) + ->addMember(id_constructor(), Attr_Data|Attr_NotEnumerable, &index); Q_ASSERT(index == ErrorPrototype::Index_Constructor); internalClasses[EngineBase::Class_ErrorProto] = internalClasses[EngineBase::Class_ErrorProto]->addMember((str = newIdentifier(QStringLiteral("message"))), Attr_Data|Attr_NotEnumerable, &index); Q_ASSERT(index == ErrorPrototype::Index_Message); @@ -337,10 +349,10 @@ ExecutionEngine::ExecutionEngine(EvalISelFactory *factory) jsObjects[TypeErrorProto] = memoryManager->allocObject(internalClasses[EngineBase::Class_ErrorProto], errorPrototype()); jsObjects[URIErrorProto] = memoryManager->allocObject(internalClasses[EngineBase::Class_ErrorProto], errorPrototype()); - jsObjects[VariantProto] = memoryManager->allocObject(internalClasses[Class_Object], objectPrototype()); + jsObjects[VariantProto] = memoryManager->allocObject(); Q_ASSERT(variantPrototype()->prototype() == objectPrototype()->d()); - jsObjects[SequenceProto] = ScopedValue(scope, memoryManager->allocObject(internalClasses[Class_ArrayObject], arrayPrototype())); + jsObjects[SequenceProto] = ScopedValue(scope, memoryManager->allocObject()); ExecutionContext *global = rootContext(); jsObjects[Object_Ctor] = memoryManager->allocObject(global); diff --git a/src/qml/jsruntime/qv4enginebase_p.h b/src/qml/jsruntime/qv4enginebase_p.h index 783ddc5bd3..e124adb810 100644 --- a/src/qml/jsruntime/qv4enginebase_p.h +++ b/src/qml/jsruntime/qv4enginebase_p.h @@ -87,14 +87,16 @@ struct EngineBase { Class_MemberData, Class_SimpleArrayData, Class_SparseArrayData, + Class_ExecutionContext, Class_Object, Class_ArrayObject, Class_FunctionObject, Class_StringObject, Class_ScriptFunction, Class_ObjectProto, - Class_RegExpExecArray, + Class_RegExp, Class_RegExpObject, + Class_RegExpExecArray, Class_ArgumentsObject, Class_StrictArgumentsObject, Class_ErrorObject, diff --git a/src/qml/jsruntime/qv4errorobject.cpp b/src/qml/jsruntime/qv4errorobject.cpp index 63b778b56d..65507e2251 100644 --- a/src/qml/jsruntime/qv4errorobject.cpp +++ b/src/qml/jsruntime/qv4errorobject.cpp @@ -183,8 +183,6 @@ void ErrorObject::markObjects(Heap::Base *that, ExecutionEngine *e) DEFINE_OBJECT_VTABLE(ErrorObject); -DEFINE_OBJECT_VTABLE(SyntaxErrorObject); - void Heap::SyntaxErrorObject::init(const Value &msg) { Heap::ErrorObject::init(msg, SyntaxError); diff --git a/src/qml/jsruntime/qv4errorobject_p.h b/src/qml/jsruntime/qv4errorobject_p.h index 896b54da5e..34e4b4a682 100644 --- a/src/qml/jsruntime/qv4errorobject_p.h +++ b/src/qml/jsruntime/qv4errorobject_p.h @@ -203,8 +203,10 @@ struct ReferenceErrorObject: ErrorObject { }; struct SyntaxErrorObject: ErrorObject { - V4_OBJECT2(SyntaxErrorObject, ErrorObject) + typedef Heap::SyntaxErrorObject Data; V4_PROTOTYPE(syntaxErrorPrototype) + const Data *d() const { return static_cast(ErrorObject::d()); } + Data *d() { return static_cast(ErrorObject::d()); } }; struct TypeErrorObject: ErrorObject { diff --git a/src/qml/jsruntime/qv4internalclass.cpp b/src/qml/jsruntime/qv4internalclass.cpp index e117da1a04..9a4087485f 100644 --- a/src/qml/jsruntime/qv4internalclass.cpp +++ b/src/qml/jsruntime/qv4internalclass.cpp @@ -249,8 +249,17 @@ InternalClass *InternalClass::changeVTableImpl(const VTable *vt) // create a new class and add it to the tree InternalClass *newClass; - newClass = engine->newClass(*this); - newClass->vtable = vt; + if (this == engine->internalClasses[EngineBase::Class_Empty]) { + newClass = engine->newClass(*this); + newClass->vtable = vt; + } else { + newClass = engine->internalClasses[EngineBase::Class_Empty]->changeVTable(vt); + newClass = newClass->changePrototype(prototype); + for (uint i = 0; i < size; ++i) { + if (!propertyData.at(i).isEmpty()) + newClass = newClass->addMember(nameMap.at(i), propertyData.at(i)); + } + } t.lookup = newClass; Q_ASSERT(t.lookup); diff --git a/src/qml/jsruntime/qv4internalclass_p.h b/src/qml/jsruntime/qv4internalclass_p.h index c68a6638e7..3c4e0838d9 100644 --- a/src/qml/jsruntime/qv4internalclass_p.h +++ b/src/qml/jsruntime/qv4internalclass_p.h @@ -280,7 +280,7 @@ struct InternalClass : public QQmlJS::Managed { void destroy(); private: - InternalClass *changeVTableImpl(const VTable *vt); + Q_QML_EXPORT InternalClass *changeVTableImpl(const VTable *vt); InternalClass *addMemberImpl(Identifier *identifier, PropertyAttributes data, uint *index); friend struct ExecutionEngine; InternalClass(ExecutionEngine *engine); diff --git a/src/qml/jsruntime/qv4managed_p.h b/src/qml/jsruntime/qv4managed_p.h index 00bfad78dd..814755efe9 100644 --- a/src/qml/jsruntime/qv4managed_p.h +++ b/src/qml/jsruntime/qv4managed_p.h @@ -198,6 +198,8 @@ public: }; Q_MANAGED_TYPE(Invalid) + InternalClass *internalClass() const { return d()->internalClass; } + bool isListType() const { return d()->vtable()->type == Type_QmlSequence; } bool isArrayObject() const { return d()->vtable()->type == Type_ArrayObject; } diff --git a/src/qml/jsruntime/qv4numberobject_p.h b/src/qml/jsruntime/qv4numberobject_p.h index 364b866a16..85d306020c 100644 --- a/src/qml/jsruntime/qv4numberobject_p.h +++ b/src/qml/jsruntime/qv4numberobject_p.h @@ -85,6 +85,7 @@ struct NumberCtor: FunctionObject struct NumberPrototype: NumberObject { + V4_PROTOTYPE(objectPrototype) void init(ExecutionEngine *engine, Object *ctor); static void method_isFinite(const BuiltinFunction *, Scope &scope, CallData *callData); diff --git a/src/qml/jsruntime/qv4object.cpp b/src/qml/jsruntime/qv4object.cpp index f5dafa7914..838ae96c59 100644 --- a/src/qml/jsruntime/qv4object.cpp +++ b/src/qml/jsruntime/qv4object.cpp @@ -61,6 +61,7 @@ DEFINE_OBJECT_VTABLE(Object); void Object::setInternalClass(InternalClass *ic) { d()->internalClass = ic; + Q_ASSERT(ic && ic->vtable); uint nInline = d()->vtable()->nInlineProperties; if (ic->size <= nInline) return; diff --git a/src/qml/jsruntime/qv4object_p.h b/src/qml/jsruntime/qv4object_p.h index 78ee263c80..951659a4bc 100644 --- a/src/qml/jsruntime/qv4object_p.h +++ b/src/qml/jsruntime/qv4object_p.h @@ -95,7 +95,6 @@ struct Object : Base { return memberData->data + index; } - InternalClass *internalClass; Pointer prototype; Pointer memberData; Pointer arrayData; @@ -204,7 +203,6 @@ struct Q_QML_EXPORT Object: Managed { SetterOffset = 1 }; - InternalClass *internalClass() const { return d()->internalClass; } void setInternalClass(InternalClass *ic); const Value *propertyData(uint index) const { return d()->propertyData(index); } diff --git a/src/qml/jsruntime/qv4qmlcontext.cpp b/src/qml/jsruntime/qv4qmlcontext.cpp index 889f4ea288..ef1a1c11ed 100644 --- a/src/qml/jsruntime/qv4qmlcontext.cpp +++ b/src/qml/jsruntime/qv4qmlcontext.cpp @@ -331,6 +331,7 @@ Heap::QmlContext *QmlContext::createWorkerContext(ExecutionContext *parent, cons qml->setReadOnly(true); Heap::QmlContext *c = parent->d()->engine->memoryManager->alloc(parent, qml); + Q_ASSERT(c->vtable() == staticVTable()); return c; } @@ -340,6 +341,7 @@ Heap::QmlContext *QmlContext::create(ExecutionContext *parent, QQmlContextData * Scoped qml(scope, scope.engine->memoryManager->allocObject(context, scopeObject)); Heap::QmlContext *c = parent->d()->engine->memoryManager->alloc(parent, qml); + Q_ASSERT(c->vtable() == staticVTable()); return c; } diff --git a/src/qml/jsruntime/qv4qobjectwrapper.cpp b/src/qml/jsruntime/qv4qobjectwrapper.cpp index 67b1356e65..f484d56040 100644 --- a/src/qml/jsruntime/qv4qobjectwrapper.cpp +++ b/src/qml/jsruntime/qv4qobjectwrapper.cpp @@ -997,7 +997,6 @@ void QObjectWrapper::destroyObject(bool lastCall) } } - h->internalClass = 0; h->~Data(); } diff --git a/src/qml/jsruntime/qv4regexp_p.h b/src/qml/jsruntime/qv4regexp_p.h index d3e63375a5..04cdb468bf 100644 --- a/src/qml/jsruntime/qv4regexp_p.h +++ b/src/qml/jsruntime/qv4regexp_p.h @@ -100,6 +100,7 @@ struct RegExp : public Managed V4_MANAGED(RegExp, Managed) Q_MANAGED_TYPE(RegExp) V4_NEEDS_DESTROY + V4_INTERNALCLASS(RegExp) QString pattern() const { return *d()->pattern; } JSC::Yarr::BytecodePattern *byteCode() { return d()->byteCode; } diff --git a/src/qml/jsruntime/qv4sequenceobject_p.h b/src/qml/jsruntime/qv4sequenceobject_p.h index 6f96b9f760..0879f149fa 100644 --- a/src/qml/jsruntime/qv4sequenceobject_p.h +++ b/src/qml/jsruntime/qv4sequenceobject_p.h @@ -65,6 +65,7 @@ namespace QV4 { struct SequencePrototype : public QV4::Object { + V4_PROTOTYPE(arrayPrototype) void init(); static void method_valueOf(const BuiltinFunction *, Scope &scope, CallData *callData) diff --git a/src/qml/jsruntime/qv4string_p.h b/src/qml/jsruntime/qv4string_p.h index bf8c48ceee..ad30165ce5 100644 --- a/src/qml/jsruntime/qv4string_p.h +++ b/src/qml/jsruntime/qv4string_p.h @@ -72,7 +72,6 @@ struct Q_QML_PRIVATE_EXPORT String : Base { }; #ifndef V4_BOOTSTRAP - V4_INTERNALCLASS(String) void init(MemoryManager *mm, const QString &text); void init(MemoryManager *mm, String *l, String *n); void destroy(); @@ -140,6 +139,7 @@ struct Q_QML_PRIVATE_EXPORT String : public Managed { #ifndef V4_BOOTSTRAP V4_MANAGED(String, Managed) Q_MANAGED_TYPE(String) + V4_INTERNALCLASS(String) V4_NEEDS_DESTROY enum { IsString = true diff --git a/src/qml/jsruntime/qv4typedarray.cpp b/src/qml/jsruntime/qv4typedarray.cpp index 542460ee81..bb28a7683c 100644 --- a/src/qml/jsruntime/qv4typedarray.cpp +++ b/src/qml/jsruntime/qv4typedarray.cpp @@ -372,7 +372,8 @@ void Heap::TypedArray::init(Type t) Heap::TypedArray *TypedArray::create(ExecutionEngine *e, Heap::TypedArray::Type t) { - return e->memoryManager->allocObject(e->internalClasses[EngineBase::Class_Object], e->typedArrayPrototype + t, t); + QV4::InternalClass *ic = e->internalClasses[EngineBase::Class_Empty]->changeVTable(staticVTable()); + return e->memoryManager->allocObject(ic, e->typedArrayPrototype + t, t); } void TypedArray::markObjects(Heap::Base *that, ExecutionEngine *e) diff --git a/src/qml/jsruntime/qv4typedarray_p.h b/src/qml/jsruntime/qv4typedarray_p.h index eefed2db4b..a6a74e4b9b 100644 --- a/src/qml/jsruntime/qv4typedarray_p.h +++ b/src/qml/jsruntime/qv4typedarray_p.h @@ -148,6 +148,7 @@ struct TypedArrayCtor: FunctionObject struct TypedArrayPrototype : Object { V4_OBJECT2(TypedArrayPrototype, Object) + V4_PROTOTYPE(objectPrototype) void init(ExecutionEngine *engine, TypedArrayCtor *ctor); diff --git a/src/qml/jsruntime/qv4variantobject_p.h b/src/qml/jsruntime/qv4variantobject_p.h index ef51b6632d..dba14b13fb 100644 --- a/src/qml/jsruntime/qv4variantobject_p.h +++ b/src/qml/jsruntime/qv4variantobject_p.h @@ -105,6 +105,7 @@ struct VariantObject : Object struct VariantPrototype : VariantObject { public: + V4_PROTOTYPE(objectPrototype) void init(); static void method_preserve(const BuiltinFunction *, Scope &scope, CallData *callData); diff --git a/src/qml/memory/qv4heap_p.h b/src/qml/memory/qv4heap_p.h index cd0a6d9a81..a4e96b4c84 100644 --- a/src/qml/memory/qv4heap_p.h +++ b/src/qml/memory/qv4heap_p.h @@ -53,6 +53,7 @@ #include #include #include +#include #include // To check if Heap::Base::init is called (meaning, all subclasses did their init and called their @@ -69,6 +70,8 @@ QT_BEGIN_NAMESPACE namespace QV4 { +struct InternalClass; + struct VTable { const VTable * const parent; @@ -93,13 +96,12 @@ namespace Heap { struct Q_QML_EXPORT Base { void *operator new(size_t) = delete; - const VTable *vt; + InternalClass *internalClass; inline ReturnedValue asReturnedValue() const; inline void mark(QV4::ExecutionEngine *engine); - void setVtable(const VTable *v) { vt = v; } - const VTable *vtable() const { return vt; } + const VTable *vtable() const { return internalClass->vtable; } inline bool isMarked() const { const HeapItem *h = reinterpret_cast(this); Chunk *c = h->chunk(); @@ -166,7 +168,7 @@ V4_ASSERT_IS_TRIVIAL(Base) // for a size/offset translation when cross-compiling between 32- and // 64-bit. Q_STATIC_ASSERT(std::is_standard_layout::value); -Q_STATIC_ASSERT(offsetof(Base, vt) == 0); +Q_STATIC_ASSERT(offsetof(Base, internalClass) == 0); Q_STATIC_ASSERT(sizeof(Base) == QT_POINTER_SIZE); template diff --git a/src/qml/memory/qv4mm.cpp b/src/qml/memory/qv4mm.cpp index ef36e62373..56f1254421 100644 --- a/src/qml/memory/qv4mm.cpp +++ b/src/qml/memory/qv4mm.cpp @@ -787,7 +787,8 @@ Heap::Object *MemoryManager::allocObjectWithMemberData(const QV4::VTable *vtable m = *blockAllocator.allocate(memberSize, true); memset(m, 0, memberSize); o->memberData = static_cast(m); - o->memberData->setVtable(MemberData::staticVTable()); + o->memberData->internalClass = engine->internalClasses[EngineBase::Class_MemberData]; + Q_ASSERT(o->memberData->internalClass); o->memberData->size = static_cast((memberSize - sizeof(Heap::MemberData) + sizeof(Value))/sizeof(Value)); o->memberData->init(); // qDebug() << " got" << o->memberData << o->memberData->size; diff --git a/src/qml/memory/qv4mm_p.h b/src/qml/memory/qv4mm_p.h index 9b4c2cd8df..8f12fa7cbd 100644 --- a/src/qml/memory/qv4mm_p.h +++ b/src/qml/memory/qv4mm_p.h @@ -210,7 +210,8 @@ public: { Heap::CallContext *ctxt = stackAllocator.allocate(); memset(ctxt, 0, sizeof(Heap::CallContext)); - ctxt->setVtable(QV4::CallContext::staticVTable()); + ctxt->internalClass = CallContext::defaultInternalClass(engine); + Q_ASSERT(ctxt->internalClass && ctxt->internalClass->vtable); ctxt->init(v4); return ctxt; @@ -224,7 +225,10 @@ public: V4_ASSERT_IS_TRIVIAL(typename ManagedType::Data) size = align(size); Heap::Base *o = allocData(size); - o->setVtable(ManagedType::staticVTable()); + InternalClass *ic = ManagedType::defaultInternalClass(engine); + ic = ic->changeVTable(ManagedType::staticVTable()); + o->internalClass = ic; + Q_ASSERT(o->internalClass && o->internalClass->vtable); return static_cast(o); } @@ -232,8 +236,9 @@ public: typename ObjectType::Data *allocateObject(InternalClass *ic) { Heap::Object *o = allocObjectWithMemberData(ObjectType::staticVTable(), ic->size); - o->setVtable(ObjectType::staticVTable()); o->internalClass = ic; + Q_ASSERT(o->internalClass && o->internalClass->vtable); + Q_ASSERT(ic->vtable == ObjectType::staticVTable()); return static_cast(o); } @@ -241,10 +246,11 @@ public: typename ObjectType::Data *allocateObject() { InternalClass *ic = ObjectType::defaultInternalClass(engine); + ic = ic->changeVTable(ObjectType::staticVTable()); Heap::Object *o = allocObjectWithMemberData(ObjectType::staticVTable(), ic->size); - o->setVtable(ObjectType::staticVTable()); Object *prototype = ObjectType::defaultPrototype(engine); o->internalClass = ic; + Q_ASSERT(o->internalClass && o->internalClass->vtable); o->prototype = prototype->d(); return static_cast(o); } @@ -253,7 +259,8 @@ public: typename ManagedType::Data *allocWithStringData(std::size_t unmanagedSize, Arg1 arg1) { typename ManagedType::Data *o = reinterpret_cast(allocString(unmanagedSize)); - o->setVtable(ManagedType::staticVTable()); + o->internalClass = ManagedType::defaultInternalClass(engine); + Q_ASSERT(o->internalClass && o->internalClass->vtable); o->init(this, arg1); return o; } -- cgit v1.2.3 From afbb57ae84ecbee5fab9eb6e58356b19d7995ea5 Mon Sep 17 00:00:00 2001 From: Lars Knoll Date: Mon, 15 May 2017 09:56:05 +0200 Subject: Move the prototype into the internal class This saves another pointer on all Objects. Currently introduces a slight performance regression on some of the v8 benchmarks, that needs addressing. Change-Id: I87de8e1d198d2683f4e903c467ce2a60ba542243 Reviewed-by: Simon Hausmann --- src/qml/jsruntime/qv4context_p.h | 1 + src/qml/jsruntime/qv4engine.cpp | 106 ++++++++++++++++++-------------- src/qml/jsruntime/qv4engine_p.h | 2 + src/qml/jsruntime/qv4enginebase_p.h | 2 + src/qml/jsruntime/qv4errorobject.cpp | 3 +- src/qml/jsruntime/qv4errorobject_p.h | 18 +++--- src/qml/jsruntime/qv4functionobject.cpp | 17 +++-- src/qml/jsruntime/qv4functionobject_p.h | 5 +- src/qml/jsruntime/qv4internalclass.cpp | 53 +++++++++++++++- src/qml/jsruntime/qv4internalclass_p.h | 26 +++++--- src/qml/jsruntime/qv4lookup.cpp | 60 +++++++++--------- src/qml/jsruntime/qv4object.cpp | 15 +++-- src/qml/jsruntime/qv4object_p.h | 4 +- src/qml/jsruntime/qv4stringobject_p.h | 1 + src/qml/jsruntime/qv4typedarray.cpp | 1 + src/qml/memory/qv4mm_p.h | 19 +++--- 16 files changed, 215 insertions(+), 118 deletions(-) (limited to 'src') diff --git a/src/qml/jsruntime/qv4context_p.h b/src/qml/jsruntime/qv4context_p.h index c742df7b97..89ff6dc957 100644 --- a/src/qml/jsruntime/qv4context_p.h +++ b/src/qml/jsruntime/qv4context_p.h @@ -272,6 +272,7 @@ struct Q_QML_EXPORT ExecutionContext : public Managed struct Q_QML_EXPORT CallContext : public ExecutionContext { V4_MANAGED(CallContext, ExecutionContext) + V4_INTERNALCLASS(CallContext) // formals are in reverse order Identifier * const *formals() const; diff --git a/src/qml/jsruntime/qv4engine.cpp b/src/qml/jsruntime/qv4engine.cpp index 6b05d9a05c..daab7ad279 100644 --- a/src/qml/jsruntime/qv4engine.cpp +++ b/src/qml/jsruntime/qv4engine.cpp @@ -213,12 +213,12 @@ ExecutionEngine::ExecutionEngine(EvalISelFactory *factory) classPool = new InternalClassPool; internalClasses[Class_Empty] = new (classPool) InternalClass(this); - internalClasses[Class_Object] = internalClasses[Class_Empty]->changeVTable(QV4::Object::staticVTable()); internalClasses[Class_String] = internalClasses[EngineBase::Class_Empty]->changeVTable(QV4::String::staticVTable()); internalClasses[Class_MemberData] = internalClasses[EngineBase::Class_Empty]->changeVTable(QV4::MemberData::staticVTable()); internalClasses[Class_SimpleArrayData] = internalClasses[EngineBase::Class_Empty]->changeVTable(QV4::SimpleArrayData::staticVTable()); internalClasses[Class_SparseArrayData] = internalClasses[EngineBase::Class_Empty]->changeVTable(QV4::SparseArrayData::staticVTable()); internalClasses[Class_ExecutionContext] = internalClasses[EngineBase::Class_Empty]->changeVTable(QV4::ExecutionContext::staticVTable()); + internalClasses[Class_CallContext] = internalClasses[EngineBase::Class_Empty]->changeVTable(QV4::CallContext::staticVTable()); jsStrings[String_Empty] = newIdentifier(QString()); jsStrings[String_undefined] = newIdentifier(QStringLiteral("undefined")); @@ -257,15 +257,20 @@ ExecutionEngine::ExecutionEngine(EvalISelFactory *factory) jsStrings[String_buffer] = newIdentifier(QStringLiteral("buffer")); jsStrings[String_lastIndex] = newIdentifier(QStringLiteral("lastIndex")); - jsObjects[ObjectProto] = memoryManager->allocObject(internalClasses[Class_Object]); + InternalClass *ic = internalClasses[Class_Empty]->changeVTable(QV4::Object::staticVTable()); + jsObjects[ObjectProto] = memoryManager->allocObject(ic); + internalClasses[Class_Object] = ic->changePrototype(objectPrototype()->d()); - internalClasses[Class_ArrayObject] = internalClasses[Class_Empty]->changeVTable(QV4::ArrayObject::staticVTable()); - internalClasses[Class_ArrayObject] = internalClasses[Class_ArrayObject]->addMember(id_length(), Attr_NotConfigurable|Attr_NotEnumerable); - jsObjects[ArrayProto] = memoryManager->allocObject(internalClasses[Class_ArrayObject], objectPrototype()); + ic = newInternalClass(ArrayPrototype::staticVTable(), objectPrototype()); + Q_ASSERT(ic->prototype); + ic = ic->addMember(id_length(), Attr_NotConfigurable|Attr_NotEnumerable); + Q_ASSERT(ic->prototype); + jsObjects[ArrayProto] = memoryManager->allocObject(ic, objectPrototype()); + internalClasses[Class_ArrayObject] = ic->changePrototype(arrayPrototype()->d()); jsObjects[PropertyListProto] = memoryManager->allocObject(); - InternalClass *argsClass = internalClasses[Class_Empty]->changeVTable(QV4::ArgumentsObject::staticVTable()) - ->addMember(id_length(), Attr_NotEnumerable); + InternalClass *argsClass = newInternalClass(ArgumentsObject::staticVTable(), objectPrototype()); + argsClass = argsClass->addMember(id_length(), Attr_NotEnumerable); internalClasses[EngineBase::Class_ArgumentsObject] = argsClass->addMember(id_callee(), Attr_Data|Attr_NotEnumerable); argsClass = argsClass->addMember(id_callee(), Attr_Accessor|Attr_NotConfigurable|Attr_NotEnumerable); internalClasses[EngineBase::Class_StrictArgumentsObject] = argsClass->addMember(id_caller(), Attr_Accessor|Attr_NotConfigurable|Attr_NotEnumerable); @@ -274,25 +279,31 @@ ExecutionEngine::ExecutionEngine(EvalISelFactory *factory) Q_ASSERT(globalObject->d()->vtable()); initRootContext(); - internalClasses[Class_StringObject] = internalClasses[Class_Empty]->changeVTable(QV4::StringObject::staticVTable()); - internalClasses[EngineBase::Class_StringObject] = internalClasses[Class_StringObject]->addMember(id_length(), Attr_ReadOnly); + ic = newInternalClass(QV4::StringObject::staticVTable(), objectPrototype()); + ic = ic->addMember(id_length(), Attr_ReadOnly); + jsObjects[StringProto] = memoryManager->allocObject(ic); + internalClasses[Class_StringObject] = ic->changePrototype(stringPrototype()->d()); Q_ASSERT(internalClasses[EngineBase::Class_StringObject]->find(id_length()) == Heap::StringObject::LengthPropertyIndex); - jsObjects[StringProto] = memoryManager->allocObject(internalClasses[EngineBase::Class_StringObject], objectPrototype()); + jsObjects[NumberProto] = memoryManager->allocObject(); jsObjects[BooleanProto] = memoryManager->allocObject(); jsObjects[DateProto] = memoryManager->allocObject(); uint index; - InternalClass *functionProtoClass = - internalClasses[Class_Empty]->changeVTable(QV4::FunctionPrototype::staticVTable()) - ->addMember(id_prototype(), Attr_NotEnumerable, &index); + ic = newInternalClass(QV4::FunctionPrototype::staticVTable(), objectPrototype()); + ic = ic->addMember(id_prototype(), Attr_NotEnumerable, &index); Q_ASSERT(index == Heap::FunctionObject::Index_Prototype); - jsObjects[FunctionProto] = memoryManager->allocObject(functionProtoClass, objectPrototype()); - internalClasses[EngineBase::Class_FunctionObject] = internalClasses[Class_Object]->addMember(id_prototype(), Attr_NotEnumerable|Attr_NotConfigurable, &index); + jsObjects[FunctionProto] = memoryManager->allocObject(ic, objectPrototype()); + ic = newInternalClass(FunctionObject::staticVTable(), functionPrototype()); + ic = ic->addMember(id_prototype(), Attr_NotEnumerable|Attr_NotConfigurable, &index); Q_ASSERT(index == Heap::FunctionObject::Index_Prototype); - internalClasses[EngineBase::Class_ScriptFunction] = internalClasses[EngineBase::Class_FunctionObject]->addMember(id_name(), Attr_ReadOnly, &index); + internalClasses[EngineBase::Class_FunctionObject] = ic; + ic = ic->addMember(id_name(), Attr_ReadOnly, &index); Q_ASSERT(index == Heap::ScriptFunction::Index_Name); - internalClasses[EngineBase::Class_ScriptFunction] = internalClasses[EngineBase::Class_ScriptFunction]->addMember(id_length(), Attr_ReadOnly, &index); + ic = ic->changeVTable(ScriptFunction::staticVTable()); + internalClasses[EngineBase::Class_ScriptFunction] = ic->addMember(id_length(), Attr_ReadOnly, &index); + Q_ASSERT(index == Heap::ScriptFunction::Index_Length); + internalClasses[EngineBase::Class_BuiltinFunction] = ic->changeVTable(BuiltinFunction::staticVTable()); Q_ASSERT(index == Heap::ScriptFunction::Index_Length); internalClasses[EngineBase::Class_ObjectProto] = internalClasses[Class_Object]->addMember(id_constructor(), Attr_NotEnumerable, &index); Q_ASSERT(index == Heap::FunctionObject::Index_ProtoConstructor); @@ -300,59 +311,59 @@ ExecutionEngine::ExecutionEngine(EvalISelFactory *factory) Scope scope(this); ScopedString str(scope); internalClasses[Class_RegExp] = internalClasses[EngineBase::Class_Empty]->changeVTable(QV4::RegExp::staticVTable()); - internalClasses[EngineBase::Class_RegExpObject] = - internalClasses[Class_Empty]->changeVTable(QV4::RegExpObject::staticVTable()) - ->addMember(id_lastIndex(), Attr_NotEnumerable|Attr_NotConfigurable, &index); + ic = newInternalClass(QV4::RegExpObject::staticVTable(), objectPrototype()); + ic = ic->addMember(id_lastIndex(), Attr_NotEnumerable|Attr_NotConfigurable, &index); Q_ASSERT(index == RegExpObject::Index_LastIndex); - internalClasses[EngineBase::Class_RegExpObject] = internalClasses[EngineBase::Class_RegExpObject]->addMember((str = newIdentifier(QStringLiteral("source"))), Attr_ReadOnly, &index); + ic = ic->addMember((str = newIdentifier(QStringLiteral("source"))), Attr_ReadOnly, &index); Q_ASSERT(index == RegExpObject::Index_Source); - internalClasses[EngineBase::Class_RegExpObject] = internalClasses[EngineBase::Class_RegExpObject]->addMember((str = newIdentifier(QStringLiteral("global"))), Attr_ReadOnly, &index); + ic = ic->addMember((str = newIdentifier(QStringLiteral("global"))), Attr_ReadOnly, &index); Q_ASSERT(index == RegExpObject::Index_Global); - internalClasses[EngineBase::Class_RegExpObject] = internalClasses[EngineBase::Class_RegExpObject]->addMember((str = newIdentifier(QStringLiteral("ignoreCase"))), Attr_ReadOnly, &index); + ic = ic->addMember((str = newIdentifier(QStringLiteral("ignoreCase"))), Attr_ReadOnly, &index); Q_ASSERT(index == RegExpObject::Index_IgnoreCase); - internalClasses[EngineBase::Class_RegExpObject] = internalClasses[EngineBase::Class_RegExpObject]->addMember((str = newIdentifier(QStringLiteral("multiline"))), Attr_ReadOnly, &index); + ic = ic->addMember((str = newIdentifier(QStringLiteral("multiline"))), Attr_ReadOnly, &index); Q_ASSERT(index == RegExpObject::Index_Multiline); + jsObjects[RegExpProto] = memoryManager->allocObject(ic, objectPrototype()); + internalClasses[Class_RegExpObject] = ic->changePrototype(regExpPrototype()->d()); - jsObjects[RegExpProto] = memoryManager->allocObject(internalClasses[EngineBase::Class_RegExpObject], objectPrototype()); - internalClasses[EngineBase::Class_RegExpExecArray] = internalClasses[Class_ArrayObject]->addMember(id_index(), Attr_Data, &index); + ic = internalClasses[Class_ArrayObject]->addMember(id_index(), Attr_Data, &index); Q_ASSERT(index == RegExpObject::Index_ArrayIndex); - internalClasses[EngineBase::Class_RegExpExecArray] = internalClasses[EngineBase::Class_RegExpExecArray]->addMember(id_input(), Attr_Data, &index); + internalClasses[EngineBase::Class_RegExpExecArray] = ic->addMember(id_input(), Attr_Data, &index); Q_ASSERT(index == RegExpObject::Index_ArrayInput); - internalClasses[EngineBase::Class_ErrorObject] = - internalClasses[Class_Empty]->changeVTable(QV4::ErrorObject::staticVTable()) - ->addMember((str = newIdentifier(QStringLiteral("stack"))), Attr_Accessor|Attr_NotConfigurable|Attr_NotEnumerable, &index); + ic = newInternalClass(ErrorObject::staticVTable(), 0); + ic = ic->addMember((str = newIdentifier(QStringLiteral("stack"))), Attr_Accessor|Attr_NotConfigurable|Attr_NotEnumerable, &index); Q_ASSERT(index == ErrorObject::Index_Stack); - internalClasses[EngineBase::Class_ErrorObject] = internalClasses[EngineBase::Class_ErrorObject]->addMember((str = newIdentifier(QStringLiteral("fileName"))), Attr_Data|Attr_NotEnumerable, &index); + ic = ic->addMember((str = newIdentifier(QStringLiteral("fileName"))), Attr_Data|Attr_NotEnumerable, &index); Q_ASSERT(index == ErrorObject::Index_FileName); - internalClasses[EngineBase::Class_ErrorObject] = internalClasses[EngineBase::Class_ErrorObject]->addMember((str = newIdentifier(QStringLiteral("lineNumber"))), Attr_Data|Attr_NotEnumerable, &index); + ic = ic->addMember((str = newIdentifier(QStringLiteral("lineNumber"))), Attr_Data|Attr_NotEnumerable, &index); + internalClasses[EngineBase::Class_ErrorObject] = ic; Q_ASSERT(index == ErrorObject::Index_LineNumber); - internalClasses[EngineBase::Class_ErrorObjectWithMessage] = internalClasses[EngineBase::Class_ErrorObject]->addMember((str = newIdentifier(QStringLiteral("message"))), Attr_Data|Attr_NotEnumerable, &index); + internalClasses[EngineBase::Class_ErrorObjectWithMessage] = ic->addMember((str = newIdentifier(QStringLiteral("message"))), Attr_Data|Attr_NotEnumerable, &index); Q_ASSERT(index == ErrorObject::Index_Message); - internalClasses[EngineBase::Class_ErrorProto] = - internalClasses[Class_Empty]->changeVTable(QV4::ErrorPrototype::staticVTable()) - ->addMember(id_constructor(), Attr_Data|Attr_NotEnumerable, &index); + ic = newInternalClass(ErrorObject::staticVTable(), objectPrototype()); + ic = ic->addMember(id_constructor(), Attr_Data|Attr_NotEnumerable, &index); Q_ASSERT(index == ErrorPrototype::Index_Constructor); - internalClasses[EngineBase::Class_ErrorProto] = internalClasses[EngineBase::Class_ErrorProto]->addMember((str = newIdentifier(QStringLiteral("message"))), Attr_Data|Attr_NotEnumerable, &index); + ic = ic->addMember((str = newIdentifier(QStringLiteral("message"))), Attr_Data|Attr_NotEnumerable, &index); Q_ASSERT(index == ErrorPrototype::Index_Message); - internalClasses[EngineBase::Class_ErrorProto] = internalClasses[EngineBase::Class_ErrorProto]->addMember(id_name(), Attr_Data|Attr_NotEnumerable, &index); + internalClasses[EngineBase::Class_ErrorProto] = ic->addMember(id_name(), Attr_Data|Attr_NotEnumerable, &index); Q_ASSERT(index == ErrorPrototype::Index_Name); jsObjects[GetStack_Function] = BuiltinFunction::create(rootContext(), str = newIdentifier(QStringLiteral("stack")), ErrorObject::method_get_stack); getStackFunction()->defineReadonlyProperty(id_length(), Primitive::fromInt32(0)); jsObjects[ErrorProto] = memoryManager->allocObject(internalClasses[EngineBase::Class_ErrorProto], objectPrototype()); - jsObjects[EvalErrorProto] = memoryManager->allocObject(internalClasses[EngineBase::Class_ErrorProto], errorPrototype()); - jsObjects[RangeErrorProto] = memoryManager->allocObject(internalClasses[EngineBase::Class_ErrorProto], errorPrototype()); - jsObjects[ReferenceErrorProto] = memoryManager->allocObject(internalClasses[EngineBase::Class_ErrorProto], errorPrototype()); - jsObjects[SyntaxErrorProto] = memoryManager->allocObject(internalClasses[EngineBase::Class_ErrorProto], errorPrototype()); - jsObjects[TypeErrorProto] = memoryManager->allocObject(internalClasses[EngineBase::Class_ErrorProto], errorPrototype()); - jsObjects[URIErrorProto] = memoryManager->allocObject(internalClasses[EngineBase::Class_ErrorProto], errorPrototype()); + jsObjects[EvalErrorProto] = memoryManager->allocObject(internalClasses[EngineBase::Class_ErrorProto]->changePrototype(errorPrototype()->d()), errorPrototype()); + jsObjects[RangeErrorProto] = memoryManager->allocObject(internalClasses[EngineBase::Class_ErrorProto]->changePrototype(errorPrototype()->d()), errorPrototype()); + jsObjects[ReferenceErrorProto] = memoryManager->allocObject(internalClasses[EngineBase::Class_ErrorProto]->changePrototype(errorPrototype()->d()), errorPrototype()); + jsObjects[SyntaxErrorProto] = memoryManager->allocObject(internalClasses[EngineBase::Class_ErrorProto]->changePrototype(errorPrototype()->d()), errorPrototype()); + jsObjects[TypeErrorProto] = memoryManager->allocObject(internalClasses[EngineBase::Class_ErrorProto]->changePrototype(errorPrototype()->d()), errorPrototype()); + jsObjects[URIErrorProto] = memoryManager->allocObject(internalClasses[EngineBase::Class_ErrorProto]->changePrototype(errorPrototype()->d()), errorPrototype()); jsObjects[VariantProto] = memoryManager->allocObject(); Q_ASSERT(variantPrototype()->prototype() == objectPrototype()->d()); - jsObjects[SequenceProto] = ScopedValue(scope, memoryManager->allocObject()); + ic = newInternalClass(SequencePrototype::staticVTable(), SequencePrototype::defaultPrototype(this)); + jsObjects[SequenceProto] = ScopedValue(scope, memoryManager->allocObject(ic, SequencePrototype::defaultPrototype(this))); ExecutionContext *global = rootContext(); jsObjects[Object_Ctor] = memoryManager->allocObject(global); @@ -538,6 +549,11 @@ ExecutionContext *ExecutionEngine::pushGlobalContext() return currentContext; } +InternalClass *ExecutionEngine::newInternalClass(const VTable *vtable, Object *prototype) +{ + return internalClasses[EngineBase::Class_Empty]->changeVTable(vtable)->changePrototype(prototype ? prototype->d() : 0); +} + Heap::Object *ExecutionEngine::newObject() { return memoryManager->allocObject(); diff --git a/src/qml/jsruntime/qv4engine_p.h b/src/qml/jsruntime/qv4engine_p.h index 1d07196c28..a569b8ddf9 100644 --- a/src/qml/jsruntime/qv4engine_p.h +++ b/src/qml/jsruntime/qv4engine_p.h @@ -366,6 +366,8 @@ public: void popContext(); ExecutionContext *parentContext(ExecutionContext *context) const; + InternalClass *newInternalClass(const VTable *vtable, Object *prototype); + Heap::Object *newObject(); Heap::Object *newObject(InternalClass *internalClass, Object *prototype); diff --git a/src/qml/jsruntime/qv4enginebase_p.h b/src/qml/jsruntime/qv4enginebase_p.h index e124adb810..06c346b3c0 100644 --- a/src/qml/jsruntime/qv4enginebase_p.h +++ b/src/qml/jsruntime/qv4enginebase_p.h @@ -88,11 +88,13 @@ struct EngineBase { Class_SimpleArrayData, Class_SparseArrayData, Class_ExecutionContext, + Class_CallContext, Class_Object, Class_ArrayObject, Class_FunctionObject, Class_StringObject, Class_ScriptFunction, + Class_BuiltinFunction, Class_ObjectProto, Class_RegExp, Class_RegExpObject, diff --git a/src/qml/jsruntime/qv4errorobject.cpp b/src/qml/jsruntime/qv4errorobject.cpp index 65507e2251..6811438915 100644 --- a/src/qml/jsruntime/qv4errorobject.cpp +++ b/src/qml/jsruntime/qv4errorobject.cpp @@ -328,8 +328,7 @@ void ErrorPrototype::init(ExecutionEngine *engine, Object *ctor, Object *obj, He *obj->propertyData(Index_Constructor) = ctor; *obj->propertyData(Index_Message) = engine->id_empty(); *obj->propertyData(Index_Name) = engine->newString(QString::fromLatin1(ErrorObject::className(t))); - if (t == Heap::ErrorObject::Error) - obj->defineDefaultProperty(engine->id_toString(), method_toString, 0); + obj->defineDefaultProperty(engine->id_toString(), method_toString, 0); } void ErrorPrototype::method_toString(const BuiltinFunction *, Scope &scope, CallData *callData) diff --git a/src/qml/jsruntime/qv4errorobject_p.h b/src/qml/jsruntime/qv4errorobject_p.h index 34e4b4a682..12531c9309 100644 --- a/src/qml/jsruntime/qv4errorobject_p.h +++ b/src/qml/jsruntime/qv4errorobject_p.h @@ -326,25 +326,25 @@ inline SyntaxErrorObject *ErrorObject::asSyntaxError() template Heap::Object *ErrorObject::create(ExecutionEngine *e, const Value &message) { - return e->memoryManager->allocObject( - e->internalClasses[message.isUndefined() ? EngineBase::Class_ErrorObject : EngineBase::Class_ErrorObjectWithMessage], - T::defaultPrototype(e), message); + InternalClass *ic = e->internalClasses[message.isUndefined() ? EngineBase::Class_ErrorObject : EngineBase::Class_ErrorObjectWithMessage]; + ic = ic->changePrototype(T::defaultPrototype(e)->d()); + return e->memoryManager->allocObject(ic, T::defaultPrototype(e), message); } template Heap::Object *ErrorObject::create(ExecutionEngine *e, const QString &message) { Scope scope(e); ScopedValue v(scope, message.isEmpty() ? Encode::undefined() : e->newString(message)->asReturnedValue()); - return e->memoryManager->allocObject( - e->internalClasses[v->isUndefined() ? EngineBase::Class_ErrorObject : EngineBase::Class_ErrorObjectWithMessage], - T::defaultPrototype(e), v); + InternalClass *ic = e->internalClasses[v->isUndefined() ? EngineBase::Class_ErrorObject : EngineBase::Class_ErrorObjectWithMessage]; + ic = ic->changePrototype(T::defaultPrototype(e)->d()); + return e->memoryManager->allocObject(ic, T::defaultPrototype(e), v); } template Heap::Object *ErrorObject::create(ExecutionEngine *e, const QString &message, const QString &filename, int line, int column) { Scope scope(e); ScopedValue v(scope, message.isEmpty() ? Encode::undefined() : e->newString(message)->asReturnedValue()); - return e->memoryManager->allocObject( - e->internalClasses[v->isUndefined() ? EngineBase::Class_ErrorObject : EngineBase::Class_ErrorObjectWithMessage], - T::defaultPrototype(e), v, filename, line, column); + InternalClass *ic = e->internalClasses[v->isUndefined() ? EngineBase::Class_ErrorObject : EngineBase::Class_ErrorObjectWithMessage]; + ic = ic->changePrototype(T::defaultPrototype(e)->d()); + return e->memoryManager->allocObject(ic, T::defaultPrototype(e), v, filename, line, column); } diff --git a/src/qml/jsruntime/qv4functionobject.cpp b/src/qml/jsruntime/qv4functionobject.cpp index 86362fa0cb..4be14c09ba 100644 --- a/src/qml/jsruntime/qv4functionobject.cpp +++ b/src/qml/jsruntime/qv4functionobject.cpp @@ -375,8 +375,8 @@ void ScriptFunction::construct(const Managed *that, Scope &scope, CallData *call Scoped f(scope, static_cast(that)); - InternalClass *ic = v4->internalClasses[EngineBase::Class_Object]; - ScopedObject proto(scope, f->protoForConstructor()); + InternalClass *ic = f->classForConstructor(); + ScopedObject proto(scope, ic->prototype); ScopedObject obj(scope, v4->newObject(ic, proto)); callData->thisObject = obj.asReturnedValue(); @@ -444,12 +444,19 @@ void Heap::ScriptFunction::init(QV4::ExecutionContext *scope, Function *function } } -Heap::Object *ScriptFunction::protoForConstructor() const +InternalClass *ScriptFunction::classForConstructor() const { const Object *o = d()->protoProperty(); + InternalClass *ic = d()->cachedClassForConstructor; + if (ic && ic->prototype == o->d()) + return ic; + + ic = engine()->internalClasses[EngineBase::Class_Object]; if (o) - return o->d(); - return engine()->objectPrototype()->d(); + ic = ic->changePrototype(o->d()); + d()->cachedClassForConstructor = ic; + + return ic; } diff --git a/src/qml/jsruntime/qv4functionobject_p.h b/src/qml/jsruntime/qv4functionobject_p.h index bfaa1ae056..354f6b2e3f 100644 --- a/src/qml/jsruntime/qv4functionobject_p.h +++ b/src/qml/jsruntime/qv4functionobject_p.h @@ -117,6 +117,8 @@ struct ScriptFunction : FunctionObject { Index_Length }; void init(QV4::ExecutionContext *scope, Function *function); + + QV4::InternalClass *cachedClassForConstructor; }; struct BoundFunction : FunctionObject { @@ -199,6 +201,7 @@ struct Q_QML_EXPORT OldBuiltinFunction : FunctionObject { struct Q_QML_EXPORT BuiltinFunction : FunctionObject { V4_OBJECT2(BuiltinFunction, FunctionObject) + V4_INTERNALCLASS(BuiltinFunction) static Heap::OldBuiltinFunction *create(ExecutionContext *scope, String *name, ReturnedValue (*code)(CallContext *)) { @@ -241,7 +244,7 @@ struct ScriptFunction : FunctionObject { static void construct(const Managed *, Scope &scope, CallData *callData); static void call(const Managed *that, Scope &scope, CallData *callData); - Heap::Object *protoForConstructor() const; + InternalClass *classForConstructor() const; }; diff --git a/src/qml/jsruntime/qv4internalclass.cpp b/src/qml/jsruntime/qv4internalclass.cpp index 9a4087485f..600198567a 100644 --- a/src/qml/jsruntime/qv4internalclass.cpp +++ b/src/qml/jsruntime/qv4internalclass.cpp @@ -106,6 +106,7 @@ void PropertyHash::addEntry(const PropertyHash::Entry &entry, int classSize) InternalClass::InternalClass(ExecutionEngine *engine) : engine(engine) , vtable(0) + , prototype(0) , m_sealed(0) , m_frozen(0) , size(0) @@ -118,6 +119,7 @@ InternalClass::InternalClass(const QV4::InternalClass &other) : QQmlJS::Managed() , engine(other.engine) , vtable(other.vtable) + , prototype(other.prototype) , propertyTable(other.propertyTable) , nameMap(other.nameMap) , propertyData(other.propertyData) @@ -223,6 +225,7 @@ InternalClass *InternalClass::changeMember(Identifier *identifier, PropertyAttri // create a new class and add it to the tree InternalClass *newClass = engine->internalClasses[EngineBase::Class_Empty]->changeVTable(vtable); + newClass = newClass->changePrototype(prototype); for (uint i = 0; i < size; ++i) { if (i == idx) { newClass = newClass->addMember(nameMap.at(i), data); @@ -236,6 +239,35 @@ InternalClass *InternalClass::changeMember(Identifier *identifier, PropertyAttri return newClass; } +InternalClass *InternalClass::changePrototypeImpl(Heap::Object *proto) +{ + Q_ASSERT(prototype != proto); + + Transition temp = { { nullptr }, 0, Transition::PrototypeChange }; + temp.prototype = proto; + + Transition &t = lookupOrInsertTransition(temp); + if (t.lookup) + return t.lookup; + + // create a new class and add it to the tree + InternalClass *newClass; + if (!size && !prototype) { + newClass = engine->newClass(*this); + newClass->prototype = proto; + } else { + newClass = engine->internalClasses[EngineBase::Class_Empty]->changeVTable(vtable); + newClass = newClass->changePrototype(proto); + for (uint i = 0; i < size; ++i) { + if (!propertyData.at(i).isEmpty()) + newClass = newClass->addMember(nameMap.at(i), propertyData.at(i)); + } + } + + t.lookup = newClass; + return newClass; +} + InternalClass *InternalClass::changeVTableImpl(const VTable *vt) { Q_ASSERT(vtable != vt); @@ -366,6 +398,7 @@ void InternalClass::removeMember(Object *object, Identifier *id) } else { // create a new class and add it to the tree InternalClass *newClass = oldClass->engine->internalClasses[EngineBase::Class_Empty]->changeVTable(oldClass->vtable); + newClass = newClass->changePrototype(oldClass->prototype); for (uint i = 0; i < oldClass->size; ++i) { if (i == propIdx) continue; @@ -411,6 +444,7 @@ InternalClass *InternalClass::sealed() return m_sealed; m_sealed = engine->internalClasses[EngineBase::Class_Empty]->changeVTable(vtable); + m_sealed = m_sealed->changePrototype(prototype); for (uint i = 0; i < size; ++i) { PropertyAttributes attrs = propertyData.at(i); if (attrs.isEmpty()) @@ -440,6 +474,7 @@ InternalClass *InternalClass::frozen() InternalClass *InternalClass::propertiesFrozen() const { InternalClass *frozen = engine->internalClasses[EngineBase::Class_Empty]->changeVTable(vtable); + frozen = frozen->changePrototype(prototype); for (uint i = 0; i < size; ++i) { PropertyAttributes attrs = propertyData.at(i); if (attrs.isEmpty()) @@ -480,9 +515,25 @@ void InternalClass::destroy() } } +void InternalClass::mark(ExecutionEngine *e) +{ + if (m_sealed) + m_sealed->mark(e); + if (m_frozen) + m_frozen->mark(e); + + for (size_t i = 0; i < transitions.size(); ++i) { + Q_ASSERT(transitions.at(i).lookup); + transitions.at(i).lookup->mark(e); + } + if (prototype) + prototype->mark(engine); +} + void InternalClassPool::markObjects(ExecutionEngine *engine) { - Q_UNUSED(engine); + InternalClass *ic = engine->internalClasses[EngineBase::Class_Empty]; + ic->mark(engine); } QT_END_NAMESPACE diff --git a/src/qml/jsruntime/qv4internalclass_p.h b/src/qml/jsruntime/qv4internalclass_p.h index 3c4e0838d9..031f66793b 100644 --- a/src/qml/jsruntime/qv4internalclass_p.h +++ b/src/qml/jsruntime/qv4internalclass_p.h @@ -223,6 +223,7 @@ struct InternalClassTransition union { Identifier *id; const VTable *vtable; + Heap::Object *prototype; }; InternalClass *lookup; int flags; @@ -230,6 +231,7 @@ struct InternalClassTransition // range 0-0xff is reserved for attribute changes NotExtensible = 0x100, VTableChange = 0x200, + PrototypeChange = 0x201 }; bool operator==(const InternalClassTransition &other) const @@ -242,6 +244,7 @@ struct InternalClassTransition struct InternalClass : public QQmlJS::Managed { ExecutionEngine *engine; const VTable *vtable; + Heap::Object *prototype; PropertyHash propertyTable; // id to valueIndex SharedInternalClassData nameMap; @@ -257,30 +260,37 @@ struct InternalClass : public QQmlJS::Managed { uint size; bool extensible; - InternalClass *nonExtensible(); - InternalClass *changeVTable(const VTable *vt) { + Q_REQUIRED_RESULT InternalClass *nonExtensible(); + Q_REQUIRED_RESULT InternalClass *changeVTable(const VTable *vt) { if (vtable == vt) return this; return changeVTableImpl(vt); } + Q_REQUIRED_RESULT InternalClass *changePrototype(Heap::Object *proto) { + if (prototype == proto) + return this; + return changePrototypeImpl(proto); + } static void addMember(Object *object, String *string, PropertyAttributes data, uint *index); - InternalClass *addMember(String *string, PropertyAttributes data, uint *index = 0); - InternalClass *addMember(Identifier *identifier, PropertyAttributes data, uint *index = 0); - InternalClass *changeMember(Identifier *identifier, PropertyAttributes data, uint *index = 0); + Q_REQUIRED_RESULT InternalClass *addMember(String *string, PropertyAttributes data, uint *index = 0); + Q_REQUIRED_RESULT InternalClass *addMember(Identifier *identifier, PropertyAttributes data, uint *index = 0); + Q_REQUIRED_RESULT InternalClass *changeMember(Identifier *identifier, PropertyAttributes data, uint *index = 0); static void changeMember(Object *object, String *string, PropertyAttributes data, uint *index = 0); static void removeMember(Object *object, Identifier *id); uint find(const String *string); uint find(const Identifier *id); - InternalClass *sealed(); - InternalClass *frozen(); - InternalClass *propertiesFrozen() const; + Q_REQUIRED_RESULT InternalClass *sealed(); + Q_REQUIRED_RESULT InternalClass *frozen(); + Q_REQUIRED_RESULT InternalClass *propertiesFrozen() const; void destroy(); + void mark(ExecutionEngine *e); private: Q_QML_EXPORT InternalClass *changeVTableImpl(const VTable *vt); + Q_QML_EXPORT InternalClass *changePrototypeImpl(Heap::Object *proto); InternalClass *addMemberImpl(Identifier *identifier, PropertyAttributes data, uint *index); friend struct ExecutionEngine; InternalClass(ExecutionEngine *engine); diff --git a/src/qml/jsruntime/qv4lookup.cpp b/src/qml/jsruntime/qv4lookup.cpp index f8ac0cb650..25fa670115 100644 --- a/src/qml/jsruntime/qv4lookup.cpp +++ b/src/qml/jsruntime/qv4lookup.cpp @@ -63,7 +63,7 @@ ReturnedValue Lookup::lookup(const Value &thisObject, Object *o, PropertyAttribu return !attrs->isAccessor() ? v->asReturnedValue() : Object::getValue(thisObject, *v, *attrs); } - obj = obj->prototype; + obj = obj->prototype(); ++i; } level = Size; @@ -76,7 +76,7 @@ ReturnedValue Lookup::lookup(const Value &thisObject, Object *o, PropertyAttribu return !attrs->isAccessor() ? v->asReturnedValue() : Object::getValue(thisObject, *v, *attrs); } - obj = obj->prototype; + obj = obj->prototype(); } return Primitive::emptyValue().asReturnedValue(); } @@ -98,7 +98,7 @@ ReturnedValue Lookup::lookup(const Object *thisObject, PropertyAttributes *attrs return !attrs->isAccessor() ? v->asReturnedValue() : thisObject->getValue(*v, *attrs); } - obj = obj->prototype; + obj = obj->prototype(); ++i; } level = Size; @@ -111,7 +111,7 @@ ReturnedValue Lookup::lookup(const Object *thisObject, PropertyAttributes *attrs return !attrs->isAccessor() ? v->asReturnedValue() : thisObject->getValue(*v, *attrs); } - obj = obj->prototype; + obj = obj->prototype(); } return Primitive::emptyValue().asReturnedValue(); } @@ -402,8 +402,8 @@ ReturnedValue Lookup::getter1(Lookup *l, ExecutionEngine *engine, const Value &o // the internal class won't match Heap::Object *o = static_cast(object.heapObject()); if (o) { - if (l->classList[0] == o->internalClass && l->classList[1] == o->prototype->internalClass) - return o->prototype->propertyData(l->index)->asReturnedValue(); + if (l->classList[0] == o->internalClass && l->classList[1] == o->prototype()->internalClass) + return o->prototype()->propertyData(l->index)->asReturnedValue(); } return getterTwoClasses(l, engine, object); } @@ -415,9 +415,9 @@ ReturnedValue Lookup::getter2(Lookup *l, ExecutionEngine *engine, const Value &o Heap::Object *o = static_cast(object.heapObject()); if (o) { if (l->classList[0] == o->internalClass) { - Heap::Object *p = o->prototype; + Heap::Object *p = o->prototype(); if (l->classList[1] == p->internalClass) { - p = p->prototype; + p = p->prototype(); if (l->classList[2] == p->internalClass) return p->propertyData(l->index)->asReturnedValue(); } @@ -480,8 +480,8 @@ ReturnedValue Lookup::getter0Inlinegetter1(Lookup *l, ExecutionEngine *engine, c if (o) { if (l->classList[0] == o->internalClass) return o->inlinePropertyData(l->index)->asReturnedValue(); - if (l->classList[2] == o->internalClass && l->classList[3] == o->prototype->internalClass) - return o->prototype->propertyData(l->index2)->asReturnedValue(); + if (l->classList[2] == o->internalClass && l->classList[3] == o->prototype()->internalClass) + return o->prototype()->propertyData(l->index2)->asReturnedValue(); } l->getter = getterFallback; return getterFallback(l, engine, object); @@ -495,8 +495,8 @@ ReturnedValue Lookup::getter0MemberDatagetter1(Lookup *l, ExecutionEngine *engin if (o) { if (l->classList[0] == o->internalClass) return o->memberData->data[l->index].asReturnedValue(); - if (l->classList[2] == o->internalClass && l->classList[3] == o->prototype->internalClass) - return o->prototype->propertyData(l->index2)->asReturnedValue(); + if (l->classList[2] == o->internalClass && l->classList[3] == o->prototype()->internalClass) + return o->prototype()->propertyData(l->index2)->asReturnedValue(); } l->getter = getterFallback; return getterFallback(l, engine, object); @@ -509,11 +509,11 @@ ReturnedValue Lookup::getter1getter1(Lookup *l, ExecutionEngine *engine, const V Heap::Object *o = static_cast(object.heapObject()); if (o) { if (l->classList[0] == o->internalClass && - l->classList[1] == o->prototype->internalClass) - return o->prototype->propertyData(l->index)->asReturnedValue(); + l->classList[1] == o->prototype()->internalClass) + return o->prototype()->propertyData(l->index)->asReturnedValue(); if (l->classList[2] == o->internalClass && - l->classList[3] == o->prototype->internalClass) - return o->prototype->propertyData(l->index2)->asReturnedValue(); + l->classList[3] == o->prototype()->internalClass) + return o->prototype()->propertyData(l->index2)->asReturnedValue(); return getterFallback(l, engine, object); } l->getter = getterFallback; @@ -550,9 +550,9 @@ ReturnedValue Lookup::getterAccessor1(Lookup *l, ExecutionEngine *engine, const Heap::Object *o = static_cast(object.heapObject()); if (o) { if (l->classList[0] == o->internalClass && - l->classList[1] == o->prototype->internalClass) { + l->classList[1] == o->prototype()->internalClass) { Scope scope(o->internalClass->engine); - ScopedFunctionObject getter(scope, o->prototype->propertyData(l->index + Object::GetterOffset)); + ScopedFunctionObject getter(scope, o->prototype()->propertyData(l->index + Object::GetterOffset)); if (!getter) return Encode::undefined(); @@ -573,9 +573,9 @@ ReturnedValue Lookup::getterAccessor2(Lookup *l, ExecutionEngine *engine, const Heap::Object *o = static_cast(object.heapObject()); if (o) { if (l->classList[0] == o->internalClass) { - o = o->prototype; + o = o->prototype(); if (l->classList[1] == o->internalClass) { - o = o->prototype; + o = o->prototype(); if (l->classList[2] == o->internalClass) { Scope scope(o->internalClass->engine); ScopedFunctionObject getter(scope, o->propertyData(l->index + Object::GetterOffset)); @@ -621,8 +621,8 @@ ReturnedValue Lookup::primitiveGetter1(Lookup *l, ExecutionEngine *engine, const if (object.type() == l->type) { Heap::Object *o = l->proto; if (l->classList[0] == o->internalClass && - l->classList[1] == o->prototype->internalClass) - return o->prototype->propertyData(l->index)->asReturnedValue(); + l->classList[1] == o->prototype()->internalClass) + return o->prototype()->propertyData(l->index)->asReturnedValue(); } l->getter = getterGeneric; return getterGeneric(l, engine, object); @@ -653,9 +653,9 @@ ReturnedValue Lookup::primitiveGetterAccessor1(Lookup *l, ExecutionEngine *engin if (object.type() == l->type) { Heap::Object *o = l->proto; if (l->classList[0] == o->internalClass && - l->classList[1] == o->prototype->internalClass) { + l->classList[1] == o->prototype()->internalClass) { Scope scope(o->internalClass->engine); - ScopedFunctionObject getter(scope, o->prototype->propertyData(l->index + Object::GetterOffset)); + ScopedFunctionObject getter(scope, o->prototype()->propertyData(l->index + Object::GetterOffset)); if (!getter) return Encode::undefined(); @@ -758,11 +758,11 @@ ReturnedValue Lookup::globalGetter2(Lookup *l, ExecutionEngine *engine) { Heap::Object *o = engine->globalObject->d(); if (l->classList[0] == o->internalClass) { - o = o->prototype; + o = o->prototype(); if (l->classList[1] == o->internalClass) { - o = o->prototype; + o = o->prototype(); if (l->classList[2] == o->internalClass) { - return o->prototype->propertyData(l->index)->asReturnedValue(); + return o->prototype()->propertyData(l->index)->asReturnedValue(); } } } @@ -811,9 +811,9 @@ ReturnedValue Lookup::globalGetterAccessor2(Lookup *l, ExecutionEngine *engine) { Heap::Object *o = engine->globalObject->d(); if (l->classList[0] == o->internalClass) { - o = o->prototype; + o = o->prototype(); if (l->classList[1] == o->internalClass) { - o = o->prototype; + o = o->prototype(); if (l->classList[2] == o->internalClass) { Scope scope(o->internalClass->engine); ScopedFunctionObject getter(scope, o->propertyData(l->index + Object::GetterOffset)); @@ -934,7 +934,7 @@ void Lookup::setterInsert2(Lookup *l, ExecutionEngine *engine, Value &object, co if (o && o->internalClass() == l->classList[0]) { Heap::Object *p = o->prototype(); if (p && p->internalClass == l->classList[1]) { - p = p->prototype; + p = p->prototype(); if (p && p->internalClass == l->classList[2]) { o->setInternalClass(l->classList[3]); *o->propertyData(l->index) = value; diff --git a/src/qml/jsruntime/qv4object.cpp b/src/qml/jsruntime/qv4object.cpp index 838ae96c59..4abe508e10 100644 --- a/src/qml/jsruntime/qv4object.cpp +++ b/src/qml/jsruntime/qv4object.cpp @@ -88,13 +88,14 @@ void Object::setProperty(uint index, const Property *p) bool Object::setPrototype(Object *proto) { - Heap::Object *pp = proto ? proto->d() : 0; + Heap::Object *p = proto ? proto->d() : 0; + Heap::Object *pp = p; while (pp) { if (pp == d()) return false; - pp = pp->prototype; + pp = pp->prototype(); } - d()->prototype = proto ? proto->d() : 0; + setInternalClass(internalClass()->changePrototype(p)); return true; } @@ -264,8 +265,6 @@ void Object::markObjects(Heap::Base *that, ExecutionEngine *e) o->memberData->mark(e); if (o->arrayData) o->arrayData->mark(e); - if (o->prototype) - o->prototype->mark(e); uint nInline = o->vtable()->nInlineProperties; Value *v = reinterpret_cast(o) + o->vtable()->inlinePropertyOffset; const Value *end = v + nInline; @@ -345,7 +344,7 @@ Value *Object::getValueOrSetter(String *name, PropertyAttributes *attrs) return o->propertyData(attrs->isAccessor() ? idx + SetterOffset : idx); } - o = o->prototype; + o = o->prototype(); } *attrs = Attr_Invalid; return 0; @@ -368,7 +367,7 @@ Value *Object::getValueOrSetter(uint index, PropertyAttributes *attrs) return reinterpret_cast(0x1); } } - o = o->prototype; + o = o->prototype(); } *attrs = Attr_Invalid; return 0; @@ -1204,7 +1203,7 @@ ReturnedValue Object::instanceOf(const Object *typeObject, const Value &var) // 15.3.5.3, 4 while (v) { // 15.3.5.3, 4, a - v = v->prototype; + v = v->prototype(); // 15.3.5.3, 4, b if (!v) diff --git a/src/qml/jsruntime/qv4object_p.h b/src/qml/jsruntime/qv4object_p.h index 951659a4bc..cf04a84175 100644 --- a/src/qml/jsruntime/qv4object_p.h +++ b/src/qml/jsruntime/qv4object_p.h @@ -95,7 +95,7 @@ struct Object : Base { return memberData->data + index; } - Pointer prototype; + Heap::Object *prototype() const { return internalClass->prototype; } Pointer memberData; Pointer arrayData; }; @@ -215,7 +215,7 @@ struct Q_QML_EXPORT Object: Managed { void setProperty(uint index, const Property *p); const ObjectVTable *vtable() const { return reinterpret_cast(d()->vtable()); } - Heap::Object *prototype() const { return d()->prototype; } + Heap::Object *prototype() const { return d()->prototype(); } bool setPrototype(Object *proto); void getOwnProperty(String *name, PropertyAttributes *attrs, Property *p = 0); diff --git a/src/qml/jsruntime/qv4stringobject_p.h b/src/qml/jsruntime/qv4stringobject_p.h index b8fb80546f..2e64364f9f 100644 --- a/src/qml/jsruntime/qv4stringobject_p.h +++ b/src/qml/jsruntime/qv4stringobject_p.h @@ -109,6 +109,7 @@ struct StringCtor: FunctionObject struct StringPrototype: StringObject { + V4_PROTOTYPE(objectPrototype) void init(ExecutionEngine *engine, Object *ctor); static void method_toString(const BuiltinFunction *, Scope &scope, CallData *callData); diff --git a/src/qml/jsruntime/qv4typedarray.cpp b/src/qml/jsruntime/qv4typedarray.cpp index bb28a7683c..80655aded6 100644 --- a/src/qml/jsruntime/qv4typedarray.cpp +++ b/src/qml/jsruntime/qv4typedarray.cpp @@ -373,6 +373,7 @@ void Heap::TypedArray::init(Type t) Heap::TypedArray *TypedArray::create(ExecutionEngine *e, Heap::TypedArray::Type t) { QV4::InternalClass *ic = e->internalClasses[EngineBase::Class_Empty]->changeVTable(staticVTable()); + ic = ic->changePrototype(e->typedArrayPrototype[t].d()); return e->memoryManager->allocObject(ic, e->typedArrayPrototype + t, t); } diff --git a/src/qml/memory/qv4mm_p.h b/src/qml/memory/qv4mm_p.h index 8f12fa7cbd..69d3eeb93c 100644 --- a/src/qml/memory/qv4mm_p.h +++ b/src/qml/memory/qv4mm_p.h @@ -247,11 +247,11 @@ public: { InternalClass *ic = ObjectType::defaultInternalClass(engine); ic = ic->changeVTable(ObjectType::staticVTable()); + ic = ic->changePrototype(ObjectType::defaultPrototype(engine)->d()); Heap::Object *o = allocObjectWithMemberData(ObjectType::staticVTable(), ic->size); - Object *prototype = ObjectType::defaultPrototype(engine); o->internalClass = ic; Q_ASSERT(o->internalClass && o->internalClass->vtable); - o->prototype = prototype->d(); + Q_ASSERT(o->internalClass->prototype == ObjectType::defaultPrototype(engine)->d()); return static_cast(o); } @@ -279,7 +279,8 @@ public: { Scope scope(engine); Scoped t(scope, allocateObject(ic)); - t->d_unchecked()->prototype = prototype->d(); + Q_ASSERT(t->internalClass()->prototype == (prototype ? prototype->d() : 0)); + Q_UNUSED(prototype); t->d_unchecked()->init(); return t->d(); } @@ -289,7 +290,8 @@ public: { Scope scope(engine); Scoped t(scope, allocateObject(ic)); - t->d_unchecked()->prototype = prototype->d(); + Q_ASSERT(t->internalClass()->prototype == (prototype ? prototype->d() : 0)); + Q_UNUSED(prototype); t->d_unchecked()->init(arg1); return t->d(); } @@ -299,7 +301,8 @@ public: { Scope scope(engine); Scoped t(scope, allocateObject(ic)); - t->d_unchecked()->prototype = prototype->d(); + Q_ASSERT(t->internalClass()->prototype == (prototype ? prototype->d() : 0)); + Q_UNUSED(prototype); t->d_unchecked()->init(arg1, arg2); return t->d(); } @@ -309,7 +312,8 @@ public: { Scope scope(engine); Scoped t(scope, allocateObject(ic)); - t->d_unchecked()->prototype = prototype->d(); + Q_ASSERT(t->internalClass()->prototype == (prototype ? prototype->d() : 0)); + Q_UNUSED(prototype); t->d_unchecked()->init(arg1, arg2, arg3); return t->d(); } @@ -319,7 +323,8 @@ public: { Scope scope(engine); Scoped t(scope, allocateObject(ic)); - t->d_unchecked()->prototype = prototype->d(); + Q_ASSERT(t->internalClass()->prototype == (prototype ? prototype->d() : 0)); + Q_UNUSED(prototype); t->d_unchecked()->init(arg1, arg2, arg3, arg4); return t->d(); } -- cgit v1.2.3 From 10b237882cfe76521b4dc65300a2a0473faca174 Mon Sep 17 00:00:00 2001 From: Lars Knoll Date: Mon, 15 May 2017 12:42:56 +0200 Subject: Optimize lookups based on IC changes Change-Id: I1f4f4aaad0c8194bce2ebde4503df38cab0990a2 Reviewed-by: Simon Hausmann --- src/qml/jsruntime/qv4lookup.cpp | 50 ++++++++++++++++++++++------------------- src/qml/jsruntime/qv4lookup_p.h | 3 ++- src/qml/jsruntime/qv4object.cpp | 2 ++ 3 files changed, 31 insertions(+), 24 deletions(-) (limited to 'src') diff --git a/src/qml/jsruntime/qv4lookup.cpp b/src/qml/jsruntime/qv4lookup.cpp index 25fa670115..faaa5539ab 100644 --- a/src/qml/jsruntime/qv4lookup.cpp +++ b/src/qml/jsruntime/qv4lookup.cpp @@ -402,8 +402,8 @@ ReturnedValue Lookup::getter1(Lookup *l, ExecutionEngine *engine, const Value &o // the internal class won't match Heap::Object *o = static_cast(object.heapObject()); if (o) { - if (l->classList[0] == o->internalClass && l->classList[1] == o->prototype()->internalClass) - return o->prototype()->propertyData(l->index)->asReturnedValue(); + if (l->classList[0] == o->internalClass && l->classList[1] == l->proto->internalClass) + return l->proto->propertyData(l->index)->asReturnedValue(); } return getterTwoClasses(l, engine, object); } @@ -415,9 +415,9 @@ ReturnedValue Lookup::getter2(Lookup *l, ExecutionEngine *engine, const Value &o Heap::Object *o = static_cast(object.heapObject()); if (o) { if (l->classList[0] == o->internalClass) { - Heap::Object *p = o->prototype(); - if (l->classList[1] == p->internalClass) { - p = p->prototype(); + Q_ASSERT(l->proto == o->prototype()); + if (l->classList[1] == l->proto->internalClass) { + Heap::Object *p = l->proto->prototype(); if (l->classList[2] == p->internalClass) return p->propertyData(l->index)->asReturnedValue(); } @@ -550,7 +550,7 @@ ReturnedValue Lookup::getterAccessor1(Lookup *l, ExecutionEngine *engine, const Heap::Object *o = static_cast(object.heapObject()); if (o) { if (l->classList[0] == o->internalClass && - l->classList[1] == o->prototype()->internalClass) { + l->classList[1] == l->proto->internalClass) { Scope scope(o->internalClass->engine); ScopedFunctionObject getter(scope, o->prototype()->propertyData(l->index + Object::GetterOffset)); if (!getter) @@ -573,9 +573,9 @@ ReturnedValue Lookup::getterAccessor2(Lookup *l, ExecutionEngine *engine, const Heap::Object *o = static_cast(object.heapObject()); if (o) { if (l->classList[0] == o->internalClass) { - o = o->prototype(); - if (l->classList[1] == o->internalClass) { - o = o->prototype(); + Q_ASSERT(o->prototype() == l->proto); + if (l->classList[1] == l->proto->internalClass) { + o = l->proto->prototype(); if (l->classList[2] == o->internalClass) { Scope scope(o->internalClass->engine); ScopedFunctionObject getter(scope, o->propertyData(l->index + Object::GetterOffset)); @@ -877,7 +877,7 @@ void Lookup::setterFallback(Lookup *l, ExecutionEngine *engine, Value &object, c void Lookup::setter0(Lookup *l, ExecutionEngine *engine, Value &object, const Value &value) { - Object *o = object.as(); + Object *o = static_cast(object.managed()); if (o && o->internalClass() == l->classList[0]) { *o->propertyData(l->index) = value; return; @@ -888,7 +888,7 @@ void Lookup::setter0(Lookup *l, ExecutionEngine *engine, Value &object, const Va void Lookup::setter0Inline(Lookup *l, ExecutionEngine *engine, Value &object, const Value &value) { - Object *o = object.as(); + Object *o = static_cast(object.managed()); if (o && o->internalClass() == l->classList[0]) { *o->d()->inlinePropertyData(l->index) = value; return; @@ -899,13 +899,12 @@ void Lookup::setter0Inline(Lookup *l, ExecutionEngine *engine, Value &object, co void Lookup::setterInsert0(Lookup *l, ExecutionEngine *engine, Value &object, const Value &value) { - Object *o = object.as(); + Object *o = static_cast(object.managed()); if (o && o->internalClass() == l->classList[0]) { - if (!o->prototype()) { - o->setInternalClass(l->classList[3]); - *o->propertyData(l->index) = value; - return; - } + Q_ASSERT(!o->prototype()); + o->setInternalClass(l->classList[3]); + *o->propertyData(l->index) = value; + return; } l->setter = setterFallback; @@ -914,10 +913,12 @@ void Lookup::setterInsert0(Lookup *l, ExecutionEngine *engine, Value &object, co void Lookup::setterInsert1(Lookup *l, ExecutionEngine *engine, Value &object, const Value &value) { - Object *o = object.as(); + Object *o = static_cast(object.managed()); if (o && o->internalClass() == l->classList[0]) { Heap::Object *p = o->prototype(); - if (p && p->internalClass == l->classList[1]) { + Q_ASSERT(p); + if (p->internalClass == l->classList[1]) { + Q_ASSERT(!p->prototype()); o->setInternalClass(l->classList[3]); *o->propertyData(l->index) = value; return; @@ -930,12 +931,15 @@ void Lookup::setterInsert1(Lookup *l, ExecutionEngine *engine, Value &object, co void Lookup::setterInsert2(Lookup *l, ExecutionEngine *engine, Value &object, const Value &value) { - Object *o = object.as(); + Object *o = static_cast(object.managed()); if (o && o->internalClass() == l->classList[0]) { Heap::Object *p = o->prototype(); - if (p && p->internalClass == l->classList[1]) { + Q_ASSERT(p); + if (p->internalClass == l->classList[1]) { p = p->prototype(); - if (p && p->internalClass == l->classList[2]) { + Q_ASSERT(p); + if (p->internalClass == l->classList[2]) { + Q_ASSERT(!p->prototype()); o->setInternalClass(l->classList[3]); *o->propertyData(l->index) = value; return; @@ -949,7 +953,7 @@ void Lookup::setterInsert2(Lookup *l, ExecutionEngine *engine, Value &object, co void Lookup::setter0setter0(Lookup *l, ExecutionEngine *engine, Value &object, const Value &value) { - Object *o = object.as(); + Object *o = static_cast(object.managed()); if (o) { if (o->internalClass() == l->classList[0]) { *o->propertyData(l->index) = value; diff --git a/src/qml/jsruntime/qv4lookup_p.h b/src/qml/jsruntime/qv4lookup_p.h index 9e50235b73..151231991f 100644 --- a/src/qml/jsruntime/qv4lookup_p.h +++ b/src/qml/jsruntime/qv4lookup_p.h @@ -79,13 +79,14 @@ struct Lookup { struct { void *dummy0; void *dummy1; + void *dummy2; Heap::Object *proto; - unsigned type; }; }; union { int level; uint index2; + unsigned type; }; uint index; uint nameIndex; diff --git a/src/qml/jsruntime/qv4object.cpp b/src/qml/jsruntime/qv4object.cpp index 4abe508e10..c3ebb53622 100644 --- a/src/qml/jsruntime/qv4object.cpp +++ b/src/qml/jsruntime/qv4object.cpp @@ -505,7 +505,9 @@ ReturnedValue Object::getLookup(const Managed *m, Lookup *l) PropertyAttributes attrs; ReturnedValue v = l->lookup(o, &attrs); if (v != Primitive::emptyValue().asReturnedValue()) { + l->proto = l->classList[0]->prototype; if (attrs.isData()) { + Q_ASSERT(l->classList[0] == o->internalClass()); if (l->level == 0) { uint nInline = o->d()->vtable()->nInlineProperties; if (l->index < nInline) -- cgit v1.2.3 From c03eedaf8c6846dc80ab014face4d514deb9665d Mon Sep 17 00:00:00 2001 From: Lars Knoll Date: Tue, 16 May 2017 15:03:39 +0200 Subject: Optimize lookups in the internalClass Inline the version taking an identifier, and use that one where it makes sense. Change-Id: I414c5999e61cdba219ecd1080957f3037dfebc1b Reviewed-by: Simon Hausmann --- src/qml/jsruntime/qv4context.cpp | 22 +++++++++++++++++----- src/qml/jsruntime/qv4internalclass.cpp | 9 --------- src/qml/jsruntime/qv4internalclass_p.h | 9 ++++++++- src/qml/jsruntime/qv4object.cpp | 30 ++++++++++++++++++++++-------- 4 files changed, 47 insertions(+), 23 deletions(-) (limited to 'src') diff --git a/src/qml/jsruntime/qv4context.cpp b/src/qml/jsruntime/qv4context.cpp index c4a0539750..03595aa59d 100644 --- a/src/qml/jsruntime/qv4context.cpp +++ b/src/qml/jsruntime/qv4context.cpp @@ -209,6 +209,9 @@ unsigned int CallContext::variableCount() const bool ExecutionContext::deleteProperty(String *name) { + name->makeIdentifier(engine()); + Identifier *id = name->identifier(); + Scope scope(this); bool hasWith = false; ScopedContext ctx(scope, this); @@ -237,7 +240,7 @@ bool ExecutionContext::deleteProperty(String *name) case Heap::ExecutionContext::Type_SimpleCallContext: { Heap::CallContext *c = static_cast(ctx->d()); if (c->v4Function && (c->v4Function->needsActivation() || hasWith)) { - uint index = c->v4Function->internalClass->find(name); + uint index = c->v4Function->internalClass->find(id); if (index < UINT_MAX) // ### throw in strict mode? return false; @@ -361,6 +364,9 @@ void QV4::ExecutionContext::simpleCall(Scope &scope, CallData *callData, Functio void ExecutionContext::setProperty(String *name, const Value &value) { + name->makeIdentifier(engine()); + Identifier *id = name->identifier(); + Scope scope(this); ScopedContext ctx(scope, this); ScopedObject activation(scope); @@ -392,7 +398,7 @@ void ExecutionContext::setProperty(String *name, const Value &value) case Heap::ExecutionContext::Type_SimpleCallContext: { Heap::CallContext *c = static_cast(ctx->d()); if (c->v4Function) { - uint index = c->v4Function->internalClass->find(name); + uint index = c->v4Function->internalClass->find(id); if (index < UINT_MAX) { if (index < c->v4Function->nFormals) { c->callData->args[c->v4Function->nFormals - index - 1] = value; @@ -414,7 +420,7 @@ void ExecutionContext::setProperty(String *name, const Value &value) } if (activation) { - uint member = activation->internalClass()->find(name); + uint member = activation->internalClass()->find(id); if (member < UINT_MAX) { activation->putValue(member, value); return; @@ -473,7 +479,10 @@ ReturnedValue ExecutionContext::getProperty(String *name) case Heap::ExecutionContext::Type_SimpleCallContext: { Heap::CallContext *c = static_cast(ctx->d()); if (c->v4Function && (c->v4Function->needsActivation() || hasWith || hasCatchScope)) { - uint index = c->v4Function->internalClass->find(name); + name->makeIdentifier(engine()); + Identifier *id = name->identifier(); + + uint index = c->v4Function->internalClass->find(id); if (index < UINT_MAX) { if (index < c->v4Function->nFormals) return c->callData->args[c->v4Function->nFormals - index - 1].asReturnedValue(); @@ -551,7 +560,10 @@ ReturnedValue ExecutionContext::getPropertyAndBase(String *name, Value *base) case Heap::ExecutionContext::Type_SimpleCallContext: { Heap::CallContext *c = static_cast(ctx->d()); if (c->v4Function && (c->v4Function->needsActivation() || hasWith || hasCatchScope)) { - uint index = c->v4Function->internalClass->find(name); + name->makeIdentifier(engine()); + Identifier *id = name->identifier(); + + uint index = c->v4Function->internalClass->find(id); if (index < UINT_MAX) { if (index < c->v4Function->nFormals) return c->callData->args[c->v4Function->nFormals - index - 1].asReturnedValue(); diff --git a/src/qml/jsruntime/qv4internalclass.cpp b/src/qml/jsruntime/qv4internalclass.cpp index 600198567a..9f43871f27 100644 --- a/src/qml/jsruntime/qv4internalclass.cpp +++ b/src/qml/jsruntime/qv4internalclass.cpp @@ -429,15 +429,6 @@ uint QV4::InternalClass::find(const String *string) return UINT_MAX; } -uint InternalClass::find(const Identifier *id) -{ - uint index = propertyTable.lookup(id); - if (index < size) - return index; - - return UINT_MAX; -} - InternalClass *InternalClass::sealed() { if (m_sealed) diff --git a/src/qml/jsruntime/qv4internalclass_p.h b/src/qml/jsruntime/qv4internalclass_p.h index 031f66793b..34422098d9 100644 --- a/src/qml/jsruntime/qv4internalclass_p.h +++ b/src/qml/jsruntime/qv4internalclass_p.h @@ -279,7 +279,14 @@ struct InternalClass : public QQmlJS::Managed { static void changeMember(Object *object, String *string, PropertyAttributes data, uint *index = 0); static void removeMember(Object *object, Identifier *id); uint find(const String *string); - uint find(const Identifier *id); + uint find(const Identifier *id) + { + uint index = propertyTable.lookup(id); + if (index < size) + return index; + + return UINT_MAX; + } Q_REQUIRED_RESULT InternalClass *sealed(); Q_REQUIRED_RESULT InternalClass *frozen(); diff --git a/src/qml/jsruntime/qv4object.cpp b/src/qml/jsruntime/qv4object.cpp index c3ebb53622..cac9d8ad7d 100644 --- a/src/qml/jsruntime/qv4object.cpp +++ b/src/qml/jsruntime/qv4object.cpp @@ -294,7 +294,10 @@ void Object::getOwnProperty(String *name, PropertyAttributes *attrs, Property *p if (idx != UINT_MAX) return getOwnProperty(idx, attrs, p); - uint member = internalClass()->find(name); + name->makeIdentifier(engine()); + Identifier *id = name->identifier(); + + uint member = internalClass()->find(id); if (member < UINT_MAX) { *attrs = internalClass()->propertyData[member]; if (p) { @@ -336,9 +339,12 @@ Value *Object::getValueOrSetter(String *name, PropertyAttributes *attrs) { Q_ASSERT(name->asArrayIndex() == UINT_MAX); + name->makeIdentifier(engine()); + Identifier *id = name->identifier(); + Heap::Object *o = d(); while (o) { - uint idx = o->internalClass->find(name); + uint idx = o->internalClass->find(id); if (idx < UINT_MAX) { *attrs = o->internalClass->propertyData[idx]; return o->propertyData(attrs->isAccessor() ? idx + SetterOffset : idx); @@ -411,7 +417,10 @@ bool Object::hasOwnProperty(String *name) const if (idx != UINT_MAX) return hasOwnProperty(idx); - if (internalClass()->find(name) < UINT_MAX) + name->makeIdentifier(engine()); + Identifier *id = name->identifier(); + + if (internalClass()->find(id) < UINT_MAX) return true; if (!query(name).isEmpty()) return true; @@ -468,8 +477,11 @@ PropertyAttributes Object::query(const Managed *m, String *name) if (idx != UINT_MAX) return queryIndexed(m, idx); + name->makeIdentifier(m->internalClass()->engine); + Identifier *id = name->identifier(); + const Object *o = static_cast(m); - idx = o->internalClass()->find(name); + idx = o->internalClass()->find(id); if (idx < UINT_MAX) return o->internalClass()->propertyData[idx]; @@ -670,10 +682,11 @@ ReturnedValue Object::internalGet(String *name, bool *hasProperty) const Scope scope(engine()); name->makeIdentifier(scope.engine); + Identifier *id = name->identifier(); ScopedObject o(scope, this); while (o) { - uint idx = o->internalClass()->find(name); + uint idx = o->internalClass()->find(id); if (idx < UINT_MAX) { if (hasProperty) *hasProperty = true; @@ -736,8 +749,9 @@ void Object::internalPut(String *name, const Value &value) return putIndexed(idx, value); name->makeIdentifier(engine()); + Identifier *id = name->identifier(); - uint member = internalClass()->find(name); + uint member = internalClass()->find(id); Value *v = 0; PropertyAttributes attrs; if (member < UINT_MAX) { @@ -890,7 +904,7 @@ bool Object::internalDeleteProperty(String *name) name->makeIdentifier(engine()); - uint memberIdx = internalClass()->find(name); + uint memberIdx = internalClass()->find(name->identifier()); if (memberIdx != UINT_MAX) { if (internalClass()->propertyData[memberIdx].isConfigurable()) { InternalClass::removeMember(this, name->identifier()); @@ -961,7 +975,7 @@ bool Object::__defineOwnProperty__(ExecutionEngine *engine, String *name, const } // Clause 1 - memberIndex = internalClass()->find(name); + memberIndex = internalClass()->find(name->identifier()); if (memberIndex == UINT_MAX) { // clause 3 -- cgit v1.2.3 From 8bb01e03e018de7e040b3224c6cdaf43d86051e5 Mon Sep 17 00:00:00 2001 From: Lars Knoll Date: Tue, 16 May 2017 15:10:03 +0200 Subject: Give standard objects a bit more inline storage by default Make sure we have at least 2 slots for inline storage available for regular JS objects. Speeds up JS execution quite a bit, while still keeping memory consumption low for most other cases. Change-Id: I01824d8db1ffd828c1c1b6a9cbcf9bf1a9070ec3 Reviewed-by: Simon Hausmann --- src/qml/jsruntime/qv4managed_p.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/qml/jsruntime/qv4managed_p.h b/src/qml/jsruntime/qv4managed_p.h index 814755efe9..4c387a7fe7 100644 --- a/src/qml/jsruntime/qv4managed_p.h +++ b/src/qml/jsruntime/qv4managed_p.h @@ -131,7 +131,7 @@ inline void qYouForgotTheQ_MANAGED_Macro(T1, T2) {} { \ parentVTable, \ (sizeof(classname::Data) + sizeof(QV4::Value) - 1)/sizeof(QV4::Value), \ - (sizeof(classname::Data) + QV4::Chunk::SlotSize - 1)/QV4::Chunk::SlotSize*QV4::Chunk::SlotSize/sizeof(QV4::Value) \ + (sizeof(classname::Data) + (std::is_same::value ? 2*sizeof(QV4::Value) : 0) + QV4::Chunk::SlotSize - 1)/QV4::Chunk::SlotSize*QV4::Chunk::SlotSize/sizeof(QV4::Value) \ - (sizeof(classname::Data) + sizeof(QV4::Value) - 1)/sizeof(QV4::Value), \ classname::IsExecutionContext, \ classname::IsString, \ -- cgit v1.2.3 From 32a1d14a3a1dead69dd1306adf70eefd3415639e Mon Sep 17 00:00:00 2001 From: Lars Knoll Date: Tue, 16 May 2017 15:29:17 +0200 Subject: Optimize marking of prototypes in the InternalClass tree There's no need to iterate over all internal classes, as prototype changes always happen in the first or second level of the tree. Change-Id: I99bf11a6cd238286c1547922d61ab47319b6eb97 Reviewed-by: Simon Hausmann --- src/qml/jsruntime/qv4internalclass.cpp | 32 ++++++++++++++++---------------- src/qml/jsruntime/qv4internalclass_p.h | 1 - 2 files changed, 16 insertions(+), 17 deletions(-) (limited to 'src') diff --git a/src/qml/jsruntime/qv4internalclass.cpp b/src/qml/jsruntime/qv4internalclass.cpp index 9f43871f27..0bcd510541 100644 --- a/src/qml/jsruntime/qv4internalclass.cpp +++ b/src/qml/jsruntime/qv4internalclass.cpp @@ -506,25 +506,25 @@ void InternalClass::destroy() } } -void InternalClass::mark(ExecutionEngine *e) -{ - if (m_sealed) - m_sealed->mark(e); - if (m_frozen) - m_frozen->mark(e); - - for (size_t i = 0; i < transitions.size(); ++i) { - Q_ASSERT(transitions.at(i).lookup); - transitions.at(i).lookup->mark(e); - } - if (prototype) - prototype->mark(engine); -} - void InternalClassPool::markObjects(ExecutionEngine *engine) { InternalClass *ic = engine->internalClasses[EngineBase::Class_Empty]; - ic->mark(engine); + Q_ASSERT(!ic->prototype); + + // only need to go two levels into the IC hierarchy, as prototype changes + // can only happen there + for (auto &t : ic->transitions) { + Q_ASSERT(t.lookup); + if (t.flags == InternalClassTransition::VTableChange) { + InternalClass *ic2 = t.lookup; + for (auto &t2 : ic2->transitions) { + if (t2.flags == InternalClassTransition::PrototypeChange) + t2.lookup->prototype->mark(engine); + } + } else if (t.flags == InternalClassTransition::PrototypeChange) { + t.lookup->prototype->mark(engine); + } + } } QT_END_NAMESPACE diff --git a/src/qml/jsruntime/qv4internalclass_p.h b/src/qml/jsruntime/qv4internalclass_p.h index 34422098d9..9e8ab9e73e 100644 --- a/src/qml/jsruntime/qv4internalclass_p.h +++ b/src/qml/jsruntime/qv4internalclass_p.h @@ -293,7 +293,6 @@ struct InternalClass : public QQmlJS::Managed { Q_REQUIRED_RESULT InternalClass *propertiesFrozen() const; void destroy(); - void mark(ExecutionEngine *e); private: Q_QML_EXPORT InternalClass *changeVTableImpl(const VTable *vt); -- cgit v1.2.3 From 6a02fb09af8dce6ca533e816d2223e070b30f294 Mon Sep 17 00:00:00 2001 From: Robin Burchell Date: Tue, 16 May 2017 19:08:28 +0200 Subject: QQmlIRBuilder: Only query type name cache for type names The behavior here was always incorrect: type names must start with an uppercase letter, so querying the type name cache with a lowercase string is wrong. However, this was turned into a larger problem by making more extensive use of QQmlTypeNameCache in e74a1d0b342f2c95dc3a543c8c9ec07fd52d8fe0, as it contained a lot of new types (including composite types, which previously were only in the cache if they were singletons). Task-number: QTBUG-60547 Change-Id: I40be2d535e99d3e1af250d995d7149ecbe2965d7 Reviewed-by: Simon Hausmann --- src/qml/compiler/qqmlirbuilder.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/qml/compiler/qqmlirbuilder.cpp b/src/qml/compiler/qqmlirbuilder.cpp index 9f2c2294ed..16eee50cf9 100644 --- a/src/qml/compiler/qqmlirbuilder.cpp +++ b/src/qml/compiler/qqmlirbuilder.cpp @@ -1924,7 +1924,7 @@ QV4::IR::Expr *JSCodeGen::fallbackNameLookup(const QString &name, int line, int // with the correct QML context. // Look for IDs first. - for (const IdMapping &mapping : qAsConst(_idObjects)) + for (const IdMapping &mapping : qAsConst(_idObjects)) { if (name == mapping.name) { if (_function->isQmlBinding) _function->idObjectDependencies.insert(mapping.idIndex); @@ -1942,8 +1942,9 @@ QV4::IR::Expr *JSCodeGen::fallbackNameLookup(const QString &name, int line, int result->isReadOnly = true; // don't allow use as lvalue return result; } + } - { + if (name.at(0).isUpper()) { QQmlTypeNameCache::Result r = imports->query(name); if (r.isValid()) { if (r.scriptIndex != -1) { -- cgit v1.2.3 From 5f49b2b3bb30678a26341e1f45e0cfd6a6fd2c57 Mon Sep 17 00:00:00 2001 From: J-P Nurmi Date: Thu, 11 May 2017 17:19:14 +0200 Subject: QML Settings: fix JS array handling Before Qt 5.4, JS arrays were passed as QVariantLists. Since Qt 5.4, they are passed as QJSValues instead. Use QJSValue::toVariant() (the same way as QQuickItemView::setModel(QVariant) which was fixed in cf959b4b) to convert JS values to QSettings-compatible variants. Task-number: QTBUG-45316 Change-Id: Icc6f8ad09bfef089d9efcf5b90e3783bb3f73a9f Reviewed-by: Simon Hausmann --- src/imports/settings/qqmlsettings.cpp | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/src/imports/settings/qqmlsettings.cpp b/src/imports/settings/qqmlsettings.cpp index cd6fcbc718..df67c04654 100644 --- a/src/imports/settings/qqmlsettings.cpp +++ b/src/imports/settings/qqmlsettings.cpp @@ -41,6 +41,7 @@ #include #include #include +#include #include #include @@ -241,6 +242,7 @@ public: void store(); void _q_propertyChanged(); + QVariant readProperty(const QMetaProperty &property) const; QQmlSettings *q_ptr; int timerId; @@ -295,7 +297,7 @@ void QQmlSettingsPrivate::load() for (int i = offset; i < count; ++i) { QMetaProperty property = mo->property(i); - const QVariant previousValue = property.read(q); + const QVariant previousValue = readProperty(property); const QVariant currentValue = instance()->value(property.name(), previousValue); if (!currentValue.isNull() && (!previousValue.isValid() @@ -340,9 +342,10 @@ void QQmlSettingsPrivate::_q_propertyChanged() const int count = mo->propertyCount(); for (int i = offset; i < count; ++i) { const QMetaProperty &property = mo->property(i); - changedProperties.insert(property.name(), property.read(q)); + const QVariant value = readProperty(property); + changedProperties.insert(property.name(), value); #ifdef SETTINGS_DEBUG - qDebug() << "QQmlSettings: cache" << property.name() << ":" << property.read(q); + qDebug() << "QQmlSettings: cache" << property.name() << ":" << value; #endif } if (timerId != 0) @@ -350,6 +353,15 @@ void QQmlSettingsPrivate::_q_propertyChanged() timerId = q->startTimer(settingsWriteDelay); } +QVariant QQmlSettingsPrivate::readProperty(const QMetaProperty &property) const +{ + Q_Q(const QQmlSettings); + QVariant var = property.read(q); + if (var.userType() == qMetaTypeId()) + var = var.value().toVariant(); + return var; +} + QQmlSettings::QQmlSettings(QObject *parent) : QObject(parent), d_ptr(new QQmlSettingsPrivate) { -- cgit v1.2.3 From 5bc38a50308665bdc185eb96dbcc9ba7948ab4e0 Mon Sep 17 00:00:00 2001 From: Lars Knoll Date: Fri, 19 May 2017 12:39:52 +0200 Subject: Get rid of the old way of defining builtin functions The old calling convention used for builtin functions is very inefficient. It was still being used in a few places. Clean those up and convert them to the new and much more effiecient calling convention. Change-Id: I6b769c6185df7e9be1e80709330fc1ca868576c1 Reviewed-by: Robin Burchell --- src/imports/localstorage/plugin.cpp | 97 +++++++++++++---------------- src/particles/qquickv4particledata.cpp | 107 ++++++++++++++------------------ src/qml/jsruntime/qv4engine.cpp | 4 +- src/qml/jsruntime/qv4functionobject.cpp | 36 ----------- src/qml/jsruntime/qv4functionobject_p.h | 11 ---- src/qml/jsruntime/qv4object.cpp | 40 ------------ src/qml/jsruntime/qv4object_p.h | 4 -- src/qml/util/qqmladaptormodel.cpp | 44 ++++++------- 8 files changed, 114 insertions(+), 229 deletions(-) (limited to 'src') diff --git a/src/imports/localstorage/plugin.cpp b/src/imports/localstorage/plugin.cpp index 40682dd6a8..a7d95cc295 100644 --- a/src/imports/localstorage/plugin.cpp +++ b/src/imports/localstorage/plugin.cpp @@ -73,8 +73,8 @@ QT_BEGIN_NAMESPACE QV4::ScopedString v(scope, scope.engine->newString(desc)); \ QV4::ScopedObject ex(scope, scope.engine->newErrorObject(v)); \ ex->put(QV4::ScopedString(scope, scope.engine->newIdentifier(QStringLiteral("code"))).getPointer(), QV4::ScopedValue(scope, Primitive::fromInt32(error))); \ - ctx->engine()->throwError(ex); \ - return Encode::undefined(); \ + scope.engine->throwError(ex); \ + RETURN_UNDEFINED(); \ } #define V4THROW_SQL2(error, desc) { \ @@ -87,8 +87,8 @@ QT_BEGIN_NAMESPACE #define V4THROW_REFERENCE(string) { \ QV4::ScopedString v(scope, scope.engine->newString(string)); \ - ctx->engine()->throwReferenceError(v); \ - return Encode::undefined(); \ + scope.engine->throwReferenceError(v); \ + RETURN_UNDEFINED(); \ } @@ -164,20 +164,18 @@ DEFINE_OBJECT_VTABLE(QV4::QQmlSqlDatabaseWrapper); -static ReturnedValue qmlsqldatabase_version(CallContext *ctx) +static void qmlsqldatabase_version(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData) { - QV4::Scope scope(ctx); - QV4::Scoped r(scope, ctx->thisObject().as()); + QV4::Scoped r(scope, callData->thisObject.as()); if (!r || r->d()->type != Heap::QQmlSqlDatabaseWrapper::Database) V4THROW_REFERENCE("Not a SQLDatabase object"); - return Encode(scope.engine->newString(*r->d()->version)); + RETURN_RESULT(Encode(scope.engine->newString(*r->d()->version))); } -static ReturnedValue qmlsqldatabase_rows_length(CallContext *ctx) +static void qmlsqldatabase_rows_length(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData) { - QV4::Scope scope(ctx); - QV4::Scoped r(scope, ctx->thisObject().as()); + QV4::Scoped r(scope, callData->thisObject.as()); if (!r || r->d()->type != Heap::QQmlSqlDatabaseWrapper::Rows) V4THROW_REFERENCE("Not a SQLDatabase::Rows object"); @@ -190,29 +188,27 @@ static ReturnedValue qmlsqldatabase_rows_length(CallContext *ctx) s = 0; } } - return Encode(s); + RETURN_RESULT(Encode(s)); } -static ReturnedValue qmlsqldatabase_rows_forwardOnly(CallContext *ctx) +static void qmlsqldatabase_rows_forwardOnly(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData) { - QV4::Scope scope(ctx); - QV4::Scoped r(scope, ctx->thisObject().as()); + QV4::Scoped r(scope, callData->thisObject.as()); if (!r || r->d()->type != Heap::QQmlSqlDatabaseWrapper::Rows) V4THROW_REFERENCE("Not a SQLDatabase::Rows object"); - return Encode(r->d()->sqlQuery->isForwardOnly()); + RETURN_RESULT(Encode(r->d()->sqlQuery->isForwardOnly())); } -static ReturnedValue qmlsqldatabase_rows_setForwardOnly(CallContext *ctx) +static void qmlsqldatabase_rows_setForwardOnly(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData) { - QV4::Scope scope(ctx); - QV4::Scoped r(scope, ctx->thisObject().as()); + QV4::Scoped r(scope, callData->thisObject.as()); if (!r || r->d()->type != Heap::QQmlSqlDatabaseWrapper::Rows) V4THROW_REFERENCE("Not a SQLDatabase::Rows object"); - if (ctx->argc() < 1) - return ctx->engine()->throwTypeError(); + if (callData->argc < 1) + RETURN_RESULT(scope.engine->throwTypeError()); - r->d()->sqlQuery->setForwardOnly(ctx->args()[0].toBoolean()); - return Encode::undefined(); + r->d()->sqlQuery->setForwardOnly(callData->args[0].toBoolean()); + RETURN_UNDEFINED(); } QQmlSqlDatabaseData::~QQmlSqlDatabaseData() @@ -253,14 +249,13 @@ ReturnedValue QQmlSqlDatabaseWrapper::getIndexed(const Managed *m, uint index, b return qmlsqldatabase_rows_index(r, r->engine(), index, hasProperty); } -static ReturnedValue qmlsqldatabase_rows_item(CallContext *ctx) +static void qmlsqldatabase_rows_item(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData) { - QV4::Scope scope(ctx); - QV4::Scoped r(scope, ctx->thisObject().as()); + QV4::Scoped r(scope, callData->thisObject.as()); if (!r || r->d()->type != Heap::QQmlSqlDatabaseWrapper::Rows) V4THROW_REFERENCE("Not a SQLDatabase::Rows object"); - return qmlsqldatabase_rows_index(r, scope.engine, ctx->argc() ? ctx->args()[0].toUInt32() : 0); + RETURN_RESULT(qmlsqldatabase_rows_index(r, scope.engine, callData->argc ? callData->args[0].toUInt32() : 0)); } static QVariant toSqlVariant(QV4::ExecutionEngine *engine, const QV4::ScopedValue &value) @@ -272,10 +267,9 @@ static QVariant toSqlVariant(QV4::ExecutionEngine *engine, const QV4::ScopedValu return engine->toVariant(value, /*typehint*/-1); } -static ReturnedValue qmlsqldatabase_executeSql(CallContext *ctx) +static void qmlsqldatabase_executeSql(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData) { - QV4::Scope scope(ctx); - QV4::Scoped r(scope, ctx->thisObject().as()); + QV4::Scoped r(scope, callData->thisObject.as()); if (!r || r->d()->type != Heap::QQmlSqlDatabaseWrapper::Query) V4THROW_REFERENCE("Not a SQLDatabase::Query object"); @@ -284,7 +278,7 @@ static ReturnedValue qmlsqldatabase_executeSql(CallContext *ctx) QSqlDatabase db = *r->d()->database; - QString sql = ctx->argc() ? ctx->args()[0].toQString() : QString(); + QString sql = callData->argc ? callData->args[0].toQString() : QString(); if (r->d()->readonly && !sql.startsWith(QLatin1String("SELECT"),Qt::CaseInsensitive)) { V4THROW_SQL(SQLEXCEPTION_SYNTAX_ERR, QQmlEngine::tr("Read-only Transaction")); @@ -296,8 +290,8 @@ static ReturnedValue qmlsqldatabase_executeSql(CallContext *ctx) ScopedValue result(scope, Primitive::undefinedValue()); if (query.prepare(sql)) { - if (ctx->argc() > 1) { - ScopedValue values(scope, ctx->args()[1]); + if (callData->argc > 1) { + ScopedValue values(scope, callData->args[1]); if (values->as()) { ScopedArrayObject array(scope, values); quint32 size = array->getLength(); @@ -351,7 +345,7 @@ static ReturnedValue qmlsqldatabase_executeSql(CallContext *ctx) if (err) V4THROW_SQL(SQLEXCEPTION_DATABASE_ERR,query.lastError().text()); - return result->asReturnedValue(); + RETURN_RESULT(result->asReturnedValue()); } struct TransactionRollback { @@ -383,21 +377,19 @@ struct TransactionRollback { }; -static ReturnedValue qmlsqldatabase_changeVersion(CallContext *ctx) +static void qmlsqldatabase_changeVersion(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData) { - if (ctx->argc() < 2) - return Encode::undefined(); - - Scope scope(ctx); + if (callData->argc < 2) + RETURN_UNDEFINED(); - Scoped r(scope, ctx->thisObject()); + Scoped r(scope, callData->thisObject); if (!r || r->d()->type != Heap::QQmlSqlDatabaseWrapper::Database) V4THROW_REFERENCE("Not a SQLDatabase object"); QSqlDatabase db = *r->d()->database; - QString from_version = ctx->args()[0].toQString(); - QString to_version = ctx->args()[1].toQString(); - ScopedFunctionObject callback(scope, ctx->argument(2)); + QString from_version = callData->args[0].toQString(); + QString to_version = callData->args[1].toQString(); + ScopedFunctionObject callback(scope, callData->argc > 2 ? callData->args[2] : Primitive::undefinedValue()); if (from_version != *r->d()->version) V4THROW_SQL(SQLEXCEPTION_VERSION_ERR, QQmlEngine::tr("Version mismatch: expected %1, found %2").arg(from_version).arg(*r->d()->version)); @@ -438,17 +430,16 @@ static ReturnedValue qmlsqldatabase_changeVersion(CallContext *ctx) #endif } - return Encode::undefined(); + RETURN_UNDEFINED(); } -static ReturnedValue qmlsqldatabase_transaction_shared(CallContext *ctx, bool readOnly) +static void qmlsqldatabase_transaction_shared(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData, bool readOnly) { - QV4::Scope scope(ctx); - QV4::Scoped r(scope, ctx->thisObject().as()); + QV4::Scoped r(scope, callData->thisObject.as()); if (!r || r->d()->type != Heap::QQmlSqlDatabaseWrapper::Database) V4THROW_REFERENCE("Not a SQLDatabase object"); - const FunctionObject *callback = ctx->argc() ? ctx->args()[0].as() : 0; + const FunctionObject *callback = callData->argc ? callData->args[0].as() : 0; if (!callback) V4THROW_SQL(SQLEXCEPTION_UNKNOWN_ERR, QQmlEngine::tr("transaction: missing callback")); @@ -475,17 +466,17 @@ static ReturnedValue qmlsqldatabase_transaction_shared(CallContext *ctx, bool re db.rollback(); } - return Encode::undefined(); + RETURN_UNDEFINED(); } -static ReturnedValue qmlsqldatabase_transaction(CallContext *ctx) +static void qmlsqldatabase_transaction(const QV4::BuiltinFunction *f, QV4::Scope &scope, QV4::CallData *callData) { - return qmlsqldatabase_transaction_shared(ctx, false); + qmlsqldatabase_transaction_shared(f, scope, callData, false); } -static ReturnedValue qmlsqldatabase_read_transaction(CallContext *ctx) +static void qmlsqldatabase_read_transaction(const QV4::BuiltinFunction *f, QV4::Scope &scope, QV4::CallData *callData) { - return qmlsqldatabase_transaction_shared(ctx, true); + qmlsqldatabase_transaction_shared(f, scope, callData, true); } QQmlSqlDatabaseData::QQmlSqlDatabaseData(ExecutionEngine *v4) diff --git a/src/particles/qquickv4particledata.cpp b/src/particles/qquickv4particledata.cpp index 967652f31a..e8376f1c27 100644 --- a/src/particles/qquickv4particledata.cpp +++ b/src/particles/qquickv4particledata.cpp @@ -296,123 +296,112 @@ public: QV4::PersistentValue proto; }; -static QV4::ReturnedValue particleData_discard(QV4::CallContext *ctx) +static void particleData_discard(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData) { - QV4::Scope scope(ctx); - QV4::Scoped r(scope, ctx->thisObject()); + QV4::Scoped r(scope, callData->thisObject); if (!r || !r->d()->datum) - return ctx->engine()->throwError(QStringLiteral("Not a valid ParticleData object")); + RETURN_RESULT(scope.engine->throwError(QStringLiteral("Not a valid ParticleData object"))); r->d()->datum->lifeSpan = 0; //Don't kill(), because it could still be in the middle of being created - return QV4::Encode::undefined(); + RETURN_RESULT(QV4::Encode::undefined()); } -static QV4::ReturnedValue particleData_lifeLeft(QV4::CallContext *ctx) +static void particleData_lifeLeft(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData) { - QV4::Scope scope(ctx); - QV4::Scoped r(scope, ctx->thisObject()); + QV4::Scoped r(scope, callData->thisObject); if (!r || !r->d()->datum) - return ctx->engine()->throwError(QStringLiteral("Not a valid ParticleData object")); + RETURN_RESULT(scope.engine->throwError(QStringLiteral("Not a valid ParticleData object"))); - return QV4::Encode(r->d()->datum->lifeLeft(r->d()->particleSystem)); + RETURN_RESULT(QV4::Encode(r->d()->datum->lifeLeft(r->d()->particleSystem))); } -static QV4::ReturnedValue particleData_curSize(QV4::CallContext *ctx) +static void particleData_curSize(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData) { - QV4::Scope scope(ctx); - QV4::Scoped r(scope, ctx->thisObject()); + QV4::Scoped r(scope, callData->thisObject); if (!r || !r->d()->datum) - return ctx->engine()->throwError(QStringLiteral("Not a valid ParticleData object")); + RETURN_RESULT(scope.engine->throwError(QStringLiteral("Not a valid ParticleData object"))); - return QV4::Encode(r->d()->datum->curSize(r->d()->particleSystem)); + RETURN_RESULT(QV4::Encode(r->d()->datum->curSize(r->d()->particleSystem))); } -#define COLOR_GETTER_AND_SETTER(VAR, NAME) static QV4::ReturnedValue particleData_get_ ## NAME (QV4::CallContext *ctx) \ +#define COLOR_GETTER_AND_SETTER(VAR, NAME) static void particleData_get_ ## NAME (const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData) \ { \ - QV4::Scope scope(ctx); \ - QV4::Scoped r(scope, ctx->thisObject()); \ + QV4::Scoped r(scope, callData->thisObject); \ if (!r || !r->d()->datum) \ - ctx->engine()->throwError(QStringLiteral("Not a valid ParticleData object")); \ + RETURN_RESULT(scope.engine->throwError(QStringLiteral("Not a valid ParticleData object"))); \ \ - return QV4::Encode((r->d()->datum->color. VAR )/255.0);\ + RETURN_RESULT(QV4::Encode((r->d()->datum->color. VAR )/255.0));\ }\ \ -static QV4::ReturnedValue particleData_set_ ## NAME (QV4::CallContext *ctx)\ +static void particleData_set_ ## NAME (const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData)\ {\ - QV4::Scope scope(ctx); \ - QV4::Scoped r(scope, ctx->thisObject()); \ + QV4::Scoped r(scope, callData->thisObject); \ if (!r || !r->d()->datum)\ - ctx->engine()->throwError(QStringLiteral("Not a valid ParticleData object"));\ + RETURN_RESULT(scope.engine->throwError(QStringLiteral("Not a valid ParticleData object")));\ \ - double d = ctx->argc() ? ctx->args()[0].toNumber() : 0; \ + double d = callData->argc ? callData->args[0].toNumber() : 0; \ r->d()->datum->color. VAR = qMin(255, qMax(0, (int)::floor(d * 255.0)));\ - return QV4::Encode::undefined(); \ + RETURN_UNDEFINED(); \ } -#define SEMIBOOL_GETTER_AND_SETTER(VARIABLE) static QV4::ReturnedValue particleData_get_ ## VARIABLE (QV4::CallContext *ctx) \ +#define SEMIBOOL_GETTER_AND_SETTER(VARIABLE) static void particleData_get_ ## VARIABLE (const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData) \ { \ - QV4::Scope scope(ctx); \ - QV4::Scoped r(scope, ctx->thisObject()); \ + QV4::Scoped r(scope, callData->thisObject); \ if (!r || !r->d()->datum) \ - ctx->engine()->throwError(QStringLiteral("Not a valid ParticleData object")); \ + RETURN_RESULT(scope.engine->throwError(QStringLiteral("Not a valid ParticleData object"))); \ \ - return QV4::Encode(r->d()->datum-> VARIABLE);\ + RETURN_RESULT(QV4::Encode(r->d()->datum-> VARIABLE));\ }\ \ -static QV4::ReturnedValue particleData_set_ ## VARIABLE (QV4::CallContext *ctx)\ +static void particleData_set_ ## VARIABLE (const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData)\ {\ - QV4::Scope scope(ctx); \ - QV4::Scoped r(scope, ctx->thisObject()); \ + QV4::Scoped r(scope, callData->thisObject); \ if (!r || !r->d()->datum)\ - ctx->engine()->throwError(QStringLiteral("Not a valid ParticleData object"));\ + RETURN_RESULT(scope.engine->throwError(QStringLiteral("Not a valid ParticleData object")));\ \ - r->d()->datum-> VARIABLE = (ctx->argc() && ctx->args()[0].toBoolean()) ? 1.0 : 0.0;\ - return QV4::Encode::undefined(); \ + r->d()->datum-> VARIABLE = (callData->argc && callData->args[0].toBoolean()) ? 1.0 : 0.0;\ + RETURN_UNDEFINED(); \ } -#define FLOAT_GETTER_AND_SETTER(VARIABLE) static QV4::ReturnedValue particleData_get_ ## VARIABLE (QV4::CallContext *ctx) \ +#define FLOAT_GETTER_AND_SETTER(VARIABLE) static void particleData_get_ ## VARIABLE (const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData) \ { \ - QV4::Scope scope(ctx); \ - QV4::Scoped r(scope, ctx->thisObject()); \ + QV4::Scoped r(scope, callData->thisObject); \ if (!r || !r->d()->datum) \ - ctx->engine()->throwError(QStringLiteral("Not a valid ParticleData object")); \ + RETURN_RESULT(scope.engine->throwError(QStringLiteral("Not a valid ParticleData object"))); \ \ - return QV4::Encode(r->d()->datum-> VARIABLE);\ + RETURN_RESULT(QV4::Encode(r->d()->datum-> VARIABLE));\ }\ \ -static QV4::ReturnedValue particleData_set_ ## VARIABLE (QV4::CallContext *ctx)\ +static void particleData_set_ ## VARIABLE (const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData)\ {\ - QV4::Scope scope(ctx); \ - QV4::Scoped r(scope, ctx->thisObject()); \ + QV4::Scoped r(scope, callData->thisObject); \ if (!r || !r->d()->datum)\ - ctx->engine()->throwError(QStringLiteral("Not a valid ParticleData object"));\ + RETURN_RESULT(scope.engine->throwError(QStringLiteral("Not a valid ParticleData object")));\ \ - r->d()->datum-> VARIABLE = ctx->argc() ? ctx->args()[0].toNumber() : qt_qnan();\ - return QV4::Encode::undefined(); \ + r->d()->datum-> VARIABLE = callData->argc ? callData->args[0].toNumber() : qt_qnan();\ + RETURN_UNDEFINED(); \ } -#define FAKE_FLOAT_GETTER_AND_SETTER(VARIABLE, GETTER, SETTER) static QV4::ReturnedValue particleData_get_ ## VARIABLE (QV4::CallContext *ctx) \ +#define FAKE_FLOAT_GETTER_AND_SETTER(VARIABLE, GETTER, SETTER) static void particleData_get_ ## VARIABLE (const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData) \ { \ - QV4::Scope scope(ctx); \ - QV4::Scoped r(scope, ctx->thisObject()); \ + QV4::Scoped r(scope, callData->thisObject); \ if (!r || !r->d()->datum) \ - ctx->engine()->throwError(QStringLiteral("Not a valid ParticleData object")); \ + RETURN_RESULT(scope.engine->throwError(QStringLiteral("Not a valid ParticleData object"))); \ \ - return QV4::Encode(r->d()->datum-> GETTER (r->d()->particleSystem));\ + RETURN_RESULT(QV4::Encode(r->d()->datum-> GETTER (r->d()->particleSystem)));\ }\ \ -static QV4::ReturnedValue particleData_set_ ## VARIABLE (QV4::CallContext *ctx)\ +static void particleData_set_ ## VARIABLE (const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData)\ {\ - QV4::Scope scope(ctx); \ - QV4::Scoped r(scope, ctx->thisObject()); \ + QV4::Scoped r(scope, callData->thisObject); \ if (!r || !r->d()->datum)\ - ctx->engine()->throwError(QStringLiteral("Not a valid ParticleData object"));\ + RETURN_RESULT(scope.engine->throwError(QStringLiteral("Not a valid ParticleData object")));\ \ - r->d()->datum-> SETTER (ctx->argc() ? ctx->args()[0].toNumber() : qt_qnan(), r->d()->particleSystem);\ - return QV4::Encode::undefined(); \ + r->d()->datum-> SETTER (callData->argc ? callData->args[0].toNumber() : qt_qnan(), r->d()->particleSystem);\ + RETURN_UNDEFINED(); \ } #define REGISTER_ACCESSOR(PROTO, ENGINE, VARIABLE, NAME) \ diff --git a/src/qml/jsruntime/qv4engine.cpp b/src/qml/jsruntime/qv4engine.cpp index daab7ad279..cb666451bb 100644 --- a/src/qml/jsruntime/qv4engine.cpp +++ b/src/qml/jsruntime/qv4engine.cpp @@ -109,9 +109,9 @@ using namespace QV4; static QBasicAtomicInt engineSerial = Q_BASIC_ATOMIC_INITIALIZER(1); -static ReturnedValue throwTypeError(CallContext *ctx) +void throwTypeError(const BuiltinFunction *, Scope &scope, CallData *) { - return ctx->engine()->throwTypeError(); + scope.result = scope.engine->throwTypeError(); } diff --git a/src/qml/jsruntime/qv4functionobject.cpp b/src/qml/jsruntime/qv4functionobject.cpp index 4be14c09ba..bd6eb17bb4 100644 --- a/src/qml/jsruntime/qv4functionobject.cpp +++ b/src/qml/jsruntime/qv4functionobject.cpp @@ -460,42 +460,6 @@ InternalClass *ScriptFunction::classForConstructor() const } - -DEFINE_OBJECT_VTABLE(OldBuiltinFunction); - -void Heap::OldBuiltinFunction::init(QV4::ExecutionContext *scope, QV4::String *name, ReturnedValue (*code)(QV4::CallContext *)) -{ - Heap::FunctionObject::init(scope, name); - this->code = code; -} - -void OldBuiltinFunction::construct(const Managed *f, Scope &scope, CallData *) -{ - scope.result = static_cast(f)->internalClass()->engine->throwTypeError(); -} - -void OldBuiltinFunction::call(const Managed *that, Scope &scope, CallData *callData) -{ - const OldBuiltinFunction *f = static_cast(that); - ExecutionEngine *v4 = scope.engine; - if (v4->hasException) { - scope.result = Encode::undefined(); - return; - } - CHECK_STACK_LIMITS(v4, scope); - - ExecutionContextSaver ctxSaver(scope); - - CallContext::Data *ctx = v4->memoryManager->allocSimpleCallContext(v4); - ctx->strictMode = f->scope()->strictMode; // ### needed? scope or parent context? - ctx->callData = callData; - v4->pushContext(ctx); - Q_ASSERT(v4->current == ctx); - - scope.result = f->d()->code(static_cast(v4->currentContext)); - v4->memoryManager->freeSimpleCallContext(); -} - DEFINE_OBJECT_VTABLE(BuiltinFunction); void Heap::BuiltinFunction::init(QV4::ExecutionContext *scope, QV4::String *name, void (*code)(const QV4::BuiltinFunction *, Scope &, CallData *)) diff --git a/src/qml/jsruntime/qv4functionobject_p.h b/src/qml/jsruntime/qv4functionobject_p.h index 354f6b2e3f..d691b869fe 100644 --- a/src/qml/jsruntime/qv4functionobject_p.h +++ b/src/qml/jsruntime/qv4functionobject_p.h @@ -192,21 +192,10 @@ struct FunctionPrototype: FunctionObject static void method_bind(const BuiltinFunction *, Scope &scope, CallData *callData); }; -struct Q_QML_EXPORT OldBuiltinFunction : FunctionObject { - V4_OBJECT2(OldBuiltinFunction, FunctionObject) - - static void construct(const Managed *, Scope &scope, CallData *); - static void call(const Managed *that, Scope &scope, CallData *callData); -}; - struct Q_QML_EXPORT BuiltinFunction : FunctionObject { V4_OBJECT2(BuiltinFunction, FunctionObject) V4_INTERNALCLASS(BuiltinFunction) - static Heap::OldBuiltinFunction *create(ExecutionContext *scope, String *name, ReturnedValue (*code)(CallContext *)) - { - return scope->engine()->memoryManager->allocObject(scope, name, code); - } static Heap::BuiltinFunction *create(ExecutionContext *scope, String *name, void (*code)(const BuiltinFunction *, Scope &, CallData *)) { return scope->engine()->memoryManager->allocObject(scope, name, code); diff --git a/src/qml/jsruntime/qv4object.cpp b/src/qml/jsruntime/qv4object.cpp index cac9d8ad7d..04336d4f88 100644 --- a/src/qml/jsruntime/qv4object.cpp +++ b/src/qml/jsruntime/qv4object.cpp @@ -162,17 +162,6 @@ void Object::defineDefaultProperty(const QString &name, const Value &value) defineDefaultProperty(s, value); } -void Object::defineDefaultProperty(const QString &name, ReturnedValue (*code)(CallContext *), int argumentCount) -{ - ExecutionEngine *e = engine(); - Scope scope(e); - ScopedString s(scope, e->newIdentifier(name)); - ExecutionContext *global = e->rootContext(); - ScopedFunctionObject function(scope, BuiltinFunction::create(global, s, code)); - function->defineReadonlyProperty(e->id_length(), Primitive::fromInt32(argumentCount)); - defineDefaultProperty(s, function); -} - void Object::defineDefaultProperty(const QString &name, void (*code)(const BuiltinFunction *, Scope &, CallData *), int argumentCount) { ExecutionEngine *e = engine(); @@ -184,16 +173,6 @@ void Object::defineDefaultProperty(const QString &name, void (*code)(const Built defineDefaultProperty(s, function); } -void Object::defineDefaultProperty(String *name, ReturnedValue (*code)(CallContext *), int argumentCount) -{ - ExecutionEngine *e = engine(); - Scope scope(e); - ExecutionContext *global = e->rootContext(); - ScopedFunctionObject function(scope, BuiltinFunction::create(global, name, code)); - function->defineReadonlyProperty(e->id_length(), Primitive::fromInt32(argumentCount)); - defineDefaultProperty(name, function); -} - void Object::defineDefaultProperty(String *name, void (*code)(const BuiltinFunction *, Scope &, CallData *), int argumentCount) { ExecutionEngine *e = engine(); @@ -204,25 +183,6 @@ void Object::defineDefaultProperty(String *name, void (*code)(const BuiltinFunct defineDefaultProperty(name, function); } -void Object::defineAccessorProperty(const QString &name, ReturnedValue (*getter)(CallContext *), ReturnedValue (*setter)(CallContext *)) -{ - ExecutionEngine *e = engine(); - Scope scope(e); - ScopedString s(scope, e->newIdentifier(name)); - defineAccessorProperty(s, getter, setter); -} - -void Object::defineAccessorProperty(String *name, ReturnedValue (*getter)(CallContext *), ReturnedValue (*setter)(CallContext *)) -{ - ExecutionEngine *v4 = engine(); - QV4::Scope scope(v4); - ScopedProperty p(scope); - ExecutionContext *global = v4->rootContext(); - p->setGetter(ScopedFunctionObject(scope, (getter ? BuiltinFunction::create(global, name, getter) : 0))); - p->setSetter(ScopedFunctionObject(scope, (setter ? BuiltinFunction::create(global, name, setter) : 0))); - insertMember(name, p, QV4::Attr_Accessor|QV4::Attr_NotConfigurable|QV4::Attr_NotEnumerable); -} - void Object::defineAccessorProperty(const QString &name, void (*getter)(const BuiltinFunction *, Scope &, CallData *), void (*setter)(const BuiltinFunction *, Scope &, CallData *)) { diff --git a/src/qml/jsruntime/qv4object_p.h b/src/qml/jsruntime/qv4object_p.h index cf04a84175..a9afe14129 100644 --- a/src/qml/jsruntime/qv4object_p.h +++ b/src/qml/jsruntime/qv4object_p.h @@ -255,12 +255,8 @@ struct Q_QML_EXPORT Object: Managed { insertMember(name, value, Attr_Data|Attr_NotEnumerable); } void defineDefaultProperty(const QString &name, const Value &value); - void defineDefaultProperty(const QString &name, ReturnedValue (*code)(CallContext *), int argumentCount = 0); void defineDefaultProperty(const QString &name, void (*code)(const BuiltinFunction *, Scope &, CallData *), int argumentCount = 0); - void defineDefaultProperty(String *name, ReturnedValue (*code)(CallContext *), int argumentCount = 0); void defineDefaultProperty(String *name, void (*code)(const BuiltinFunction *, Scope &, CallData *), int argumentCount = 0); - void defineAccessorProperty(const QString &name, ReturnedValue (*getter)(CallContext *), ReturnedValue (*setter)(CallContext *)); - void defineAccessorProperty(String *name, ReturnedValue (*getter)(CallContext *), ReturnedValue (*setter)(CallContext *)); void defineAccessorProperty(const QString &name, void (*getter)(const BuiltinFunction *, Scope &, CallData *), void (*setter)(const BuiltinFunction *, Scope &, CallData *)); void defineAccessorProperty(String *name, void (*getter)(const BuiltinFunction *, Scope &, CallData *), diff --git a/src/qml/util/qqmladaptormodel.cpp b/src/qml/util/qqmladaptormodel.cpp index b9d312d41f..d4aa2e19ed 100644 --- a/src/qml/util/qqmladaptormodel.cpp +++ b/src/qml/util/qqmladaptormodel.cpp @@ -61,14 +61,13 @@ public: V4_DEFINE_EXTENSION(QQmlAdaptorModelEngineData, engineData) -static QV4::ReturnedValue get_index(QV4::CallContext *ctx) +static void get_index(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData) { - QV4::Scope scope(ctx); - QV4::Scoped o(scope, ctx->thisObject().as()); + QV4::Scoped o(scope, callData->thisObject.as()); if (!o) - return ctx->engine()->throwTypeError(QStringLiteral("Not a valid VisualData object")); + RETURN_RESULT(scope.engine->throwTypeError(QStringLiteral("Not a valid VisualData object"))); - return QV4::Encode(o->d()->item->index); + RETURN_RESULT(QV4::Encode(o->d()->item->index)); } template static void setModelDataType(QMetaObjectBuilder *builder, M *metaType) @@ -195,19 +194,18 @@ public: dataType->watchedRoles += newRoles; } - static QV4::ReturnedValue get_hasModelChildren(QV4::CallContext *ctx) + static void get_hasModelChildren(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData) { - QV4::Scope scope(ctx); - QV4::Scoped o(scope, ctx->thisObject().as()); + QV4::Scoped o(scope, callData->thisObject.as()); if (!o) - return ctx->engine()->throwTypeError(QStringLiteral("Not a valid VisualData object")); + RETURN_RESULT(scope.engine->throwTypeError(QStringLiteral("Not a valid VisualData object"))); const QQmlAdaptorModel *const model = static_cast(o->d()->item)->type->model; if (o->d()->item->index >= 0 && *model) { const QAbstractItemModel * const aim = model->aim(); - return QV4::Encode(aim->hasChildren(aim->index(o->d()->item->index, 0, model->rootIndex))); + RETURN_RESULT(QV4::Encode(aim->hasChildren(aim->index(o->d()->item->index, 0, model->rootIndex)))); } else { - return QV4::Encode(false); + RETURN_RESULT(QV4::Encode(false)); } } @@ -583,27 +581,25 @@ public: } } - static QV4::ReturnedValue get_modelData(QV4::CallContext *ctx) + static void get_modelData(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData) { - QV4::Scope scope(ctx); - QV4::Scoped o(scope, ctx->thisObject().as()); + QV4::Scoped o(scope, callData->thisObject.as()); if (!o) - return ctx->engine()->throwTypeError(QStringLiteral("Not a valid VisualData object")); + RETURN_RESULT(scope.engine->throwTypeError(QStringLiteral("Not a valid VisualData object"))); - return scope.engine->fromVariant(static_cast(o->d()->item)->cachedData); + RETURN_RESULT(scope.engine->fromVariant(static_cast(o->d()->item)->cachedData)); } - static QV4::ReturnedValue set_modelData(QV4::CallContext *ctx) + static void set_modelData(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData) { - QV4::Scope scope(ctx); - QV4::Scoped o(scope, ctx->thisObject().as()); + QV4::Scoped o(scope, callData->thisObject.as()); if (!o) - return ctx->engine()->throwTypeError(QStringLiteral("Not a valid VisualData object")); - if (!ctx->argc()) - return ctx->engine()->throwTypeError(); + RETURN_RESULT(scope.engine->throwTypeError(QStringLiteral("Not a valid VisualData object"))); + if (!callData->argc) + RETURN_RESULT(scope.engine->throwTypeError()); - static_cast(o->d()->item)->setModelData(scope.engine->toVariant(ctx->args()[0], QVariant::Invalid)); - return QV4::Encode::undefined(); + static_cast(o->d()->item)->setModelData(scope.engine->toVariant(callData->args[0], QVariant::Invalid)); + RETURN_RESULT(QV4::Encode::undefined()); } QV4::ReturnedValue get() -- cgit v1.2.3 From 8bc243f569e3feb1005fbca426bf24f59c38af2e Mon Sep 17 00:00:00 2001 From: Lars Knoll Date: Fri, 19 May 2017 15:50:22 +0200 Subject: Move the engine() accessor from Object to Managed We can easily do this now that Managed has a pointer to an internal class (which always has a back pointer to the ExecutionEngine). Remove the extra engine pointer from ExecutionContext, and clean up tow methods in String. Change-Id: I98d750b1afbdeadf42e66ae0c92c48db1a7adc31 Reviewed-by: Robin Burchell --- .../qmldbg_debugger/qv4datacollector.cpp | 2 +- .../qmltooling/qmldbg_debugger/qv4debugger.cpp | 2 +- .../qqmlnativedebugservice.cpp | 6 +-- src/qml/jsapi/qjsvalue.cpp | 4 +- src/qml/jsruntime/qv4argumentsobject.cpp | 21 +++++----- src/qml/jsruntime/qv4context.cpp | 47 +++++++++------------- src/qml/jsruntime/qv4context_p.h | 17 +++----- src/qml/jsruntime/qv4engine.cpp | 4 +- src/qml/jsruntime/qv4functionobject.cpp | 12 +++--- src/qml/jsruntime/qv4globalobject.cpp | 2 +- src/qml/jsruntime/qv4managed_p.h | 1 + src/qml/jsruntime/qv4object.cpp | 18 ++++----- src/qml/jsruntime/qv4object_p.h | 2 - src/qml/jsruntime/qv4qmlcontext.cpp | 6 +-- src/qml/jsruntime/qv4qobjectwrapper.cpp | 4 +- src/qml/jsruntime/qv4scopedvalue_p.h | 2 +- src/qml/jsruntime/qv4string.cpp | 4 +- src/qml/jsruntime/qv4string_p.h | 6 +-- src/qml/jsruntime/qv4vme_moth.cpp | 2 +- src/qml/memory/qv4mm_p.h | 4 +- src/qml/qml/qqmlxmlhttprequest.cpp | 4 +- 21 files changed, 76 insertions(+), 94 deletions(-) (limited to 'src') diff --git a/src/plugins/qmltooling/qmldbg_debugger/qv4datacollector.cpp b/src/plugins/qmltooling/qmldbg_debugger/qv4datacollector.cpp index b4b95f6713..755235a3a7 100644 --- a/src/plugins/qmltooling/qmldbg_debugger/qv4datacollector.cpp +++ b/src/plugins/qmltooling/qmldbg_debugger/qv4datacollector.cpp @@ -76,7 +76,7 @@ QV4::Heap::CallContext *QV4DataCollector::findScope(QV4::ExecutionContext *ctxt, if (!ctxt) return 0; - QV4::Scope s(ctxt->d()->engine); + QV4::Scope s(ctxt); QV4::ScopedContext ctx(s, ctxt); for (; scope > 0 && ctx; --scope) ctx = ctx->d()->outer; diff --git a/src/plugins/qmltooling/qmldbg_debugger/qv4debugger.cpp b/src/plugins/qmltooling/qmldbg_debugger/qv4debugger.cpp index 9e8be84c33..b82df9c6a9 100644 --- a/src/plugins/qmltooling/qmldbg_debugger/qv4debugger.cpp +++ b/src/plugins/qmltooling/qmldbg_debugger/qv4debugger.cpp @@ -260,7 +260,7 @@ QV4::Function *QV4Debugger::getFunction() const if (QV4::Function *function = context->getFunction()) return function; else - return context->d()->engine->globalCode; + return m_engine->globalCode; } void QV4Debugger::runJobUnpaused() diff --git a/src/plugins/qmltooling/qmldbg_nativedebugger/qqmlnativedebugservice.cpp b/src/plugins/qmltooling/qmldbg_nativedebugger/qqmlnativedebugservice.cpp index 7f842419e7..2015118d95 100644 --- a/src/plugins/qmltooling/qmldbg_nativedebugger/qqmlnativedebugservice.cpp +++ b/src/plugins/qmltooling/qmldbg_nativedebugger/qqmlnativedebugservice.cpp @@ -465,7 +465,7 @@ void NativeDebugger::handleVariables(QJsonObject *response, const QJsonObject &a } TRACE_PROTOCOL("Context: " << executionContext); - QV4::ExecutionEngine *engine = executionContext->d()->engine; + QV4::ExecutionEngine *engine = executionContext->engine(); if (!engine) { setError(response, QStringLiteral("No execution engine passed")); return; @@ -517,7 +517,7 @@ void NativeDebugger::handleExpressions(QJsonObject *response, const QJsonObject } TRACE_PROTOCOL("Context: " << executionContext); - QV4::ExecutionEngine *engine = executionContext->d()->engine; + QV4::ExecutionEngine *engine = executionContext->engine(); if (!engine) { setError(response, QStringLiteral("No execution engine passed")); return; @@ -669,7 +669,7 @@ QV4::Function *NativeDebugger::getFunction() const if (QV4::Function *function = context->getFunction()) return function; else - return context->d()->engine->globalCode; + return m_engine->globalCode; } void NativeDebugger::pauseAndWait() diff --git a/src/qml/jsapi/qjsvalue.cpp b/src/qml/jsapi/qjsvalue.cpp index bab2e633a7..3a3cf46ddb 100644 --- a/src/qml/jsapi/qjsvalue.cpp +++ b/src/qml/jsapi/qjsvalue.cpp @@ -1019,7 +1019,7 @@ QJSValue QJSValue::property(const QString& name) const if (idx < UINT_MAX) return property(idx); - s->makeIdentifier(engine); + s->makeIdentifier(); QV4::ScopedValue result(scope, o->get(s)); if (engine->hasException) result = engine->catchException(); @@ -1090,7 +1090,7 @@ void QJSValue::setProperty(const QString& name, const QJSValue& value) return; } - s->makeIdentifier(scope.engine); + s->makeIdentifier(); QV4::ScopedValue v(scope, QJSValuePrivate::convertedToValue(engine, value)); o->put(s, v); if (engine->hasException) diff --git a/src/qml/jsruntime/qv4argumentsobject.cpp b/src/qml/jsruntime/qv4argumentsobject.cpp index 9354bcb1a3..6ab838c387 100644 --- a/src/qml/jsruntime/qv4argumentsobject.cpp +++ b/src/qml/jsruntime/qv4argumentsobject.cpp @@ -53,13 +53,13 @@ void Heap::ArgumentsObject::init(QV4::CallContext *context) this->context = context->d(); Q_ASSERT(vtable() == QV4::ArgumentsObject::staticVTable()); - ExecutionEngine *v4 = context->d()->engine; + ExecutionEngine *v4 = context->engine(); Scope scope(v4); Scoped args(scope, this); if (context->d()->strictMode) { - Q_ASSERT(CalleePropertyIndex == args->internalClass()->find(context->d()->engine->id_callee())); - Q_ASSERT(CallerPropertyIndex == args->internalClass()->find(context->d()->engine->id_caller())); + Q_ASSERT(CalleePropertyIndex == args->internalClass()->find(v4->id_callee())); + Q_ASSERT(CallerPropertyIndex == args->internalClass()->find(v4->id_caller())); *args->propertyData(CalleePropertyIndex + QV4::Object::GetterOffset) = v4->thrower(); *args->propertyData(CalleePropertyIndex + QV4::Object::SetterOffset) = v4->thrower(); *args->propertyData(CallerPropertyIndex + QV4::Object::GetterOffset) = v4->thrower(); @@ -69,10 +69,10 @@ void Heap::ArgumentsObject::init(QV4::CallContext *context) args->arrayPut(0, context->args(), context->argc()); args->d()->fullyCreated = true; } else { - Q_ASSERT(CalleePropertyIndex == args->internalClass()->find(context->d()->engine->id_callee())); + Q_ASSERT(CalleePropertyIndex == args->internalClass()->find(v4->id_callee())); *args->propertyData(CalleePropertyIndex) = context->d()->function->asReturnedValue(); } - Q_ASSERT(LengthPropertyIndex == args->internalClass()->find(context->d()->engine->id_length())); + Q_ASSERT(LengthPropertyIndex == args->internalClass()->find(v4->id_length())); *args->propertyData(LengthPropertyIndex) = Primitive::fromInt32(context->d()->callData->argc); } @@ -81,18 +81,19 @@ void ArgumentsObject::fullyCreate() if (fullyCreated()) return; + Scope scope(engine()); + uint argCount = context()->callData->argc; uint numAccessors = qMin(context()->formalParameterCount(), argCount); ArrayData::realloc(this, Heap::ArrayData::Sparse, argCount, true); - context()->engine->requireArgumentsAccessors(numAccessors); + scope.engine->requireArgumentsAccessors(numAccessors); - Scope scope(engine()); Scoped md(scope, d()->mappedArguments); if (numAccessors) { - d()->mappedArguments = md->allocate(engine(), numAccessors); + d()->mappedArguments = md->allocate(scope.engine, numAccessors); for (uint i = 0; i < numAccessors; ++i) { d()->mappedArguments->data[i] = context()->callData->args[i]; - arraySet(i, context()->engine->argumentsAccessors + i, Attr_Accessor); + arraySet(i, scope.engine->argumentsAccessors + i, Attr_Accessor); } } arrayPut(numAccessors, context()->callData->args + numAccessors, argCount - numAccessors); @@ -114,7 +115,7 @@ bool ArgumentsObject::defineOwnProperty(ExecutionEngine *engine, uint index, con uint numAccessors = qMin((int)context()->formalParameterCount(), context()->callData->argc); if (pd && index < (uint)numAccessors) isMapped = arrayData()->attributes(index).isAccessor() && - pd->getter() == context()->engine->argumentsAccessors[index].getter(); + pd->getter() == scope.engine->argumentsAccessors[index].getter(); if (isMapped) { Q_ASSERT(arrayData()); diff --git a/src/qml/jsruntime/qv4context.cpp b/src/qml/jsruntime/qv4context.cpp index 03595aa59d..3ff864d7b9 100644 --- a/src/qml/jsruntime/qv4context.cpp +++ b/src/qml/jsruntime/qv4context.cpp @@ -66,9 +66,9 @@ DEFINE_MANAGED_VTABLE(GlobalContext); Heap::CallContext *ExecutionContext::newCallContext(Function *function, CallData *callData) { - Heap::CallContext *c = d()->engine->memoryManager->allocManaged( + Heap::CallContext *c = engine()->memoryManager->allocManaged( requiredMemoryForExecutionContect(function, callData->argc)); - c->init(d()->engine, Heap::ExecutionContext::Type_CallContext); + c->init(Heap::ExecutionContext::Type_CallContext); c->v4Function = function; @@ -95,27 +95,16 @@ Heap::CallContext *ExecutionContext::newCallContext(Function *function, CallData return c; } -Heap::CallContext *Heap::CallContext::createSimpleContext(ExecutionEngine *v4) -{ - Heap::CallContext *ctxt = v4->memoryManager->allocSimpleCallContext(v4); - return ctxt; -} - -void Heap::CallContext::freeSimpleCallContext() -{ - engine->memoryManager->freeSimpleCallContext(); -} - Heap::WithContext *ExecutionContext::newWithContext(Heap::Object *with) { - return d()->engine->memoryManager->alloc(d(), with); + return engine()->memoryManager->alloc(d(), with); } Heap::CatchContext *ExecutionContext::newCatchContext(Heap::String *exceptionVarName, ReturnedValue exceptionValue) { Scope scope(this); ScopedValue e(scope, exceptionValue); - return d()->engine->memoryManager->alloc(d(), exceptionVarName, e); + return engine()->memoryManager->alloc(d(), exceptionVarName, e); } void ExecutionContext::createMutableBinding(String *name, bool deletable) @@ -165,14 +154,14 @@ void ExecutionContext::createMutableBinding(String *name, bool deletable) void Heap::GlobalContext::init(ExecutionEngine *eng) { - Heap::ExecutionContext::init(eng, Heap::ExecutionContext::Type_GlobalContext); + Heap::ExecutionContext::init(Heap::ExecutionContext::Type_GlobalContext); global = eng->globalObject->d(); } void Heap::CatchContext::init(ExecutionContext *outerContext, String *exceptionVarName, const Value &exceptionValue) { - Heap::ExecutionContext::init(outerContext->engine, Heap::ExecutionContext::Type_CatchContext); + Heap::ExecutionContext::init(Heap::ExecutionContext::Type_CatchContext); outer = outerContext; strictMode = outer->strictMode; callData = outer->callData; @@ -209,7 +198,7 @@ unsigned int CallContext::variableCount() const bool ExecutionContext::deleteProperty(String *name) { - name->makeIdentifier(engine()); + name->makeIdentifier(); Identifier *id = name->identifier(); Scope scope(this); @@ -339,7 +328,7 @@ void QV4::ExecutionContext::simpleCall(Scope &scope, CallData *callData, Functio ExecutionContextSaver ctxSaver(scope); - CallContext::Data *ctx = scope.engine->memoryManager->allocSimpleCallContext(scope.engine); + CallContext::Data *ctx = scope.engine->memoryManager->allocSimpleCallContext(); ctx->strictMode = function->isStrict(); ctx->callData = callData; @@ -364,7 +353,7 @@ void QV4::ExecutionContext::simpleCall(Scope &scope, CallData *callData, Functio void ExecutionContext::setProperty(String *name, const Value &value) { - name->makeIdentifier(engine()); + name->makeIdentifier(); Identifier *id = name->identifier(); Scope scope(this); @@ -428,21 +417,21 @@ void ExecutionContext::setProperty(String *name, const Value &value) } } - if (d()->strictMode || name->equals(d()->engine->id_this())) { + if (d()->strictMode || name->equals(engine()->id_this())) { ScopedValue n(scope, name->asReturnedValue()); engine()->throwReferenceError(n); return; } - d()->engine->globalObject->put(name, value); + engine()->globalObject->put(name, value); } ReturnedValue ExecutionContext::getProperty(String *name) { Scope scope(this); ScopedValue v(scope); - name->makeIdentifier(scope.engine); + name->makeIdentifier(); - if (name->equals(d()->engine->id_this())) + if (name->equals(engine()->id_this())) return thisObject().asReturnedValue(); bool hasWith = false; @@ -479,7 +468,7 @@ ReturnedValue ExecutionContext::getProperty(String *name) case Heap::ExecutionContext::Type_SimpleCallContext: { Heap::CallContext *c = static_cast(ctx->d()); if (c->v4Function && (c->v4Function->needsActivation() || hasWith || hasCatchScope)) { - name->makeIdentifier(engine()); + name->makeIdentifier(); Identifier *id = name->identifier(); uint index = c->v4Function->internalClass->find(id); @@ -520,9 +509,9 @@ ReturnedValue ExecutionContext::getPropertyAndBase(String *name, Value *base) Scope scope(this); ScopedValue v(scope); base->setM(0); - name->makeIdentifier(scope.engine); + name->makeIdentifier(); - if (name->equals(d()->engine->id_this())) + if (name->equals(engine()->id_this())) return thisObject().asReturnedValue(); bool hasWith = false; @@ -560,7 +549,7 @@ ReturnedValue ExecutionContext::getPropertyAndBase(String *name, Value *base) case Heap::ExecutionContext::Type_SimpleCallContext: { Heap::CallContext *c = static_cast(ctx->d()); if (c->v4Function && (c->v4Function->needsActivation() || hasWith || hasCatchScope)) { - name->makeIdentifier(engine()); + name->makeIdentifier(); Identifier *id = name->identifier(); uint index = c->v4Function->internalClass->find(id); @@ -600,7 +589,7 @@ ReturnedValue ExecutionContext::getPropertyAndBase(String *name, Value *base) Function *ExecutionContext::getFunction() const { - Scope scope(d()->engine); + Scope scope(engine()); ScopedContext it(scope, this->d()); for (; it; it = it->d()->outer) { if (const CallContext *callCtx = it->asCallContext()) diff --git a/src/qml/jsruntime/qv4context_p.h b/src/qml/jsruntime/qv4context_p.h index 89ff6dc957..0b63922a4b 100644 --- a/src/qml/jsruntime/qv4context_p.h +++ b/src/qml/jsruntime/qv4context_p.h @@ -105,7 +105,6 @@ struct QmlContext; // can use the Members macro struct ExecutionContextData { CallData *callData; - ExecutionEngine *engine; ExecutionContext *outer; Lookup *lookups; const QV4::Value *constantTable; @@ -120,8 +119,7 @@ struct ExecutionContextData { Q_STATIC_ASSERT(std::is_standard_layout::value); Q_STATIC_ASSERT(offsetof(ExecutionContextData, callData) == 0); -Q_STATIC_ASSERT(offsetof(ExecutionContextData, engine) == offsetof(ExecutionContextData, callData) + QT_POINTER_SIZE); -Q_STATIC_ASSERT(offsetof(ExecutionContextData, outer) == offsetof(ExecutionContextData, engine) + QT_POINTER_SIZE); +Q_STATIC_ASSERT(offsetof(ExecutionContextData, outer) == offsetof(ExecutionContextData, callData) + QT_POINTER_SIZE); Q_STATIC_ASSERT(offsetof(ExecutionContextData, lookups) == offsetof(ExecutionContextData, outer) + QT_POINTER_SIZE); Q_STATIC_ASSERT(offsetof(ExecutionContextData, constantTable) == offsetof(ExecutionContextData, lookups) + QT_POINTER_SIZE); Q_STATIC_ASSERT(offsetof(ExecutionContextData, compilationUnit) == offsetof(ExecutionContextData, constantTable) + QT_POINTER_SIZE); @@ -141,11 +139,10 @@ struct ExecutionContext : Base, public ExecutionContextData { Type_CallContext = 0x6 }; - void init(ExecutionEngine *engine, ContextType t) + void init(ContextType t) { Base::init(); - this->engine = engine; type = t; lineNumber = -1; } @@ -172,12 +169,10 @@ struct CallContextSizeStruct : public ExecutionContext, public CallContextData { struct CallContext : ExecutionContext, public CallContextData { static Q_CONSTEXPR size_t baseOffset = sizeof(CallContextSizeStruct) - sizeof(CallContextData); - static CallContext *createSimpleContext(ExecutionEngine *v4); - void freeSimpleCallContext(); - void init(ExecutionEngine *engine, ContextType t = Type_SimpleCallContext) + void init(ContextType t = Type_SimpleCallContext) { - ExecutionContext::init(engine, t); + ExecutionContext::init(t); } inline unsigned int formalParameterCount() const; @@ -204,7 +199,7 @@ V4_ASSERT_IS_TRIVIAL(CatchContext) struct WithContext : ExecutionContext { void init(ExecutionContext *outerContext, Object *with) { - Heap::ExecutionContext::init(outerContext->engine, Heap::ExecutionContext::Type_WithContext); + Heap::ExecutionContext::init(Heap::ExecutionContext::Type_WithContext); outer = outerContext; callData = outer->callData; lookups = outer->lookups; @@ -230,8 +225,6 @@ struct Q_QML_EXPORT ExecutionContext : public Managed Q_MANAGED_TYPE(ExecutionContext) V4_INTERNALCLASS(ExecutionContext) - ExecutionEngine *engine() const { return d()->engine; } - Heap::CallContext *newCallContext(Function *f, CallData *callData); Heap::WithContext *newWithContext(Heap::Object *with); Heap::CatchContext *newCatchContext(Heap::String *exceptionVarName, ReturnedValue exceptionValue); diff --git a/src/qml/jsruntime/qv4engine.cpp b/src/qml/jsruntime/qv4engine.cpp index cb666451bb..0cb1b1ee13 100644 --- a/src/qml/jsruntime/qv4engine.cpp +++ b/src/qml/jsruntime/qv4engine.cpp @@ -868,8 +868,8 @@ static inline char *v4StackTrace(const ExecutionContext *context) QString result; QTextStream str(&result); str << "stack=["; - if (context && context->d()->engine) { - const QVector stackTrace = context->d()->engine->stackTrace(20); + if (context && context->engine()) { + const QVector stackTrace = context->engine()->stackTrace(20); for (int i = 0; i < stackTrace.size(); ++i) { if (i) str << ','; diff --git a/src/qml/jsruntime/qv4functionobject.cpp b/src/qml/jsruntime/qv4functionobject.cpp index bd6eb17bb4..9eb9d2ad36 100644 --- a/src/qml/jsruntime/qv4functionobject.cpp +++ b/src/qml/jsruntime/qv4functionobject.cpp @@ -122,7 +122,7 @@ void FunctionObject::init(String *n, bool createProto) Q_ASSERT(internalClass() && internalClass()->find(s.engine->id_prototype()) == Heap::FunctionObject::Index_Prototype); if (createProto) { - ScopedObject proto(s, scope()->engine->newObject(s.engine->internalClasses[EngineBase::Class_ObjectProto], s.engine->objectPrototype())); + ScopedObject proto(s, s.engine->newObject(s.engine->internalClasses[EngineBase::Class_ObjectProto], s.engine->objectPrototype())); Q_ASSERT(s.engine->internalClasses[EngineBase::Class_ObjectProto]->find(s.engine->id_constructor()) == Heap::FunctionObject::Index_ProtoConstructor); *proto->propertyData(Heap::FunctionObject::Index_ProtoConstructor) = this->asReturnedValue(); *propertyData(Heap::FunctionObject::Index_Prototype) = proto.asReturnedValue(); @@ -136,7 +136,7 @@ void FunctionObject::init(String *n, bool createProto) ReturnedValue FunctionObject::name() const { - return get(scope()->engine->id_name()); + return get(scope()->internalClass->engine->id_name()); } void FunctionObject::construct(const Managed *that, Scope &scope, CallData *) @@ -160,7 +160,7 @@ void FunctionObject::markObjects(Heap::Base *that, ExecutionEngine *e) Heap::FunctionObject *FunctionObject::createScriptFunction(ExecutionContext *scope, Function *function) { - return scope->d()->engine->memoryManager->allocObject(scope, function); + return scope->engine()->memoryManager->allocObject(scope, function); } bool FunctionObject::isBinding() const @@ -439,8 +439,8 @@ void Heap::ScriptFunction::init(QV4::ExecutionContext *scope, Function *function ScopedProperty pd(s); pd->value = s.engine->thrower(); pd->set = s.engine->thrower(); - f->insertMember(scope->d()->engine->id_caller(), pd, Attr_Accessor|Attr_NotConfigurable|Attr_NotEnumerable); - f->insertMember(scope->d()->engine->id_arguments(), pd, Attr_Accessor|Attr_NotConfigurable|Attr_NotEnumerable); + f->insertMember(s.engine->id_caller(), pd, Attr_Accessor|Attr_NotConfigurable|Attr_NotEnumerable); + f->insertMember(s.engine->id_arguments(), pd, Attr_Accessor|Attr_NotConfigurable|Attr_NotEnumerable); } } @@ -497,7 +497,7 @@ void IndexedBuiltinFunction::call(const Managed *that, Scope &scope, CallData *c ExecutionContextSaver ctxSaver(scope); - CallContext::Data *ctx = v4->memoryManager->allocSimpleCallContext(v4); + CallContext::Data *ctx = v4->memoryManager->allocSimpleCallContext(); ctx->strictMode = f->scope()->strictMode; // ### needed? scope or parent context? ctx->callData = callData; v4->pushContext(ctx); diff --git a/src/qml/jsruntime/qv4globalobject.cpp b/src/qml/jsruntime/qv4globalobject.cpp index f0630660d4..0916e8e110 100644 --- a/src/qml/jsruntime/qv4globalobject.cpp +++ b/src/qml/jsruntime/qv4globalobject.cpp @@ -332,8 +332,8 @@ DEFINE_OBJECT_VTABLE(EvalFunction); void Heap::EvalFunction::init(QV4::ExecutionContext *scope) { - Heap::FunctionObject::init(scope, scope->d()->engine->id_eval()); Scope s(scope); + Heap::FunctionObject::init(scope, s.engine->id_eval()); ScopedFunctionObject f(s, this); f->defineReadonlyProperty(s.engine->id_length(), Primitive::fromInt32(1)); } diff --git a/src/qml/jsruntime/qv4managed_p.h b/src/qml/jsruntime/qv4managed_p.h index 4c387a7fe7..6859334797 100644 --- a/src/qml/jsruntime/qv4managed_p.h +++ b/src/qml/jsruntime/qv4managed_p.h @@ -199,6 +199,7 @@ public: Q_MANAGED_TYPE(Invalid) InternalClass *internalClass() const { return d()->internalClass; } + inline ExecutionEngine *engine() const { return internalClass()->engine; } bool isListType() const { return d()->vtable()->type == Type_QmlSequence; } diff --git a/src/qml/jsruntime/qv4object.cpp b/src/qml/jsruntime/qv4object.cpp index 04336d4f88..98f5c7464f 100644 --- a/src/qml/jsruntime/qv4object.cpp +++ b/src/qml/jsruntime/qv4object.cpp @@ -254,7 +254,7 @@ void Object::getOwnProperty(String *name, PropertyAttributes *attrs, Property *p if (idx != UINT_MAX) return getOwnProperty(idx, attrs, p); - name->makeIdentifier(engine()); + name->makeIdentifier(); Identifier *id = name->identifier(); uint member = internalClass()->find(id); @@ -299,7 +299,7 @@ Value *Object::getValueOrSetter(String *name, PropertyAttributes *attrs) { Q_ASSERT(name->asArrayIndex() == UINT_MAX); - name->makeIdentifier(engine()); + name->makeIdentifier(); Identifier *id = name->identifier(); Heap::Object *o = d(); @@ -377,7 +377,7 @@ bool Object::hasOwnProperty(String *name) const if (idx != UINT_MAX) return hasOwnProperty(idx); - name->makeIdentifier(engine()); + name->makeIdentifier(); Identifier *id = name->identifier(); if (internalClass()->find(id) < UINT_MAX) @@ -437,7 +437,7 @@ PropertyAttributes Object::query(const Managed *m, String *name) if (idx != UINT_MAX) return queryIndexed(m, idx); - name->makeIdentifier(m->internalClass()->engine); + name->makeIdentifier(); Identifier *id = name->identifier(); const Object *o = static_cast(m); @@ -640,10 +640,10 @@ ReturnedValue Object::internalGet(String *name, bool *hasProperty) const if (idx != UINT_MAX) return getIndexed(idx, hasProperty); - Scope scope(engine()); - name->makeIdentifier(scope.engine); + name->makeIdentifier(); Identifier *id = name->identifier(); + Scope scope(engine()); ScopedObject o(scope, this); while (o) { uint idx = o->internalClass()->find(id); @@ -708,7 +708,7 @@ void Object::internalPut(String *name, const Value &value) if (idx != UINT_MAX) return putIndexed(idx, value); - name->makeIdentifier(engine()); + name->makeIdentifier(); Identifier *id = name->identifier(); uint member = internalClass()->find(id); @@ -862,7 +862,7 @@ bool Object::internalDeleteProperty(String *name) if (idx != UINT_MAX) return deleteIndexedProperty(idx); - name->makeIdentifier(engine()); + name->makeIdentifier(); uint memberIdx = internalClass()->find(name->identifier()); if (memberIdx != UINT_MAX) { @@ -901,7 +901,7 @@ bool Object::__defineOwnProperty__(ExecutionEngine *engine, String *name, const return __defineOwnProperty__(engine, idx, p, attrs); Scope scope(engine); - name->makeIdentifier(scope.engine); + name->makeIdentifier(); uint memberIndex; diff --git a/src/qml/jsruntime/qv4object_p.h b/src/qml/jsruntime/qv4object_p.h index a9afe14129..9592ff5d1b 100644 --- a/src/qml/jsruntime/qv4object_p.h +++ b/src/qml/jsruntime/qv4object_p.h @@ -273,8 +273,6 @@ struct Q_QML_EXPORT Object: Managed { } void insertMember(String *s, const Property *p, PropertyAttributes attributes); - inline ExecutionEngine *engine() const { return internalClass()->engine; } - bool isExtensible() const { return d()->internalClass->extensible; } // Array handling diff --git a/src/qml/jsruntime/qv4qmlcontext.cpp b/src/qml/jsruntime/qv4qmlcontext.cpp index ef1a1c11ed..91d65a70c9 100644 --- a/src/qml/jsruntime/qv4qmlcontext.cpp +++ b/src/qml/jsruntime/qv4qmlcontext.cpp @@ -300,7 +300,7 @@ void QmlContextWrapper::put(Managed *m, String *name, const Value &value) void Heap::QmlContext::init(QV4::ExecutionContext *outerContext, QV4::QmlContextWrapper *qml) { - Heap::ExecutionContext::init(outerContext->engine(), Heap::ExecutionContext::Type_QmlContext); + Heap::ExecutionContext::init(Heap::ExecutionContext::Type_QmlContext); outer = outerContext->d(); strictMode = false; callData = outer->callData; @@ -330,7 +330,7 @@ Heap::QmlContext *QmlContext::createWorkerContext(ExecutionContext *parent, cons qml->QV4::Object::put(QV4::ScopedString(scope, scope.engine->newString(QStringLiteral("WorkerScript"))), api); qml->setReadOnly(true); - Heap::QmlContext *c = parent->d()->engine->memoryManager->alloc(parent, qml); + Heap::QmlContext *c = scope.engine->memoryManager->alloc(parent, qml); Q_ASSERT(c->vtable() == staticVTable()); return c; } @@ -340,7 +340,7 @@ Heap::QmlContext *QmlContext::create(ExecutionContext *parent, QQmlContextData * Scope scope(parent); Scoped qml(scope, scope.engine->memoryManager->allocObject(context, scopeObject)); - Heap::QmlContext *c = parent->d()->engine->memoryManager->alloc(parent, qml); + Heap::QmlContext *c = scope.engine->memoryManager->alloc(parent, qml); Q_ASSERT(c->vtable() == staticVTable()); return c; } diff --git a/src/qml/jsruntime/qv4qobjectwrapper.cpp b/src/qml/jsruntime/qv4qobjectwrapper.cpp index f484d56040..d7978cc212 100644 --- a/src/qml/jsruntime/qv4qobjectwrapper.cpp +++ b/src/qml/jsruntime/qv4qobjectwrapper.cpp @@ -1688,7 +1688,7 @@ QV4::ReturnedValue CallArgument::toValue(QV4::ExecutionEngine *engine) ReturnedValue QObjectMethod::create(ExecutionContext *scope, QObject *object, int index) { Scope valueScope(scope); - Scoped method(valueScope, scope->d()->engine->memoryManager->allocObject(scope)); + Scoped method(valueScope, valueScope.engine->memoryManager->allocObject(scope)); method->d()->setObject(object); if (QQmlData *ddata = QQmlData::get(object)) @@ -1739,7 +1739,7 @@ QV4::ReturnedValue QObjectMethod::method_toString(QV4::ExecutionContext *ctx) co result = QLatin1String("null"); } - return ctx->d()->engine->newString(result)->asReturnedValue(); + return ctx->engine()->newString(result)->asReturnedValue(); } QV4::ReturnedValue QObjectMethod::method_destroy(QV4::ExecutionContext *ctx, const Value *args, int argc) const diff --git a/src/qml/jsruntime/qv4scopedvalue_p.h b/src/qml/jsruntime/qv4scopedvalue_p.h index bc882bbd95..04a0c74133 100644 --- a/src/qml/jsruntime/qv4scopedvalue_p.h +++ b/src/qml/jsruntime/qv4scopedvalue_p.h @@ -102,7 +102,7 @@ struct ScopedValue; struct Scope { inline Scope(ExecutionContext *ctx) - : engine(ctx->d()->engine) + : engine(ctx->engine()) , mark(engine->jsStackTop) , result(*engine->jsAlloca(1)) { diff --git a/src/qml/jsruntime/qv4string.cpp b/src/qml/jsruntime/qv4string.cpp index cde2131aab..1404ab6d9b 100644 --- a/src/qml/jsruntime/qv4string.cpp +++ b/src/qml/jsruntime/qv4string.cpp @@ -141,12 +141,12 @@ uint String::toUInt(bool *ok) const return UINT_MAX; } -void String::makeIdentifierImpl(ExecutionEngine *e) const +void String::makeIdentifierImpl() const { if (d()->largestSubLength) d()->simplifyString(); Q_ASSERT(!d()->largestSubLength); - e->identifierTable->identifier(this); + engine()->identifierTable->identifier(this); } void Heap::String::simplifyString() const diff --git a/src/qml/jsruntime/qv4string_p.h b/src/qml/jsruntime/qv4string_p.h index ad30165ce5..458a9edae6 100644 --- a/src/qml/jsruntime/qv4string_p.h +++ b/src/qml/jsruntime/qv4string_p.h @@ -176,13 +176,13 @@ struct Q_QML_PRIVATE_EXPORT String : public Managed { } uint toUInt(bool *ok) const; - void makeIdentifier(ExecutionEngine *e) const { + void makeIdentifier() const { if (d()->identifier) return; - makeIdentifierImpl(e); + makeIdentifierImpl(); } - void makeIdentifierImpl(ExecutionEngine *e) const; + void makeIdentifierImpl() const; static uint createHashValue(const QChar *ch, int length, uint *subtype) { diff --git a/src/qml/jsruntime/qv4vme_moth.cpp b/src/qml/jsruntime/qv4vme_moth.cpp index d662b1738d..9d65f67f0f 100644 --- a/src/qml/jsruntime/qv4vme_moth.cpp +++ b/src/qml/jsruntime/qv4vme_moth.cpp @@ -172,7 +172,7 @@ static QV4::Function *qt_v4ExtractFunction(QV4::ExecutionContext *context) if (QV4::Function *function = context->getFunction()) return function; else - return context->d()->engine->globalCode; + return context->engine()->globalCode; } static void qt_v4TriggerBreakpoint(const Breakpoint &bp, QV4::Function *function) diff --git a/src/qml/memory/qv4mm_p.h b/src/qml/memory/qv4mm_p.h index 69d3eeb93c..c5334a0dde 100644 --- a/src/qml/memory/qv4mm_p.h +++ b/src/qml/memory/qv4mm_p.h @@ -206,13 +206,13 @@ public: Q_DECL_CONSTEXPR static inline std::size_t align(std::size_t size) { return (size + Chunk::SlotSize - 1) & ~(Chunk::SlotSize - 1); } - QV4::Heap::CallContext *allocSimpleCallContext(QV4::ExecutionEngine *v4) + QV4::Heap::CallContext *allocSimpleCallContext() { Heap::CallContext *ctxt = stackAllocator.allocate(); memset(ctxt, 0, sizeof(Heap::CallContext)); ctxt->internalClass = CallContext::defaultInternalClass(engine); Q_ASSERT(ctxt->internalClass && ctxt->internalClass->vtable); - ctxt->init(v4); + ctxt->init(); return ctxt; } diff --git a/src/qml/qml/qqmlxmlhttprequest.cpp b/src/qml/qml/qqmlxmlhttprequest.cpp index d0d9f080da..f3a39313c1 100644 --- a/src/qml/qml/qqmlxmlhttprequest.cpp +++ b/src/qml/qml/qqmlxmlhttprequest.cpp @@ -895,7 +895,7 @@ ReturnedValue NamedNodeMap::get(const Managed *m, String *name, bool *hasPropert const NamedNodeMap *r = static_cast(m); QV4::ExecutionEngine *v4 = r->engine(); - name->makeIdentifier(v4); + name->makeIdentifier(); if (name->equals(v4->id_length())) return Primitive::fromInt32(r->d()->list().count()).asReturnedValue(); @@ -940,7 +940,7 @@ ReturnedValue NodeList::get(const Managed *m, String *name, bool *hasProperty) const NodeList *r = static_cast(m); QV4::ExecutionEngine *v4 = r->engine(); - name->makeIdentifier(v4); + name->makeIdentifier(); if (name->equals(v4->id_length())) return Primitive::fromInt32(r->d()->d->children.count()).asReturnedValue(); -- cgit v1.2.3 From a5dad4e78ff78777eafbae723442db4e9da2d6ff Mon Sep 17 00:00:00 2001 From: Lars Knoll Date: Fri, 19 May 2017 15:57:13 +0200 Subject: Get rid of the MemoryManager pointer inside String We can always get the pointer through the internalClass. Change-Id: If68432845e7c67da70d9e19aef1a90ebe1e6056b Reviewed-by: Robin Burchell --- src/qml/jsruntime/qv4function.cpp | 4 ++-- src/qml/jsruntime/qv4runtime.cpp | 4 ++-- src/qml/jsruntime/qv4string.cpp | 10 ++++------ src/qml/jsruntime/qv4string_p.h | 5 ++--- src/qml/memory/qv4mm_p.h | 2 +- 5 files changed, 11 insertions(+), 14 deletions(-) (limited to 'src') diff --git a/src/qml/jsruntime/qv4function.cpp b/src/qml/jsruntime/qv4function.cpp index 994dede26d..31b57b97e9 100644 --- a/src/qml/jsruntime/qv4function.cpp +++ b/src/qml/jsruntime/qv4function.cpp @@ -74,7 +74,7 @@ Function::Function(ExecutionEngine *engine, CompiledData::CompilationUnit *unit, } // duplicate arguments, need some trick to store them MemoryManager *mm = engine->memoryManager; - arg = mm->alloc(mm, arg->d(), engine->newString(QString(0xfffe))); + arg = mm->alloc(arg->d(), engine->newString(QString(0xfffe))); } } nFormals = compiledFunction->nFormals; @@ -109,7 +109,7 @@ void Function::updateInternalClass(ExecutionEngine *engine, const QListmemoryManager->alloc(engine->memoryManager, arg->d(), engine->newString(QString(0xfffe))); + arg = engine->memoryManager->alloc(arg->d(), engine->newString(QString(0xfffe))); } } nFormals = parameters.size(); diff --git a/src/qml/jsruntime/qv4runtime.cpp b/src/qml/jsruntime/qv4runtime.cpp index a79eab3778..37a2bfdf90 100644 --- a/src/qml/jsruntime/qv4runtime.cpp +++ b/src/qml/jsruntime/qv4runtime.cpp @@ -554,7 +554,7 @@ QV4::ReturnedValue RuntimeHelpers::addHelper(ExecutionEngine *engine, const Valu if (!sright->d()->length()) return sleft->asReturnedValue(); MemoryManager *mm = engine->memoryManager; - return (mm->alloc(mm, sleft->d(), sright->d()))->asReturnedValue(); + return (mm->alloc(sleft->d(), sright->d()))->asReturnedValue(); } double x = RuntimeHelpers::toNumber(pleft); double y = RuntimeHelpers::toNumber(pright); @@ -586,7 +586,7 @@ QV4::ReturnedValue Runtime::method_addString(ExecutionEngine *engine, const Valu if (!sright->d()->length()) return pleft->asReturnedValue(); MemoryManager *mm = engine->memoryManager; - return (mm->alloc(mm, sleft->d(), sright->d()))->asReturnedValue(); + return (mm->alloc(sleft->d(), sright->d()))->asReturnedValue(); } void Runtime::method_setProperty(ExecutionEngine *engine, const Value &object, int nameIndex, const Value &value) diff --git a/src/qml/jsruntime/qv4string.cpp b/src/qml/jsruntime/qv4string.cpp index 1404ab6d9b..515d61c8e4 100644 --- a/src/qml/jsruntime/qv4string.cpp +++ b/src/qml/jsruntime/qv4string.cpp @@ -75,10 +75,9 @@ bool String::isEqualTo(Managed *t, Managed *o) } -void Heap::String::init(MemoryManager *mm, const QString &t) +void Heap::String::init(const QString &t) { Base::init(); - this->mm = mm; subtype = String::StringType_Unknown; @@ -90,10 +89,9 @@ void Heap::String::init(MemoryManager *mm, const QString &t) len = text->size; } -void Heap::String::init(MemoryManager *mm, String *l, String *r) +void Heap::String::init(String *l, String *r) { Base::init(); - this->mm = mm; subtype = String::StringType_Unknown; @@ -116,7 +114,7 @@ void Heap::String::init(MemoryManager *mm, String *l, String *r) void Heap::String::destroy() { if (!largestSubLength) { - mm->changeUnmanagedHeapSizeUsage(qptrdiff(-text->size) * (int)sizeof(QChar)); + internalClass->engine->memoryManager->changeUnmanagedHeapSizeUsage(qptrdiff(-text->size) * (int)sizeof(QChar)); if (!text->ref.deref()) QStringData::deallocate(text); } @@ -161,7 +159,7 @@ void Heap::String::simplifyString() const text->ref.ref(); identifier = 0; largestSubLength = 0; - mm->changeUnmanagedHeapSizeUsage(qptrdiff(text->size) * (qptrdiff)sizeof(QChar)); + internalClass->engine->memoryManager->changeUnmanagedHeapSizeUsage(qptrdiff(text->size) * (qptrdiff)sizeof(QChar)); } void Heap::String::append(const String *data, QChar *ch) diff --git a/src/qml/jsruntime/qv4string_p.h b/src/qml/jsruntime/qv4string_p.h index 458a9edae6..f5311ae5d4 100644 --- a/src/qml/jsruntime/qv4string_p.h +++ b/src/qml/jsruntime/qv4string_p.h @@ -72,8 +72,8 @@ struct Q_QML_PRIVATE_EXPORT String : Base { }; #ifndef V4_BOOTSTRAP - void init(MemoryManager *mm, const QString &text); - void init(MemoryManager *mm, String *l, String *n); + void init(const QString &text); + void init(String *l, String *n); void destroy(); void simplifyString() const; int length() const { @@ -126,7 +126,6 @@ struct Q_QML_PRIVATE_EXPORT String : Base { mutable uint stringHash; mutable uint largestSubLength; uint len; - MemoryManager *mm; private: static void append(const String *data, QChar *ch); #endif diff --git a/src/qml/memory/qv4mm_p.h b/src/qml/memory/qv4mm_p.h index c5334a0dde..77c5885dfe 100644 --- a/src/qml/memory/qv4mm_p.h +++ b/src/qml/memory/qv4mm_p.h @@ -261,7 +261,7 @@ public: typename ManagedType::Data *o = reinterpret_cast(allocString(unmanagedSize)); o->internalClass = ManagedType::defaultInternalClass(engine); Q_ASSERT(o->internalClass && o->internalClass->vtable); - o->init(this, arg1); + o->init(arg1); return o; } -- cgit v1.2.3 From 96f6ba5f562073f508cd8569ac354592fdd48f4a Mon Sep 17 00:00:00 2001 From: Shawn Rutledge Date: Thu, 11 May 2017 20:36:51 +0200 Subject: Revert "Temporarily restore QQuickPointerDevice::pointerEvent() accessor" This reverts commit ee6b07b3ce8ba80632868181d45d96253acb1064. This is to be integrated after the qtlocation change to remove the dependency on this private function. Task-number: QTBUG-57253 Change-Id: I756681fb2595d1326b7e5206bac57ccc318c0a46 Reviewed-by: Liang Qi --- src/quick/items/qquickevents_p_p.h | 7 ------- src/quick/items/qquickwindow.cpp | 5 +---- 2 files changed, 1 insertion(+), 11 deletions(-) (limited to 'src') diff --git a/src/quick/items/qquickevents_p_p.h b/src/quick/items/qquickevents_p_p.h index 323ecfa4ff..3735d68a85 100644 --- a/src/quick/items/qquickevents_p_p.h +++ b/src/quick/items/qquickevents_p_p.h @@ -501,7 +501,6 @@ public: : m_deviceType(devType), m_pointerType(pType), m_capabilities(caps) , m_maximumTouchPoints(maxPoints), m_buttonCount(buttonCount), m_name(name) , m_uniqueId(QPointingDeviceUniqueId::fromNumericId(uniqueId)) - , m_event(nullptr) { } @@ -514,8 +513,6 @@ public: QString name() const { return m_name; } QPointingDeviceUniqueId uniqueId() const { return m_uniqueId; } - QQuickPointerEvent *pointerEvent() const { return m_event; } // deprecated - static QQuickPointerDevice *touchDevice(QTouchDevice *d); static QList touchDevices(); static QQuickPointerDevice *genericMouseDevice(); @@ -530,10 +527,6 @@ private: QString m_name; QPointingDeviceUniqueId m_uniqueId; - // the event instance used last time within the context of one window - QQuickPointerEvent *m_event; // deprecated - friend class QQuickWindowPrivate; // not needed after removing the above - Q_DISABLE_COPY(QQuickPointerDevice) }; diff --git a/src/quick/items/qquickwindow.cpp b/src/quick/items/qquickwindow.cpp index 816c057ab0..c441cfc357 100644 --- a/src/quick/items/qquickwindow.cpp +++ b/src/quick/items/qquickwindow.cpp @@ -2117,10 +2117,8 @@ QQuickPointerEvent *QQuickWindowPrivate::pointerEventInstance(QQuickPointerDevic { // the list of devices should be very small so a linear search should be ok for (QQuickPointerEvent *e: pointerEventInstances) { - if (e->device() == device) { - device->m_event = e; + if (e->device() == device) return e; - } } QQuickPointerEvent *ev = nullptr; @@ -2138,7 +2136,6 @@ QQuickPointerEvent *QQuickWindowPrivate::pointerEventInstance(QQuickPointerDevic break; } pointerEventInstances << ev; - device->m_event = ev; return ev; } -- cgit v1.2.3 From 3f9367cb32533b691cb8c761213f21a524e3d1cb Mon Sep 17 00:00:00 2001 From: Lars Knoll Date: Mon, 22 May 2017 08:34:00 +0200 Subject: Fix compilation of QtScxml QtScxml was using internal API in v4, that has changed. Restore the old function signature until all it's uses have been cleaned up. Task-number: QTBUG-60938 Change-Id: Ie40c09da9df9e5684972669cd9a511a868b920a4 Reviewed-by: Simon Hausmann --- src/qml/jsruntime/qv4string_p.h | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'src') diff --git a/src/qml/jsruntime/qv4string_p.h b/src/qml/jsruntime/qv4string_p.h index f5311ae5d4..d9625e3f4e 100644 --- a/src/qml/jsruntime/qv4string_p.h +++ b/src/qml/jsruntime/qv4string_p.h @@ -175,6 +175,10 @@ struct Q_QML_PRIVATE_EXPORT String : public Managed { } uint toUInt(bool *ok) const; + Q_DECL_DEPRECATED void makeIdentifier(ExecutionEngine *) { + makeIdentifier(); + } + void makeIdentifier() const { if (d()->identifier) return; -- cgit v1.2.3 From 16105b1b0cf9dc3849d9ff03503fa8bed1b8da40 Mon Sep 17 00:00:00 2001 From: Marco Benelli Date: Fri, 19 May 2017 11:27:48 +0200 Subject: Update qmltypes Small update of qmltypes. Change-Id: I5408f0ae50a70ca1c1cc0c0deaa8ddf6458c88c1 Reviewed-by: Thomas Hartmann Reviewed-by: Erik Verbruggen --- src/imports/builtins/builtins.qmltypes | 3 ++- src/imports/qtquick2/plugins.qmltypes | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/imports/builtins/builtins.qmltypes b/src/imports/builtins/builtins.qmltypes index ac95a8837b..c2f8f5b521 100644 --- a/src/imports/builtins/builtins.qmltypes +++ b/src/imports/builtins/builtins.qmltypes @@ -426,7 +426,8 @@ Module { "WA_X11DoNotAcceptFocus": 126, "WA_MacNoShadow": 127, "WA_AlwaysStackOnTop": 128, - "WA_AttributeCount": 129 + "WA_TabletTracking": 129, + "WA_AttributeCount": 130 } } Enum { diff --git a/src/imports/qtquick2/plugins.qmltypes b/src/imports/qtquick2/plugins.qmltypes index a9534b5ccc..834b4bfac2 100644 --- a/src/imports/qtquick2/plugins.qmltypes +++ b/src/imports/qtquick2/plugins.qmltypes @@ -1414,7 +1414,7 @@ Module { Property { name: "source"; type: "QObject"; isPointer: true } Property { name: "target"; type: "QObject"; isReadonly: true; isPointer: true } Property { name: "hotSpot"; type: "QPointF" } - Property { name: "imageSource"; revision: 8; type: "QUrl" } + Property { name: "imageSource"; type: "QUrl" } Property { name: "keys"; type: "QStringList" } Property { name: "mimeData"; type: "QVariantMap" } Property { name: "supportedActions"; type: "Qt::DropActions" } -- cgit v1.2.3 From 101bd41490be160be218aa638f35cfa609267a83 Mon Sep 17 00:00:00 2001 From: Andy Nichols Date: Tue, 23 May 2017 12:13:35 +0200 Subject: Software: Fix QQuickWidget rendering in QMdiArea It is not safe to assume that the paintRegion is always the same as the updateRegion reported by the software renderer, since in some cases more needs to be flushed, such as in the case of the QMdiArea. Now we make sure to unite both of these regions and flush everything needed. Task-number: QTBUG-60985 Change-Id: I0408c21e42dd4107b0974877144e8e93f2c30fae Reviewed-by: Laszlo Agocs --- src/quickwidgets/qquickwidget.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/quickwidgets/qquickwidget.cpp b/src/quickwidgets/qquickwidget.cpp index 4d021cb680..49ac0caefd 100644 --- a/src/quickwidgets/qquickwidget.cpp +++ b/src/quickwidgets/qquickwidget.cpp @@ -1596,10 +1596,10 @@ QQuickWindow *QQuickWidget::quickWindow() const void QQuickWidget::paintEvent(QPaintEvent *event) { - Q_UNUSED(event) Q_D(QQuickWidget); if (d->useSoftwareRenderer) { QPainter painter(this); + d->updateRegion = d->updateRegion.united(event->region()); if (d->updateRegion.isNull()) { //Paint everything painter.drawImage(rect(), d->softwareImage); -- cgit v1.2.3 From 082d7361ae54cc9081a7e33ae7bd49949dfb3e08 Mon Sep 17 00:00:00 2001 From: Friedemann Kleint Date: Tue, 23 May 2017 12:59:14 +0200 Subject: QtQml: Restrict alloca definition to MSVC Fix developer build with MinGW: In file included from memory\qv4mm.cpp:60:0: jsruntime/qv4alloca_p.h:62:0: error: "alloca" redefined [-Werror] # define alloca _alloca ^ In file included from .../mingw32/i686-w64-mingw32/include/stdlib.h:686:0, from .../mingw32/i686-w64-mingw32/include/c++/cstdlib:72, from .../mingw32/i686-w64-mingw32/include/c++/bits/stl_algo.h:59, from .../mingw32/i686-w64-mingw32/include/c++/algorithm:62, from .../qtbase/src/corelib/global/qglobal.h:109, from ...\qtbase\include/QtCore/qglobal.h:1, from jsruntime/qv4global_p.h:54, from jsruntime/qv4engine_p.h:53, from memory\qv4mm.cpp:40: .../mingw32/i686-w64-mingw32/include/malloc.h:183:0: note: this is the location of the previous definition #define alloca(x) __builtin_alloca((x)) Amends change a225bddf67f4786c845193630d4ab20b99a2fc3a. Change-Id: I4a758776dbf78225f62883393eb50b7121297a1b Reviewed-by: Simon Hausmann --- src/qml/jsruntime/qv4alloca_p.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/qml/jsruntime/qv4alloca_p.h b/src/qml/jsruntime/qv4alloca_p.h index c21878fa42..1e9f83a90e 100644 --- a/src/qml/jsruntime/qv4alloca_p.h +++ b/src/qml/jsruntime/qv4alloca_p.h @@ -58,7 +58,7 @@ #elif QT_CONFIG(alloca_malloc_h) # include // This does not matter unless compiling in strict standard mode. -# ifdef Q_OS_WIN +# ifdef Q_CC_MSVC # define alloca _alloca # endif #else -- cgit v1.2.3 From 4b71719d1c02e484192e5b840e0937e1778d33c2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=BCri=20Valdmann?= Date: Mon, 15 May 2017 12:24:41 +0200 Subject: Improve dirty region calculation in software renderer The software renderers dirty region calculation is done in integral logical coordinates, which leads to quite some trouble when handling scene graph elements with fractional coordinates (used by WebEngine for example). The optimal solution would probably be to either use integral physical coordinates or floating point logical coordinates, however this would seem to require substantial changes to QPainter and QBackingStore and so on. So, this patch instead changes the calculation to use something like interval arithmetic: instead of just rounding each logical coordinate to the nearest integer the renderer now uses (very carefully) both the upper and lower boundaries to make sure that the dirty regions always err on the side of caution. I expect this change to make rendering slower but only in situations where previously there would be rendering errors. Task-number: QTBUG-60393 Change-Id: I7f8e7d2739c810328c841130df9c1c7332439447 Reviewed-by: Andy Nichols --- .../software/qsgabstractsoftwarerenderer.cpp | 8 +-- .../software/qsgsoftwarerenderablenode.cpp | 77 +++++++++++++--------- .../software/qsgsoftwarerenderablenode_p.h | 6 +- 3 files changed, 55 insertions(+), 36 deletions(-) (limited to 'src') diff --git a/src/quick/scenegraph/adaptations/software/qsgabstractsoftwarerenderer.cpp b/src/quick/scenegraph/adaptations/software/qsgabstractsoftwarerenderer.cpp index 2ff180ea99..02cf8209d1 100644 --- a/src/quick/scenegraph/adaptations/software/qsgabstractsoftwarerenderer.cpp +++ b/src/quick/scenegraph/adaptations/software/qsgabstractsoftwarerenderer.cpp @@ -165,12 +165,12 @@ QRegion QSGAbstractSoftwareRenderer::optimizeRenderList() // Keep up with obscured regions if (node->isOpaque()) { - m_obscuredRegion += QRegion(node->boundingRect()); + m_obscuredRegion += node->boundingRectMin(); } if (node->isDirty()) { // Don't paint things outside of the rendering area - if (!m_background->rect().toRect().contains(node->boundingRect(), /*proper*/ true)) { + if (!m_background->rect().toRect().contains(node->boundingRectMax(), /*proper*/ true)) { // Some part(s) of node is(are) outside of the rendering area QRegion renderArea(m_background->rect().toRect()); QRegion outsideRegions = node->dirtyRegion().subtracted(renderArea); @@ -181,7 +181,7 @@ QRegion QSGAbstractSoftwareRenderer::optimizeRenderList() // Get the dirty region's to pass to the next nodes if (node->isOpaque()) { // if isOpaque, subtract node's dirty rect from m_dirtyRegion - m_dirtyRegion -= node->dirtyRegion(); + m_dirtyRegion -= node->boundingRectMin(); } else { // if isAlpha, add node's dirty rect to m_dirtyRegion m_dirtyRegion += node->dirtyRegion(); @@ -264,7 +264,7 @@ void QSGAbstractSoftwareRenderer::nodeRemoved(QSGNode *node) // Need to mark this region dirty in the other nodes QRegion dirtyRegion = renderable->previousDirtyRegion(true); if (dirtyRegion.isEmpty()) - dirtyRegion = renderable->boundingRect(); + dirtyRegion = renderable->boundingRectMax(); m_dirtyRegion += dirtyRegion; m_nodes.remove(node); delete renderable; diff --git a/src/quick/scenegraph/adaptations/software/qsgsoftwarerenderablenode.cpp b/src/quick/scenegraph/adaptations/software/qsgsoftwarerenderablenode.cpp index 59c47db0c4..ce08d18057 100644 --- a/src/quick/scenegraph/adaptations/software/qsgsoftwarerenderablenode.cpp +++ b/src/quick/scenegraph/adaptations/software/qsgsoftwarerenderablenode.cpp @@ -54,10 +54,28 @@ #include #include +#include + Q_LOGGING_CATEGORY(lcRenderable, "qt.scenegraph.softwarecontext.renderable") QT_BEGIN_NAMESPACE +// Largest subrectangle with integer coordinates +inline QRect toRectMin(const QRectF & r) +{ + int x1 = qCeil(r.left()); + int x2 = qFloor(r.right()); + int y1 = qCeil(r.top()); + int y2 = qFloor(r.bottom()); + return QRect(x1, y1, x2 - x1, y2 - y1); +} + +// Smallest superrectangle with integer coordinates +inline QRect toRectMax(const QRectF & r) +{ + return r.toAlignedRect(); +} + QSGSoftwareRenderableNode::QSGSoftwareRenderableNode(NodeType type, QSGNode *node) : m_nodeType(type) , m_isOpaque(true) @@ -117,7 +135,7 @@ void QSGSoftwareRenderableNode::update() // Update the Node properties m_isDirty = true; - QRect boundingRect; + QRectF boundingRect; switch (m_nodeType) { case QSGSoftwareRenderableNode::SimpleRect: @@ -126,7 +144,7 @@ void QSGSoftwareRenderableNode::update() else m_isOpaque = false; - boundingRect = m_handle.simpleRectNode->rect().toRect(); + boundingRect = m_handle.simpleRectNode->rect(); break; case QSGSoftwareRenderableNode::SimpleTexture: if (!m_handle.simpleTextureNode->texture()->hasAlphaChannel() && !m_transform.isRotating()) @@ -134,7 +152,7 @@ void QSGSoftwareRenderableNode::update() else m_isOpaque = false; - boundingRect = m_handle.simpleTextureNode->rect().toRect(); + boundingRect = m_handle.simpleTextureNode->rect(); break; case QSGSoftwareRenderableNode::Image: // There isn't a way to tell, so assume it's not @@ -148,7 +166,7 @@ void QSGSoftwareRenderableNode::update() else m_isOpaque = false; - boundingRect = QRect(0, 0, m_handle.painterNode->size().width(), m_handle.painterNode->size().height()); + boundingRect = QRectF(0, 0, m_handle.painterNode->size().width(), m_handle.painterNode->size().height()); break; case QSGSoftwareRenderableNode::Rectangle: if (m_handle.rectangleNode->isOpaque() && !m_transform.isRotating()) @@ -156,19 +174,19 @@ void QSGSoftwareRenderableNode::update() else m_isOpaque = false; - boundingRect = m_handle.rectangleNode->rect().toRect(); + boundingRect = m_handle.rectangleNode->rect(); break; case QSGSoftwareRenderableNode::Glyph: // Always has alpha m_isOpaque = false; - boundingRect = m_handle.glpyhNode->boundingRect().toAlignedRect(); + boundingRect = m_handle.glpyhNode->boundingRect(); break; case QSGSoftwareRenderableNode::NinePatch: // Difficult to tell, assume non-opaque m_isOpaque = false; - boundingRect = m_handle.ninePatchNode->bounds().toRect(); + boundingRect = m_handle.ninePatchNode->bounds(); break; case QSGSoftwareRenderableNode::SimpleRectangle: if (m_handle.simpleRectangleNode->color().alpha() == 255 && !m_transform.isRotating()) @@ -176,7 +194,7 @@ void QSGSoftwareRenderableNode::update() else m_isOpaque = false; - boundingRect = m_handle.simpleRectangleNode->rect().toRect(); + boundingRect = m_handle.simpleRectangleNode->rect(); break; case QSGSoftwareRenderableNode::SimpleImage: if (!m_handle.simpleImageNode->texture()->hasAlphaChannel() && !m_transform.isRotating()) @@ -184,12 +202,12 @@ void QSGSoftwareRenderableNode::update() else m_isOpaque = false; - boundingRect = m_handle.simpleImageNode->rect().toRect(); + boundingRect = m_handle.simpleImageNode->rect(); break; #if QT_CONFIG(quick_sprite) case QSGSoftwareRenderableNode::SpriteNode: m_isOpaque = m_handle.spriteNode->isOpaque(); - boundingRect = m_handle.spriteNode->rect().toRect(); + boundingRect = m_handle.spriteNode->rect(); break; #endif case QSGSoftwareRenderableNode::RenderNode: @@ -198,27 +216,32 @@ void QSGSoftwareRenderableNode::update() else m_isOpaque = false; - boundingRect = m_handle.renderNode->rect().toRect(); + boundingRect = m_handle.renderNode->rect(); break; default: break; } - m_boundingRect = m_transform.mapRect(boundingRect); + const QRectF transformedRect = m_transform.mapRect(boundingRect); + m_boundingRectMin = toRectMin(transformedRect); + m_boundingRectMax = toRectMax(transformedRect); if (m_hasClipRegion && m_clipRegion.rectCount() <= 1) { // If there is a clipRegion, and it is empty, the item wont be rendered - if (m_clipRegion.isEmpty()) - m_boundingRect = QRect(); - else - m_boundingRect = m_boundingRect.intersected(m_clipRegion.rects().first()); + if (m_clipRegion.isEmpty()) { + m_boundingRectMin = QRect(); + m_boundingRectMax = QRect(); + } else { + m_boundingRectMin = m_boundingRectMin.intersected(m_clipRegion.rects().first()); + m_boundingRectMax = m_boundingRectMax.intersected(m_clipRegion.rects().first()); + } } // Overrides if (m_opacity < 1.0f) m_isOpaque = false; - m_dirtyRegion = QRegion(m_boundingRect); + m_dirtyRegion = QRegion(m_boundingRectMax); } struct RenderNodeState : public QSGRenderNode::RenderState @@ -258,7 +281,7 @@ QRegion QSGSoftwareRenderableNode::renderNode(QPainter *painter, bool forceOpaqu rs.cr = m_clipRegion; const QRect br = m_handle.renderNode->flags().testFlag(QSGRenderNode::BoundedRectRendering) - ? m_boundingRect : + ? m_boundingRectMax : QRect(0, 0, painter->device()->width(), painter->device()->height()); painter->save(); @@ -335,19 +358,13 @@ QRegion QSGSoftwareRenderableNode::renderNode(QPainter *painter, bool forceOpaqu painter->restore(); QRegion areaToBeFlushed = m_dirtyRegion; - m_previousDirtyRegion = QRegion(m_boundingRect); + m_previousDirtyRegion = QRegion(m_boundingRectMax); m_isDirty = false; m_dirtyRegion = QRegion(); return areaToBeFlushed; } -QRect QSGSoftwareRenderableNode::boundingRect() const -{ - // This returns the bounding area of a renderable node in world coordinates - return m_boundingRect; -} - bool QSGSoftwareRenderableNode::isDirtyRegionEmpty() const { return m_dirtyRegion.isEmpty(); @@ -392,12 +409,12 @@ void QSGSoftwareRenderableNode::markMaterialDirty() void QSGSoftwareRenderableNode::addDirtyRegion(const QRegion &dirtyRegion, bool forceDirty) { - // Check if the dirty region applys to this node + // Check if the dirty region applies to this node QRegion prev = m_dirtyRegion; - if (dirtyRegion.intersects(boundingRect())) { + if (dirtyRegion.intersects(m_boundingRectMax)) { if (forceDirty) m_isDirty = true; - m_dirtyRegion += dirtyRegion.intersected(boundingRect()); + m_dirtyRegion += dirtyRegion.intersected(m_boundingRectMax); } qCDebug(lcRenderable) << "addDirtyRegion: " << dirtyRegion << "old dirtyRegion: " << prev << "new dirtyRegion: " << m_dirtyRegion; } @@ -407,7 +424,7 @@ void QSGSoftwareRenderableNode::subtractDirtyRegion(const QRegion &dirtyRegion) QRegion prev = m_dirtyRegion; if (m_isDirty) { // Check if this rect concerns us - if (dirtyRegion.intersects(QRegion(boundingRect()))) { + if (dirtyRegion.intersects(m_boundingRectMax)) { m_dirtyRegion -= dirtyRegion; if (m_dirtyRegion.isEmpty()) m_isDirty = false; @@ -423,7 +440,7 @@ QRegion QSGSoftwareRenderableNode::previousDirtyRegion(bool wasRemoved) const if (wasRemoved) return m_previousDirtyRegion; - return m_previousDirtyRegion.subtracted(QRegion(m_boundingRect)); + return m_previousDirtyRegion.subtracted(QRegion(m_boundingRectMax)); } QRegion QSGSoftwareRenderableNode::dirtyRegion() const diff --git a/src/quick/scenegraph/adaptations/software/qsgsoftwarerenderablenode_p.h b/src/quick/scenegraph/adaptations/software/qsgsoftwarerenderablenode_p.h index 473578c185..8fc87db179 100644 --- a/src/quick/scenegraph/adaptations/software/qsgsoftwarerenderablenode_p.h +++ b/src/quick/scenegraph/adaptations/software/qsgsoftwarerenderablenode_p.h @@ -98,7 +98,8 @@ public: void update(); QRegion renderNode(QPainter *painter, bool forceOpaquePainting = false); - QRect boundingRect() const; + QRect boundingRectMin() const { return m_boundingRectMin; } + QRect boundingRectMax() const { return m_boundingRectMax; } NodeType type() const { return m_nodeType; } bool isOpaque() const { return m_isOpaque; } bool isDirty() const { return m_isDirty; } @@ -149,7 +150,8 @@ private: bool m_hasClipRegion; float m_opacity; - QRect m_boundingRect; + QRect m_boundingRectMin; + QRect m_boundingRectMax; }; QT_END_NAMESPACE -- cgit v1.2.3 From a5fbfc9ab1dc06c9f80beda2179b15bd7c499c77 Mon Sep 17 00:00:00 2001 From: Jesus Fernandez Date: Mon, 22 May 2017 09:49:18 +0200 Subject: Document the default value of x, y, width & height The default values of the coordinates and size variables were missing. Change-Id: I1bba77b3db68d3f726c1211c6a0090e97f687b51 Reviewed-by: Mitch Curtis Reviewed-by: Shawn Rutledge --- src/quick/items/qquickitem.cpp | 1 + 1 file changed, 1 insertion(+) (limited to 'src') diff --git a/src/quick/items/qquickitem.cpp b/src/quick/items/qquickitem.cpp index 8e90827a3d..5f5611d711 100644 --- a/src/quick/items/qquickitem.cpp +++ b/src/quick/items/qquickitem.cpp @@ -6343,6 +6343,7 @@ void QQuickItem::setFlags(Flags flags) \qmlproperty real QtQuick::Item::height Defines the item's position and size. + The default value is \c 0. The (x,y) position is relative to the \l parent. -- cgit v1.2.3 From df30d90eadcd92eebb4bf79f3eb251bc58d25d09 Mon Sep 17 00:00:00 2001 From: Liang Qi Date: Tue, 23 May 2017 17:09:32 +0200 Subject: Revert "Fix compilation of QtScxml" This reverts commit 3f9367cb32533b691cb8c761213f21a524e3d1cb. QtScxml adapted to new API. Task-number: QTBUG-60938 Change-Id: I417b604ceb9949ee3c0197ac9f88efdbe53ebe48 Reviewed-by: Simon Hausmann --- src/qml/jsruntime/qv4string_p.h | 4 ---- 1 file changed, 4 deletions(-) (limited to 'src') diff --git a/src/qml/jsruntime/qv4string_p.h b/src/qml/jsruntime/qv4string_p.h index d9625e3f4e..f5311ae5d4 100644 --- a/src/qml/jsruntime/qv4string_p.h +++ b/src/qml/jsruntime/qv4string_p.h @@ -175,10 +175,6 @@ struct Q_QML_PRIVATE_EXPORT String : public Managed { } uint toUInt(bool *ok) const; - Q_DECL_DEPRECATED void makeIdentifier(ExecutionEngine *) { - makeIdentifier(); - } - void makeIdentifier() const { if (d()->identifier) return; -- cgit v1.2.3 From 44a5b008f7a6dce065f5997503e403609ee62859 Mon Sep 17 00:00:00 2001 From: Laszlo Agocs Date: Tue, 23 May 2017 14:34:23 +0200 Subject: Forward ShortcutOverride in QQuickWidget This is now essential since otherwise these events are simply lost. Amends 0dbc575c1a8359534761167a5f5f1e29abedd51d Task-number: QTBUG-60988 Change-Id: Ib1d99d8fcd5bb92c9b52977796f2910f0fe71c48 Reviewed-by: J-P Nurmi Reviewed-by: Andy Nichols --- src/quickwidgets/qquickwidget.cpp | 3 +++ 1 file changed, 3 insertions(+) (limited to 'src') diff --git a/src/quickwidgets/qquickwidget.cpp b/src/quickwidgets/qquickwidget.cpp index 49ac0caefd..2e8623f508 100644 --- a/src/quickwidgets/qquickwidget.cpp +++ b/src/quickwidgets/qquickwidget.cpp @@ -1440,6 +1440,9 @@ bool QQuickWidget::event(QEvent *e) d->offscreenWindow->setWindowState(resolveWindowState(windowState())); break; + case QEvent::ShortcutOverride: + return QCoreApplication::sendEvent(d->offscreenWindow, e); + default: break; } -- cgit v1.2.3 From 06c0702e7e252227ca907bc3654179ad079cd1b5 Mon Sep 17 00:00:00 2001 From: Stephan Binner Date: Sat, 6 May 2017 23:04:03 +0200 Subject: Add sections and update purposes of features Change-Id: I95923fa183172bb4fe5d0a6ae34c801e0cee2a63 Reviewed-by: Oswald Buddenhagen Reviewed-by: Shawn Rutledge --- src/qml/configure.json | 9 ++++++--- src/quick/configure.json | 41 +++++++++++++++++++++++++++-------------- 2 files changed, 33 insertions(+), 17 deletions(-) (limited to 'src') diff --git a/src/qml/configure.json b/src/qml/configure.json index 2c4887365f..257bedecbc 100644 --- a/src/qml/configure.json +++ b/src/qml/configure.json @@ -15,17 +15,20 @@ "features": { "qml-interpreter": { "label": "QML interpreter", - "purpose": "Support for the QML interpreter", + "purpose": "Provides the QML interpreter.", + "section": "QML", "output": [ "privateFeature" ] }, "qml-network": { "label": "QML network support", - "purpose": "Provides network transparency for QML", + "purpose": "Provides network transparency.", + "section": "QML", "output": [ "publicFeature" ] }, "qml-profiler": { "label": "Command line QML Profiler", - "purpose": "The QML Profiler retrieves QML tracing data from an application.", + "purpose": "Supports retrieving QML tracing data from an application.", + "section": "QML", "condition": [ "features.commandlineparser", "features.localserver", diff --git a/src/quick/configure.json b/src/quick/configure.json index 047fa8c948..65ad5b810b 100644 --- a/src/quick/configure.json +++ b/src/quick/configure.json @@ -34,7 +34,8 @@ "features": { "d3d12": { "label": "Direct3D 12", - "purpose": "Provides a Direct3D 12 backend for the Qt Quick Scenegraph", + "purpose": "Provides a Direct3D 12 backend for the scenegraph.", + "section": "Qt Quick", "condition": "tests.d3d12", "output": [ "publicFeature" @@ -42,7 +43,8 @@ }, "quick-animatedimage": { "label": "AnimatedImage item", - "purpose": "Provides the Qt Quick AnimatedImage Item", + "purpose": "Provides the AnimatedImage item.", + "section": "Qt Quick", "condition": "features.movie", "output": [ "privateFeature" @@ -50,29 +52,33 @@ }, "quick-canvas": { "label": "Canvas item", - "purpose": "Provides the Qt Quick Canvas Item", + "purpose": "Provides the Canvas item.", + "section": "Qt Quick", "condition": "features.quick-path", "output": [ "privateFeature" ] }, "quick-designer": { - "label": "Support for Quick Designer", - "purpose": "Provides support for the Qt Quick Designer in Qt Creator", + "label": "Support for Qt Quick Designer", + "purpose": "Provides support for the Qt Quick Designer in Qt Creator.", + "section": "Qt Quick", "output": [ "privateFeature" ] }, "quick-flipable": { "label": "Flipable item", - "purpose": "Provides the Qt Quick Flipable Item", + "purpose": "Provides the Flipable item.", + "section": "Qt Quick", "output": [ "privateFeature" ] }, "quick-gridview": { "label": "GridView item", - "purpose": "Provides the Qt Quick GridView item", + "purpose": "Provides the GridView item.", + "section": "Qt Quick", "output": [ "privateFeature" ] @@ -93,14 +99,16 @@ }, "quick-listview": { "label": "ListView item", - "purpose": "Provides the Qt Quick ListView item", + "purpose": "Provides the ListView item.", + "section": "Qt Quick", "output": [ "privateFeature" ] }, "quick-particles": { "label": "Particle support", - "purpose": "Provides a particle system for Qt Quick", + "purpose": "Provides a particle system.", + "section": "Qt Quick", "condition": "features.quick-shadereffect && features.quick-sprite && features.opengl", "output": [ "privateFeature" @@ -108,14 +116,16 @@ }, "quick-path": { "label": "Path support", - "purpose": "Provides Path elements in Qt Quick", + "purpose": "Provides Path elements.", + "section": "Qt Quick", "output": [ "privateFeature" ] }, "quick-pathview": { "label": "PathView item", - "purpose": "Provides the Qt Quick PathView item", + "purpose": "Provides the PathView item.", + "section": "Qt Quick", "condition": "features.quick-path", "output": [ "privateFeature" @@ -123,21 +133,24 @@ }, "quick-positioners": { "label": "Positioner items", - "purpose": "Provides Positioner items in Qt Quick", + "purpose": "Provides Positioner items.", + "section": "Qt Quick", "output": [ "privateFeature" ] }, "quick-shadereffect": { "label": "ShaderEffect item", - "purpose": "Provides Shader effects in Qt Quick", + "purpose": "Provides Shader effects.", + "section": "Qt Quick", "output": [ "privateFeature" ] }, "quick-sprite": { "label": "Sprite item", - "purpose": "Provides the Qt Quick Sprite Item", + "purpose": "Provides the Sprite item.", + "section": "Qt Quick", "output": [ "privateFeature" ] -- cgit v1.2.3 From 651a4f7e094f844cac3740744d148102bbf7689f Mon Sep 17 00:00:00 2001 From: Robin Burchell Date: Thu, 1 Jun 2017 13:16:28 +0200 Subject: Revert "QQuickRectangle: Optimize setGradient" This reverts commit 9709d04ba7787c853a1ddbeed0347eab27c0924f. We changed this from using a signal for notification to using parenting. But this cannot be done for two related reasons: the first: QtObject { property Gradient someGradient: Gradient { id: someGradient } } ... Rectangle { gradient: someGradient } ... should work, and no longer did, because the Gradient's parent was the QtObject, not the Rectangle it was tied to. And secondly: Rectangle { id: rectOne gradient: Gradient { id: someGradient } } Rectangle { id: rectTwo gradient: someGradient } ... also didn't work anymore, as the Gradient was only notifying a single Item about changes to it. The easiest way to fix this is to just revert back to using a signal connection. This also caused problems in qtquickcontrols autotests. Change-Id: Ic07dd02e9920596d0c047bfc23995b3be8c96c49 Task-number: QTBUG-60268 Reviewed-by: J-P Nurmi --- src/quick/items/qquickrectangle.cpp | 19 +++++++++++++++++-- src/quick/items/qquickrectangle_p.h | 6 ++++++ src/quick/items/qquickrectangle_p_p.h | 1 + 3 files changed, 24 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/quick/items/qquickrectangle.cpp b/src/quick/items/qquickrectangle.cpp index 0c532bcd4c..65284eb532 100644 --- a/src/quick/items/qquickrectangle.cpp +++ b/src/quick/items/qquickrectangle.cpp @@ -1,6 +1,5 @@ /**************************************************************************** ** -** Copyright (C) 2017 Crimson AS ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** @@ -270,9 +269,11 @@ QGradientStops QQuickGradient::gradientStops() const void QQuickGradient::doUpdate() { - static_cast(parent())->update(); + emit updated(); } +int QQuickRectanglePrivate::doUpdateSlotIdx = -1; + /*! \qmltype Rectangle \instantiates QQuickRectangle @@ -326,6 +327,11 @@ QQuickRectangle::QQuickRectangle(QQuickItem *parent) setFlag(ItemHasContents); } +void QQuickRectangle::doUpdate() +{ + update(); +} + /*! \qmlproperty bool QtQuick::Rectangle::antialiasing @@ -390,7 +396,16 @@ void QQuickRectangle::setGradient(QQuickGradient *gradient) Q_D(QQuickRectangle); if (d->gradient == gradient) return; + static int updatedSignalIdx = -1; + if (updatedSignalIdx < 0) + updatedSignalIdx = QMetaMethod::fromSignal(&QQuickGradient::updated).methodIndex(); + if (d->doUpdateSlotIdx < 0) + d->doUpdateSlotIdx = QQuickRectangle::staticMetaObject.indexOfSlot("doUpdate()"); + if (d->gradient) + QMetaObject::disconnect(d->gradient, updatedSignalIdx, this, d->doUpdateSlotIdx); d->gradient = gradient; + if (d->gradient) + QMetaObject::connect(d->gradient, updatedSignalIdx, this, d->doUpdateSlotIdx); update(); } diff --git a/src/quick/items/qquickrectangle_p.h b/src/quick/items/qquickrectangle_p.h index 627f778e44..724a06013c 100644 --- a/src/quick/items/qquickrectangle_p.h +++ b/src/quick/items/qquickrectangle_p.h @@ -129,6 +129,9 @@ public: QGradientStops gradientStops() const; +Q_SIGNALS: + void updated(); + private: void doUpdate(); @@ -169,6 +172,9 @@ Q_SIGNALS: protected: QSGNode *updatePaintNode(QSGNode *, UpdatePaintNodeData *) Q_DECL_OVERRIDE; +private Q_SLOTS: + void doUpdate(); + private: Q_DISABLE_COPY(QQuickRectangle) Q_DECLARE_PRIVATE(QQuickRectangle) diff --git a/src/quick/items/qquickrectangle_p_p.h b/src/quick/items/qquickrectangle_p_p.h index e771beec87..3c1aaf7661 100644 --- a/src/quick/items/qquickrectangle_p_p.h +++ b/src/quick/items/qquickrectangle_p_p.h @@ -76,6 +76,7 @@ public: QQuickGradient *gradient; QQuickPen *pen; qreal radius; + static int doUpdateSlotIdx; }; QT_END_NAMESPACE -- cgit v1.2.3 From ac02a71a9cb8e80014218ba7de46f4f914b6e00c Mon Sep 17 00:00:00 2001 From: Mitch Curtis Date: Tue, 30 May 2017 09:11:28 +0200 Subject: Revert "QQuickWindow::createTextureFromImage(): return nullptr for null images" This reverts commit e6acf80136db9f667d0d4664f6c68065355d6811. This breaks behavioral compatibility. Task-number: QTBUG-61083 Change-Id: I0161d536502bab31aaf4ebc38f91e6c8842f72b0 Reviewed-by: Laszlo Agocs --- src/quick/items/qquickwindow.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/quick/items/qquickwindow.cpp b/src/quick/items/qquickwindow.cpp index ff4a357641..c441cfc357 100644 --- a/src/quick/items/qquickwindow.cpp +++ b/src/quick/items/qquickwindow.cpp @@ -3862,7 +3862,7 @@ QSGTexture *QQuickWindow::createTextureFromImage(const QImage &image) const QSGTexture *QQuickWindow::createTextureFromImage(const QImage &image, CreateTextureOptions options) const { Q_D(const QQuickWindow); - if (!isSceneGraphInitialized() || image.isNull()) // check both for d->context and d->context->isValid() + if (!isSceneGraphInitialized()) // check both for d->context and d->context->isValid() return 0; uint flags = 0; if (options & TextureCanUseAtlas) flags |= QSGRenderContext::CreateTexture_Atlas; -- cgit v1.2.3 From 7ab6f0dda1cbe4ffd154226996482bc6b092690b Mon Sep 17 00:00:00 2001 From: Albert Astals Cid Date: Wed, 31 May 2017 16:05:46 +0200 Subject: Remove QQuickAnimatedImage::sourceSizeChanged Thanks to moc improvements now the Q_PROPERTY can use the signal defined in the parent Change-Id: Ib69a1b985e7d972cf3a787d22f0403b63b330c36 Reviewed-by: Mitch Curtis --- src/quick/items/qquickanimatedimage_p.h | 1 - 1 file changed, 1 deletion(-) (limited to 'src') diff --git a/src/quick/items/qquickanimatedimage_p.h b/src/quick/items/qquickanimatedimage_p.h index 143fe8904d..54da093259 100644 --- a/src/quick/items/qquickanimatedimage_p.h +++ b/src/quick/items/qquickanimatedimage_p.h @@ -97,7 +97,6 @@ Q_SIGNALS: void playingChanged(); void pausedChanged(); void frameChanged(); - void sourceSizeChanged(); private Q_SLOTS: void movieUpdate(); -- cgit v1.2.3 From af6655885cf19de69d5f57ac9daee9f6b9935a70 Mon Sep 17 00:00:00 2001 From: J-P Nurmi Date: Thu, 1 Jun 2017 10:48:00 +0200 Subject: QQuickWindow/View: set a QObject-parent on the root item People are often confused why eg. the objects from: window->contentItem()->findChildren() are not included in window->findChildren(). This change connects the item tree to the window's object tree to make findChild() and findChildren() produce expected results. The same technique is already used for QQuickFlickable's contentItem. [ChangeLog][QtQuick][QQuickWindow] Set the window as the QObject-parent of the contentItem to ensure consistent behavior for calling findChildren() on QQuickWindow and QQuickWindow::contentItem. [ChangeLog][QtQuick][QQuickView] Set the window's contentItem as the QObject-parent of the rootObject to ensure consistent behavior for calling findChildren() on QQuickWindow::contentItem and QQuickView::rootObject. Change-Id: Idb7834eb5e560088ca849e6ce90e6fa3b3ae3e91 Reviewed-by: Mitch Curtis --- src/quick/items/qquickview.cpp | 1 + src/quick/items/qquickwindow.cpp | 1 + 2 files changed, 2 insertions(+) (limited to 'src') diff --git a/src/quick/items/qquickview.cpp b/src/quick/items/qquickview.cpp index 8313b53a7d..fca1805fc9 100644 --- a/src/quick/items/qquickview.cpp +++ b/src/quick/items/qquickview.cpp @@ -496,6 +496,7 @@ void QQuickViewPrivate::setRootObject(QObject *obj) if (QQuickItem *sgItem = qobject_cast(obj)) { root = sgItem; sgItem->setParentItem(q->QQuickWindow::contentItem()); + QQml_setParent_noEvent(sgItem, q->QQuickWindow::contentItem()); } else if (qobject_cast(obj)) { qWarning() << "QQuickView does not support using windows as a root item." << endl << endl diff --git a/src/quick/items/qquickwindow.cpp b/src/quick/items/qquickwindow.cpp index c441cfc357..d30f1c3f78 100644 --- a/src/quick/items/qquickwindow.cpp +++ b/src/quick/items/qquickwindow.cpp @@ -526,6 +526,7 @@ void QQuickWindowPrivate::init(QQuickWindow *c, QQuickRenderControl *control) Q_Q(QQuickWindow); contentItem = new QQuickRootItem; + QQml_setParent_noEvent(contentItem, c); QQmlEngine::setObjectOwnership(contentItem, QQmlEngine::CppOwnership); QQuickItemPrivate *contentItemPrivate = QQuickItemPrivate::get(contentItem); contentItemPrivate->window = q; -- cgit v1.2.3 From d77587b95f490ba9be372acfb81a1659f2844b2f Mon Sep 17 00:00:00 2001 From: Thiago Macieira Date: Tue, 18 Apr 2017 16:51:28 -0700 Subject: Move Q_REQUIRED_RESULT to the beginning of the declaration MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit That's the correct place and works with C++11 attributes. Change-Id: I7814054a102a407d876ffffd14b6a2f74423c222 Reviewed-by: Sérgio Martins --- src/qml/compiler/qqmlpropertyvalidator_p.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/qml/compiler/qqmlpropertyvalidator_p.h b/src/qml/compiler/qqmlpropertyvalidator_p.h index d0bd314461..e37b8141f4 100644 --- a/src/qml/compiler/qqmlpropertyvalidator_p.h +++ b/src/qml/compiler/qqmlpropertyvalidator_p.h @@ -69,8 +69,8 @@ private: bool canCoerce(int to, QQmlPropertyCache *fromMo) const; - QVector recordError(const QV4::CompiledData::Location &location, const QString &description) const Q_REQUIRED_RESULT; - QVector recordError(const QQmlCompileError &error) const Q_REQUIRED_RESULT; + Q_REQUIRED_RESULT QVector recordError(const QV4::CompiledData::Location &location, const QString &description) const; + Q_REQUIRED_RESULT QVector recordError(const QQmlCompileError &error) const; QString stringAt(int index) const { return qmlUnit->stringAt(index); } QQmlEnginePrivate *enginePrivate; -- cgit v1.2.3 From d7b45f7dc1d5f28ecdb022c5a4c7673bc55257c8 Mon Sep 17 00:00:00 2001 From: Sami Nurmenniemi Date: Mon, 29 May 2017 10:21:38 +0300 Subject: Add Qt.platform.pluginName property This exposes QGuiApplication::platformName() for qml. It is required at least for tests that are run on the "offscreen" platform (armv7 tests on qemu). [ChangeLog][QtQuick] Added Qt.platform.pluginName property. Task-number: QTBUG-60268 Change-Id: Ie55a282485d4d76ffe7ed8e77359ad7183f579c2 Reviewed-by: Simon Hausmann --- src/qml/qml/qqmlengine.cpp | 6 ++++++ src/qml/qml/qqmlglobal.cpp | 2 ++ src/qml/qml/qqmlglobal_p.h | 1 + src/qml/qml/qqmlplatform.cpp | 6 ++++++ src/qml/qml/qqmlplatform_p.h | 2 ++ src/quick/util/qquickglobal.cpp | 5 +++++ 6 files changed, 22 insertions(+) (limited to 'src') diff --git a/src/qml/qml/qqmlengine.cpp b/src/qml/qml/qqmlengine.cpp index 4a21acb050..d8779e0d12 100644 --- a/src/qml/qml/qqmlengine.cpp +++ b/src/qml/qml/qqmlengine.cpp @@ -449,6 +449,12 @@ The following functions are also on the Qt object. \li \c "windows" - Windows \li \c "winrt" - WinRT / UWP \endlist + + \row + \li \c platform.pluginName + \li This is the name of the platform set on the QGuiApplication instance + as returned by \l QGuiApplication::platformName() + \endtable */ diff --git a/src/qml/qml/qqmlglobal.cpp b/src/qml/qml/qqmlglobal.cpp index 7939656107..6418812bae 100644 --- a/src/qml/qml/qqmlglobal.cpp +++ b/src/qml/qml/qqmlglobal.cpp @@ -343,6 +343,8 @@ QObject *QQmlGuiProvider::styleHints() return o; } +QString QQmlGuiProvider::pluginName() const { return QString(); } + static QQmlGuiProvider *guiProvider = 0; Q_QML_PRIVATE_EXPORT QQmlGuiProvider *QQml_setGuiProvider(QQmlGuiProvider *newProvider) diff --git a/src/qml/qml/qqmlglobal_p.h b/src/qml/qml/qqmlglobal_p.h index 707814e781..a6c113f5a7 100644 --- a/src/qml/qml/qqmlglobal_p.h +++ b/src/qml/qml/qqmlglobal_p.h @@ -311,6 +311,7 @@ public: virtual QObject *styleHints(); virtual QStringList fontFamilies(); virtual bool openUrlExternally(QUrl &); + virtual QString pluginName() const; }; Q_QML_PRIVATE_EXPORT QQmlGuiProvider *QQml_setGuiProvider(QQmlGuiProvider *); diff --git a/src/qml/qml/qqmlplatform.cpp b/src/qml/qml/qqmlplatform.cpp index 165cde5eb3..a8c402af2e 100644 --- a/src/qml/qml/qqmlplatform.cpp +++ b/src/qml/qml/qqmlplatform.cpp @@ -38,6 +38,7 @@ ****************************************************************************/ #include "qqmlplatform_p.h" +#include "qqmlglobal_p.h" QT_BEGIN_NAMESPACE @@ -78,6 +79,11 @@ QString QQmlPlatform::os() #endif } +QString QQmlPlatform::pluginName() const +{ + return QQml_guiProvider()->pluginName(); +} + QT_END_NAMESPACE #include "moc_qqmlplatform_p.cpp" diff --git a/src/qml/qml/qqmlplatform_p.h b/src/qml/qml/qqmlplatform_p.h index 6887720adb..6246ca7105 100644 --- a/src/qml/qml/qqmlplatform_p.h +++ b/src/qml/qml/qqmlplatform_p.h @@ -61,12 +61,14 @@ class Q_QML_PRIVATE_EXPORT QQmlPlatform : public QObject { Q_OBJECT Q_PROPERTY(QString os READ os CONSTANT) + Q_PROPERTY(QString pluginName READ pluginName CONSTANT) public: explicit QQmlPlatform(QObject *parent = 0); virtual ~QQmlPlatform(); static QString os(); + QString pluginName() const; private: Q_DISABLE_COPY(QQmlPlatform) diff --git a/src/quick/util/qquickglobal.cpp b/src/quick/util/qquickglobal.cpp index 2070fd7ff0..1d2f3de1df 100644 --- a/src/quick/util/qquickglobal.cpp +++ b/src/quick/util/qquickglobal.cpp @@ -814,6 +814,11 @@ public: return false; #endif } + + QString pluginName() const override + { + return QGuiApplication::platformName(); + } }; -- cgit v1.2.3