diff options
187 files changed, 5010 insertions, 3172 deletions
diff --git a/.qmake.conf b/.qmake.conf index f03d05c7ac..4e4a28b8f9 100644 --- a/.qmake.conf +++ b/.qmake.conf @@ -1,4 +1,4 @@ load(qt_build_config) CONFIG += warning_clean -MODULE_VERSION = 5.9.0 +MODULE_VERSION = 5.10.0 diff --git a/examples/quick/rendercontrol/window_singlethreaded.cpp b/examples/quick/rendercontrol/window_singlethreaded.cpp index ef8f2fed43..bd4de9a7cb 100644 --- a/examples/quick/rendercontrol/window_singlethreaded.cpp +++ b/examples/quick/rendercontrol/window_singlethreaded.cpp @@ -82,6 +82,10 @@ WindowSingleThreaded::WindowSingleThreaded() { setSurfaceType(QSurface::OpenGLSurface); + // The rendercontrol does not necessarily need an FBO. Demonstrate this + // when requested. + m_onscreen = QCoreApplication::arguments().contains(QStringLiteral("--onscreen")); + QSurfaceFormat format; // Qt Quick may need a depth and stencil buffer. Always make sure these are available. format.setDepthBufferSize(16); @@ -164,8 +168,14 @@ void WindowSingleThreaded::createFbo() // The scene graph has been initialized. It is now time to create an FBO and associate // it with the QQuickWindow. m_dpr = devicePixelRatio(); - m_fbo = new QOpenGLFramebufferObject(size() * m_dpr, QOpenGLFramebufferObject::CombinedDepthStencil); - m_quickWindow->setRenderTarget(m_fbo); + if (!m_onscreen) { + m_fbo = new QOpenGLFramebufferObject(size() * m_dpr, QOpenGLFramebufferObject::CombinedDepthStencil); + m_quickWindow->setRenderTarget(m_fbo); + } else { + // Special case: No FBO. Render directly to the window's default framebuffer. + m_onscreenSize = size() * m_dpr; + m_quickWindow->setRenderTarget(0, m_onscreenSize); + } } void WindowSingleThreaded::destroyFbo() @@ -176,7 +186,10 @@ void WindowSingleThreaded::destroyFbo() void WindowSingleThreaded::render() { - if (!m_context->makeCurrent(m_offscreenSurface)) + QSurface *surface = m_offscreenSurface; + if (m_onscreen) + surface = this; + if (!m_context->makeCurrent(surface)) return; // Polish, synchronize and render the next frame (into our fbo). In this example @@ -195,7 +208,10 @@ void WindowSingleThreaded::render() m_quickReady = true; // Get something onto the screen. - m_cubeRenderer->render(this, m_context, m_quickReady ? m_fbo->texture() : 0); + if (!m_onscreen) + m_cubeRenderer->render(this, m_context, m_quickReady ? m_fbo->texture() : 0); + else + m_context->swapBuffers(this); } void WindowSingleThreaded::requestUpdate() @@ -237,7 +253,10 @@ void WindowSingleThreaded::run() updateSizes(); // Initialize the render control and our OpenGL resources. - m_context->makeCurrent(m_offscreenSurface); + QSurface *surface = m_offscreenSurface; + if (m_onscreen) + surface = this; + m_context->makeCurrent(surface); m_renderControl->initialize(m_context); m_quickInitialized = true; } @@ -266,7 +285,8 @@ void WindowSingleThreaded::exposeEvent(QExposeEvent *) { if (isExposed()) { if (!m_quickInitialized) { - m_cubeRenderer->render(this, m_context, m_quickReady ? m_fbo->texture() : 0); + if (!m_onscreen) + m_cubeRenderer->render(this, m_context, m_quickReady ? m_fbo->texture() : 0); startQuick(QStringLiteral("qrc:/rendercontrol/demo.qml")); } } @@ -274,7 +294,10 @@ void WindowSingleThreaded::exposeEvent(QExposeEvent *) void WindowSingleThreaded::resizeFbo() { - if (m_rootItem && m_context->makeCurrent(m_offscreenSurface)) { + QSurface *surface = m_offscreenSurface; + if (m_onscreen) + surface = this; + if (m_rootItem && m_context->makeCurrent(surface)) { delete m_fbo; createFbo(); m_context->doneCurrent(); @@ -287,8 +310,13 @@ void WindowSingleThreaded::resizeEvent(QResizeEvent *) { // If this is a resize after the scene is up and running, recreate the fbo and the // Quick item and scene. - if (m_fbo && m_fbo->size() != size() * devicePixelRatio()) - resizeFbo(); + if (!m_onscreen) { + if (m_fbo && m_fbo->size() != size() * devicePixelRatio()) + resizeFbo(); + } else { + if (m_onscreenSize != size() * devicePixelRatio()) + resizeFbo(); + } } void WindowSingleThreaded::handleScreenChange() diff --git a/examples/quick/rendercontrol/window_singlethreaded.h b/examples/quick/rendercontrol/window_singlethreaded.h index 534d6b9bc3..4736f036ad 100644 --- a/examples/quick/rendercontrol/window_singlethreaded.h +++ b/examples/quick/rendercontrol/window_singlethreaded.h @@ -97,6 +97,8 @@ private: QTimer m_updateTimer; CubeRenderer *m_cubeRenderer; qreal m_dpr; + bool m_onscreen; + QSize m_onscreenSize; }; #endif diff --git a/src/3rdparty/masm/assembler/MacroAssemblerX86_64.h b/src/3rdparty/masm/assembler/MacroAssemblerX86_64.h index 3566702413..14757f4ea2 100644 --- a/src/3rdparty/masm/assembler/MacroAssemblerX86_64.h +++ b/src/3rdparty/masm/assembler/MacroAssemblerX86_64.h @@ -327,14 +327,61 @@ public: m_assembler.xorq_ir(imm.m_value, srcDest); } + void lshift64(TrustedImm32 imm, RegisterID dest) + { + m_assembler.shlq_i8r(imm.m_value, dest); + } + + void lshift64(RegisterID src, RegisterID dest) + { + if (src == X86Registers::ecx) + m_assembler.shlq_CLr(dest); + else { + ASSERT(src != dest); + + // Can only shift by ecx, so we do some swapping if we see anything else. + swap(src, X86Registers::ecx); + m_assembler.shlq_CLr(dest == X86Registers::ecx ? src : dest); + swap(src, X86Registers::ecx); + } + } + + void rshift64(TrustedImm32 imm, RegisterID dest) + { + m_assembler.sarq_i8r(imm.m_value, dest); + } + + void rshift64(RegisterID src, RegisterID dest) + { + if (src == X86Registers::ecx) + m_assembler.sarq_CLr(dest); + else { + ASSERT(src != dest); + + // Can only shift by ecx, so we do some swapping if we see anything else. + swap(src, X86Registers::ecx); + m_assembler.sarq_CLr(dest == X86Registers::ecx ? src : dest); + swap(src, X86Registers::ecx); + } + } + void urshift64(TrustedImm32 imm, RegisterID dest) { m_assembler.shrq_i8r(imm.m_value, dest); } - void lshift64(TrustedImm32 imm, RegisterID dest) + void urshift64(RegisterID src, RegisterID dest) { - m_assembler.shlq_i8r(imm.m_value, dest); + if (src == X86Registers::ecx) + m_assembler.shrq_CLr(dest); + else { + ASSERT(src != dest); + + // Can only shift by ecx, so we do some swapping if we see anything else. + swap(src, X86Registers::ecx); + m_assembler.shrq_CLr(dest == X86Registers::ecx ? src : dest); + swap(src, X86Registers::ecx); + } } void load64(ImplicitAddress address, RegisterID dest) diff --git a/src/3rdparty/masm/assembler/X86Assembler.h b/src/3rdparty/masm/assembler/X86Assembler.h index 46f2cd714a..b71cf290f8 100644 --- a/src/3rdparty/masm/assembler/X86Assembler.h +++ b/src/3rdparty/masm/assembler/X86Assembler.h @@ -725,6 +725,21 @@ public: } } + void sarq_CLr(RegisterID dst) + { + m_formatter.oneByteOp64(OP_GROUP2_EvCL, GROUP2_OP_SAR, dst); + } + + void sarq_i8r(int imm, RegisterID dst) + { + if (imm == 1) + m_formatter.oneByteOp64(OP_GROUP2_Ev1, GROUP2_OP_SAR, dst); + else { + m_formatter.oneByteOp64(OP_GROUP2_EvIb, GROUP2_OP_SAR, dst); + m_formatter.immediate8(imm); + } + } + void shrq_i8r(int imm, RegisterID dst) { // ### doesn't work when removing the "0 &&" @@ -736,6 +751,11 @@ public: } } + void shrq_CLr(RegisterID dst) + { + m_formatter.oneByteOp64(OP_GROUP2_EvCL, GROUP2_OP_SHR, dst); + } + void shlq_i8r(int imm, RegisterID dst) { // ### doesn't work when removing the "0 &&" @@ -747,7 +767,10 @@ public: } } - + void shlq_CLr(RegisterID dst) + { + m_formatter.oneByteOp64(OP_GROUP2_EvCL, GROUP2_OP_SHL, dst); + } #endif void sarl_i8r(int imm, RegisterID dst) @@ -795,23 +818,6 @@ public: m_formatter.oneByteOp(OP_GROUP2_EvCL, GROUP2_OP_SHL, dst); } -#if CPU(X86_64) - void sarq_CLr(RegisterID dst) - { - m_formatter.oneByteOp64(OP_GROUP2_EvCL, GROUP2_OP_SAR, dst); - } - - void sarq_i8r(int imm, RegisterID dst) - { - if (imm == 1) - m_formatter.oneByteOp64(OP_GROUP2_Ev1, GROUP2_OP_SAR, dst); - else { - m_formatter.oneByteOp64(OP_GROUP2_EvIb, GROUP2_OP_SAR, dst); - m_formatter.immediate8(imm); - } - } -#endif - void imull_rr(RegisterID src, RegisterID dst) { m_formatter.twoByteOp(OP2_IMUL_GvEv, dst, src); diff --git a/src/particles/qquickimageparticle.cpp b/src/particles/qquickimageparticle.cpp index ccfebddb0e..fde491b1ef 100644 --- a/src/particles/qquickimageparticle.cpp +++ b/src/particles/qquickimageparticle.cpp @@ -118,15 +118,15 @@ public: Q_ASSERT(!m_fragment_code.isNull()); } - const char *vertexShader() const { return m_vertex_code.constData(); } - const char *fragmentShader() const { return m_fragment_code.constData(); } + const char *vertexShader() const override { return m_vertex_code.constData(); } + const char *fragmentShader() const override { return m_fragment_code.constData(); } - QList<QByteArray> attributes() const { + QList<QByteArray> attributes() const override { return QList<QByteArray>() << "vPosTex" << "vData" << "vVec" << "vColor" << "vDeformVec" << "vRotation"; }; - void initialize() { + void initialize() override { QSGSimpleMaterialShader<TabledMaterialData>::initialize(); program()->bind(); program()->setUniformValue("_qt_texture", 0); @@ -138,7 +138,7 @@ public: m_opacitytable_id = program()->uniformLocation("opacitytable"); } - void updateState(const TabledMaterialData* d, const TabledMaterialData*) { + void updateState(const TabledMaterialData* d, const TabledMaterialData*) override { glFuncs->glActiveTexture(GL_TEXTURE1); d->colorTable->bind(); @@ -192,15 +192,15 @@ public: Q_ASSERT(!m_fragment_code.isNull()); } - const char *vertexShader() const { return m_vertex_code.constData(); } - const char *fragmentShader() const { return m_fragment_code.constData(); } + const char *vertexShader() const override { return m_vertex_code.constData(); } + const char *fragmentShader() const override { return m_fragment_code.constData(); } - QList<QByteArray> attributes() const { + QList<QByteArray> attributes() const override { return QList<QByteArray>() << "vPosTex" << "vData" << "vVec" << "vColor" << "vDeformVec" << "vRotation"; }; - void initialize() { + void initialize() override { QSGSimpleMaterialShader<DeformableMaterialData>::initialize(); program()->bind(); program()->setUniformValue("_qt_texture", 0); @@ -209,7 +209,7 @@ public: m_entry_id = program()->uniformLocation("entry"); } - void updateState(const DeformableMaterialData* d, const DeformableMaterialData*) { + void updateState(const DeformableMaterialData* d, const DeformableMaterialData*) override { d->texture->bind(); program()->setUniformValue(m_timestamp_id, (float) d->timestamp); @@ -259,15 +259,15 @@ public: Q_ASSERT(!m_fragment_code.isNull()); } - const char *vertexShader() const { return m_vertex_code.constData(); } - const char *fragmentShader() const { return m_fragment_code.constData(); } + const char *vertexShader() const override { return m_vertex_code.constData(); } + const char *fragmentShader() const override { return m_fragment_code.constData(); } - QList<QByteArray> attributes() const { + QList<QByteArray> attributes() const override { return QList<QByteArray>() << "vPosTex" << "vData" << "vVec" << "vColor" << "vDeformVec" << "vRotation" << "vAnimData" << "vAnimPos"; } - void initialize() { + void initialize() override { QSGSimpleMaterialShader<SpriteMaterialData>::initialize(); program()->bind(); program()->setUniformValue("_qt_texture", 0); @@ -280,7 +280,7 @@ public: m_opacitytable_id = program()->uniformLocation("opacitytable"); } - void updateState(const SpriteMaterialData* d, const SpriteMaterialData*) { + void updateState(const SpriteMaterialData* d, const SpriteMaterialData*) override { glFuncs->glActiveTexture(GL_TEXTURE1); d->colorTable->bind(); @@ -333,10 +333,10 @@ public: Q_ASSERT(!m_fragment_code.isNull()); } - const char *vertexShader() const { return m_vertex_code.constData(); } - const char *fragmentShader() const { return m_fragment_code.constData(); } + const char *vertexShader() const override { return m_vertex_code.constData(); } + const char *fragmentShader() const override { return m_fragment_code.constData(); } - void activate() { + void activate() override { QSGSimpleMaterialShader<ColoredMaterialData>::activate(); #if !defined(QT_OPENGL_ES_2) && !defined(Q_OS_WIN) glEnable(GL_POINT_SPRITE); @@ -344,7 +344,7 @@ public: #endif } - void deactivate() { + void deactivate() override { QSGSimpleMaterialShader<ColoredMaterialData>::deactivate(); #if !defined(QT_OPENGL_ES_2) && !defined(Q_OS_WIN) glDisable(GL_POINT_SPRITE); @@ -352,11 +352,11 @@ public: #endif } - QList<QByteArray> attributes() const { + QList<QByteArray> attributes() const override { return QList<QByteArray>() << "vPos" << "vData" << "vVec" << "vColor"; } - void initialize() { + void initialize() override { QSGSimpleMaterialShader<ColoredMaterialData>::initialize(); program()->bind(); program()->setUniformValue("_qt_texture", 0); @@ -365,7 +365,7 @@ public: m_entry_id = program()->uniformLocation("entry"); } - void updateState(const ColoredMaterialData* d, const ColoredMaterialData*) { + void updateState(const ColoredMaterialData* d, const ColoredMaterialData*) override { d->texture->bind(); program()->setUniformValue(m_timestamp_id, (float) d->timestamp); @@ -407,10 +407,10 @@ public: Q_ASSERT(!m_fragment_code.isNull()); } - const char *vertexShader() const { return m_vertex_code.constData(); } - const char *fragmentShader() const { return m_fragment_code.constData(); } + const char *vertexShader() const override { return m_vertex_code.constData(); } + const char *fragmentShader() const override { return m_fragment_code.constData(); } - void activate() { + void activate() override { QSGSimpleMaterialShader<SimpleMaterialData>::activate(); #if !defined(QT_OPENGL_ES_2) && !defined(Q_OS_WIN) glEnable(GL_POINT_SPRITE); @@ -418,7 +418,7 @@ public: #endif } - void deactivate() { + void deactivate() override { QSGSimpleMaterialShader<SimpleMaterialData>::deactivate(); #if !defined(QT_OPENGL_ES_2) && !defined(Q_OS_WIN) glDisable(GL_POINT_SPRITE); @@ -426,11 +426,11 @@ public: #endif } - QList<QByteArray> attributes() const { + QList<QByteArray> attributes() const override { return QList<QByteArray>() << "vPos" << "vData" << "vVec"; } - void initialize() { + void initialize() override { QSGSimpleMaterialShader<SimpleMaterialData>::initialize(); program()->bind(); program()->setUniformValue("_qt_texture", 0); @@ -439,7 +439,7 @@ public: m_entry_id = program()->uniformLocation("entry"); } - void updateState(const SimpleMaterialData* d, const SimpleMaterialData*) { + void updateState(const SimpleMaterialData* d, const SimpleMaterialData*) override { d->texture->bind(); program()->setUniformValue(m_timestamp_id, (float) d->timestamp); diff --git a/src/plugins/qmltooling/qmldbg_debugger/qv4datacollector.cpp b/src/plugins/qmltooling/qmldbg_debugger/qv4datacollector.cpp index b4b95f6713..430ba4f255 100644 --- a/src/plugins/qmltooling/qmldbg_debugger/qv4datacollector.cpp +++ b/src/plugins/qmltooling/qmldbg_debugger/qv4datacollector.cpp @@ -55,11 +55,11 @@ QT_BEGIN_NAMESPACE -QV4::CallContext *QV4DataCollector::findContext(int frame) +QV4::SimpleCallContext *QV4DataCollector::findContext(int frame) { QV4::ExecutionContext *ctx = engine()->currentContext; while (ctx) { - QV4::CallContext *cCtxt = ctx->asCallContext(); + QV4::SimpleCallContext *cCtxt = ctx->asSimpleCallContext(); if (cCtxt && cCtxt->d()->v4Function) { if (frame < 1) return cCtxt; @@ -71,7 +71,7 @@ QV4::CallContext *QV4DataCollector::findContext(int frame) return 0; } -QV4::Heap::CallContext *QV4DataCollector::findScope(QV4::ExecutionContext *ctxt, int scope) +QV4::Heap::SimpleCallContext *QV4DataCollector::findScope(QV4::ExecutionContext *ctxt, int scope) { if (!ctxt) return 0; @@ -81,7 +81,7 @@ QV4::Heap::CallContext *QV4DataCollector::findScope(QV4::ExecutionContext *ctxt, for (; scope > 0 && ctx; --scope) ctx = ctx->d()->outer; - return (ctx && ctx->d()) ? ctx->asCallContext()->d() : 0; + return (ctx && ctx->d()) ? ctx->asSimpleCallContext()->d() : 0; } QVector<QV4::Heap::ExecutionContext::ContextType> QV4DataCollector::getScopeTypes(int frame) @@ -89,7 +89,7 @@ QVector<QV4::Heap::ExecutionContext::ContextType> QV4DataCollector::getScopeType QVector<QV4::Heap::ExecutionContext::ContextType> types; QV4::Scope scope(engine()); - QV4::CallContext *sctxt = findContext(frame); + QV4::SimpleCallContext *sctxt = findContext(frame); if (!sctxt || sctxt->d()->type < QV4::Heap::ExecutionContext::Type_QmlContext) return types; @@ -297,9 +297,11 @@ bool QV4DataCollector::collectScope(QJsonObject *dict, int frameNr, int scopeNr) QV4::ScopedObject scopeObject(scope, engine()->newObject()); Q_ASSERT(names.size() == collectedRefs.size()); - for (int i = 0, ei = collectedRefs.size(); i != ei; ++i) - scopeObject->put(engine(), names.at(i), - QV4::Value::fromReturnedValue(getValue(collectedRefs.at(i)))); + QV4::ScopedString propName(scope); + for (int i = 0, ei = collectedRefs.size(); i != ei; ++i) { + propName = engine()->newString(names.at(i)); + scopeObject->put(propName, QV4::Value::fromReturnedValue(getValue(collectedRefs.at(i)))); + } Ref scopeObjectRef = addRef(scopeObject); if (m_redundantRefs) { @@ -338,7 +340,7 @@ QJsonObject QV4DataCollector::buildFrame(const QV4::StackFrame &stackFrame, int QV4::Scope scope(engine()); QV4::ScopedContext ctxt(scope, findContext(frameNr)); while (ctxt) { - if (QV4::CallContext *cCtxt = ctxt->asCallContext()) { + if (QV4::SimpleCallContext *cCtxt = ctxt->asSimpleCallContext()) { if (cCtxt->d()->activation) break; } @@ -346,7 +348,7 @@ QJsonObject QV4DataCollector::buildFrame(const QV4::StackFrame &stackFrame, int } if (ctxt) { - QV4::ScopedValue o(scope, ctxt->asCallContext()->d()->activation); + QV4::ScopedValue o(scope, ctxt->asSimpleCallContext()->d()->activation); frame[QLatin1String("receiver")] = toRef(collect(o)); } @@ -398,8 +400,8 @@ QV4DataCollector::Ref QV4DataCollector::addRef(QV4::Value value, bool deduplicat { class ExceptionStateSaver { - quint32 *hasExceptionLoc; - quint32 hadException; + quint8 *hasExceptionLoc; + quint8 hadException; public: ExceptionStateSaver(QV4::ExecutionEngine *engine) diff --git a/src/plugins/qmltooling/qmldbg_debugger/qv4datacollector.h b/src/plugins/qmltooling/qmldbg_debugger/qv4datacollector.h index 2c2514a1b3..de12e8d527 100644 --- a/src/plugins/qmltooling/qmldbg_debugger/qv4datacollector.h +++ b/src/plugins/qmltooling/qmldbg_debugger/qv4datacollector.h @@ -58,11 +58,11 @@ public: typedef uint Ref; typedef QVector<uint> Refs; - static QV4::Heap::CallContext *findScope(QV4::ExecutionContext *ctxt, int scope); + static QV4::Heap::SimpleCallContext *findScope(QV4::ExecutionContext *ctxt, int scope); static int encodeScopeType(QV4::Heap::ExecutionContext::ContextType scopeType); QVector<QV4::Heap::ExecutionContext::ContextType> getScopeTypes(int frame); - QV4::CallContext *findContext(int frame); + QV4::SimpleCallContext *findContext(int frame); QV4DataCollector(QV4::ExecutionEngine *engine); diff --git a/src/plugins/qmltooling/qmldbg_debugger/qv4debugjob.cpp b/src/plugins/qmltooling/qmldbg_debugger/qv4debugjob.cpp index a624cf22a4..107ec60943 100644 --- a/src/plugins/qmltooling/qmldbg_debugger/qv4debugjob.cpp +++ b/src/plugins/qmltooling/qmldbg_debugger/qv4debugjob.cpp @@ -90,12 +90,15 @@ void JavaScriptJob::run() QQmlContextPrivate *ctxtPriv = QQmlContextPrivate::get(qmlRootContext); QV4::ScopedObject withContext(scope, engine->newObject()); + QV4::ScopedString k(scope); + QV4::ScopedValue v(scope); for (int ii = 0; ii < ctxtPriv->instances.count(); ++ii) { QObject *object = ctxtPriv->instances.at(ii); if (QQmlContext *context = qmlContext(object)) { if (QQmlContextData *cdata = QQmlContextData::get(context)) { - QV4::ScopedValue v(scope, QV4::QObjectWrapper::wrap(engine, object)); - withContext->put(engine, cdata->findObjectId(object), v); + v = QV4::QObjectWrapper::wrap(engine, object); + k = engine->newString(cdata->findObjectId(object)); + withContext->put(k, v); } } } diff --git a/src/plugins/qmltooling/qmldbg_local/qlocalclientconnection.cpp b/src/plugins/qmltooling/qmldbg_local/qlocalclientconnection.cpp index 6152853917..97e4b4e3e4 100644 --- a/src/plugins/qmltooling/qmldbg_local/qlocalclientconnection.cpp +++ b/src/plugins/qmltooling/qmldbg_local/qlocalclientconnection.cpp @@ -57,15 +57,15 @@ public: QLocalClientConnection(); ~QLocalClientConnection(); - void setServer(QQmlDebugServer *server); - bool setPortRange(int portFrom, int portTo, bool block, const QString &hostaddress); - bool setFileName(const QString &filename, bool block); + void setServer(QQmlDebugServer *server) override; + bool setPortRange(int portFrom, int portTo, bool block, const QString &hostaddress) override; + bool setFileName(const QString &filename, bool block) override; - bool isConnected() const; - void disconnect(); + bool isConnected() const override; + void disconnect() override; - void waitForConnection(); - void flush(); + void waitForConnection() override; + void flush() override; private: void connectionEstablished(); diff --git a/src/plugins/qmltooling/qmldbg_nativedebugger/qqmlnativedebugservice.cpp b/src/plugins/qmltooling/qmldbg_nativedebugger/qqmlnativedebugservice.cpp index 7f842419e7..6cb1ab4051 100644 --- a/src/plugins/qmltooling/qmldbg_nativedebugger/qqmlnativedebugservice.cpp +++ b/src/plugins/qmltooling/qmldbg_nativedebugger/qqmlnativedebugservice.cpp @@ -481,17 +481,20 @@ void NativeDebugger::handleVariables(QJsonObject *response, const QJsonObject &a QJsonArray output; QV4::Scope scope(engine); - if (QV4::CallContext *callContext = executionContext->asCallContext()) { + if (QV4::SimpleCallContext *callContext = executionContext->asSimpleCallContext()) { QV4::Value thisObject = callContext->thisObject(); collector.collect(&output, QString(), QStringLiteral("this"), thisObject); QV4::Identifier *const *variables = callContext->variables(); QV4::Identifier *const *formals = callContext->formals(); - for (unsigned i = 0, ei = callContext->variableCount(); i != ei; ++i) { - QString qName; - if (QV4::Identifier *name = variables[i]) - qName = name->string; - QV4::Value val = callContext->d()->locals[i]; - collector.collect(&output, QString(), qName, val); + if (callContext->d()->type == QV4::Heap::ExecutionContext::Type_CallContext) { + QV4::CallContext *ctx = static_cast<QV4::CallContext *>(callContext); + for (unsigned i = 0, ei = ctx->variableCount(); i != ei; ++i) { + QString qName; + if (QV4::Identifier *name = variables[i]) + qName = name->string; + QV4::Value val = ctx->d()->locals[i]; + collector.collect(&output, QString(), qName, val); + } } for (unsigned i = 0, ei = callContext->formalCount(); i != ei; ++i) { QString qName; diff --git a/src/plugins/qmltooling/qmldbg_server/qqmldebugserver.cpp b/src/plugins/qmltooling/qmldbg_server/qqmldebugserver.cpp index f6f48e43a4..bcfb3b8a75 100644 --- a/src/plugins/qmltooling/qmldbg_server/qqmldebugserver.cpp +++ b/src/plugins/qmltooling/qmldbg_server/qqmldebugserver.cpp @@ -114,7 +114,7 @@ public: return m_pluginName; } - void run(); + void run() override; private: QQmlDebugServerImpl *m_server; diff --git a/src/plugins/qmltooling/qmldbg_tcp/qtcpserverconnection.cpp b/src/plugins/qmltooling/qmldbg_tcp/qtcpserverconnection.cpp index b305c3f535..af4f5292ba 100644 --- a/src/plugins/qmltooling/qmldbg_tcp/qtcpserverconnection.cpp +++ b/src/plugins/qmltooling/qmldbg_tcp/qtcpserverconnection.cpp @@ -55,15 +55,15 @@ public: QTcpServerConnection(); ~QTcpServerConnection(); - void setServer(QQmlDebugServer *server); - bool setPortRange(int portFrom, int portTo, bool block, const QString &hostaddress); - bool setFileName(const QString &fileName, bool block); + void setServer(QQmlDebugServer *server) override; + bool setPortRange(int portFrom, int portTo, bool block, const QString &hostaddress) override; + bool setFileName(const QString &fileName, bool block) override; - bool isConnected() const; - void disconnect(); + bool isConnected() const override; + void disconnect() override; - void waitForConnection(); - void flush(); + void waitForConnection() override; + void flush() override; private: void newConnection(); diff --git a/src/plugins/scenegraph/d3d12/qsgd3d12layer_p.h b/src/plugins/scenegraph/d3d12/qsgd3d12layer_p.h index f1ab580a84..f828843227 100644 --- a/src/plugins/scenegraph/d3d12/qsgd3d12layer_p.h +++ b/src/plugins/scenegraph/d3d12/qsgd3d12layer_p.h @@ -86,6 +86,7 @@ public: void setDevicePixelRatio(qreal ratio) override; void setMirrorHorizontal(bool mirror) override; void setMirrorVertical(bool mirror) override; + void setSamples(int) override { } public Q_SLOTS: void markDirtyTexture() override; diff --git a/src/plugins/scenegraph/openvg/qsgopenvglayer.h b/src/plugins/scenegraph/openvg/qsgopenvglayer.h index 2af0bfb40f..8deedc3347 100644 --- a/src/plugins/scenegraph/openvg/qsgopenvglayer.h +++ b/src/plugins/scenegraph/openvg/qsgopenvglayer.h @@ -83,6 +83,7 @@ public: void setDevicePixelRatio(qreal ratio) override; void setMirrorHorizontal(bool mirror) override; void setMirrorVertical(bool mirror) override; + void setSamples(int) override { } public slots: void markDirtyTexture() override; diff --git a/src/qml/compiler/qqmlirbuilder.cpp b/src/qml/compiler/qqmlirbuilder.cpp index 0a6efa7867..18fccc8f43 100644 --- a/src/qml/compiler/qqmlirbuilder.cpp +++ b/src/qml/compiler/qqmlirbuilder.cpp @@ -1605,7 +1605,7 @@ QVector<int> JSCodeGen::generateJSCodeForFunctionsAndBindings(const QList<Compil scan.leaveEnvironment(); scan.leaveEnvironment(); - _env = 0; + _variableEnvironment = 0; _function = _module->functions.at(defineFunction(QStringLiteral("context scope"), qmlRoot, 0, 0)); for (int i = 0; i < functions.count(); ++i) { diff --git a/src/qml/compiler/qv4codegen.cpp b/src/qml/compiler/qv4codegen.cpp index a10c0730bf..3234e7ee63 100644 --- a/src/qml/compiler/qv4codegen.cpp +++ b/src/qml/compiler/qv4codegen.cpp @@ -95,7 +95,7 @@ static bool cjumpCanHandle(IR::AluOp op) Codegen::ScanFunctions::ScanFunctions(Codegen *cg, const QString &sourceCode, CompilationMode defaultProgramMode) : _cg(cg) , _sourceCode(sourceCode) - , _env(0) + , _variableEnvironment(0) , _allowFuncDecls(true) , defaultProgramMode(defaultProgramMode) { @@ -109,17 +109,17 @@ void Codegen::ScanFunctions::operator()(Node *node) void Codegen::ScanFunctions::enterEnvironment(Node *node, CompilationMode compilationMode) { - Environment *e = _cg->newEnvironment(node, _env, compilationMode); + Environment *e = _cg->newEnvironment(node, _variableEnvironment, compilationMode); if (!e->isStrict) e->isStrict = _cg->_strictMode; _envStack.append(e); - _env = e; + _variableEnvironment = e; } void Codegen::ScanFunctions::leaveEnvironment() { _envStack.pop(); - _env = _envStack.isEmpty() ? 0 : _envStack.top(); + _variableEnvironment = _envStack.isEmpty() ? 0 : _envStack.top(); } void Codegen::ScanFunctions::checkDirectivePrologue(SourceElements *ast) @@ -135,7 +135,7 @@ void Codegen::ScanFunctions::checkDirectivePrologue(SourceElements *ast) continue; QStringRef str = _sourceCode.midRef(strLit->literalToken.offset + 1, strLit->literalToken.length - 2); if (str == QLatin1String("use strict")) { - _env->isStrict = true; + _variableEnvironment->isStrict = true; } else { // TODO: give a warning. } @@ -150,7 +150,7 @@ void Codegen::ScanFunctions::checkDirectivePrologue(SourceElements *ast) void Codegen::ScanFunctions::checkName(const QStringRef &name, const SourceLocation &loc) { - if (_env->isStrict) { + if (_variableEnvironment->isStrict) { if (name == QLatin1String("implements") || name == QLatin1String("interface") || name == QLatin1String("let") @@ -168,7 +168,7 @@ void Codegen::ScanFunctions::checkForArguments(AST::FormalParameterList *paramet { while (parameters) { if (parameters->name == QLatin1String("arguments")) - _env->usesArgumentsObject = Environment::ArgumentsObjectNotUsed; + _variableEnvironment->usesArgumentsObject = Environment::ArgumentsObjectNotUsed; parameters = parameters->next; } } @@ -187,19 +187,19 @@ void Codegen::ScanFunctions::endVisit(Program *) bool Codegen::ScanFunctions::visit(CallExpression *ast) { - if (! _env->hasDirectEval) { + if (! _variableEnvironment->hasDirectEval) { if (IdentifierExpression *id = cast<IdentifierExpression *>(ast->base)) { if (id->name == QLatin1String("eval")) { - if (_env->usesArgumentsObject == Environment::ArgumentsObjectUnknown) - _env->usesArgumentsObject = Environment::ArgumentsObjectUsed; - _env->hasDirectEval = true; + if (_variableEnvironment->usesArgumentsObject == Environment::ArgumentsObjectUnknown) + _variableEnvironment->usesArgumentsObject = Environment::ArgumentsObjectUsed; + _variableEnvironment->hasDirectEval = true; } } } int argc = 0; for (ArgumentList *it = ast->arguments; it; it = it->next) ++argc; - _env->maxNumberOfArguments = qMax(_env->maxNumberOfArguments, argc); + _variableEnvironment->maxNumberOfArguments = qMax(_variableEnvironment->maxNumberOfArguments, argc); return true; } @@ -208,7 +208,7 @@ bool Codegen::ScanFunctions::visit(NewMemberExpression *ast) int argc = 0; for (ArgumentList *it = ast->arguments; it; it = it->next) ++argc; - _env->maxNumberOfArguments = qMax(_env->maxNumberOfArguments, argc); + _variableEnvironment->maxNumberOfArguments = qMax(_variableEnvironment->maxNumberOfArguments, argc); return true; } @@ -224,26 +224,38 @@ bool Codegen::ScanFunctions::visit(ArrayLiteral *ast) for (Elision *elision = ast->elision->next; elision; elision = elision->next) ++index; } - _env->maxNumberOfArguments = qMax(_env->maxNumberOfArguments, index); + _variableEnvironment->maxNumberOfArguments = qMax(_variableEnvironment->maxNumberOfArguments, index); return true; } bool Codegen::ScanFunctions::visit(VariableDeclaration *ast) { - if (_env->isStrict && (ast->name == QLatin1String("eval") || ast->name == QLatin1String("arguments"))) + if (_variableEnvironment->isStrict && (ast->name == QLatin1String("eval") || ast->name == QLatin1String("arguments"))) _cg->throwSyntaxError(ast->identifierToken, QStringLiteral("Variable name may not be eval or arguments in strict mode")); checkName(ast->name, ast->identifierToken); if (ast->name == QLatin1String("arguments")) - _env->usesArgumentsObject = Environment::ArgumentsObjectNotUsed; - _env->enter(ast->name.toString(), ast->expression ? Environment::VariableDefinition : Environment::VariableDeclaration); + _variableEnvironment->usesArgumentsObject = Environment::ArgumentsObjectNotUsed; + if (ast->scope == AST::VariableDeclaration::VariableScope::ReadOnlyBlockScope && !ast->expression) { + _cg->throwSyntaxError(ast->identifierToken, QStringLiteral("Missing initializer in const declaration")); + return false; + } + QString name = ast->name.toString(); + const Environment::Member *m = 0; + if (_variableEnvironment->memberInfo(name, &m)) { + if (m->isLexicallyScoped() || ast->isLexicallyScoped()) { + _cg->throwSyntaxError(ast->identifierToken, QStringLiteral("Identifier %1 has already been declared").arg(name)); + return false; + } + } + _variableEnvironment->enter(ast->name.toString(), ast->expression ? Environment::VariableDefinition : Environment::VariableDeclaration, ast->scope); return true; } bool Codegen::ScanFunctions::visit(IdentifierExpression *ast) { checkName(ast->name, ast->identifierToken); - if (_env->usesArgumentsObject == Environment::ArgumentsObjectUnknown && ast->name == QLatin1String("arguments")) - _env->usesArgumentsObject = Environment::ArgumentsObjectUsed; + if (_variableEnvironment->usesArgumentsObject == Environment::ArgumentsObjectUnknown && ast->name == QLatin1String("arguments")) + _variableEnvironment->usesArgumentsObject = Environment::ArgumentsObjectUsed; return true; } @@ -275,7 +287,7 @@ bool Codegen::ScanFunctions::visit(FunctionExpression *ast) void Codegen::ScanFunctions::enterFunction(FunctionExpression *ast, bool enterName, bool isExpression) { - if (_env->isStrict && (ast->name == QLatin1String("eval") || ast->name == QLatin1String("arguments"))) + if (_variableEnvironment->isStrict && (ast->name == QLatin1String("eval") || ast->name == QLatin1String("arguments"))) _cg->throwSyntaxError(ast->identifierToken, QStringLiteral("Function name may not be eval or arguments in strict mode")); enterFunction(ast, ast->name.toString(), ast->formals, ast->body, enterName ? ast : 0, isExpression); } @@ -296,7 +308,7 @@ bool Codegen::ScanFunctions::visit(ObjectLiteral *ast) if (AST::cast<AST::PropertyGetterSetter *>(it->assignment)) ++argc; } - _env->maxNumberOfArguments = qMax(_env->maxNumberOfArguments, argc); + _variableEnvironment->maxNumberOfArguments = qMax(_variableEnvironment->maxNumberOfArguments, argc); TemporaryBoolAssignment allowFuncDecls(_allowFuncDecls, true); Node::accept(ast->properties, this); @@ -328,7 +340,7 @@ void Codegen::ScanFunctions::endVisit(FunctionDeclaration *) bool Codegen::ScanFunctions::visit(WithStatement *ast) { - if (_env->isStrict) { + if (_variableEnvironment->isStrict) { _cg->throwSyntaxError(ast->withToken, QStringLiteral("'with' statement is not allowed in strict mode")); return false; } @@ -338,7 +350,7 @@ bool Codegen::ScanFunctions::visit(WithStatement *ast) bool Codegen::ScanFunctions::visit(DoWhileStatement *ast) { { - TemporaryBoolAssignment allowFuncDecls(_allowFuncDecls, !_env->isStrict); + TemporaryBoolAssignment allowFuncDecls(_allowFuncDecls, !_variableEnvironment->isStrict); Node::accept(ast->statement, this); } Node::accept(ast->expression, this); @@ -350,7 +362,7 @@ bool Codegen::ScanFunctions::visit(ForStatement *ast) { Node::accept(ast->condition, this); Node::accept(ast->expression, this); - TemporaryBoolAssignment allowFuncDecls(_allowFuncDecls, !_env->isStrict); + TemporaryBoolAssignment allowFuncDecls(_allowFuncDecls, !_variableEnvironment->isStrict); Node::accept(ast->statement, this); return false; @@ -361,7 +373,7 @@ bool Codegen::ScanFunctions::visit(LocalForStatement *ast) { Node::accept(ast->condition, this); Node::accept(ast->expression, this); - TemporaryBoolAssignment allowFuncDecls(_allowFuncDecls, !_env->isStrict); + TemporaryBoolAssignment allowFuncDecls(_allowFuncDecls, !_variableEnvironment->isStrict); Node::accept(ast->statement, this); return false; @@ -371,7 +383,7 @@ bool Codegen::ScanFunctions::visit(ForEachStatement *ast) { Node::accept(ast->initialiser, this); Node::accept(ast->expression, this); - TemporaryBoolAssignment allowFuncDecls(_allowFuncDecls, !_env->isStrict); + TemporaryBoolAssignment allowFuncDecls(_allowFuncDecls, !_variableEnvironment->isStrict); Node::accept(ast->statement, this); return false; @@ -381,7 +393,7 @@ bool Codegen::ScanFunctions::visit(LocalForEachStatement *ast) { Node::accept(ast->declaration, this); Node::accept(ast->expression, this); - TemporaryBoolAssignment allowFuncDecls(_allowFuncDecls, !_env->isStrict); + TemporaryBoolAssignment allowFuncDecls(_allowFuncDecls, !_variableEnvironment->isStrict); Node::accept(ast->statement, this); return false; @@ -389,12 +401,12 @@ bool Codegen::ScanFunctions::visit(LocalForEachStatement *ast) { bool Codegen::ScanFunctions::visit(ThisExpression *) { - _env->usesThis = true; + _variableEnvironment->usesThis = true; return false; } bool Codegen::ScanFunctions::visit(Block *ast) { - TemporaryBoolAssignment allowFuncDecls(_allowFuncDecls, _env->isStrict ? false : _allowFuncDecls); + TemporaryBoolAssignment allowFuncDecls(_allowFuncDecls, _variableEnvironment->isStrict ? false : _allowFuncDecls); Node::accept(ast->statements, this); return false; } @@ -402,26 +414,26 @@ bool Codegen::ScanFunctions::visit(Block *ast) { void Codegen::ScanFunctions::enterFunction(Node *ast, const QString &name, FormalParameterList *formals, FunctionBody *body, FunctionExpression *expr, bool isExpression) { bool wasStrict = false; - if (_env) { - _env->hasNestedFunctions = true; + if (_variableEnvironment) { + _variableEnvironment->hasNestedFunctions = true; // The identifier of a function expression cannot be referenced from the enclosing environment. if (expr) - _env->enter(name, Environment::FunctionDefinition, expr); + _variableEnvironment->enter(name, Environment::FunctionDefinition, AST::VariableDeclaration::FunctionScope, expr); if (name == QLatin1String("arguments")) - _env->usesArgumentsObject = Environment::ArgumentsObjectNotUsed; - wasStrict = _env->isStrict; + _variableEnvironment->usesArgumentsObject = Environment::ArgumentsObjectNotUsed; + wasStrict = _variableEnvironment->isStrict; } enterEnvironment(ast, FunctionCode); checkForArguments(formals); - _env->isNamedFunctionExpression = isExpression && !name.isEmpty(); - _env->formals = formals; + _variableEnvironment->isNamedFunctionExpression = isExpression && !name.isEmpty(); + _variableEnvironment->formals = formals; if (body) checkDirectivePrologue(body->elements); - if (wasStrict || _env->isStrict) { + if (wasStrict || _variableEnvironment->isStrict) { QStringList args; for (FormalParameterList *it = formals; it; it = it->next) { QString arg = it->name.toString(); @@ -445,7 +457,7 @@ Codegen::Codegen(bool strict) , _block(0) , _exitBlock(0) , _returnAddress(0) - , _env(0) + , _variableEnvironment(0) , _loop(0) , _labelledStatement(0) , _scopeAndFinally(0) @@ -465,7 +477,7 @@ void Codegen::generateFromProgram(const QString &fileName, Q_ASSERT(node); _module = module; - _env = 0; + _variableEnvironment = 0; _module->setFileName(fileName); @@ -484,7 +496,7 @@ void Codegen::generateFromFunctionExpression(const QString &fileName, { _module = module; _module->setFileName(fileName); - _env = 0; + _variableEnvironment = 0; ScanFunctions scan(this, sourceCode, GlobalCode); // fake a global environment @@ -501,14 +513,14 @@ void Codegen::generateFromFunctionExpression(const QString &fileName, void Codegen::enterEnvironment(Node *node) { - _env = _envMap.value(node); - Q_ASSERT(_env); + _variableEnvironment = _envMap.value(node); + Q_ASSERT(_variableEnvironment); } void Codegen::leaveEnvironment() { - Q_ASSERT(_env); - _env = _env->parent; + Q_ASSERT(_variableEnvironment); + _variableEnvironment = _variableEnvironment->parent; } void Codegen::enterLoop(Statement *node, IR::BasicBlock *breakBlock, IR::BasicBlock *continueBlock) @@ -1401,7 +1413,7 @@ bool Codegen::visit(DeleteExpression *ast) return false; // Temporaries cannot be deleted IR::ArgLocal *al = expr->asArgLocal(); - if (al && al->index < static_cast<unsigned>(_env->members.size())) { + if (al && al->index < static_cast<unsigned>(_variableEnvironment->members.size())) { // Trying to delete a function argument might throw. if (_function->isStrict) { throwSyntaxError(ast->deleteToken, QStringLiteral("Delete of an unqualified identifier in strict mode.")); @@ -1430,7 +1442,7 @@ bool Codegen::visit(DeleteExpression *ast) } if (expr->asTemp() || (expr->asArgLocal() && - expr->asArgLocal()->index >= static_cast<unsigned>(_env->members.size()))) { + expr->asArgLocal()->index >= static_cast<unsigned>(_variableEnvironment->members.size()))) { _expr.code = _block->CONST(IR::BoolType, 1); return false; } @@ -1481,7 +1493,7 @@ IR::Expr *Codegen::identifier(const QString &name, int line, int col) return 0; uint scope = 0; - Environment *e = _env; + Environment *e = _variableEnvironment; IR::Function *f = _function; while (f && e->parent) { @@ -1512,7 +1524,7 @@ IR::Expr *Codegen::identifier(const QString &name, int line, int col) if (IR::Expr *fallback = fallbackNameLookup(name, line, col)) return fallback; - if (!e->parent && (!f || !f->insideWithOrCatch) && _env->compilationMode != EvalCode && e->compilationMode != QmlBinding) + if (!e->parent && (!f || !f->insideWithOrCatch) && _variableEnvironment->compilationMode != EvalCode && e->compilationMode != QmlBinding) return _block->GLOBALNAME(name, line, col); // global context or with. Lookup by name @@ -2007,7 +2019,7 @@ bool Codegen::visit(FunctionDeclaration * ast) if (hasError) return false; - if (_env->compilationMode == QmlBinding) + if (_variableEnvironment->compilationMode == QmlBinding) move(_block->TEMP(_returnAddress), _block->NAME(ast->name.toString(), 0, 0)); _expr.accept(nx); return false; @@ -2031,26 +2043,26 @@ int Codegen::defineFunction(const QString &name, AST::Node *ast, IR::BasicBlock *entryBlock = function->newBasicBlock(0); IR::BasicBlock *exitBlock = function->newBasicBlock(0, IR::Function::DontInsertBlock); - function->hasDirectEval = _env->hasDirectEval || _env->compilationMode == EvalCode + function->hasDirectEval = _variableEnvironment->hasDirectEval || _variableEnvironment->compilationMode == EvalCode || _module->debugMode; // Conditional breakpoints are like eval in the function - function->usesArgumentsObject = _env->parent && (_env->usesArgumentsObject == Environment::ArgumentsObjectUsed); - function->usesThis = _env->usesThis; - function->maxNumberOfArguments = qMax(_env->maxNumberOfArguments, (int)QV4::Global::ReservedArgumentCount); - function->isStrict = _env->isStrict; - function->isNamedExpression = _env->isNamedFunctionExpression; - function->isQmlBinding = _env->compilationMode == QmlBinding; + function->usesArgumentsObject = _variableEnvironment->parent && (_variableEnvironment->usesArgumentsObject == Environment::ArgumentsObjectUsed); + function->usesThis = _variableEnvironment->usesThis; + function->maxNumberOfArguments = qMax(_variableEnvironment->maxNumberOfArguments, (int)QV4::Global::ReservedArgumentCount); + function->isStrict = _variableEnvironment->isStrict; + function->isNamedExpression = _variableEnvironment->isNamedFunctionExpression; + function->isQmlBinding = _variableEnvironment->compilationMode == QmlBinding; AST::SourceLocation loc = ast->firstSourceLocation(); function->line = loc.startLine; function->column = loc.startColumn; if (function->usesArgumentsObject) - _env->enter(QStringLiteral("arguments"), Environment::VariableDeclaration); + _variableEnvironment->enter(QStringLiteral("arguments"), Environment::VariableDeclaration, AST::VariableDeclaration::FunctionScope); // variables in global code are properties of the global context object, not locals as with other functions. - if (_env->compilationMode == FunctionCode || _env->compilationMode == QmlBinding) { + if (_variableEnvironment->compilationMode == FunctionCode || _variableEnvironment->compilationMode == QmlBinding) { unsigned t = 0; - for (Environment::MemberMap::iterator it = _env->members.begin(), end = _env->members.end(); it != end; ++it) { + for (Environment::MemberMap::iterator it = _variableEnvironment->members.begin(), end = _variableEnvironment->members.end(); it != end; ++it) { const QString &local = it.key(); function->LOCAL(local); (*it).index = t; @@ -2058,18 +2070,19 @@ int Codegen::defineFunction(const QString &name, AST::Node *ast, ++t; } } else { - if (!_env->isStrict) { + if (!_variableEnvironment->isStrict) { for (const QString &inheritedLocal : qAsConst(inheritedLocals)) { function->LOCAL(inheritedLocal); unsigned tempIndex = entryBlock->newTemp(); Environment::Member member = { Environment::UndefinedMember, - static_cast<int>(tempIndex), 0 }; - _env->members.insert(inheritedLocal, member); + static_cast<int>(tempIndex), 0, + AST::VariableDeclaration::VariableScope::FunctionScope }; + _variableEnvironment->members.insert(inheritedLocal, member); } } IR::ExprList *args = 0; - for (Environment::MemberMap::const_iterator it = _env->members.constBegin(), cend = _env->members.constEnd(); it != cend; ++it) { + for (Environment::MemberMap::const_iterator it = _variableEnvironment->members.constBegin(), cend = _variableEnvironment->members.constEnd(); it != cend; ++it) { const QString &local = it.key(); IR::ExprList *next = function->New<IR::ExprList>(); next->expr = entryBlock->NAME(local, 0, 0); @@ -2101,11 +2114,11 @@ int Codegen::defineFunction(const QString &name, AST::Node *ast, _function->RECEIVE(it->name.toString()); } - for (const Environment::Member &member : qAsConst(_env->members)) { + for (const Environment::Member &member : qAsConst(_variableEnvironment->members)) { if (member.function) { const int function = defineFunction(member.function->name.toString(), member.function, member.function->formals, member.function->body ? member.function->body->elements : 0); - if (! _env->parent) { + if (! _variableEnvironment->parent) { move(_block->NAME(member.function->name.toString(), member.function->identifierToken.startLine, member.function->identifierToken.startColumn), _block->CLOSURE(function)); } else { @@ -2281,7 +2294,7 @@ bool Codegen::visit(ExpressionStatement *ast) if (hasError) return true; - if (_env->compilationMode == EvalCode || _env->compilationMode == QmlBinding) { + if (_variableEnvironment->compilationMode == EvalCode || _variableEnvironment->compilationMode == QmlBinding) { Result e = expression(ast->expression); if (*e) move(_block->TEMP(_returnAddress), *e); @@ -2517,7 +2530,7 @@ bool Codegen::visit(ReturnStatement *ast) if (hasError) return true; - if (_env->compilationMode != FunctionCode && _env->compilationMode != QmlBinding) { + if (_variableEnvironment->compilationMode != FunctionCode && _variableEnvironment->compilationMode != QmlBinding) { throwSyntaxError(ast->returnToken, QStringLiteral("Return statement outside of function")); return false; } @@ -2895,7 +2908,7 @@ bool Codegen::visit(UiSourceElement *) bool Codegen::throwSyntaxErrorOnEvalOrArgumentsInStrictMode(IR::Expr *expr, const SourceLocation& loc) { - if (!_env->isStrict) + if (!_variableEnvironment->isStrict) return false; if (IR::Name *n = expr->asName()) { if (*n->id != QLatin1String("eval") && *n->id != QLatin1String("arguments")) diff --git a/src/qml/compiler/qv4codegen_p.h b/src/qml/compiler/qv4codegen_p.h index 742ee79648..239ed5c4b9 100644 --- a/src/qml/compiler/qv4codegen_p.h +++ b/src/qml/compiler/qv4codegen_p.h @@ -141,10 +141,14 @@ protected: VariableDeclaration, FunctionDefinition }; + struct Member { MemberType type; int index; AST::FunctionExpression *function; + AST::VariableDeclaration::VariableScope scope; + + bool isLexicallyScoped() const { return this->scope != AST::VariableDeclaration::FunctionScope; } }; typedef QMap<QString, Member> MemberMap; @@ -191,6 +195,18 @@ protected: return (*it).index; } + bool memberInfo(const QString &name, const Member **m) const + { + Q_ASSERT(m); + MemberMap::const_iterator it = members.find(name); + if (it == members.end()) { + *m = 0; + return false; + } + *m = &(*it); + return true; + } + bool lookupMember(const QString &name, Environment **scope, int *index, int *distance) { Environment *it = this; @@ -206,7 +222,7 @@ protected: return false; } - void enter(const QString &name, MemberType type, AST::FunctionExpression *function = 0) + void enter(const QString &name, MemberType type, AST::VariableDeclaration::VariableScope scope, AST::FunctionExpression *function = 0) { if (! name.isEmpty()) { if (type != FunctionDefinition) { @@ -220,8 +236,10 @@ protected: m.index = -1; m.type = type; m.function = function; + m.scope = scope; members.insert(name, m); } else { + Q_ASSERT(scope == (*it).scope); if ((*it).type <= type) { (*it).type = type; (*it).function = function; @@ -448,7 +466,7 @@ protected: QV4::IR::BasicBlock *_block; QV4::IR::BasicBlock *_exitBlock; unsigned _returnAddress; - Environment *_env; + Environment *_variableEnvironment; Loop *_loop; AST::LabelledStatement *_labelledStatement; ScopeAndFinally *_scopeAndFinally; @@ -526,7 +544,7 @@ protected: // fields: Codegen *_cg; const QString _sourceCode; - Environment *_env; + Environment *_variableEnvironment; QStack<Environment *> _envStack; bool _allowFuncDecls; diff --git a/src/qml/compiler/qv4compileddata.cpp b/src/qml/compiler/qv4compileddata.cpp index 1805ab3f54..edb5edb0bc 100644 --- a/src/qml/compiler/qv4compileddata.cpp +++ b/src/qml/compiler/qv4compileddata.cpp @@ -125,8 +125,10 @@ QV4::Function *CompilationUnit::linkToEngine(ExecutionEngine *engine) runtimeStrings = (QV4::Heap::String **)malloc(data->stringTableSize * sizeof(QV4::Heap::String*)); // memset the strings to 0 in case a GC run happens while we're within the loop below memset(runtimeStrings, 0, data->stringTableSize * sizeof(QV4::Heap::String*)); - for (uint i = 0; i < data->stringTableSize; ++i) + for (uint i = 0; i < data->stringTableSize; ++i) { runtimeStrings[i] = engine->newIdentifier(data->stringAt(i)); + runtimeStrings[i]->setMarkBit(); + } runtimeRegularExpressions = new QV4::Value[data->regexpTableSize]; // memset the regexps to 0 in case a GC run happens while we're within the loop below @@ -140,7 +142,14 @@ QV4::Function *CompilationUnit::linkToEngine(ExecutionEngine *engine) flags |= IR::RegExp::RegExp_IgnoreCase; if (re->flags & CompiledData::RegExp::RegExp_Multiline) flags |= IR::RegExp::RegExp_Multiline; - runtimeRegularExpressions[i] = engine->newRegExpObject(data->stringAt(re->stringIndex), flags); + QV4::Heap::RegExpObject *ro = engine->newRegExpObject(data->stringAt(re->stringIndex), flags); + runtimeRegularExpressions[i] = ro; +#if WRITEBARRIER(steele) + if (engine->memoryManager->nextGCIsIncremental) { + ro->setMarkBit(); + ro->setGrayBit(); + } +#endif } if (data->lookupTableSize) { @@ -167,8 +176,6 @@ QV4::Function *CompilationUnit::linkToEngine(ExecutionEngine *engine) l->level = -1; l->index = UINT_MAX; l->nameIndex = compiledLookups[i].nameIndex; - if (type == CompiledData::Lookup::Type_IndexedGetter || type == CompiledData::Lookup::Type_IndexedSetter) - l->engine = engine; } } diff --git a/src/qml/compiler/qv4compileddata_p.h b/src/qml/compiler/qv4compileddata_p.h index 8cf5437928..9c21d5e9ae 100644 --- a/src/qml/compiler/qv4compileddata_p.h +++ b/src/qml/compiler/qv4compileddata_p.h @@ -211,7 +211,8 @@ struct Function HasDirectEval = 0x2, UsesArgumentsObject = 0x4, IsNamedExpression = 0x8, - HasCatchOrWith = 0x10 + HasCatchOrWith = 0x10, + CanUseSimpleCall = 0x20 }; // Absolute offset into file where the code for this function is located. Only used when the function diff --git a/src/qml/compiler/qv4compiler.cpp b/src/qml/compiler/qv4compiler.cpp index 64f034ddcb..b81d724fe7 100644 --- a/src/qml/compiler/qv4compiler.cpp +++ b/src/qml/compiler/qv4compiler.cpp @@ -296,6 +296,8 @@ void QV4::Compiler::JSUnitGenerator::writeFunction(char *f, QV4::IR::Function *i function->flags |= CompiledData::Function::IsNamedExpression; if (irFunction->hasTry || irFunction->hasWith) function->flags |= CompiledData::Function::HasCatchOrWith; + if (irFunction->canUseSimpleCall()) + function->flags |= CompiledData::Function::CanUseSimpleCall; function->nFormals = irFunction->formals.size(); function->formalsOffset = currentOffset; currentOffset += function->nFormals * sizeof(quint32); diff --git a/src/qml/compiler/qv4jsir_p.h b/src/qml/compiler/qv4jsir_p.h index d9192c1a3b..f7c7b76ea8 100644 --- a/src/qml/compiler/qv4jsir_p.h +++ b/src/qml/compiler/qv4jsir_p.h @@ -1352,6 +1352,31 @@ struct Function { int getNewStatementId() { return _statementCount++; } int statementCount() const { return _statementCount; } + bool canUseSimpleCall() const { + return nestedFunctions.isEmpty() && + locals.isEmpty() && formals.size() <= QV4::Global::ReservedArgumentCount && + !hasTry && !hasWith && !isNamedExpression && !usesArgumentsObject && !hasDirectEval; + } + + bool argLocalRequiresWriteBarrier(ArgLocal *al) const { + uint scope = al->scope; + const IR::Function *f = this; + while (scope) { + f = f->outer; + --scope; + } + return !f->canUseSimpleCall(); + } + int localsCountForScope(ArgLocal *al) const { + uint scope = al->scope; + const IR::Function *f = this; + while (scope) { + f = f->outer; + --scope; + } + return f->locals.size(); + } + private: BasicBlock *getOrCreateBasicBlock(int index); void setStatementCount(int cnt); @@ -1420,6 +1445,7 @@ public: ArgLocal *newArgLocal = f->New<ArgLocal>(); newArgLocal->init(argLocal->kind, argLocal->index, argLocal->scope); newArgLocal->type = argLocal->type; + newArgLocal->isArgumentsOrEval = argLocal->isArgumentsOrEval; return newArgLocal; } diff --git a/src/qml/doc/src/javascript/functionlist.qdoc b/src/qml/doc/src/javascript/functionlist.qdoc index f5b1ed3cf1..fd916e1e24 100644 --- a/src/qml/doc/src/javascript/functionlist.qdoc +++ b/src/qml/doc/src/javascript/functionlist.qdoc @@ -182,6 +182,7 @@ \li lastIndexOf(searchString, position) \li localeCompare(that) \li match(regexp) + \li repeat(count) // ECMAScript 6: Added in Qt 5.9 \li replace(searchValue, replaceValue) \li search(regexp) \li slice(start, end) diff --git a/src/qml/doc/src/javascript/hostenvironment.qdoc b/src/qml/doc/src/javascript/hostenvironment.qdoc index 1e33f2f641..7e9a22f5d3 100644 --- a/src/qml/doc/src/javascript/hostenvironment.qdoc +++ b/src/qml/doc/src/javascript/hostenvironment.qdoc @@ -74,6 +74,19 @@ Note that QML makes the following modifications to native objects: \li Locale-aware conversion functions are added to the \l Date and \l Number prototypes. \endlist +In addition, QML also extends the behavior of the instanceof function to +allow for type checking against QML types. This means that you may use it to +verify that a variable is indeed the type you expect, for example: + +\qml + var v = something(); + if (!v instanceof Item) { + throw new TypeError("I need an Item type!"); + } + + ... +\endqml + \section1 JavaScript Environment Restrictions diff --git a/src/qml/jit/qv4assembler.cpp b/src/qml/jit/qv4assembler.cpp index 5c90aba464..81d34701a9 100644 --- a/src/qml/jit/qv4assembler.cpp +++ b/src/qml/jit/qv4assembler.cpp @@ -246,13 +246,16 @@ void Assembler<TargetConfiguration>::generateCJumpOnCompare(RelationalCondition } template <typename TargetConfiguration> -typename Assembler<TargetConfiguration>::Pointer Assembler<TargetConfiguration>::loadAddress(RegisterID tmp, IR::Expr *e) +typename Assembler<TargetConfiguration>::Pointer +Assembler<TargetConfiguration>::loadAddressForWriting(RegisterID tmp, IR::Expr *e, WriteBarrier::Type *barrier) { + if (barrier) + *barrier = WriteBarrier::NoBarrier; IR::Temp *t = e->asTemp(); if (t) return loadTempAddress(t); else - return loadArgLocalAddress(tmp, e->asArgLocal()); + return loadArgLocalAddressForWriting(tmp, e->asArgLocal(), barrier); } template <typename TargetConfiguration> @@ -265,34 +268,42 @@ typename Assembler<TargetConfiguration>::Pointer Assembler<TargetConfiguration>: } template <typename TargetConfiguration> -typename Assembler<TargetConfiguration>::Pointer Assembler<TargetConfiguration>::loadArgLocalAddress(RegisterID baseReg, IR::ArgLocal *al) +typename Assembler<TargetConfiguration>::Pointer +Assembler<TargetConfiguration>::loadArgLocalAddressForWriting(RegisterID baseReg, IR::ArgLocal *al, WriteBarrier::Type *barrier) { + if (barrier) + *barrier = _function->argLocalRequiresWriteBarrier(al) ? WriteBarrier::Barrier : WriteBarrier::NoBarrier; + int32_t offset = 0; int scope = al->scope; loadPtr(Address(EngineRegister, targetStructureOffset(offsetof(EngineBase, current))), baseReg); - const qint32 outerOffset = targetStructureOffset(Heap::ExecutionContext::baseOffset + offsetof(Heap::ExecutionContextData, outer)); + const qint32 outerOffset = targetStructureOffset(Heap::ExecutionContextData::baseOffset + offsetof(Heap::ExecutionContextData, outer)); + const qint32 localsOffset = targetStructureOffset(Heap::CallContextData::baseOffset + offsetof(Heap::CallContextData, function)) + + 8 // locals is always 8 bytes away from function, regardless of pointer size. + + offsetof(ValueArray<0>, values); - if (scope) { + while (scope) { loadPtr(Address(baseReg, outerOffset), baseReg); --scope; - while (scope) { - loadPtr(Address(baseReg, outerOffset), baseReg); - --scope; - } } switch (al->kind) { case IR::ArgLocal::Formal: case IR::ArgLocal::ScopedFormal: { - const qint32 callDataOffset = targetStructureOffset(Heap::ExecutionContext::baseOffset + offsetof(Heap::ExecutionContextData, callData)); - loadPtr(Address(baseReg, callDataOffset), baseReg); - offset = sizeof(CallData) + (al->index - 1) * sizeof(Value); + if (barrier && *barrier == WriteBarrier::Barrier) { + // if we need a barrier, the baseReg has to point to the ExecutionContext + // callData comes directly after locals, calculate the offset using that + offset = localsOffset + _function->localsCountForScope(al) * sizeof(Value); + offset += sizeof(CallData) + (al->index - 1) * sizeof(Value); + } else { + const qint32 callDataOffset = targetStructureOffset(Heap::ExecutionContextData::baseOffset + offsetof(Heap::ExecutionContextData, callData)); + loadPtr(Address(baseReg, callDataOffset), baseReg); + offset = sizeof(CallData) + (al->index - 1) * sizeof(Value); + } } break; case IR::ArgLocal::Local: case IR::ArgLocal::ScopedLocal: { - const qint32 localsOffset = targetStructureOffset(Heap::CallContext::baseOffset + offsetof(Heap::CallContextData, locals)); - loadPtr(Address(baseReg, localsOffset), baseReg); - offset = al->index * sizeof(Value); + offset = localsOffset + al->index * sizeof(Value); } break; default: Q_UNREACHABLE(); @@ -304,7 +315,7 @@ template <typename TargetConfiguration> typename Assembler<TargetConfiguration>::Pointer Assembler<TargetConfiguration>::loadStringAddress(RegisterID reg, const QString &string) { loadPtr(Address(Assembler::EngineRegister, targetStructureOffset(offsetof(QV4::EngineBase, current))), Assembler::ScratchRegister); - loadPtr(Address(Assembler::ScratchRegister, targetStructureOffset(Heap::ExecutionContext::baseOffset + offsetof(Heap::ExecutionContextData, compilationUnit))), Assembler::ScratchRegister); + loadPtr(Address(Assembler::ScratchRegister, targetStructureOffset(Heap::ExecutionContextData::baseOffset + offsetof(Heap::ExecutionContextData, compilationUnit))), Assembler::ScratchRegister); loadPtr(Address(Assembler::ScratchRegister, offsetof(CompiledData::CompilationUnitBase, runtimeStrings)), reg); const int id = _jsGenerator->registerString(string); return Pointer(reg, id * sizeof(QV4::String*)); @@ -320,7 +331,7 @@ template <typename TargetConfiguration> typename Assembler<TargetConfiguration>::Address Assembler<TargetConfiguration>::loadConstant(const Primitive &v, RegisterID baseReg) { loadPtr(Address(Assembler::EngineRegister, targetStructureOffset(offsetof(QV4::EngineBase, current))), baseReg); - loadPtr(Address(baseReg, targetStructureOffset(Heap::ExecutionContext::baseOffset + offsetof(Heap::ExecutionContextData, constantTable))), baseReg); + loadPtr(Address(baseReg, targetStructureOffset(Heap::ExecutionContextData::baseOffset + offsetof(Heap::ExecutionContextData, constantTable))), baseReg); const int index = _jsGenerator->registerConstant(v.asReturnedValue()); return Address(baseReg, index * sizeof(QV4::Value)); } @@ -335,8 +346,9 @@ void Assembler<TargetConfiguration>::loadStringRef(RegisterID reg, const QString template <typename TargetConfiguration> void Assembler<TargetConfiguration>::storeValue(QV4::Primitive value, IR::Expr *destination) { - Address addr = loadAddress(ScratchRegister, destination); - storeValue(value, addr); + WriteBarrier::Type barrier; + Address addr = loadAddressForWriting(ScratchRegister, destination, &barrier); + storeValue(value, addr, barrier); } template <typename TargetConfiguration> @@ -425,7 +437,7 @@ typename Assembler<TargetConfiguration>::Jump Assembler<TargetConfiguration>::ge // It's not a number type, so it cannot be in a register. Q_ASSERT(src->asArgLocal() || src->asTemp()->kind != IR::Temp::PhysicalRegister || src->type == IR::BoolType); - Assembler::Pointer tagAddr = loadAddress(Assembler::ScratchRegister, src); + Assembler::Pointer tagAddr = loadAddressForReading(Assembler::ScratchRegister, src); tagAddr.offset += 4; load32(tagAddr, Assembler::ScratchRegister); @@ -524,7 +536,7 @@ void Assembler<TargetConfiguration>::returnFromFunction(IR::Ret *s, RegisterInfo const int locals = stackLayout().calculateJSStackFrameSize(); subPtr(TrustedImm32(sizeof(QV4::Value)*locals), JITTargetPlatform::LocalsRegister); loadPtr(Address(JITTargetPlatform::EngineRegister, targetStructureOffset(offsetof(QV4::EngineBase, current))), JITTargetPlatform::ScratchRegister); - loadPtr(Address(JITTargetPlatform::ScratchRegister, targetStructureOffset(Heap::ExecutionContext::baseOffset + offsetof(Heap::ExecutionContextData, engine))), JITTargetPlatform::ScratchRegister); + loadPtr(Address(JITTargetPlatform::ScratchRegister, targetStructureOffset(Heap::ExecutionContextData::baseOffset + offsetof(Heap::ExecutionContextData, engine))), JITTargetPlatform::ScratchRegister); storePtr(JITTargetPlatform::LocalsRegister, Address(JITTargetPlatform::ScratchRegister, targetStructureOffset(offsetof(EngineBase, jsStackTop)))); leaveStandardStackFrame(regularRegistersToSave, fpRegistersToSave); @@ -553,7 +565,7 @@ public: ~QIODevicePrintStream() {} - void vprintf(const char* format, va_list argList) WTF_ATTRIBUTE_PRINTF(2, 0) + void vprintf(const char* format, va_list argList) override WTF_ATTRIBUTE_PRINTF(2, 0) { const int written = qvsnprintf(buf.data(), buf.size(), format, argList); if (written > 0) @@ -561,7 +573,7 @@ public: memset(buf.data(), 0, qMin(written, buf.size())); } - void flush() + void flush() override {} private: diff --git a/src/qml/jit/qv4assembler_p.h b/src/qml/jit/qv4assembler_p.h index e507a14f12..addbfc12a3 100644 --- a/src/qml/jit/qv4assembler_p.h +++ b/src/qml/jit/qv4assembler_p.h @@ -57,6 +57,7 @@ #include "private/qv4value_p.h" #include "private/qv4context_p.h" #include "private/qv4engine_p.h" +#include "private/qv4writebarrier_p.h" #include "qv4targetplatform_p.h" #include <config.h> @@ -153,34 +154,94 @@ struct RegisterSizeDependentAssembler<JITAssembler, MacroAssembler, TargetPlatfo using Jump = typename JITAssembler::Jump; using Label = typename JITAssembler::Label; + static void emitSetGrayBit(JITAssembler *as, RegisterID base) + { + bool returnValueUsed = (base == TargetPlatform::ReturnValueRegister); + + as->push(TargetPlatform::EngineRegister); // free up one register for work + + RegisterID grayBitmap = returnValueUsed ? TargetPlatform::ScratchRegister : TargetPlatform::ReturnValueRegister; + as->move(base, grayBitmap); + Q_ASSERT(base != grayBitmap); + as->urshift32(TrustedImm32(Chunk::ChunkShift), grayBitmap); + as->lshift32(TrustedImm32(Chunk::ChunkShift), grayBitmap); + Q_STATIC_ASSERT(offsetof(Chunk, grayBitmap) == 0); + + RegisterID index = base; + as->move(base, index); + as->sub32(grayBitmap, index); + as->urshift32(TrustedImm32(Chunk::SlotSizeShift), index); + RegisterID grayIndex = TargetPlatform::EngineRegister; + as->move(index, grayIndex); + as->urshift32(TrustedImm32(Chunk::BitShift), grayIndex); + as->lshift32(TrustedImm32(2), grayIndex); // 4 bytes per quintptr + as->add32(grayIndex, grayBitmap); + as->and32(TrustedImm32(Chunk::Bits - 1), index); + + RegisterID bit = TargetPlatform::EngineRegister; + as->move(TrustedImm32(1), bit); + as->lshift32(index, bit); + + as->load32(Pointer(grayBitmap, 0), index); + as->or32(bit, index); + as->store32(index, Pointer(grayBitmap, 0)); + + as->pop(TargetPlatform::EngineRegister); + } + +#if WRITEBARRIER(steele) + static void emitWriteBarrier(JITAssembler *as, Address addr) + { +// RegisterID test = addr.base == TargetPlatform::ReturnValueRegister ? TargetPlatform::ScratchRegister : TargetPlatform::ReturnValueRegister; + // if (engine->writeBarrier) +// as->load8(Address(TargetPlatform::EngineRegister, offsetof(EngineBase, writeBarrierActive)), test); +// typename JITAssembler::Jump jump = as->branch32(JITAssembler::Equal, test, TrustedImm32(0)); + // ### emit fence + emitSetGrayBit(as, addr.base); +// jump.link(as); + } +#elif WRITEBARRIER(none) + static Q_ALWAYS_INLINE void emitWriteBarrier(JITAssembler *, Address) {} +#endif + static void loadDouble(JITAssembler *as, Address addr, FPRegisterID dest) { as->MacroAssembler::loadDouble(addr, dest); } - static void storeDouble(JITAssembler *as, FPRegisterID source, Address addr) + static void storeDouble(JITAssembler *as, FPRegisterID source, Address addr, WriteBarrier::Type barrier) { as->MacroAssembler::storeDouble(source, addr); + if (WriteBarrier::isRequired<WriteBarrier::Primitive>() && barrier == WriteBarrier::Barrier) + emitWriteBarrier(as, addr); } static void storeDouble(JITAssembler *as, FPRegisterID source, IR::Expr* target) { - Pointer ptr = as->loadAddress(TargetPlatform::ScratchRegister, target); - as->storeDouble(source, ptr); + WriteBarrier::Type barrier; + Pointer ptr = as->loadAddressForWriting(TargetPlatform::ScratchRegister, target, &barrier); + as->storeDouble(source, ptr, barrier); } - static void storeValue(JITAssembler *as, QV4::Primitive value, Address destination) + static void storeValue(JITAssembler *as, QV4::Primitive value, Address destination, WriteBarrier::Type barrier) { as->store32(TrustedImm32(value.int_32()), destination); destination.offset += 4; as->store32(TrustedImm32(value.tag()), destination); + if (WriteBarrier::isRequired<WriteBarrier::Primitive>() && barrier == WriteBarrier::Barrier) + emitWriteBarrier(as, destination); } template <typename Source, typename Destination> - static void copyValueViaRegisters(JITAssembler *as, Source source, Destination destination) + static void copyValueViaRegisters(JITAssembler *as, Source source, Destination destination, WriteBarrier::Type barrier) { as->loadDouble(source, TargetPlatform::FPGpr0); - as->storeDouble(TargetPlatform::FPGpr0, destination); + // We need to pass NoBarrier to storeDouble and call emitWriteBarrier ourselves, as the + // code in storeDouble assumes the type we're storing is actually a double, something + // that isn't always the case here. + as->storeDouble(TargetPlatform::FPGpr0, destination, WriteBarrier::NoBarrier); + if (WriteBarrier::isRequired<WriteBarrier::Unknown>() && barrier == WriteBarrier::Barrier) + emitWriteBarrier(as, destination); } static void loadDoubleConstant(JITAssembler *as, IR::Const *c, FPRegisterID target) @@ -193,12 +254,14 @@ struct RegisterSizeDependentAssembler<JITAssembler, MacroAssembler, TargetPlatfo as->moveIntsToDouble(TargetPlatform::LowReturnValueRegister, TargetPlatform::HighReturnValueRegister, dest, TargetPlatform::FPGpr0); } - static void storeReturnValue(JITAssembler *as, const Pointer &dest) + static void storeReturnValue(JITAssembler *as, const Pointer &dest, WriteBarrier::Type barrier) { Address destination = dest; as->store32(TargetPlatform::LowReturnValueRegister, destination); destination.offset += 4; as->store32(TargetPlatform::HighReturnValueRegister, destination); + if (WriteBarrier::isRequired<WriteBarrier::Unknown>() && barrier == WriteBarrier::Barrier) + emitWriteBarrier(as, dest); } static void setFunctionReturnValueFromTemp(JITAssembler *as, IR::Temp *t) @@ -234,7 +297,7 @@ struct RegisterSizeDependentAssembler<JITAssembler, MacroAssembler, TargetPlatfo Q_UNREACHABLE(); } } else { - Pointer addr = as->loadAddress(TargetPlatform::ScratchRegister, t); + Pointer addr = as->loadAddressForReading(TargetPlatform::ScratchRegister, t); as->load32(addr, lowReg); addr.offset += 4; as->load32(addr, highReg); @@ -295,7 +358,7 @@ struct RegisterSizeDependentAssembler<JITAssembler, MacroAssembler, TargetPlatfo IR::BasicBlock *nextBlock, IR::BasicBlock *currentBlock, IR::BasicBlock *trueBlock, IR::BasicBlock *falseBlock) { - Pointer tagAddr = as->loadAddress(scratchRegister, right); + Pointer tagAddr = as->loadAddressForReading(scratchRegister, right); as->load32(tagAddr, tagRegister); Jump j = as->branch32(JITAssembler::invert(cond), tagRegister, TrustedImm32(0)); as->addPatch(falseBlock, j); @@ -312,7 +375,7 @@ struct RegisterSizeDependentAssembler<JITAssembler, MacroAssembler, TargetPlatfo { Q_ASSERT(source->type == IR::VarType); // load the tag: - Pointer addr = as->loadAddress(TargetPlatform::ScratchRegister, source); + Pointer addr = as->loadAddressForReading(TargetPlatform::ScratchRegister, source); Pointer tagAddr = addr; tagAddr.offset += 4; as->load32(tagAddr, TargetPlatform::ReturnValueRegister); @@ -323,10 +386,13 @@ struct RegisterSizeDependentAssembler<JITAssembler, MacroAssembler, TargetPlatfo IR::Temp *targetTemp = target->asTemp(); if (!targetTemp || targetTemp->kind == IR::Temp::StackSlot) { as->load32(addr, TargetPlatform::ReturnValueRegister); - Pointer targetAddr = as->loadAddress(TargetPlatform::ScratchRegister, target); + WriteBarrier::Type barrier; + Pointer targetAddr = as->loadAddressForWriting(TargetPlatform::ScratchRegister, target, &barrier); as->store32(TargetPlatform::ReturnValueRegister, targetAddr); targetAddr.offset += 4; as->store32(TrustedImm32(Value::Integer_Type_Internal), targetAddr); + if (WriteBarrier::isRequired<WriteBarrier::Primitive>() && barrier == WriteBarrier::Barrier) + emitWriteBarrier(as, targetAddr); } else { as->load32(addr, (RegisterID) targetTemp->index); } @@ -335,17 +401,19 @@ struct RegisterSizeDependentAssembler<JITAssembler, MacroAssembler, TargetPlatfo // not an int: fallback.link(as); generateRuntimeCall(as, TargetPlatform::ReturnValueRegister, toInt, - as->loadAddress(TargetPlatform::ScratchRegister, source)); + as->loadAddressForReading(TargetPlatform::ScratchRegister, source)); as->storeInt32(TargetPlatform::ReturnValueRegister, target); intDone.link(as); } - static void loadManagedPointer(JITAssembler *as, RegisterID registerWithPtr, Pointer destAddr) + static void loadManagedPointer(JITAssembler *as, RegisterID registerWithPtr, Pointer destAddr, WriteBarrier::Type barrier) { as->store32(registerWithPtr, destAddr); destAddr.offset += 4; as->store32(TrustedImm32(QV4::Value::Managed_Type_Internal_32), destAddr); + if (WriteBarrier::isRequired<WriteBarrier::Object>() && barrier == WriteBarrier::Barrier) + emitWriteBarrier(as, destAddr); } static Jump generateIsDoubleCheck(JITAssembler *as, RegisterID tagOrValueRegister) @@ -384,6 +452,56 @@ struct RegisterSizeDependentAssembler<JITAssembler, MacroAssembler, TargetPlatfo using Jump = typename JITAssembler::Jump; using Label = typename JITAssembler::Label; + static void emitSetGrayBit(JITAssembler *as, RegisterID base) + { + bool returnValueUsed = (base == TargetPlatform::ReturnValueRegister); + + as->push(TargetPlatform::EngineRegister); // free up one register for work + + RegisterID grayBitmap = returnValueUsed ? TargetPlatform::ScratchRegister : TargetPlatform::ReturnValueRegister; + as->move(base, grayBitmap); + Q_ASSERT(base != grayBitmap); + as->urshift64(TrustedImm32(Chunk::ChunkShift), grayBitmap); + as->lshift64(TrustedImm32(Chunk::ChunkShift), grayBitmap); + Q_STATIC_ASSERT(offsetof(Chunk, grayBitmap) == 0); + + RegisterID index = base; + as->move(base, index); + as->sub64(grayBitmap, index); + as->urshift64(TrustedImm32(Chunk::SlotSizeShift), index); + RegisterID grayIndex = TargetPlatform::EngineRegister; + as->move(index, grayIndex); + as->urshift64(TrustedImm32(Chunk::BitShift), grayIndex); + as->lshift64(TrustedImm32(3), grayIndex); // 8 bytes per quintptr + as->add64(grayIndex, grayBitmap); + as->and64(TrustedImm32(Chunk::Bits - 1), index); + + RegisterID bit = TargetPlatform::EngineRegister; + as->move(TrustedImm32(1), bit); + as->lshift64(index, bit); + + as->load64(Pointer(grayBitmap, 0), index); + as->or64(bit, index); + as->store64(index, Pointer(grayBitmap, 0)); + + as->pop(TargetPlatform::EngineRegister); + } + +#if WRITEBARRIER(steele) + static void emitWriteBarrier(JITAssembler *as, Address addr) + { +// RegisterID test = addr.base == TargetPlatform::ReturnValueRegister ? TargetPlatform::ScratchRegister : TargetPlatform::ReturnValueRegister; + // if (engine->writeBarrier) +// as->load8(Address(TargetPlatform::EngineRegister, offsetof(EngineBase, writeBarrierActive)), test); +// typename JITAssembler::Jump jump = as->branch32(JITAssembler::Equal, test, TrustedImm32(0)); + // ### emit fence + emitSetGrayBit(as, addr.base); +// jump.link(as); + } +#elif WRITEBARRIER(none) + static Q_ALWAYS_INLINE void emitWriteBarrier(JITAssembler *, Address) {} +#endif + static void loadDouble(JITAssembler *as, Address addr, FPRegisterID dest) { as->load64(addr, TargetPlatform::ReturnValueRegister); @@ -391,19 +509,24 @@ struct RegisterSizeDependentAssembler<JITAssembler, MacroAssembler, TargetPlatfo as->move64ToDouble(TargetPlatform::ReturnValueRegister, dest); } - static void storeDouble(JITAssembler *as, FPRegisterID source, Address addr) + static void storeDouble(JITAssembler *as, FPRegisterID source, Address addr, WriteBarrier::Type barrier) { as->moveDoubleTo64(source, TargetPlatform::ReturnValueRegister); as->xor64(TargetPlatform::DoubleMaskRegister, TargetPlatform::ReturnValueRegister); as->store64(TargetPlatform::ReturnValueRegister, addr); + if (WriteBarrier::isRequired<WriteBarrier::Primitive>() && barrier == WriteBarrier::Barrier) + emitWriteBarrier(as, addr); } static void storeDouble(JITAssembler *as, FPRegisterID source, IR::Expr* target) { as->moveDoubleTo64(source, TargetPlatform::ReturnValueRegister); as->xor64(TargetPlatform::DoubleMaskRegister, TargetPlatform::ReturnValueRegister); - Pointer ptr = as->loadAddress(TargetPlatform::ScratchRegister, target); + WriteBarrier::Type barrier; + Pointer ptr = as->loadAddressForWriting(TargetPlatform::ScratchRegister, target, &barrier); as->store64(TargetPlatform::ReturnValueRegister, ptr); + if (WriteBarrier::isRequired<WriteBarrier::Primitive>() && barrier == WriteBarrier::Barrier) + emitWriteBarrier(as, ptr); } static void storeReturnValue(JITAssembler *as, FPRegisterID dest) @@ -412,9 +535,11 @@ struct RegisterSizeDependentAssembler<JITAssembler, MacroAssembler, TargetPlatfo as->move64ToDouble(TargetPlatform::ReturnValueRegister, dest); } - static void storeReturnValue(JITAssembler *as, const Pointer &dest) + static void storeReturnValue(JITAssembler *as, const Pointer &dest, WriteBarrier::Type barrier) { as->store64(TargetPlatform::ReturnValueRegister, dest); + if (WriteBarrier::isRequired<WriteBarrier::Unknown>() && barrier == WriteBarrier::Barrier) + emitWriteBarrier(as, dest); } static void setFunctionReturnValueFromTemp(JITAssembler *as, IR::Temp *t) @@ -455,7 +580,7 @@ struct RegisterSizeDependentAssembler<JITAssembler, MacroAssembler, TargetPlatfo TargetPlatform::ReturnValueRegister); } } else { - as->copyValue(TargetPlatform::ReturnValueRegister, t); + as->copyValue(TargetPlatform::ReturnValueRegister, t, WriteBarrier::NoBarrier); } } @@ -464,18 +589,20 @@ struct RegisterSizeDependentAssembler<JITAssembler, MacroAssembler, TargetPlatfo as->move(TrustedImm64(retVal.rawValue()), TargetPlatform::ReturnValueRegister); } - static void storeValue(JITAssembler *as, QV4::Primitive value, Address destination) + static void storeValue(JITAssembler *as, QV4::Primitive value, Address destination, WriteBarrier::Type barrier) { as->store64(TrustedImm64(value.rawValue()), destination); + if (WriteBarrier::isRequired<WriteBarrier::Unknown>() && barrier == WriteBarrier::Barrier) + emitWriteBarrier(as, destination); } template <typename Source, typename Destination> - static void copyValueViaRegisters(JITAssembler *as, Source source, Destination destination) + static void copyValueViaRegisters(JITAssembler *as, Source source, Destination destination, WriteBarrier::Type barrier) { // Use ReturnValueRegister as "scratch" register because loadArgument // and storeArgument are functions that may need a scratch register themselves. loadArgumentInRegister(as, source, TargetPlatform::ReturnValueRegister, 0); - as->storeReturnValue(destination); + as->storeReturnValue(destination, barrier); } static void loadDoubleConstant(JITAssembler *as, IR::Const *c, FPRegisterID target) @@ -511,7 +638,7 @@ struct RegisterSizeDependentAssembler<JITAssembler, MacroAssembler, TargetPlatfo Q_UNUSED(argumentNumber); if (al) { - Pointer addr = as->loadArgLocalAddress(dest, al); + Pointer addr = as->loadArgLocalAddressForReading(dest, al); as->load64(addr, dest); } else { QV4::Value undefined = QV4::Primitive::undefinedValue(); @@ -580,7 +707,7 @@ struct RegisterSizeDependentAssembler<JITAssembler, MacroAssembler, TargetPlatfo IR::BasicBlock *nextBlock, IR::BasicBlock *currentBlock, IR::BasicBlock *trueBlock, IR::BasicBlock *falseBlock) { - Pointer addr = as->loadAddress(scratchRegister, right); + Pointer addr = as->loadAddressForReading(scratchRegister, right); as->load64(addr, tagRegister); const TrustedImm64 tag(0); generateCJumpOnCompare(as, cond, tagRegister, tag, nextBlock, currentBlock, trueBlock, falseBlock); @@ -589,7 +716,7 @@ struct RegisterSizeDependentAssembler<JITAssembler, MacroAssembler, TargetPlatfo static void convertVarToSInt32(JITAssembler *as, IR::Expr *source, IR::Expr *target) { Q_ASSERT(source->type == IR::VarType); - Pointer addr = as->loadAddress(TargetPlatform::ScratchRegister, source); + Pointer addr = as->loadAddressForReading(TargetPlatform::ScratchRegister, source); as->load64(addr, TargetPlatform::ScratchRegister); as->move(TargetPlatform::ScratchRegister, TargetPlatform::ReturnValueRegister); @@ -613,25 +740,30 @@ struct RegisterSizeDependentAssembler<JITAssembler, MacroAssembler, TargetPlatfo // not an int: fallback.link(as); generateRuntimeCall(as, TargetPlatform::ReturnValueRegister, toInt, - as->loadAddress(TargetPlatform::ScratchRegister, source)); + as->loadAddressForReading(TargetPlatform::ScratchRegister, source)); isIntConvertible.link(as); success.link(as); IR::Temp *targetTemp = target->asTemp(); if (!targetTemp || targetTemp->kind == IR::Temp::StackSlot) { - Pointer targetAddr = as->loadAddress(TargetPlatform::ScratchRegister, target); + WriteBarrier::Type barrier; + Pointer targetAddr = as->loadAddressForWriting(TargetPlatform::ScratchRegister, target, &barrier); as->store32(TargetPlatform::ReturnValueRegister, targetAddr); targetAddr.offset += 4; as->store32(TrustedImm32(Value::Integer_Type_Internal), targetAddr); + if (WriteBarrier::isRequired<WriteBarrier::Primitive>() && barrier == WriteBarrier::Barrier) + emitWriteBarrier(as, targetAddr); } else { as->storeInt32(TargetPlatform::ReturnValueRegister, target); } } - static void loadManagedPointer(JITAssembler *as, RegisterID registerWithPtr, Pointer destAddr) + static void loadManagedPointer(JITAssembler *as, RegisterID registerWithPtr, Pointer destAddr, WriteBarrier::Type barrier) { as->store64(registerWithPtr, destAddr); + if (WriteBarrier::isRequired<WriteBarrier::Object>() && barrier == WriteBarrier::Barrier) + emitWriteBarrier(as, destAddr); } static Jump generateIsDoubleCheck(JITAssembler *as, RegisterID tagOrValueRegister) @@ -968,9 +1100,16 @@ public: Jump branchDouble(bool invertCondition, IR::AluOp op, IR::Expr *left, IR::Expr *right); Jump branchInt32(bool invertCondition, IR::AluOp op, IR::Expr *left, IR::Expr *right); - Pointer loadAddress(RegisterID tmp, IR::Expr *t); + Pointer loadAddressForWriting(RegisterID tmp, IR::Expr *t, WriteBarrier::Type *barrier); + Pointer loadAddressForReading(RegisterID tmp, IR::Expr *t) { + return loadAddressForWriting(tmp, t, 0); + } + Pointer loadTempAddress(IR::Temp *t); - Pointer loadArgLocalAddress(RegisterID baseReg, IR::ArgLocal *al); + Pointer loadArgLocalAddressForWriting(RegisterID baseReg, IR::ArgLocal *al, WriteBarrier::Type *barrier); + Pointer loadArgLocalAddressForReading(RegisterID baseReg, IR::ArgLocal *al) { + return loadArgLocalAddressForWriting(baseReg, al, 0); + } Pointer loadStringAddress(RegisterID reg, const QString &string); Address loadConstant(IR::Const *c, RegisterID baseReg); Address loadConstant(const Primitive &v, RegisterID baseReg); @@ -992,16 +1131,16 @@ public: Pointer addr(_stackLayout->savedRegPointer(argumentNumber)); switch (t->type) { case IR::BoolType: - storeBool((RegisterID) t->index, addr); + storeBool((RegisterID) t->index, addr, WriteBarrier::NoBarrier); break; case IR::SInt32Type: - storeInt32((RegisterID) t->index, addr); + storeInt32((RegisterID) t->index, addr, WriteBarrier::NoBarrier); break; case IR::UInt32Type: - storeUInt32((RegisterID) t->index, addr); + storeUInt32((RegisterID) t->index, addr, WriteBarrier::NoBarrier); break; case IR::DoubleType: - storeDouble((FPRegisterID) t->index, addr); + storeDouble((FPRegisterID) t->index, addr, WriteBarrier::NoBarrier); break; default: Q_UNIMPLEMENTED(); @@ -1032,7 +1171,7 @@ public: if (!temp.value) { RegisterSizeDependentOps::zeroRegister(this, dest); } else { - Pointer addr = toAddress(dest, temp.value, argumentNumber); + Pointer addr = toAddress(dest, temp.value, argumentNumber, 0); loadArgumentInRegister(addr, dest, argumentNumber); } } @@ -1045,7 +1184,7 @@ public: void loadArgumentInRegister(Reference temp, RegisterID dest, int argumentNumber) { Q_ASSERT(temp.value); - Pointer addr = loadAddress(dest, temp.value); + Pointer addr = loadAddressForReading(dest, temp.value); loadArgumentInRegister(addr, dest, argumentNumber); } @@ -1078,8 +1217,10 @@ public: move(imm32, dest); } - void storeReturnValue(RegisterID dest) + void storeReturnValue(RegisterID dest, WriteBarrier::Type barrier = WriteBarrier::NoBarrier) { + Q_UNUSED(barrier); + Q_ASSERT(barrier == WriteBarrier::NoBarrier); move(ReturnValueRegister, dest); } @@ -1087,7 +1228,7 @@ public: { subPtr(TrustedImm32(sizeof(QV4::Value)), StackPointerRegister); Pointer tmp(StackPointerRegister, 0); - storeReturnValue(tmp); + storeReturnValue(tmp, WriteBarrier::NoBarrier); toUInt32Register(tmp, dest); addPtr(TrustedImm32(sizeof(QV4::Value)), StackPointerRegister); } @@ -1097,9 +1238,9 @@ public: RegisterSizeDependentOps::storeReturnValue(this, dest); } - void storeReturnValue(const Pointer &dest) + void storeReturnValue(const Pointer &dest, WriteBarrier::Type barrier) { - RegisterSizeDependentOps::storeReturnValue(this, dest); + RegisterSizeDependentOps::storeReturnValue(this, dest, barrier); } void storeReturnValue(IR::Expr *target) @@ -1107,22 +1248,19 @@ public: if (!target) return; - if (IR::Temp *temp = target->asTemp()) { - if (temp->kind == IR::Temp::PhysicalRegister) { - if (temp->type == IR::DoubleType) - storeReturnValue((FPRegisterID) temp->index); - else if (temp->type == IR::UInt32Type) - storeUInt32ReturnValue((RegisterID) temp->index); - else - storeReturnValue((RegisterID) temp->index); - return; - } else { - Pointer addr = loadTempAddress(temp); - storeReturnValue(addr); - } - } else if (IR::ArgLocal *al = target->asArgLocal()) { - Pointer addr = loadArgLocalAddress(ScratchRegister, al); - storeReturnValue(addr); + IR::Temp *temp = target->asTemp(); + if (temp && temp->kind == IR::Temp::PhysicalRegister) { + if (temp->type == IR::DoubleType) + storeReturnValue((FPRegisterID) temp->index); + else if (temp->type == IR::UInt32Type) + storeUInt32ReturnValue((RegisterID) temp->index); + else + storeReturnValue((RegisterID) temp->index); + return; + } else { + WriteBarrier::Type barrier; + Pointer addr = loadAddressForWriting(ScratchRegister, target, &barrier); + storeReturnValue(addr, barrier); } } @@ -1159,7 +1297,7 @@ public: void loadArgumentOnStack(PointerToValue temp, int argumentNumber) { if (temp.value) { - Pointer ptr = toAddress(ScratchRegister, temp.value, argumentNumber); + Pointer ptr = toAddress(ScratchRegister, temp.value, argumentNumber, 0); loadArgumentOnStack<StackSlot>(ptr, argumentNumber); } else { RegisterSizeDependentOps::zeroStackSlot(this, StackSlot); @@ -1179,7 +1317,7 @@ public: { Q_ASSERT (temp.value); - Pointer ptr = loadAddress(ScratchRegister, temp.value); + Pointer ptr = loadAddressForReading(ScratchRegister, temp.value); loadArgumentOnStack<StackSlot>(ptr, argumentNumber); } @@ -1190,7 +1328,7 @@ public: moveDouble((FPRegisterID) sourceTemp->index, dest); return; } - Pointer ptr = loadAddress(ScratchRegister, source); + Pointer ptr = loadAddressForReading(ScratchRegister, source); loadDouble(ptr, dest); } @@ -1209,30 +1347,44 @@ public: RegisterSizeDependentOps::loadDouble(this, addr, dest); } - void storeDouble(FPRegisterID source, Address addr) + void storeDouble(FPRegisterID source, Address addr, WriteBarrier::Type barrier) { - RegisterSizeDependentOps::storeDouble(this, source, addr); + RegisterSizeDependentOps::storeDouble(this, source, addr, barrier); } template <typename Result, typename Source> - void copyValue(Result result, Source source); + void copyValue(Result result, Source source, WriteBarrier::Type barrier); template <typename Result> - void copyValue(Result result, IR::Expr* source); + void copyValue(Result result, IR::Expr* source, WriteBarrier::Type barrier); // The scratch register is used to calculate the temp address for the source. - void memcopyValue(Pointer target, IR::Expr *source, RegisterID scratchRegister) + void memcopyValue(Pointer target, IR::Expr *source, RegisterID scratchRegister, WriteBarrier::Type barrier) { Q_ASSERT(!source->asTemp() || source->asTemp()->kind != IR::Temp::PhysicalRegister); Q_ASSERT(target.base != scratchRegister); - TargetConfiguration::MacroAssembler::loadDouble(loadAddress(scratchRegister, source), FPGpr0); - TargetConfiguration::MacroAssembler::storeDouble(FPGpr0, target); + loadRawValue(loadAddressForReading(scratchRegister, source), FPGpr0); + storeRawValue(FPGpr0, target, barrier); } // The scratch register is used to calculate the temp address for the source. void memcopyValue(IR::Expr *target, Pointer source, FPRegisterID fpScratchRegister, RegisterID scratchRegister) { - TargetConfiguration::MacroAssembler::loadDouble(source, fpScratchRegister); - TargetConfiguration::MacroAssembler::storeDouble(fpScratchRegister, loadAddress(scratchRegister, target)); + loadRawValue(source, fpScratchRegister); + WriteBarrier::Type barrier; + Pointer dest = loadAddressForWriting(scratchRegister, target, &barrier); + storeRawValue(fpScratchRegister, dest, barrier); + } + + void loadRawValue(Pointer source, FPRegisterID dest) + { + TargetConfiguration::MacroAssembler::loadDouble(source, dest); + } + + void storeRawValue(FPRegisterID source, Pointer dest, WriteBarrier::Type barrier) + { + TargetConfiguration::MacroAssembler::storeDouble(source, dest); + if (WriteBarrier::isRequired<WriteBarrier::Unknown>() && barrier == WriteBarrier::Barrier) + RegisterSizeDependentOps::emitWriteBarrier(this, dest); } void storeValue(QV4::Primitive value, RegisterID destination) @@ -1242,20 +1394,25 @@ public: Q_UNREACHABLE(); } - void storeValue(QV4::Primitive value, Address destination) + void storeValue(QV4::Primitive value, Address destination, WriteBarrier::Type barrier) { - RegisterSizeDependentOps::storeValue(this, value, destination); + RegisterSizeDependentOps::storeValue(this, value, destination, barrier); } void storeValue(QV4::Primitive value, IR::Expr* temp); + void emitWriteBarrier(Address addr, WriteBarrier::Type barrier) { + if (WriteBarrier::isRequired<WriteBarrier::Primitive>() && barrier == WriteBarrier::Barrier) + RegisterSizeDependentOps::emitWriteBarrier(this, addr); + } + void enterStandardStackFrame(const RegisterInformation ®ularRegistersToSave, const RegisterInformation &fpRegistersToSave); void leaveStandardStackFrame(const RegisterInformation ®ularRegistersToSave, const RegisterInformation &fpRegistersToSave); void checkException() { - load32(Address(EngineRegister, targetStructureOffset(offsetof(QV4::EngineBase, hasException))), ScratchRegister); + this->load8(Address(EngineRegister, targetStructureOffset(offsetof(QV4::EngineBase, hasException))), ScratchRegister); Jump exceptionThrown = branch32(RelationalCondition::NotEqual, ScratchRegister, TrustedImm32(0)); if (catchBlock) addPatch(catchBlock, exceptionThrown); @@ -1324,7 +1481,7 @@ public: // load the table from the context loadPtr(Address(EngineRegister, targetStructureOffset(offsetof(QV4::EngineBase, current))), ScratchRegister); - loadPtr(Address(ScratchRegister, targetStructureOffset(Heap::ExecutionContext::baseOffset + offsetof(Heap::ExecutionContextData, lookups))), + loadPtr(Address(ScratchRegister, targetStructureOffset(Heap::ExecutionContextData::baseOffset + offsetof(Heap::ExecutionContextData, lookups))), lookupCall.addr.base); // pre-calculate the indirect address for the lookupCall table: if (lookupCall.addr.offset) @@ -1417,8 +1574,10 @@ public: generateFunctionCallImp(needsExceptionCheck, r, functionName, function, arg1, VoidType(), VoidType(), VoidType(), VoidType(), VoidType()); } - Pointer toAddress(RegisterID tmpReg, IR::Expr *e, int offset) + Pointer toAddress(RegisterID tmpReg, IR::Expr *e, int offset, WriteBarrier::Type *barrier) { + if (barrier) + *barrier = WriteBarrier::NoBarrier; if (IR::Const *c = e->asConst()) { Address addr = _stackLayout->savedRegPointer(offset); Address tagAddr = addr; @@ -1434,14 +1593,16 @@ public: if (t->kind == IR::Temp::PhysicalRegister) return Pointer(_stackLayout->savedRegPointer(offset)); - return loadAddress(tmpReg, e); + return loadAddressForWriting(tmpReg, e, barrier); } - void storeBool(RegisterID reg, Pointer addr) + void storeBool(RegisterID reg, Pointer addr, WriteBarrier::Type barrier) { store32(reg, addr); addr.offset += 4; store32(TrustedImm32(QV4::Primitive::fromBoolean(0).tag()), addr); + if (WriteBarrier::isRequired<WriteBarrier::Primitive>() && barrier == WriteBarrier::Barrier) + RegisterSizeDependentOps::emitWriteBarrier(this, addr); } void storeBool(RegisterID src, RegisterID dest) @@ -1458,8 +1619,9 @@ public: } } - Pointer addr = loadAddress(ScratchRegister, target); - storeBool(reg, addr); + WriteBarrier::Type barrier; + Pointer addr = loadAddressForWriting(ScratchRegister, target, &barrier); + storeBool(reg, addr, barrier); } void storeBool(bool value, IR::Expr *target) { @@ -1481,25 +1643,24 @@ public: move(src, dest); } - void storeInt32(RegisterID reg, Pointer addr) + void storeInt32(RegisterID reg, Pointer addr, WriteBarrier::Type barrier) { store32(reg, addr); addr.offset += 4; store32(TrustedImm32(QV4::Primitive::fromInt32(0).tag()), addr); + if (WriteBarrier::isRequired<WriteBarrier::Primitive>() && barrier == WriteBarrier::Barrier) + RegisterSizeDependentOps::emitWriteBarrier(this, addr); } void storeInt32(RegisterID reg, IR::Expr *target) { - if (IR::Temp *targetTemp = target->asTemp()) { - if (targetTemp->kind == IR::Temp::PhysicalRegister) { - move(reg, (RegisterID) targetTemp->index); - } else { - Pointer addr = loadTempAddress(targetTemp); - storeInt32(reg, addr); - } - } else if (IR::ArgLocal *al = target->asArgLocal()) { - Pointer addr = loadArgLocalAddress(ScratchRegister, al); - storeInt32(reg, addr); + IR::Temp *targetTemp = target->asTemp(); + if (targetTemp && targetTemp->kind == IR::Temp::PhysicalRegister) { + move(reg, (RegisterID) targetTemp->index); + } else { + WriteBarrier::Type barrier; + Pointer addr = loadAddressForWriting(ScratchRegister, target, &barrier); + storeInt32(reg, addr, barrier); } } @@ -1508,15 +1669,15 @@ public: move(src, dest); } - void storeUInt32(RegisterID reg, Pointer addr) + void storeUInt32(RegisterID reg, Pointer addr, WriteBarrier::Type barrier) { // The UInt32 representation in QV4::Value is really convoluted. See also toUInt32Register. Jump intRange = branch32(RelationalCondition::GreaterThanOrEqual, reg, TrustedImm32(0)); convertUInt32ToDouble(reg, FPGpr0, ReturnValueRegister); - storeDouble(FPGpr0, addr); + storeDouble(FPGpr0, addr, barrier); Jump done = jump(); intRange.link(this); - storeInt32(reg, addr); + storeInt32(reg, addr, barrier); done.link(this); } @@ -1526,8 +1687,9 @@ public: if (targetTemp && targetTemp->kind == IR::Temp::PhysicalRegister) { move(reg, (RegisterID) targetTemp->index); } else { - Pointer addr = loadAddress(ScratchRegister, target); - storeUInt32(reg, addr); + WriteBarrier::Type barrier; + Pointer addr = loadAddressForWriting(ScratchRegister, target, &barrier); + storeUInt32(reg, addr, barrier); } } @@ -1562,7 +1724,7 @@ public: if (t->kind == IR::Temp::PhysicalRegister) return (RegisterID) t->index; - return toInt32Register(loadAddress(scratchReg, e), scratchReg); + return toInt32Register(loadAddressForReading(scratchReg, e), scratchReg); } RegisterID toInt32Register(Pointer addr, RegisterID scratchReg) @@ -1582,7 +1744,7 @@ public: if (t->kind == IR::Temp::PhysicalRegister) return (RegisterID) t->index; - return toUInt32Register(loadAddress(scratchReg, e), scratchReg); + return toUInt32Register(loadAddressForReading(scratchReg, e), scratchReg); } RegisterID toUInt32Register(Pointer addr, RegisterID scratchReg) @@ -1654,31 +1816,31 @@ private: template <typename TargetConfiguration> template <typename Result, typename Source> -void Assembler<TargetConfiguration>::copyValue(Result result, Source source) +void Assembler<TargetConfiguration>::copyValue(Result result, Source source, WriteBarrier::Type barrier) { - RegisterSizeDependentOps::copyValueViaRegisters(this, source, result); + RegisterSizeDependentOps::copyValueViaRegisters(this, source, result, barrier); } template <typename TargetConfiguration> template <typename Result> -void Assembler<TargetConfiguration>::copyValue(Result result, IR::Expr* source) +void Assembler<TargetConfiguration>::copyValue(Result result, IR::Expr* source, WriteBarrier::Type barrier) { if (source->type == IR::BoolType) { RegisterID reg = toInt32Register(source, ScratchRegister); - storeBool(reg, result); + storeBool(reg, result, barrier); } else if (source->type == IR::SInt32Type) { RegisterID reg = toInt32Register(source, ScratchRegister); - storeInt32(reg, result); + storeInt32(reg, result, barrier); } else if (source->type == IR::UInt32Type) { RegisterID reg = toUInt32Register(source, ScratchRegister); - storeUInt32(reg, result); + storeUInt32(reg, result, barrier); } else if (source->type == IR::DoubleType) { - storeDouble(toDoubleRegister(source), result); + storeDouble(toDoubleRegister(source), result, barrier); } else if (source->asTemp() || source->asArgLocal()) { - RegisterSizeDependentOps::copyValueViaRegisters(this, source, result); + RegisterSizeDependentOps::copyValueViaRegisters(this, source, result, barrier); } else if (IR::Const *c = source->asConst()) { QV4::Primitive v = convertToValue(c); - storeValue(v, result); + storeValue(v, result, barrier); } else { Q_UNREACHABLE(); } diff --git a/src/qml/jit/qv4binop.cpp b/src/qml/jit/qv4binop.cpp index feb30ee298..a1c65f644c 100644 --- a/src/qml/jit/qv4binop.cpp +++ b/src/qml/jit/qv4binop.cpp @@ -492,7 +492,7 @@ bool Binop<JITAssembler>::int32Binop(IR::Expr *leftSource, IR::Expr *rightSource return false; } } else if (inplaceOpWithAddress) { // All cases of X = X op [address-of-Y] - Pointer rhsAddr = as->loadAddress(JITAssembler::ScratchRegister, rightSource); + Pointer rhsAddr = as->loadAddressForReading(JITAssembler::ScratchRegister, rightSource); switch (op) { case IR::OpBitAnd: as->and32(rhsAddr, targetReg); break; case IR::OpBitOr: as->or32 (rhsAddr, targetReg); break; diff --git a/src/qml/jit/qv4isel_masm.cpp b/src/qml/jit/qv4isel_masm.cpp index 4a222e20f4..9841620481 100644 --- a/src/qml/jit/qv4isel_masm.cpp +++ b/src/qml/jit/qv4isel_masm.cpp @@ -133,7 +133,7 @@ void InstructionSelection<JITAssembler>::run(int functionIndex) if (s->location.isValid()) { if (int(s->location.startLine) != lastLine) { _as->loadPtr(Address(JITTargetPlatform::EngineRegister, JITAssembler::targetStructureOffset(offsetof(QV4::EngineBase, current))), JITTargetPlatform::ScratchRegister); - Address lineAddr(JITTargetPlatform::ScratchRegister, JITAssembler::targetStructureOffset(Heap::ExecutionContext::baseOffset + offsetof(Heap::ExecutionContextData, lineNumber))); + Address lineAddr(JITTargetPlatform::ScratchRegister, JITAssembler::targetStructureOffset(Heap::ExecutionContextData::baseOffset + offsetof(Heap::ExecutionContextData, lineNumber))); _as->store32(TrustedImm32(s->location.startLine), lineAddr); lastLine = s->location.startLine; } @@ -350,11 +350,11 @@ void InstructionSelection<JITAssembler>::callBuiltinDefineObjectLiteral(IR::Expr bool isData = it->expr->asConst()->value; it = it->next; - _as->copyValue(_as->stackLayout().argumentAddressForCall(argc++), it->expr); + _as->copyValue(_as->stackLayout().argumentAddressForCall(argc++), it->expr, WriteBarrier::NoBarrier); if (!isData) { it = it->next; - _as->copyValue(_as->stackLayout().argumentAddressForCall(argc++), it->expr); + _as->copyValue(_as->stackLayout().argumentAddressForCall(argc++), it->expr, WriteBarrier::NoBarrier); } } @@ -376,10 +376,10 @@ void InstructionSelection<JITAssembler>::callBuiltinDefineObjectLiteral(IR::Expr ++arrayValueCount; // Index - _as->storeValue(QV4::Primitive::fromUInt32(index), _as->stackLayout().argumentAddressForCall(argc++)); + _as->storeValue(QV4::Primitive::fromUInt32(index), _as->stackLayout().argumentAddressForCall(argc++), WriteBarrier::NoBarrier); // Value - _as->copyValue(_as->stackLayout().argumentAddressForCall(argc++), it->expr); + _as->copyValue(_as->stackLayout().argumentAddressForCall(argc++), it->expr, WriteBarrier::NoBarrier); it = it->next; } @@ -400,14 +400,14 @@ void InstructionSelection<JITAssembler>::callBuiltinDefineObjectLiteral(IR::Expr ++arrayGetterSetterCount; // Index - _as->storeValue(QV4::Primitive::fromUInt32(index), _as->stackLayout().argumentAddressForCall(argc++)); + _as->storeValue(QV4::Primitive::fromUInt32(index), _as->stackLayout().argumentAddressForCall(argc++), WriteBarrier::NoBarrier); // Getter - _as->copyValue(_as->stackLayout().argumentAddressForCall(argc++), it->expr); + _as->copyValue(_as->stackLayout().argumentAddressForCall(argc++), it->expr, WriteBarrier::NoBarrier); it = it->next; // Setter - _as->copyValue(_as->stackLayout().argumentAddressForCall(argc++), it->expr); + _as->copyValue(_as->stackLayout().argumentAddressForCall(argc++), it->expr, WriteBarrier::NoBarrier); it = it->next; } @@ -447,9 +447,11 @@ void InstructionSelection<JITAssembler>::callValue(IR::Expr *value, IR::ExprList template <typename JITAssembler> void InstructionSelection<JITAssembler>::loadThisObject(IR::Expr *temp) { - _as->loadPtr(Address(JITTargetPlatform::EngineRegister, JITAssembler::targetStructureOffset(offsetof(QV4::EngineBase, current))), JITTargetPlatform::ScratchRegister); - _as->loadPtr(Address(JITTargetPlatform::ScratchRegister, JITAssembler::targetStructureOffset(Heap::ExecutionContext::baseOffset + offsetof(Heap::ExecutionContextData, callData))), JITTargetPlatform::ScratchRegister); - _as->copyValue(temp, Address(JITTargetPlatform::ScratchRegister, offsetof(CallData, thisObject))); + WriteBarrier::Type barrier; + Pointer addr = _as->loadAddressForWriting(JITTargetPlatform::ScratchRegister, temp, &barrier); + _as->loadPtr(Address(JITTargetPlatform::EngineRegister, JITAssembler::targetStructureOffset(offsetof(QV4::EngineBase, current))), JITTargetPlatform::ReturnValueRegister); + _as->loadPtr(Address(JITTargetPlatform::ReturnValueRegister,JITAssembler::targetStructureOffset(Heap::ExecutionContextData::baseOffset + offsetof(Heap::ExecutionContextData, callData))), JITTargetPlatform::ReturnValueRegister); + _as->copyValue(addr, Address(JITTargetPlatform::ReturnValueRegister, offsetof(CallData, thisObject)), barrier); } template <typename JITAssembler> @@ -503,8 +505,9 @@ void InstructionSelection<JITAssembler>::loadString(const QString &str, IR::Expr { Pointer srcAddr = _as->loadStringAddress(JITTargetPlatform::ReturnValueRegister, str); _as->loadPtr(srcAddr, JITTargetPlatform::ReturnValueRegister); - Pointer destAddr = _as->loadAddress(JITTargetPlatform::ScratchRegister, target); - JITAssembler::RegisterSizeDependentOps::loadManagedPointer(_as, JITTargetPlatform::ReturnValueRegister, destAddr); + WriteBarrier::Type barrier; + Pointer destAddr = _as->loadAddressForWriting(JITTargetPlatform::ScratchRegister, target, &barrier); + JITAssembler::RegisterSizeDependentOps::loadManagedPointer(_as, JITTargetPlatform::ReturnValueRegister, destAddr, barrier); } template <typename JITAssembler> @@ -621,6 +624,7 @@ void InstructionSelection<JITAssembler>::getElement(IR::Expr *base, IR::Expr *in if (useFastLookups) { uint lookup = registerIndexedGetterLookup(); generateLookupCall(target, lookup, offsetof(QV4::Lookup, indexedGetter), + JITTargetPlatform::EngineRegister, PointerToValue(base), PointerToValue(index)); return; @@ -636,6 +640,7 @@ void InstructionSelection<JITAssembler>::setElement(IR::Expr *source, IR::Expr * if (useFastLookups) { uint lookup = registerIndexedSetterLookup(); generateLookupCall(JITAssembler::Void, lookup, offsetof(QV4::Lookup, indexedSetter), + JITTargetPlatform::EngineRegister, PointerToValue(targetBase), PointerToValue(targetIndex), PointerToValue(source)); return; @@ -711,8 +716,10 @@ void InstructionSelection<JITAssembler>::copyValue(IR::Expr *source, IR::Expr *t } } + WriteBarrier::Type barrier; + Pointer addr = _as->loadAddressForWriting(JITTargetPlatform::ReturnValueRegister, target, &barrier); // The target is not a physical register, nor is the source. So we can do a memory-to-memory copy: - _as->memcopyValue(_as->loadAddress(JITTargetPlatform::ReturnValueRegister, target), source, JITTargetPlatform::ScratchRegister); + _as->memcopyValue(addr, source, JITTargetPlatform::ScratchRegister, barrier); } template <typename JITAssembler> @@ -739,14 +746,13 @@ void InstructionSelection<JITAssembler>::swapValues(IR::Expr *source, IR::Expr * } else if (!sourceTemp || sourceTemp->kind == IR::Temp::StackSlot) { if (!targetTemp || targetTemp->kind == IR::Temp::StackSlot) { // Note: a swap for two stack-slots can involve different types. - Pointer sAddr = _as->loadAddress(JITTargetPlatform::ScratchRegister, source); - Pointer tAddr = _as->loadAddress(JITTargetPlatform::ReturnValueRegister, target); - // use the implementation in JSC::MacroAssembler, as it doesn't do bit swizzling - auto platformAs = static_cast<typename JITAssembler::MacroAssembler*>(_as); - platformAs->loadDouble(sAddr, JITTargetPlatform::FPGpr0); - platformAs->loadDouble(tAddr, JITTargetPlatform::FPGpr1); - platformAs->storeDouble(JITTargetPlatform::FPGpr1, sAddr); - platformAs->storeDouble(JITTargetPlatform::FPGpr0, tAddr); + WriteBarrier::Type barrierForSource, barrierForTarget; + Pointer sAddr = _as->loadAddressForWriting(JITTargetPlatform::ScratchRegister, source, &barrierForSource); + Pointer tAddr = _as->loadAddressForWriting(JITTargetPlatform::ReturnValueRegister, target, &barrierForTarget); + _as->loadRawValue(sAddr, JITTargetPlatform::FPGpr0); + _as->loadRawValue(tAddr, JITTargetPlatform::FPGpr1); + _as->storeRawValue(JITTargetPlatform::FPGpr1, sAddr, barrierForSource); + _as->storeRawValue(JITTargetPlatform::FPGpr0, tAddr, barrierForTarget); return; } } @@ -757,14 +763,15 @@ void InstructionSelection<JITAssembler>::swapValues(IR::Expr *source, IR::Expr * Q_ASSERT(memExpr); Q_ASSERT(regTemp); - Pointer addr = _as->loadAddress(JITTargetPlatform::ReturnValueRegister, memExpr); + WriteBarrier::Type barrier; + Pointer addr = _as->loadAddressForWriting(JITTargetPlatform::ReturnValueRegister, memExpr, &barrier); if (regTemp->type == IR::DoubleType) { _as->loadDouble(addr, JITTargetPlatform::FPGpr0); - _as->storeDouble((FPRegisterID) regTemp->index, addr); + _as->storeDouble((FPRegisterID) regTemp->index, addr, barrier); _as->moveDouble(JITTargetPlatform::FPGpr0, (FPRegisterID) regTemp->index); } else if (regTemp->type == IR::UInt32Type) { _as->toUInt32Register(addr, JITTargetPlatform::ScratchRegister); - _as->storeUInt32((RegisterID) regTemp->index, addr); + _as->storeUInt32((RegisterID) regTemp->index, addr, barrier); _as->move(JITTargetPlatform::ScratchRegister, (RegisterID) regTemp->index); } else { _as->load32(addr, JITTargetPlatform::ScratchRegister); @@ -784,6 +791,7 @@ void InstructionSelection<JITAssembler>::swapValues(IR::Expr *source, IR::Expr * Q_UNREACHABLE(); } _as->store32(TrustedImm32(tag), addr); + _as->emitWriteBarrier(addr, barrier); } _as->move(JITTargetPlatform::ScratchRegister, (RegisterID) regTemp->index); } @@ -913,13 +921,13 @@ void InstructionSelection<JITAssembler>::convertTypeToDouble(IR::Expr *source, I convertUIntToDouble(source, target); break; case IR::UndefinedType: - _as->loadDouble(_as->loadAddress(JITTargetPlatform::ScratchRegister, source), JITTargetPlatform::FPGpr0); + _as->loadDouble(_as->loadAddressForReading(JITTargetPlatform::ScratchRegister, source), JITTargetPlatform::FPGpr0); _as->storeDouble(JITTargetPlatform::FPGpr0, target); break; case IR::StringType: case IR::VarType: { // load the tag: - Pointer tagAddr = _as->loadAddress(JITTargetPlatform::ScratchRegister, source); + Pointer tagAddr = _as->loadAddressForReading(JITTargetPlatform::ScratchRegister, source); tagAddr.offset += 4; _as->load32(tagAddr, JITTargetPlatform::ScratchRegister); @@ -938,7 +946,7 @@ void InstructionSelection<JITAssembler>::convertTypeToDouble(IR::Expr *source, I // it is a double: isDbl.link(_as); - Pointer addr2 = _as->loadAddress(JITTargetPlatform::ScratchRegister, source); + Pointer addr2 = _as->loadAddressForReading(JITTargetPlatform::ScratchRegister, source); IR::Temp *targetTemp = target->asTemp(); if (!targetTemp || targetTemp->kind == IR::Temp::StackSlot) { _as->memcopyValue(target, addr2, JITTargetPlatform::FPGpr0, JITTargetPlatform::ReturnValueRegister); @@ -996,7 +1004,7 @@ void InstructionSelection<JITAssembler>::convertTypeToBool(IR::Expr *source, IR: _as->storeBool(JITTargetPlatform::ReturnValueRegister, target); case IR::VarType: default: - Pointer addr = _as->loadAddress(JITTargetPlatform::ScratchRegister, source); + Pointer addr = _as->loadAddressForReading(JITTargetPlatform::ScratchRegister, source); Pointer tagAddr = addr; tagAddr.offset += 4; _as->load32(tagAddr, JITTargetPlatform::ReturnValueRegister); @@ -1061,7 +1069,7 @@ void InstructionSelection<JITAssembler>::convertTypeToSInt32(IR::Expr *source, I case IR::StringType: default: generateRuntimeCall(_as, JITTargetPlatform::ReturnValueRegister, toInt, - _as->loadAddress(JITTargetPlatform::ScratchRegister, source)); + _as->loadAddressForReading(JITTargetPlatform::ScratchRegister, source)); _as->storeInt32(JITTargetPlatform::ReturnValueRegister, target); break; } // switch (source->type) @@ -1073,21 +1081,21 @@ void InstructionSelection<JITAssembler>::convertTypeToUInt32(IR::Expr *source, I switch (source->type) { case IR::VarType: { // load the tag: - Pointer tagAddr = _as->loadAddress(JITTargetPlatform::ScratchRegister, source); + Pointer tagAddr = _as->loadAddressForReading(JITTargetPlatform::ScratchRegister, source); tagAddr.offset += 4; _as->load32(tagAddr, JITTargetPlatform::ScratchRegister); // check if it's an int32: Jump isNoInt = _as->branch32(RelationalCondition::NotEqual, JITTargetPlatform::ScratchRegister, TrustedImm32(Value::Integer_Type_Internal)); - Pointer addr = _as->loadAddress(JITTargetPlatform::ScratchRegister, source); + Pointer addr = _as->loadAddressForReading(JITTargetPlatform::ScratchRegister, source); _as->storeUInt32(_as->toInt32Register(addr, JITTargetPlatform::ScratchRegister), target); Jump intDone = _as->jump(); // not an int: isNoInt.link(_as); generateRuntimeCall(_as, JITTargetPlatform::ReturnValueRegister, toUInt, - _as->loadAddress(JITTargetPlatform::ScratchRegister, source)); + _as->loadAddressForReading(JITTargetPlatform::ScratchRegister, source)); _as->storeInt32(JITTargetPlatform::ReturnValueRegister, target); intDone.link(_as); @@ -1192,7 +1200,7 @@ void InstructionSelection<JITAssembler>::visitCJump(IR::CJump *s) reg = JITTargetPlatform::ReturnValueRegister; _as->toInt32Register(t, reg); } else { - Address temp = _as->loadAddress(JITTargetPlatform::ScratchRegister, s->cond); + Address temp = _as->loadAddressForReading(JITTargetPlatform::ScratchRegister, s->cond); Address tag = temp; tag.offset += QV4::Value::tagOffset(); Jump booleanConversion = _as->branch32(RelationalCondition::NotEqual, tag, TrustedImm32(QV4::Value::Boolean_Type_Internal)); @@ -1297,9 +1305,9 @@ int InstructionSelection<JITAssembler>::prepareVariableArguments(IR::ExprList* a Q_ASSERT(arg != 0); Pointer dst(_as->stackLayout().argumentAddressForCall(i)); if (arg->asTemp() && arg->asTemp()->kind != IR::Temp::PhysicalRegister) - _as->memcopyValue(dst, arg->asTemp(), JITTargetPlatform::ScratchRegister); + _as->memcopyValue(dst, arg->asTemp(), JITTargetPlatform::ScratchRegister, WriteBarrier::NoBarrier); else - _as->copyValue(dst, arg); + _as->copyValue(dst, arg, WriteBarrier::NoBarrier); } return argc; @@ -1319,9 +1327,9 @@ int InstructionSelection<JITAssembler>::prepareCallData(IR::ExprList* args, IR:: _as->store32(TrustedImm32(argc), p); p = _as->stackLayout().callDataAddress(offsetof(CallData, thisObject)); if (!thisObject) - _as->storeValue(QV4::Primitive::undefinedValue(), p); + _as->storeValue(QV4::Primitive::undefinedValue(), p, WriteBarrier::NoBarrier); else - _as->copyValue(p, thisObject); + _as->copyValue(p, thisObject, WriteBarrier::NoBarrier); int i = 0; for (IR::ExprList *it = args; it; it = it->next, ++i) { @@ -1329,9 +1337,9 @@ int InstructionSelection<JITAssembler>::prepareCallData(IR::ExprList* args, IR:: Q_ASSERT(arg != 0); Pointer dst(_as->stackLayout().argumentAddressForCall(i)); if (arg->asTemp() && arg->asTemp()->kind != IR::Temp::PhysicalRegister) - _as->memcopyValue(dst, arg->asTemp(), JITTargetPlatform::ScratchRegister); + _as->memcopyValue(dst, arg->asTemp(), JITTargetPlatform::ScratchRegister, WriteBarrier::NoBarrier); else - _as->copyValue(dst, arg); + _as->copyValue(dst, arg, WriteBarrier::NoBarrier); } return argc; } @@ -1449,7 +1457,7 @@ bool InstructionSelection<JITAssembler>::visitCJumpStrictNull(IR::Binop *binop, return true; } - Pointer tagAddr = _as->loadAddress(JITTargetPlatform::ScratchRegister, varSrc); + Pointer tagAddr = _as->loadAddressForReading(JITTargetPlatform::ScratchRegister, varSrc); tagAddr.offset += 4; const RegisterID tagReg = JITTargetPlatform::ScratchRegister; _as->load32(tagAddr, tagReg); @@ -1532,7 +1540,7 @@ bool InstructionSelection<JITAssembler>::visitCJumpStrictBool(IR::Binop *binop, return true; } - Pointer otherAddr = _as->loadAddress(JITTargetPlatform::ReturnValueRegister, otherSrc); + Pointer otherAddr = _as->loadAddressForReading(JITTargetPlatform::ReturnValueRegister, otherSrc); otherAddr.offset += 4; // tag address // check if the tag of the var operand is indicates 'boolean' @@ -1581,7 +1589,7 @@ bool InstructionSelection<JITAssembler>::visitCJumpNullUndefined(IR::Type nullOr return true; } - Pointer tagAddr = _as->loadAddress(JITTargetPlatform::ScratchRegister, varSrc); + Pointer tagAddr = _as->loadAddressForReading(JITTargetPlatform::ScratchRegister, varSrc); tagAddr.offset += 4; const RegisterID tagReg = JITTargetPlatform::ReturnValueRegister; _as->load32(tagAddr, tagReg); diff --git a/src/qml/jit/qv4isel_masm_p.h b/src/qml/jit/qv4isel_masm_p.h index 5c046cb397..0d02284539 100644 --- a/src/qml/jit/qv4isel_masm_p.h +++ b/src/qml/jit/qv4isel_masm_p.h @@ -209,7 +209,7 @@ private: _as->convertInt32ToDouble((RegisterID) sourceTemp->index, (FPRegisterID) targetTemp->index); } else { - _as->convertInt32ToDouble(_as->loadAddress(JITTargetPlatform::ReturnValueRegister, sourceTemp), + _as->convertInt32ToDouble(_as->loadAddressForReading(JITTargetPlatform::ReturnValueRegister, sourceTemp), (FPRegisterID) targetTemp->index); } } else { @@ -223,7 +223,7 @@ private: _as->convertInt32ToDouble(_as->toInt32Register(source, JITTargetPlatform::ScratchRegister), JITTargetPlatform::FPGpr0); - _as->storeDouble(JITTargetPlatform::FPGpr0, _as->loadAddress(JITTargetPlatform::ReturnValueRegister, target)); + _as->storeDouble(JITTargetPlatform::FPGpr0, target); } void convertUIntToDouble(IR::Expr *source, IR::Expr *target) @@ -240,7 +240,7 @@ private: _as->convertUInt32ToDouble(_as->toUInt32Register(source, tmpReg), JITTargetPlatform::FPGpr0, tmpReg); - _as->storeDouble(JITTargetPlatform::FPGpr0, _as->loadAddress(tmpReg, target)); + _as->storeDouble(JITTargetPlatform::FPGpr0, target); } void convertIntToBool(IR::Expr *source, IR::Expr *target) @@ -260,8 +260,8 @@ private: void calculateRegistersToSave(const RegisterInformation &used); - template <typename Retval, typename Arg1, typename Arg2, typename Arg3> - void generateLookupCall(Retval retval, uint index, uint getterSetterOffset, Arg1 arg1, Arg2 arg2, Arg3 arg3) + template <typename Retval, typename Arg1, typename Arg2, typename Arg3, typename Arg4> + void generateLookupCall(Retval retval, uint index, uint getterSetterOffset, Arg1 arg1, Arg2 arg2, Arg3 arg3, Arg4 arg4) { // Note: using the return value register is intentional: for ABIs where the first parameter // goes into the same register as the return value (currently only ARM), the prepareCall @@ -271,7 +271,7 @@ private: _as->generateFunctionCallImp(true, retval, "lookup getter/setter", typename JITAssembler::LookupCall(lookupAddr, getterSetterOffset), lookupAddr, - arg1, arg2, arg3); + arg1, arg2, arg3, arg4); } template <typename Retval, typename Arg1, typename Arg2> @@ -280,6 +280,12 @@ private: generateLookupCall(retval, index, getterSetterOffset, arg1, arg2, typename JITAssembler::VoidType()); } + template <typename Retval, typename Arg1, typename Arg2, typename Arg3> + void generateLookupCall(Retval retval, uint index, uint getterSetterOffset, Arg1 arg1, Arg2 arg2, Arg3 arg3) + { + generateLookupCall(retval, index, getterSetterOffset, arg1, arg2, arg3, typename JITAssembler::VoidType()); + } + IR::BasicBlock *_block; BitVector _removableJumps; JITAssembler* _as; diff --git a/src/qml/jsapi/qjsengine.cpp b/src/qml/jsapi/qjsengine.cpp index e4c150057a..b52c859ecb 100644 --- a/src/qml/jsapi/qjsengine.cpp +++ b/src/qml/jsapi/qjsengine.cpp @@ -333,7 +333,7 @@ QJSEngine::~QJSEngine() */ void QJSEngine::collectGarbage() { - d->m_v4Engine->memoryManager->runGC(); + d->m_v4Engine->memoryManager->runGC(/* forceFullCollection = */ true); } #if QT_DEPRECATED_SINCE(5, 6) diff --git a/src/qml/jsruntime/qv4argumentsobject.cpp b/src/qml/jsruntime/qv4argumentsobject.cpp index 9354bcb1a3..318db4f904 100644 --- a/src/qml/jsruntime/qv4argumentsobject.cpp +++ b/src/qml/jsruntime/qv4argumentsobject.cpp @@ -48,32 +48,33 @@ DEFINE_OBJECT_VTABLE(ArgumentsObject); void Heap::ArgumentsObject::init(QV4::CallContext *context) { + ExecutionEngine *v4 = context->d()->engine; + Object::init(); fullyCreated = false; - this->context = context->d(); + this->context.set(v4, context->d()); Q_ASSERT(vtable() == QV4::ArgumentsObject::staticVTable()); - ExecutionEngine *v4 = context->d()->engine; Scope scope(v4); Scoped<QV4::ArgumentsObject> 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())); - *args->propertyData(CalleePropertyIndex + QV4::Object::GetterOffset) = v4->thrower(); - *args->propertyData(CalleePropertyIndex + QV4::Object::SetterOffset) = v4->thrower(); - *args->propertyData(CallerPropertyIndex + QV4::Object::GetterOffset) = v4->thrower(); - *args->propertyData(CallerPropertyIndex + QV4::Object::SetterOffset) = v4->thrower(); + args->setProperty(CalleePropertyIndex + QV4::Object::GetterOffset, *v4->thrower()); + args->setProperty(CalleePropertyIndex + QV4::Object::SetterOffset, *v4->thrower()); + args->setProperty(CallerPropertyIndex + QV4::Object::GetterOffset, *v4->thrower()); + args->setProperty(CallerPropertyIndex + QV4::Object::SetterOffset, *v4->thrower()); args->arrayReserve(context->argc()); args->arrayPut(0, context->args(), context->argc()); args->d()->fullyCreated = true; } else { Q_ASSERT(CalleePropertyIndex == args->internalClass()->find(context->d()->engine->id_callee())); - *args->propertyData(CalleePropertyIndex) = context->d()->function->asReturnedValue(); + args->setProperty(CalleePropertyIndex, context->d()->function); } Q_ASSERT(LengthPropertyIndex == args->internalClass()->find(context->d()->engine->id_length())); - *args->propertyData(LengthPropertyIndex) = Primitive::fromInt32(context->d()->callData->argc); + args->setProperty(LengthPropertyIndex, Primitive::fromInt32(context->d()->callData->argc)); } void ArgumentsObject::fullyCreate() @@ -89,9 +90,9 @@ void ArgumentsObject::fullyCreate() Scope scope(engine()); Scoped<MemberData> md(scope, d()->mappedArguments); if (numAccessors) { - d()->mappedArguments = md->allocate(engine(), numAccessors); + d()->mappedArguments.set(scope.engine, md->allocate(engine(), numAccessors)); for (uint i = 0; i < numAccessors; ++i) { - d()->mappedArguments->data[i] = context()->callData->args[i]; + d()->mappedArguments->values.set(scope.engine, i, context()->callData->args[i]); arraySet(i, context()->engine->argumentsAccessors + i, Attr_Accessor); } } @@ -107,22 +108,22 @@ bool ArgumentsObject::defineOwnProperty(ExecutionEngine *engine, uint index, con fullyCreate(); Scope scope(engine); - Property *pd = arrayData() ? arrayData()->getProperty(index) : 0; ScopedProperty map(scope); PropertyAttributes mapAttrs; + uint numAccessors = qMin(context()->formalParameterCount(), static_cast<uint>(context()->callData->argc)); bool isMapped = false; - 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(); + if (arrayData() && index < numAccessors && + arrayData()->attributes(index).isAccessor() && + arrayData()->get(index) == context()->engine->argumentsAccessors[index].getter()->asReturnedValue()) + isMapped = true; if (isMapped) { Q_ASSERT(arrayData()); mapAttrs = arrayData()->attributes(index); - map->copy(pd, mapAttrs); + arrayData()->getProperty(index, map, &mapAttrs); setArrayAttributes(index, Attr_Data); - pd = arrayData()->getProperty(index); - pd->value = d()->mappedArguments->data[index]; + ArrayData::Index arrayIndex{ arrayData(), arrayData()->mappedIndex(index) }; + arrayIndex.set(scope.engine, d()->mappedArguments->values[index]); } bool strict = engine->current->strictMode; @@ -140,8 +141,7 @@ bool ArgumentsObject::defineOwnProperty(ExecutionEngine *engine, uint index, con if (attrs.isWritable()) { setArrayAttributes(index, mapAttrs); - pd = arrayData()->getProperty(index); - pd->copy(map, mapAttrs); + arrayData()->setProperty(engine, index, map); } } @@ -166,18 +166,17 @@ ReturnedValue ArgumentsObject::getIndexed(const Managed *m, uint index, bool *ha return Encode::undefined(); } -void ArgumentsObject::putIndexed(Managed *m, uint index, const Value &value) +bool ArgumentsObject::putIndexed(Managed *m, uint index, const Value &value) { ArgumentsObject *args = static_cast<ArgumentsObject *>(m); if (!args->fullyCreated() && index >= static_cast<uint>(args->context()->callData->argc)) args->fullyCreate(); - if (args->fullyCreated()) { - Object::putIndexed(m, index, value); - return; - } + if (args->fullyCreated()) + return Object::putIndexed(m, index, value); args->context()->callData->args[index] = value; + return true; } bool ArgumentsObject::deleteIndexedProperty(Managed *m, uint index) @@ -236,17 +235,6 @@ void ArgumentsSetterFunction::call(const Managed *setter, Scope &scope, CallData scope.result = Encode::undefined(); } -void ArgumentsObject::markObjects(Heap::Base *that, ExecutionEngine *e) -{ - ArgumentsObject::Data *o = static_cast<ArgumentsObject::Data *>(that); - if (o->context) - o->context->mark(e); - if (o->mappedArguments) - o->mappedArguments->mark(e); - - Object::markObjects(that, e); -} - uint ArgumentsObject::getLength(const Managed *m) { const ArgumentsObject *a = static_cast<const ArgumentsObject *>(m); diff --git a/src/qml/jsruntime/qv4argumentsobject_p.h b/src/qml/jsruntime/qv4argumentsobject_p.h index 0a2ea3b42a..46e1f884e8 100644 --- a/src/qml/jsruntime/qv4argumentsobject_p.h +++ b/src/qml/jsruntime/qv4argumentsobject_p.h @@ -59,26 +59,35 @@ namespace QV4 { namespace Heap { -struct ArgumentsGetterFunction : FunctionObject { +#define ArgumentsGetterFunctionMembers(class, Member) \ + Member(class, NoMark, uint, index) + +DECLARE_HEAP_OBJECT(ArgumentsGetterFunction, FunctionObject) { + DECLARE_MARK_TABLE(ArgumentsGetterFunction); inline void init(QV4::ExecutionContext *scope, uint index); - uint index; }; -struct ArgumentsSetterFunction : FunctionObject { +#define ArgumentsSetterFunctionMembers(class, Member) \ + Member(class, NoMark, uint, index) + +DECLARE_HEAP_OBJECT(ArgumentsSetterFunction, FunctionObject) { + DECLARE_MARK_TABLE(ArgumentsSetterFunction); inline void init(QV4::ExecutionContext *scope, uint index); - uint index; }; -struct ArgumentsObject : Object { +#define ArgumentsObjectMembers(class, Member) \ + Member(class, Pointer, CallContext *, context) \ + Member(class, Pointer, MemberData *, mappedArguments) \ + Member(class, NoMark, bool, fullyCreated) + +DECLARE_HEAP_OBJECT(ArgumentsObject, Object) { + DECLARE_MARK_TABLE(ArgumentsObject); enum { LengthPropertyIndex = 0, CalleePropertyIndex = 1, CallerPropertyIndex = 3 }; void init(QV4::CallContext *context); - Pointer<CallContext> context; - bool fullyCreated; - Pointer<MemberData> mappedArguments; }; } @@ -128,10 +137,9 @@ struct ArgumentsObject: Object { bool defineOwnProperty(ExecutionEngine *engine, uint index, const Property *desc, PropertyAttributes attrs); static ReturnedValue getIndexed(const Managed *m, uint index, bool *hasProperty); - static void putIndexed(Managed *m, uint index, const Value &value); + static bool putIndexed(Managed *m, uint index, const Value &value); static bool deleteIndexedProperty(Managed *m, uint index); static PropertyAttributes queryIndexed(const Managed *m, uint index); - static void markObjects(Heap::Base *that, ExecutionEngine *e); static uint getLength(const Managed *m); void fullyCreate(); diff --git a/src/qml/jsruntime/qv4arraydata.cpp b/src/qml/jsruntime/qv4arraydata.cpp index c29cedaa9b..4a619858b4 100644 --- a/src/qml/jsruntime/qv4arraydata.cpp +++ b/src/qml/jsruntime/qv4arraydata.cpp @@ -50,6 +50,7 @@ QT_WARNING_SUPPRESS_GCC_TAUTOLOGICAL_COMPARE_ON const QV4::VTable QV4::ArrayData::static_vtbl = { 0, + 0, QV4::ArrayData::IsExecutionContext, QV4::ArrayData::IsString, QV4::ArrayData::IsObject, @@ -128,7 +129,7 @@ void ArrayData::realloc(Object *o, Type newType, uint requested, bool enforceAtt if (d->type() < Heap::ArrayData::Sparse) { offset = d->d()->offset; - toCopy = d->d()->len; + toCopy = d->d()->values.size; } else { toCopy = d->alloc(); } @@ -149,7 +150,7 @@ void ArrayData::realloc(Object *o, Type newType, uint requested, bool enforceAtt Heap::SimpleArrayData *n = scope.engine->memoryManager->allocManaged<SimpleArrayData>(size); n->init(); n->offset = 0; - n->len = d ? d->d()->len : 0; + n->values.size = d ? d->d()->values.size : 0; newData = n; } else { Heap::SparseArrayData *n = scope.engine->memoryManager->allocManaged<SparseArrayData>(size); @@ -158,7 +159,7 @@ void ArrayData::realloc(Object *o, Type newType, uint requested, bool enforceAtt } newData->setAlloc(alloc); newData->setType(newType); - newData->setAttrs(enforceAttributes ? reinterpret_cast<PropertyAttributes *>(newData->d()->arrayData + alloc) : 0); + newData->setAttrs(enforceAttributes ? reinterpret_cast<PropertyAttributes *>(newData->d()->values.values + alloc) : 0); o->setArrayData(newData); if (d) { @@ -170,12 +171,14 @@ void ArrayData::realloc(Object *o, Type newType, uint requested, bool enforceAtt newData->attrs()[i] = Attr_Data; } - if (toCopy > d->d()->alloc - offset) { - uint copyFromStart = toCopy - (d->d()->alloc - offset); - memcpy(newData->d()->arrayData + toCopy - copyFromStart, d->d()->arrayData, sizeof(Value)*copyFromStart); + if (toCopy > d->d()->values.alloc - offset) { + uint copyFromStart = toCopy - (d->d()->values.alloc - offset); + // no write barrier required here + memcpy(newData->d()->values.values + toCopy - copyFromStart, d->d()->values.values, sizeof(Value)*copyFromStart); toCopy -= copyFromStart; } - memcpy(newData->d()->arrayData, d->d()->arrayData + offset, sizeof(Value)*toCopy); + // no write barrier required here + memcpy(newData->d()->values.values, d->d()->values.values + offset, sizeof(Value)*toCopy); } if (newType != Heap::ArrayData::Sparse) @@ -195,22 +198,22 @@ void ArrayData::realloc(Object *o, Type newType, uint requested, bool enforceAtt lastFree = &sparse->freeList; storeValue(lastFree, 0); for (uint i = 0; i < toCopy; ++i) { - if (!sparse->arrayData[i].isEmpty()) { + if (!sparse->values[i].isEmpty()) { SparseArrayNode *n = sparse->sparse->insert(i); n->value = i; } else { storeValue(lastFree, i); - sparse->arrayData[i].setEmpty(); - lastFree = &sparse->arrayData[i].rawValueRef(); + sparse->values.values[i].setEmpty(); + lastFree = &sparse->values.values[i].rawValueRef(); } } } - if (toCopy < sparse->alloc) { - for (uint i = toCopy; i < sparse->alloc; ++i) { + if (toCopy < sparse->values.alloc) { + for (uint i = toCopy; i < sparse->values.alloc; ++i) { storeValue(lastFree, i); - sparse->arrayData[i].setEmpty(); - lastFree = &sparse->arrayData[i].rawValueRef(); + sparse->values.values[i].setEmpty(); + lastFree = &sparse->values.values[i].rawValueRef(); } storeValue(lastFree, UINT_MAX); } @@ -233,24 +236,10 @@ void ArrayData::ensureAttributes(Object *o) ArrayData::realloc(o, Heap::ArrayData::Simple, 0, true); } - -void SimpleArrayData::markObjects(Heap::Base *d, ExecutionEngine *e) -{ - Heap::SimpleArrayData *dd = static_cast<Heap::SimpleArrayData *>(d); - uint end = dd->offset + dd->len; - if (end > dd->alloc) { - for (uint i = 0; i < end - dd->alloc; ++i) - dd->arrayData[i].mark(e); - end = dd->alloc; - } - for (uint i = dd->offset; i < end; ++i) - dd->arrayData[i].mark(e); -} - ReturnedValue SimpleArrayData::get(const Heap::ArrayData *d, uint index) { const Heap::SimpleArrayData *dd = static_cast<const Heap::SimpleArrayData *>(d); - if (index >= dd->len) + if (index >= dd->values.size) return Primitive::emptyValue().asReturnedValue(); return dd->data(index).asReturnedValue(); } @@ -258,13 +247,13 @@ ReturnedValue SimpleArrayData::get(const Heap::ArrayData *d, uint index) bool SimpleArrayData::put(Object *o, uint index, const Value &value) { Heap::SimpleArrayData *dd = o->d()->arrayData.cast<Heap::SimpleArrayData>(); - Q_ASSERT(index >= dd->len || !dd->attrs || !dd->attrs[index].isAccessor()); + Q_ASSERT(index >= dd->values.size || !dd->attrs || !dd->attrs[index].isAccessor()); // ### honour attributes - dd->data(index) = value; - if (index >= dd->len) { + dd->setData(o->engine(), index, value); + if (index >= dd->values.size) { if (dd->attrs) dd->attrs[index] = Attr_Data; - dd->len = index + 1; + dd->values.size = index + 1; } return true; } @@ -272,11 +261,11 @@ bool SimpleArrayData::put(Object *o, uint index, const Value &value) bool SimpleArrayData::del(Object *o, uint index) { Heap::SimpleArrayData *dd = o->d()->arrayData.cast<Heap::SimpleArrayData>(); - if (index >= dd->len) + if (index >= dd->values.size) return true; if (!dd->attrs || dd->attrs[index].isConfigurable()) { - dd->data(index) = Primitive::emptyValue(); + dd->setData(o->engine(), index, Primitive::emptyValue()); if (dd->attrs) dd->attrs[index] = Attr_Data; return true; @@ -295,8 +284,8 @@ void SimpleArrayData::push_front(Object *o, const Value *values, uint n) { Heap::SimpleArrayData *dd = o->d()->arrayData.cast<Heap::SimpleArrayData>(); Q_ASSERT(!dd->attrs); - if (dd->len + n > dd->alloc) { - realloc(o, Heap::ArrayData::Simple, dd->len + n, false); + if (dd->values.size + n > dd->values.alloc) { + realloc(o, Heap::ArrayData::Simple, dd->values.size + n, false); Q_ASSERT(o->d()->arrayData->type == Heap::ArrayData::Simple); dd = o->d()->arrayData.cast<Heap::SimpleArrayData>(); } @@ -304,70 +293,71 @@ void SimpleArrayData::push_front(Object *o, const Value *values, uint n) dd->offset -= n; // there is enough space left in front } else { // we need to wrap around, so: - dd->offset = dd->alloc - // start at the back, but subtract: + dd->offset = dd->values.alloc - // start at the back, but subtract: (n - dd->offset); // the number of items we can put in the free space at the start of the allocated array } - dd->len += n; + dd->values.size += n; for (uint i = 0; i < n; ++i) - dd->data(i) = values[i].asReturnedValue(); + dd->setData(o->engine(), i, values[i]); } ReturnedValue SimpleArrayData::pop_front(Object *o) { Heap::SimpleArrayData *dd = o->d()->arrayData.cast<Heap::SimpleArrayData>(); Q_ASSERT(!dd->attrs); - if (!dd->len) + if (!dd->values.size) return Encode::undefined(); ReturnedValue v = dd->data(0).isEmpty() ? Encode::undefined() : dd->data(0).asReturnedValue(); - dd->offset = (dd->offset + 1) % dd->alloc; - --dd->len; + dd->offset = (dd->offset + 1) % dd->values.alloc; + --dd->values.size; return v; } uint SimpleArrayData::truncate(Object *o, uint newLen) { Heap::SimpleArrayData *dd = o->d()->arrayData.cast<Heap::SimpleArrayData>(); - if (dd->len < newLen) + if (dd->values.size < newLen) return newLen; if (!dd->attrs) { - dd->len = newLen; + dd->values.size = newLen; return newLen; } - while (dd->len > newLen) { - if (!dd->data(dd->len - 1).isEmpty() && !dd->attrs[dd->len - 1].isConfigurable()) - return dd->len; - --dd->len; + while (dd->values.size > newLen) { + if (!dd->data(dd->values.size - 1).isEmpty() && !dd->attrs[dd->values.size - 1].isConfigurable()) + return dd->values.size; + --dd->values.size; } - return dd->len; + return dd->values.size; } uint SimpleArrayData::length(const Heap::ArrayData *d) { - return d->len; + return d->values.size; } bool SimpleArrayData::putArray(Object *o, uint index, const Value *values, uint n) { Heap::SimpleArrayData *dd = o->d()->arrayData.cast<Heap::SimpleArrayData>(); - if (index + n > dd->alloc) { + if (index + n > dd->values.alloc) { reallocate(o, index + n + 1, false); dd = o->d()->arrayData.cast<Heap::SimpleArrayData>(); } - for (uint i = dd->len; i < index; ++i) - dd->data(i) = Primitive::emptyValue(); + QV4::ExecutionEngine *e = o->engine(); + for (uint i = dd->values.size; i < index; ++i) + dd->setData(e, i, Primitive::emptyValue()); for (uint i = 0; i < n; ++i) - dd->data(index + i) = values[i]; - dd->len = qMax(dd->len, index + n); + dd->setData(e, index + i, values[i]); + dd->values.size = qMax(dd->values.size, index + n); return true; } void SparseArrayData::free(Heap::ArrayData *d, uint idx) { Q_ASSERT(d && d->type == Heap::ArrayData::Sparse); - Value *v = d->arrayData + idx; + Value *v = d->values.values + idx; if (d->attrs && d->attrs[idx].isAccessor()) { // double slot, free both. Order is important, so we have a double slot for allocation again afterwards. v[1].setEmpty(Value::fromReturnedValue(d->freeList).emptyValue()); @@ -380,15 +370,6 @@ void SparseArrayData::free(Heap::ArrayData *d, uint idx) d->attrs[idx].clear(); } - -void SparseArrayData::markObjects(Heap::Base *d, ExecutionEngine *e) -{ - Heap::SparseArrayData *dd = static_cast<Heap::SparseArrayData *>(d); - uint l = dd->alloc; - for (uint i = 0; i < l; ++i) - dd->arrayData[i].mark(e); -} - Heap::ArrayData *SparseArrayData::reallocate(Object *o, uint n, bool enforceAttributes) { realloc(o, Heap::ArrayData::Sparse, n, enforceAttributes); @@ -404,32 +385,32 @@ uint SparseArrayData::allocate(Object *o, bool doubleSlot) ReturnedValue *last = &dd->freeList; while (1) { if (Value::fromReturnedValue(*last).value() == UINT_MAX) { - reallocate(o, dd->alloc + 2, true); + reallocate(o, dd->values.alloc + 2, true); dd = o->d()->arrayData.cast<Heap::SimpleArrayData>(); last = &dd->freeList; Q_ASSERT(Value::fromReturnedValue(*last).value() != UINT_MAX); } - Q_ASSERT(dd->arrayData[Value::fromReturnedValue(*last).value()].value() != Value::fromReturnedValue(*last).value()); - if (dd->arrayData[Value::fromReturnedValue(*last).value()].value() == (Value::fromReturnedValue(*last).value() + 1)) { + Q_ASSERT(dd->values[Value::fromReturnedValue(*last).value()].value() != Value::fromReturnedValue(*last).value()); + if (dd->values[Value::fromReturnedValue(*last).value()].value() == (Value::fromReturnedValue(*last).value() + 1)) { // found two slots in a row uint idx = Value::fromReturnedValue(*last).emptyValue(); Value lastV = Value::fromReturnedValue(*last); - lastV.setEmpty(dd->arrayData[lastV.emptyValue() + 1].value()); + lastV.setEmpty(dd->values[lastV.emptyValue() + 1].value()); *last = lastV.rawValue(); dd->attrs[idx] = Attr_Accessor; return idx; } - last = &dd->arrayData[Value::fromReturnedValue(*last).value()].rawValueRef(); + last = &dd->values.values[Value::fromReturnedValue(*last).value()].rawValueRef(); } } else { if (Value::fromReturnedValue(dd->freeList).value() == UINT_MAX) { - reallocate(o, dd->alloc + 1, false); + reallocate(o, dd->values.alloc + 1, false); dd = o->d()->arrayData.cast<Heap::SimpleArrayData>(); } uint idx = Value::fromReturnedValue(dd->freeList).value(); Q_ASSERT(idx != UINT_MAX); - dd->freeList = dd->arrayData[idx].asReturnedValue(); + dd->freeList = dd->values[idx].asReturnedValue(); Q_ASSERT(Value::fromReturnedValue(dd->freeList).isEmpty()); if (dd->attrs) dd->attrs[idx] = Attr_Data; @@ -443,7 +424,7 @@ ReturnedValue SparseArrayData::get(const Heap::ArrayData *d, uint index) index = s->mappedIndex(index); if (index == UINT_MAX) return Primitive::emptyValue().asReturnedValue(); - return s->arrayData[index].asReturnedValue(); + return s->values[index].asReturnedValue(); } bool SparseArrayData::put(Object *o, uint index, const Value &value) @@ -457,7 +438,7 @@ bool SparseArrayData::put(Object *o, uint index, const Value &value) if (n->value == UINT_MAX) n->value = allocate(o); s = o->d()->arrayData.cast<Heap::SparseArrayData>(); - s->arrayData[n->value] = value; + s->setArrayData(o->engine(), n->value, value); if (s->attrs) s->attrs[n->value] = Attr_Data; return true; @@ -472,7 +453,7 @@ bool SparseArrayData::del(Object *o, uint index) return true; uint pidx = n->value; - Q_ASSERT(!dd->arrayData[pidx].isEmpty()); + Q_ASSERT(!dd->values[pidx].isEmpty()); bool isAccessor = false; if (dd->attrs) { @@ -485,11 +466,11 @@ bool SparseArrayData::del(Object *o, uint index) if (isAccessor) { // free up both indices - dd->arrayData[pidx + 1].setEmpty(Value::fromReturnedValue(dd->freeList).emptyValue()); - dd->arrayData[pidx].setEmpty(pidx + 1); + dd->values.values[pidx + 1].setEmpty(Value::fromReturnedValue(dd->freeList).emptyValue()); + dd->values.values[pidx].setEmpty(pidx + 1); } else { Q_ASSERT(dd->type == Heap::ArrayData::Sparse); - dd->arrayData[pidx].setEmpty(Value::fromReturnedValue(dd->freeList).emptyValue()); + dd->values.values[pidx].setEmpty(Value::fromReturnedValue(dd->freeList).emptyValue()); } dd->freeList = Primitive::emptyValue(pidx).asReturnedValue(); @@ -518,10 +499,10 @@ void SparseArrayData::push_front(Object *o, const Value *values, uint n) { Heap::SparseArrayData *d = o->d()->arrayData.cast<Heap::SparseArrayData>(); Q_ASSERT(!d->attrs); - for (int i = n - 1; i >= 0; --i) { + for (int i = static_cast<int>(n) - 1; i >= 0; --i) { uint idx = allocate(o); d = o->d()->arrayData.cast<Heap::SparseArrayData>(); - d->arrayData[idx] = values[i]; + d->setArrayData(o->engine(), idx, values[i]); d->sparse->push_front(idx); } } @@ -533,7 +514,7 @@ ReturnedValue SparseArrayData::pop_front(Object *o) uint idx = d->sparse->pop_front(); ReturnedValue v; if (idx != UINT_MAX) { - v = d->arrayData[idx].asReturnedValue(); + v = d->values[idx].asReturnedValue(); free(o->arrayData(), idx); } else { v = Encode::undefined(); @@ -611,24 +592,24 @@ uint ArrayData::append(Object *obj, ArrayObject *otherObj, uint n) ScopedValue v(scope); for (const SparseArrayNode *it = os->sparse->begin(); it != os->sparse->end(); it = it->nextNode()) { - v = otherObj->getValue(os->arrayData[it->value], other->d()->attrs[it->value]); + v = otherObj->getValue(os->values[it->value], other->d()->attrs[it->value]); obj->arraySet(oldSize + it->key(), v); } } else { for (const SparseArrayNode *it = other->d()->sparse->begin(); it != os->sparse->end(); it = it->nextNode()) - obj->arraySet(oldSize + it->key(), os->arrayData[it->value]); + obj->arraySet(oldSize + it->key(), os->values[it->value]); } } else { Heap::SimpleArrayData *os = static_cast<Heap::SimpleArrayData *>(other->d()); uint toCopy = n; uint chunk = toCopy; - if (chunk > os->alloc - os->offset) - chunk -= os->alloc - os->offset; - obj->arrayPut(oldSize, os->arrayData + os->offset, chunk); + if (chunk > os->values.alloc - os->offset) + chunk -= os->values.alloc - os->offset; + obj->arrayPut(oldSize, os->values.data() + os->offset, chunk); toCopy -= chunk; if (toCopy) - obj->arrayPut(oldSize + chunk, os->arrayData, toCopy); + obj->arrayPut(oldSize + chunk, os->values.data(), toCopy); } return oldSize + n; @@ -638,18 +619,18 @@ void ArrayData::insert(Object *o, uint index, const Value *v, bool isAccessor) { if (!isAccessor && o->d()->arrayData->type != Heap::ArrayData::Sparse) { Heap::SimpleArrayData *d = o->d()->arrayData.cast<Heap::SimpleArrayData>(); - if (index < 0x1000 || index < d->len + (d->len >> 2)) { - if (index >= d->alloc) { + if (index < 0x1000 || index < d->values.size + (d->values.size >> 2)) { + if (index >= d->values.alloc) { o->arrayReserve(index + 1); d = o->d()->arrayData.cast<Heap::SimpleArrayData>(); } - if (index >= d->len) { + if (index >= d->values.size) { // mark possible hole in the array - for (uint i = d->len; i < index; ++i) - d->data(i) = Primitive::emptyValue(); - d->len = index + 1; + for (uint i = d->values.size; i < index; ++i) + d->setData(o->engine(), i, Primitive::emptyValue()); + d->values.size = index + 1; } - d->arrayData[d->mappedIndex(index)] = *v; + d->setData(o->engine(), index, *v); return; } } @@ -660,9 +641,9 @@ void ArrayData::insert(Object *o, uint index, const Value *v, bool isAccessor) if (n->value == UINT_MAX) n->value = SparseArrayData::allocate(o, isAccessor); s = o->d()->arrayData.cast<Heap::SparseArrayData>(); - s->arrayData[n->value] = *v; + s->setArrayData(o->engine(), n->value, *v); if (isAccessor) - s->arrayData[n->value + Object::SetterOffset] = v[Object::SetterOffset]; + s->setArrayData(o->engine(), n->value + Object::SetterOffset, v[Object::SetterOffset]); } @@ -799,7 +780,7 @@ void ArrayData::sort(ExecutionEngine *engine, Object *thisObject, const Value &c break; PropertyAttributes a = sparse->attrs() ? sparse->attrs()[n->value] : Attr_Data; - d->data(i) = thisObject->getValue(sparse->arrayData()[n->value], a); + d->setData(engine, i, Value::fromReturnedValue(thisObject->getValue(sparse->arrayData()[n->value], a))); d->attrs[i] = a.isAccessor() ? Attr_Data : a; n = n->nextNode(); @@ -809,12 +790,12 @@ void ArrayData::sort(ExecutionEngine *engine, Object *thisObject, const Value &c while (n != sparse->sparse()->end()) { if (n->value >= len) break; - d->data(i) = sparse->arrayData()[n->value]; + d->setData(engine, i, sparse->arrayData()[n->value]); n = n->nextNode(); ++i; } } - d->len = i; + d->values.size = i; if (len > i) len = i; if (n != sparse->sparse()->end()) { @@ -822,7 +803,7 @@ void ArrayData::sort(ExecutionEngine *engine, Object *thisObject, const Value &c thisObject->initSparseArray(); while (n != sparse->sparse()->end()) { PropertyAttributes a = sparse->attrs() ? sparse->attrs()[n->value] : Attr_Data; - thisObject->arraySet(n->value, reinterpret_cast<Property *>(sparse->arrayData() + n->value), a); + thisObject->arraySet(n->value, reinterpret_cast<const Property *>(sparse->arrayData() + n->value), a); n = n->nextNode(); } @@ -830,8 +811,8 @@ void ArrayData::sort(ExecutionEngine *engine, Object *thisObject, const Value &c } } else { Heap::SimpleArrayData *d = thisObject->d()->arrayData.cast<Heap::SimpleArrayData>(); - if (len > d->len) - len = d->len; + if (len > d->values.size) + len = d->values.size; // sort empty values to the end for (uint i = 0; i < len; i++) { @@ -840,8 +821,8 @@ void ArrayData::sort(ExecutionEngine *engine, Object *thisObject, const Value &c if (!d->data(len).isEmpty()) break; Q_ASSERT(!d->attrs || !d->attrs[len].isAccessor()); - d->data(i) = d->data(len); - d->data(len) = Primitive::emptyValue(); + d->setData(engine, i, d->data(len)); + d->setData(engine, len, Primitive::emptyValue()); } } @@ -852,7 +833,7 @@ void ArrayData::sort(ExecutionEngine *engine, Object *thisObject, const Value &c ArrayElementLessThan lessThan(engine, thisObject, comparefn); - Value *begin = thisObject->arrayData()->arrayData; + Value *begin = thisObject->arrayData()->values.values; sortHelper(begin, begin + len, *begin, lessThan); #ifdef CHECK_SPARSE_ARRAYS diff --git a/src/qml/jsruntime/qv4arraydata_p.h b/src/qml/jsruntime/qv4arraydata_p.h index 24b948f01e..c2c81e886b 100644 --- a/src/qml/jsruntime/qv4arraydata_p.h +++ b/src/qml/jsruntime/qv4arraydata_p.h @@ -90,27 +90,31 @@ struct ArrayVTable namespace Heap { -struct ArrayData : public Base { - enum Type { - Simple = 0, - Complex = 1, - Sparse = 2, - Custom = 3 +#define ArrayDataMembers(class, Member) \ + Member(class, NoMark, uint, type) \ + Member(class, NoMark, uint, offset) \ + Member(class, NoMark, PropertyAttributes *, attrs) \ + Member(class, NoMark, ReturnedValue, freeList) \ + Member(class, NoMark, SparseArray *, sparse) \ + Member(class, ValueArray, ValueArray, values) + +DECLARE_HEAP_OBJECT(ArrayData, Base) { + DECLARE_MARK_TABLE(ArrayData); + + enum Type { Simple = 0, Complex = 1, Sparse = 2, Custom = 3 }; + + struct Index { + Heap::ArrayData *arrayData; + uint index; + + void set(ExecutionEngine *e, Value newVal) { + arrayData->values.set(e, index, newVal); + } + const Value *operator->() const { return &arrayData->values[index]; } + const Value &operator*() const { return arrayData->values[index]; } + bool isNull() const { return !arrayData; } }; - uint alloc; - Type type; - PropertyAttributes *attrs; - union { - uint len; - ReturnedValue freeList; - }; - union { - uint offset; - SparseArray *sparse; - }; - Value arrayData[1]; - bool isSparse() const { return type == Sparse; } const ArrayVTable *vtable() const { return reinterpret_cast<const ArrayVTable *>(Base::vtable()); } @@ -118,35 +122,32 @@ struct ArrayData : public Base { inline ReturnedValue get(uint i) const { return vtable()->get(this, i); } - inline void getProperty(uint index, Property *p, PropertyAttributes *attrs); - inline void setProperty(uint index, const Property *p); - inline Property *getProperty(uint index); - inline Value *getValueOrSetter(uint index, PropertyAttributes *attrs); + inline bool getProperty(uint index, Property *p, PropertyAttributes *attrs); + inline void setProperty(ExecutionEngine *e, uint index, const Property *p); + inline Index getValueOrSetter(uint index, PropertyAttributes *attrs); inline PropertyAttributes attributes(uint i) const; bool isEmpty(uint i) const { return get(i) == Primitive::emptyValue().asReturnedValue(); } - inline ReturnedValue length() const { + inline uint length() const { return vtable()->length(this); } + void setArrayData(ExecutionEngine *e, uint index, Value newVal) { + values.set(e, index, newVal); + } + + uint mappedIndex(uint index) const; }; V4_ASSERT_IS_TRIVIAL(ArrayData) struct SimpleArrayData : public ArrayData { - uint mappedIndex(uint index) const { return (index + offset) % alloc; } - Value data(uint index) const { return arrayData[mappedIndex(index)]; } - Value &data(uint index) { return arrayData[mappedIndex(index)]; } - - Property *getProperty(uint index) { - if (index >= len) - return 0; - index = mappedIndex(index); - if (arrayData[index].isEmpty()) - return 0; - return reinterpret_cast<Property *>(arrayData + index); + uint mappedIndex(uint index) const { return (index + offset) % values.alloc; } + const Value &data(uint index) const { return values[mappedIndex(index)]; } + void setData(ExecutionEngine *e, uint index, Value newVal) { + values.set(e, mappedIndex(index), newVal); } PropertyAttributes attributes(uint i) const { @@ -168,13 +169,6 @@ struct SparseArrayData : public ArrayData { return n->value; } - Property *getProperty(uint index) { - SparseArrayNode *n = sparse->findNode(index); - if (!n) - return 0; - return reinterpret_cast<Property *>(arrayData + n->value); - } - PropertyAttributes attributes(uint i) const { if (!attrs) return Attr_Data; @@ -189,16 +183,23 @@ struct Q_QML_EXPORT ArrayData : public Managed { typedef Heap::ArrayData::Type Type; V4_MANAGED(ArrayData, Managed) + enum { + IsArrayData = true + }; - uint alloc() const { return d()->alloc; } - uint &alloc() { return d()->alloc; } - void setAlloc(uint a) { d()->alloc = a; } - Type type() const { return d()->type; } + typedef Heap::ArrayData::Index Index; + + uint alloc() const { return d()->values.alloc; } + uint &alloc() { return d()->values.alloc; } + void setAlloc(uint a) { d()->values.alloc = a; } + Type type() const { return static_cast<Type>(d()->type); } void setType(Type t) { d()->type = t; } PropertyAttributes *attrs() const { return d()->attrs; } void setAttrs(PropertyAttributes *a) { d()->attrs = a; } - const Value *arrayData() const { return &d()->arrayData[0]; } - Value *arrayData() { return &d()->arrayData[0]; } + const Value *arrayData() const { return d()->values.data(); } + void setArrayData(ExecutionEngine *e, uint index, Value newVal) { + d()->setArrayData(e, index, newVal); + } const ArrayVTable *vtable() const { return d()->vtable(); } bool isSparse() const { return type() == Heap::ArrayData::Sparse; } @@ -221,9 +222,6 @@ struct Q_QML_EXPORT ArrayData : public Managed ReturnedValue get(uint i) const { return d()->get(i); } - inline Property *getProperty(uint index) { - return d()->getProperty(index); - } static void ensureAttributes(Object *o); static void realloc(Object *o, Type newType, uint alloc, bool enforceAttributes); @@ -239,15 +237,12 @@ struct Q_QML_EXPORT SimpleArrayData : public ArrayData uint mappedIndex(uint index) const { return d()->mappedIndex(index); } Value data(uint index) const { return d()->data(index); } - Value &data(uint index) { return d()->data(index); } - uint &len() { return d()->len; } - uint len() const { return d()->len; } + uint &len() { return d()->values.size; } + uint len() const { return d()->values.size; } static Heap::ArrayData *reallocate(Object *o, uint n, bool enforceAttributes); - static void markObjects(Heap::Base *d, ExecutionEngine *e); - static ReturnedValue get(const Heap::ArrayData *d, uint index); static bool put(Object *o, uint index, const Value &value); static bool putArray(Object *o, uint index, const Value *values, uint n); @@ -274,8 +269,6 @@ struct Q_QML_EXPORT SparseArrayData : public ArrayData uint mappedIndex(uint index) const { return d()->mappedIndex(index); } - static void markObjects(Heap::Base *d, ExecutionEngine *e); - static Heap::ArrayData *reallocate(Object *o, uint n, bool enforceAttributes); static ReturnedValue get(const Heap::ArrayData *d, uint index); static bool put(Object *o, uint index, const Value &value); @@ -290,30 +283,38 @@ struct Q_QML_EXPORT SparseArrayData : public ArrayData namespace Heap { -void ArrayData::getProperty(uint index, Property *p, PropertyAttributes *attrs) +inline uint ArrayData::mappedIndex(uint index) const { - Property *pd = getProperty(index); - Q_ASSERT(pd); - *attrs = attributes(index); - p->value = pd->value; - if (attrs->isAccessor()) - p->set = pd->set; + if (isSparse()) + return static_cast<const SparseArrayData *>(this)->mappedIndex(index); + if (index >= values.size) + return UINT_MAX; + uint idx = static_cast<const SimpleArrayData *>(this)->mappedIndex(index); + return values[idx].isEmpty() ? UINT_MAX : idx; } -void ArrayData::setProperty(uint index, const Property *p) +bool ArrayData::getProperty(uint index, Property *p, PropertyAttributes *attrs) { - Property *pd = getProperty(index); - Q_ASSERT(pd); - pd->value = p->value; - if (attributes(index).isAccessor()) - pd->set = p->set; + uint mapped = mappedIndex(index); + if (mapped == UINT_MAX) { + *attrs = Attr_Invalid; + return false; + } + + *attrs = attributes(index); + p->value = *(Index{ this, mapped }); + if (attrs->isAccessor()) + p->set = *(Index{ this, mapped + 1 /*Object::SetterOffset*/ }); + return true; } -inline Property *ArrayData::getProperty(uint index) +void ArrayData::setProperty(QV4::ExecutionEngine *e, uint index, const Property *p) { - if (isSparse()) - return static_cast<SparseArrayData *>(this)->getProperty(index); - return static_cast<SimpleArrayData *>(this)->getProperty(index); + uint mapped = mappedIndex(index); + Q_ASSERT(mapped != UINT_MAX); + values.set(e, mapped, p->value); + if (attributes(index).isAccessor()) + values.set(e, mapped + 1 /*QV4::Object::SetterOffset*/, p->set); } inline PropertyAttributes ArrayData::attributes(uint i) const @@ -323,16 +324,16 @@ inline PropertyAttributes ArrayData::attributes(uint i) const return static_cast<const SimpleArrayData *>(this)->attributes(i); } -Value *ArrayData::getValueOrSetter(uint index, PropertyAttributes *attrs) +ArrayData::Index ArrayData::getValueOrSetter(uint index, PropertyAttributes *attrs) { - Property *p = getProperty(index); - if (!p) { + uint idx = mappedIndex(index); + if (idx == UINT_MAX) { *attrs = Attr_Invalid; - return 0; + return { 0, 0 }; } *attrs = attributes(index); - return attrs->isAccessor() ? &p->set : &p->value; + return { this, attrs->isAccessor() ? idx + 1 /* QV4::Object::SetterOffset*/ : idx }; } diff --git a/src/qml/jsruntime/qv4arrayobject.cpp b/src/qml/jsruntime/qv4arrayobject.cpp index 759354f4e2..a2c19e1f2d 100644 --- a/src/qml/jsruntime/qv4arrayobject.cpp +++ b/src/qml/jsruntime/qv4arrayobject.cpp @@ -690,8 +690,8 @@ void ArrayPrototype::method_indexOf(const BuiltinFunction *, Scope &scope, CallD } else { Q_ASSERT(instance->arrayType() == Heap::ArrayData::Simple || instance->arrayType() == Heap::ArrayData::Complex); Heap::SimpleArrayData *sa = instance->d()->arrayData.cast<Heap::SimpleArrayData>(); - if (len > sa->len) - len = sa->len; + if (len > sa->values.size) + len = sa->values.size; uint idx = fromIndex; while (idx < len) { value = sa->data(idx); diff --git a/src/qml/jsruntime/qv4context.cpp b/src/qml/jsruntime/qv4context.cpp index c4a0539750..b71e71b92f 100644 --- a/src/qml/jsruntime/qv4context.cpp +++ b/src/qml/jsruntime/qv4context.cpp @@ -54,58 +54,50 @@ using namespace QV4; DEFINE_MANAGED_VTABLE(ExecutionContext); +DEFINE_MANAGED_VTABLE(SimpleCallContext); DEFINE_MANAGED_VTABLE(CallContext); DEFINE_MANAGED_VTABLE(WithContext); DEFINE_MANAGED_VTABLE(CatchContext); DEFINE_MANAGED_VTABLE(GlobalContext); -/* Function *f, int argc */ -#define requiredMemoryForExecutionContect(f, argc) \ - ((sizeof(CallContext::Data) + 7) & ~7) + \ - sizeof(Value) * (f->compiledFunction->nLocals + qMax((uint)argc, f->nFormals)) + sizeof(CallData) - Heap::CallContext *ExecutionContext::newCallContext(Function *function, CallData *callData) { - Heap::CallContext *c = d()->engine->memoryManager->allocManaged<CallContext>( - requiredMemoryForExecutionContect(function, callData->argc)); + uint localsAndFormals = function->compiledFunction->nLocals + qMax(static_cast<uint>(callData->argc), function->nFormals); + size_t requiredMemory = sizeof(CallContext::Data) - sizeof(Value) + \ + sizeof(Value) * (localsAndFormals) + sizeof(CallData) - sizeof(Value); + + Heap::CallContext *c = d()->engine->memoryManager->allocManaged<CallContext>(requiredMemory); c->init(d()->engine, Heap::ExecutionContext::Type_CallContext); c->v4Function = function; c->strictMode = function->isStrict(); - c->outer = this->d(); - - c->activation = 0; + c->outer.set(d()->engine, this->d()); c->compilationUnit = function->compilationUnit; c->lookups = function->compilationUnit->runtimeLookups; c->constantTable = function->compilationUnit->constants; - c->locals = (Value *)((quintptr(c + 1) + 7) & ~7); const CompiledData::Function *compiledFunction = function->compiledFunction; - int nLocals = compiledFunction->nLocals; + uint nLocals = compiledFunction->nLocals; + c->locals.size = nLocals; + c->locals.alloc = localsAndFormals; +#if QT_POINTER_SIZE == 8 + // memory allocated from the JS heap is 0 initialized, so skip the std::fill() below + Q_ASSERT(Primitive::undefinedValue().asReturnedValue() == 0); +#else if (nLocals) - std::fill(c->locals, c->locals + nLocals, Primitive::undefinedValue()); + std::fill(c->locals.values, c->locals.values + nLocals, Primitive::undefinedValue()); +#endif - c->callData = reinterpret_cast<CallData *>(c->locals + nLocals); - ::memcpy(c->callData, callData, sizeof(CallData) + (callData->argc - 1) * sizeof(Value)); + c->callData = reinterpret_cast<CallData *>(c->locals.values + nLocals); + ::memcpy(c->callData, callData, sizeof(CallData) - sizeof(Value) + static_cast<uint>(callData->argc) * sizeof(Value)); if (callData->argc < static_cast<int>(compiledFunction->nFormals)) std::fill(c->callData->args + c->callData->argc, c->callData->args + compiledFunction->nFormals, Primitive::undefinedValue()); 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<WithContext>(d(), with); @@ -129,10 +121,10 @@ void ExecutionContext::createMutableBinding(String *name, bool deletable) switch (ctx->d()->type) { case Heap::ExecutionContext::Type_CallContext: case Heap::ExecutionContext::Type_SimpleCallContext: { - Heap::CallContext *c = static_cast<Heap::CallContext *>(ctx->d()); + Heap::SimpleCallContext *c = static_cast<Heap::SimpleCallContext *>(ctx->d()); if (!activation) { if (!c->activation) - c->activation = scope.engine->newObject(); + c->activation.set(scope.engine, scope.engine->newObject()); activation = c->activation; } break; @@ -155,7 +147,7 @@ void ExecutionContext::createMutableBinding(String *name, bool deletable) ctx = ctx->d()->outer; } - if (activation->hasProperty(name)) + if (activation->hasOwnProperty(name)) return; ScopedProperty desc(scope); PropertyAttributes attrs(Attr_Data); @@ -166,41 +158,52 @@ void ExecutionContext::createMutableBinding(String *name, bool deletable) void Heap::GlobalContext::init(ExecutionEngine *eng) { Heap::ExecutionContext::init(eng, Heap::ExecutionContext::Type_GlobalContext); - global = eng->globalObject->d(); + global.set(eng, eng->globalObject->d()); } void Heap::CatchContext::init(ExecutionContext *outerContext, String *exceptionVarName, const Value &exceptionValue) { Heap::ExecutionContext::init(outerContext->engine, Heap::ExecutionContext::Type_CatchContext); - outer = outerContext; + outer.set(engine, outerContext); strictMode = outer->strictMode; callData = outer->callData; lookups = outer->lookups; constantTable = outer->constantTable; compilationUnit = outer->compilationUnit; - this->exceptionVarName = exceptionVarName; - this->exceptionValue = exceptionValue; + this->exceptionVarName.set(engine, exceptionVarName); + this->exceptionValue.set(engine, exceptionValue); } +void Heap::WithContext::init(ExecutionContext *outerContext, Object *with) +{ + Heap::ExecutionContext::init(outerContext->engine, Heap::ExecutionContext::Type_WithContext); + outer.set(engine, outerContext); + callData = outer->callData; + lookups = outer->lookups; + constantTable = outer->constantTable; + compilationUnit = outer->compilationUnit; + + withObject.set(engine, with); +} -Identifier * const *CallContext::formals() const +Identifier * const *SimpleCallContext::formals() const { return d()->v4Function ? d()->v4Function->internalClass->nameMap.constData() : 0; } -unsigned int CallContext::formalCount() const +unsigned int SimpleCallContext::formalCount() const { return d()->v4Function ? d()->v4Function->nFormals : 0; } -Identifier * const *CallContext::variables() const +Identifier * const *SimpleCallContext::variables() const { return d()->v4Function ? d()->v4Function->internalClass->nameMap.constData() + d()->v4Function->nFormals : 0; } -unsigned int CallContext::variableCount() const +unsigned int SimpleCallContext::variableCount() const { return d()->v4Function ? d()->v4Function->compiledFunction->nLocals : 0; } @@ -210,7 +213,6 @@ unsigned int CallContext::variableCount() const bool ExecutionContext::deleteProperty(String *name) { Scope scope(this); - bool hasWith = false; ScopedContext ctx(scope, this); for (; ctx; ctx = ctx->d()->outer) { switch (ctx->d()->type) { @@ -221,7 +223,6 @@ bool ExecutionContext::deleteProperty(String *name) break; } case Heap::ExecutionContext::Type_WithContext: { - hasWith = true; ScopedObject withObject(scope, static_cast<Heap::WithContext *>(ctx->d())->withObject); if (withObject->hasProperty(name)) return withObject->deleteProperty(name); @@ -233,15 +234,16 @@ bool ExecutionContext::deleteProperty(String *name) return global->deleteProperty(name); break; } - case Heap::ExecutionContext::Type_CallContext: - case Heap::ExecutionContext::Type_SimpleCallContext: { + case Heap::ExecutionContext::Type_CallContext: { Heap::CallContext *c = static_cast<Heap::CallContext *>(ctx->d()); - if (c->v4Function && (c->v4Function->needsActivation() || hasWith)) { - uint index = c->v4Function->internalClass->find(name); - if (index < UINT_MAX) - // ### throw in strict mode? - return false; - } + uint index = c->v4Function->internalClass->find(name); + if (index < UINT_MAX) + // ### throw in strict mode? + return false; + Q_FALLTHROUGH(); + } + case Heap::ExecutionContext::Type_SimpleCallContext: { + Heap::SimpleCallContext *c = static_cast<Heap::SimpleCallContext *>(ctx->d()); ScopedObject qml(scope, c->activation); if (qml && qml->hasProperty(name)) return qml->deleteProperty(name); @@ -258,61 +260,6 @@ bool ExecutionContext::deleteProperty(String *name) return true; } -bool CallContext::needsOwnArguments() const -{ - QV4::Function *f = d()->v4Function; - return (f && f->needsActivation()) || (argc() < (f ? static_cast<int>(f->nFormals) : 0)); -} - -void ExecutionContext::markObjects(Heap::Base *m, ExecutionEngine *engine) -{ - ExecutionContext::Data *ctx = static_cast<ExecutionContext::Data *>(m); - - if (ctx->outer) - ctx->outer->mark(engine); - - switch (ctx->type) { - case Heap::ExecutionContext::Type_CatchContext: { - CatchContext::Data *c = static_cast<CatchContext::Data *>(ctx); - c->exceptionVarName->mark(engine); - c->exceptionValue.mark(engine); - break; - } - case Heap::ExecutionContext::Type_WithContext: { - WithContext::Data *w = static_cast<WithContext::Data *>(ctx); - if (w->withObject) - w->withObject->mark(engine); - break; - } - case Heap::ExecutionContext::Type_GlobalContext: { - GlobalContext::Data *g = static_cast<GlobalContext::Data *>(ctx); - g->global->mark(engine); - break; - } - case Heap::ExecutionContext::Type_SimpleCallContext: - break; - case Heap::ExecutionContext::Type_CallContext: { - QV4::Heap::CallContext *c = static_cast<Heap::CallContext *>(ctx); - Q_ASSERT(c->v4Function); - ctx->callData->thisObject.mark(engine); - for (int arg = 0; arg < qMax(ctx->callData->argc, (int)c->v4Function->nFormals); ++arg) - ctx->callData->args[arg].mark(engine); - for (unsigned local = 0, lastLocal = c->v4Function->compiledFunction->nLocals; local < lastLocal; ++local) - c->locals[local].mark(engine); - if (c->activation) - c->activation->mark(engine); - if (c->function) - c->function->mark(engine); - break; - } - case Heap::ExecutionContext::Type_QmlContext: { - QmlContext::Data *g = static_cast<QmlContext::Data *>(ctx); - g->qml->mark(engine); - break; - } - } -} - // Do a standard call with this execution context as the outer scope void ExecutionContext::call(Scope &scope, CallData *callData, Function *function, const FunctionObject *f) { @@ -320,7 +267,7 @@ void ExecutionContext::call(Scope &scope, CallData *callData, Function *function Scoped<CallContext> ctx(scope, newCallContext(function, callData)); if (f) - ctx->d()->function = f->d(); + ctx->d()->function.set(scope.engine, f->d()); scope.engine->pushContext(ctx); scope.result = Q_V4_PROFILE(scope.engine, function); @@ -336,7 +283,7 @@ void QV4::ExecutionContext::simpleCall(Scope &scope, CallData *callData, Functio ExecutionContextSaver ctxSaver(scope); - CallContext::Data *ctx = scope.engine->memoryManager->allocSimpleCallContext(scope.engine); + SimpleCallContext::Data *ctx = scope.engine->memoryManager->allocSimpleCallContext(scope.engine); ctx->strictMode = function->isStrict(); ctx->callData = callData; @@ -344,8 +291,7 @@ void QV4::ExecutionContext::simpleCall(Scope &scope, CallData *callData, Functio ctx->compilationUnit = function->compilationUnit; ctx->lookups = function->compilationUnit->runtimeLookups; ctx->constantTable = function->compilationUnit->constants; - ctx->outer = this->d(); - ctx->locals = scope.alloc(function->compiledFunction->nLocals); + ctx->outer.set(scope.engine, this->d()); for (int i = callData->argc; i < (int)function->nFormals; ++i) callData->args[i] = Encode::undefined(); @@ -371,7 +317,7 @@ void ExecutionContext::setProperty(String *name, const Value &value) case Heap::ExecutionContext::Type_CatchContext: { Heap::CatchContext *c = static_cast<Heap::CatchContext *>(ctx->d()); if (c->exceptionVarName->isEqualTo(name->d())) { - c->exceptionValue = value; + c->exceptionValue.set(scope.engine, value); return; } break; @@ -390,15 +336,16 @@ void ExecutionContext::setProperty(String *name, const Value &value) } case Heap::ExecutionContext::Type_CallContext: case Heap::ExecutionContext::Type_SimpleCallContext: { - Heap::CallContext *c = static_cast<Heap::CallContext *>(ctx->d()); + Heap::SimpleCallContext *c = static_cast<Heap::SimpleCallContext *>(ctx->d()); if (c->v4Function) { uint index = c->v4Function->internalClass->find(name); if (index < UINT_MAX) { if (index < c->v4Function->nFormals) { c->callData->args[c->v4Function->nFormals - index - 1] = value; } else { + Q_ASSERT(c->type == Heap::ExecutionContext::Type_CallContext); index -= c->v4Function->nFormals; - c->locals[index] = value; + static_cast<Heap::CallContext *>(c)->locals.set(scope.engine, index, value); } return; } @@ -439,13 +386,10 @@ ReturnedValue ExecutionContext::getProperty(String *name) if (name->equals(d()->engine->id_this())) return thisObject().asReturnedValue(); - bool hasWith = false; - bool hasCatchScope = false; ScopedContext ctx(scope, this); for (; ctx; ctx = ctx->d()->outer) { switch (ctx->d()->type) { case Heap::ExecutionContext::Type_CatchContext: { - hasCatchScope = true; Heap::CatchContext *c = static_cast<Heap::CatchContext *>(ctx->d()); if (c->exceptionVarName->isEqualTo(name->d())) return c->exceptionValue.asReturnedValue(); @@ -453,7 +397,6 @@ ReturnedValue ExecutionContext::getProperty(String *name) } case Heap::ExecutionContext::Type_WithContext: { ScopedObject w(scope, static_cast<Heap::WithContext *>(ctx->d())->withObject); - hasWith = true; bool hasProperty = false; v = w->get(name, &hasProperty); if (hasProperty) { @@ -469,17 +412,23 @@ ReturnedValue ExecutionContext::getProperty(String *name) return v->asReturnedValue(); break; } - case Heap::ExecutionContext::Type_CallContext: - case Heap::ExecutionContext::Type_SimpleCallContext: { + case Heap::ExecutionContext::Type_CallContext: { Heap::CallContext *c = static_cast<Heap::CallContext *>(ctx->d()); - if (c->v4Function && (c->v4Function->needsActivation() || hasWith || hasCatchScope)) { - uint index = c->v4Function->internalClass->find(name); - if (index < UINT_MAX) { - if (index < c->v4Function->nFormals) - return c->callData->args[c->v4Function->nFormals - index - 1].asReturnedValue(); - return c->locals[index - c->v4Function->nFormals].asReturnedValue(); - } + uint index = c->v4Function->internalClass->find(name); + if (index < UINT_MAX) { + if (index < c->v4Function->nFormals) + return c->callData->args[c->v4Function->nFormals - index - 1].asReturnedValue(); + Q_ASSERT(c->type == Heap::ExecutionContext::Type_CallContext); + return c->locals[index - c->v4Function->nFormals].asReturnedValue(); } + if (c->v4Function->isNamedExpression()) { + if (c->function && name->equals(ScopedString(scope, c->v4Function->name()))) + return c->function->asReturnedValue(); + } + Q_FALLTHROUGH(); + } + case Heap::ExecutionContext::Type_SimpleCallContext: { + Heap::SimpleCallContext *c = static_cast<Heap::SimpleCallContext *>(ctx->d()); ScopedObject activation(scope, c->activation); if (activation) { bool hasProperty = false; @@ -487,9 +436,6 @@ ReturnedValue ExecutionContext::getProperty(String *name) if (hasProperty) return v->asReturnedValue(); } - if (c->function && c->v4Function->isNamedExpression() - && name->equals(ScopedString(scope, c->v4Function->name()))) - return c->function->asReturnedValue(); break; } case Heap::ExecutionContext::Type_QmlContext: { @@ -516,13 +462,10 @@ ReturnedValue ExecutionContext::getPropertyAndBase(String *name, Value *base) if (name->equals(d()->engine->id_this())) return thisObject().asReturnedValue(); - bool hasWith = false; - bool hasCatchScope = false; ScopedContext ctx(scope, this); for (; ctx; ctx = ctx->d()->outer) { switch (ctx->d()->type) { case Heap::ExecutionContext::Type_CatchContext: { - hasCatchScope = true; Heap::CatchContext *c = static_cast<Heap::CatchContext *>(ctx->d()); if (c->exceptionVarName->isEqualTo(name->d())) return c->exceptionValue.asReturnedValue(); @@ -530,7 +473,6 @@ ReturnedValue ExecutionContext::getPropertyAndBase(String *name, Value *base) } case Heap::ExecutionContext::Type_WithContext: { ScopedObject w(scope, static_cast<Heap::WithContext *>(ctx->d())->withObject); - hasWith = true; bool hasProperty = false; v = w->get(name, &hasProperty); if (hasProperty) { @@ -547,17 +489,22 @@ ReturnedValue ExecutionContext::getPropertyAndBase(String *name, Value *base) return v->asReturnedValue(); break; } - case Heap::ExecutionContext::Type_CallContext: - case Heap::ExecutionContext::Type_SimpleCallContext: { + case Heap::ExecutionContext::Type_CallContext: { Heap::CallContext *c = static_cast<Heap::CallContext *>(ctx->d()); - if (c->v4Function && (c->v4Function->needsActivation() || hasWith || hasCatchScope)) { - uint index = c->v4Function->internalClass->find(name); - if (index < UINT_MAX) { - if (index < c->v4Function->nFormals) - return c->callData->args[c->v4Function->nFormals - index - 1].asReturnedValue(); - return c->locals[index - c->v4Function->nFormals].asReturnedValue(); - } + uint index = c->v4Function->internalClass->find(name); + if (index < UINT_MAX) { + if (index < c->v4Function->nFormals) + return c->callData->args[c->v4Function->nFormals - index - 1].asReturnedValue(); + return c->locals[index - c->v4Function->nFormals].asReturnedValue(); } + if (c->v4Function->isNamedExpression()) { + if (c->function && name->equals(ScopedString(scope, c->v4Function->name()))) + return c->function->asReturnedValue(); + } + Q_FALLTHROUGH(); + } + case Heap::ExecutionContext::Type_SimpleCallContext: { + Heap::SimpleCallContext *c = static_cast<Heap::SimpleCallContext *>(ctx->d()); ScopedObject activation(scope, c->activation); if (activation) { bool hasProperty = false; @@ -565,9 +512,6 @@ ReturnedValue ExecutionContext::getPropertyAndBase(String *name, Value *base) if (hasProperty) return v->asReturnedValue(); } - if (c->function && c->v4Function->isNamedExpression() - && name->equals(ScopedString(scope, c->v4Function->name()))) - return c->function->asReturnedValue(); break; } case Heap::ExecutionContext::Type_QmlContext: { @@ -591,7 +535,7 @@ Function *ExecutionContext::getFunction() const Scope scope(d()->engine); ScopedContext it(scope, this->d()); for (; it; it = it->d()->outer) { - if (const CallContext *callCtx = it->asCallContext()) + if (const SimpleCallContext *callCtx = it->asSimpleCallContext()) return callCtx->d()->v4Function; else if (it->asCatchContext() || it->asWithContext()) continue; // look in the parent context for a FunctionObject diff --git a/src/qml/jsruntime/qv4context_p.h b/src/qml/jsruntime/qv4context_p.h index c769dcd142..3b37ea69dc 100644 --- a/src/qml/jsruntime/qv4context_p.h +++ b/src/qml/jsruntime/qv4context_p.h @@ -68,6 +68,7 @@ struct Function; struct Function; struct Identifier; struct CallContext; +struct SimpleCallContext; struct CatchContext; struct WithContext; struct QmlContext; @@ -101,36 +102,18 @@ namespace Heap { struct QmlContext; -// ### Temporary arrangment until this code hits the dev branch and -// can use the Members macro -struct ExecutionContextData { - CallData *callData; - ExecutionEngine *engine; - ExecutionContext *outer; - Lookup *lookups; - const QV4::Value *constantTable; - CompiledData::CompilationUnitBase *compilationUnit; - // as member of non-pointer size this has to come last to preserve the ability to - // translate offsetof of it between 64-bit and 32-bit. - int lineNumber; -#if QT_POINTER_SIZE == 8 - uint padding_; -#endif -}; - -Q_STATIC_ASSERT(std::is_standard_layout<ExecutionContextData>::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, 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); -Q_STATIC_ASSERT(offsetof(ExecutionContextData, lineNumber) == offsetof(ExecutionContextData, compilationUnit) + QT_POINTER_SIZE); +#define ExecutionContextMembers(class, Member) \ + Member(class, NoMark, CallData *, callData) \ + Member(class, NoMark, ExecutionEngine *, engine) \ + Member(class, Pointer, ExecutionContext *, outer) \ + Member(class, NoMark, Lookup *, lookups) \ + Member(class, NoMark, const QV4::Value *, constantTable) \ + Member(class, NoMark, CompiledData::CompilationUnitBase *, compilationUnit) \ + Member(class, NoMark, int, lineNumber) // as member of non-pointer size this has to come last to preserve the ability to + // translate offsetof of it between 64-bit and 32-bit. -struct ExecutionContextSizeStruct : public Base, public ExecutionContextData {}; - -struct ExecutionContext : Base, public ExecutionContextData { - static Q_CONSTEXPR size_t baseOffset = sizeof(ExecutionContextSizeStruct) - sizeof(ExecutionContextData); +DECLARE_HEAP_OBJECT(ExecutionContext, Base) { + DECLARE_MARK_TABLE(ExecutionContext); enum ContextType { Type_GlobalContext = 0x1, @@ -161,19 +144,21 @@ struct ExecutionContext : Base, public ExecutionContextData { V4_ASSERT_IS_TRIVIAL(ExecutionContext) Q_STATIC_ASSERT(sizeof(ExecutionContext) == sizeof(Base) + sizeof(ExecutionContextData) + QT_POINTER_SIZE); -struct CallContextData { - Value *locals; -}; - -Q_STATIC_ASSERT(std::is_standard_layout<CallContextData>::value); -Q_STATIC_ASSERT(offsetof(CallContextData, locals) == 0); +Q_STATIC_ASSERT(std::is_standard_layout<ExecutionContextData>::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, 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); +Q_STATIC_ASSERT(offsetof(ExecutionContextData, lineNumber) == offsetof(ExecutionContextData, compilationUnit) + QT_POINTER_SIZE); -struct CallContextSizeStruct : public ExecutionContext, public CallContextData {}; +#define SimpleCallContextMembers(class, Member) \ + Member(class, Pointer, Object *, activation) \ + Member(class, NoMark, QV4::Function *, v4Function) -struct CallContext : ExecutionContext, public CallContextData { - static Q_CONSTEXPR size_t baseOffset = sizeof(CallContextSizeStruct) - sizeof(CallContextData); - static CallContext *createSimpleContext(ExecutionEngine *v4); - void freeSimpleCallContext(); +DECLARE_HEAP_OBJECT(SimpleCallContext, ExecutionContext) { + DECLARE_MARK_TABLE(SimpleCallContext); void init(ExecutionEngine *engine, ContextType t = Type_SimpleCallContext) { @@ -182,39 +167,66 @@ struct CallContext : ExecutionContext, public CallContextData { inline unsigned int formalParameterCount() const; - Pointer<FunctionObject> function; - QV4::Function *v4Function; - Pointer<Object> activation; }; -V4_ASSERT_IS_TRIVIAL(CallContext) +V4_ASSERT_IS_TRIVIAL(SimpleCallContext) +Q_STATIC_ASSERT(std::is_standard_layout<SimpleCallContextData>::value); +Q_STATIC_ASSERT(offsetof(SimpleCallContextData, activation) == 0); +Q_STATIC_ASSERT(offsetof(SimpleCallContextData, v4Function) == offsetof(SimpleCallContextData, activation) + QT_POINTER_SIZE); +Q_STATIC_ASSERT(sizeof(SimpleCallContextData) == 2 * QT_POINTER_SIZE); +Q_STATIC_ASSERT(sizeof(SimpleCallContext) == sizeof(ExecutionContext) + sizeof(SimpleCallContextData)); + +#if QT_POINTER_SIZE == 8 +#define CallContextMembers(class, Member) \ + Member(class, Pointer, FunctionObject *, function) \ + Member(class, ValueArray, ValueArray, locals) +#else +#define CallContextMembers(class, Member) \ + Member(class, Pointer, FunctionObject *, function) \ + Member(class, NoMark, void *, padding) \ + Member(class, ValueArray, ValueArray, locals) +#endif + +DECLARE_HEAP_OBJECT(CallContext, SimpleCallContext) { + DECLARE_MARK_TABLE(CallContext); + + using SimpleCallContext::formalParameterCount; +}; + +Q_STATIC_ASSERT(std::is_standard_layout<CallContextData>::value); +Q_STATIC_ASSERT(offsetof(CallContextData, function) == 0); +// IMPORTANT: we cannot do offsetof(CallContextData, locals) in the JIT as the offset does not scale with +// the pointer size. On 32-bit ARM the offset of the ValueArray is aligned to 8 bytes, on 32-bit x86 for +// example it is not. Therefore we have a padding in place and always have a distance of 8 bytes. +Q_STATIC_ASSERT(offsetof(CallContextData, locals) == offsetof(CallContextData, function) + 8); + +#define GlobalContextMembers(class, Member) \ + Member(class, Pointer, Object *, global) + +DECLARE_HEAP_OBJECT(GlobalContext, ExecutionContext) { + DECLARE_MARK_TABLE(GlobalContext); -struct GlobalContext : ExecutionContext { void init(ExecutionEngine *engine); - Pointer<Object> global; }; V4_ASSERT_IS_TRIVIAL(GlobalContext) -struct CatchContext : ExecutionContext { +#define CatchContextMembers(class, Member) \ + Member(class, Pointer, String *, exceptionVarName) \ + Member(class, HeapValue, HeapValue, exceptionValue) + +DECLARE_HEAP_OBJECT(CatchContext, ExecutionContext) { + DECLARE_MARK_TABLE(CatchContext); + void init(ExecutionContext *outerContext, String *exceptionVarName, const Value &exceptionValue); - Pointer<String> exceptionVarName; - Value exceptionValue; }; V4_ASSERT_IS_TRIVIAL(CatchContext) -struct WithContext : ExecutionContext { - void init(ExecutionContext *outerContext, Object *with) - { - Heap::ExecutionContext::init(outerContext->engine, Heap::ExecutionContext::Type_WithContext); - outer = outerContext; - callData = outer->callData; - lookups = outer->lookups; - constantTable = outer->constantTable; - compilationUnit = outer->compilationUnit; - - withObject = with; - } +#define WithContextMembers(class, Member) \ + Member(class, Pointer, Object *, withObject) + +DECLARE_HEAP_OBJECT(WithContext, ExecutionContext) { + DECLARE_MARK_TABLE(WithContext); - Pointer<Object> withObject; + void init(ExecutionContext *outerContext, Object *with); }; V4_ASSERT_IS_TRIVIAL(WithContext) @@ -242,15 +254,13 @@ struct Q_QML_EXPORT ExecutionContext : public Managed ReturnedValue getPropertyAndBase(String *name, Value *base); bool deleteProperty(String *name); - inline CallContext *asCallContext(); - inline const CallContext *asCallContext() const; + inline SimpleCallContext *asSimpleCallContext(); + inline const SimpleCallContext *asSimpleCallContext() const; inline const CatchContext *asCatchContext() const; inline const WithContext *asWithContext() const; Function *getFunction() const; - static void markObjects(Heap::Base *m, ExecutionEngine *e); - Value &thisObject() const { return d()->callData->thisObject; } @@ -268,9 +278,9 @@ struct Q_QML_EXPORT ExecutionContext : public Managed void simpleCall(Scope &scope, CallData *callData, QV4::Function *function); }; -struct Q_QML_EXPORT CallContext : public ExecutionContext +struct Q_QML_EXPORT SimpleCallContext : public ExecutionContext { - V4_MANAGED(CallContext, ExecutionContext) + V4_MANAGED(SimpleCallContext, ExecutionContext) // formals are in reverse order Identifier * const *formals() const; @@ -279,14 +289,17 @@ struct Q_QML_EXPORT CallContext : public ExecutionContext unsigned int variableCount() const; inline ReturnedValue argument(int i) const; - bool needsOwnArguments() const; - }; -inline ReturnedValue CallContext::argument(int i) const { +inline ReturnedValue SimpleCallContext::argument(int i) const { return i < argc() ? args()[i].asReturnedValue() : Primitive::undefinedValue().asReturnedValue(); } +struct Q_QML_EXPORT CallContext : public SimpleCallContext +{ + V4_MANAGED(CallContext, SimpleCallContext) +}; + struct GlobalContext : public ExecutionContext { V4_MANAGED(GlobalContext, ExecutionContext) @@ -303,14 +316,14 @@ struct WithContext : public ExecutionContext V4_MANAGED(WithContext, ExecutionContext) }; -inline CallContext *ExecutionContext::asCallContext() +inline SimpleCallContext *ExecutionContext::asSimpleCallContext() { - return d()->type >= Heap::ExecutionContext::Type_SimpleCallContext ? static_cast<CallContext *>(this) : 0; + return d()->type >= Heap::ExecutionContext::Type_SimpleCallContext ? static_cast<SimpleCallContext *>(this) : 0; } -inline const CallContext *ExecutionContext::asCallContext() const +inline const SimpleCallContext *ExecutionContext::asSimpleCallContext() const { - return d()->type >= Heap::ExecutionContext::Type_SimpleCallContext ? static_cast<const CallContext *>(this) : 0; + return d()->type >= Heap::ExecutionContext::Type_SimpleCallContext ? static_cast<const SimpleCallContext *>(this) : 0; } inline const CatchContext *ExecutionContext::asCatchContext() const diff --git a/src/qml/jsruntime/qv4dataview.cpp b/src/qml/jsruntime/qv4dataview.cpp index a810b38f24..f1405e08ee 100644 --- a/src/qml/jsruntime/qv4dataview.cpp +++ b/src/qml/jsruntime/qv4dataview.cpp @@ -73,7 +73,7 @@ void DataViewCtor::construct(const Managed *, Scope &scope, CallData *callData) } Scoped<DataView> a(scope, scope.engine->memoryManager->allocObject<DataView>()); - a->d()->buffer = buffer->d(); + a->d()->buffer.set(scope.engine, buffer->d()); a->d()->byteLength = byteLength; a->d()->byteOffset = byteOffset; scope.result = a.asReturnedValue(); @@ -84,13 +84,6 @@ void DataViewCtor::call(const Managed *that, Scope &scope, CallData *callData) construct(that, scope, callData); } - -void DataView::markObjects(Heap::Base *that, ExecutionEngine *e) -{ - DataView::Data *v = static_cast<DataView::Data *>(that); - v->buffer->mark(e); -} - void DataViewPrototype::init(ExecutionEngine *engine, Object *ctor) { Scope scope(engine); diff --git a/src/qml/jsruntime/qv4dataview_p.h b/src/qml/jsruntime/qv4dataview_p.h index 11cc0a6bd9..5c50df4655 100644 --- a/src/qml/jsruntime/qv4dataview_p.h +++ b/src/qml/jsruntime/qv4dataview_p.h @@ -63,11 +63,14 @@ struct DataViewCtor : FunctionObject { void init(QV4::ExecutionContext *scope); }; -struct DataView : Object { +#define DataViewMembers(class, Member) \ + Member(class, Pointer, ArrayBuffer *, buffer) \ + Member(class, NoMark, uint, byteLength) \ + Member(class, NoMark, uint, byteOffset) + +DECLARE_HEAP_OBJECT(DataView, Object) { + DECLARE_MARK_TABLE(DataView); void init() { Object::init(); } - Pointer<ArrayBuffer> buffer; - uint byteLength; - uint byteOffset; }; } @@ -84,8 +87,6 @@ struct DataView : Object { V4_OBJECT2(DataView, Object) V4_PROTOTYPE(dataViewPrototype) - - static void markObjects(Heap::Base *that, ExecutionEngine *e); }; struct DataViewPrototype: Object diff --git a/src/qml/jsruntime/qv4dateobject.cpp b/src/qml/jsruntime/qv4dateobject.cpp index b90c335b1c..c56d007028 100644 --- a/src/qml/jsruntime/qv4dateobject.cpp +++ b/src/qml/jsruntime/qv4dateobject.cpp @@ -340,7 +340,9 @@ static inline double TimeClip(double t) { if (! qt_is_finite(t) || fabs(t) > 8.64e15) return qt_qnan(); - return Primitive::toInteger(t); + + // +0 looks weird, but is correct. See ES6 20.3.1.15. We must not return -0. + return Primitive::toInteger(t) + 0; } static inline double ParseString(const QString &s) @@ -724,7 +726,7 @@ void DatePrototype::init(ExecutionEngine *engine, Object *ctor) Scope scope(engine); ScopedObject o(scope); ctor->defineReadonlyProperty(engine->id_prototype(), (o = this)); - ctor->defineReadonlyProperty(engine->id_length(), Primitive::fromInt32(7)); + ctor->defineReadonlyConfigurableProperty(engine->id_length(), Primitive::fromInt32(7)); LocalTZA = getLocalTZA(); ctor->defineDefaultProperty(QStringLiteral("parse"), method_parse, 1); @@ -774,8 +776,21 @@ void DatePrototype::init(ExecutionEngine *engine, Object *ctor) defineDefaultProperty(QStringLiteral("setYear"), method_setYear, 1); defineDefaultProperty(QStringLiteral("setFullYear"), method_setFullYear, 3); defineDefaultProperty(QStringLiteral("setUTCFullYear"), method_setUTCFullYear, 3); - defineDefaultProperty(QStringLiteral("toUTCString"), method_toUTCString, 0); - defineDefaultProperty(QStringLiteral("toGMTString"), method_toUTCString, 0); + + // ES6: B.2.4.3 & 20.3.4.43: + // We have to use the *same object* for toUTCString and toGMTString + { + QString toUtcString(QStringLiteral("toUTCString")); + QString toGmtString(QStringLiteral("toGMTString")); + ScopedString us(scope, engine->newIdentifier(toUtcString)); + ScopedString gs(scope, engine->newIdentifier(toGmtString)); + ExecutionContext *global = engine->rootContext(); + ScopedFunctionObject toUtcGmtStringFn(scope, BuiltinFunction::create(global, us, method_toUTCString)); + toUtcGmtStringFn->defineReadonlyConfigurableProperty(engine->id_length(), Primitive::fromInt32(0)); + defineDefaultProperty(us, toUtcGmtStringFn); + defineDefaultProperty(gs, toUtcGmtStringFn); + } + defineDefaultProperty(QStringLiteral("toISOString"), method_toISOString, 0); defineDefaultProperty(QStringLiteral("toJSON"), method_toJSON, 1); } @@ -1025,6 +1040,7 @@ void DatePrototype::method_setTime(const BuiltinFunction *, Scope &scope, CallDa THROW_TYPE_ERROR(); double t = callData->argc ? callData->args[0].toNumber() : qt_qnan(); + CHECK_EXCEPTION(); self->setDate(TimeClip(t)); scope.result = Encode(self->date()); } @@ -1036,7 +1052,9 @@ void DatePrototype::method_setMilliseconds(const BuiltinFunction *, Scope &scope THROW_TYPE_ERROR(); double t = LocalTime(self->date()); + CHECK_EXCEPTION(); double ms = callData->argc ? callData->args[0].toNumber() : qt_qnan(); + CHECK_EXCEPTION(); self->setDate(TimeClip(UTC(MakeDate(Day(t), MakeTime(HourFromTime(t), MinFromTime(t), SecFromTime(t), ms))))); scope.result = Encode(self->date()); } @@ -1048,7 +1066,9 @@ void DatePrototype::method_setUTCMilliseconds(const BuiltinFunction *, Scope &sc THROW_TYPE_ERROR(); double t = self->date(); + CHECK_EXCEPTION(); double ms = callData->argc ? callData->args[0].toNumber() : qt_qnan(); + CHECK_EXCEPTION(); self->setDate(TimeClip(MakeDate(Day(t), MakeTime(HourFromTime(t), MinFromTime(t), SecFromTime(t), ms)))); scope.result = Encode(self->date()); } @@ -1060,8 +1080,11 @@ void DatePrototype::method_setSeconds(const BuiltinFunction *, Scope &scope, Cal THROW_TYPE_ERROR(); double t = LocalTime(self->date()); + CHECK_EXCEPTION(); double sec = callData->argc ? callData->args[0].toNumber() : qt_qnan(); + CHECK_EXCEPTION(); double ms = (callData->argc < 2) ? msFromTime(t) : callData->args[1].toNumber(); + CHECK_EXCEPTION(); t = TimeClip(UTC(MakeDate(Day(t), MakeTime(HourFromTime(t), MinFromTime(t), sec, ms)))); self->setDate(t); scope.result = Encode(self->date()); @@ -1088,9 +1111,13 @@ void DatePrototype::method_setMinutes(const BuiltinFunction *, Scope &scope, Cal THROW_TYPE_ERROR(); double t = LocalTime(self->date()); + CHECK_EXCEPTION(); double min = callData->argc ? callData->args[0].toNumber() : qt_qnan(); + CHECK_EXCEPTION(); double sec = (callData->argc < 2) ? SecFromTime(t) : callData->args[1].toNumber(); + CHECK_EXCEPTION(); double ms = (callData->argc < 3) ? msFromTime(t) : callData->args[2].toNumber(); + CHECK_EXCEPTION(); t = TimeClip(UTC(MakeDate(Day(t), MakeTime(HourFromTime(t), min, sec, ms)))); self->setDate(t); scope.result = Encode(self->date()); @@ -1118,10 +1145,15 @@ void DatePrototype::method_setHours(const BuiltinFunction *, Scope &scope, CallD THROW_TYPE_ERROR(); double t = LocalTime(self->date()); + CHECK_EXCEPTION(); double hour = callData->argc ? callData->args[0].toNumber() : qt_qnan(); + CHECK_EXCEPTION(); double min = (callData->argc < 2) ? MinFromTime(t) : callData->args[1].toNumber(); + CHECK_EXCEPTION(); double sec = (callData->argc < 3) ? SecFromTime(t) : callData->args[2].toNumber(); + CHECK_EXCEPTION(); double ms = (callData->argc < 4) ? msFromTime(t) : callData->args[3].toNumber(); + CHECK_EXCEPTION(); t = TimeClip(UTC(MakeDate(Day(t), MakeTime(hour, min, sec, ms)))); self->setDate(t); scope.result = Encode(self->date()); @@ -1150,7 +1182,9 @@ void DatePrototype::method_setDate(const BuiltinFunction *, Scope &scope, CallDa THROW_TYPE_ERROR(); double t = LocalTime(self->date()); + CHECK_EXCEPTION(); double date = callData->argc ? callData->args[0].toNumber() : qt_qnan(); + CHECK_EXCEPTION(); t = TimeClip(UTC(MakeDate(MakeDay(YearFromTime(t), MonthFromTime(t), date), TimeWithinDay(t)))); self->setDate(t); scope.result = Encode(self->date()); @@ -1163,7 +1197,9 @@ void DatePrototype::method_setUTCDate(const BuiltinFunction *, Scope &scope, Cal THROW_TYPE_ERROR(); double t = self->date(); + CHECK_EXCEPTION(); double date = callData->argc ? callData->args[0].toNumber() : qt_qnan(); + CHECK_EXCEPTION(); t = TimeClip(MakeDate(MakeDay(YearFromTime(t), MonthFromTime(t), date), TimeWithinDay(t))); self->setDate(t); scope.result = Encode(self->date()); @@ -1176,8 +1212,11 @@ void DatePrototype::method_setMonth(const BuiltinFunction *, Scope &scope, CallD THROW_TYPE_ERROR(); double t = LocalTime(self->date()); + CHECK_EXCEPTION(); double month = callData->argc ? callData->args[0].toNumber() : qt_qnan(); + CHECK_EXCEPTION(); double date = (callData->argc < 2) ? DateFromTime(t) : callData->args[1].toNumber(); + CHECK_EXCEPTION(); t = TimeClip(UTC(MakeDate(MakeDay(YearFromTime(t), month, date), TimeWithinDay(t)))); self->setDate(t); scope.result = Encode(self->date()); @@ -1245,11 +1284,15 @@ void DatePrototype::method_setFullYear(const BuiltinFunction *, Scope &scope, Ca THROW_TYPE_ERROR(); double t = LocalTime(self->date()); + CHECK_EXCEPTION(); if (std::isnan(t)) t = 0; double year = callData->argc ? callData->args[0].toNumber() : qt_qnan(); + CHECK_EXCEPTION(); double month = (callData->argc < 2) ? MonthFromTime(t) : callData->args[1].toNumber(); + CHECK_EXCEPTION(); double date = (callData->argc < 3) ? DateFromTime(t) : callData->args[2].toNumber(); + CHECK_EXCEPTION(); t = TimeClip(UTC(MakeDate(MakeDay(year, month, date), TimeWithinDay(t)))); self->setDate(t); scope.result = Encode(self->date()); diff --git a/src/qml/jsruntime/qv4dateobject_p.h b/src/qml/jsruntime/qv4dateobject_p.h index a56d17f9b1..b32b2c3f66 100644 --- a/src/qml/jsruntime/qv4dateobject_p.h +++ b/src/qml/jsruntime/qv4dateobject_p.h @@ -112,7 +112,7 @@ struct DateCtor: FunctionObject static void call(const Managed *that, Scope &scope, CallData *); }; -struct DatePrototype: DateObject +struct DatePrototype: Object { void init(ExecutionEngine *engine, Object *ctor); diff --git a/src/qml/jsruntime/qv4engine.cpp b/src/qml/jsruntime/qv4engine.cpp index 83b00f0356..679cd41ce0 100644 --- a/src/qml/jsruntime/qv4engine.cpp +++ b/src/qml/jsruntime/qv4engine.cpp @@ -148,6 +148,8 @@ ExecutionEngine::ExecutionEngine(EvalISelFactory *factory) , m_profiler(0) #endif { + writeBarrierActive = true; + memoryManager = new QV4::MemoryManager(this); if (maxCallDepth == -1) { @@ -397,13 +399,14 @@ ExecutionEngine::ExecutionEngine(EvalISelFactory *factory) // // set up the global object // - rootContext()->d()->global = globalObject->d(); + rootContext()->d()->global.set(scope.engine, globalObject->d()); rootContext()->d()->callData->thisObject = globalObject; Q_ASSERT(globalObject->d()->vtable()); globalObject->defineDefaultProperty(QStringLiteral("Object"), *objectCtor()); globalObject->defineDefaultProperty(QStringLiteral("String"), *stringCtor()); - globalObject->defineDefaultProperty(QStringLiteral("Number"), *numberCtor()); + FunctionObject *numberObject = numberCtor(); + globalObject->defineDefaultProperty(QStringLiteral("Number"), *numberObject); globalObject->defineDefaultProperty(QStringLiteral("Boolean"), *booleanCtor()); globalObject->defineDefaultProperty(QStringLiteral("Array"), *arrayCtor()); globalObject->defineDefaultProperty(QStringLiteral("Function"), *functionCtor()); @@ -433,8 +436,26 @@ ExecutionEngine::ExecutionEngine(EvalISelFactory *factory) jsObjects[Eval_Function] = memoryManager->allocObject<EvalFunction>(global); globalObject->defineDefaultProperty(QStringLiteral("eval"), *evalFunction()); - globalObject->defineDefaultProperty(QStringLiteral("parseInt"), GlobalFunctions::method_parseInt, 2); - globalObject->defineDefaultProperty(QStringLiteral("parseFloat"), GlobalFunctions::method_parseFloat, 1); + // ES6: 20.1.2.12 & 20.1.2.13: + // parseInt and parseFloat must be the same FunctionObject on the global & + // Number object. + { + QString piString(QStringLiteral("parseInt")); + QString pfString(QStringLiteral("parseFloat")); + Scope scope(this); + ScopedString pi(scope, newIdentifier(piString)); + ScopedString pf(scope, newIdentifier(pfString)); + ExecutionContext *global = rootContext(); + ScopedFunctionObject parseIntFn(scope, BuiltinFunction::create(global, pi, GlobalFunctions::method_parseInt)); + ScopedFunctionObject parseFloatFn(scope, BuiltinFunction::create(global, pf, GlobalFunctions::method_parseFloat)); + parseIntFn->defineReadonlyConfigurableProperty(id_length(), Primitive::fromInt32(2)); + parseFloatFn->defineReadonlyConfigurableProperty(id_length(), Primitive::fromInt32(1)); + globalObject->defineDefaultProperty(piString, parseIntFn); + globalObject->defineDefaultProperty(pfString, parseFloatFn); + numberObject->defineDefaultProperty(piString, parseIntFn); + numberObject->defineDefaultProperty(pfString, parseFloatFn); + } + globalObject->defineDefaultProperty(QStringLiteral("isNaN"), GlobalFunctions::method_isNaN, 1); globalObject->defineDefaultProperty(QStringLiteral("isFinite"), GlobalFunctions::method_isFinite, 1); globalObject->defineDefaultProperty(QStringLiteral("decodeURI"), GlobalFunctions::method_decodeURI, 1); @@ -580,12 +601,14 @@ Heap::ArrayObject *ExecutionEngine::newArrayObject(const Value *values, int leng size_t size = sizeof(Heap::ArrayData) + (length-1)*sizeof(Value); Heap::SimpleArrayData *d = scope.engine->memoryManager->allocManaged<SimpleArrayData>(size); d->init(); - d->alloc = length; d->type = Heap::ArrayData::Simple; d->offset = 0; - d->len = length; - memcpy(&d->arrayData, values, length*sizeof(Value)); - a->d()->arrayData = d; + d->values.alloc = length; + d->values.size = length; + // this doesn't require a write barrier, things will be ok, when the new array data gets inserted into + // the parent object + memcpy(&d->values.values, values, length*sizeof(Value)); + a->d()->arrayData.set(this, d); a->setArrayLengthUnchecked(length); } return a->d(); @@ -866,7 +889,7 @@ QUrl ExecutionEngine::resolvedUrl(const QString &file) QUrl base; ExecutionContext *c = currentContext; while (c) { - CallContext *callCtx = c->asCallContext(); + SimpleCallContext *callCtx = c->asSimpleCallContext(); if (callCtx && callCtx->d()->v4Function) { base.setUrl(callCtx->d()->v4Function->sourceFile()); break; @@ -909,23 +932,25 @@ void ExecutionEngine::requireArgumentsAccessors(int n) } } -void ExecutionEngine::markObjects() +void ExecutionEngine::markObjects(bool incremental) { - identifierTable->mark(this); + if (!incremental) { + identifierTable->mark(this); - for (int i = 0; i < nArgumentsAccessors; ++i) { - const Property &pd = argumentsAccessors[i]; - if (Heap::FunctionObject *getter = pd.getter()) - getter->mark(this); - if (Heap::FunctionObject *setter = pd.setter()) - setter->mark(this); - } + for (int i = 0; i < nArgumentsAccessors; ++i) { + const Property &pd = argumentsAccessors[i]; + if (Heap::FunctionObject *getter = pd.getter()) + getter->mark(this); + if (Heap::FunctionObject *setter = pd.setter()) + setter->mark(this); + } - classPool->markObjects(this); + classPool->markObjects(this); - for (QSet<CompiledData::CompilationUnit*>::ConstIterator it = compilationUnits.constBegin(), end = compilationUnits.constEnd(); - it != end; ++it) - (*it)->markObjects(this); + for (QSet<CompiledData::CompilationUnit*>::ConstIterator it = compilationUnits.constBegin(), end = compilationUnits.constEnd(); + it != end; ++it) + (*it)->markObjects(this); + } } ReturnedValue ExecutionEngine::throwError(const Value &value) diff --git a/src/qml/jsruntime/qv4engine_p.h b/src/qml/jsruntime/qv4engine_p.h index 5182f24235..1160d69c6c 100644 --- a/src/qml/jsruntime/qv4engine_p.h +++ b/src/qml/jsruntime/qv4engine_p.h @@ -118,7 +118,7 @@ public: } Heap::Base *popForGC() { --jsStackTop; - return jsStackTop->heapObject(); + return jsStackTop->m(); } QML_NEARLY_ALWAYS_INLINE Value *jsAlloca(int nValues) { @@ -446,7 +446,7 @@ public: void requireArgumentsAccessors(int n); - void markObjects(); + void markObjects(bool incremental); void initRootContext(); @@ -546,13 +546,19 @@ inline void Heap::Base::mark(QV4::ExecutionEngine *engine) { Q_ASSERT(inUse()); - if (isMarked()) - return; + const HeapItem *h = reinterpret_cast<const HeapItem *>(this); + Chunk *c = h->chunk(); + size_t index = h - c->realBase(); + Q_ASSERT(!Chunk::testBit(c->extendsBitmap, index)); + quintptr *bitmap = c->blackBitmap + Chunk::bitmapIndex(index); + quintptr bit = Chunk::bitForIndex(index); + if (!(*bitmap & bit)) { #ifndef QT_NO_DEBUG - engine->assertObjectBelongsToEngine(*this); + engine->assertObjectBelongsToEngine(*this); #endif - setMarkBit(); - engine->pushForGC(this); + *bitmap |= bit; + engine->pushForGC(this); + } } inline void Value::mark(ExecutionEngine *e) diff --git a/src/qml/jsruntime/qv4errorobject.cpp b/src/qml/jsruntime/qv4errorobject.cpp index f290bc5136..58742a0b84 100644 --- a/src/qml/jsruntime/qv4errorobject.cpp +++ b/src/qml/jsruntime/qv4errorobject.cpp @@ -78,10 +78,10 @@ void Heap::ErrorObject::init() if (internalClass == scope.engine->errorProtoClass) return; - *propertyData(QV4::ErrorObject::Index_Stack) = scope.engine->getStackFunction(); - *propertyData(QV4::ErrorObject::Index_Stack + QV4::Object::SetterOffset) = Encode::undefined(); - *propertyData(QV4::ErrorObject::Index_FileName) = Encode::undefined(); - *propertyData(QV4::ErrorObject::Index_LineNumber) = Encode::undefined(); + setProperty(scope.engine, QV4::ErrorObject::Index_Stack, scope.engine->getStackFunction()->d()); + setProperty(scope.engine, QV4::ErrorObject::Index_Stack + QV4::Object::SetterOffset, Primitive::undefinedValue()); + setProperty(scope.engine, QV4::ErrorObject::Index_FileName, Primitive::undefinedValue()); + setProperty(scope.engine, QV4::ErrorObject::Index_LineNumber, Primitive::undefinedValue()); } void Heap::ErrorObject::init(const Value &message, ErrorType t) @@ -92,17 +92,17 @@ void Heap::ErrorObject::init(const Value &message, ErrorType t) Scope scope(internalClass->engine); Scoped<QV4::ErrorObject> e(scope, this); - *propertyData(QV4::ErrorObject::Index_Stack) = scope.engine->getStackFunction(); - *propertyData(QV4::ErrorObject::Index_Stack + QV4::Object::SetterOffset) = Encode::undefined(); + setProperty(scope.engine, QV4::ErrorObject::Index_Stack, scope.engine->getStackFunction()->d()); + setProperty(scope.engine, QV4::ErrorObject::Index_Stack + QV4::Object::SetterOffset, Primitive::undefinedValue()); e->d()->stackTrace = new StackTrace(scope.engine->stackTrace()); if (!e->d()->stackTrace->isEmpty()) { - *propertyData(QV4::ErrorObject::Index_FileName) = scope.engine->newString(e->d()->stackTrace->at(0).source); - *propertyData(QV4::ErrorObject::Index_LineNumber) = Primitive::fromInt32(e->d()->stackTrace->at(0).line); + setProperty(scope.engine, QV4::ErrorObject::Index_FileName, scope.engine->newString(e->d()->stackTrace->at(0).source)); + setProperty(scope.engine, QV4::ErrorObject::Index_LineNumber, Primitive::fromInt32(e->d()->stackTrace->at(0).line)); } if (!message.isUndefined()) - *propertyData(QV4::ErrorObject::Index_Message) = message; + setProperty(scope.engine, QV4::ErrorObject::Index_Message, message); } void Heap::ErrorObject::init(const Value &message, const QString &fileName, int line, int column, ErrorObject::ErrorType t) @@ -113,8 +113,8 @@ void Heap::ErrorObject::init(const Value &message, const QString &fileName, int Scope scope(internalClass->engine); Scoped<QV4::ErrorObject> e(scope, this); - *propertyData(QV4::ErrorObject::Index_Stack) = scope.engine->getStackFunction(); - *propertyData(QV4::ErrorObject::Index_Stack + QV4::Object::SetterOffset) = Encode::undefined(); + setProperty(scope.engine, QV4::ErrorObject::Index_Stack, scope.engine->getStackFunction()->d()); + setProperty(scope.engine, QV4::ErrorObject::Index_Stack + QV4::Object::SetterOffset, Primitive::undefinedValue()); e->d()->stackTrace = new StackTrace(scope.engine->stackTrace()); StackFrame frame; @@ -124,12 +124,12 @@ void Heap::ErrorObject::init(const Value &message, const QString &fileName, int e->d()->stackTrace->prepend(frame); if (!e->d()->stackTrace->isEmpty()) { - *propertyData(QV4::ErrorObject::Index_FileName) = scope.engine->newString(e->d()->stackTrace->at(0).source); - *propertyData(QV4::ErrorObject::Index_LineNumber) = Primitive::fromInt32(e->d()->stackTrace->at(0).line); + setProperty(scope.engine, QV4::ErrorObject::Index_FileName, scope.engine->newString(e->d()->stackTrace->at(0).source)); + setProperty(scope.engine, QV4::ErrorObject::Index_LineNumber, Primitive::fromInt32(e->d()->stackTrace->at(0).line)); } if (!message.isUndefined()) - *propertyData(QV4::ErrorObject::Index_Message) = message; + setProperty(scope.engine, QV4::ErrorObject::Index_Message, message); } const char *ErrorObject::className(Heap::ErrorObject::ErrorType t) @@ -168,19 +168,11 @@ void ErrorObject::method_get_stack(const BuiltinFunction *, Scope &scope, CallDa if (frame.line >= 0) trace += QLatin1Char(':') + QString::number(frame.line); } - This->d()->stack = scope.engine->newString(trace); + This->d()->stack.set(scope.engine, scope.engine->newString(trace)); } scope.result = This->d()->stack; } -void ErrorObject::markObjects(Heap::Base *that, ExecutionEngine *e) -{ - ErrorObject::Data *This = static_cast<ErrorObject::Data *>(that); - if (This->stack) - This->stack->mark(e); - Object::markObjects(that, e); -} - DEFINE_OBJECT_VTABLE(ErrorObject); DEFINE_OBJECT_VTABLE(SyntaxErrorObject); @@ -327,9 +319,9 @@ void ErrorPrototype::init(ExecutionEngine *engine, Object *ctor, Object *obj, He ScopedObject o(scope); ctor->defineReadonlyProperty(engine->id_prototype(), (o = obj)); ctor->defineReadonlyProperty(engine->id_length(), Primitive::fromInt32(1)); - *obj->propertyData(Index_Constructor) = ctor; - *obj->propertyData(Index_Message) = engine->id_empty(); - *obj->propertyData(Index_Name) = engine->newString(QString::fromLatin1(ErrorObject::className(t))); + obj->setProperty(Index_Constructor, ctor->d()); + obj->setProperty(Index_Message, engine->id_empty()->d()); + obj->setProperty(Index_Name, engine->newString(QString::fromLatin1(ErrorObject::className(t)))); if (t == Heap::ErrorObject::Error) obj->defineDefaultProperty(engine->id_toString(), method_toString, 0); } diff --git a/src/qml/jsruntime/qv4errorobject_p.h b/src/qml/jsruntime/qv4errorobject_p.h index 9ba9f05234..5afd9efcba 100644 --- a/src/qml/jsruntime/qv4errorobject_p.h +++ b/src/qml/jsruntime/qv4errorobject_p.h @@ -62,7 +62,12 @@ struct SyntaxErrorObject; namespace Heap { -struct ErrorObject : Object { + +#define ErrorObjectMembers(class, Member) \ + Member(class, Pointer, String *, stack) + +DECLARE_HEAP_OBJECT(ErrorObject, Object) { + DECLARE_MARK_TABLE(ErrorObject); enum ErrorType { Error, EvalError, @@ -72,6 +77,8 @@ struct ErrorObject : Object { TypeError, URIError }; + StackTrace *stackTrace; + ErrorType errorType; void init(); void init(const Value &message, ErrorType t = Error); @@ -80,10 +87,6 @@ struct ErrorObject : Object { delete stackTrace; Object::destroy(); } - - ErrorType errorType; - StackTrace *stackTrace; - Pointer<String> stack; }; struct EvalErrorObject : ErrorObject { @@ -173,7 +176,6 @@ struct ErrorObject: Object { static const char *className(Heap::ErrorObject::ErrorType t); static void method_get_stack(const BuiltinFunction *, Scope &scope, CallData *callData); - static void markObjects(Heap::Base *that, ExecutionEngine *e); }; template<> diff --git a/src/qml/jsruntime/qv4function.cpp b/src/qml/jsruntime/qv4function.cpp index 358c2d079c..ed9e3699f2 100644 --- a/src/qml/jsruntime/qv4function.cpp +++ b/src/qml/jsruntime/qv4function.cpp @@ -83,10 +83,7 @@ Function::Function(ExecutionEngine *engine, CompiledData::CompilationUnit *unit, for (quint32 i = 0; i < compiledFunction->nLocals; ++i) internalClass = internalClass->addMember(compilationUnit->runtimeStrings[localsIndices[i]]->identifier, Attr_NotConfigurable); - activationRequired = compiledFunction->nInnerFunctions > 0 || (compiledFunction->flags & (CompiledData::Function::HasDirectEval | CompiledData::Function::UsesArgumentsObject)); - - canUseSimpleCall = !needsActivation() && !(compiledFunction->flags & CompiledData::Function::HasCatchOrWith) && - !(compiledFunction->nFormals > QV4::Global::ReservedArgumentCount) && !isNamedExpression(); + canUseSimpleCall = compiledFunction->flags & CompiledData::Function::CanUseSimpleCall; } Function::~Function() @@ -118,7 +115,7 @@ void Function::updateInternalClass(ExecutionEngine *engine, const QList<QByteArr for (quint32 i = 0; i < compiledFunction->nLocals; ++i) internalClass = internalClass->addMember(compilationUnit->runtimeStrings[localsIndices[i]]->identifier, Attr_NotConfigurable); - activationRequired = true; + canUseSimpleCall = false; } QT_END_NAMESPACE diff --git a/src/qml/jsruntime/qv4function_p.h b/src/qml/jsruntime/qv4function_p.h index 54d0528c42..b11c8af94a 100644 --- a/src/qml/jsruntime/qv4function_p.h +++ b/src/qml/jsruntime/qv4function_p.h @@ -69,7 +69,6 @@ struct Q_QML_EXPORT Function { // first nArguments names in internalClass are the actual arguments InternalClass *internalClass; uint nFormals; - bool activationRequired; bool hasQmlDependencies; bool canUseSimpleCall; @@ -89,9 +88,6 @@ struct Q_QML_EXPORT Function { inline bool isStrict() const { return compiledFunction->flags & CompiledData::Function::IsStrict; } inline bool isNamedExpression() const { return compiledFunction->flags & CompiledData::Function::IsNamedExpression; } - inline bool needsActivation() const - { return activationRequired; } - inline bool canUseSimpleFunction() const { return canUseSimpleCall; } QQmlSourceLocation sourceLocation() const @@ -102,7 +98,7 @@ struct Q_QML_EXPORT Function { }; -inline unsigned int Heap::CallContext::formalParameterCount() const +inline unsigned int Heap::SimpleCallContext::formalParameterCount() const { return v4Function ? v4Function->nFormals : 0; } diff --git a/src/qml/jsruntime/qv4functionobject.cpp b/src/qml/jsruntime/qv4functionobject.cpp index b2d89220ea..5c8f03dc72 100644 --- a/src/qml/jsruntime/qv4functionobject.cpp +++ b/src/qml/jsruntime/qv4functionobject.cpp @@ -69,11 +69,13 @@ using namespace QV4; DEFINE_OBJECT_VTABLE(FunctionObject); +Q_STATIC_ASSERT((Heap::FunctionObject::markTable & Heap::Object::markTable) == Heap::Object::markTable); + void Heap::FunctionObject::init(QV4::ExecutionContext *scope, QV4::String *name, bool createProto) { Object::init(); function = nullptr; - this->scope = scope->d(); + this->scope.set(scope->engine(), scope->d()); Scope s(scope->engine()); ScopedFunctionObject f(s, this); f->init(name, createProto); @@ -84,7 +86,7 @@ void Heap::FunctionObject::init(QV4::ExecutionContext *scope, Function *function Object::init(); this->function = function; function->compilationUnit->addref(); - this->scope = scope->d(); + this->scope.set(scope->engine(), scope->d()); Scope s(scope->engine()); ScopedString name(s, function->name()); ScopedFunctionObject f(s, this); @@ -102,9 +104,9 @@ void Heap::FunctionObject::init() { Object::init(); function = nullptr; - this->scope = internalClass->engine->rootContext()->d(); + this->scope.set(internalClass->engine, internalClass->engine->rootContext()->d()); Q_ASSERT(internalClass && internalClass->find(internalClass->engine->id_prototype()) == Index_Prototype); - *propertyData(Index_Prototype) = Encode::undefined(); + setProperty(internalClass->engine, Index_Prototype, Primitive::undefinedValue()); } @@ -124,14 +126,14 @@ void FunctionObject::init(String *n, bool createProto) 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); - *proto->propertyData(Heap::FunctionObject::Index_ProtoConstructor) = this->asReturnedValue(); - *propertyData(Heap::FunctionObject::Index_Prototype) = proto.asReturnedValue(); + proto->setProperty(Heap::FunctionObject::Index_ProtoConstructor, d()); + setProperty(Heap::FunctionObject::Index_Prototype, proto); } else { - *propertyData(Heap::FunctionObject::Index_Prototype) = Encode::undefined(); + setProperty(Heap::FunctionObject::Index_Prototype, Primitive::undefinedValue()); } if (n) - defineReadonlyProperty(s.engine->id_name(), *n); + defineReadonlyConfigurableProperty(s.engine->id_name(), *n); } ReturnedValue FunctionObject::name() const @@ -149,15 +151,6 @@ void FunctionObject::call(const Managed *, Scope &scope, CallData *) scope.result = Encode::undefined(); } -void FunctionObject::markObjects(Heap::Base *that, ExecutionEngine *e) -{ - Heap::FunctionObject *o = static_cast<Heap::FunctionObject *>(that); - if (o->scope) - o->scope->mark(e); - - Object::markObjects(that, e); -} - Heap::FunctionObject *FunctionObject::createScriptFunction(ExecutionContext *scope, Function *function) { return scope->d()->engine->memoryManager->allocObject<ScriptFunction>(scope, function); @@ -258,10 +251,10 @@ void FunctionPrototype::init(ExecutionEngine *engine, Object *ctor) Scope scope(engine); ScopedObject o(scope); - ctor->defineReadonlyProperty(engine->id_length(), Primitive::fromInt32(1)); + ctor->defineReadonlyConfigurableProperty(engine->id_length(), Primitive::fromInt32(1)); ctor->defineReadonlyProperty(engine->id_prototype(), (o = this)); - defineReadonlyProperty(engine->id_length(), Primitive::fromInt32(0)); + defineReadonlyConfigurableProperty(engine->id_length(), Primitive::fromInt32(0)); defineDefaultProperty(QStringLiteral("constructor"), (o = ctor)); defineDefaultProperty(engine->id_toString(), method_toString, 0); defineDefaultProperty(QStringLiteral("apply"), method_apply, 2); @@ -309,7 +302,7 @@ void FunctionPrototype::method_apply(const BuiltinFunction *, Scope &scope, Call cData->args[i] = Primitive::undefinedValue(); } else if (arr->arrayType() == Heap::ArrayData::Simple && !arr->protoHasArray()) { auto sad = static_cast<Heap::SimpleArrayData *>(arr->arrayData()); - uint alen = sad ? sad->len : 0; + uint alen = sad ? sad->values.size : 0; if (alen > len) alen = len; for (uint i = 0; i < alen; ++i) @@ -352,8 +345,9 @@ void FunctionPrototype::method_bind(const BuiltinFunction *, Scope &scope, CallD Scoped<MemberData> boundArgs(scope, (Heap::MemberData *)0); if (callData->argc > 1) { boundArgs = MemberData::allocate(scope.engine, callData->argc - 1); - boundArgs->d()->size = callData->argc - 1; - memcpy(boundArgs->data(), callData->args + 1, (callData->argc - 1)*sizeof(Value)); + boundArgs->d()->values.size = callData->argc - 1; + for (uint i = 0; i < static_cast<uint>(callData->argc - 1); ++i) + boundArgs->set(scope.engine, i, callData->args[i + 1]); } ExecutionContext *global = scope.engine->rootContext(); @@ -420,7 +414,7 @@ void ScriptFunction::call(const Managed *that, Scope &scope, CallData *callData) void Heap::ScriptFunction::init(QV4::ExecutionContext *scope, Function *function) { FunctionObject::init(); - this->scope = scope->d(); + this->scope.set(scope->engine(), scope->d()); this->function = function; function->compilationUnit->addref(); @@ -433,7 +427,7 @@ void Heap::ScriptFunction::init(QV4::ExecutionContext *scope, Function *function ScopedString name(s, function->name()); f->init(name, true); Q_ASSERT(internalClass && internalClass->find(s.engine->id_length()) == Index_Length); - *propertyData(Index_Length) = Primitive::fromInt32(f->formalParameterCount()); + setProperty(s.engine, Index_Length, Primitive::fromInt32(f->formalParameterCount())); if (scope->d()->strictMode) { ScopedProperty pd(s); @@ -479,7 +473,7 @@ void OldBuiltinFunction::call(const Managed *that, Scope &scope, CallData *callD ExecutionContextSaver ctxSaver(scope); - CallContext::Data *ctx = v4->memoryManager->allocSimpleCallContext(v4); + SimpleCallContext::Data *ctx = v4->memoryManager->allocSimpleCallContext(v4); ctx->strictMode = f->scope()->strictMode; // ### needed? scope or parent context? ctx->callData = callData; v4->pushContext(ctx); @@ -526,7 +520,7 @@ void IndexedBuiltinFunction::call(const Managed *that, Scope &scope, CallData *c ExecutionContextSaver ctxSaver(scope); - CallContext::Data *ctx = v4->memoryManager->allocSimpleCallContext(v4); + SimpleCallContext::Data *ctx = v4->memoryManager->allocSimpleCallContext(v4); ctx->strictMode = f->scope()->strictMode; // ### needed? scope or parent context? ctx->callData = callData; v4->pushContext(ctx); @@ -543,12 +537,12 @@ DEFINE_OBJECT_VTABLE(BoundFunction); void Heap::BoundFunction::init(QV4::ExecutionContext *scope, QV4::FunctionObject *target, const Value &boundThis, QV4::MemberData *boundArgs) { + Scope s(scope); Heap::FunctionObject::init(scope, QStringLiteral("__bound function__")); - this->target = target->d(); - this->boundArgs = boundArgs ? boundArgs->d() : 0; - this->boundThis = boundThis; + this->target.set(s.engine, target->d()); + this->boundArgs.set(s.engine, boundArgs ? boundArgs->d() : 0); + this->boundThis.set(scope->engine(), boundThis); - Scope s(scope); ScopedObject f(s, this); ScopedValue l(s, target->get(s.engine->id_length())); @@ -557,7 +551,7 @@ void Heap::BoundFunction::init(QV4::ExecutionContext *scope, QV4::FunctionObject len -= boundArgs->size(); if (len < 0) len = 0; - f->defineReadonlyProperty(s.engine->id_length(), Primitive::fromInt32(len)); + f->defineReadonlyConfigurableProperty(s.engine->id_length(), Primitive::fromInt32(len)); ScopedProperty pd(s); pd->value = s.engine->thrower(); @@ -606,14 +600,3 @@ void BoundFunction::construct(const Managed *that, Scope &scope, CallData *dd) ScopedFunctionObject t(scope, f->target()); t->construct(scope, callData); } - -void BoundFunction::markObjects(Heap::Base *that, ExecutionEngine *e) -{ - BoundFunction::Data *o = static_cast<BoundFunction::Data *>(that); - if (o->target) - o->target->mark(e); - o->boundThis.mark(e); - if (o->boundArgs) - o->boundArgs->mark(e); - FunctionObject::markObjects(that, e); -} diff --git a/src/qml/jsruntime/qv4functionobject_p.h b/src/qml/jsruntime/qv4functionobject_p.h index 45d7485f1b..d375153058 100644 --- a/src/qml/jsruntime/qv4functionobject_p.h +++ b/src/qml/jsruntime/qv4functionobject_p.h @@ -65,7 +65,12 @@ struct BuiltinFunction; namespace Heap { -struct Q_QML_PRIVATE_EXPORT FunctionObject : Object { +#define FunctionObjectMembers(class, Member) \ + Member(class, Pointer, ExecutionContext *, scope) \ + Member(class, NoMark, Function *, function) + +DECLARE_HEAP_OBJECT(FunctionObject, Object) { + DECLARE_MARK_TABLE(FunctionObject); enum { Index_Prototype = 0, Index_ProtoConstructor = 0 @@ -79,12 +84,8 @@ struct Q_QML_PRIVATE_EXPORT FunctionObject : Object { unsigned int formalParameterCount() { return function ? function->nFormals : 0; } unsigned int varCount() { return function ? function->compiledFunction->nLocals : 0; } - bool needsActivation() const { return function ? function->needsActivation() : false; } const QV4::Object *protoProperty() const { return propertyData(Index_Prototype)->cast<QV4::Object>(); } - - Pointer<ExecutionContext> scope; - Function *function; }; struct FunctionCtor : FunctionObject { @@ -119,11 +120,15 @@ struct ScriptFunction : FunctionObject { void init(QV4::ExecutionContext *scope, Function *function); }; -struct BoundFunction : FunctionObject { +#define BoundFunctionMembers(class, Member) \ + Member(class, Pointer, FunctionObject *, target) \ + Member(class, HeapValue, HeapValue, boundThis) \ + Member(class, Pointer, MemberData *, boundArgs) + +DECLARE_HEAP_OBJECT(BoundFunction, FunctionObject) { + DECLARE_MARK_TABLE(BoundFunction); + void init(QV4::ExecutionContext *scope, QV4::FunctionObject *target, const Value &boundThis, QV4::MemberData *boundArgs); - Pointer<FunctionObject> target; - Value boundThis; - Pointer<MemberData> boundArgs; }; } @@ -154,14 +159,11 @@ struct Q_QML_EXPORT FunctionObject: Object { static Heap::FunctionObject *createScriptFunction(ExecutionContext *scope, Function *function); - bool needsActivation() const { return d()->needsActivation(); } bool strictMode() const { return d()->function ? d()->function->isStrict() : false; } bool isBinding() const; bool isBoundFunction() const; QQmlSourceLocation sourceLocation() const; - - static void markObjects(Heap::Base *that, ExecutionEngine *e); }; template<> @@ -259,8 +261,6 @@ struct BoundFunction: FunctionObject { static void construct(const Managed *, Scope &scope, CallData *d); static void call(const Managed *that, Scope &scope, CallData *dd); - - static void markObjects(Heap::Base *that, ExecutionEngine *e); }; } diff --git a/src/qml/jsruntime/qv4global_p.h b/src/qml/jsruntime/qv4global_p.h index c2a5e75a1f..0665295287 100644 --- a/src/qml/jsruntime/qv4global_p.h +++ b/src/qml/jsruntime/qv4global_p.h @@ -182,6 +182,7 @@ namespace Heap { struct DataView; struct TypedArray; + template <typename T, size_t> struct Pointer; } class MemoryManager; @@ -196,9 +197,12 @@ struct ScriptFunction; struct InternalClass; struct Property; struct Value; +template<size_t> struct HeapValue; +template<size_t> struct ValueArray; struct Lookup; struct ArrayData; struct VTable; +struct Function; struct BooleanObject; struct NumberObject; @@ -256,6 +260,7 @@ enum PropertyFlag { Attr_NotEnumerable = 0x4, Attr_NotConfigurable = 0x8, Attr_ReadOnly = Attr_NotWritable|Attr_NotEnumerable|Attr_NotConfigurable, + Attr_ReadOnly_ButConfigurable = Attr_NotWritable|Attr_NotEnumerable, Attr_Invalid = 0xff }; diff --git a/src/qml/jsruntime/qv4identifiertable.cpp b/src/qml/jsruntime/qv4identifiertable.cpp index 3def6defbf..d3ef238716 100644 --- a/src/qml/jsruntime/qv4identifiertable.cpp +++ b/src/qml/jsruntime/qv4identifiertable.cpp @@ -81,6 +81,7 @@ void IdentifierTable::addEntry(Heap::String *str) str->identifier = new Identifier; str->identifier->string = str->toQString(); str->identifier->hashValue = hash; + str->setMarkBit(); bool grow = (alloc <= size*2); diff --git a/src/qml/jsruntime/qv4internalclass.cpp b/src/qml/jsruntime/qv4internalclass.cpp index bac71b4537..9b18a5566e 100644 --- a/src/qml/jsruntime/qv4internalclass.cpp +++ b/src/qml/jsruntime/qv4internalclass.cpp @@ -126,26 +126,6 @@ InternalClass::InternalClass(const QV4::InternalClass &other) Q_ASSERT(extensible); } -static void insertHoleIntoPropertyData(Object *object, int idx) -{ - int icSize = object->internalClass()->size; - int from = idx; - int to = from + 1; - if (from < icSize) - memmove(object->propertyData(to), object->propertyData(from), - (icSize - from - 1) * sizeof(Value)); -} - -static void removeFromPropertyData(Object *object, int idx, bool accessor = false) -{ - int delta = (accessor ? 2 : 1); - int oldSize = object->internalClass()->size + delta; - int to = idx; - int from = to + delta; - if (from < oldSize) - memmove(object->propertyData(to), object->d()->propertyData(from), (oldSize - to)*sizeof(Value)); -} - void InternalClass::changeMember(Object *object, String *string, PropertyAttributes data, uint *index) { uint idx; @@ -157,10 +137,10 @@ void InternalClass::changeMember(Object *object, String *string, PropertyAttribu object->setInternalClass(newClass); if (newClass->size > oldClass->size) { Q_ASSERT(newClass->size == oldClass->size + 1); - insertHoleIntoPropertyData(object, idx + 1); + object->d()->memberData->values.insertData(newClass->engine, idx + 1, Primitive::emptyValue()); } else if (newClass->size < oldClass->size) { Q_ASSERT(newClass->size == oldClass->size - 1); - removeFromPropertyData(object, idx + 1); + object->d()->memberData->values.removeData(newClass->engine, idx + 1); } } @@ -318,7 +298,7 @@ void InternalClass::removeMember(Object *object, Identifier *id) Q_ASSERT(object->internalClass()->size == oldClass->size - (accessor ? 2 : 1)); // remove the entry in the property data - removeFromPropertyData(object, propIdx, accessor); + object->d()->memberData->values.removeData(oldClass->engine, propIdx, accessor ? 2 : 1); t.lookup = object->internalClass(); Q_ASSERT(t.lookup); diff --git a/src/qml/jsruntime/qv4jsonobject.cpp b/src/qml/jsruntime/qv4jsonobject.cpp index 1d571f53f3..0f021c8bd0 100644 --- a/src/qml/jsruntime/qv4jsonobject.cpp +++ b/src/qml/jsruntime/qv4jsonobject.cpp @@ -705,7 +705,7 @@ QString Stringify::Str(const QString &key, const Value &v) if (replacerFunction) { ScopedObject holder(scope, v4->newObject()); - holder->put(scope.engine, QString(), scope.result); + holder->put(scope.engine->id_empty(), scope.result); ScopedCallData callData(scope, 2); callData->args[0] = v4->newString(key); callData->args[1] = scope.result; diff --git a/src/qml/jsruntime/qv4lookup.cpp b/src/qml/jsruntime/qv4lookup.cpp index 52ed449664..11d7767e05 100644 --- a/src/qml/jsruntime/qv4lookup.cpp +++ b/src/qml/jsruntime/qv4lookup.cpp @@ -59,7 +59,7 @@ ReturnedValue Lookup::lookup(const Value &thisObject, Object *o, PropertyAttribu if (index != UINT_MAX) { level = i; *attrs = obj->internalClass->propertyData.at(index); - Value *v = obj->propertyData(index); + const Value *v = obj->propertyData(index); return !attrs->isAccessor() ? v->asReturnedValue() : Object::getValue(thisObject, *v, *attrs); } @@ -72,7 +72,7 @@ ReturnedValue Lookup::lookup(const Value &thisObject, Object *o, PropertyAttribu index = obj->internalClass->find(name); if (index != UINT_MAX) { *attrs = obj->internalClass->propertyData.at(index); - Value *v = obj->propertyData(index); + const Value *v = obj->propertyData(index); return !attrs->isAccessor() ? v->asReturnedValue() : Object::getValue(thisObject, *v, *attrs); } @@ -94,7 +94,7 @@ ReturnedValue Lookup::lookup(const Object *thisObject, PropertyAttributes *attrs if (index != UINT_MAX) { level = i; *attrs = obj->internalClass->propertyData.at(index); - Value *v = obj->propertyData(index); + const Value *v = obj->propertyData(index); return !attrs->isAccessor() ? v->asReturnedValue() : thisObject->getValue(*v, *attrs); } @@ -107,7 +107,7 @@ ReturnedValue Lookup::lookup(const Object *thisObject, PropertyAttributes *attrs index = obj->internalClass->find(name); if (index != UINT_MAX) { *attrs = obj->internalClass->propertyData.at(index); - Value *v = obj->propertyData(index); + const Value *v = obj->propertyData(index); return !attrs->isAccessor() ? v->asReturnedValue() : thisObject->getValue(*v, *attrs); } @@ -116,20 +116,20 @@ ReturnedValue Lookup::lookup(const Object *thisObject, PropertyAttributes *attrs return Primitive::emptyValue().asReturnedValue(); } -ReturnedValue Lookup::indexedGetterGeneric(Lookup *l, const Value &object, const Value &index) +ReturnedValue Lookup::indexedGetterGeneric(Lookup *l, ExecutionEngine *engine, const Value &object, const Value &index) { uint idx; if (object.isObject() && index.asArrayIndex(idx)) { l->indexedGetter = indexedGetterObjectInt; - return indexedGetterObjectInt(l, object, index); + return indexedGetterObjectInt(l, engine, object, index); } - return indexedGetterFallback(l, object, index); + return indexedGetterFallback(l, engine, object, index); } -ReturnedValue Lookup::indexedGetterFallback(Lookup *l, const Value &object, const Value &index) +ReturnedValue Lookup::indexedGetterFallback(Lookup *l, ExecutionEngine *engine, const Value &object, const Value &index) { Q_UNUSED(l); - Scope scope(l->engine); + Scope scope(engine); uint idx = 0; bool isInt = index.asArrayIndex(idx); @@ -147,7 +147,7 @@ ReturnedValue Lookup::indexedGetterFallback(Lookup *l, const Value &object, cons if (object.isNullOrUndefined()) { QString message = QStringLiteral("Cannot read property '%1' of %2").arg(index.toQStringNoThrow()).arg(object.toQStringNoThrow()); - return l->engine->throwTypeError(message); + return engine->throwTypeError(message); } o = RuntimeHelpers::convertToObject(scope.engine, object); @@ -173,7 +173,7 @@ ReturnedValue Lookup::indexedGetterFallback(Lookup *l, const Value &object, cons } -ReturnedValue Lookup::indexedGetterObjectInt(Lookup *l, const Value &object, const Value &index) +ReturnedValue Lookup::indexedGetterObjectInt(Lookup *l, ExecutionEngine *engine, const Value &object, const Value &index) { uint idx; if (index.asArrayIndex(idx)) { @@ -182,7 +182,7 @@ ReturnedValue Lookup::indexedGetterObjectInt(Lookup *l, const Value &object, con Heap::Object *o = static_cast<Heap::Object *>(b); if (o->arrayData && o->arrayData->type == Heap::ArrayData::Simple) { Heap::SimpleArrayData *s = o->arrayData.cast<Heap::SimpleArrayData>(); - if (idx < s->len) + if (idx < s->values.size) if (!s->data(idx).isEmpty()) return s->data(idx).asReturnedValue(); } @@ -190,25 +190,25 @@ ReturnedValue Lookup::indexedGetterObjectInt(Lookup *l, const Value &object, con } } - return indexedGetterFallback(l, object, index); + return indexedGetterFallback(l, engine, object, index); } -void Lookup::indexedSetterGeneric(Lookup *l, const Value &object, const Value &index, const Value &v) +void Lookup::indexedSetterGeneric(Lookup *l, ExecutionEngine *engine, const Value &object, const Value &index, const Value &v) { if (Object *o = object.objectValue()) { uint idx; if (o->d()->arrayData && o->d()->arrayData->type == Heap::ArrayData::Simple && index.asArrayIndex(idx)) { l->indexedSetter = indexedSetterObjectInt; - indexedSetterObjectInt(l, object, index, v); + indexedSetterObjectInt(l, engine, object, index, v); return; } } - indexedSetterFallback(l, object, index, v); + indexedSetterFallback(l, engine, object, index, v); } -void Lookup::indexedSetterFallback(Lookup *l, const Value &object, const Value &index, const Value &value) +void Lookup::indexedSetterFallback(Lookup *, ExecutionEngine *engine, const Value &object, const Value &index, const Value &value) { - Scope scope(l->engine); + Scope scope(engine); ScopedObject o(scope, object.toObject(scope.engine)); if (scope.engine->hasException) return; @@ -217,8 +217,8 @@ void Lookup::indexedSetterFallback(Lookup *l, const Value &object, const Value & if (index.asArrayIndex(idx)) { if (o->d()->arrayData && o->d()->arrayData->type == Heap::ArrayData::Simple) { Heap::SimpleArrayData *s = o->d()->arrayData.cast<Heap::SimpleArrayData>(); - if (idx < s->len) { - s->data(idx) = value; + if (idx < s->values.size) { + s->setData(engine, idx, value); return; } } @@ -230,7 +230,7 @@ void Lookup::indexedSetterFallback(Lookup *l, const Value &object, const Value & o->put(name, value); } -void Lookup::indexedSetterObjectInt(Lookup *l, const Value &object, const Value &index, const Value &v) +void Lookup::indexedSetterObjectInt(Lookup *l, ExecutionEngine *engine, const Value &object, const Value &index, const Value &v) { uint idx; if (index.asArrayIndex(idx)) { @@ -239,15 +239,15 @@ void Lookup::indexedSetterObjectInt(Lookup *l, const Value &object, const Value Heap::Object *o = static_cast<Heap::Object *>(b); if (o->arrayData && o->arrayData->type == Heap::ArrayData::Simple) { Heap::SimpleArrayData *s = o->arrayData.cast<Heap::SimpleArrayData>(); - if (idx < s->len) { - s->data(idx) = v; + if (idx < s->values.size) { + s->setData(engine, idx, v); return; } } } } } - indexedSetterFallback(l, object, index, v); + indexedSetterFallback(l, engine, object, index, v); } ReturnedValue Lookup::getterGeneric(Lookup *l, ExecutionEngine *engine, const Value &object) @@ -772,7 +772,7 @@ void Lookup::setter0(Lookup *l, ExecutionEngine *engine, Value &object, const Va { Object *o = object.as<Object>(); if (o && o->internalClass() == l->classList[0]) { - *o->propertyData(l->index) = value; + o->setProperty(engine, l->index, value); return; } @@ -785,7 +785,7 @@ void Lookup::setterInsert0(Lookup *l, ExecutionEngine *engine, Value &object, co if (o && o->internalClass() == l->classList[0]) { if (!o->prototype()) { o->setInternalClass(l->classList[3]); - *o->propertyData(l->index) = value; + o->setProperty(l->index, value); return; } } @@ -801,7 +801,7 @@ void Lookup::setterInsert1(Lookup *l, ExecutionEngine *engine, Value &object, co Heap::Object *p = o->prototype(); if (p && p->internalClass == l->classList[1]) { o->setInternalClass(l->classList[3]); - *o->propertyData(l->index) = value; + o->setProperty(l->index, value); return; } } @@ -819,7 +819,7 @@ void Lookup::setterInsert2(Lookup *l, ExecutionEngine *engine, Value &object, co p = p->prototype; if (p && p->internalClass == l->classList[2]) { o->setInternalClass(l->classList[3]); - *o->propertyData(l->index) = value; + o->setProperty(l->index, value); return; } } @@ -834,11 +834,11 @@ void Lookup::setter0setter0(Lookup *l, ExecutionEngine *engine, Value &object, c Object *o = object.as<Object>(); if (o) { if (o->internalClass() == l->classList[0]) { - *o->propertyData(l->index) = value; + o->setProperty(l->index, value); return; } if (o->internalClass() == l->classList[1]) { - *o->propertyData(l->index2) = value; + o->setProperty(l->index2, value); return; } } diff --git a/src/qml/jsruntime/qv4lookup_p.h b/src/qml/jsruntime/qv4lookup_p.h index 2ffb43cce9..daf3c71e27 100644 --- a/src/qml/jsruntime/qv4lookup_p.h +++ b/src/qml/jsruntime/qv4lookup_p.h @@ -67,14 +67,13 @@ namespace QV4 { struct Lookup { enum { Size = 4 }; union { - ReturnedValue (*indexedGetter)(Lookup *l, const Value &object, const Value &index); - void (*indexedSetter)(Lookup *l, const Value &object, const Value &index, const Value &v); + ReturnedValue (*indexedGetter)(Lookup *l, ExecutionEngine *engine, const Value &object, const Value &index); + void (*indexedSetter)(Lookup *l, ExecutionEngine *engine, const Value &object, const Value &index, const Value &v); ReturnedValue (*getter)(Lookup *l, ExecutionEngine *engine, const Value &object); ReturnedValue (*globalGetter)(Lookup *l, ExecutionEngine *engine); void (*setter)(Lookup *l, ExecutionEngine *engine, Value &object, const Value &v); }; union { - ExecutionEngine *engine; InternalClass *classList[Size]; struct { void *dummy0; @@ -90,13 +89,13 @@ struct Lookup { uint index; uint nameIndex; - static ReturnedValue indexedGetterGeneric(Lookup *l, const Value &object, const Value &index); - static ReturnedValue indexedGetterFallback(Lookup *l, const Value &object, const Value &index); - static ReturnedValue indexedGetterObjectInt(Lookup *l, const Value &object, const Value &index); + static ReturnedValue indexedGetterGeneric(Lookup *l, ExecutionEngine *engine, const Value &object, const Value &index); + static ReturnedValue indexedGetterFallback(Lookup *l, ExecutionEngine *engine, const Value &object, const Value &index); + static ReturnedValue indexedGetterObjectInt(Lookup *l, ExecutionEngine *engine, const Value &object, const Value &index); - static void indexedSetterGeneric(Lookup *l, const Value &object, const Value &index, const Value &v); - static void indexedSetterFallback(Lookup *l, const Value &object, const Value &index, const Value &value); - static void indexedSetterObjectInt(Lookup *l, const Value &object, const Value &index, const Value &v); + static void indexedSetterGeneric(Lookup *l, ExecutionEngine *engine, const Value &object, const Value &index, const Value &v); + static void indexedSetterFallback(Lookup *l, ExecutionEngine *engine, const Value &object, const Value &index, const Value &value); + static void indexedSetterObjectInt(Lookup *l, ExecutionEngine *engine, const Value &object, const Value &index, const Value &v); static ReturnedValue getterGeneric(Lookup *l, ExecutionEngine *engine, const Value &object); static ReturnedValue getterTwoClasses(Lookup *l, ExecutionEngine *engine, const Value &object); @@ -146,7 +145,6 @@ Q_STATIC_ASSERT(std::is_standard_layout<Lookup>::value); // across 32-bit and 64-bit (matters when cross-compiling). Q_STATIC_ASSERT(offsetof(Lookup, indexedGetter) == 0); Q_STATIC_ASSERT(offsetof(Lookup, getter) == 0); -Q_STATIC_ASSERT(offsetof(Lookup, engine) == offsetof(Lookup, getter) + QT_POINTER_SIZE); } diff --git a/src/qml/jsruntime/qv4managed.cpp b/src/qml/jsruntime/qv4managed.cpp index 3a84a83b9c..1b43fd86e8 100644 --- a/src/qml/jsruntime/qv4managed.cpp +++ b/src/qml/jsruntime/qv4managed.cpp @@ -47,6 +47,7 @@ using namespace QV4; const VTable Managed::static_vtbl = { 0, + 0, Managed::IsExecutionContext, Managed::IsString, Managed::IsObject, diff --git a/src/qml/jsruntime/qv4managed_p.h b/src/qml/jsruntime/qv4managed_p.h index 5c764e7ff0..3dc54b13da 100644 --- a/src/qml/jsruntime/qv4managed_p.h +++ b/src/qml/jsruntime/qv4managed_p.h @@ -53,6 +53,7 @@ #include "qv4global_p.h" #include "qv4value_p.h" #include <private/qv4heap_p.h> +#include <private/qv4writebarrier_p.h> QT_BEGIN_NAMESPACE @@ -91,6 +92,7 @@ inline void qYouForgotTheQ_MANAGED_Macro(T1, T2) {} dptr->_checkIsInitialized(); \ return dptr; \ } \ + static Q_CONSTEXPR quint64 markTable = QV4::Heap::DataClass::markTable; \ V4_ASSERT_IS_TRIVIAL(QV4::Heap::DataClass) #define V4_MANAGED(DataClass, superClass) \ @@ -129,6 +131,7 @@ inline void qYouForgotTheQ_MANAGED_Macro(T1, T2) {} #define DEFINE_MANAGED_VTABLE_INT(classname, parentVTable) \ { \ parentVTable, \ + markTable, \ classname::IsExecutionContext, \ classname::IsString, \ classname::IsObject, \ @@ -139,7 +142,7 @@ inline void qYouForgotTheQ_MANAGED_Macro(T1, T2) {} classname::MyType, \ #classname, \ Q_VTABLE_FUNCTION(classname, destroy), \ - markObjects, \ + Q_VTABLE_FUNCTION(classname, markObjects), \ isEqualTo \ } @@ -206,6 +209,7 @@ public: bool markBit() const { return d()->isMarked(); } static void destroy(Heap::Base *) {} + static void markObjects(Heap::Base *, ExecutionEngine *) {} Q_ALWAYS_INLINE Heap::Base *heapObject() const { return m(); diff --git a/src/qml/jsruntime/qv4memberdata.cpp b/src/qml/jsruntime/qv4memberdata.cpp index db45c77472..8f862d63e9 100644 --- a/src/qml/jsruntime/qv4memberdata.cpp +++ b/src/qml/jsruntime/qv4memberdata.cpp @@ -45,24 +45,19 @@ using namespace QV4; DEFINE_MANAGED_VTABLE(MemberData); -void MemberData::markObjects(Heap::Base *that, ExecutionEngine *e) -{ - Heap::MemberData *m = static_cast<Heap::MemberData *>(that); - for (uint i = 0; i < m->size; ++i) - m->data[i].mark(e); -} - Heap::MemberData *MemberData::allocate(ExecutionEngine *e, uint n, Heap::MemberData *old) { - Q_ASSERT(!old || old->size < n); + Q_ASSERT(!old || old->values.size < n); Q_ASSERT(n); size_t alloc = MemoryManager::align(sizeof(Heap::MemberData) + (n - 1)*sizeof(Value)); Heap::MemberData *m = e->memoryManager->allocManaged<MemberData>(alloc); if (old) - memcpy(m, old, sizeof(Heap::MemberData) + (old->size - 1)* sizeof(Value)); + // no write barrier required here + memcpy(m, old, sizeof(Heap::MemberData) + (old->values.size - 1) * sizeof(Value)); else m->init(); - m->size = static_cast<uint>((alloc - sizeof(Heap::MemberData) + sizeof(Value))/sizeof(Value)); + m->values.alloc = static_cast<uint>((alloc - sizeof(Heap::MemberData) + sizeof(Value))/sizeof(Value)); + m->values.size = m->values.alloc; return m; } diff --git a/src/qml/jsruntime/qv4memberdata_p.h b/src/qml/jsruntime/qv4memberdata_p.h index 5c89dfe8ec..fbe66757e0 100644 --- a/src/qml/jsruntime/qv4memberdata_p.h +++ b/src/qml/jsruntime/qv4memberdata_p.h @@ -59,12 +59,11 @@ namespace QV4 { namespace Heap { -struct MemberData : Base { - union { - uint size; - double _dummy; - }; - Value data[1]; +#define MemberDataMembers(class, Member) \ + Member(class, ValueArray, ValueArray, values) + +DECLARE_HEAP_OBJECT(MemberData, Base) { + DECLARE_MARK_TABLE(MemberData); }; V4_ASSERT_IS_TRIVIAL(MemberData) @@ -74,14 +73,26 @@ struct MemberData : Managed { V4_MANAGED(MemberData, Managed) - Value &operator[] (uint idx) { return d()->data[idx]; } - const Value *data() const { return d()->data; } - Value *data() { return d()->data; } - inline uint size() const { return d()->size; } + struct Index { + Heap::MemberData *memberData; + uint index; - static Heap::MemberData *allocate(QV4::ExecutionEngine *e, uint n, Heap::MemberData *old = 0); + void set(ExecutionEngine *e, Value newVal) { + memberData->values.set(e, index, newVal); + } + const Value *operator->() const { return &memberData->values[index]; } + const Value &operator*() const { return memberData->values[index]; } + bool isNull() const { return !memberData; } + }; - static void markObjects(Heap::Base *that, ExecutionEngine *e); + const Value &operator[] (uint idx) const { return d()->values[idx]; } + const Value *data() const { return d()->values.data(); } + void set(ExecutionEngine *e, uint index, Value v) { d()->values.set(e, index, v); } + void set(ExecutionEngine *e, uint index, Heap::Base *b) { d()->values.set(e, index, b); } + + inline uint size() const { return d()->values.size; } + + static Heap::MemberData *allocate(QV4::ExecutionEngine *e, uint n, Heap::MemberData *old = 0); }; } diff --git a/src/qml/jsruntime/qv4numberobject.cpp b/src/qml/jsruntime/qv4numberobject.cpp index 09644c161d..8cfa930888 100644 --- a/src/qml/jsruntime/qv4numberobject.cpp +++ b/src/qml/jsruntime/qv4numberobject.cpp @@ -102,6 +102,8 @@ void NumberPrototype::init(ExecutionEngine *engine, Object *ctor) ctor->defineReadonlyProperty(QStringLiteral("POSITIVE_INFINITY"), Primitive::fromDouble(qInf())); ctor->defineReadonlyProperty(QStringLiteral("MAX_VALUE"), Primitive::fromDouble(1.7976931348623158e+308)); ctor->defineReadonlyProperty(QStringLiteral("EPSILON"), Primitive::fromDouble(std::numeric_limits<double>::epsilon())); + ctor->defineReadonlyProperty(QStringLiteral("MAX_SAFE_INTEGER"), Primitive::fromDouble(9007199254740991)); + ctor->defineReadonlyProperty(QStringLiteral("MIN_SAFE_INTEGER"), Primitive::fromDouble(-9007199254740991)); QT_WARNING_PUSH QT_WARNING_DISABLE_INTEL(239) @@ -109,15 +111,17 @@ QT_WARNING_DISABLE_INTEL(239) QT_WARNING_POP ctor->defineDefaultProperty(QStringLiteral("isFinite"), method_isFinite, 1); + ctor->defineDefaultProperty(QStringLiteral("isInteger"), method_isInteger, 1); + ctor->defineDefaultProperty(QStringLiteral("isSafeInteger"), method_isSafeInteger, 1); ctor->defineDefaultProperty(QStringLiteral("isNaN"), method_isNaN, 1); defineDefaultProperty(QStringLiteral("constructor"), (o = ctor)); - defineDefaultProperty(engine->id_toString(), method_toString); + defineDefaultProperty(engine->id_toString(), method_toString, 1); defineDefaultProperty(QStringLiteral("toLocaleString"), method_toLocaleString); defineDefaultProperty(engine->id_valueOf(), method_valueOf); defineDefaultProperty(QStringLiteral("toFixed"), method_toFixed, 1); - defineDefaultProperty(QStringLiteral("toExponential"), method_toExponential); - defineDefaultProperty(QStringLiteral("toPrecision"), method_toPrecision); + defineDefaultProperty(QStringLiteral("toExponential"), method_toExponential, 1); + defineDefaultProperty(QStringLiteral("toPrecision"), method_toPrecision, 1); } inline ReturnedValue thisNumberValue(Scope &scope, CallData *callData) @@ -155,6 +159,52 @@ void NumberPrototype::method_isFinite(const BuiltinFunction *, Scope &scope, Cal scope.result = Encode(!std::isnan(v) && !qt_is_inf(v)); } +void NumberPrototype::method_isInteger(const BuiltinFunction *, Scope &scope, CallData *callData) +{ + if (!callData->argc) { + scope.result = Encode(false); + return; + } + + const Value &v = callData->args[0]; + if (!v.isNumber()) { + scope.result = Encode(false); + return; + } + + double dv = v.toNumber(); + if (std::isnan(dv) || qt_is_inf(dv)) { + scope.result = Encode(false); + return; + } + + double iv = v.toInteger(); + scope.result = Encode(dv == iv); +} + +void NumberPrototype::method_isSafeInteger(const BuiltinFunction *, Scope &scope, CallData *callData) +{ + if (!callData->argc) { + scope.result = Encode(false); + return; + } + + const Value &v = callData->args[0]; + if (!v.isNumber()) { + scope.result = Encode(false); + return; + } + + double dv = v.toNumber(); + if (std::isnan(dv) || qt_is_inf(dv)) { + scope.result = Encode(false); + return; + } + + double iv = v.toInteger(); + scope.result = Encode(dv == iv && std::fabs(iv) <= (2^53)-1); +} + void NumberPrototype::method_isNaN(const BuiltinFunction *, Scope &scope, CallData *callData) { if (!callData->argc) { diff --git a/src/qml/jsruntime/qv4numberobject_p.h b/src/qml/jsruntime/qv4numberobject_p.h index 364b866a16..e18267c50c 100644 --- a/src/qml/jsruntime/qv4numberobject_p.h +++ b/src/qml/jsruntime/qv4numberobject_p.h @@ -88,6 +88,8 @@ struct NumberPrototype: NumberObject void init(ExecutionEngine *engine, Object *ctor); static void method_isFinite(const BuiltinFunction *, Scope &scope, CallData *callData); + static void method_isInteger(const BuiltinFunction *, Scope &scope, CallData *callData); + static void method_isSafeInteger(const BuiltinFunction *, Scope &scope, CallData *callData); static void method_isNaN(const BuiltinFunction *, Scope &scope, CallData *callData); static void method_toString(const BuiltinFunction *, Scope &scope, CallData *callData); static void method_toLocaleString(const BuiltinFunction *, Scope &scope, CallData *callData); diff --git a/src/qml/jsruntime/qv4object.cpp b/src/qml/jsruntime/qv4object.cpp index 12157af728..d400c2ae64 100644 --- a/src/qml/jsruntime/qv4object.cpp +++ b/src/qml/jsruntime/qv4object.cpp @@ -62,8 +62,8 @@ void Object::setInternalClass(InternalClass *ic) { d()->internalClass = ic; 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); + if ((!hasMD && ic->size) || (hasMD && d()->memberData->values.size < ic->size)) + d()->memberData.set(engine(), MemberData::allocate(ic->engine, ic->size, d()->memberData)); } void Object::getProperty(uint index, Property *p, PropertyAttributes *attrs) const @@ -76,9 +76,9 @@ void Object::getProperty(uint index, Property *p, PropertyAttributes *attrs) con void Object::setProperty(uint index, const Property *p) { - *propertyData(index) = p->value; + setProperty(index, p->value); if (internalClass()->propertyData.at(index).isAccessor()) - *propertyData(index + SetterOffset) = p->set; + setProperty(index + SetterOffset, p->set); } bool Object::setPrototype(Object *proto) @@ -89,17 +89,10 @@ bool Object::setPrototype(Object *proto) return false; pp = pp->prototype; } - d()->prototype = proto ? proto->d() : 0; + d()->prototype.set(engine(), proto ? proto->d() : 0); return true; } -void Object::put(ExecutionEngine *engine, const QString &name, const Value &value) -{ - Scope scope(engine); - ScopedString n(scope, engine->newString(name)); - put(n, value); -} - ReturnedValue Object::getValue(const Value &thisObject, const Value &v, PropertyAttributes attrs) { if (!attrs.isAccessor()) @@ -115,16 +108,16 @@ ReturnedValue Object::getValue(const Value &thisObject, const Value &v, Property return scope.result.asReturnedValue(); } -void Object::putValue(uint memberIndex, const Value &value) +bool Object::putValue(uint memberIndex, const Value &value) { QV4::InternalClass *ic = internalClass(); if (ic->engine->hasException) - return; + return false; PropertyAttributes attrs = ic->propertyData[memberIndex]; if (attrs.isAccessor()) { - FunctionObject *set = propertyData(memberIndex + SetterOffset)->as<FunctionObject>(); + const FunctionObject *set = propertyData(memberIndex + SetterOffset)->as<FunctionObject>(); if (set) { Scope scope(ic->engine); ScopedFunctionObject setter(scope, set); @@ -132,7 +125,7 @@ void Object::putValue(uint memberIndex, const Value &value) callData->args[0] = value; callData->thisObject = this; setter->call(scope, callData); - return; + return !ic->engine->hasException; } goto reject; } @@ -140,12 +133,13 @@ void Object::putValue(uint memberIndex, const Value &value) if (!attrs.isWritable()) goto reject; - *propertyData(memberIndex) = value; - return; + setProperty(memberIndex, value); + return true; reject: if (engine()->current->strictMode) engine()->throwTypeError(); + return false; } void Object::defineDefaultProperty(const QString &name, const Value &value) @@ -163,7 +157,7 @@ void Object::defineDefaultProperty(const QString &name, ReturnedValue (*code)(Ca 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)); + function->defineReadonlyConfigurableProperty(e->id_length(), Primitive::fromInt32(argumentCount)); defineDefaultProperty(s, function); } @@ -174,7 +168,7 @@ void Object::defineDefaultProperty(const QString &name, void (*code)(const Built 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)); + function->defineReadonlyConfigurableProperty(e->id_length(), Primitive::fromInt32(argumentCount)); defineDefaultProperty(s, function); } @@ -184,7 +178,7 @@ void Object::defineDefaultProperty(String *name, ReturnedValue (*code)(CallConte Scope scope(e); ExecutionContext *global = e->rootContext(); ScopedFunctionObject function(scope, BuiltinFunction::create(global, name, code)); - function->defineReadonlyProperty(e->id_length(), Primitive::fromInt32(argumentCount)); + function->defineReadonlyConfigurableProperty(e->id_length(), Primitive::fromInt32(argumentCount)); defineDefaultProperty(name, function); } @@ -194,7 +188,7 @@ void Object::defineDefaultProperty(String *name, void (*code)(const BuiltinFunct Scope scope(e); ExecutionContext *global = e->rootContext(); ScopedFunctionObject function(scope, BuiltinFunction::create(global, name, code)); - function->defineReadonlyProperty(e->id_length(), Primitive::fromInt32(argumentCount)); + function->defineReadonlyConfigurableProperty(e->id_length(), Primitive::fromInt32(argumentCount)); defineDefaultProperty(name, function); } @@ -251,16 +245,17 @@ void Object::defineReadonlyProperty(String *name, const Value &value) insertMember(name, value, Attr_ReadOnly); } -void Object::markObjects(Heap::Base *that, ExecutionEngine *e) +void Object::defineReadonlyConfigurableProperty(const QString &name, const Value &value) { - Heap::Object *o = static_cast<Heap::Object *>(that); - - if (o->memberData) - o->memberData->mark(e); - if (o->arrayData) - o->arrayData->mark(e); - if (o->prototype) - o->prototype->mark(e); + QV4::ExecutionEngine *e = engine(); + Scope scope(e); + ScopedString s(scope, e->newIdentifier(name)); + defineReadonlyConfigurableProperty(s, value); +} + +void Object::defineReadonlyConfigurableProperty(String *name, const Value &value) +{ + insertMember(name, value, Attr_ReadOnly_ButConfigurable); } void Object::insertMember(String *s, const Property *p, PropertyAttributes attributes) @@ -269,10 +264,10 @@ void Object::insertMember(String *s, const Property *p, PropertyAttributes attri InternalClass::addMember(this, s, attributes, &idx); if (attributes.isAccessor()) { - *propertyData(idx + GetterOffset) = p->value; - *propertyData(idx + SetterOffset) = p->set; + setProperty(idx + GetterOffset, p->value); + setProperty(idx + SetterOffset, p->set); } else { - *propertyData(idx) = p->value; + setProperty(idx, p->value); } } @@ -301,12 +296,9 @@ void Object::getOwnProperty(String *name, PropertyAttributes *attrs, Property *p void Object::getOwnProperty(uint index, PropertyAttributes *attrs, Property *p) { - Property *pd = arrayData() ? arrayData()->getProperty(index) : 0; - if (pd) { - *attrs = arrayData()->attributes(index); - if (p) - p->copy(pd, *attrs); - return; + if (arrayData()) { + if (arrayData()->getProperty(index, p, attrs)) + return; } if (isStringObject()) { *attrs = Attr_NotConfigurable|Attr_NotWritable; @@ -321,7 +313,7 @@ void Object::getOwnProperty(uint index, PropertyAttributes *attrs, Property *p) } // Section 8.12.2 -Value *Object::getValueOrSetter(String *name, PropertyAttributes *attrs) +MemberData::Index Object::getValueOrSetter(String *name, PropertyAttributes *attrs) { Q_ASSERT(name->asArrayIndex() == UINT_MAX); @@ -330,36 +322,38 @@ Value *Object::getValueOrSetter(String *name, PropertyAttributes *attrs) uint idx = o->internalClass->find(name); if (idx < UINT_MAX) { *attrs = o->internalClass->propertyData[idx]; - return o->propertyData(attrs->isAccessor() ? idx + SetterOffset : idx); + return MemberData::Index{ o->memberData, attrs->isAccessor() ? idx + SetterOffset : idx }; } o = o->prototype; } *attrs = Attr_Invalid; - return 0; + return { 0, 0 }; } -Value *Object::getValueOrSetter(uint index, PropertyAttributes *attrs) +ArrayData::Index Object::getValueOrSetter(uint index, PropertyAttributes *attrs) { Heap::Object *o = d(); while (o) { - Property *p = o->arrayData ? o->arrayData->getProperty(index) : 0; - if (p) { - *attrs = o->arrayData->attributes(index); - return attrs->isAccessor() ? &p->set : &p->value; + if (o->arrayData) { + uint idx = o->arrayData->mappedIndex(index); + if (idx != UINT_MAX) { + *attrs = o->arrayData->attributes(index); + return { o->arrayData , attrs->isAccessor() ? idx + SetterOffset : idx }; + } } if (o->vtable()->type == Type_StringObject) { if (index < static_cast<const Heap::StringObject *>(o)->length()) { // this is an evil hack, but it works, as the method is only ever called from putIndexed, // where we don't use the returned pointer there for non writable attributes *attrs = (Attr_NotWritable|Attr_NotConfigurable); - return reinterpret_cast<Value *>(0x1); + return { reinterpret_cast<Heap::ArrayData *>(0x1), 0 }; } } o = o->prototype; } *attrs = Attr_Invalid; - return 0; + return { 0, 0 }; } bool Object::hasProperty(String *name) const @@ -441,14 +435,14 @@ ReturnedValue Object::getIndexed(const Managed *m, uint index, bool *hasProperty return static_cast<const Object *>(m)->internalGetIndexed(index, hasProperty); } -void Object::put(Managed *m, String *name, const Value &value) +bool Object::put(Managed *m, String *name, const Value &value) { - static_cast<Object *>(m)->internalPut(name, value); + return static_cast<Object *>(m)->internalPut(name, value); } -void Object::putIndexed(Managed *m, uint index, const Value &value) +bool Object::putIndexed(Managed *m, uint index, const Value &value) { - static_cast<Object *>(m)->internalPutIndexed(index, value); + return static_cast<Object *>(m)->internalPutIndexed(index, value); } PropertyAttributes Object::query(const Managed *m, String *name) @@ -532,7 +526,7 @@ void Object::setLookup(Managed *m, Lookup *l, const Value &value) l->classList[0] = o->internalClass(); l->index = idx; l->setter = Lookup::setter0; - *o->propertyData(idx) = value; + o->setProperty(idx, value); return; } @@ -587,7 +581,7 @@ void Object::advanceIterator(Managed *m, ObjectIterator *it, Value *name, uint * int k = it->arrayNode->key(); uint pidx = it->arrayNode->value; Heap::SparseArrayData *sa = o->d()->arrayData.cast<Heap::SparseArrayData>(); - Property *p = reinterpret_cast<Property *>(sa->arrayData + pidx); + const Property *p = reinterpret_cast<const Property *>(sa->values.data() + pidx); it->arrayNode = it->arrayNode->nextNode(); PropertyAttributes a = sa->attrs ? sa->attrs[pidx] : Attr_Data; if (!(it->flags & ObjectIterator::EnumerableOnly) || a.isEnumerable()) { @@ -602,9 +596,9 @@ void Object::advanceIterator(Managed *m, ObjectIterator *it, Value *name, uint * it->arrayIndex = UINT_MAX; } // dense arrays - while (it->arrayIndex < o->d()->arrayData->len) { + while (it->arrayIndex < o->d()->arrayData->values.size) { Heap::SimpleArrayData *sa = o->d()->arrayData.cast<Heap::SimpleArrayData>(); - Value &val = sa->data(it->arrayIndex); + const Value &val = sa->data(it->arrayIndex); PropertyAttributes a = o->arrayData()->attributes(it->arrayIndex); ++it->arrayIndex; if (!val.isEmpty() @@ -670,15 +664,14 @@ ReturnedValue Object::internalGet(String *name, bool *hasProperty) const ReturnedValue Object::internalGetIndexed(uint index, bool *hasProperty) const { - Property *pd = 0; PropertyAttributes attrs; Scope scope(engine()); ScopedObject o(scope, this); + ScopedProperty pd(scope); + bool exists = false; while (o) { - Property *p = o->arrayData() ? o->arrayData()->getProperty(index) : 0; - if (p) { - pd = p; - attrs = o->arrayData()->attributes(index); + if (o->arrayData() && o->arrayData()->getProperty(index, pd, &attrs)) { + exists = true; break; } if (o->isStringObject()) { @@ -693,7 +686,7 @@ ReturnedValue Object::internalGetIndexed(uint index, bool *hasProperty) const o = o->prototype(); } - if (pd) { + if (exists) { if (hasProperty) *hasProperty = true; return getValue(pd->value, attrs); @@ -706,56 +699,58 @@ ReturnedValue Object::internalGetIndexed(uint index, bool *hasProperty) const // Section 8.12.5 -void Object::internalPut(String *name, const Value &value) +bool Object::internalPut(String *name, const Value &value) { - if (internalClass()->engine->hasException) - return; + ExecutionEngine *engine = this->engine(); + if (engine->hasException) + return false; uint idx = name->asArrayIndex(); if (idx != UINT_MAX) return putIndexed(idx, value); - name->makeIdentifier(engine()); + name->makeIdentifier(engine); + MemberData::Index memberIndex{0, 0}; uint member = internalClass()->find(name); - Value *v = 0; PropertyAttributes attrs; if (member < UINT_MAX) { attrs = internalClass()->propertyData[member]; - v = propertyData(attrs.isAccessor() ? member + SetterOffset : member); + memberIndex = { d()->memberData, (attrs.isAccessor() ? member + SetterOffset : member) }; } // clause 1 - if (v) { + if (!memberIndex.isNull()) { if (attrs.isAccessor()) { - if (v->as<FunctionObject>()) + if (memberIndex->as<FunctionObject>()) goto cont; goto reject; } else if (!attrs.isWritable()) goto reject; - else if (isArrayObject() && name->equals(engine()->id_length())) { + else if (isArrayObject() && name->equals(engine->id_length())) { bool ok; uint l = value.asArrayLength(&ok); if (!ok) { - engine()->throwRangeError(value); - return; + engine->throwRangeError(value); + return false; } ok = setArrayLength(l); if (!ok) goto reject; } else { - *v = value; + memberIndex.set(engine, value); } - return; + return true; } else if (!prototype()) { if (!isExtensible()) goto reject; } else { // clause 4 - Scope scope(engine()); - if ((v = ScopedObject(scope, prototype())->getValueOrSetter(name, &attrs))) { + Scope scope(engine); + memberIndex = ScopedObject(scope, prototype())->getValueOrSetter(name, &attrs); + if (!memberIndex.isNull()) { if (attrs.isAccessor()) { - if (!v->as<FunctionObject>()) + if (!memberIndex->as<FunctionObject>()) goto reject; } else if (!isExtensible() || !attrs.isWritable()) { goto reject; @@ -768,64 +763,68 @@ void Object::internalPut(String *name, const Value &value) cont: // Clause 5 - if (v && attrs.isAccessor()) { - Q_ASSERT(v->as<FunctionObject>()); + if (!memberIndex.isNull() && attrs.isAccessor()) { + Q_ASSERT(memberIndex->as<FunctionObject>()); - Scope scope(engine()); - ScopedFunctionObject setter(scope, *v); + Scope scope(engine); + ScopedFunctionObject setter(scope, *memberIndex); ScopedCallData callData(scope, 1); callData->args[0] = value; callData->thisObject = this; setter->call(scope, callData); - return; + return !internalClass()->engine->hasException; } insertMember(name, value); - return; + return true; reject: - if (engine()->current->strictMode) { + // ### this should be removed once everything is ported to use Object::set() + if (engine->current->strictMode) { QString message = QLatin1String("Cannot assign to read-only property \"") + name->toQString() + QLatin1Char('\"'); - engine()->throwTypeError(message); + engine->throwTypeError(message); } + return false; } -void Object::internalPutIndexed(uint index, const Value &value) +bool Object::internalPutIndexed(uint index, const Value &value) { - if (internalClass()->engine->hasException) - return; + ExecutionEngine *engine = this->engine(); + if (engine->hasException) + return false; PropertyAttributes attrs; - Value *v = arrayData() ? arrayData()->getValueOrSetter(index, &attrs) : 0; + ArrayData::Index arrayIndex = arrayData() ? arrayData()->getValueOrSetter(index, &attrs) : ArrayData::Index{ 0, 0 }; - if (!v && isStringObject()) { + if (arrayIndex.isNull() && isStringObject()) { if (index < static_cast<StringObject *>(this)->length()) // not writable goto reject; } // clause 1 - if (v) { + if (!arrayIndex.isNull()) { if (attrs.isAccessor()) { - if (v->as<FunctionObject>()) + if (arrayIndex->as<FunctionObject>()) goto cont; goto reject; } else if (!attrs.isWritable()) goto reject; - else - *v = value; - return; + + arrayIndex.set(engine, value); + return true; } else if (!prototype()) { if (!isExtensible()) goto reject; } else { // clause 4 - Scope scope(engine()); - if ((v = ScopedObject(scope, prototype())->getValueOrSetter(index, &attrs))) { + Scope scope(engine); + arrayIndex = ScopedObject(scope, prototype())->getValueOrSetter(index, &attrs); + if (!arrayIndex.isNull()) { if (attrs.isAccessor()) { - if (!v->as<FunctionObject>()) + if (!arrayIndex->as<FunctionObject>()) goto reject; } else if (!isExtensible() || !attrs.isWritable()) { goto reject; @@ -838,24 +837,26 @@ void Object::internalPutIndexed(uint index, const Value &value) cont: // Clause 5 - if (v && attrs.isAccessor()) { - Q_ASSERT(v->as<FunctionObject>()); + if (!arrayIndex.isNull() && attrs.isAccessor()) { + Q_ASSERT(arrayIndex->as<FunctionObject>()); - Scope scope(engine()); - ScopedFunctionObject setter(scope, *v); + Scope scope(engine); + ScopedFunctionObject setter(scope, *arrayIndex); ScopedCallData callData(scope, 1); callData->args[0] = value; callData->thisObject = this; setter->call(scope, callData); - return; + return !internalClass()->engine->hasException; } arraySet(index, value); - return; + return true; reject: - if (engine()->current->strictMode) - engine()->throwTypeError(); + // ### this should be removed once everything is ported to use Object::setIndexed() + if (engine->current->strictMode) + engine->throwTypeError(); + return false; } // Section 8.12.7 @@ -984,8 +985,8 @@ bool Object::defineOwnProperty2(ExecutionEngine *engine, uint index, const Prope // Clause 1 if (arrayData()) { - hasProperty = arrayData()->getProperty(index); - if (!hasProperty && isStringObject()) + hasProperty = arrayData()->mappedIndex(index) != UINT_MAX; + if (!hasProperty && isStringObject()) hasProperty = (index < static_cast<StringObject *>(this)->length()); } @@ -1097,7 +1098,7 @@ bool Object::__defineOwnProperty__(ExecutionEngine *engine, uint index, String * setProperty(index, current); } else { setArrayAttributes(index, cattrs); - arrayData()->setProperty(index, current); + arrayData()->setProperty(scope.engine, index, current); } return true; reject: @@ -1133,7 +1134,8 @@ void Object::copyArrayData(Object *other) ; } else { Q_ASSERT(!arrayData() && other->arrayData()); - ArrayData::realloc(this, other->d()->arrayData->type, other->d()->arrayData->alloc, false); + ArrayData::realloc(this, static_cast<ArrayData::Type>(other->d()->arrayData->type), + other->d()->arrayData->values.alloc, false); if (other->arrayType() == Heap::ArrayData::Sparse) { Heap::ArrayData *od = other->d()->arrayData; Heap::ArrayData *dd = d()->arrayData; @@ -1141,10 +1143,11 @@ void Object::copyArrayData(Object *other) dd->freeList = od->freeList; } else { Heap::ArrayData *dd = d()->arrayData; - dd->len = other->d()->arrayData->len; + dd->values.size = other->d()->arrayData->values.size; dd->offset = other->d()->arrayData->offset; } - memcpy(d()->arrayData->arrayData, other->d()->arrayData->arrayData, other->d()->arrayData->alloc*sizeof(Value)); + // ### need a write barrier + memcpy(d()->arrayData->values.values, other->d()->arrayData->values.values, other->d()->arrayData->values.alloc*sizeof(Value)); } setArrayLengthUnchecked(other->getLength()); } diff --git a/src/qml/jsruntime/qv4object_p.h b/src/qml/jsruntime/qv4object_p.h index 6a543ae1a8..df9d68525d 100644 --- a/src/qml/jsruntime/qv4object_p.h +++ b/src/qml/jsruntime/qv4object_p.h @@ -67,19 +67,24 @@ struct BuiltinFunction; namespace Heap { -struct Object : Base { +#define ObjectMembers(class, Member) \ + Member(class, NoMark, InternalClass *, internalClass) \ + Member(class, Pointer, Object *, prototype) \ + Member(class, Pointer, MemberData *, memberData) \ + Member(class, Pointer, ArrayData *, arrayData) + +DECLARE_HEAP_OBJECT(Object, Base) { + DECLARE_MARK_TABLE(Object); 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; } - - InternalClass *internalClass; - Pointer<Object> prototype; - Pointer<MemberData> memberData; - Pointer<ArrayData> arrayData; + const Value *propertyData(uint index) const { return memberData->values.data() + index; } + void setProperty(ExecutionEngine *e, uint index, Value v) const { memberData->values.set(e, index, v); } + void setProperty(ExecutionEngine *e, uint index, Heap::Base *b) const { memberData->values.set(e, index, b); } }; +Q_STATIC_ASSERT(Object::markTable == ((2 << 4) | (2 << 6) | (2 << 8))); + } #define V4_OBJECT(superClass) \ @@ -114,7 +119,8 @@ struct Object : Base { dptr->_checkIsInitialized(); \ return dptr; \ } \ - V4_ASSERT_IS_TRIVIAL(QV4::Heap::DataClass); + V4_ASSERT_IS_TRIVIAL(QV4::Heap::DataClass); \ + static Q_CONSTEXPR quint64 markTable = QV4::Heap::DataClass::markTable; #define V4_INTERNALCLASS(c) \ static QV4::InternalClass *defaultInternalClass(QV4::ExecutionEngine *e) \ @@ -130,8 +136,8 @@ struct ObjectVTable void (*construct)(const Managed *, Scope &scope, CallData *data); ReturnedValue (*get)(const Managed *, String *name, bool *hasProperty); ReturnedValue (*getIndexed)(const Managed *, uint index, bool *hasProperty); - void (*put)(Managed *, String *name, const Value &value); - void (*putIndexed)(Managed *, uint index, const Value &value); + bool (*put)(Managed *, String *name, const Value &value); + bool (*putIndexed)(Managed *, uint index, const Value &value); PropertyAttributes (*query)(const Managed *, String *name); PropertyAttributes (*queryIndexed)(const Managed *, uint index); bool (*deleteProperty)(Managed *m, String *name); @@ -190,13 +196,16 @@ struct Q_QML_EXPORT Object: Managed { void setInternalClass(InternalClass *ic); const Value *propertyData(uint index) const { return d()->propertyData(index); } - Value *propertyData(uint index) { return d()->propertyData(index); } Heap::ArrayData *arrayData() const { return d()->arrayData; } - void setArrayData(ArrayData *a) { d()->arrayData = a->d(); } + void setArrayData(ArrayData *a) { d()->arrayData.set(engine(), a->d()); } void getProperty(uint index, Property *p, PropertyAttributes *attrs) const; void setProperty(uint index, const Property *p); + void setProperty(uint index, Value v) const { d()->setProperty(engine(), index, v); } + void setProperty(uint index, Heap::Base *b) const { d()->setProperty(engine(), index, b); } + void setProperty(ExecutionEngine *engine, uint index, Value v) const { d()->setProperty(engine, index, v); } + void setProperty(ExecutionEngine *engine, uint index, Heap::Base *b) const { d()->setProperty(engine, index, b); } const ObjectVTable *vtable() const { return reinterpret_cast<const ObjectVTable *>(d()->vtable()); } Heap::Object *prototype() const { return d()->prototype; } @@ -205,8 +214,8 @@ struct Q_QML_EXPORT Object: Managed { void getOwnProperty(String *name, PropertyAttributes *attrs, Property *p = 0); void getOwnProperty(uint index, PropertyAttributes *attrs, Property *p = 0); - Value *getValueOrSetter(String *name, PropertyAttributes *attrs); - Value *getValueOrSetter(uint index, PropertyAttributes *attrs); + MemberData::Index getValueOrSetter(String *name, PropertyAttributes *attrs); + ArrayData::Index getValueOrSetter(uint index, PropertyAttributes *attrs); bool hasProperty(String *name) const; bool hasProperty(uint index) const; @@ -223,8 +232,6 @@ struct Q_QML_EXPORT Object: Managed { // // helpers // - void put(ExecutionEngine *engine, const QString &name, const Value &value); - static ReturnedValue getValue(const Value &thisObject, const Value &v, PropertyAttributes attrs); ReturnedValue getValue(const Value &v, PropertyAttributes attrs) const { Scope scope(this->engine()); @@ -232,7 +239,7 @@ struct Q_QML_EXPORT Object: Managed { return getValue(t, v, attrs); } - void putValue(uint memberIndex, const Value &value); + bool putValue(uint memberIndex, const Value &value); /* The spec default: Writable: true, Enumerable: false, Configurable: true */ void defineDefaultProperty(String *name, const Value &value) { @@ -253,6 +260,10 @@ struct Q_QML_EXPORT Object: Managed { void defineReadonlyProperty(const QString &name, const Value &value); void defineReadonlyProperty(String *name, const Value &value); + /* Fixed: Writable: false, Enumerable: false, Configurable: true */ + void defineReadonlyConfigurableProperty(const QString &name, const Value &value); + void defineReadonlyConfigurableProperty(String *name, const Value &value); + void insertMember(String *s, const Value &v, PropertyAttributes attributes = Attr_Data) { Scope scope(engine()); ScopedProperty p(scope); @@ -294,7 +305,7 @@ public: void push_back(const Value &v); ArrayData::Type arrayType() const { - return arrayData() ? d()->arrayData->type : Heap::ArrayData::Simple; + return arrayData() ? static_cast<ArrayData::Type>(d()->arrayData->type) : Heap::ArrayData::Simple; } // ### remove me void setArrayType(ArrayData::Type t) { @@ -334,10 +345,47 @@ public: { return vtable()->get(this, name, hasProperty); } inline ReturnedValue getIndexed(uint idx, bool *hasProperty = 0) const { return vtable()->getIndexed(this, idx, hasProperty); } - inline void put(String *name, const Value &v) - { vtable()->put(this, name, v); } - inline void putIndexed(uint idx, const Value &v) - { vtable()->putIndexed(this, idx, v); } + + // use the set variants instead, to customize throw behavior + inline bool put(String *name, const Value &v) + { return vtable()->put(this, name, v); } + inline bool putIndexed(uint idx, const Value &v) + { return vtable()->putIndexed(this, idx, v); } + + enum ThrowOnFailure { + DoThrowOnRejection, + DoNotThrow + }; + + // ES6: 7.3.3 Set (O, P, V, Throw) + inline bool set(String *name, const Value &v, ThrowOnFailure shouldThrow) + { + bool ret = vtable()->put(this, name, v); + // ES6: 7.3.3, 6: If success is false and Throw is true, throw a TypeError exception. + if (!ret && shouldThrow == ThrowOnFailure::DoThrowOnRejection) { + ExecutionEngine *e = engine(); + if (!e->hasException) { // allow a custom set impl to throw itself + QString message = QLatin1String("Cannot assign to read-only property \"") + + name->toQString() + QLatin1Char('\"'); + e->throwTypeError(message); + } + } + return ret; + } + + inline bool setIndexed(uint idx, const Value &v, ThrowOnFailure shouldThrow) + { + bool ret = vtable()->putIndexed(this, idx, v); + if (!ret && shouldThrow == ThrowOnFailure::DoThrowOnRejection) { + ExecutionEngine *e = engine(); + if (!e->hasException) { // allow a custom set impl to throw itself + e->throwTypeError(); + } + } + return ret; + } + + PropertyAttributes query(String *name) const { return vtable()->query(this, name); } PropertyAttributes queryIndexed(uint index) const @@ -361,13 +409,12 @@ public: inline void call(Scope &scope, CallData *d) const { vtable()->call(this, scope, d); } protected: - static void markObjects(Heap::Base *that, ExecutionEngine *e); static void construct(const Managed *m, Scope &scope, CallData *); static void call(const Managed *m, Scope &scope, CallData *); static ReturnedValue get(const Managed *m, String *name, bool *hasProperty); static ReturnedValue getIndexed(const Managed *m, uint index, bool *hasProperty); - static void put(Managed *m, String *name, const Value &value); - static void putIndexed(Managed *m, uint index, const Value &value); + static bool put(Managed *m, String *name, const Value &value); + static bool putIndexed(Managed *m, uint index, const Value &value); static PropertyAttributes query(const Managed *m, String *name); static PropertyAttributes queryIndexed(const Managed *m, uint index); static bool deleteProperty(Managed *m, String *name); @@ -381,8 +428,8 @@ protected: private: ReturnedValue internalGet(String *name, bool *hasProperty) const; ReturnedValue internalGetIndexed(uint index, bool *hasProperty) const; - void internalPut(String *name, const Value &value); - void internalPutIndexed(uint index, const Value &value); + bool internalPut(String *name, const Value &value); + bool internalPutIndexed(uint index, const Value &value); bool internalDeleteProperty(String *name); bool internalDeleteIndexedProperty(uint index); @@ -426,7 +473,7 @@ struct ArrayObject : Object { private: void commonInit() - { *propertyData(LengthPropertyIndex) = Primitive::fromInt32(0); } + { setProperty(internalClass->engine, LengthPropertyIndex, Primitive::fromInt32(0)); } }; } @@ -466,7 +513,7 @@ struct ArrayObject: Object { inline void Object::setArrayLengthUnchecked(uint l) { if (isArrayObject()) - *propertyData(Heap::ArrayObject::LengthPropertyIndex) = Primitive::fromUInt32(l); + setProperty(Heap::ArrayObject::LengthPropertyIndex, Primitive::fromUInt32(l)); } inline void Object::push_back(const Value &v) @@ -483,7 +530,7 @@ inline void Object::arraySet(uint index, const Property *p, PropertyAttributes a { // ### Clean up arrayCreate(); - if (attributes.isAccessor() || (index > 0x1000 && index > 2*d()->arrayData->alloc)) { + if (attributes.isAccessor() || (index > 0x1000 && index > 2*d()->arrayData->values.alloc)) { initSparseArray(); } else { arrayData()->vtable()->reallocate(this, index + 1, false); @@ -498,7 +545,7 @@ inline void Object::arraySet(uint index, const Property *p, PropertyAttributes a inline void Object::arraySet(uint index, const Value &value) { arrayCreate(); - if (index > 0x1000 && index > 2*d()->arrayData->alloc) { + if (index > 0x1000 && index > 2*d()->arrayData->values.alloc) { initSparseArray(); } ArrayData::insert(this, index, &value); diff --git a/src/qml/jsruntime/qv4objectproto.cpp b/src/qml/jsruntime/qv4objectproto.cpp index 97dbe24339..2e72c0f13f 100644 --- a/src/qml/jsruntime/qv4objectproto.cpp +++ b/src/qml/jsruntime/qv4objectproto.cpp @@ -1,5 +1,6 @@ /**************************************************************************** ** +** Copyright (C) 2017 Crimson AS <info@crimson.no> ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** @@ -89,10 +90,11 @@ void ObjectPrototype::init(ExecutionEngine *v4, Object *ctor) ScopedObject o(scope, this); ctor->defineReadonlyProperty(v4->id_prototype(), o); - ctor->defineReadonlyProperty(v4->id_length(), Primitive::fromInt32(1)); + ctor->defineReadonlyConfigurableProperty(v4->id_length(), Primitive::fromInt32(1)); ctor->defineDefaultProperty(QStringLiteral("getPrototypeOf"), method_getPrototypeOf, 1); ctor->defineDefaultProperty(QStringLiteral("getOwnPropertyDescriptor"), method_getOwnPropertyDescriptor, 2); ctor->defineDefaultProperty(QStringLiteral("getOwnPropertyNames"), method_getOwnPropertyNames, 1); + ctor->defineDefaultProperty(QStringLiteral("assign"), method_assign, 2); ctor->defineDefaultProperty(QStringLiteral("create"), method_create, 2); ctor->defineDefaultProperty(QStringLiteral("defineProperty"), method_defineProperty, 3); ctor->defineDefaultProperty(QStringLiteral("defineProperties"), method_defineProperties, 2); @@ -123,9 +125,8 @@ void ObjectPrototype::init(ExecutionEngine *v4, Object *ctor) void ObjectPrototype::method_getPrototypeOf(const BuiltinFunction *, Scope &scope, CallData *callData) { - ScopedObject o(scope, callData->argument(0)); - if (!o) - THROW_TYPE_ERROR(); + ScopedObject o(scope, callData->args[0].toObject(scope.engine)); + CHECK_EXCEPTION(); ScopedObject p(scope, o->prototype()); scope.result = !!p ? p->asReturnedValue() : Encode::null(); @@ -133,11 +134,8 @@ void ObjectPrototype::method_getPrototypeOf(const BuiltinFunction *, Scope &scop void ObjectPrototype::method_getOwnPropertyDescriptor(const BuiltinFunction *, Scope &scope, CallData *callData) { - ScopedObject O(scope, callData->argument(0)); - if (!O) { - scope.result = scope.engine->throwTypeError(); - return; - } + ScopedObject O(scope, callData->args[0].toObject(scope.engine)); + CHECK_EXCEPTION(); if (ArgumentsObject::isNonStrictArgumentsObject(O)) static_cast<ArgumentsObject *>(O.getPointer())->fullyCreate(); @@ -154,13 +152,54 @@ void ObjectPrototype::method_getOwnPropertyDescriptor(const BuiltinFunction *, S void ObjectPrototype::method_getOwnPropertyNames(const BuiltinFunction *, Scope &scope, CallData *callData) { - ScopedObject O(scope, callData->argument(0)); - if (!O) { - scope.result = scope.engine->throwTypeError(); + ScopedObject O(scope, callData->args[0].toObject(scope.engine)); + CHECK_EXCEPTION(); + + scope.result = getOwnPropertyNames(scope.engine, callData->args[0]); +} + +// 19.1.2.1 +void ObjectPrototype::method_assign(const BuiltinFunction *, Scope &scope, CallData *callData) +{ + ScopedObject to(scope, callData->args[0].toObject(scope.engine)); + CHECK_EXCEPTION(); + + if (callData->argc == 1) { + scope.result = to; return; } - scope.result = getOwnPropertyNames(scope.engine, callData->args[0]); + for (int i = 1; i < callData->argc; ++i) { + if (callData->args[i].isUndefined() || callData->args[i].isNull()) + continue; + + ScopedObject from(scope, callData->args[i].toObject(scope.engine)); + CHECK_EXCEPTION(); + QV4::ScopedArrayObject keys(scope, QV4::ObjectPrototype::getOwnPropertyNames(scope.engine, from)); + quint32 length = keys->getLength(); + + ScopedString nextKey(scope); + ScopedValue propValue(scope); + for (quint32 i = 0; i < length; ++i) { + nextKey = Value::fromReturnedValue(keys->getIndexed(i)).toString(scope.engine); + + PropertyAttributes attrs; + ScopedProperty prop(scope); + from->getOwnProperty(nextKey, &attrs, prop); + + if (attrs == PropertyFlag::Attr_Invalid) + continue; + + if (!attrs.isEnumerable()) + continue; + + propValue = from->get(nextKey); + to->set(nextKey, propValue, Object::DoThrowOnRejection); + CHECK_EXCEPTION(); + } + } + + scope.result = to; } void ObjectPrototype::method_create(const BuiltinFunction *builtin, Scope &scope, CallData *callData) @@ -246,14 +285,17 @@ void ObjectPrototype::method_defineProperties(const BuiltinFunction *, Scope &sc void ObjectPrototype::method_seal(const BuiltinFunction *, Scope &scope, CallData *callData) { ScopedObject o(scope, callData->argument(0)); - if (!o) - THROW_TYPE_ERROR(); + if (!o) { + // 19.1.2.17, 1 + scope.result = callData->argument(0); + return; + } o->setInternalClass(o->internalClass()->sealed()); if (o->arrayData()) { ArrayData::ensureAttributes(o); - for (uint i = 0; i < o->d()->arrayData->alloc; ++i) { + for (uint i = 0; i < o->d()->arrayData->values.alloc; ++i) { if (!o->arrayData()->isEmpty(i)) o->d()->arrayData->attrs[i].setConfigurable(false); } @@ -265,8 +307,11 @@ void ObjectPrototype::method_seal(const BuiltinFunction *, Scope &scope, CallDat void ObjectPrototype::method_freeze(const BuiltinFunction *, Scope &scope, CallData *callData) { ScopedObject o(scope, callData->argument(0)); - if (!o) - THROW_TYPE_ERROR(); + if (!o) { + // 19.1.2.5, 1 + scope.result = callData->argument(0); + return; + } if (ArgumentsObject::isNonStrictArgumentsObject(o)) static_cast<ArgumentsObject *>(o.getPointer())->fullyCreate(); @@ -275,7 +320,7 @@ void ObjectPrototype::method_freeze(const BuiltinFunction *, Scope &scope, CallD if (o->arrayData()) { ArrayData::ensureAttributes(o); - for (uint i = 0; i < o->arrayData()->alloc; ++i) { + for (uint i = 0; i < o->arrayData()->values.alloc; ++i) { if (!o->arrayData()->isEmpty(i)) o->arrayData()->attrs[i].setConfigurable(false); if (o->arrayData()->attrs[i].isData()) @@ -287,9 +332,11 @@ void ObjectPrototype::method_freeze(const BuiltinFunction *, Scope &scope, CallD void ObjectPrototype::method_preventExtensions(const BuiltinFunction *, Scope &scope, CallData *callData) { - ScopedObject o(scope, callData->argument(0)); - if (!o) - THROW_TYPE_ERROR(); + ScopedObject o(scope, callData->args[0].toObject(scope.engine)); + if (!o) { + scope.result = callData->argument(0); + return; + } o->setInternalClass(o->internalClass()->nonExtensible()); scope.result = o; @@ -297,9 +344,11 @@ void ObjectPrototype::method_preventExtensions(const BuiltinFunction *, Scope &s void ObjectPrototype::method_isSealed(const BuiltinFunction *, Scope &scope, CallData *callData) { - ScopedObject o(scope, callData->argument(0)); - if (!o) - THROW_TYPE_ERROR(); + ScopedObject o(scope, callData->args[0].toObject(scope.engine)); + if (!o) { + scope.result = Encode(true); + return; + } if (o->isExtensible()) { scope.result = Encode(false); @@ -322,7 +371,7 @@ void ObjectPrototype::method_isSealed(const BuiltinFunction *, Scope &scope, Cal return; } - for (uint i = 0; i < o->arrayData()->alloc; ++i) { + for (uint i = 0; i < o->arrayData()->values.alloc; ++i) { if (!o->arrayData()->isEmpty(i)) if (o->arrayData()->attributes(i).isConfigurable()) { scope.result = Encode(false); @@ -335,9 +384,11 @@ void ObjectPrototype::method_isSealed(const BuiltinFunction *, Scope &scope, Cal void ObjectPrototype::method_isFrozen(const BuiltinFunction *, Scope &scope, CallData *callData) { - ScopedObject o(scope, callData->argument(0)); - if (!o) - THROW_TYPE_ERROR(); + ScopedObject o(scope, callData->args[0].toObject(scope.engine)); + if (!o) { + scope.result = Encode(true); + return; + } if (o->isExtensible()) { scope.result = Encode(false); @@ -360,7 +411,7 @@ void ObjectPrototype::method_isFrozen(const BuiltinFunction *, Scope &scope, Cal return; } - for (uint i = 0; i < o->arrayData()->alloc; ++i) { + for (uint i = 0; i < o->arrayData()->values.alloc; ++i) { if (!o->arrayData()->isEmpty(i)) if (o->arrayData()->attributes(i).isConfigurable() || o->arrayData()->attributes(i).isWritable()) { scope.result = Encode(false); @@ -373,18 +424,19 @@ void ObjectPrototype::method_isFrozen(const BuiltinFunction *, Scope &scope, Cal void ObjectPrototype::method_isExtensible(const BuiltinFunction *, Scope &scope, CallData *callData) { - ScopedObject o(scope, callData->argument(0)); - if (!o) - THROW_TYPE_ERROR(); + ScopedObject o(scope, callData->args[0].toObject(scope.engine)); + if (!o) { + scope.result = Encode(false); + return; + } scope.result = Encode((bool)o->isExtensible()); } void ObjectPrototype::method_keys(const BuiltinFunction *, Scope &scope, CallData *callData) { - ScopedObject o(scope, callData->argument(0)); - if (!o) - THROW_TYPE_ERROR(); + ScopedObject o(scope, callData->args[0].toObject(scope.engine)); + CHECK_EXCEPTION(); ScopedArrayObject a(scope, scope.engine->newArrayObject()); @@ -670,12 +722,12 @@ ReturnedValue ObjectPrototype::fromPropertyDescriptor(ExecutionEngine *engine, c return o.asReturnedValue(); } - +// es6: GetOwnPropertyKeys Heap::ArrayObject *ObjectPrototype::getOwnPropertyNames(ExecutionEngine *v4, const Value &o) { Scope scope(v4); ScopedArrayObject array(scope, v4->newArrayObject()); - ScopedObject O(scope, o); + ScopedObject O(scope, o.toObject(v4)); if (O) { ObjectIterator it(scope, O, ObjectIterator::NoFlags); ScopedValue name(scope); diff --git a/src/qml/jsruntime/qv4objectproto_p.h b/src/qml/jsruntime/qv4objectproto_p.h index 1db8615511..44b54267f3 100644 --- a/src/qml/jsruntime/qv4objectproto_p.h +++ b/src/qml/jsruntime/qv4objectproto_p.h @@ -81,6 +81,7 @@ struct ObjectPrototype: Object static void method_getPrototypeOf(const BuiltinFunction *, Scope &scope, CallData *callData); static void method_getOwnPropertyDescriptor(const BuiltinFunction *, Scope &scope, CallData *callData); static void method_getOwnPropertyNames(const BuiltinFunction *, Scope &scope, CallData *callData); + static void method_assign(const BuiltinFunction *, Scope &scope, CallData *callData); static void method_create(const BuiltinFunction *, Scope &scope, CallData *callData); static void method_defineProperty(const BuiltinFunction *, Scope &scope, CallData *callData); static void method_defineProperties(const BuiltinFunction *, Scope &scope, CallData *callData); diff --git a/src/qml/jsruntime/qv4persistent.cpp b/src/qml/jsruntime/qv4persistent.cpp index 987c322e47..de82bf835f 100644 --- a/src/qml/jsruntime/qv4persistent.cpp +++ b/src/qml/jsruntime/qv4persistent.cpp @@ -215,15 +215,6 @@ void PersistentValueStorage::free(Value *v) freePage(p); } -static void drainMarkStack(QV4::ExecutionEngine *engine, Value *markBase) -{ - while (engine->jsStackTop > markBase) { - Heap::Base *h = engine->popForGC(); - Q_ASSERT (h->vtable()->markObjects); - h->vtable()->markObjects(h, engine); - } -} - void PersistentValueStorage::mark(ExecutionEngine *e) { Value *markBase = e->jsStackTop; @@ -234,7 +225,7 @@ void PersistentValueStorage::mark(ExecutionEngine *e) if (Managed *m = p->values[i].as<Managed>()) m->mark(e); } - drainMarkStack(e, markBase); + e->memoryManager->drainMarkStack(markBase); p = p->header.next; } diff --git a/src/qml/jsruntime/qv4property_p.h b/src/qml/jsruntime/qv4property_p.h index 5069d7690b..2a5b6f7f74 100644 --- a/src/qml/jsruntime/qv4property_p.h +++ b/src/qml/jsruntime/qv4property_p.h @@ -78,12 +78,6 @@ struct Property { attrs->resolve(); } - static Property genericDescriptor() { - Property pd; - pd.value = Primitive::emptyValue(); - return pd; - } - inline bool isSubset(const PropertyAttributes &attrs, const Property *other, PropertyAttributes otherAttrs) const; inline void merge(PropertyAttributes &attrs, const Property *other, PropertyAttributes otherAttrs); @@ -99,19 +93,12 @@ struct Property { } explicit Property() { value = Encode::undefined(); set = Value::fromHeapObject(0); } - explicit Property(Value v) : value(v) { set = Value::fromHeapObject(0); } - Property(FunctionObject *getter, FunctionObject *setter) { - value = reinterpret_cast<Managed *>(getter); - set = reinterpret_cast<Managed *>(setter); - } Property(Heap::FunctionObject *getter, Heap::FunctionObject *setter) { value.setM(reinterpret_cast<Heap::Base *>(getter)); set.setM(reinterpret_cast<Heap::Base *>(setter)); } - Property &operator=(Value v) { value = v; return *this; } private: - Property(const Property &); - Property &operator=(const Property &); + Q_DISABLE_COPY(Property) }; inline bool Property::isSubset(const PropertyAttributes &attrs, const Property *other, PropertyAttributes otherAttrs) const diff --git a/src/qml/jsruntime/qv4qmlcontext.cpp b/src/qml/jsruntime/qv4qmlcontext.cpp index 889f4ea288..56ecc9f682 100644 --- a/src/qml/jsruntime/qv4qmlcontext.cpp +++ b/src/qml/jsruntime/qv4qmlcontext.cpp @@ -225,21 +225,19 @@ ReturnedValue QmlContextWrapper::get(const Managed *m, String *name, bool *hasPr return Encode::undefined(); } -void QmlContextWrapper::put(Managed *m, String *name, const Value &value) +bool QmlContextWrapper::put(Managed *m, String *name, const Value &value) { Q_ASSERT(m->as<QmlContextWrapper>()); QmlContextWrapper *resource = static_cast<QmlContextWrapper *>(m); ExecutionEngine *v4 = resource->engine(); QV4::Scope scope(v4); if (scope.hasException()) - return; + return false; QV4::Scoped<QmlContextWrapper> wrapper(scope, resource); uint member = wrapper->internalClass()->find(name); - if (member < UINT_MAX) { - wrapper->putValue(member, value); - return; - } + if (member < UINT_MAX) + return wrapper->putValue(member, value); if (wrapper->d()->isNullWrapper) { if (wrapper && wrapper->d()->readOnly) { @@ -247,11 +245,10 @@ void QmlContextWrapper::put(Managed *m, String *name, const Value &value) QLatin1Char('"'); ScopedString e(scope, v4->newString(error)); v4->throwError(e); - return; + return false; } - Object::put(m, name, value); - return; + return Object::put(m, name, value); } // Its possible we could delay the calculation of the "actual" context (in the case @@ -260,7 +257,7 @@ void QmlContextWrapper::put(Managed *m, String *name, const Value &value) QQmlContextData *expressionContext = context; if (!context) - return; + return false; // See QV8ContextWrapper::Getter for resolution order @@ -270,18 +267,18 @@ void QmlContextWrapper::put(Managed *m, String *name, const Value &value) const QV4::IdentifierHash<int> &properties = context->propertyNames(); // Search context properties if (properties.count() && properties.value(name) != -1) - return; + return false; // Search scope object if (scopeObject && QV4::QObjectWrapper::setQmlProperty(v4, context, scopeObject, name, QV4::QObjectWrapper::CheckRevision, value)) - return; + return true; scopeObject = 0; // Search context object if (context->contextObject && QV4::QObjectWrapper::setQmlProperty(v4, context, context->contextObject, name, QV4::QObjectWrapper::CheckRevision, value)) - return; + return true; context = context->parent; } @@ -292,23 +289,23 @@ void QmlContextWrapper::put(Managed *m, String *name, const Value &value) QString error = QLatin1String("Invalid write to global property \"") + name->toQString() + QLatin1Char('"'); v4->throwError(error); - return; + return false; } - Object::put(m, name, value); + return Object::put(m, name, value); } void Heap::QmlContext::init(QV4::ExecutionContext *outerContext, QV4::QmlContextWrapper *qml) { Heap::ExecutionContext::init(outerContext->engine(), Heap::ExecutionContext::Type_QmlContext); - outer = outerContext->d(); + outer.set(engine, outerContext->d()); strictMode = false; callData = outer->callData; lookups = outer->lookups; constantTable = outer->constantTable; compilationUnit = outer->compilationUnit; - this->qml = qml->d(); + this->qml.set(engine, qml->d()); } Heap::QmlContext *QmlContext::createWorkerContext(ExecutionContext *parent, const QUrl &source, Value *sendFunction) diff --git a/src/qml/jsruntime/qv4qmlcontext_p.h b/src/qml/jsruntime/qv4qmlcontext_p.h index 9aec7467da..835c9236fe 100644 --- a/src/qml/jsruntime/qv4qmlcontext_p.h +++ b/src/qml/jsruntime/qv4qmlcontext_p.h @@ -77,10 +77,13 @@ struct QmlContextWrapper : Object { QQmlQPointer<QObject> scopeObject; }; -struct QmlContext : ExecutionContext { - void init(QV4::ExecutionContext *outerContext, QV4::QmlContextWrapper *qml); +#define QmlContextMembers(class, Member) \ + Member(class, Pointer, QmlContextWrapper *, qml) + +DECLARE_HEAP_OBJECT(QmlContext, ExecutionContext) { + DECLARE_MARK_TABLE(QmlContext); - Pointer<QmlContextWrapper> qml; + void init(QV4::ExecutionContext *outerContext, QV4::QmlContextWrapper *qml); }; } @@ -100,7 +103,7 @@ struct Q_QML_EXPORT QmlContextWrapper : Object void setReadOnly(bool b) { d()->readOnly = b; } static ReturnedValue get(const Managed *m, String *name, bool *hasProperty); - static void put(Managed *m, String *name, const Value &value); + static bool put(Managed *m, String *name, const Value &value); }; struct Q_QML_EXPORT QmlContext : public ExecutionContext diff --git a/src/qml/jsruntime/qv4qobjectwrapper.cpp b/src/qml/jsruntime/qv4qobjectwrapper.cpp index 346ca62a6f..4f6c179026 100644 --- a/src/qml/jsruntime/qv4qobjectwrapper.cpp +++ b/src/qml/jsruntime/qv4qobjectwrapper.cpp @@ -625,13 +625,13 @@ QV4::ReturnedValue QObjectWrapper::get(const Managed *m, String *name, bool *has return that->getQmlProperty(qmlContext, name, IgnoreRevision, hasProperty, /*includeImports*/ true); } -void QObjectWrapper::put(Managed *m, String *name, const Value &value) +bool QObjectWrapper::put(Managed *m, String *name, const Value &value) { QObjectWrapper *that = static_cast<QObjectWrapper*>(m); ExecutionEngine *v4 = that->engine(); if (v4->hasException || QQmlData::wasDeleted(that->d()->object())) - return; + return false; QQmlContextData *qmlContext = v4->callingQmlContext(); if (!setQmlProperty(v4, qmlContext, that->d()->object(), name, QV4::QObjectWrapper::IgnoreRevision, value)) { @@ -642,10 +642,13 @@ void QObjectWrapper::put(Managed *m, String *name, const Value &value) QString error = QLatin1String("Cannot assign to non-existent property \"") + name->toQString() + QLatin1Char('\"'); v4->throwError(error); + return false; } else { - QV4::Object::put(m, name, value); + return QV4::Object::put(m, name, value); } } + + return true; } PropertyAttributes QObjectWrapper::query(const Managed *m, String *name) @@ -1701,7 +1704,7 @@ ReturnedValue QObjectMethod::create(ExecutionContext *scope, const QQmlValueType Scoped<QObjectMethod> method(valueScope, valueScope.engine->memoryManager->allocObject<QObjectMethod>(scope)); method->d()->setPropertyCache(valueType->d()->propertyCache()); method->d()->index = index; - method->d()->valueTypeWrapper = valueType->d(); + method->d()->valueTypeWrapper.set(valueScope.engine, valueType->d()); return method.asReturnedValue(); } @@ -1838,15 +1841,6 @@ void QObjectMethod::callInternal(CallData *callData, Scope &scope) const } } -void QObjectMethod::markObjects(Heap::Base *that, ExecutionEngine *e) -{ - QObjectMethod::Data *This = static_cast<QObjectMethod::Data*>(that); - if (This->valueTypeWrapper) - This->valueTypeWrapper->mark(e); - - FunctionObject::markObjects(that, e); -} - DEFINE_OBJECT_VTABLE(QObjectMethod); diff --git a/src/qml/jsruntime/qv4qobjectwrapper_p.h b/src/qml/jsruntime/qv4qobjectwrapper_p.h index b09e06cec5..c031a40211 100644 --- a/src/qml/jsruntime/qv4qobjectwrapper_p.h +++ b/src/qml/jsruntime/qv4qobjectwrapper_p.h @@ -95,7 +95,15 @@ private: QQmlQPointer<QObject> qObj; }; -struct QObjectMethod : FunctionObject { +#define QObjectMethodMembers(class, Member) \ + Member(class, Pointer, QQmlValueTypeWrapper *, valueTypeWrapper) \ + Member(class, NoMark, QQmlQPointer<QObject>, qObj) \ + Member(class, NoMark, QQmlPropertyCache *, _propertyCache) \ + Member(class, NoMark, int, index) + +DECLARE_HEAP_OBJECT(QObjectMethod, FunctionObject) { + DECLARE_MARK_TABLE(QObjectMethod); + void init(QV4::ExecutionContext *scope); void destroy() { @@ -113,18 +121,10 @@ struct QObjectMethod : FunctionObject { _propertyCache = c; } - Pointer<QQmlValueTypeWrapper> valueTypeWrapper; - const QMetaObject *metaObject(); QObject *object() const { return qObj.data(); } void setObject(QObject *o) { qObj = o; } -private: - QQmlQPointer<QObject> qObj; - QQmlPropertyCache *_propertyCache; - -public: - int index; }; struct QMetaObjectWrapper : FunctionObject { @@ -192,7 +192,7 @@ protected: QQmlPropertyData *findProperty(ExecutionEngine *engine, QQmlContextData *qmlContext, String *name, RevisionMode revisionMode, QQmlPropertyData *local) const; static ReturnedValue get(const Managed *m, String *name, bool *hasProperty); - static void put(Managed *m, String *name, const Value &value); + static bool put(Managed *m, String *name, const Value &value); static PropertyAttributes query(const Managed *, String *name); static void advanceIterator(Managed *m, ObjectIterator *it, Value *name, uint *index, Property *p, PropertyAttributes *attributes); static void markObjects(Heap::Base *that, QV4::ExecutionEngine *e); @@ -243,8 +243,6 @@ struct Q_QML_EXPORT QObjectMethod : public QV4::FunctionObject void callInternal(CallData *callData, Scope &scope) const; - static void markObjects(Heap::Base *that, QV4::ExecutionEngine *e); - static QPair<QObject *, int> extractQtMethod(const QV4::FunctionObject *function); }; diff --git a/src/qml/jsruntime/qv4regexp.cpp b/src/qml/jsruntime/qv4regexp.cpp index 9e94c58432..6778145ff1 100644 --- a/src/qml/jsruntime/qv4regexp.cpp +++ b/src/qml/jsruntime/qv4regexp.cpp @@ -126,9 +126,3 @@ void Heap::RegExp::destroy() delete pattern; Base::destroy(); } - -void RegExp::markObjects(Heap::Base *that, ExecutionEngine *e) -{ - Q_UNUSED(that); - Q_UNUSED(e); -} diff --git a/src/qml/jsruntime/qv4regexp_p.h b/src/qml/jsruntime/qv4regexp_p.h index d3e63375a5..348af0fb14 100644 --- a/src/qml/jsruntime/qv4regexp_p.h +++ b/src/qml/jsruntime/qv4regexp_p.h @@ -119,8 +119,6 @@ struct RegExp : public Managed int captureCount() const { return subPatternCount() + 1; } - static void markObjects(Heap::Base *that, QV4::ExecutionEngine *e); - friend class RegExpCache; }; diff --git a/src/qml/jsruntime/qv4regexpobject.cpp b/src/qml/jsruntime/qv4regexpobject.cpp index 0894d0c25b..85e37ebe82 100644 --- a/src/qml/jsruntime/qv4regexpobject.cpp +++ b/src/qml/jsruntime/qv4regexpobject.cpp @@ -74,17 +74,17 @@ void Heap::RegExpObject::init() Object::init(); Scope scope(internalClass->engine); Scoped<QV4::RegExpObject> o(scope, this); - o->d()->value = QV4::RegExp::create(scope.engine, QString(), false, false); - o->d()->global = false; + value.set(scope.engine, QV4::RegExp::create(scope.engine, QString(), false, false)); + global = false; o->initProperties(); } void Heap::RegExpObject::init(QV4::RegExp *value, bool global) { Object::init(); - this->global = global; - this->value = value->d(); Scope scope(internalClass->engine); + this->global = global; + this->value.set(scope.engine, value->d()); Scoped<QV4::RegExpObject> o(scope, this); o->initProperties(); } @@ -137,14 +137,15 @@ void Heap::RegExpObject::init(const QRegExp &re) Scope scope(internalClass->engine); Scoped<QV4::RegExpObject> o(scope, this); - o->d()->value = QV4::RegExp::create(scope.engine, pattern, re.caseSensitivity() == Qt::CaseInsensitive, false); + o->d()->value.set(scope.engine, + QV4::RegExp::create(scope.engine, pattern, re.caseSensitivity() == Qt::CaseInsensitive, false)); o->initProperties(); } void RegExpObject::initProperties() { - *propertyData(Index_LastIndex) = Primitive::fromInt32(0); + setProperty(Index_LastIndex, Primitive::fromInt32(0)); Q_ASSERT(value()); @@ -156,25 +157,10 @@ void RegExpObject::initProperties() p.replace('/', QLatin1String("\\/")); } - *propertyData(Index_Source) = engine()->newString(p); - *propertyData(Index_Global) = Primitive::fromBoolean(global()); - *propertyData(Index_IgnoreCase) = Primitive::fromBoolean(value()->ignoreCase); - *propertyData(Index_Multiline) = Primitive::fromBoolean(value()->multiLine); -} - - -void RegExpObject::markObjects(Heap::Base *that, ExecutionEngine *e) -{ - RegExpObject::Data *re = static_cast<RegExpObject::Data *>(that); - if (re->value) - re->value->mark(e); - Object::markObjects(that, e); -} - -Value *RegExpObject::lastIndexProperty() -{ - Q_ASSERT(0 == internalClass()->find(engine()->id_lastIndex())); - return propertyData(0); + setProperty(Index_Source, engine()->newString(p)); + setProperty(Index_Global, Primitive::fromBoolean(global())); + setProperty(Index_IgnoreCase, Primitive::fromBoolean(value()->ignoreCase)); + setProperty(Index_Multiline, Primitive::fromBoolean(value()->multiLine)); } // Converts a JS RegExp to a QRegExp. @@ -228,8 +214,8 @@ void Heap::RegExpCtor::init(QV4::ExecutionContext *scope) void Heap::RegExpCtor::clearLastMatch() { - lastMatch = Primitive::nullValue(); - lastInput = internalClass->engine->id_empty()->d(); + lastMatch.set(internalClass->engine, Primitive::nullValue()); + lastInput.set(internalClass->engine, internalClass->engine->id_empty()->d()); lastMatchStart = 0; lastMatchEnd = 0; } @@ -303,15 +289,6 @@ void RegExpCtor::call(const Managed *that, Scope &scope, CallData *callData) construct(that, scope, callData); } -void RegExpCtor::markObjects(Heap::Base *that, ExecutionEngine *e) -{ - RegExpCtor::Data *This = static_cast<RegExpCtor::Data *>(that); - This->lastMatch.mark(e); - if (This->lastInput) - This->lastInput->mark(e); - FunctionObject::markObjects(that, e); -} - void RegExpPrototype::init(ExecutionEngine *engine, Object *constructor) { Scope scope(engine); @@ -361,9 +338,9 @@ void RegExpPrototype::method_exec(const BuiltinFunction *, Scope &scope, CallDat RETURN_UNDEFINED(); QString s = str->toQString(); - int offset = r->global() ? r->lastIndexProperty()->toInt32() : 0; + int offset = r->global() ? r->lastIndex() : 0; if (offset < 0 || offset > s.length()) { - *r->lastIndexProperty() = Primitive::fromInt32(0); + r->setLastIndex(0); RETURN_RESULT(Encode::null()); } @@ -374,7 +351,7 @@ void RegExpPrototype::method_exec(const BuiltinFunction *, Scope &scope, CallDat regExpCtor->d()->clearLastMatch(); if (result == -1) { - *r->lastIndexProperty() = Primitive::fromInt32(0); + r->setLastIndex(0); RETURN_RESULT(Encode::null()); } @@ -390,17 +367,17 @@ void RegExpPrototype::method_exec(const BuiltinFunction *, Scope &scope, CallDat array->arrayPut(i, v); } array->setArrayLengthUnchecked(len); - *array->propertyData(Index_ArrayIndex) = Primitive::fromInt32(result); - *array->propertyData(Index_ArrayInput) = str; + array->setProperty(Index_ArrayIndex, Primitive::fromInt32(result)); + array->setProperty(Index_ArrayInput, str); RegExpCtor::Data *dd = regExpCtor->d(); - dd->lastMatch = array; - dd->lastInput = str->d(); + dd->lastMatch.set(scope.engine, array); + dd->lastInput.set(scope.engine, str->d()); dd->lastMatchStart = matchOffsets[0]; dd->lastMatchEnd = matchOffsets[1]; if (r->global()) - *r->lastIndexProperty() = Primitive::fromInt32(matchOffsets[1]); + r->setLastIndex(matchOffsets[1]); scope.result = array; } @@ -432,7 +409,7 @@ void RegExpPrototype::method_compile(const BuiltinFunction *, Scope &scope, Call scope.engine->regExpCtor()->as<FunctionObject>()->construct(scope, cData); Scoped<RegExpObject> re(scope, scope.result.asReturnedValue()); - r->d()->value = re->value(); + r->d()->value.set(scope.engine, re->value()); r->d()->global = re->global(); RETURN_UNDEFINED(); } diff --git a/src/qml/jsruntime/qv4regexpobject_p.h b/src/qml/jsruntime/qv4regexpobject_p.h index c0c7dfa78a..0fcfe93135 100644 --- a/src/qml/jsruntime/qv4regexpobject_p.h +++ b/src/qml/jsruntime/qv4regexpobject_p.h @@ -73,21 +73,28 @@ namespace QV4 { namespace Heap { -struct RegExpObject : Object { +#define RegExpObjectMembers(class, Member) \ + Member(class, Pointer, RegExp *, value) \ + Member(class, NoMark, bool, global) + +DECLARE_HEAP_OBJECT(RegExpObject, Object) { + DECLARE_MARK_TABLE(RegExpObject); + void init(); void init(QV4::RegExp *value, bool global); void init(const QRegExp &re); - - Pointer<RegExp> value; - bool global; }; -struct RegExpCtor : FunctionObject { +#define RegExpCtorMembers(class, Member) \ + Member(class, HeapValue, HeapValue, lastMatch) \ + Member(class, Pointer, String *, lastInput) \ + Member(class, NoMark, int, lastMatchStart) \ + Member(class, NoMark, int, lastMatchEnd) + +DECLARE_HEAP_OBJECT(RegExpCtor, FunctionObject) { + DECLARE_MARK_TABLE(RegExpCtor); + void init(QV4::ExecutionContext *scope); - Value lastMatch; - Pointer<String> lastInput; - int lastMatchStart; - int lastMatchEnd; void clearLastMatch(); }; @@ -121,14 +128,19 @@ struct RegExpObject: Object { void initProperties(); - Value *lastIndexProperty(); + int lastIndex() const { + Q_ASSERT(Index_LastIndex == internalClass()->find(engine()->id_lastIndex())); + return propertyData(Index_LastIndex)->toInt32(); + } + void setLastIndex(int index) { + Q_ASSERT(Index_LastIndex == internalClass()->find(engine()->id_lastIndex())); + return setProperty(Index_LastIndex, Primitive::fromInt32(index)); + } + QRegExp toQRegExp() const; QString toString() const; QString source() const; uint flags() const; - -protected: - static void markObjects(Heap::Base *that, ExecutionEngine *e); }; struct RegExpCtor: FunctionObject @@ -142,7 +154,6 @@ struct RegExpCtor: FunctionObject static void construct(const Managed *m, Scope &scope, CallData *callData); static void call(const Managed *that, Scope &scope, CallData *callData); - static void markObjects(Heap::Base *that, ExecutionEngine *e); }; struct RegExpPrototype: RegExpObject diff --git a/src/qml/jsruntime/qv4runtime.cpp b/src/qml/jsruntime/qv4runtime.cpp index 97fd533af2..3b92096386 100644 --- a/src/qml/jsruntime/qv4runtime.cpp +++ b/src/qml/jsruntime/qv4runtime.cpp @@ -651,8 +651,8 @@ void Runtime::method_setElement(ExecutionEngine *engine, const Value &object, co if (idx < UINT_MAX) { if (o->arrayType() == Heap::ArrayData::Simple) { Heap::SimpleArrayData *s = static_cast<Heap::SimpleArrayData *>(o->arrayData()); - if (s && idx < s->len && !s->data(idx).isEmpty()) { - s->data(idx) = value; + if (s && idx < s->values.size && !s->data(idx).isEmpty()) { + s->setData(engine, idx, value); return; } } @@ -1319,7 +1319,7 @@ ReturnedValue Runtime::method_objectLiteral(ExecutionEngine *engine, const QV4:: } for (uint i = 0; i < klass->size; ++i) - *o->propertyData(i) = *args++; + o->setProperty(i, *args++); if (arrayValueCount > 0) { ScopedValue entry(scope); diff --git a/src/qml/jsruntime/qv4sequenceobject.cpp b/src/qml/jsruntime/qv4sequenceobject.cpp index 8ce10e326d..6d3110771e 100644 --- a/src/qml/jsruntime/qv4sequenceobject.cpp +++ b/src/qml/jsruntime/qv4sequenceobject.cpp @@ -274,20 +274,20 @@ public: return Encode::undefined(); } - void containerPutIndexed(uint index, const QV4::Value &value) + bool containerPutIndexed(uint index, const QV4::Value &value) { if (internalClass()->engine->hasException) - return; + return false; /* Qt containers have int (rather than uint) allowable indexes. */ if (index > INT_MAX) { generateWarning(engine(), QLatin1String("Index out of range during indexed set")); - return; + return false; } if (d()->isReference) { if (!d()->object) - return; + return false; loadReference(); } @@ -313,6 +313,7 @@ public: if (d()->isReference) storeReference(); + return true; } QV4::PropertyAttributes containerQueryIndexed(uint index) const @@ -540,8 +541,8 @@ public: static QV4::ReturnedValue getIndexed(const QV4::Managed *that, uint index, bool *hasProperty) { return static_cast<const QQmlSequence<Container> *>(that)->containerGetIndexed(index, hasProperty); } - static void putIndexed(Managed *that, uint index, const QV4::Value &value) - { static_cast<QQmlSequence<Container> *>(that)->containerPutIndexed(index, value); } + static bool putIndexed(Managed *that, uint index, const QV4::Value &value) + { return static_cast<QQmlSequence<Container> *>(that)->containerPutIndexed(index, value); } static QV4::PropertyAttributes queryIndexed(const QV4::Managed *that, uint index) { return static_cast<const QQmlSequence<Container> *>(that)->containerQueryIndexed(index); } static bool deleteIndexedProperty(QV4::Managed *that, uint index) diff --git a/src/qml/jsruntime/qv4stringobject.cpp b/src/qml/jsruntime/qv4stringobject.cpp index 1596f4b0fa..81f5c3566c 100644 --- a/src/qml/jsruntime/qv4stringobject.cpp +++ b/src/qml/jsruntime/qv4stringobject.cpp @@ -77,15 +77,15 @@ void Heap::StringObject::init() { Object::init(); Q_ASSERT(vtable() == QV4::StringObject::staticVTable()); - string = internalClass->engine->id_empty()->d(); - *propertyData(LengthPropertyIndex) = Primitive::fromInt32(0); + string.set(internalClass->engine, internalClass->engine->id_empty()->d()); + setProperty(internalClass->engine, LengthPropertyIndex, Primitive::fromInt32(0)); } void Heap::StringObject::init(const QV4::String *str) { Object::init(); - string = str->d(); - *propertyData(LengthPropertyIndex) = Primitive::fromInt32(length()); + string.set(internalClass->engine, str->d()); + setProperty(internalClass->engine, LengthPropertyIndex, Primitive::fromInt32(length())); } Heap::String *Heap::StringObject::getIndex(uint index) const @@ -145,13 +145,6 @@ void StringObject::advanceIterator(Managed *m, ObjectIterator *it, Value *name, return Object::advanceIterator(m, it, name, index, p, attrs); } -void StringObject::markObjects(Heap::Base *that, ExecutionEngine *e) -{ - StringObject::Data *o = static_cast<StringObject::Data *>(that); - o->string->mark(e); - Object::markObjects(that, e); -} - DEFINE_OBJECT_VTABLE(StringCtor); void Heap::StringCtor::init(QV4::ExecutionContext *scope) @@ -200,6 +193,7 @@ void StringPrototype::init(ExecutionEngine *engine, Object *ctor) defineDefaultProperty(QStringLiteral("lastIndexOf"), method_lastIndexOf, 1); defineDefaultProperty(QStringLiteral("localeCompare"), method_localeCompare, 1); defineDefaultProperty(QStringLiteral("match"), method_match, 1); + defineDefaultProperty(QStringLiteral("repeat"), method_repeat, 1); defineDefaultProperty(QStringLiteral("replace"), method_replace, 2); defineDefaultProperty(QStringLiteral("search"), method_search, 1); defineDefaultProperty(QStringLiteral("slice"), method_slice, 2); @@ -458,6 +452,21 @@ void StringPrototype::method_match(const BuiltinFunction *, Scope &scope, CallDa scope.result = a; } +void StringPrototype::method_repeat(const BuiltinFunction *, Scope &scope, CallData *callData) +{ + QString value = getThisString(scope, callData); + CHECK_EXCEPTION(); + + double repeats = callData->args[0].toInteger(); + + if (repeats < 0 || qIsInf(repeats)) { + scope.result = scope.engine->throwRangeError(QLatin1String("Invalid count value")); + return; + } + + scope.result = scope.engine->newString(value.repeated(int(repeats))); +} + static void appendReplacementString(QString *result, const QString &input, const QString& replaceValue, uint* matchOffsets, int captureCount) { result->reserve(result->length() + replaceValue.length()); @@ -547,7 +556,7 @@ void StringPrototype::method_replace(const BuiltinFunction *, Scope &scope, Call offset = qMax(offset + 1, matchOffsets[oldSize + 1]); } if (regExp->global()) - *regExp->lastIndexProperty() = Primitive::fromUInt32(0); + regExp->setLastIndex(0); numStringMatches = nMatchOffsets / (regExp->value()->captureCount() * 2); numCaptures = regExp->value()->captureCount(); } else { diff --git a/src/qml/jsruntime/qv4stringobject_p.h b/src/qml/jsruntime/qv4stringobject_p.h index 0ee7a6ece9..5ccee3335e 100644 --- a/src/qml/jsruntime/qv4stringobject_p.h +++ b/src/qml/jsruntime/qv4stringobject_p.h @@ -60,14 +60,18 @@ namespace QV4 { namespace Heap { -struct StringObject : Object { +#define StringObjectMembers(class, Member) \ + Member(class, Pointer, String *, string) + +DECLARE_HEAP_OBJECT(StringObject, Object) { + DECLARE_MARK_TABLE(StringObject); + enum { LengthPropertyIndex = 0 }; void init(); void init(const QV4::String *string); - String *string; Heap::String *getIndex(uint index) const; uint length() const; @@ -96,7 +100,6 @@ struct StringObject: Object { protected: static void advanceIterator(Managed *m, ObjectIterator *it, Value *name, uint *index, Property *p, PropertyAttributes *attrs); - static void markObjects(Heap::Base *that, ExecutionEngine *e); }; struct StringCtor: FunctionObject @@ -121,6 +124,7 @@ struct StringPrototype: StringObject static void method_lastIndexOf(const BuiltinFunction *, Scope &scope, CallData *callData); static void method_localeCompare(const BuiltinFunction *, Scope &scope, CallData *callData); static void method_match(const BuiltinFunction *, Scope &scope, CallData *callData); + static void method_repeat(const BuiltinFunction *, Scope &scope, CallData *callData); static void method_replace(const BuiltinFunction *, Scope &scope, CallData *callData); static void method_search(const BuiltinFunction *, Scope &scope, CallData *callData); static void method_slice(const BuiltinFunction *, Scope &scope, CallData *callData); diff --git a/src/qml/jsruntime/qv4typedarray.cpp b/src/qml/jsruntime/qv4typedarray.cpp index cecd1e6958..a34a8922e1 100644 --- a/src/qml/jsruntime/qv4typedarray.cpp +++ b/src/qml/jsruntime/qv4typedarray.cpp @@ -229,8 +229,8 @@ void TypedArrayCtor::construct(const Managed *m, Scope &scope, CallData *callDat return; } - Scoped<TypedArray > array(scope, TypedArray::create(scope.engine, that->d()->type)); - array->d()->buffer = buffer->d(); + Scoped<TypedArray> array(scope, TypedArray::create(scope.engine, that->d()->type)); + array->d()->buffer.set(scope.engine, buffer->d()); array->d()->byteLength = byteLength; array->d()->byteOffset = 0; @@ -252,8 +252,8 @@ void TypedArrayCtor::construct(const Managed *m, Scope &scope, CallData *callDat return; } - Scoped<TypedArray > array(scope, TypedArray::create(scope.engine, that->d()->type)); - array->d()->buffer = newBuffer->d(); + Scoped<TypedArray> array(scope, TypedArray::create(scope.engine, that->d()->type)); + array->d()->buffer.set(scope.engine, newBuffer->d()); array->d()->byteLength = destByteLength; array->d()->byteOffset = 0; @@ -311,8 +311,8 @@ void TypedArrayCtor::construct(const Managed *m, Scope &scope, CallData *callDat byteLength = (uint)l; } - Scoped<TypedArray > array(scope, TypedArray::create(scope.engine, that->d()->type)); - array->d()->buffer = buffer->d(); + Scoped<TypedArray> array(scope, TypedArray::create(scope.engine, that->d()->type)); + array->d()->buffer.set(scope.engine, buffer->d()); array->d()->byteLength = byteLength; array->d()->byteOffset = byteOffset; scope.result = array.asReturnedValue(); @@ -335,8 +335,8 @@ void TypedArrayCtor::construct(const Managed *m, Scope &scope, CallData *callDat return; } - Scoped<TypedArray > array(scope, TypedArray::create(scope.engine, that->d()->type)); - array->d()->buffer = newBuffer->d(); + Scoped<TypedArray> array(scope, TypedArray::create(scope.engine, that->d()->type)); + array->d()->buffer.set(scope.engine, newBuffer->d()); array->d()->byteLength = l * elementSize; array->d()->byteOffset = 0; @@ -375,12 +375,6 @@ Heap::TypedArray *TypedArray::create(ExecutionEngine *e, Heap::TypedArray::Type return e->memoryManager->allocObject<TypedArray>(e->emptyClass, e->typedArrayPrototype + t, t); } -void TypedArray::markObjects(Heap::Base *that, ExecutionEngine *e) -{ - static_cast<TypedArray::Data *>(that)->buffer->mark(e); - Object::markObjects(that, e); -} - ReturnedValue TypedArray::getIndexed(const Managed *m, uint index, bool *hasProperty) { Scope scope(static_cast<const Object *>(m)->engine()); @@ -398,11 +392,11 @@ ReturnedValue TypedArray::getIndexed(const Managed *m, uint index, bool *hasProp return a->d()->type->read(a->d()->buffer->data->data(), byteOffset); } -void TypedArray::putIndexed(Managed *m, uint index, const Value &value) +bool TypedArray::putIndexed(Managed *m, uint index, const Value &value) { ExecutionEngine *v4 = static_cast<Object *>(m)->engine(); if (v4->hasException) - return; + return false; Scope scope(v4); Scoped<TypedArray> a(scope, static_cast<TypedArray *>(m)); @@ -413,11 +407,12 @@ void TypedArray::putIndexed(Managed *m, uint index, const Value &value) goto reject; a->d()->type->write(scope.engine, a->d()->buffer->data->data(), byteOffset, value); - return; + return true; reject: if (scope.engine->current->strictMode) scope.engine->throwTypeError(); + return false; } void TypedArrayPrototype::init(ExecutionEngine *engine, TypedArrayCtor *ctor) diff --git a/src/qml/jsruntime/qv4typedarray_p.h b/src/qml/jsruntime/qv4typedarray_p.h index eefed2db4b..96786c8231 100644 --- a/src/qml/jsruntime/qv4typedarray_p.h +++ b/src/qml/jsruntime/qv4typedarray_p.h @@ -72,7 +72,15 @@ struct TypedArrayOperations { namespace Heap { -struct TypedArray : Object { +#define TypedArrayMembers(class, Member) \ + Member(class, Pointer, ArrayBuffer *, buffer) \ + Member(class, NoMark, const TypedArrayOperations *, type) \ + Member(class, NoMark, uint, byteLength) \ + Member(class, NoMark, uint, byteOffset) \ + Member(class, NoMark, uint, arrayType) + +DECLARE_HEAP_OBJECT(TypedArray, Object) { + DECLARE_MARK_TABLE(TypedArray); enum Type { Int8Array, UInt8Array, @@ -87,12 +95,6 @@ struct TypedArray : Object { }; void init(Type t); - - const TypedArrayOperations *type; - Pointer<ArrayBuffer> buffer; - uint byteLength; - uint byteOffset; - Type arrayType; }; struct TypedArrayCtor : FunctionObject { @@ -128,12 +130,11 @@ struct Q_QML_PRIVATE_EXPORT TypedArray : Object } Heap::TypedArray::Type arrayType() const { - return d()->arrayType; + return static_cast<Heap::TypedArray::Type>(d()->arrayType); } - static void markObjects(Heap::Base *that, ExecutionEngine *e); static ReturnedValue getIndexed(const Managed *m, uint index, bool *hasProperty); - static void putIndexed(Managed *m, uint index, const Value &value); + static bool putIndexed(Managed *m, uint index, const Value &value); }; struct TypedArrayCtor: FunctionObject diff --git a/src/qml/jsruntime/qv4value_p.h b/src/qml/jsruntime/qv4value_p.h index 5662432f0d..11d75dde99 100644 --- a/src/qml/jsruntime/qv4value_p.h +++ b/src/qml/jsruntime/qv4value_p.h @@ -706,7 +706,6 @@ inline unsigned int Value::toUInt32() const return (unsigned int)toInt32(); } - } QT_END_NAMESPACE diff --git a/src/qml/jsruntime/qv4variantobject.cpp b/src/qml/jsruntime/qv4variantobject.cpp index 5cab4c5386..f2ff5d307e 100644 --- a/src/qml/jsruntime/qv4variantobject.cpp +++ b/src/qml/jsruntime/qv4variantobject.cpp @@ -84,7 +84,7 @@ bool VariantObject::isEqualTo(Managed *m, Managed *other) return false; } -void VariantObject::addVmePropertyReference() +void VariantObject::addVmePropertyReference() const { if (d()->isScarce() && ++d()->vmePropertyReferenceCount == 1) { // remove from the ep->scarceResources list @@ -94,7 +94,7 @@ void VariantObject::addVmePropertyReference() } } -void VariantObject::removeVmePropertyReference() +void VariantObject::removeVmePropertyReference() const { if (d()->isScarce() && --d()->vmePropertyReferenceCount == 0) { // and add to the ep->scarceResources list diff --git a/src/qml/jsruntime/qv4variantobject_p.h b/src/qml/jsruntime/qv4variantobject_p.h index ef51b6632d..e281602bb5 100644 --- a/src/qml/jsruntime/qv4variantobject_p.h +++ b/src/qml/jsruntime/qv4variantobject_p.h @@ -96,8 +96,8 @@ struct VariantObject : Object V4_PROTOTYPE(variantPrototype) V4_NEEDS_DESTROY - void addVmePropertyReference(); - void removeVmePropertyReference(); + void addVmePropertyReference() const; + void removeVmePropertyReference() const; static bool isEqualTo(Managed *m, Managed *other); }; diff --git a/src/qml/jsruntime/qv4vme_moth.cpp b/src/qml/jsruntime/qv4vme_moth.cpp index 075a9a4a5d..8d523f17e9 100644 --- a/src/qml/jsruntime/qv4vme_moth.cpp +++ b/src/qml/jsruntime/qv4vme_moth.cpp @@ -249,10 +249,8 @@ int qt_v4DebuggerHook(const char *json) return -NoSuchCommand; // Failure. } -static void qt_v4CheckForBreak(QV4::ExecutionContext *context, QV4::Value **scopes, int scopeDepth) +static void qt_v4CheckForBreak(QV4::ExecutionContext *context) { - Q_UNUSED(scopes); - Q_UNUSED(scopeDepth); const int lineNumber = context->d()->lineNumber; QV4::Function *function = qt_v4ExtractFunction(context); QString engineName = function->sourceFile(); @@ -335,18 +333,24 @@ Param traceParam(const Param ¶m) return param; } # define VALUE(param) (*VALUEPTR(param)) -# define VALUEPTR(param) (scopes[traceParam(param).scope] + param.index) +# define VALUEPTR(param) (scopes[traceParam(param).scope].values + param.index) #else # define VALUE(param) (*VALUEPTR(param)) -# define VALUEPTR(param) (scopes[param.scope] + param.index) +# define VALUEPTR(param) (scopes[param.scope].values + param.index) #endif +// ### add write barrier here #define STOREVALUE(param, value) { \ QV4::ReturnedValue tmp = (value); \ if (engine->hasException) \ goto catchException; \ - VALUE(param) = tmp; \ - } + if (Q_LIKELY(!engine->writeBarrierActive || !scopes[param.scope].base)) { \ + VALUE(param) = tmp; \ + } else { \ + QV4::WriteBarrier::write(engine, scopes[param.scope].base, VALUEPTR(param), QV4::Value::fromReturnedValue(tmp)); \ + } \ +} + // qv4scopedvalue_p.h also defines a CHECK_EXCEPTION macro #ifdef CHECK_EXCEPTION #undef CHECK_EXCEPTION @@ -402,21 +406,29 @@ QV4::ReturnedValue VME::run(ExecutionEngine *engine, const uchar *code } } - Q_ALLOCA_VAR(QV4::Value*, scopes, sizeof(QV4::Value *)*(2 + 2*scopeDepth)); + struct Scopes { + QV4::Value *values; + QV4::Heap::Base *base; // non 0 if a write barrier is required + }; + Q_ALLOCA_VAR(Scopes, scopes, sizeof(Scopes)*(2 + 2*scopeDepth)); { - scopes[0] = const_cast<QV4::Value *>(static_cast<CompiledData::CompilationUnit*>(context->d()->compilationUnit)->constants); + scopes[0] = { const_cast<QV4::Value *>(static_cast<CompiledData::CompilationUnit*>(context->d()->compilationUnit)->constants), 0 }; // stack gets setup in push instruction - scopes[1] = 0; + scopes[1] = { 0, 0 }; QV4::Heap::ExecutionContext *scope = context->d(); int i = 0; while (scope) { - if (scope->type >= QV4::Heap::ExecutionContext::Type_SimpleCallContext) { + if (scope->type == QV4::Heap::ExecutionContext::Type_SimpleCallContext) { + QV4::Heap::SimpleCallContext *cc = static_cast<QV4::Heap::SimpleCallContext *>(scope); + scopes[2*i + 2] = { cc->callData->args, 0 }; + scopes[2*i + 3] = { 0, 0 }; + } else if (scope->type == QV4::Heap::ExecutionContext::Type_CallContext) { QV4::Heap::CallContext *cc = static_cast<QV4::Heap::CallContext *>(scope); - scopes[2*i + 2] = cc->callData->args; - scopes[2*i + 3] = cc->locals; + scopes[2*i + 2] = { cc->callData->args, cc }; + scopes[2*i + 3] = { cc->locals.values, cc }; } else { - scopes[2*i + 2] = 0; - scopes[2*i + 3] = 0; + scopes[2*i + 2] = { 0, 0 }; + scopes[2*i + 3] = { 0, 0 }; } ++i; scope = scope->outer; @@ -480,7 +492,7 @@ QV4::ReturnedValue VME::run(ExecutionEngine *engine, const uchar *code MOTH_BEGIN_INSTR(LoadElementLookup) QV4::Lookup *l = context->d()->lookups + instr.lookup; - STOREVALUE(instr.result, l->indexedGetter(l, VALUE(instr.base), VALUE(instr.index))); + STOREVALUE(instr.result, l->indexedGetter(l, engine, VALUE(instr.base), VALUE(instr.index))); MOTH_END_INSTR(LoadElementLookup) MOTH_BEGIN_INSTR(StoreElement) @@ -490,7 +502,7 @@ QV4::ReturnedValue VME::run(ExecutionEngine *engine, const uchar *code MOTH_BEGIN_INSTR(StoreElementLookup) QV4::Lookup *l = context->d()->lookups + instr.lookup; - l->indexedSetter(l, VALUE(instr.base), VALUE(instr.index), VALUE(instr.source)); + l->indexedSetter(l, engine, VALUE(instr.base), VALUE(instr.index), VALUE(instr.source)); CHECK_EXCEPTION; MOTH_END_INSTR(StoreElementLookup) @@ -557,7 +569,7 @@ QV4::ReturnedValue VME::run(ExecutionEngine *engine, const uchar *code TRACE(inline, "stack size: %u", instr.value); stackSize = instr.value; stack = scope.alloc(stackSize); - scopes[1] = stack; + scopes[1].values = stack; MOTH_END_INSTR(Push) MOTH_BEGIN_INSTR(CallValue) @@ -915,13 +927,13 @@ QV4::ReturnedValue VME::run(ExecutionEngine *engine, const uchar *code if (debugger && debugger->pauseAtNextOpportunity()) debugger->maybeBreakAtInstruction(); if (qt_v4IsDebugging) - qt_v4CheckForBreak(context, scopes, scopeDepth); + qt_v4CheckForBreak(context); MOTH_END_INSTR(Debug) MOTH_BEGIN_INSTR(Line) engine->current->lineNumber = instr.lineNumber; if (qt_v4IsDebugging) - qt_v4CheckForBreak(context, scopes, scopeDepth); + qt_v4CheckForBreak(context); MOTH_END_INSTR(Line) #endif // QT_NO_QML_DEBUGGER diff --git a/src/qml/memory/memory.pri b/src/qml/memory/memory.pri index 38fadbf23f..7956e4a9a1 100644 --- a/src/qml/memory/memory.pri +++ b/src/qml/memory/memory.pri @@ -7,7 +7,8 @@ SOURCES += \ HEADERS += \ $$PWD/qv4mm_p.h \ - $$PWD/qv4mmdefs_p.h + $$PWD/qv4mmdefs_p.h \ + $$PWD/qv4writebarrier_p.h } HEADERS += \ diff --git a/src/qml/memory/qv4heap_p.h b/src/qml/memory/qv4heap_p.h index bdb5bef92b..89e69fd9d6 100644 --- a/src/qml/memory/qv4heap_p.h +++ b/src/qml/memory/qv4heap_p.h @@ -72,6 +72,7 @@ namespace QV4 { struct VTable { const VTable * const parent; + const quint64 markTable; uint isExecutionContext : 1; uint isString : 1; uint isObject : 1; @@ -91,6 +92,8 @@ namespace Heap { struct Q_QML_EXPORT Base { void *operator new(size_t) = delete; + static Q_CONSTEXPR quint64 markTable = 0; + const VTable *vt; inline ReturnedValue asReturnedValue() const; @@ -110,6 +113,12 @@ struct Q_QML_EXPORT Base { Q_ASSERT(!Chunk::testBit(c->extendsBitmap, h - c->realBase())); return Chunk::setBit(c->blackBitmap, h - c->realBase()); } + inline void setGrayBit() { + const HeapItem *h = reinterpret_cast<const HeapItem *>(this); + Chunk *c = h->chunk(); + Q_ASSERT(!Chunk::testBit(c->extendsBitmap, h - c->realBase())); + return Chunk::setBit(c->grayBitmap, h - c->realBase()); + } inline bool inUse() const { const HeapItem *h = reinterpret_cast<const HeapItem *>(this); @@ -167,20 +176,6 @@ Q_STATIC_ASSERT(std::is_standard_layout<Base>::value); Q_STATIC_ASSERT(offsetof(Base, vt) == 0); Q_STATIC_ASSERT(sizeof(Base) == QT_POINTER_SIZE); -template <typename T> -struct Pointer { - T *operator->() const { return ptr; } - operator T *() const { return ptr; } - - Pointer &operator =(T *t) { ptr = t; return *this; } - - template <typename Type> - Type *cast() { return static_cast<Type *>(ptr); } - - T *ptr; -}; -V4_ASSERT_IS_TRIVIAL(Pointer<void>) - } #ifdef QT_NO_QOBJECT diff --git a/src/qml/memory/qv4mm.cpp b/src/qml/memory/qv4mm.cpp index 27adfcb517..180371c088 100644 --- a/src/qml/memory/qv4mm.cpp +++ b/src/qml/memory/qv4mm.cpp @@ -60,7 +60,11 @@ #include "qv4alloca_p.h" #include "qv4profiling_p.h" -#define MM_DEBUG 0 +//#define MM_STATS + +#if !defined(MM_STATS) && !defined(QT_NO_DEBUG) +#define MM_STATS +#endif #if MM_DEBUG #define DEBUG qDebug() << "MM:" @@ -261,7 +265,9 @@ void Chunk::sweep() // DEBUG << "sweeping chunk" << this << (*freeList); HeapItem *o = realBase(); for (uint i = 0; i < Chunk::EntriesInBitmap; ++i) { +#if WRITEBARRIER(none) Q_ASSERT((grayBitmap[i] | blackBitmap[i]) == blackBitmap[i]); // check that we don't have gray only objects +#endif quintptr toFree = objectBitmap[i] ^ blackBitmap[i]; Q_ASSERT((toFree & objectBitmap[i]) == toFree); // check all black objects are marked as being used quintptr e = extendsBitmap[i]; @@ -290,7 +296,7 @@ void Chunk::sweep() } } objectBitmap[i] = blackBitmap[i]; - blackBitmap[i] = 0; + grayBitmap[i] = 0; extendsBitmap[i] = e; o += Chunk::Bits; } @@ -329,13 +335,56 @@ void Chunk::freeAll() } } objectBitmap[i] = 0; - blackBitmap[i] = 0; + grayBitmap[i] = 0; extendsBitmap[i] = e; o += Chunk::Bits; } // DEBUG << "swept chunk" << this << "freed" << slotsFreed << "slots."; } +void Chunk::resetBlackBits() +{ + memset(blackBitmap, 0, sizeof(blackBitmap)); +} + +#ifdef MM_STATS +static uint nGrayItems = 0; +#endif + +void Chunk::collectGrayItems(ExecutionEngine *engine) +{ + // DEBUG << "sweeping chunk" << this << (*freeList); + HeapItem *o = realBase(); + for (uint i = 0; i < Chunk::EntriesInBitmap; ++i) { +#if WRITEBARRIER(none) + Q_ASSERT((grayBitmap[i] | blackBitmap[i]) == blackBitmap[i]); // check that we don't have gray only objects +#endif + quintptr toMark = blackBitmap[i] & grayBitmap[i]; // correct for a Steele type barrier + Q_ASSERT((toMark & objectBitmap[i]) == toMark); // check all black objects are marked as being used + // DEBUG << hex << " index=" << i << toFree; + while (toMark) { + uint index = qCountTrailingZeroBits(toMark); + quintptr bit = (static_cast<quintptr>(1) << index); + + toMark ^= bit; // mask out marked slot + // DEBUG << " index" << hex << index << toFree; + + HeapItem *itemToFree = o + index; + Heap::Base *b = *itemToFree; + Q_ASSERT(b->inUse()); + engine->pushForGC(b); +#ifdef MM_STATS + ++nGrayItems; +// qDebug() << "adding gray item" << b << "to mark stack"; +#endif + } + grayBitmap[i] = 0; + o += Chunk::Bits; + } + // DEBUG << "swept chunk" << this << "freed" << slotsFreed << "slots."; + +} + void Chunk::sortIntoBins(HeapItem **bins, uint nBins) { // qDebug() << "sortIntoBins:"; @@ -345,7 +394,7 @@ void Chunk::sortIntoBins(HeapItem **bins, uint nBins) #else const int start = 1; #endif -#ifndef QT_NO_DEBUG +#ifdef MM_STATS uint freeSlots = 0; uint allocatedSlots = 0; #endif @@ -355,7 +404,7 @@ void Chunk::sortIntoBins(HeapItem **bins, uint nBins) if (!i) usedSlots |= (static_cast<quintptr>(1) << (HeaderSize/SlotSize)) - 1; #endif -#ifndef QT_NO_DEBUG +#ifdef MM_STATS allocatedSlots += qPopulationCount(usedSlots); // qDebug() << hex << " i=" << i << "used=" << usedSlots; #endif @@ -372,7 +421,7 @@ void Chunk::sortIntoBins(HeapItem **bins, uint nBins) break; } usedSlots = (objectBitmap[i]|extendsBitmap[i]); -#ifndef QT_NO_DEBUG +#ifdef MM_STATS allocatedSlots += qPopulationCount(usedSlots); // qDebug() << hex << " i=" << i << "used=" << usedSlots; #endif @@ -383,7 +432,7 @@ void Chunk::sortIntoBins(HeapItem **bins, uint nBins) usedSlots |= (quintptr(1) << index) - 1; uint freeEnd = i*Bits + index; uint nSlots = freeEnd - freeStart; -#ifndef QT_NO_DEBUG +#ifdef MM_STATS // qDebug() << hex << " got free slots from" << freeStart << "to" << freeEnd << "n=" << nSlots << "usedSlots=" << usedSlots; freeSlots += nSlots; #endif @@ -394,7 +443,7 @@ void Chunk::sortIntoBins(HeapItem **bins, uint nBins) bins[bin] = freeItem; } } -#ifndef QT_NO_DEBUG +#ifdef MM_STATS Q_ASSERT(freeSlots + allocatedSlots == (EntriesInBitmap - start) * 8 * sizeof(quintptr)); #endif } @@ -565,6 +614,19 @@ void BlockAllocator::freeAll() } } +void BlockAllocator::resetBlackBits() +{ + for (auto c : chunks) + c->resetBlackBits(); +} + +void BlockAllocator::collectGrayItems(ExecutionEngine *engine) +{ + for (auto c : chunks) + c->collectGrayItems(engine); + +} + #if MM_DEBUG void BlockAllocator::stats() { DEBUG << "MM stats:"; @@ -617,7 +679,6 @@ static void freeHugeChunk(ChunkAllocator *chunkAllocator, const HugeItemAllocato void HugeItemAllocator::sweep() { auto isBlack = [this] (const HugeChunk &c) { bool b = c.chunk->first()->isBlack(); - Chunk::clearBit(c.chunk->blackBitmap, c.chunk->first() - c.chunk->realBase()); if (!b) freeHugeChunk(chunkAllocator, c); return !b; @@ -627,6 +688,24 @@ void HugeItemAllocator::sweep() { chunks.erase(newEnd, chunks.end()); } +void HugeItemAllocator::resetBlackBits() +{ + for (auto c : chunks) + Chunk::clearBit(c.chunk->blackBitmap, c.chunk->first() - c.chunk->realBase()); +} + +void HugeItemAllocator::collectGrayItems(ExecutionEngine *engine) +{ + for (auto c : chunks) + // Correct for a Steele type barrier + if (Chunk::testBit(c.chunk->blackBitmap, c.chunk->first() - c.chunk->realBase()) && + Chunk::testBit(c.chunk->grayBitmap, c.chunk->first() - c.chunk->realBase())) { + HeapItem *i = c.chunk->first(); + Heap::Base *b = *i; + b->mark(engine); + } +} + void HugeItemAllocator::freeAll() { for (auto &c : chunks) { @@ -652,15 +731,17 @@ MemoryManager::MemoryManager(ExecutionEngine *engine) #endif } -#ifndef QT_NO_DEBUG -static size_t lastAllocRequestedSlots = 0; +#ifdef MM_STATS +static int allocationCount = 0; +static int lastAllocRequestedSlots = 0; #endif Heap::Base *MemoryManager::allocString(std::size_t unmanagedSize) { const size_t stringSize = align(sizeof(Heap::String)); -#ifndef QT_NO_DEBUG +#ifdef MM_STATS lastAllocRequestedSlots = stringSize >> Chunk::SlotSizeShift; + ++allocationCount; #endif bool didGCRun = false; @@ -671,7 +752,8 @@ Heap::Base *MemoryManager::allocString(std::size_t unmanagedSize) unmanagedHeapSize += unmanagedSize; if (unmanagedHeapSize > unmanagedHeapSizeGCLimit) { - runGC(); + if (!didGCRun) + runGC(); if (3*unmanagedHeapSizeGCLimit <= 4*unmanagedHeapSize) // more than 75% full, raise limit @@ -689,14 +771,16 @@ Heap::Base *MemoryManager::allocString(std::size_t unmanagedSize) m = blockAllocator.allocate(stringSize, true); } +// qDebug() << "allocated string" << m; memset(m, 0, stringSize); return *m; } Heap::Base *MemoryManager::allocData(std::size_t size) { -#ifndef QT_NO_DEBUG +#ifdef MM_STATS lastAllocRequestedSlots = size >> Chunk::SlotSizeShift; + ++allocationCount; #endif bool didRunGC = false; @@ -713,8 +797,11 @@ Heap::Base *MemoryManager::allocData(std::size_t size) // qDebug() << "unmanagedHeapSize:" << unmanagedHeapSize << "limit:" << unmanagedHeapSizeGCLimit << "unmanagedSize:" << unmanagedSize; - if (size > Chunk::DataSize) - return *hugeItemAllocator.allocate(size); + if (size > Chunk::DataSize) { + HeapItem *h = hugeItemAllocator.allocate(size); +// qDebug() << "allocating huge item" << h; + return *h; + } HeapItem *m = blockAllocator.allocate(size); if (!m) { @@ -724,39 +811,92 @@ Heap::Base *MemoryManager::allocData(std::size_t size) } memset(m, 0, size); +// qDebug() << "allocating data" << m; return *m; } Heap::Object *MemoryManager::allocObjectWithMemberData(std::size_t size, uint nMembers) { - Heap::Object *o = static_cast<Heap::Object *>(allocData(size)); - - // ### Could optimize this and allocate both in one go through the block allocator - if (nMembers) { + Heap::Object *o; + if (!nMembers) { + o = static_cast<Heap::Object *>(allocData(size)); + } else { + // Allocate both in one go through the block allocator std::size_t memberSize = align(sizeof(Heap::MemberData) + (nMembers - 1)*sizeof(Value)); -// qDebug() << "allocating member data for" << o << nMembers << memberSize; - Heap::Base *m; - if (memberSize > Chunk::DataSize) - m = *hugeItemAllocator.allocate(memberSize); - else - m = *blockAllocator.allocate(memberSize, true); - memset(m, 0, memberSize); - o->memberData = static_cast<Heap::MemberData *>(m); - o->memberData->setVtable(MemberData::staticVTable()); - o->memberData->size = static_cast<uint>((memberSize - sizeof(Heap::MemberData) + sizeof(Value))/sizeof(Value)); - o->memberData->init(); + size_t totalSize = size + memberSize; + Heap::MemberData *m; + if (totalSize > Chunk::DataSize) { + o = static_cast<Heap::Object *>(allocData(size)); + m = hugeItemAllocator.allocate(memberSize)->as<Heap::MemberData>(); + } else { + HeapItem *mh = reinterpret_cast<HeapItem *>(allocData(totalSize)); + Heap::Base *b = *mh; + o = static_cast<Heap::Object *>(b); + mh += (size >> Chunk::SlotSizeShift); + m = mh->as<Heap::MemberData>(); + Chunk *c = mh->chunk(); + size_t index = mh - c->realBase(); + Chunk::setBit(c->objectBitmap, index); + Chunk::clearBit(c->extendsBitmap, index); + } + o->memberData.set(engine, m); + m->setVtable(MemberData::staticVTable()); + m->values.alloc = static_cast<uint>((memberSize - sizeof(Heap::MemberData) + sizeof(Value))/sizeof(Value)); + m->values.size = o->memberData->values.alloc; + m->init(); // qDebug() << " got" << o->memberData << o->memberData->size; } +// qDebug() << "allocating object with memberData" << o << o->memberData.operator->(); return o; } -static void drainMarkStack(QV4::ExecutionEngine *engine, Value *markBase) +static uint markStackSize = 0; + +void MemoryManager::drainMarkStack(Value *markBase) { while (engine->jsStackTop > markBase) { Heap::Base *h = engine->popForGC(); + ++markStackSize; Q_ASSERT(h); // at this point we should only have Heap::Base objects in this area on the stack. If not, weird things might happen. - Q_ASSERT (h->vtable()->markObjects); - h->vtable()->markObjects(h, engine); + if (h->vtable()->markObjects) + h->vtable()->markObjects(h, engine); + if (quint64 m = h->vtable()->markTable) { +// qDebug() << "using mark table:" << hex << m << "for" << h; + void **mem = reinterpret_cast<void **>(h); + while (m) { + MarkFlags mark = static_cast<MarkFlags>(m & 3); + switch (mark) { + case Mark_NoMark: + break; + case Mark_Value: +// qDebug() << "marking value at " << mem; + reinterpret_cast<Value *>(mem)->mark(engine); + break; + case Mark_Pointer: { +// qDebug() << "marking pointer at " << mem; + Heap::Base *p = *reinterpret_cast<Heap::Base **>(mem); + if (p) + p->mark(engine); + break; + } + case Mark_ValueArray: { + Q_ASSERT(m == Mark_ValueArray); +// qDebug() << "marking Value Array at offset" << hex << (mem - reinterpret_cast<void **>(h)); + ValueArray<0> *a = reinterpret_cast<ValueArray<0> *>(mem); + Value *v = a->values; + const Value *end = v + a->alloc; + while (v < end) { + v->mark(engine); + ++v; + } + break; + } + } + + m >>= 2; + ++mem; + } + } } } @@ -764,12 +904,28 @@ void MemoryManager::mark() { Value *markBase = engine->jsStackTop; - engine->markObjects(); + markStackSize = 0; + + if (nextGCIsIncremental) { + // need to collect all gray items and push them onto the mark stack + blockAllocator.collectGrayItems(engine); + hugeItemAllocator.collectGrayItems(engine); + } + +// qDebug() << ">>>> Mark phase:"; +// qDebug() << " mark stack after gray items" << (engine->jsStackTop - markBase); + + engine->markObjects(nextGCIsIncremental); + +// qDebug() << " mark stack after engine->mark" << (engine->jsStackTop - markBase); collectFromJSStack(); +// qDebug() << " mark stack after js stack collect" << (engine->jsStackTop - markBase); m_persistentValues->mark(engine); +// qDebug() << " mark stack after persistants" << (engine->jsStackTop - markBase); + // Preserve QObject ownership rules within JavaScript: A parent with c++ ownership // keeps all of its children alive in JavaScript. @@ -798,14 +954,20 @@ void MemoryManager::mark() qobjectWrapper->mark(engine); if (engine->jsStackTop >= engine->jsStackLimit) - drainMarkStack(engine, markBase); + drainMarkStack(markBase); } - drainMarkStack(engine, markBase); + drainMarkStack(markBase); } void MemoryManager::sweep(bool lastSweep) { + if (lastSweep && nextGCIsIncremental) { + // ensure we properly clean up on destruction even if the GC is in incremental mode + blockAllocator.resetBlackBits(); + hugeItemAllocator.resetBlackBits(); + } + for (PersistentValueStorage::Iterator it = m_weakValues->begin(); it != m_weakValues->end(); ++it) { Managed *m = (*it).managed(); if (!m || m->markBit()) @@ -858,41 +1020,48 @@ void MemoryManager::sweep(bool lastSweep) bool MemoryManager::shouldRunGC() const { size_t total = blockAllocator.totalSlots(); - size_t usedSlots = blockAllocator.usedSlotsAfterLastSweep; - if (total > MinSlotsGCLimit && usedSlots * GCOverallocation < total * 100) + if (total > MinSlotsGCLimit && usedSlotsAfterLastFullSweep * GCOverallocation < total * 100) return true; return false; } size_t dumpBins(BlockAllocator *b, bool printOutput = true) { - size_t totalFragmentedSlots = 0; + size_t totalSlotMem = 0; if (printOutput) - qDebug() << "Fragmentation map:"; + qDebug() << "Slot map:"; for (uint i = 0; i < BlockAllocator::NumBins; ++i) { uint nEntries = 0; HeapItem *h = b->freeBins[i]; while (h) { ++nEntries; - totalFragmentedSlots += h->freeData.availableSlots; + totalSlotMem += h->freeData.availableSlots; h = h->freeData.next; } if (printOutput) qDebug() << " number of entries in slot" << i << ":" << nEntries; } if (printOutput) - qDebug() << " total mem in bins" << totalFragmentedSlots*Chunk::SlotSize; - return totalFragmentedSlots*Chunk::SlotSize; + qDebug() << " total mem in bins" << totalSlotMem*Chunk::SlotSize; + return totalSlotMem*Chunk::SlotSize; } -void MemoryManager::runGC() +void MemoryManager::runGC(bool forceFullCollection) { if (gcBlocked) { // qDebug() << "Not running GC."; return; } + if (forceFullCollection) { + // do a full GC + blockAllocator.resetBlackBits(); + hugeItemAllocator.resetBlackBits(); + nextGCIsIncremental = false; + } + QScopedValueRollback<bool> gcBlocker(gcBlocked, true); +// qDebug() << "runGC"; if (!gcStats) { // uint oldUsed = allocator.usedMem(); @@ -907,21 +1076,29 @@ void MemoryManager::runGC() const size_t largeItemsBefore = getLargeItemsMem(); qDebug() << "========== GC =========="; -#ifndef QT_NO_DEBUG +#ifdef MM_STATS qDebug() << " Triggered by alloc request of" << lastAllocRequestedSlots << "slots."; + qDebug() << " Allocations since last GC" << allocationCount; + allocationCount = 0; #endif + qDebug() << "Incremental:" << nextGCIsIncremental; qDebug() << "Allocated" << totalMem << "bytes in" << blockAllocator.chunks.size() << "chunks"; qDebug() << "Fragmented memory before GC" << (totalMem - usedBefore); dumpBins(&blockAllocator); +#ifdef MM_STATS + nGrayItems = 0; +#endif + QElapsedTimer t; t.start(); mark(); - qint64 markTime = t.restart(); + qint64 markTime = t.nsecsElapsed()/1000; + t.restart(); sweep(); const size_t usedAfter = getUsedMem(); const size_t largeItemsAfter = getLargeItemsMem(); - qint64 sweepTime = t.elapsed(); + qint64 sweepTime = t.nsecsElapsed()/1000; if (triggeredByUnmanagedHeap) { qDebug() << "triggered by unmanaged heap:"; @@ -930,11 +1107,16 @@ void MemoryManager::runGC() qDebug() << " unmanaged heap limit:" << unmanagedHeapSizeGCLimit; } size_t memInBins = dumpBins(&blockAllocator); - qDebug() << "Marked object in" << markTime << "ms."; - qDebug() << "Sweeped object in" << sweepTime << "ms."; +#ifdef MM_STATS + if (nextGCIsIncremental) + qDebug() << " number of gray items:" << nGrayItems; +#endif + qDebug() << "Marked object in" << markTime << "us."; + qDebug() << " " << markStackSize << "objects marked"; + qDebug() << "Sweeped object in" << sweepTime << "us."; qDebug() << "Used memory before GC:" << usedBefore; - qDebug() << "Used memory after GC:" << usedAfter; - qDebug() << "Freed up bytes:" << (usedBefore - usedAfter); + qDebug() << "Used memory after GC :" << usedAfter; + qDebug() << "Freed up bytes :" << (usedBefore - usedAfter); size_t lost = blockAllocator.allocatedMem() - memInBins - usedAfter; if (lost) qDebug() << "!!!!!!!!!!!!!!!!!!!!! LOST MEM:" << lost << "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!"; @@ -950,6 +1132,37 @@ void MemoryManager::runGC() // ensure we don't 'loose' any memory Q_ASSERT(blockAllocator.allocatedMem() == getUsedMem() + dumpBins(&blockAllocator, false)); } + + if (!nextGCIsIncremental) + usedSlotsAfterLastFullSweep = blockAllocator.usedSlotsAfterLastSweep; + +#if WRITEBARRIER(steele) + static int count = 0; + ++count; + if (aggressiveGC) { + nextGCIsIncremental = (count % 256); + } else { + size_t total = blockAllocator.totalSlots(); + size_t usedSlots = blockAllocator.usedSlotsAfterLastSweep; + if (!nextGCIsIncremental) { + // always try an incremental GC after a full one, unless there is anyway lots of memory pressure + nextGCIsIncremental = usedSlots * 4 < total * 3; + count = 0; + } else { + if (count > 16) + nextGCIsIncremental = false; + else + nextGCIsIncremental = usedSlots * 4 < total * 3; // less than 75% full + } + } +#else + nextGCIsIncremental = false; +#endif + if (!nextGCIsIncremental) { + // do a full GC + blockAllocator.resetBlackBits(); + hugeItemAllocator.resetBlackBits(); + } } size_t MemoryManager::getUsedMem() const diff --git a/src/qml/memory/qv4mm_p.h b/src/qml/memory/qv4mm_p.h index 00daf8a622..7f02a4f929 100644 --- a/src/qml/memory/qv4mm_p.h +++ b/src/qml/memory/qv4mm_p.h @@ -80,27 +80,28 @@ struct StackAllocator { StackAllocator(ChunkAllocator *chunkAlloc); T *allocate() { - T *m = nextFree->as<T>(); + HeapItem *m = nextFree; if (Q_UNLIKELY(nextFree == lastInChunk)) { nextChunk(); } else { nextFree += requiredSlots; } -#if MM_DEBUG +#if MM_DEBUG || !defined(QT_NO_DEBUG) Chunk *c = m->chunk(); Chunk::setBit(c->objectBitmap, m - c->realBase()); #endif - return m; + return m->as<T>(); } void free() { -#if MM_DEBUG - Chunk::clearBit(item->chunk()->objectBitmap, item - item->chunk()->realBase()); -#endif if (Q_UNLIKELY(nextFree == firstInChunk)) { prevChunk(); } else { nextFree -= requiredSlots; } +#if MM_DEBUG || !defined(QT_NO_DEBUG) + Chunk *c = nextFree->chunk(); + Chunk::clearBit(c->objectBitmap, nextFree - c->realBase()); +#endif } void nextChunk(); @@ -154,6 +155,8 @@ struct BlockAllocator { void sweep(); void freeAll(); + void resetBlackBits(); + void collectGrayItems(ExecutionEngine *engine); // bump allocations HeapItem *nextFree = 0; @@ -175,6 +178,8 @@ struct HugeItemAllocator { HeapItem *allocate(size_t size); void sweep(); void freeAll(); + void resetBlackBits(); + void collectGrayItems(ExecutionEngine *engine); size_t usedMem() const { size_t used = 0; @@ -206,11 +211,11 @@ 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::SimpleCallContext *allocSimpleCallContext(QV4::ExecutionEngine *v4) { Heap::CallContext *ctxt = stackAllocator.allocate(); - memset(ctxt, 0, sizeof(Heap::CallContext)); - ctxt->setVtable(QV4::CallContext::staticVTable()); + memset(ctxt, 0, sizeof(Heap::SimpleCallContext)); + ctxt->setVtable(QV4::SimpleCallContext::staticVTable()); ctxt->init(v4); return ctxt; @@ -245,7 +250,7 @@ public: o->setVtable(ObjectType::staticVTable()); Object *prototype = ObjectType::defaultPrototype(engine); o->internalClass = ic; - o->prototype = prototype->d(); + o->prototype.set(engine, prototype->d()); return static_cast<typename ObjectType::Data *>(o); } @@ -272,7 +277,7 @@ public: { Scope scope(engine); Scoped<ObjectType> t(scope, allocateObject<ObjectType>(ic)); - t->d_unchecked()->prototype = prototype->d(); + t->d_unchecked()->prototype.set(engine, prototype->d()); t->d_unchecked()->init(); return t->d(); } @@ -282,7 +287,7 @@ public: { Scope scope(engine); Scoped<ObjectType> t(scope, allocateObject<ObjectType>(ic)); - t->d_unchecked()->prototype = prototype->d(); + t->d_unchecked()->prototype.set(engine, prototype->d()); t->d_unchecked()->init(arg1); return t->d(); } @@ -292,7 +297,7 @@ public: { Scope scope(engine); Scoped<ObjectType> t(scope, allocateObject<ObjectType>(ic)); - t->d_unchecked()->prototype = prototype->d(); + t->d_unchecked()->prototype.set(engine, prototype->d()); t->d_unchecked()->init(arg1, arg2); return t->d(); } @@ -302,7 +307,7 @@ public: { Scope scope(engine); Scoped<ObjectType> t(scope, allocateObject<ObjectType>(ic)); - t->d_unchecked()->prototype = prototype->d(); + t->d_unchecked()->prototype.set(engine, prototype->d()); t->d_unchecked()->init(arg1, arg2, arg3); return t->d(); } @@ -312,7 +317,7 @@ public: { Scope scope(engine); Scoped<ObjectType> t(scope, allocateObject<ObjectType>(ic)); - t->d_unchecked()->prototype = prototype->d(); + t->d_unchecked()->prototype.set(engine, prototype->d()); t->d_unchecked()->init(arg1, arg2, arg3, arg4); return t->d(); } @@ -417,7 +422,7 @@ public: return t->d(); } - void runGC(); + void runGC(bool forceFullCollection = false); void dumpStats() const; @@ -427,6 +432,7 @@ public: // called when a JS object grows itself. Specifically: Heap::String::append void changeUnmanagedHeapSizeUsage(qptrdiff delta) { unmanagedHeapSize += delta; } + void drainMarkStack(Value *markBase); protected: @@ -457,10 +463,12 @@ public: std::size_t unmanagedHeapSize = 0; // the amount of bytes of heap that is not managed by the memory manager, but which is held onto by managed items. std::size_t unmanagedHeapSizeGCLimit; + std::size_t usedSlotsAfterLastFullSweep = 0; bool gcBlocked = false; bool aggressiveGC = false; bool gcStats = false; + bool nextGCIsIncremental = false; }; } diff --git a/src/qml/memory/qv4mmdefs_p.h b/src/qml/memory/qv4mmdefs_p.h index db0ffe11a2..1fc7b6a527 100644 --- a/src/qml/memory/qv4mmdefs_p.h +++ b/src/qml/memory/qv4mmdefs_p.h @@ -112,22 +112,29 @@ struct Chunk { HeapItem *realBase(); HeapItem *first(); + static Q_ALWAYS_INLINE size_t bitmapIndex(size_t index) { + return index >> BitShift; + } + static Q_ALWAYS_INLINE quintptr bitForIndex(size_t index) { + return static_cast<quintptr>(1) << (index & (Bits - 1)); + } + static void setBit(quintptr *bitmap, size_t index) { // Q_ASSERT(index >= HeaderSize/SlotSize && index < ChunkSize/SlotSize); - bitmap += index >> BitShift; - quintptr bit = static_cast<quintptr>(1) << (index & (Bits - 1)); + bitmap += bitmapIndex(index); + quintptr bit = bitForIndex(index); *bitmap |= bit; } static void clearBit(quintptr *bitmap, size_t index) { // Q_ASSERT(index >= HeaderSize/SlotSize && index < ChunkSize/SlotSize); - bitmap += index >> BitShift; - quintptr bit = static_cast<quintptr>(1) << (index & (Bits - 1)); + bitmap += bitmapIndex(index); + quintptr bit = bitForIndex(index); *bitmap &= ~bit; } static bool testBit(quintptr *bitmap, size_t index) { // Q_ASSERT(index >= HeaderSize/SlotSize && index < ChunkSize/SlotSize); - bitmap += index >> BitShift; - quintptr bit = static_cast<quintptr>(1) << (index & (Bits - 1)); + bitmap += bitmapIndex(index); + quintptr bit = bitForIndex(index); return (*bitmap & bit); } static void setBits(quintptr *bitmap, size_t index, size_t nBits) { @@ -177,6 +184,8 @@ struct Chunk { void sweep(); void freeAll(); + void resetBlackBits(); + void collectGrayItems(ExecutionEngine *engine); void sortIntoBins(HeapItem **bins, uint nBins); }; @@ -265,7 +274,9 @@ struct EngineBase { Heap::ExecutionContext *current = 0; Value *jsStackTop = 0; - quint32 hasException = false; + quint8 hasException = false; + quint8 writeBarrierActive = false; + quint16 unused = 0; #if QT_POINTER_SIZE == 8 quint8 padding[4]; #endif @@ -283,6 +294,73 @@ Q_STATIC_ASSERT(offsetof(EngineBase, hasException) == offsetof(EngineBase, jsSta Q_STATIC_ASSERT(offsetof(EngineBase, memoryManager) == offsetof(EngineBase, hasException) + QT_POINTER_SIZE); Q_STATIC_ASSERT(offsetof(EngineBase, runtime) == offsetof(EngineBase, memoryManager) + QT_POINTER_SIZE); +// Some helper classes and macros to automate the generation of our +// tables used for marking objects + +enum MarkFlags { + Mark_NoMark = 0, + Mark_Value = 1, + Mark_Pointer = 2, + Mark_ValueArray = 3 +}; + +template <typename T> +struct MarkFlagEvaluator { + static Q_CONSTEXPR quint64 value = 0; +}; +template <typename T, size_t o> +struct MarkFlagEvaluator<Heap::Pointer<T, o>> { + static Q_CONSTEXPR quint64 value = static_cast<quint64>(Mark_Pointer) << (2*o / sizeof(quintptr)); +}; +template <size_t o> +struct MarkFlagEvaluator<ValueArray<o>> { + static Q_CONSTEXPR quint64 value = static_cast<quint64>(Mark_ValueArray) << (2*o / sizeof(quintptr)); +}; +template <size_t o> +struct MarkFlagEvaluator<HeapValue<o>> { + static Q_CONSTEXPR quint64 value = static_cast<quint64>(Mark_Value) << (2 *o / sizeof(quintptr)); +}; + +#define HEAP_OBJECT_OFFSET_MEMBER_EXPANSION(c, gcType, type, name) \ + HEAP_OBJECT_OFFSET_MEMBER_EXPANSION_##gcType(c, type, name) + +#define HEAP_OBJECT_OFFSET_MEMBER_EXPANSION_Pointer(c, type, name) Pointer<type, 0> name; +#define HEAP_OBJECT_OFFSET_MEMBER_EXPANSION_NoMark(c, type, name) type name; +#define HEAP_OBJECT_OFFSET_MEMBER_EXPANSION_HeapValue(c, type, name) HeapValue<0> name; +#define HEAP_OBJECT_OFFSET_MEMBER_EXPANSION_ValueArray(c, type, name) type<0> name; + +#define HEAP_OBJECT_MEMBER_EXPANSION(c, gcType, type, name) \ + HEAP_OBJECT_MEMBER_EXPANSION_##gcType(c, type, name) + +#define HEAP_OBJECT_MEMBER_EXPANSION_Pointer(c, type, name) \ + Pointer<type, offsetof(c##OffsetStruct, name) + baseOffset> name; +#define HEAP_OBJECT_MEMBER_EXPANSION_NoMark(c, type, name) \ + type name; +#define HEAP_OBJECT_MEMBER_EXPANSION_HeapValue(c, type, name) \ + HeapValue<offsetof(c##OffsetStruct, name) + baseOffset> name; +#define HEAP_OBJECT_MEMBER_EXPANSION_ValueArray(c, type, name) \ + type<offsetof(c##OffsetStruct, name) + baseOffset> name; + +#define HEAP_OBJECT_MARK_EXPANSION(class, gcType, type, name) \ + MarkFlagEvaluator<decltype(class::name)>::value | + +#define DECLARE_HEAP_OBJECT(name, base) \ +struct name##OffsetStruct { \ + name##Members(name, HEAP_OBJECT_OFFSET_MEMBER_EXPANSION) \ +}; \ +struct name##SizeStruct : base, name##OffsetStruct {}; \ +struct name##Data { \ + static Q_CONSTEXPR size_t baseOffset = sizeof(name##SizeStruct) - sizeof(name##OffsetStruct); \ + name##Members(name, HEAP_OBJECT_MEMBER_EXPANSION) \ +}; \ +Q_STATIC_ASSERT(sizeof(name##SizeStruct) == sizeof(name##Data) + name##Data::baseOffset); \ +static Q_CONSTEXPR quint64 name##_markTable = \ + (name##Members(name##Data, HEAP_OBJECT_MARK_EXPANSION) 0) | QV4::Heap::base::markTable; \ + \ +struct name : base, name##Data + +#define DECLARE_MARK_TABLE(class) static Q_CONSTEXPR quint64 markTable = class##_markTable + } QT_END_NAMESPACE diff --git a/src/qml/memory/qv4writebarrier_p.h b/src/qml/memory/qv4writebarrier_p.h new file mode 100644 index 0000000000..455de4bf3d --- /dev/null +++ b/src/qml/memory/qv4writebarrier_p.h @@ -0,0 +1,239 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtQml module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ +#ifndef QV4WRITEBARRIER_P_H +#define QV4WRITEBARRIER_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include <private/qv4global_p.h> +#include <private/qv4value_p.h> + +QT_BEGIN_NAMESPACE + +#define WRITEBARRIER_steele 1 +#define WRITEBARRIER_none -1 + +#define WRITEBARRIER(x) (1/WRITEBARRIER_##x == 1) + +namespace QV4 { + +namespace WriteBarrier { + +enum Type { + NoBarrier, + Barrier +}; + +enum NewValueType { + Primitive, + Object, + Unknown +}; + +// ### this needs to be filled with a real memory fence once marking is concurrent +Q_ALWAYS_INLINE void fence() {} + +#if WRITEBARRIER(steele) + +template <NewValueType type> +static Q_CONSTEXPR inline bool isRequired() { + return type != Primitive; +} + +inline void write(EngineBase *engine, Heap::Base *base, Value *slot, Value value) +{ + Q_UNUSED(engine); + *slot = value; + if (isRequired<Unknown>()) { + fence(); + base->setGrayBit(); + } +} + +inline void write(EngineBase *engine, Heap::Base *base, Value *slot, Heap::Base *value) +{ + Q_UNUSED(engine); + *slot = value; + if (isRequired<Object>()) { + fence(); + base->setGrayBit(); + } +} + +inline void write(EngineBase *engine, Heap::Base *base, Heap::Base **slot, Heap::Base *value) +{ + Q_UNUSED(engine); + *slot = value; + fence(); + base->setGrayBit(); +} + +#elif WRITEBARRIER(none) + +template <NewValueType type> +static Q_CONSTEXPR inline bool isRequired() { + return false; +} + +inline void write(EngineBase *engine, Heap::Base *base, Value *slot, Value value) +{ + Q_UNUSED(engine); + Q_UNUSED(base); + *slot = value; +} + +inline void write(EngineBase *engine, Heap::Base *base, Value *slot, Heap::Base *value) +{ + Q_UNUSED(engine); + Q_UNUSED(base); + *slot = value; +} + +inline void write(EngineBase *engine, Heap::Base *base, Heap::Base **slot, Heap::Base *value) +{ + Q_UNUSED(engine); + Q_UNUSED(base); + *slot = value; +} + +#endif + +} + +namespace Heap { + +template <typename T, size_t o> +struct Pointer { + static Q_CONSTEXPR size_t offset = o; + T operator->() const { return ptr; } + operator T () const { return ptr; } + + Heap::Base *base() { + Heap::Base *base = reinterpret_cast<Heap::Base *>(this) - (offset/sizeof(Heap::Base)); + Q_ASSERT(base->inUse()); + return base; + } + + void set(ExecutionEngine *e, T newVal) { + WriteBarrier::write(e, base(), reinterpret_cast<Heap::Base **>(&ptr), reinterpret_cast<Heap::Base *>(newVal)); + } + + template <typename Type> + Type *cast() { return static_cast<Type *>(ptr); } + +private: + T ptr; +}; +typedef Pointer<char *, 0> V4PointerCheck; +V4_ASSERT_IS_TRIVIAL(V4PointerCheck) + +} + +template <size_t offset> +struct HeapValue : Value { + Heap::Base *base() { + Heap::Base *base = reinterpret_cast<Heap::Base *>(this) - (offset/sizeof(Heap::Base)); + Q_ASSERT(base->inUse()); + return base; + } + + void set(ExecutionEngine *e, const Value &newVal) { + WriteBarrier::write(e, base(), this, newVal); + } +}; + +template <size_t offset> +struct ValueArray { + uint size; + uint alloc; + Value values[1]; + + Heap::Base *base() { + Heap::Base *base = reinterpret_cast<Heap::Base *>(this) - (offset/sizeof(Heap::Base)); + Q_ASSERT(base->inUse()); + return base; + } + + void set(ExecutionEngine *e, uint index, Value v) { + WriteBarrier::write(e, base(), values + index, v); + } + void set(ExecutionEngine *e, uint index, Heap::Base *b) { + WriteBarrier::write(e, base(), values + index, b); + } + inline const Value &operator[] (uint index) const { + Q_ASSERT(index < alloc); + return values[index]; + } + inline const Value *data() const { + return values; + } + + void insertData(ExecutionEngine *e, uint index, Value v) { + for (uint i = size - 1; i > index; --i) { + values[i] = values[i - 1]; + } + set(e, index, v); + } + void removeData(ExecutionEngine *e, uint index, int n = 1) { + Q_UNUSED(e); + for (uint i = index; i < size - n; ++i) { + values[i] = values[i + n]; + } + } +}; + +// It's really important that the offset of values in this structure is +// constant across all architecture, otherwise JIT cross-compiled code will +// have wrong offsets between host and target. +Q_STATIC_ASSERT(offsetof(ValueArray<0>, values) == 8); + +} + +QT_END_NAMESPACE + +#endif diff --git a/src/qml/parser/qqmljs.g b/src/qml/parser/qqmljs.g index 9cd212015e..ca84e0c157 100644 --- a/src/qml/parser/qqmljs.g +++ b/src/qml/parser/qqmljs.g @@ -71,7 +71,7 @@ %token T_VAR "var" T_VOID "void" T_WHILE "while" %token T_WITH "with" T_XOR "^" T_XOR_EQ "^=" %token T_NULL "null" T_TRUE "true" T_FALSE "false" -%token T_CONST "const" +%token T_CONST "const" T_LET "let" %token T_DEBUGGER "debugger" %token T_RESERVED_WORD "reserved word" %token T_MULTILINE_STRING_LITERAL "multiline string literal" @@ -1622,6 +1622,7 @@ ReservedIdentifier: T_VAR ; ReservedIdentifier: T_VOID ; ReservedIdentifier: T_WHILE ; ReservedIdentifier: T_CONST ; +ReservedIdentifier: T_LET ; ReservedIdentifier: T_DEBUGGER ; ReservedIdentifier: T_RESERVED_WORD ; ReservedIdentifier: T_WITH ; @@ -2486,14 +2487,26 @@ VariableStatement: VariableDeclarationKind VariableDeclarationList T_AUTOMATIC_S VariableStatement: VariableDeclarationKind VariableDeclarationList T_SEMICOLON ; /. case $rule_number: { - AST::VariableStatement *node = new (pool) AST::VariableStatement( - sym(2).VariableDeclarationList->finish (/*readOnly=*/sym(1).ival == T_CONST)); + AST::VariableDeclaration::VariableScope s = AST::VariableDeclaration::FunctionScope; + if (sym(1).ival == T_LET) + s = AST::VariableDeclaration::BlockScope; + else if (sym(1).ival == T_CONST) + s = AST::VariableDeclaration::ReadOnlyBlockScope; + + AST::VariableStatement *node = new (pool) AST::VariableStatement(sym(2).VariableDeclarationList->finish(s)); node->declarationKindToken = loc(1); node->semicolonToken = loc(3); sym(1).Node = node; } break; ./ +VariableDeclarationKind: T_LET ; +/. +case $rule_number: { + sym(1).ival = T_LET; +} break; +./ + VariableDeclarationKind: T_CONST ; /. case $rule_number: { @@ -2542,7 +2555,8 @@ case $rule_number: { VariableDeclaration: JsIdentifier InitialiserOpt ; /. case $rule_number: { - AST::VariableDeclaration *node = new (pool) AST::VariableDeclaration(stringRef(1), sym(2).Expression); + AST::VariableDeclaration::VariableScope s = AST::VariableDeclaration::FunctionScope; + AST::VariableDeclaration *node = new (pool) AST::VariableDeclaration(stringRef(1), sym(2).Expression, s); node->identifierToken = loc(1); sym(1).Node = node; } break; @@ -2551,7 +2565,8 @@ case $rule_number: { VariableDeclarationNotIn: JsIdentifier InitialiserNotInOpt ; /. case $rule_number: { - AST::VariableDeclaration *node = new (pool) AST::VariableDeclaration(stringRef(1), sym(2).Expression); + AST::VariableDeclaration::VariableScope s = AST::VariableDeclaration::FunctionScope; + AST::VariableDeclaration *node = new (pool) AST::VariableDeclaration(stringRef(1), sym(2).Expression, s); node->identifierToken = loc(1); sym(1).Node = node; } break; @@ -2677,8 +2692,9 @@ case $rule_number: { IterationStatement: T_FOR T_LPAREN T_VAR VariableDeclarationListNotIn T_SEMICOLON ExpressionOpt T_SEMICOLON ExpressionOpt T_RPAREN Statement ; /. case $rule_number: { + AST::VariableDeclaration::VariableScope s = AST::VariableDeclaration::FunctionScope; AST::LocalForStatement *node = new (pool) AST::LocalForStatement( - sym(4).VariableDeclarationList->finish (/*readOnly=*/false), sym(6).Expression, + sym(4).VariableDeclarationList->finish(s), sym(6).Expression, sym(8).Expression, sym(10).Statement); node->forToken = loc(1); node->lparenToken = loc(2); diff --git a/src/qml/parser/qqmljsast_p.h b/src/qml/parser/qqmljsast_p.h index 9b06bf3d31..0de419d697 100644 --- a/src/qml/parser/qqmljsast_p.h +++ b/src/qml/parser/qqmljsast_p.h @@ -1315,10 +1315,18 @@ class QML_PARSER_EXPORT VariableDeclaration: public Node public: QQMLJS_DECLARE_AST_NODE(VariableDeclaration) - VariableDeclaration(const QStringRef &n, ExpressionNode *e): - name (n), expression (e), readOnly(false) + enum VariableScope { + FunctionScope, + BlockScope, // let + ReadOnlyBlockScope // const + }; + + VariableDeclaration(const QStringRef &n, ExpressionNode *e, VariableScope s): + name (n), expression (e), scope(s) { kind = K; } + bool isLexicallyScoped() const { return scope != FunctionScope; } + void accept0(Visitor *visitor) override; SourceLocation firstSourceLocation() const override @@ -1330,8 +1338,8 @@ public: // attributes QStringRef name; ExpressionNode *expression; - bool readOnly; SourceLocation identifierToken; + VariableScope scope; }; class QML_PARSER_EXPORT VariableDeclarationList: public Node @@ -1363,14 +1371,13 @@ public: return declaration->lastSourceLocation(); } - inline VariableDeclarationList *finish (bool readOnly) + inline VariableDeclarationList *finish(VariableDeclaration::VariableScope s) { VariableDeclarationList *front = next; next = 0; - if (readOnly) { - VariableDeclarationList *vdl; - for (vdl = front; vdl != 0; vdl = vdl->next) - vdl->declaration->readOnly = true; + VariableDeclarationList *vdl; + for (vdl = front; vdl != 0; vdl = vdl->next) { + vdl->declaration->scope = s; } return front; } diff --git a/src/qml/parser/qqmljsgrammar.cpp b/src/qml/parser/qqmljsgrammar.cpp index b27f4af080..ca5a4bbd85 100644 --- a/src/qml/parser/qqmljsgrammar.cpp +++ b/src/qml/parser/qqmljsgrammar.cpp @@ -51,48 +51,48 @@ const char *const QQmlJSGrammar::spell [] = { "||", "+", "+=", "++", "?", "}", "]", "%", "%=", "return", ")", ";", 0, "*", "*=", "string literal", "property", "signal", "readonly", "switch", "this", "throw", "~", "try", "typeof", "var", "void", "while", "with", "^", - "^=", "null", "true", "false", "const", "debugger", "reserved word", "multiline string literal", "comment", 0, - "public", "import", "pragma", "as", "on", "get", "set", 0, 0, 0, - 0, 0, 0, 0, 0, 0}; + "^=", "null", "true", "false", "const", "let", "debugger", "reserved word", "multiline string literal", "comment", + 0, "public", "import", "pragma", "as", "on", "get", "set", 0, 0, + 0, 0, 0, 0, 0, 0, 0}; const short QQmlJSGrammar::lhs [] = { - 106, 106, 106, 106, 106, 106, 107, 113, 113, 116, - 116, 116, 116, 119, 121, 117, 117, 118, 118, 118, - 118, 118, 118, 118, 118, 122, 123, 115, 114, 126, - 126, 127, 127, 128, 128, 125, 111, 111, 111, 111, - 130, 130, 130, 130, 130, 130, 130, 111, 138, 138, - 138, 138, 139, 139, 140, 140, 111, 111, 111, 111, - 111, 111, 111, 111, 111, 111, 111, 111, 111, 111, - 111, 111, 111, 111, 111, 111, 124, 124, 124, 124, - 124, 124, 124, 143, 143, 143, 143, 143, 143, 143, - 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, - 143, 129, 145, 145, 145, 145, 144, 144, 149, 149, - 149, 147, 147, 150, 150, 150, 150, 153, 153, 153, - 153, 153, 153, 153, 153, 153, 153, 153, 153, 153, - 153, 153, 153, 153, 153, 153, 153, 153, 153, 153, - 153, 153, 153, 153, 153, 153, 153, 153, 154, 154, - 120, 120, 120, 120, 120, 157, 157, 158, 158, 158, - 158, 156, 156, 159, 159, 160, 160, 161, 161, 161, - 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, - 163, 163, 163, 163, 164, 164, 164, 165, 165, 165, - 165, 166, 166, 166, 166, 166, 166, 166, 167, 167, - 167, 167, 167, 167, 168, 168, 168, 168, 168, 169, - 169, 169, 169, 169, 170, 170, 171, 171, 172, 172, - 173, 173, 174, 174, 175, 175, 176, 176, 177, 177, - 178, 178, 179, 179, 180, 180, 181, 181, 148, 148, - 182, 182, 183, 183, 183, 183, 183, 183, 183, 183, - 183, 183, 183, 183, 109, 109, 184, 184, 185, 185, - 186, 186, 108, 108, 108, 108, 108, 108, 108, 108, - 108, 108, 108, 108, 108, 108, 108, 131, 195, 195, - 194, 194, 142, 142, 196, 196, 197, 197, 199, 199, - 198, 200, 203, 201, 201, 204, 202, 202, 132, 133, - 133, 134, 134, 187, 187, 187, 187, 187, 187, 187, - 187, 188, 188, 188, 188, 189, 189, 189, 189, 190, - 190, 135, 136, 205, 205, 208, 208, 206, 206, 209, - 207, 191, 192, 192, 137, 137, 137, 210, 211, 193, - 193, 212, 141, 155, 155, 213, 213, 152, 152, 151, - 151, 214, 112, 112, 215, 215, 110, 110, 146, 146, - 216}; + 107, 107, 107, 107, 107, 107, 108, 114, 114, 117, + 117, 117, 117, 120, 122, 118, 118, 119, 119, 119, + 119, 119, 119, 119, 119, 123, 124, 116, 115, 127, + 127, 128, 128, 129, 129, 126, 112, 112, 112, 112, + 131, 131, 131, 131, 131, 131, 131, 112, 139, 139, + 139, 139, 140, 140, 141, 141, 112, 112, 112, 112, + 112, 112, 112, 112, 112, 112, 112, 112, 112, 112, + 112, 112, 112, 112, 112, 112, 125, 125, 125, 125, + 125, 125, 125, 144, 144, 144, 144, 144, 144, 144, + 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, + 144, 130, 146, 146, 146, 146, 145, 145, 150, 150, + 150, 148, 148, 151, 151, 151, 151, 154, 154, 154, + 154, 154, 154, 154, 154, 154, 154, 154, 154, 154, + 154, 154, 154, 154, 154, 154, 154, 154, 154, 154, + 154, 154, 154, 154, 154, 154, 154, 154, 154, 155, + 155, 121, 121, 121, 121, 121, 158, 158, 159, 159, + 159, 159, 157, 157, 160, 160, 161, 161, 162, 162, + 162, 163, 163, 163, 163, 163, 163, 163, 163, 163, + 163, 164, 164, 164, 164, 165, 165, 165, 166, 166, + 166, 166, 167, 167, 167, 167, 167, 167, 167, 168, + 168, 168, 168, 168, 168, 169, 169, 169, 169, 169, + 170, 170, 170, 170, 170, 171, 171, 172, 172, 173, + 173, 174, 174, 175, 175, 176, 176, 177, 177, 178, + 178, 179, 179, 180, 180, 181, 181, 182, 182, 149, + 149, 183, 183, 184, 184, 184, 184, 184, 184, 184, + 184, 184, 184, 184, 184, 110, 110, 185, 185, 186, + 186, 187, 187, 109, 109, 109, 109, 109, 109, 109, + 109, 109, 109, 109, 109, 109, 109, 109, 132, 196, + 196, 195, 195, 143, 143, 197, 197, 197, 198, 198, + 200, 200, 199, 201, 204, 202, 202, 205, 203, 203, + 133, 134, 134, 135, 135, 188, 188, 188, 188, 188, + 188, 188, 188, 189, 189, 189, 189, 190, 190, 190, + 190, 191, 191, 136, 137, 206, 206, 209, 209, 207, + 207, 210, 208, 192, 193, 193, 138, 138, 138, 211, + 212, 194, 194, 213, 142, 156, 156, 214, 214, 153, + 153, 152, 152, 215, 113, 113, 216, 216, 111, 111, + 147, 147, 217}; const short QQmlJSGrammar::rhs [] = { 2, 2, 2, 2, 2, 2, 2, 1, 1, 1, @@ -110,777 +110,798 @@ const short QQmlJSGrammar::rhs [] = { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 4, 3, 5, 1, 2, 4, 4, 4, - 3, 0, 1, 1, 3, 1, 1, 1, 2, 2, - 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 1, 3, 3, 3, 1, 3, 3, 1, 3, 3, - 3, 1, 3, 3, 3, 3, 3, 3, 1, 3, - 3, 3, 3, 3, 1, 3, 3, 3, 3, 1, - 3, 3, 3, 3, 1, 3, 1, 3, 1, 3, - 1, 3, 1, 3, 1, 3, 1, 3, 1, 3, - 1, 3, 1, 3, 1, 5, 1, 5, 1, 3, - 1, 3, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 3, 0, 1, 1, 3, - 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 3, 1, 2, - 0, 1, 3, 3, 1, 1, 1, 3, 1, 3, - 2, 2, 2, 0, 1, 2, 0, 1, 1, 2, - 2, 7, 5, 7, 7, 7, 5, 9, 10, 7, - 8, 2, 2, 3, 3, 2, 2, 3, 3, 3, - 3, 5, 5, 3, 5, 1, 2, 0, 1, 4, - 3, 3, 3, 3, 3, 3, 4, 5, 2, 2, - 2, 1, 8, 8, 7, 1, 3, 0, 1, 0, - 1, 1, 1, 1, 1, 2, 1, 1, 0, 1, - 2}; + 1, 1, 1, 4, 3, 5, 1, 2, 4, 4, + 4, 3, 0, 1, 1, 3, 1, 1, 1, 2, + 2, 1, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 1, 3, 3, 3, 1, 3, 3, 1, 3, + 3, 3, 1, 3, 3, 3, 3, 3, 3, 1, + 3, 3, 3, 3, 3, 1, 3, 3, 3, 3, + 1, 3, 3, 3, 3, 1, 3, 1, 3, 1, + 3, 1, 3, 1, 3, 1, 3, 1, 3, 1, + 3, 1, 3, 1, 3, 1, 5, 1, 5, 1, + 3, 1, 3, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 3, 0, 1, 1, + 3, 0, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 3, 1, + 2, 0, 1, 3, 3, 1, 1, 1, 1, 3, + 1, 3, 2, 2, 2, 0, 1, 2, 0, 1, + 1, 2, 2, 7, 5, 7, 7, 7, 5, 9, + 10, 7, 8, 2, 2, 3, 3, 2, 2, 3, + 3, 3, 3, 5, 5, 3, 5, 1, 2, 0, + 1, 4, 3, 3, 3, 3, 3, 3, 4, 5, + 2, 2, 2, 1, 8, 8, 7, 1, 3, 0, + 1, 0, 1, 1, 1, 1, 1, 2, 1, 1, + 0, 1, 2}; const short QQmlJSGrammar::action_default [] = { - 0, 0, 28, 0, 0, 0, 28, 0, 188, 255, - 219, 227, 223, 167, 239, 215, 3, 152, 85, 168, - 231, 235, 156, 185, 166, 171, 151, 205, 192, 0, - 92, 93, 88, 0, 82, 77, 359, 0, 0, 0, + 0, 0, 28, 0, 0, 0, 28, 0, 189, 256, + 220, 228, 224, 168, 240, 216, 3, 153, 85, 169, + 232, 236, 157, 186, 167, 172, 152, 206, 193, 0, + 92, 93, 88, 0, 82, 77, 361, 0, 0, 0, 0, 90, 0, 0, 86, 89, 81, 0, 0, 78, - 80, 83, 79, 91, 84, 0, 87, 0, 0, 181, - 0, 0, 168, 187, 170, 169, 0, 0, 0, 183, - 184, 182, 186, 0, 216, 0, 0, 0, 0, 206, - 0, 0, 0, 0, 0, 0, 196, 0, 0, 0, - 190, 191, 189, 194, 198, 197, 195, 193, 208, 207, - 209, 0, 224, 0, 220, 0, 0, 162, 149, 161, - 150, 118, 119, 120, 145, 121, 146, 122, 123, 124, - 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, - 147, 135, 136, 137, 138, 139, 140, 141, 142, 143, - 144, 148, 0, 0, 160, 256, 163, 0, 164, 0, - 165, 159, 0, 252, 245, 243, 250, 251, 249, 248, - 254, 247, 246, 244, 253, 240, 0, 228, 0, 0, - 232, 0, 0, 236, 0, 0, 162, 154, 0, 153, - 0, 158, 172, 0, 348, 348, 349, 0, 346, 0, - 347, 0, 350, 263, 270, 269, 277, 265, 0, 266, - 0, 351, 0, 358, 267, 268, 85, 273, 271, 355, - 352, 357, 274, 0, 285, 0, 0, 0, 0, 342, - 0, 359, 257, 299, 0, 0, 0, 286, 0, 0, - 275, 276, 0, 264, 272, 300, 301, 0, 348, 0, - 0, 350, 0, 343, 344, 0, 332, 356, 0, 316, - 317, 318, 319, 0, 312, 313, 314, 315, 340, 341, - 0, 0, 0, 0, 0, 304, 305, 306, 261, 259, - 221, 229, 225, 241, 217, 262, 0, 168, 233, 237, - 210, 199, 0, 0, 218, 0, 0, 0, 0, 211, - 0, 0, 0, 0, 0, 203, 201, 204, 202, 200, - 213, 212, 214, 0, 226, 0, 222, 0, 260, 168, - 0, 242, 257, 258, 0, 257, 0, 0, 308, 0, - 0, 0, 310, 0, 230, 0, 0, 234, 0, 0, - 238, 297, 0, 289, 298, 292, 0, 296, 0, 257, - 290, 0, 257, 0, 0, 309, 0, 0, 0, 311, - 0, 0, 0, 303, 0, 302, 85, 112, 360, 0, - 0, 117, 279, 282, 0, 118, 285, 121, 146, 123, - 124, 88, 128, 129, 82, 130, 133, 86, 89, 257, - 83, 91, 136, 84, 138, 87, 140, 141, 286, 143, - 144, 148, 0, 114, 113, 116, 100, 115, 99, 0, - 109, 280, 278, 0, 0, 0, 350, 0, 110, 156, - 157, 162, 0, 155, 0, 320, 321, 0, 348, 0, - 0, 350, 0, 111, 0, 0, 0, 323, 328, 326, - 329, 0, 0, 327, 328, 0, 324, 0, 325, 281, - 331, 0, 281, 330, 0, 333, 334, 0, 281, 335, - 336, 0, 0, 337, 0, 0, 0, 338, 339, 174, - 173, 0, 0, 0, 307, 0, 0, 0, 322, 294, - 287, 0, 295, 291, 0, 293, 283, 0, 284, 288, - 0, 0, 350, 0, 345, 103, 0, 0, 107, 94, - 0, 96, 105, 0, 97, 106, 108, 98, 104, 95, - 0, 101, 178, 176, 180, 177, 175, 179, 353, 6, - 354, 4, 2, 75, 102, 0, 0, 78, 80, 79, - 37, 5, 0, 76, 0, 51, 50, 49, 0, 0, - 51, 0, 0, 0, 52, 0, 67, 68, 0, 65, - 0, 66, 41, 42, 43, 44, 46, 47, 71, 45, - 0, 51, 0, 0, 0, 0, 0, 61, 0, 62, - 0, 0, 32, 0, 0, 72, 33, 0, 36, 34, - 30, 0, 35, 31, 0, 63, 0, 64, 156, 0, - 69, 73, 0, 0, 0, 0, 156, 281, 0, 70, - 85, 118, 285, 121, 146, 123, 124, 88, 128, 129, - 130, 133, 86, 89, 257, 91, 136, 84, 138, 87, - 140, 141, 286, 143, 144, 148, 74, 0, 59, 53, - 60, 54, 0, 0, 0, 0, 56, 0, 57, 58, - 55, 0, 0, 0, 0, 48, 0, 38, 39, 0, - 40, 8, 0, 0, 9, 0, 11, 0, 10, 0, - 1, 27, 15, 14, 26, 13, 12, 29, 7, 0, - 18, 0, 19, 0, 24, 25, 0, 20, 21, 0, - 22, 23, 16, 17, 361}; + 80, 83, 79, 91, 84, 0, 87, 0, 0, 182, + 0, 0, 169, 188, 171, 170, 0, 0, 0, 184, + 185, 183, 187, 0, 217, 0, 0, 0, 0, 207, + 0, 0, 0, 0, 0, 0, 197, 0, 0, 0, + 191, 192, 190, 195, 199, 198, 196, 194, 209, 208, + 210, 0, 225, 0, 221, 0, 0, 163, 150, 162, + 151, 118, 119, 120, 145, 121, 147, 122, 123, 124, + 125, 126, 127, 128, 129, 130, 131, 132, 146, 133, + 134, 148, 135, 136, 137, 138, 139, 140, 141, 142, + 143, 144, 149, 0, 0, 161, 257, 164, 0, 165, + 0, 166, 160, 0, 253, 246, 244, 251, 252, 250, + 249, 255, 248, 247, 245, 254, 241, 0, 229, 0, + 0, 233, 0, 0, 237, 0, 0, 163, 155, 0, + 154, 0, 159, 173, 0, 350, 350, 351, 0, 348, + 0, 349, 0, 352, 264, 271, 270, 278, 266, 0, + 267, 0, 353, 0, 360, 268, 269, 85, 274, 272, + 357, 354, 359, 275, 0, 287, 0, 0, 0, 0, + 344, 0, 361, 286, 258, 301, 0, 0, 0, 288, + 0, 0, 276, 277, 0, 265, 273, 302, 303, 0, + 350, 0, 0, 352, 0, 345, 346, 0, 334, 358, + 0, 318, 319, 320, 321, 0, 314, 315, 316, 317, + 342, 343, 0, 0, 0, 0, 0, 306, 307, 308, + 262, 260, 222, 230, 226, 242, 218, 263, 0, 169, + 234, 238, 211, 200, 0, 0, 219, 0, 0, 0, + 0, 212, 0, 0, 0, 0, 0, 204, 202, 205, + 203, 201, 214, 213, 215, 0, 227, 0, 223, 0, + 261, 169, 0, 243, 258, 259, 0, 258, 0, 0, + 310, 0, 0, 0, 312, 0, 231, 0, 0, 235, + 0, 0, 239, 299, 0, 291, 300, 294, 0, 298, + 0, 258, 292, 0, 258, 0, 0, 311, 0, 0, + 0, 313, 0, 0, 0, 305, 0, 304, 85, 112, + 362, 0, 0, 117, 280, 283, 0, 118, 287, 121, + 147, 123, 124, 88, 128, 129, 82, 130, 286, 133, + 86, 89, 258, 83, 91, 136, 84, 138, 87, 140, + 141, 288, 143, 144, 149, 0, 114, 113, 116, 100, + 115, 99, 0, 109, 281, 279, 0, 0, 0, 352, + 0, 110, 157, 158, 163, 0, 156, 0, 322, 323, + 0, 350, 0, 0, 352, 0, 111, 0, 0, 0, + 325, 330, 328, 331, 0, 0, 329, 330, 0, 326, + 0, 327, 282, 333, 0, 282, 332, 0, 335, 336, + 0, 282, 337, 338, 0, 0, 339, 0, 0, 0, + 340, 341, 175, 174, 0, 0, 0, 309, 0, 0, + 0, 324, 296, 289, 0, 297, 293, 0, 295, 284, + 0, 285, 290, 0, 0, 352, 0, 347, 103, 0, + 0, 107, 94, 0, 96, 105, 0, 97, 106, 108, + 98, 104, 95, 0, 101, 179, 177, 181, 178, 176, + 180, 355, 6, 356, 4, 2, 75, 102, 0, 0, + 78, 80, 79, 37, 5, 0, 76, 0, 51, 50, + 49, 0, 0, 51, 0, 0, 0, 52, 0, 67, + 68, 0, 65, 0, 66, 41, 42, 43, 44, 46, + 47, 71, 45, 0, 51, 0, 0, 0, 0, 0, + 61, 0, 62, 0, 0, 32, 0, 0, 72, 33, + 0, 36, 34, 30, 0, 35, 31, 0, 63, 0, + 64, 157, 0, 69, 73, 0, 0, 0, 0, 157, + 282, 0, 70, 85, 118, 287, 121, 147, 123, 124, + 88, 128, 129, 130, 286, 133, 86, 89, 258, 91, + 136, 84, 138, 87, 140, 141, 288, 143, 144, 149, + 74, 0, 59, 53, 60, 54, 0, 0, 0, 0, + 56, 0, 57, 58, 55, 0, 0, 0, 0, 48, + 0, 38, 39, 0, 40, 8, 0, 0, 9, 0, + 11, 0, 10, 0, 1, 27, 15, 14, 26, 13, + 12, 29, 7, 0, 18, 0, 19, 0, 24, 25, + 0, 20, 21, 0, 22, 23, 16, 17, 363}; const short QQmlJSGrammar::goto_default [] = { - 7, 650, 211, 198, 209, 521, 509, 645, 658, 508, - 644, 648, 646, 654, 22, 651, 649, 647, 18, 520, - 571, 561, 568, 563, 548, 193, 197, 199, 204, 234, - 212, 231, 552, 622, 621, 203, 233, 26, 487, 486, - 359, 358, 9, 357, 360, 202, 480, 361, 109, 17, - 147, 24, 13, 146, 19, 25, 59, 23, 8, 28, - 27, 280, 15, 274, 10, 270, 12, 272, 11, 271, - 20, 278, 21, 279, 14, 273, 269, 310, 414, 275, - 276, 205, 195, 194, 208, 207, 230, 196, 364, 363, - 232, 471, 470, 332, 333, 473, 335, 472, 334, 427, - 431, 434, 430, 429, 449, 450, 200, 186, 201, 210, + 7, 654, 212, 199, 210, 524, 512, 649, 662, 511, + 648, 652, 650, 658, 22, 655, 653, 651, 18, 523, + 574, 564, 571, 566, 551, 194, 198, 200, 205, 236, + 213, 233, 555, 626, 625, 204, 235, 26, 490, 489, + 361, 360, 9, 359, 362, 203, 483, 363, 109, 17, + 148, 24, 13, 147, 19, 25, 59, 23, 8, 28, + 27, 282, 15, 276, 10, 272, 12, 274, 11, 273, + 20, 280, 21, 281, 14, 275, 271, 312, 417, 277, + 278, 206, 196, 195, 209, 208, 232, 197, 366, 365, + 234, 474, 473, 334, 335, 476, 337, 475, 336, 430, + 434, 437, 433, 432, 452, 453, 201, 187, 202, 211, 0}; const short QQmlJSGrammar::action_index [] = { - 246, 1285, 2768, 2768, 2666, 998, 98, 198, 86, -106, - 26, -15, -39, 234, -106, 314, 54, -106, -106, 714, - 89, 151, 212, 219, -106, -106, -106, 412, 279, 1285, - -106, -106, -106, 525, -106, -106, 2360, 1675, 1285, 1285, - 1285, -106, 902, 1285, -106, -106, -106, 1285, 1285, -106, - -106, -106, -106, -106, -106, 1285, -106, 1285, 1285, -106, - 1285, 1285, 103, 197, -106, -106, 1285, 1285, 1285, -106, - -106, -106, 214, 1285, 297, 1285, 1285, 1285, 1285, 392, - 1285, 1285, 1285, 1285, 1285, 1285, 213, 1285, 1285, 1285, - 96, 100, 101, 279, 279, 195, 190, 181, 402, 372, - 382, 1285, -10, 1285, 106, 2258, 1285, 1285, -106, -106, - -106, -106, -106, -106, -106, -106, -106, -106, -106, -106, - -106, -106, -106, -106, -106, -106, -106, -106, -106, -106, - -106, -106, -106, -106, -106, -106, -106, -106, -106, -106, - -106, -106, 136, 1285, -106, -106, 65, 29, -106, 1285, - -106, -106, 1285, -106, -106, -106, -106, -106, -106, -106, - -106, -106, -106, -106, -106, -106, 1285, -46, 1285, 1285, - 30, 27, 1285, -106, 2258, 1285, 1285, -106, 130, -106, - -31, -106, -106, -16, 520, 520, 71, 21, -106, 421, - -106, 38, 2768, -106, -106, -106, -106, -106, 237, -106, - 520, -106, -52, -106, -106, -106, 23, -106, -106, -106, - 2768, -106, -106, 596, -106, 588, 141, 2666, 2, 1, - -1, 2972, 1285, -106, 13, 1285, 28, -106, -28, -30, - -106, -106, 435, -106, -106, -106, -106, 60, 520, 52, - 67, 2768, 64, -106, -106, 2666, -106, -106, 126, -106, - -106, -106, -106, 73, -106, -106, -106, -106, -106, -106, - -18, 34, 1285, 156, 168, -106, -106, -106, 1479, -106, - 79, 40, 48, -106, 312, 75, 42, 672, 80, 143, - 331, 279, 442, 1285, 316, 1285, 1285, 1285, 1285, 341, - 1285, 1285, 1285, 1285, 1285, 279, 360, 360, 196, 225, - 443, 357, 351, 1285, -4, 1285, 63, 1285, -106, 714, - 1285, -106, 1285, 102, 68, 1285, 62, 2666, -106, 1285, - 147, 2666, -106, 1285, 56, 1285, 1285, 91, 87, 1285, - -106, 81, 149, 74, -106, -106, 1285, -106, 439, 1285, - -106, -44, 1285, -42, 2666, -106, 1285, 153, 2666, -106, - 1285, 154, 2666, 10, 2666, -106, 0, -106, 15, -54, - 92, -106, -106, 2666, -50, 539, -7, 536, 121, 1285, - 2666, 5, -8, 445, 2462, 24, 902, 51, 50, 1384, - 2462, 47, 20, 46, 1285, 44, 19, 1285, 41, 1285, - 3, -5, 2564, -106, -106, -106, -106, -106, -106, 1285, - -106, -106, -106, 6, -17, 11, 2768, -9, -106, 249, - -106, 1285, -13, -106, 105, -106, -106, -12, 520, -41, - -20, 2768, -45, -106, 1285, 115, 12, -106, 36, -106, - 31, 122, 1285, -106, 58, 4, -106, -51, -106, 2666, - -106, 146, 2666, -106, 235, -106, -106, 140, 2666, 93, - -106, 84, 76, -106, 520, 17, 33, -106, -106, -106, - -106, 1285, 134, 2666, -106, 1285, 125, 2666, -106, 55, - -106, 163, -106, -106, 1285, -106, -106, 520, -106, -106, - 7, 45, 2768, 32, -106, -106, 120, 1773, -106, -106, - 1577, -106, -106, 1871, -106, -106, -106, -106, -106, -106, - 113, -106, -106, -106, -106, -106, -106, -106, -106, -106, - 2768, -106, -106, -106, 109, 35, 808, 206, 49, 61, - -106, -106, 229, -106, 203, 37, -106, -106, 611, 183, - -106, 124, 39, 389, -106, 97, -106, -106, 252, -106, - 2061, -106, -106, -106, -106, -106, -106, -106, -106, -106, - 269, -23, 611, 243, 180, 424, 232, -106, 16, -106, - 808, 162, -106, 22, 808, -106, -106, 1190, -106, -106, - -106, 1094, -106, -106, 248, -106, 2061, -106, 305, -24, - -106, -106, 215, 457, 18, 2156, 292, 2870, -11, -106, - 14, 599, 9, 528, 119, 1285, 2666, 8, 70, 514, - 72, 902, 95, 90, 1384, 85, 59, 77, 1285, 110, - 83, 1285, 104, 1285, 82, 78, -106, 205, -106, 236, - -106, 57, 25, 611, 167, 517, -106, 107, -106, -106, - -106, 1966, 808, 1675, 43, -106, 155, -106, -106, 53, - -106, -106, 808, 808, 108, 808, -106, 289, -106, 117, - -106, -106, 150, 157, -106, -106, -106, -106, -106, 364, - -106, 226, -106, 69, -106, -106, 432, -106, -106, 88, - -106, -106, -106, -106, -106, + 308, 1392, 2787, 2787, 2890, 1102, 71, 6, 103, -107, + 10, -35, -64, 287, -107, 310, 11, -107, -107, 815, + 30, 112, 183, 214, -107, -107, -107, 463, 203, 1392, + -107, -107, -107, 536, -107, -107, 2478, 1786, 1392, 1392, + 1392, -107, 1005, 1392, -107, -107, -107, 1392, 1392, -107, + -107, -107, -107, -107, -107, 1392, -107, 1392, 1392, -107, + 1392, 1392, 75, 204, -107, -107, 1392, 1392, 1392, -107, + -107, -107, 221, 1392, 306, 1392, 1392, 1392, 1392, 463, + 1392, 1392, 1392, 1392, 1392, 1392, 200, 1392, 1392, 1392, + 149, 145, 108, 231, 241, 295, 379, 379, 463, 463, + 463, 1392, -70, 1392, 4, 2375, 1392, 1392, -107, -107, + -107, -107, -107, -107, -107, -107, -107, -107, -107, -107, + -107, -107, -107, -107, -107, -107, -107, -107, -107, -107, + -107, -107, -107, -107, -107, -107, -107, -107, -107, -107, + -107, -107, -107, 105, 1392, -107, -107, -5, -58, -107, + 1392, -107, -107, 1392, -107, -107, -107, -107, -107, -107, + -107, -107, -107, -107, -107, -107, -107, 1392, -44, 1392, + 1392, 5, 7, 1392, -107, 2375, 1392, 1392, -107, 134, + -107, -43, -107, -107, -16, 541, 541, 15, -36, -107, + 462, -107, -4, 2787, -107, -107, -107, -107, -107, 213, + -107, 449, -107, -20, -107, -107, -107, 31, -107, -107, + -107, 2787, -107, -107, 616, -107, 711, 144, 2890, 21, + 42, 43, 3096, -107, 1392, -107, 62, 1392, 101, -107, + 102, 99, -107, -107, 417, -107, -107, -107, -107, 93, + 441, 56, 92, 2787, 34, -107, -107, 2890, -107, -107, + 118, -107, -107, -107, -107, 125, -107, -107, -107, -107, + -107, -107, -14, 33, 1392, 137, 193, -107, -107, -107, + 1488, -107, 44, -1, -42, -107, 316, -8, -60, 718, + 97, 87, 368, 222, 359, 1392, 313, 1392, 1392, 1392, + 1392, 342, 1392, 1392, 1392, 1392, 1392, 271, 270, 263, + 262, 225, 346, 352, 362, 1392, -51, 1392, 29, 1392, + -107, 815, 1392, -107, 1392, 28, -22, 1392, -19, 2890, + -107, 1392, 160, 2890, -107, 1392, 0, 1392, 1392, 97, + 45, 1392, -107, 37, 142, 25, -107, -107, 1392, -107, + 541, 1392, -107, 9, 1392, 12, 2890, -107, 1392, 128, + 2890, -107, 1392, 124, 2890, 61, 2890, -107, 60, -107, + 67, 26, 73, -107, -107, 2890, 49, 544, 80, 556, + 114, 1392, 2890, 85, 58, 482, 2581, 64, 88, 1005, + 90, 94, 1588, 2581, 96, 70, 197, 1392, 100, 76, + 1392, 104, 1392, 82, 84, 2684, -107, -107, -107, -107, + -107, -107, 1392, -107, -107, -107, 95, 63, 91, 2787, + 53, -107, 217, -107, 1392, 50, -107, 120, -107, -107, + 40, 372, 8, 27, 2787, 3, -107, 1392, 141, 20, + -107, 46, -107, 41, 147, 1392, -107, 39, 36, -107, + -15, -107, 2890, -107, 297, 2890, -107, 175, -107, -107, + 187, 2890, 14, -107, -3, -2, -107, 459, -34, -6, + -107, -107, -107, -107, 1392, 139, 2890, -107, 1392, 132, + 2890, -107, 1, -107, 251, -107, -107, 1392, -107, -107, + 541, -107, -107, -48, -23, 2787, -47, -107, -107, 113, + 1984, -107, -107, 1885, -107, -107, 1687, -107, -107, -107, + -107, -107, -107, 107, -107, -107, -107, -107, -107, -107, + -107, -107, -107, 2787, -107, -107, -107, 131, -50, 910, + 243, -45, -7, -107, -107, 232, -107, 206, -12, -107, + -107, 633, 189, -107, 198, 13, 385, -107, 153, -107, + -107, 184, -107, 2080, -107, -107, -107, -107, -107, -107, + -107, -107, -107, 208, 18, 633, 219, 129, 353, 292, + -107, 48, -107, 910, 122, -107, 81, 910, -107, -107, + 1296, -107, -107, -107, 1199, -107, -107, 224, -107, 2080, + -107, 311, 81, -107, -107, 205, 633, 98, 2176, 304, + 2993, 69, -107, 89, 613, 86, 597, 109, 1392, 2890, + 83, 55, 467, 52, 79, 804, 78, 77, 1588, 66, + 47, 59, 1392, 57, 32, 1392, 54, 1392, 38, 35, + -107, 255, -107, 228, -107, 51, 2, 524, 195, 532, + -107, 133, -107, -107, -107, 2272, 910, 1786, 17, -107, + 152, -107, -107, 16, -107, -107, 910, 910, 119, 910, + -107, 302, -107, 148, -107, -107, 143, 140, -107, -107, + -107, -107, -107, 369, -107, 249, -107, 111, -107, -107, + 364, -107, -107, 65, -107, -107, -107, -107, -107, - -111, 8, 65, 83, 84, 317, 1, -111, -111, -111, - -111, -111, -111, -111, -111, -111, -111, -111, -111, -77, - -111, -111, -111, -111, -111, -111, -111, -111, -111, 96, - -111, -111, -111, 2, -111, -111, -5, -28, 12, 106, - 95, -111, 61, 55, -111, -111, -111, 63, 70, -111, - -111, -111, -111, -111, -111, 54, -111, 172, 177, -111, - 180, 191, -111, -111, -111, -111, 197, 202, 203, -111, - -111, -111, -111, 210, -111, 209, 195, 109, 116, -111, - 146, 125, 126, 127, 135, 138, -111, 141, 144, 110, + -111, 55, 62, 77, 71, 279, -7, -111, -111, -111, + -111, -111, -111, -111, -111, -111, -111, -111, -111, -74, + -111, -111, -111, -111, -111, -111, -111, -111, -111, 70, + -111, -111, -111, -8, -111, -111, -6, -28, 12, 84, + 85, -111, 93, 100, -111, -111, -111, 101, 104, -111, + -111, -111, -111, -111, -111, 107, -111, 112, 118, -111, + 182, 184, -111, -111, -111, -111, 218, 215, 209, -111, + -111, -111, -111, 202, -111, 195, 193, 192, 191, -111, + 189, 183, 181, 175, 168, 155, -111, 170, 153, 150, -111, -111, -111, -111, -111, -111, -111, -111, -111, -111, - -111, 150, -111, 155, -111, 192, 4, -33, -111, -111, + -111, 151, -111, 142, -111, 172, 30, -4, -111, -111, -111, -111, -111, -111, -111, -111, -111, -111, -111, -111, -111, -111, -111, -111, -111, -111, -111, -111, -111, -111, -111, -111, -111, -111, -111, -111, -111, -111, -111, -111, - -111, -111, -111, -9, -111, -111, -111, -111, -111, 7, - -111, -111, 40, -111, -111, -111, -111, -111, -111, -111, - -111, -111, -111, -111, -111, -111, 99, -111, 52, 31, - -111, -111, 30, -111, 253, 44, 87, -111, -111, -111, - -111, -111, -111, -111, 45, 86, -111, -111, -111, 41, - -111, -111, 5, -111, -111, -111, -111, -111, -111, -111, - 50, -111, -111, -111, -111, -111, -111, -111, -111, -111, - 154, -111, -111, 26, -111, 49, -111, 330, -111, 28, - -111, 248, 27, -111, -111, 124, 51, -111, -111, -111, - -111, -111, 46, -111, -111, -111, -111, -111, 196, -111, - -111, 185, -111, -111, -111, 194, -111, -111, -111, -111, + -111, -111, -111, -111, -2, -111, -111, -111, -111, -111, + 0, -111, -111, 9, -111, -111, -111, -111, -111, -111, + -111, -111, -111, -111, -111, -111, -111, 125, -111, 122, + 10, -111, -111, 22, -111, 236, 46, 127, -111, -111, + -111, -111, -111, -111, -111, 37, 124, -111, -111, -111, + 39, -111, -111, 42, -111, -111, -111, -111, -111, -111, + -111, 44, -111, -111, -111, -111, -111, -111, -111, -111, + -111, 94, -111, -111, 47, -111, 48, -111, 128, -111, + 50, -111, 91, -111, -3, -111, -111, 66, 53, -111, + -111, -111, -111, -111, 57, -111, -111, -111, -111, -111, + 79, -111, -111, 78, -111, -111, -111, 82, -111, -111, -111, -111, -111, -111, -111, -111, -111, -111, -111, -111, - -111, -111, 15, -111, -111, -111, -111, -111, 74, -111, + -111, -111, -111, -111, 67, -111, -111, -111, -111, -111, + 61, -111, -111, -111, -111, -111, -111, -111, -111, -111, + -111, -111, -111, -111, 59, 258, -111, 259, 268, 269, + 272, -111, 60, 63, 73, 74, 75, -111, -111, -111, + -111, -111, -111, -111, -111, 252, -111, 242, -111, 233, + -111, -111, 232, -111, 87, -111, -111, 89, -111, 133, + -111, 51, -111, 135, -111, 231, -111, 223, 222, -111, + -111, 221, -111, -111, -111, -111, -111, -111, 219, -111, + 92, 102, -111, -111, 110, -111, 171, -111, 40, -111, + 173, -111, 38, -111, 176, -111, 179, -111, -111, -111, + -111, -111, -111, -111, -111, 180, -111, 19, -111, 18, + -111, 145, 185, -111, -111, 17, 166, -111, -111, 65, + -111, -111, 29, 177, -111, -111, -111, 25, -111, 5, + 159, -111, 164, -111, -111, 207, -111, -111, -111, -111, + -111, -111, -18, -111, -111, -111, -111, -111, -111, 212, + -111, -111, -111, -111, 216, -111, -111, -111, -111, -111, + -111, 213, -111, -111, 86, -111, -111, 16, -111, -111, + -111, -111, -111, -85, -111, 14, -111, -84, -111, -111, + -111, -111, 286, -111, -111, 287, -111, -111, -111, -111, + -111, 214, -94, -111, -111, -16, -111, -10, -111, -19, + -111, -111, -111, -111, 2, -111, 83, -111, 105, -111, + 81, -111, -111, -111, -111, -111, -111, -41, -111, -111, + 131, -111, -111, -111, -111, 76, -111, -111, -111, -111, + -35, -111, -111, 64, -111, -111, -29, -111, -111, -111, -111, -111, -111, -111, -111, -111, -111, -111, -111, -111, - -111, -111, -16, 230, -111, 233, 269, 251, 265, -111, - 80, 81, 82, 88, 89, -111, -111, -111, -111, -111, - -111, -111, -111, 216, -111, 255, -111, 259, -111, -111, - 223, -111, 68, -111, -111, 217, -111, 236, -111, 24, - -111, 244, -111, 227, -111, 226, 257, -111, -111, 263, - -111, -111, -111, -111, -111, -111, 249, -111, 113, 163, - -111, -111, 212, -111, 173, -111, 48, -111, 211, -111, - 53, -111, 206, -111, 204, -111, -111, -111, -111, -111, - -111, -111, -111, 199, -111, 23, -111, 25, -111, 134, - 175, -111, -111, 37, 200, -111, 222, -111, -111, 57, - 56, -111, -111, -111, 124, -111, 32, 43, -111, 105, - -111, -111, 139, -111, -111, -111, -111, -111, -111, 38, - -111, -111, -111, -111, -111, -111, 75, -111, -111, -111, - -111, 71, -111, -111, -111, -111, -111, -111, 72, -111, - -111, 85, -111, -111, 59, -111, -111, -111, -111, -111, - -37, -111, 62, -111, -58, -111, -111, -111, -111, 286, - -111, -111, 250, -111, -111, -111, -111, -111, 153, -57, - -111, -111, 33, -111, 34, -111, 36, -111, -111, -111, - -111, 47, -111, 77, -111, 29, -111, 67, -111, -111, - -111, -111, -111, -111, 42, -111, -111, 214, -111, -111, - -111, -111, 229, -111, -111, -111, -111, 35, -111, -111, - 145, -111, -111, 3, -111, -111, -111, -111, -111, -111, + -111, -111, -111, 208, -111, -111, -111, -111, -111, 20, + -111, -111, -111, -111, -111, -111, -111, 13, -111, -111, + -111, 26, 15, -111, -111, -111, 32, -111, -111, -111, + -111, -111, -111, 329, -111, -111, -111, -111, -111, -111, + -111, -111, -111, -111, -111, 54, 56, -111, 58, -111, + -111, -111, -111, 68, -111, -111, -111, 72, -111, -111, + 330, -111, -111, -111, 327, -111, -111, -111, -111, 389, + -111, -111, 52, -111, -111, 31, 49, -111, 371, -111, + 134, 34, -111, -111, 43, -111, 41, -111, 108, 141, + -111, -111, 35, -111, -111, 97, -111, -111, 45, -111, + -111, -111, 36, -111, 21, 129, -111, 146, -111, -111, + -111, -111, -111, -1, -111, -111, -111, 11, -5, 7, + -111, -111, -111, -111, -111, 353, 311, 408, 4, -111, + -111, -111, -111, 1, -111, -111, 8, 6, 249, 248, -111, -111, -111, -111, -111, -111, -111, -111, -111, -111, - 207, -111, -111, -111, -111, -111, 39, -111, -111, -111, - -111, -111, -111, -111, -24, -111, -111, -111, -12, -27, - -111, -111, -111, -14, -111, -111, -111, -111, -111, -111, - 333, -111, -111, -111, -111, -111, -111, -111, -111, -111, - -111, -111, 6, 22, -111, 20, -111, -111, -111, -111, - 159, -111, -111, -111, 246, -111, -111, 332, -111, -111, - -111, 436, -111, -111, -111, -111, 388, -111, -111, 18, - -111, -111, -6, 19, -111, 352, -111, 225, 14, -111, - -111, 13, -111, 11, -111, 167, 136, -111, -111, 10, - -111, 64, -111, -111, 9, -111, -111, -111, 124, -111, - 0, 69, -111, 60, -111, -111, -111, -111, -111, -10, - -111, -111, -111, -1, -11, -2, -111, -111, -111, -111, - -111, 370, 142, 315, -3, -111, -111, -111, -111, 17, - -111, -111, -13, 21, 133, 221, -111, -111, -111, -111, - -111, -111, -111, -111, -111, -111, -111, -111, -111, 16, - -111, -111, -111, -111, -111, -111, -15, -111, -111, -111, - -111, -111, -111, -111, -111}; + -111, -111, -111, 3, -111, -111, -111, -111, -111, -111, + -14, -111, -111, -111, -111, -111, -111, -111, -111}; const short QQmlJSGrammar::action_info [] = { - -145, 398, 101, 244, 438, 402, 465, 245, 461, 567, - 423, 439, -126, 421, 553, -126, -145, 342, 344, 420, - 185, 245, 567, 392, 418, 585, 354, 73, 268, 181, - 245, 465, 166, 101, 172, 350, 432, 184, 268, 461, - 103, 432, 404, 405, 406, 428, 408, 413, -142, 424, - 560, -139, 448, -137, -115, 567, 424, -116, -134, 261, - 350, 448, 143, 432, 283, 624, 448, 481, 534, 103, - 262, 192, 474, 149, 529, 305, 567, 456, 482, 189, - 283, 191, 323, 307, -137, 627, 567, 484, 303, 151, - 617, 166, -115, 323, 329, 424, 238, -116, 336, 399, - 241, 524, -134, 312, 303, 346, 268, 73, 350, 448, - 143, -142, 240, 452, 465, 582, 448, -139, 461, 243, - 454, 143, 317, 143, 174, 0, 60, 305, 490, 315, - 665, 664, 435, 143, 257, 256, 60, 61, 143, 532, - 60, 60, 143, 175, 143, 64, 451, 61, 533, 671, - 670, 61, 61, 442, 143, 143, 65, 338, 537, 536, - 452, 143, 143, 564, 143, 174, 416, 415, 629, 628, - 564, 477, 174, 501, 0, 426, 491, 436, 673, 672, - 259, 258, 259, 258, 175, 467, 179, 252, 251, 642, - 643, 175, 144, 325, 463, 532, 530, 326, 674, 642, - 643, 168, 259, 258, 555, 169, 87, 321, 88, 66, - 339, 637, 530, 348, 352, 87, 264, 88, 565, 89, - 87, 87, 88, 88, 478, 476, 66, 174, 89, 267, - 265, 66, 525, 89, 89, 551, 631, 0, 87, 558, - 88, 619, 527, 143, 530, 143, 175, 0, 176, 105, - 87, 89, 88, 526, 67, 576, 0, 266, 527, 540, - 68, 0, 567, 89, 174, 530, 620, 618, 106, 526, - 107, 67, 530, 0, 0, 0, 67, 68, 527, 0, - 0, 527, 68, 175, 174, 411, 0, 668, 667, 526, - 527, 0, 526, 559, 557, 0, 446, 445, 236, 235, - 0, 526, 0, 175, 87, 411, 88, 174, 0, 577, - 575, 527, 0, 541, 539, 75, 76, 89, 527, 666, - 174, 0, 526, 632, 0, -102, 175, 0, 176, 526, - 285, 286, 75, 76, 285, 286, 661, 0, -102, 175, - 0, 176, 77, 78, 6, 5, 4, 1, 3, 2, - 662, 660, 0, 0, 290, 291, 0, 287, 288, 77, - 78, 287, 288, 292, 290, 291, 293, 0, 294, 0, - 0, 0, 0, 292, 290, 291, 293, 0, 294, 0, - 290, 291, 659, 292, 0, 87, 293, 88, 294, 292, - 0, 0, 293, 35, 294, 80, 81, 0, 89, 0, - 0, 0, 0, 82, 83, 80, 81, 84, 0, 85, - 0, 0, 0, 82, 83, 80, 81, 84, 35, 85, - 0, 0, 0, 82, 83, 80, 81, 84, 0, 85, - 49, 52, 50, 82, 83, 80, 81, 84, 0, 85, - 0, 0, 0, 82, 83, 0, 0, 84, 0, 85, - 35, 0, 0, 35, 0, 49, 52, 50, 46, 34, - 51, 35, 0, 0, 35, 0, 290, 291, 35, 0, - 0, 35, 532, 0, 35, 292, 0, 0, 293, 0, - 294, 184, 0, 46, 34, 51, 35, 49, 52, 50, + 309, 314, 152, 150, 101, 73, 678, 167, 487, 103, + 485, 73, 484, 101, 173, 103, 527, 182, 477, 144, + 186, 585, 621, 190, 192, 532, 459, 451, 307, 193, + 285, 451, 167, 457, 455, 246, 144, 307, 247, 317, + 441, 319, 537, 442, 435, 285, 435, 305, 305, 570, + 570, 435, 331, 431, 338, 556, 348, 270, 426, 628, + 424, -142, 631, 263, -139, 451, -137, 247, 423, 264, + 344, 468, 346, -115, 464, 395, 421, 356, 185, 352, + 402, 401, 563, 427, -116, -134, -146, -145, 352, 245, + -126, 270, -126, -145, 270, -146, 247, -134, 427, 325, + 352, -116, 570, -115, 405, 588, 427, -139, 411, 451, + 416, -142, 0, 144, 570, 144, 242, 64, 464, 0, + 468, 493, 0, 408, 409, 243, 675, 674, 65, 240, + 567, 407, 144, 0, 451, 468, 144, 327, 464, 0, + 144, 328, 144, 60, 535, 144, 175, 144, 60, 144, + 340, 0, 0, 558, 61, 175, 0, 438, 175, 61, + 567, 145, 169, 646, 647, 176, 170, 504, 144, 494, + 261, 260, 669, 668, 176, 261, 260, 176, 568, 254, + 253, 419, 418, 144, 354, 60, 259, 258, 350, 60, + 180, 543, 470, 454, 633, 632, 61, 266, 175, 466, + 61, 429, 439, 341, -137, 261, 260, 455, 641, 677, + 676, 646, 647, 535, 540, 539, 66, 176, 533, 177, + 323, 144, 536, 175, 533, 87, 66, 88, 87, 0, + 88, 579, 175, 66, 533, 528, 449, 448, 89, 635, + 0, 89, 176, 0, 414, 544, 542, 87, 533, 88, + 87, 176, 88, 414, 269, 267, 87, 533, 88, 480, + 89, 67, 0, 89, 530, 570, 87, 68, 88, 89, + 530, 67, 554, 0, 238, 237, 529, 68, 67, 89, + 530, 530, 529, 268, 68, 580, 578, 87, 87, 88, + 88, 623, 529, 529, 530, 87, 87, 88, 88, 561, + 89, 89, 105, 530, 445, 144, 529, 0, 89, 89, + 672, 671, 481, 479, 0, 529, 624, 622, 530, 175, + 87, 106, 88, 107, 75, 76, 175, 636, 75, 76, + 529, 287, 288, 89, 287, 288, 0, -102, 176, 0, + 177, 0, 0, 670, -102, 176, 0, 177, 0, 665, + 0, 77, 78, 562, 560, 77, 78, 0, 289, 290, + 0, 289, 290, 666, 664, 292, 293, 0, 0, 292, + 293, 0, 0, 0, 294, 292, 293, 295, 294, 296, + 0, 295, 35, 296, 294, 292, 293, 295, 35, 296, + 0, 292, 293, 35, 294, 0, 663, 295, 35, 296, + 294, 35, 0, 295, 87, 296, 88, 6, 5, 4, + 1, 3, 2, 0, 35, 0, 0, 89, 0, 49, + 52, 50, 0, 0, 0, 49, 52, 50, 0, 0, + 49, 52, 50, 0, 0, 49, 52, 50, 49, 52, + 50, 0, 0, 0, 0, 0, 35, 0, 46, 34, + 51, 49, 52, 50, 46, 34, 51, 0, 0, 46, + 34, 51, 0, 0, 46, 34, 51, 46, 34, 51, + 35, 0, 0, 0, 0, 0, 0, 0, 35, 0, + 46, 34, 51, 49, 52, 50, 80, 81, 35, 0, + 0, 35, 0, 0, 82, 83, 35, 0, 84, 0, + 85, 0, 0, 185, 0, 0, 0, 49, 52, 50, + 0, 35, 46, 34, 51, 49, 52, 50, 185, 0, + 0, 0, 0, 0, 0, 49, 52, 50, 49, 52, + 50, 0, 0, 49, 52, 50, 46, 34, 51, 535, + 0, 0, 0, 0, 46, 34, 51, 535, 49, 52, + 50, 0, 0, 35, 46, 34, 51, 46, 34, 51, + 0, 35, 46, 34, 51, 35, 0, 0, 0, 0, + 35, 0, 185, 35, 0, 0, 0, 46, 34, 51, + 0, 0, 0, 0, 0, 35, 0, 0, 0, 0, 49, 52, 50, 0, 0, 0, 0, 0, 49, 52, - 50, 49, 52, 50, 0, 49, 52, 50, 49, 52, - 50, 49, 52, 50, 0, 46, 34, 51, 46, 34, - 51, 0, 0, 49, 52, 50, 46, 34, 51, 46, - 34, 51, 532, 46, 34, 51, 46, 34, 51, 46, - 34, 51, 0, 35, 0, 0, 35, 0, 0, 35, - 184, 46, 34, 51, 35, 0, 0, 35, 0, 0, - 0, 184, 0, 0, 0, 35, 0, 0, 35, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 49, 52, 50, 49, 52, 50, 49, 52, 50, 255, - 254, 49, 52, 50, 49, 52, 50, 255, 254, 0, - 250, 249, 49, 52, 50, 49, 52, 50, 46, 34, - 51, 46, 34, 51, 46, 34, 51, 35, 0, 46, - 34, 51, 46, 34, 51, 35, 532, 0, 35, 0, - 46, 34, 51, 46, 34, 51, 0, 0, 0, 0, - 35, 0, 0, 0, 0, 0, 0, 0, 0, 255, - 254, 0, 0, 0, 49, 52, 50, 250, 249, 0, - 250, 249, 49, 52, 50, 49, 52, 50, 0, 0, - 0, 0, 0, 0, 0, 153, 0, 49, 52, 50, - 0, 0, 46, 34, 51, 154, 0, 0, 0, 155, - 46, 34, 51, 46, 34, 51, 0, 0, 156, 0, - 157, 0, 0, 319, 0, 46, 34, 51, 0, 0, - 0, 158, 0, 159, 64, 0, 0, 153, 0, 0, - 0, 160, 0, 0, 161, 65, 0, 154, 0, 0, - 162, 155, 0, 0, 0, 0, 163, 0, 0, 0, - 156, 0, 157, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 164, 158, 0, 159, 64, 0, 0, 0, - 0, 0, 0, 160, 0, 0, 161, 65, 0, 0, - 0, 0, 162, 0, 0, 0, 0, 0, 163, 0, + 50, 0, 49, 52, 50, 252, 251, 49, 52, 50, + 49, 52, 50, 0, 0, 0, 0, 257, 256, 46, + 34, 51, 49, 52, 50, 0, 35, 46, 34, 51, + 0, 46, 34, 51, 0, 0, 46, 34, 51, 46, + 34, 51, 35, 0, 0, 35, 0, 0, 535, 0, + 0, 46, 34, 51, 0, 0, 0, 0, 257, 256, + 0, 0, 35, 49, 52, 50, 0, 0, 0, 0, + 0, 0, 0, 0, 252, 251, 0, 252, 251, 49, + 52, 50, 49, 52, 50, 0, 0, 0, 0, 0, + 0, 0, 46, 34, 51, 0, 0, 0, 0, 49, + 52, 50, 0, 0, 0, 0, 0, 0, 46, 34, + 51, 46, 34, 51, 0, 0, 0, 0, 0, 0, + 0, 154, 0, 0, 0, 0, 0, 0, 46, 34, + 51, 155, 0, 0, 0, 156, 0, 0, 0, 0, + 35, 0, 0, 0, 157, 0, 158, 0, 0, 321, + 0, 0, 0, 0, 0, 0, 0, 159, 0, 160, + 64, 0, 0, 0, 0, 0, 0, 161, 0, 0, + 162, 65, 257, 256, 0, 0, 163, 49, 52, 50, + 0, 0, 164, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 165, 0, + 0, 0, 0, 0, 0, 0, 46, 34, 51, 0, + 0, 0, 0, 0, 0, 0, 30, 31, 154, 0, + 0, 0, 0, 0, 0, 0, 33, 0, 155, 0, + 0, 0, 156, 35, 0, 0, 0, 36, 37, 0, + 38, 157, 0, 158, 0, 0, 0, 42, 0, 0, + 0, 45, 0, 0, 159, 0, 160, 64, 0, 0, + 0, 0, 0, 0, 161, 0, 0, 162, 65, 53, + 49, 52, 50, 163, 54, 0, 0, 0, 0, 164, + 0, 0, 0, 0, 0, 44, 56, 32, 0, 0, + 0, 0, 41, 0, 0, 165, 0, 0, 0, 46, + 34, 51, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 164, 0, 0, 0, 0, 0, + 0, 0, 30, 31, 0, 0, 0, 0, 0, 0, + 0, 0, 33, 0, 0, 0, 0, 0, 0, 35, + 0, 0, 0, 36, 37, 0, 38, 0, 0, 0, + 0, 0, 0, 519, 0, 0, 0, 45, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 53, 49, 52, 50, 0, + 54, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 44, 56, 32, 0, 0, 0, 0, 41, 0, + 0, 0, 0, 0, 0, 46, 34, 51, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 30, 31, 0, + 0, 0, 0, 0, 0, 0, 0, 33, 0, 0, + 0, 0, 0, 0, 35, 0, 0, 0, 36, 37, + 0, 38, 0, 0, 0, 0, 0, 0, 42, 0, + 0, 0, 45, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 30, 31, 0, 0, 0, 0, 0, 0, 0, 0, - 33, 0, 0, 0, 0, 0, 0, 35, 0, 0, - 0, 36, 37, 0, 38, 0, 0, 0, 0, 0, - 0, 516, 0, 0, 0, 45, 0, 0, 0, 0, + 53, 49, 52, 50, 0, 54, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 44, 56, 32, 0, + 0, 0, 0, 41, 0, 0, 0, 0, 0, 0, + 46, 34, 51, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 518, 0, 30, 31, 0, 0, 0, 0, + 0, 0, 0, 0, 220, 0, 0, 0, 0, 0, + 0, 35, 0, 0, 0, 36, 37, 0, 38, 0, + 0, 0, 0, 0, 0, 519, 0, 0, 0, 45, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 53, 49, 52, 50, 0, 54, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 44, - 56, 32, 0, 0, 0, 41, 0, 0, 0, 0, - 0, 0, 46, 34, 51, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 30, 31, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 53, 520, 522, + 521, 0, 54, 0, 0, 0, 0, 229, 0, 0, + 0, 0, 0, 44, 56, 32, 215, 223, 0, 0, + 41, 0, 0, 0, 0, 0, 0, 46, 34, 51, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 518, + 0, 30, 31, 0, 0, 0, 0, 0, 0, 0, + 0, 220, 0, 0, 0, 0, 0, 0, 35, 0, + 0, 0, 36, 37, 0, 38, 0, 0, 0, 0, + 0, 0, 519, 0, 0, 0, 45, 0, 0, 0, + 0, 0, 0, 0, 575, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 53, 520, 522, 521, 0, 54, + 0, 0, 0, 0, 229, 0, 0, 0, 0, 0, + 44, 56, 32, 215, 223, 0, 0, 41, 0, 0, + 0, 0, 0, 0, 46, 34, 51, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 518, 0, 30, 31, + 0, 0, 0, 0, 0, 0, 0, 0, 220, 0, + 0, 0, 0, 0, 0, 35, 0, 0, 0, 36, + 37, 0, 38, 0, 0, 0, 0, 0, 0, 519, + 0, 0, 0, 45, 0, 0, 0, 0, 0, 0, + 0, 572, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 53, 520, 522, 521, 0, 54, 0, 0, 0, + 0, 229, 0, 0, 0, 0, 0, 44, 56, 32, + 215, 223, 0, 0, 41, 0, 0, 0, 0, 0, + 0, 46, 34, 51, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 29, 30, 31, 0, 0, 0, 0, 0, 0, 0, 0, 33, 0, 0, 0, 0, 0, 0, 35, 0, 0, 0, 36, 37, 0, 38, 0, - 0, 0, 0, 0, 0, 42, 0, 0, 0, 45, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 39, 0, 40, 42, 43, 0, 0, 45, + 0, 0, 0, 47, 0, 48, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 53, 49, 52, - 50, 0, 54, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 44, 56, 32, 0, 0, 0, 41, - 0, 0, 0, 0, 0, 0, 46, 34, 51, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 515, 0, + 50, 0, 54, 0, 55, 0, 57, 0, 58, 0, + 0, 0, 0, 44, 56, 32, 0, 0, 0, 0, + 41, 0, 0, 0, 0, 0, 0, 46, 34, 51, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 29, 30, 31, 0, 0, 0, 0, 0, 0, 0, 0, - 219, 0, 0, 0, 0, 0, 0, 35, 0, 0, - 0, 36, 37, 0, 38, 0, 0, 0, 0, 0, - 0, 516, 0, 0, 0, 45, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 53, 517, 519, 518, 0, 54, 0, - 0, 0, 0, 227, 0, 0, 0, 0, 0, 44, - 56, 32, 214, 0, 0, 41, 0, 0, 0, 0, - 0, 0, 46, 34, 51, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 515, 0, 30, 31, 0, 0, - 0, 0, 0, 0, 0, 0, 219, 0, 0, 0, - 0, 0, 0, 35, 0, 0, 0, 36, 37, 0, - 38, 0, 0, 0, 0, 0, 0, 516, 0, 0, - 0, 45, 0, 0, 0, 0, 0, 0, 0, 572, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 53, - 517, 519, 518, 0, 54, 0, 0, 0, 0, 227, - 0, 0, 0, 0, 0, 44, 56, 32, 214, 0, - 0, 41, 0, 0, 0, 0, 0, 0, 46, 34, - 51, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 515, 0, 30, 31, 0, 0, 0, 0, 0, 0, - 0, 0, 219, 0, 0, 0, 0, 0, 0, 35, - 0, 0, 0, 36, 37, 0, 38, 0, 0, 0, - 0, 0, 0, 516, 0, 0, 0, 45, 0, 0, - 0, 0, 0, 0, 0, 569, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 53, 517, 519, 518, 0, - 54, 0, 0, 0, 0, 227, 0, 0, 0, 0, - 0, 44, 56, 32, 214, 0, 0, 41, 0, 0, - 0, 0, 0, 0, 46, 34, 51, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 29, 30, 31, 0, - 0, 0, 0, 0, 0, 0, 0, 33, 0, 0, - 0, 0, 0, 0, 35, 0, 0, 0, 36, 37, - 0, 38, 0, 0, 0, 39, 0, 40, 42, 43, - 0, 0, 45, 0, 0, 0, 47, 0, 48, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 53, 49, 52, 50, 0, 54, 0, 55, 0, 57, - 0, 58, 0, 0, 0, 0, 44, 56, 32, 0, - 0, 0, 41, 0, 0, 0, 0, 0, 0, 46, - 34, 51, 0, 0, 0, 0, 0, 0, 0, 0, - 0, -135, 0, 0, 0, 29, 30, 31, 0, 0, - 0, 0, 0, 0, 0, 0, 33, 0, 0, 0, - 0, 0, 0, 35, 0, 0, 0, 36, 37, 0, - 38, 0, 0, 0, 39, 0, 40, 42, 43, 0, - 0, 45, 0, 0, 0, 47, 0, 48, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 53, - 49, 52, 50, 0, 54, 0, 55, 0, 57, 0, - 58, 0, 0, 0, 0, 44, 56, 32, 0, 0, - 0, 41, 0, 0, 0, 0, 0, 0, 46, 34, - 51, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 29, 30, 31, 0, 0, 0, 0, 0, 0, 0, - 0, 33, 0, 0, 0, 0, 0, 0, 35, 0, - 0, 0, 36, 37, 0, 38, 0, 0, 0, 39, - 0, 40, 42, 43, 0, 0, 45, 0, 0, 0, - 47, 0, 48, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 53, 49, 52, 50, 0, 54, - 0, 55, 0, 57, 282, 58, 0, 0, 0, 0, - 44, 56, 32, 0, 0, 0, 41, 0, 0, 0, + 33, 0, 0, 0, 0, 0, 0, 35, 0, 0, + 0, 36, 37, 0, 38, 0, 0, 0, 39, 0, + 40, 42, 43, 0, 0, 45, 0, 0, 0, 47, + 0, 48, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 53, 49, 52, 50, 0, 54, 0, + 55, 0, 57, 284, 58, 0, 0, 0, 0, 44, + 56, 32, 0, 0, 0, 0, 41, 0, 0, 0, + 0, 0, 0, 46, 34, 51, 0, 0, 0, 0, + 0, 0, 0, 0, 0, -135, 0, 0, 0, 29, + 30, 31, 0, 0, 0, 0, 0, 0, 0, 0, + 33, 0, 0, 0, 0, 0, 0, 35, 0, 0, + 0, 36, 37, 0, 38, 0, 0, 0, 39, 0, + 40, 42, 43, 0, 0, 45, 0, 0, 0, 47, + 0, 48, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 53, 49, 52, 50, 0, 54, 0, + 55, 0, 57, 0, 58, 0, 0, 0, 0, 44, + 56, 32, 0, 0, 0, 0, 41, 0, 0, 0, 0, 0, 0, 46, 34, 51, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 488, 0, 0, 29, 30, + 0, 0, 0, 0, 0, 499, 0, 0, 29, 30, 31, 0, 0, 0, 0, 0, 0, 0, 0, 33, 0, 0, 0, 0, 0, 0, 35, 0, 0, 0, 36, 37, 0, 38, 0, 0, 0, 39, 0, 40, 42, 43, 0, 0, 45, 0, 0, 0, 47, 0, - 48, 0, 0, 494, 0, 0, 0, 0, 0, 0, + 48, 0, 0, 500, 0, 0, 0, 0, 0, 0, 0, 0, 53, 49, 52, 50, 0, 54, 0, 55, 0, 57, 0, 58, 0, 0, 0, 0, 44, 56, - 32, 0, 0, 0, 41, 0, 0, 0, 0, 0, + 32, 0, 0, 0, 0, 41, 0, 0, 0, 0, + 0, 0, 46, 34, 51, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 491, 0, 0, 29, 30, 31, + 0, 0, 0, 0, 0, 0, 0, 0, 33, 0, + 0, 0, 0, 0, 0, 35, 0, 0, 0, 36, + 37, 0, 38, 0, 0, 0, 39, 0, 40, 42, + 43, 0, 0, 45, 0, 0, 0, 47, 0, 48, + 0, 0, 492, 0, 0, 0, 0, 0, 0, 0, + 0, 53, 49, 52, 50, 0, 54, 0, 55, 0, + 57, 0, 58, 0, 0, 0, 0, 44, 56, 32, + 0, 0, 0, 0, 41, 0, 0, 0, 0, 0, 0, 46, 34, 51, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 488, 0, 0, 29, 30, 31, 0, + 0, 0, 0, 491, 0, 0, 29, 30, 31, 0, 0, 0, 0, 0, 0, 0, 0, 33, 0, 0, 0, 0, 0, 0, 35, 0, 0, 0, 36, 37, 0, 38, 0, 0, 0, 39, 0, 40, 42, 43, 0, 0, 45, 0, 0, 0, 47, 0, 48, 0, - 0, 489, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 497, 0, 0, 0, 0, 0, 0, 0, 0, 53, 49, 52, 50, 0, 54, 0, 55, 0, 57, 0, 58, 0, 0, 0, 0, 44, 56, 32, 0, - 0, 0, 41, 0, 0, 0, 0, 0, 0, 46, - 34, 51, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 496, 0, 0, 29, 30, 31, 0, 0, 0, - 0, 0, 0, 0, 0, 33, 0, 0, 0, 0, - 0, 0, 35, 0, 0, 0, 36, 37, 0, 38, - 0, 0, 0, 39, 0, 40, 42, 43, 0, 0, - 45, 0, 0, 0, 47, 0, 48, 0, 0, 499, - 0, 0, 0, 0, 0, 0, 0, 0, 53, 49, - 52, 50, 0, 54, 0, 55, 0, 57, 0, 58, - 0, 0, 0, 0, 44, 56, 32, 0, 0, 0, - 41, 0, 0, 0, 0, 0, 0, 46, 34, 51, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 496, - 0, 0, 29, 30, 31, 0, 0, 0, 0, 0, - 0, 0, 0, 33, 0, 0, 0, 0, 0, 0, - 35, 0, 0, 0, 36, 37, 0, 38, 0, 0, - 0, 39, 0, 40, 42, 43, 0, 0, 45, 0, - 0, 0, 47, 0, 48, 0, 0, 497, 0, 0, - 0, 0, 0, 0, 0, 0, 53, 49, 52, 50, - 0, 54, 0, 55, 0, 57, 0, 58, 0, 0, - 0, 0, 44, 56, 32, 0, 0, 0, 41, 0, - 0, 0, 0, 0, 0, 46, 34, 51, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 29, 30, 31, - 0, 0, 0, 0, 0, 0, 0, 0, 33, 0, - 0, 0, 0, 0, 0, 35, 220, 0, 0, 587, - 633, 0, 38, 0, 0, 0, 39, 0, 40, 42, - 43, 0, 0, 45, 0, 0, 0, 47, 0, 48, - 0, 0, 0, 0, 0, 0, 0, 223, 0, 0, - 0, 53, 49, 52, 50, 224, 54, 0, 55, 226, - 57, 0, 58, 0, 229, 0, 0, 44, 56, 32, 0, 0, 0, 41, 0, 0, 0, 0, 0, 0, 46, 34, 51, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 29, 30, 31, 0, 0, 0, 0, 0, - 0, 0, 0, 33, 0, 0, 0, 0, 0, 0, - 35, 220, 0, 0, 221, 37, 0, 38, 0, 0, - 0, 39, 0, 40, 42, 43, 0, 0, 45, 0, - 0, 0, 47, 0, 48, 0, 0, 0, 0, 0, - 0, 0, 223, 0, 0, 0, 53, 49, 52, 50, - 224, 54, 0, 55, 226, 57, 0, 58, 0, 229, - 0, 0, 44, 56, 32, 0, 0, 0, 41, 0, + 0, 0, 499, 0, 0, 29, 30, 31, 0, 0, + 0, 0, 0, 0, 0, 0, 33, 0, 0, 0, + 0, 0, 0, 35, 0, 0, 0, 36, 37, 0, + 38, 0, 0, 0, 39, 0, 40, 42, 43, 0, + 0, 45, 0, 0, 0, 47, 0, 48, 0, 0, + 502, 0, 0, 0, 0, 0, 0, 0, 0, 53, + 49, 52, 50, 0, 54, 0, 55, 0, 57, 0, + 58, 0, 0, 0, 0, 44, 56, 32, 0, 0, + 0, 0, 41, 0, 0, 0, 0, 0, 0, 46, + 34, 51, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 29, 30, 31, 0, 0, 0, 0, 0, 0, + 0, 0, 33, 0, 0, 0, 0, 0, 0, 35, + 221, 0, 0, 222, 37, 0, 38, 0, 0, 0, + 39, 0, 40, 42, 43, 0, 0, 45, 0, 0, + 0, 47, 0, 48, 0, 0, 0, 0, 0, 0, + 0, 225, 0, 0, 0, 53, 49, 52, 50, 226, + 54, 0, 55, 228, 57, 0, 58, 0, 231, 0, + 0, 44, 56, 32, 0, 0, 0, 0, 41, 0, 0, 0, 0, 0, 0, 46, 34, 51, 0, 0, 0, 0, 0, 0, 0, 0, 0, 29, 30, 31, 0, 0, 0, 0, 0, 0, 0, 0, 33, 0, - 0, 0, 0, 0, 0, 35, 220, 0, 0, 587, + 0, 0, 0, 0, 0, 35, 221, 0, 0, 590, 37, 0, 38, 0, 0, 0, 39, 0, 40, 42, 43, 0, 0, 45, 0, 0, 0, 47, 0, 48, - 0, 0, 0, 0, 0, 0, 0, 223, 0, 0, - 0, 53, 49, 52, 50, 224, 54, 0, 55, 226, - 57, 0, 58, 0, 229, 0, 0, 44, 56, 32, - 0, 0, 0, 41, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 225, 0, 0, + 0, 53, 49, 52, 50, 226, 54, 0, 55, 228, + 57, 0, 58, 0, 231, 0, 0, 44, 56, 32, + 0, 0, 0, 0, 41, 0, 0, 0, 0, 0, + 0, 46, 34, 51, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 29, 30, 31, 0, 0, 0, 0, + 0, 0, 0, 0, 33, 0, 0, 0, 0, 0, + 0, 35, 221, 0, 0, 590, 637, 0, 38, 0, + 0, 0, 39, 0, 40, 42, 43, 0, 0, 45, + 0, 0, 0, 47, 0, 48, 0, 0, 0, 0, + 0, 0, 0, 225, 0, 0, 0, 53, 49, 52, + 50, 226, 54, 0, 55, 228, 57, 0, 58, 0, + 231, 0, 0, 44, 56, 32, 0, 0, 0, 0, + 41, 0, 0, 0, 0, 0, 0, 46, 34, 51, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 111, + 112, 113, 0, 0, 115, 117, 118, 0, 0, 119, + 0, 120, 0, 0, 0, 122, 123, 124, 0, 0, + 0, 0, 0, 0, 35, 125, 126, 127, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 129, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 132, 0, 0, 0, 0, 0, + 0, 49, 52, 50, 133, 134, 135, 0, 137, 138, + 139, 140, 141, 142, 0, 0, 130, 136, 121, 114, + 128, 116, 131, 0, 0, 0, 0, 0, 0, 0, 46, 34, 51, 0, 0, 0, 0, 0, 0, 0, 0, 0, 111, 112, 113, 0, 0, 115, 117, 118, 0, 0, 119, 0, 120, 0, 0, 0, 122, 123, 124, 0, 0, 0, 0, 0, 0, 35, 125, 126, 127, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 128, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 131, 0, 0, - 0, 0, 0, 0, 49, 52, 50, 132, 133, 134, - 0, 136, 137, 138, 139, 140, 141, 0, 0, 129, - 135, 121, 114, 116, 130, 0, 0, 0, 0, 0, - 0, 0, 46, 34, 51, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 111, 112, 113, 0, 0, 115, - 117, 118, 0, 0, 119, 0, 120, 0, 0, 0, - 122, 123, 124, 0, 0, 0, 0, 0, 0, 35, - 125, 126, 127, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 128, 0, 0, 0, 395, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 131, - 0, 0, 0, 0, 0, 397, 49, 52, 50, 132, - 133, 134, 0, 136, 137, 138, 139, 140, 141, 0, - 0, 129, 135, 121, 114, 116, 130, 0, 0, 0, - 0, 0, 0, 0, 46, 374, 380, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 111, 112, 113, 0, - 0, 115, 117, 118, 0, 0, 119, 0, 120, 0, - 0, 0, 122, 123, 124, 0, 0, 0, 0, 0, - 0, 35, 125, 126, 127, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 128, 0, 0, 0, 395, + 0, 129, 0, 0, 0, 398, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 132, 0, 0, + 0, 0, 0, 400, 49, 52, 50, 133, 134, 135, + 0, 137, 138, 139, 140, 141, 142, 0, 0, 130, + 136, 121, 114, 128, 116, 131, 0, 0, 0, 0, + 0, 0, 0, 46, 376, 383, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 111, 112, 113, 0, 0, + 115, 117, 118, 0, 0, 119, 0, 120, 0, 0, + 0, 122, 123, 124, 0, 0, 0, 0, 0, 0, + 35, 125, 126, 127, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 129, 0, 0, 0, 398, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 131, 0, 0, 0, 0, 0, 397, 49, 52, - 50, 132, 133, 134, 0, 136, 137, 138, 139, 140, - 141, 0, 0, 129, 135, 121, 114, 116, 130, 0, + 132, 0, 0, 0, 0, 0, 400, 49, 52, 50, + 133, 134, 135, 0, 137, 138, 139, 140, 141, 142, + 0, 0, 130, 136, 121, 114, 128, 116, 131, 0, 0, 0, 0, 0, 0, 0, 46, 34, 51, 0, 0, 0, 0, 0, 0, 0, 0, 0, 111, 112, 113, 0, 0, 115, 117, 118, 0, 0, 119, 0, 120, 0, 0, 0, 122, 123, 124, 0, 0, 0, 0, 0, 0, 35, 125, 126, 127, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 128, 0, 0, - 0, 395, 0, 0, 0, 0, 0, 0, 0, 396, - 0, 0, 0, 131, 0, 0, 0, 0, 0, 397, - 49, 52, 50, 132, 133, 134, 0, 136, 137, 138, - 139, 140, 141, 0, 0, 129, 135, 121, 114, 116, - 130, 0, 0, 0, 0, 0, 0, 0, 46, 374, - 380, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 213, 0, 0, 0, 0, 215, 0, 29, 30, 31, - 217, 0, 0, 0, 0, 0, 0, 218, 33, 0, - 0, 0, 0, 0, 0, 35, 220, 0, 0, 221, - 37, 0, 38, 0, 0, 0, 39, 0, 40, 42, - 43, 0, 0, 45, 0, 0, 0, 47, 0, 48, - 0, 0, 0, 0, 0, 222, 0, 223, 0, 0, - 0, 53, 49, 52, 50, 224, 54, 225, 55, 226, - 57, 227, 58, 228, 229, 0, 0, 44, 56, 32, - 214, 216, 0, 41, 0, 0, 0, 0, 0, 0, - 46, 34, 51, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 213, 0, 0, 0, 0, 215, 0, 29, - 30, 31, 217, 0, 0, 0, 0, 0, 0, 218, - 219, 0, 0, 0, 0, 0, 0, 35, 220, 0, - 0, 221, 37, 0, 38, 0, 0, 0, 39, 0, - 40, 42, 43, 0, 0, 45, 0, 0, 0, 47, - 0, 48, 0, 0, 0, 0, 0, 222, 0, 223, - 0, 0, 0, 53, 49, 52, 50, 224, 54, 225, - 55, 226, 57, 227, 58, 228, 229, 0, 0, 44, - 56, 32, 214, 216, 0, 41, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 129, 0, 0, + 0, 398, 0, 0, 0, 0, 0, 0, 0, 399, + 0, 0, 0, 132, 0, 0, 0, 0, 0, 400, + 49, 52, 50, 133, 134, 135, 0, 137, 138, 139, + 140, 141, 142, 0, 0, 130, 136, 121, 114, 128, + 116, 131, 0, 0, 0, 0, 0, 0, 0, 46, + 376, 383, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 214, 0, 0, 0, 0, 216, 0, 29, 30, + 31, 218, 0, 0, 0, 0, 0, 0, 219, 220, + 0, 0, 0, 0, 0, 0, 35, 221, 0, 0, + 222, 37, 0, 38, 0, 0, 0, 39, 0, 40, + 42, 43, 0, 0, 45, 0, 0, 0, 47, 0, + 48, 0, 0, 0, 0, 0, 224, 0, 225, 0, + 0, 0, 53, 49, 52, 50, 226, 54, 227, 55, + 228, 57, 229, 58, 230, 231, 0, 0, 44, 56, + 32, 215, 223, 217, 0, 41, 0, 0, 0, 0, 0, 0, 46, 34, 51, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 591, 112, 113, 0, 0, 593, - 117, 595, 30, 31, 596, 0, 120, 0, 0, 0, - 122, 598, 599, 0, 0, 0, 0, 0, 0, 35, - 600, 126, 127, 221, 37, 0, 38, 0, 0, 0, - 39, 0, 40, 601, 43, 0, 0, 603, 0, 0, - 0, 47, 0, 48, 0, 0, 0, 0, 0, 604, - 0, 223, 0, 0, 0, 605, 49, 52, 50, 606, - 607, 608, 55, 610, 611, 612, 613, 614, 615, 0, - 0, 602, 609, 597, 592, 594, 130, 41, 0, 0, - 0, 0, 0, 0, 46, 374, 380, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 365, 112, 113, 0, - 0, 367, 117, 369, 30, 31, 370, 0, 120, 0, - 0, 0, 122, 372, 373, 0, 0, 0, 0, 0, - 0, 35, 375, 126, 127, 221, 37, 0, 38, 0, - 0, 0, 39, 0, 40, 376, 43, 0, 0, 378, - 0, 0, 0, 47, 0, 48, 0, -281, 0, 0, - 0, 379, 0, 223, 0, 0, 0, 381, 49, 52, - 50, 382, 383, 384, 55, 386, 387, 388, 389, 390, - 391, 0, 0, 377, 385, 371, 366, 368, 130, 41, - 0, 0, 0, 0, 0, 0, 46, 374, 380, 0, - 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 214, 0, 0, 0, 0, 216, + 0, 29, 30, 31, 218, 0, 0, 0, 0, 0, + 0, 219, 33, 0, 0, 0, 0, 0, 0, 35, + 221, 0, 0, 222, 37, 0, 38, 0, 0, 0, + 39, 0, 40, 42, 43, 0, 0, 45, 0, 0, + 0, 47, 0, 48, 0, 0, 0, 0, 0, 224, + 0, 225, 0, 0, 0, 53, 49, 52, 50, 226, + 54, 227, 55, 228, 57, 229, 58, 230, 231, 0, + 0, 44, 56, 32, 215, 223, 217, 0, 41, 0, + 0, 0, 0, 0, 0, 46, 34, 51, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 594, 112, 113, + 0, 0, 596, 117, 598, 30, 31, 599, 0, 120, + 0, 0, 0, 122, 601, 602, 0, 0, 0, 0, + 0, 0, 35, 603, 126, 127, 222, 37, 0, 38, + 0, 0, 0, 39, 0, 40, 605, 43, 0, 0, + 607, 0, 0, 0, 47, 0, 48, 0, 0, 0, + 0, 0, 608, 0, 225, 0, 0, 0, 609, 49, + 52, 50, 610, 611, 612, 55, 614, 615, 616, 617, + 618, 619, 0, 0, 606, 613, 600, 595, 604, 597, + 131, 41, 0, 0, 0, 0, 0, 0, 46, 376, + 383, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 367, 112, 113, 0, 0, 369, 117, 371, 30, 31, + 372, 0, 120, 0, 0, 0, 122, 374, 375, 0, + 0, 0, 0, 0, 0, 35, 377, 126, 127, 222, + 37, 0, 38, 0, 0, 0, 39, 0, 40, 379, + 43, 0, 0, 381, 0, 0, 0, 47, 0, 48, + 0, -282, 0, 0, 0, 382, 0, 225, 0, 0, + 0, 384, 49, 52, 50, 385, 386, 387, 55, 389, + 390, 391, 392, 393, 394, 0, 0, 380, 388, 373, + 368, 378, 370, 131, 41, 0, 0, 0, 0, 0, + 0, 46, 376, 383, 0, 0, 0, 0, 0, 0, + 0, 0, 0, - 152, 652, 331, 669, 535, 531, 538, 142, 528, 148, - 641, 16, 313, 393, 485, 500, 626, 630, 263, 638, - 183, 625, 623, 206, 574, 447, 583, 320, 183, 253, - 313, 248, 466, 145, 663, 653, 616, 584, 556, 640, - 581, 248, 437, 253, 248, 495, 183, 178, 453, 150, - 462, 347, 455, 550, 554, 183, 351, 447, 458, 190, - 313, 457, 425, 188, 469, 441, 433, 253, 237, 468, - 0, 313, 173, 171, 393, 409, 447, 498, 409, 464, - 400, 0, 165, 206, 475, 206, 512, 511, 0, 0, - 188, 0, 0, 206, 0, 206, 0, 62, 0, 459, - 417, 206, 206, 206, 188, 0, 62, 0, 62, 62, - 507, 504, 410, 148, 62, 410, 460, 62, 419, 505, - 407, 412, 170, 62, 62, 459, 506, 444, 277, 148, - 422, 331, 187, 281, 62, 62, 62, 180, 260, 295, - 296, 297, 62, 62, 656, 655, 314, 298, 299, 62, - 62, 503, 182, 62, 206, 362, 514, 393, 247, 62, - 62, 460, 502, 62, 62, 639, 313, 167, 92, 99, - 62, 206, 206, 514, 510, 345, 100, 260, 562, 62, - 62, 62, 394, 493, 93, 94, 95, 492, 62, 62, - 182, 206, 62, 206, 96, 62, 246, 97, 62, 90, - 62, 401, 91, 206, 62, 86, 355, 340, 353, 62, - 108, 247, 206, 349, 188, 313, 102, 206, 393, 104, - 313, 62, 206, 182, 206, 206, 62, 362, 459, 206, - 242, 62, 469, 460, 62, 514, 409, 63, 318, 110, - 657, 341, 239, 590, 403, 62, 322, 206, 72, 62, - 362, 62, 362, 69, 206, 98, 62, 62, 70, 71, - 514, 0, 206, 62, 62, 566, 356, 0, 206, 79, - 62, 108, 74, 410, 483, 281, 0, 309, 0, 0, - 62, 62, 281, 304, 62, 281, 281, 62, 362, 281, - 343, 0, 281, 284, 289, 316, 324, 327, 0, 311, - 110, 177, 0, 309, 206, 62, 479, 0, 281, 62, - 281, 309, 301, 309, 281, 0, 281, 309, 281, 62, - 306, 0, 281, 62, 281, 337, 302, 0, 281, 578, - 300, 514, 260, 328, 562, 308, 636, 570, 443, 330, - 522, 0, 0, 0, 0, 0, 514, 0, 206, 0, - 0, 0, 513, 523, 0, 522, 0, 485, 542, 543, - 544, 545, 549, 546, 547, 0, 586, 513, 523, 0, - 0, 0, 0, 0, 440, 588, 589, 542, 543, 544, - 545, 549, 546, 547, 586, 0, 0, 0, 0, 0, - 0, 0, 0, 634, 635, 542, 543, 544, 545, 549, - 546, 547, 578, 0, 0, 0, 0, 0, 0, 0, - 0, 579, 580, 542, 543, 544, 545, 549, 546, 547, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 573, 0, 0, 0, 0, 0, 0, 0, 0, - 514, 0, 0, 0, 0, 0, 0, 0, 0, 522, + 315, 478, 645, 153, 673, 465, 460, 501, 458, 461, + 184, 456, 396, 498, 488, 503, 440, 444, 436, 428, + 657, 667, 656, 644, 403, 630, 642, 629, 447, 634, + 450, 627, 315, 143, 553, 184, 255, 250, 149, 447, + 146, 353, 151, 349, 541, 531, 450, 534, 315, 179, + 538, 166, 172, 184, 322, 189, 620, 191, 16, 255, + 207, 250, 239, 586, 174, 250, 255, 587, 184, 447, + 265, 0, 577, 515, 584, 472, 559, 333, 450, 412, + 207, 514, 517, 471, 248, 467, 517, 565, 557, 207, + 315, 569, 315, 364, 207, 207, 207, 189, 249, 207, + 207, 207, 496, 0, 207, 315, 495, 412, 469, 358, + 333, 412, 207, 315, 62, 279, 413, 62, 0, 297, + 283, 486, 298, 244, 62, 241, 183, 62, 62, 62, + 262, 425, 299, 300, 301, 320, 364, 324, 62, 62, + 505, 506, 189, 262, 413, 0, 207, 0, 413, 472, + 0, 207, 593, 207, 62, 62, 507, 508, 62, 207, + 509, 62, 62, 510, 183, 316, 62, 318, 462, 149, + 188, 513, 62, 347, 463, 351, 62, 181, 355, 62, + 343, 357, 404, 62, 396, 462, 342, 262, 345, 207, + 108, 207, 171, 168, 207, 396, 62, 207, 207, 62, + 62, 183, 463, 207, 62, 62, 104, 62, 92, 62, + 406, 91, 249, 62, 97, 462, 364, 102, 62, 110, + 463, 420, 62, 482, 62, 396, 207, 96, 90, 62, + 207, 189, 207, 0, 95, 62, 62, 62, 62, 63, + 94, 72, 93, 62, 0, 62, 62, 62, 86, 62, + 397, 100, 99, 98, 108, 79, 62, 410, 149, 422, + 660, 659, 517, 62, 74, 71, 415, 661, 0, 62, + 0, 70, 62, 311, 69, 311, 311, 62, 283, 0, + 283, 283, 283, 110, 178, 62, 311, 311, 364, 364, + 283, 283, 283, 517, 329, 339, 62, 332, 330, 0, + 326, 283, 525, 0, 207, 207, 62, 308, 313, 310, + 0, 283, 62, 62, 516, 526, 0, 283, 283, 306, + 291, 286, 62, 62, 0, 517, 62, 283, 283, 302, + 303, 283, 576, 304, 643, 573, 0, 0, 0, 0, + 0, 517, 0, 0, 517, 0, 0, 0, 0, 0, + 525, 0, 0, 525, 545, 546, 547, 548, 552, 549, + 550, 0, 516, 526, 0, 516, 526, 589, 0, 0, + 0, 0, 0, 0, 443, 446, 638, 639, 545, 546, + 547, 548, 552, 549, 550, 589, 0, 0, 0, 0, + 0, 0, 0, 0, 591, 592, 545, 546, 547, 548, + 552, 549, 550, 581, 0, 0, 0, 0, 0, 0, + 0, 0, 582, 583, 545, 546, 547, 548, 552, 549, + 550, 0, 581, 0, 0, 0, 0, 565, 0, 640, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 513, 523, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 488, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0}; + 0, 0, 0, 0, 0, 0, 0, 0, 0}; const short QQmlJSGrammar::action_check [] = { - 7, 55, 48, 55, 55, 55, 36, 7, 36, 33, - 55, 7, 7, 33, 37, 7, 7, 61, 60, 60, - 36, 7, 33, 8, 36, 7, 16, 1, 36, 60, - 7, 36, 2, 48, 7, 36, 5, 36, 36, 36, - 79, 5, 36, 60, 33, 33, 55, 60, 7, 36, - 34, 7, 33, 7, 7, 33, 36, 7, 7, 77, - 36, 33, 8, 5, 1, 8, 33, 60, 29, 79, - 36, 33, 17, 8, 37, 79, 33, 60, 33, 8, - 1, 60, 2, 8, 7, 60, 33, 55, 48, 60, - 29, 2, 7, 2, 7, 36, 36, 7, 17, 7, - 33, 66, 7, 61, 48, 31, 36, 1, 36, 33, - 8, 7, 60, 20, 36, 66, 33, 7, 36, 55, - 36, 8, 60, 8, 15, -1, 40, 79, 8, 61, - 61, 62, 10, 8, 61, 62, 40, 51, 8, 15, - 40, 40, 8, 34, 8, 42, 6, 51, 24, 61, - 62, 51, 51, 7, 8, 8, 53, 8, 61, 62, - 20, 8, 8, 8, 8, 15, 61, 62, 61, 62, - 8, 8, 15, 60, -1, 60, 56, 55, 61, 62, - 61, 62, 61, 62, 34, 60, 56, 61, 62, 91, - 92, 34, 56, 50, 60, 15, 29, 54, 0, 91, - 92, 50, 61, 62, 24, 54, 25, 60, 27, 12, - 61, 56, 29, 60, 60, 25, 60, 27, 56, 38, - 25, 25, 27, 27, 61, 62, 12, 15, 38, 61, - 62, 12, 29, 38, 38, 29, 7, -1, 25, 7, - 27, 36, 75, 8, 29, 8, 34, -1, 36, 15, - 25, 38, 27, 86, 57, 7, -1, 89, 75, 7, - 63, -1, 33, 38, 15, 29, 61, 62, 34, 86, - 36, 57, 29, -1, -1, -1, 57, 63, 75, -1, - -1, 75, 63, 34, 15, 36, -1, 61, 62, 86, - 75, -1, 86, 61, 62, -1, 61, 62, 61, 62, - -1, 86, -1, 34, 25, 36, 27, 15, -1, 61, - 62, 75, -1, 61, 62, 18, 19, 38, 75, 93, - 15, -1, 86, 94, -1, 33, 34, -1, 36, 86, - 18, 19, 18, 19, 18, 19, 47, -1, 33, 34, - -1, 36, 45, 46, 98, 99, 100, 101, 102, 103, - 61, 62, -1, -1, 23, 24, -1, 45, 46, 45, - 46, 45, 46, 32, 23, 24, 35, -1, 37, -1, - -1, -1, -1, 32, 23, 24, 35, -1, 37, -1, - 23, 24, 93, 32, -1, 25, 35, 27, 37, 32, - -1, -1, 35, 29, 37, 23, 24, -1, 38, -1, - -1, -1, -1, 31, 32, 23, 24, 35, -1, 37, - -1, -1, -1, 31, 32, 23, 24, 35, 29, 37, - -1, -1, -1, 31, 32, 23, 24, 35, -1, 37, - 66, 67, 68, 31, 32, 23, 24, 35, -1, 37, - -1, -1, -1, 31, 32, -1, -1, 35, -1, 37, - 29, -1, -1, 29, -1, 66, 67, 68, 94, 95, - 96, 29, -1, -1, 29, -1, 23, 24, 29, -1, - -1, 29, 15, -1, 29, 32, -1, -1, 35, -1, - 37, 36, -1, 94, 95, 96, 29, 66, 67, 68, + 8, 61, 60, 8, 48, 1, 0, 2, 55, 79, + 33, 1, 60, 48, 7, 79, 66, 60, 17, 8, + 36, 66, 29, 8, 60, 37, 60, 33, 79, 33, + 1, 33, 2, 36, 20, 55, 8, 79, 7, 61, + 55, 60, 29, 7, 5, 1, 5, 48, 48, 33, + 33, 5, 7, 33, 17, 37, 31, 36, 55, 8, + 33, 7, 60, 77, 7, 33, 7, 7, 60, 36, + 61, 36, 60, 7, 36, 8, 36, 16, 36, 36, + 7, 55, 34, 36, 7, 7, 7, 7, 36, 55, + 7, 36, 7, 7, 36, 7, 7, 7, 36, 2, + 36, 7, 33, 7, 55, 7, 36, 7, 55, 33, + 60, 7, -1, 8, 33, 8, 60, 42, 36, -1, + 36, 8, -1, 60, 33, 33, 61, 62, 53, 36, + 8, 36, 8, -1, 33, 36, 8, 50, 36, -1, + 8, 54, 8, 40, 15, 8, 15, 8, 40, 8, + 8, -1, -1, 24, 51, 15, -1, 10, 15, 51, + 8, 56, 50, 92, 93, 34, 54, 60, 8, 56, + 61, 62, 61, 62, 34, 61, 62, 34, 56, 61, + 62, 61, 62, 8, 60, 40, 61, 62, 60, 40, + 56, 7, 60, 6, 61, 62, 51, 60, 15, 60, + 51, 60, 55, 61, 7, 61, 62, 20, 56, 61, + 62, 92, 93, 15, 61, 62, 12, 34, 29, 36, + 60, 8, 24, 15, 29, 25, 12, 27, 25, -1, + 27, 7, 15, 12, 29, 29, 61, 62, 38, 7, + -1, 38, 34, -1, 36, 61, 62, 25, 29, 27, + 25, 34, 27, 36, 61, 62, 25, 29, 27, 8, + 38, 57, -1, 38, 75, 33, 25, 63, 27, 38, + 75, 57, 29, -1, 61, 62, 87, 63, 57, 38, + 75, 75, 87, 90, 63, 61, 62, 25, 25, 27, + 27, 36, 87, 87, 75, 25, 25, 27, 27, 7, + 38, 38, 15, 75, 7, 8, 87, -1, 38, 38, + 61, 62, 61, 62, -1, 87, 61, 62, 75, 15, + 25, 34, 27, 36, 18, 19, 15, 95, 18, 19, + 87, 18, 19, 38, 18, 19, -1, 33, 34, -1, + 36, -1, -1, 94, 33, 34, -1, 36, -1, 47, + -1, 45, 46, 61, 62, 45, 46, -1, 45, 46, + -1, 45, 46, 61, 62, 23, 24, -1, -1, 23, + 24, -1, -1, -1, 32, 23, 24, 35, 32, 37, + -1, 35, 29, 37, 32, 23, 24, 35, 29, 37, + -1, 23, 24, 29, 32, -1, 94, 35, 29, 37, + 32, 29, -1, 35, 25, 37, 27, 99, 100, 101, + 102, 103, 104, -1, 29, -1, -1, 38, -1, 66, + 67, 68, -1, -1, -1, 66, 67, 68, -1, -1, + 66, 67, 68, -1, -1, 66, 67, 68, 66, 67, + 68, -1, -1, -1, -1, -1, 29, -1, 95, 96, + 97, 66, 67, 68, 95, 96, 97, -1, -1, 95, + 96, 97, -1, -1, 95, 96, 97, 95, 96, 97, + 29, -1, -1, -1, -1, -1, -1, -1, 29, -1, + 95, 96, 97, 66, 67, 68, 23, 24, 29, -1, + -1, 29, -1, -1, 31, 32, 29, -1, 35, -1, + 37, -1, -1, 36, -1, -1, -1, 66, 67, 68, + -1, 29, 95, 96, 97, 66, 67, 68, 36, -1, + -1, -1, -1, -1, -1, 66, 67, 68, 66, 67, + 68, -1, -1, 66, 67, 68, 95, 96, 97, 15, + -1, -1, -1, -1, 95, 96, 97, 15, 66, 67, + 68, -1, -1, 29, 95, 96, 97, 95, 96, 97, + -1, 29, 95, 96, 97, 29, -1, -1, -1, -1, + 29, -1, 36, 29, -1, -1, -1, 95, 96, 97, + -1, -1, -1, -1, -1, 29, -1, -1, -1, -1, 66, 67, 68, -1, -1, -1, -1, -1, 66, 67, - 68, 66, 67, 68, -1, 66, 67, 68, 66, 67, - 68, 66, 67, 68, -1, 94, 95, 96, 94, 95, - 96, -1, -1, 66, 67, 68, 94, 95, 96, 94, - 95, 96, 15, 94, 95, 96, 94, 95, 96, 94, - 95, 96, -1, 29, -1, -1, 29, -1, -1, 29, - 36, 94, 95, 96, 29, -1, -1, 29, -1, -1, - -1, 36, -1, -1, -1, 29, -1, -1, 29, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - 66, 67, 68, 66, 67, 68, 66, 67, 68, 61, - 62, 66, 67, 68, 66, 67, 68, 61, 62, -1, - 61, 62, 66, 67, 68, 66, 67, 68, 94, 95, - 96, 94, 95, 96, 94, 95, 96, 29, -1, 94, - 95, 96, 94, 95, 96, 29, 15, -1, 29, -1, - 94, 95, 96, 94, 95, 96, -1, -1, -1, -1, - 29, -1, -1, -1, -1, -1, -1, -1, -1, 61, - 62, -1, -1, -1, 66, 67, 68, 61, 62, -1, - 61, 62, 66, 67, 68, 66, 67, 68, -1, -1, - -1, -1, -1, -1, -1, 3, -1, 66, 67, 68, - -1, -1, 94, 95, 96, 13, -1, -1, -1, 17, - 94, 95, 96, 94, 95, 96, -1, -1, 26, -1, - 28, -1, -1, 31, -1, 94, 95, 96, -1, -1, - -1, 39, -1, 41, 42, -1, -1, 3, -1, -1, - -1, 49, -1, -1, 52, 53, -1, 13, -1, -1, - 58, 17, -1, -1, -1, -1, 64, -1, -1, -1, - 26, -1, 28, -1, -1, -1, -1, -1, -1, -1, - -1, -1, 80, 39, -1, 41, 42, -1, -1, -1, - -1, -1, -1, 49, -1, -1, 52, 53, -1, -1, - -1, -1, 58, -1, -1, -1, -1, -1, 64, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, 80, -1, -1, -1, -1, -1, + 68, -1, 66, 67, 68, 61, 62, 66, 67, 68, + 66, 67, 68, -1, -1, -1, -1, 61, 62, 95, + 96, 97, 66, 67, 68, -1, 29, 95, 96, 97, + -1, 95, 96, 97, -1, -1, 95, 96, 97, 95, + 96, 97, 29, -1, -1, 29, -1, -1, 15, -1, + -1, 95, 96, 97, -1, -1, -1, -1, 61, 62, + -1, -1, 29, 66, 67, 68, -1, -1, -1, -1, + -1, -1, -1, -1, 61, 62, -1, 61, 62, 66, + 67, 68, 66, 67, 68, -1, -1, -1, -1, -1, + -1, -1, 95, 96, 97, -1, -1, -1, -1, 66, + 67, 68, -1, -1, -1, -1, -1, -1, 95, 96, + 97, 95, 96, 97, -1, -1, -1, -1, -1, -1, + -1, 3, -1, -1, -1, -1, -1, -1, 95, 96, + 97, 13, -1, -1, -1, 17, -1, -1, -1, -1, + 29, -1, -1, -1, 26, -1, 28, -1, -1, 31, + -1, -1, -1, -1, -1, -1, -1, 39, -1, 41, + 42, -1, -1, -1, -1, -1, -1, 49, -1, -1, + 52, 53, 61, 62, -1, -1, 58, 66, 67, 68, + -1, -1, 64, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, 80, -1, + -1, -1, -1, -1, -1, -1, 95, 96, 97, -1, + -1, -1, -1, -1, -1, -1, 12, 13, 3, -1, + -1, -1, -1, -1, -1, -1, 22, -1, 13, -1, + -1, -1, 17, 29, -1, -1, -1, 33, 34, -1, + 36, 26, -1, 28, -1, -1, -1, 43, -1, -1, + -1, 47, -1, -1, 39, -1, 41, 42, -1, -1, + -1, -1, -1, -1, 49, -1, -1, 52, 53, 65, + 66, 67, 68, 58, 70, -1, -1, -1, -1, 64, + -1, -1, -1, -1, -1, 81, 82, 83, -1, -1, + -1, -1, 88, -1, -1, 80, -1, -1, -1, 95, + 96, 97, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, 12, 13, -1, -1, -1, -1, -1, -1, + -1, -1, 22, -1, -1, -1, -1, -1, -1, 29, + -1, -1, -1, 33, 34, -1, 36, -1, -1, -1, + -1, -1, -1, 43, -1, -1, -1, 47, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - 12, 13, -1, -1, -1, -1, -1, -1, -1, -1, - 22, -1, -1, -1, -1, -1, -1, 29, -1, -1, - -1, 33, 34, -1, 36, -1, -1, -1, -1, -1, - -1, 43, -1, -1, -1, 47, -1, -1, -1, -1, + -1, -1, -1, -1, -1, 65, 66, 67, 68, -1, + 70, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, 81, 82, 83, -1, -1, -1, -1, 88, -1, + -1, -1, -1, -1, -1, 95, 96, 97, -1, -1, + -1, -1, -1, -1, -1, -1, -1, 12, 13, -1, + -1, -1, -1, -1, -1, -1, -1, 22, -1, -1, + -1, -1, -1, -1, 29, -1, -1, -1, 33, 34, + -1, 36, -1, -1, -1, -1, -1, -1, 43, -1, + -1, -1, 47, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, 65, 66, 67, 68, -1, 70, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, 81, - 82, 83, -1, -1, -1, 87, -1, -1, -1, -1, - -1, -1, 94, 95, 96, -1, -1, -1, -1, -1, - -1, -1, -1, -1, 12, 13, -1, -1, -1, -1, + 65, 66, 67, 68, -1, 70, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, 81, 82, 83, -1, + -1, -1, -1, 88, -1, -1, -1, -1, -1, -1, + 95, 96, 97, -1, -1, -1, -1, -1, -1, -1, + -1, -1, 10, -1, 12, 13, -1, -1, -1, -1, -1, -1, -1, -1, 22, -1, -1, -1, -1, -1, -1, 29, -1, -1, -1, 33, 34, -1, 36, -1, -1, -1, -1, -1, -1, 43, -1, -1, -1, 47, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 65, 66, 67, - 68, -1, 70, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, 81, 82, 83, -1, -1, -1, 87, - -1, -1, -1, -1, -1, -1, 94, 95, 96, -1, - -1, -1, -1, -1, -1, -1, -1, -1, 10, -1, + 68, -1, 70, -1, -1, -1, -1, 75, -1, -1, + -1, -1, -1, 81, 82, 83, 84, 85, -1, -1, + 88, -1, -1, -1, -1, -1, -1, 95, 96, 97, + -1, -1, -1, -1, -1, -1, -1, -1, -1, 10, + -1, 12, 13, -1, -1, -1, -1, -1, -1, -1, + -1, 22, -1, -1, -1, -1, -1, -1, 29, -1, + -1, -1, 33, 34, -1, 36, -1, -1, -1, -1, + -1, -1, 43, -1, -1, -1, 47, -1, -1, -1, + -1, -1, -1, -1, 55, -1, -1, -1, -1, -1, + -1, -1, -1, -1, 65, 66, 67, 68, -1, 70, + -1, -1, -1, -1, 75, -1, -1, -1, -1, -1, + 81, 82, 83, 84, 85, -1, -1, 88, -1, -1, + -1, -1, -1, -1, 95, 96, 97, -1, -1, -1, + -1, -1, -1, -1, -1, -1, 10, -1, 12, 13, + -1, -1, -1, -1, -1, -1, -1, -1, 22, -1, + -1, -1, -1, -1, -1, 29, -1, -1, -1, 33, + 34, -1, 36, -1, -1, -1, -1, -1, -1, 43, + -1, -1, -1, 47, -1, -1, -1, -1, -1, -1, + -1, 55, -1, -1, -1, -1, -1, -1, -1, -1, + -1, 65, 66, 67, 68, -1, 70, -1, -1, -1, + -1, 75, -1, -1, -1, -1, -1, 81, 82, 83, + 84, 85, -1, -1, 88, -1, -1, -1, -1, -1, + -1, 95, 96, 97, -1, -1, -1, -1, -1, -1, + -1, -1, -1, 11, 12, 13, -1, -1, -1, -1, + -1, -1, -1, -1, 22, -1, -1, -1, -1, -1, + -1, 29, -1, -1, -1, 33, 34, -1, 36, -1, + -1, -1, 40, -1, 42, 43, 44, -1, -1, 47, + -1, -1, -1, 51, -1, 53, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, 65, 66, 67, + 68, -1, 70, -1, 72, -1, 74, -1, 76, -1, + -1, -1, -1, 81, 82, 83, -1, -1, -1, -1, + 88, -1, -1, -1, -1, -1, -1, 95, 96, 97, + -1, -1, -1, -1, -1, -1, -1, -1, -1, 11, 12, 13, -1, -1, -1, -1, -1, -1, -1, -1, 22, -1, -1, -1, -1, -1, -1, 29, -1, -1, - -1, 33, 34, -1, 36, -1, -1, -1, -1, -1, - -1, 43, -1, -1, -1, 47, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, 33, 34, -1, 36, -1, -1, -1, 40, -1, + 42, 43, 44, -1, -1, 47, -1, -1, -1, 51, + -1, 53, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 65, 66, 67, 68, -1, 70, -1, - -1, -1, -1, 75, -1, -1, -1, -1, -1, 81, - 82, 83, 84, -1, -1, 87, -1, -1, -1, -1, - -1, -1, 94, 95, 96, -1, -1, -1, -1, -1, - -1, -1, -1, -1, 10, -1, 12, 13, -1, -1, - -1, -1, -1, -1, -1, -1, 22, -1, -1, -1, - -1, -1, -1, 29, -1, -1, -1, 33, 34, -1, - 36, -1, -1, -1, -1, -1, -1, 43, -1, -1, - -1, 47, -1, -1, -1, -1, -1, -1, -1, 55, - -1, -1, -1, -1, -1, -1, -1, -1, -1, 65, - 66, 67, 68, -1, 70, -1, -1, -1, -1, 75, - -1, -1, -1, -1, -1, 81, 82, 83, 84, -1, - -1, 87, -1, -1, -1, -1, -1, -1, 94, 95, - 96, -1, -1, -1, -1, -1, -1, -1, -1, -1, - 10, -1, 12, 13, -1, -1, -1, -1, -1, -1, - -1, -1, 22, -1, -1, -1, -1, -1, -1, 29, - -1, -1, -1, 33, 34, -1, 36, -1, -1, -1, - -1, -1, -1, 43, -1, -1, -1, 47, -1, -1, - -1, -1, -1, -1, -1, 55, -1, -1, -1, -1, - -1, -1, -1, -1, -1, 65, 66, 67, 68, -1, - 70, -1, -1, -1, -1, 75, -1, -1, -1, -1, - -1, 81, 82, 83, 84, -1, -1, 87, -1, -1, - -1, -1, -1, -1, 94, 95, 96, -1, -1, -1, - -1, -1, -1, -1, -1, -1, 11, 12, 13, -1, - -1, -1, -1, -1, -1, -1, -1, 22, -1, -1, - -1, -1, -1, -1, 29, -1, -1, -1, 33, 34, - -1, 36, -1, -1, -1, 40, -1, 42, 43, 44, - -1, -1, 47, -1, -1, -1, 51, -1, 53, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - 65, 66, 67, 68, -1, 70, -1, 72, -1, 74, - -1, 76, -1, -1, -1, -1, 81, 82, 83, -1, - -1, -1, 87, -1, -1, -1, -1, -1, -1, 94, - 95, 96, -1, -1, -1, -1, -1, -1, -1, -1, - -1, 7, -1, -1, -1, 11, 12, 13, -1, -1, - -1, -1, -1, -1, -1, -1, 22, -1, -1, -1, - -1, -1, -1, 29, -1, -1, -1, 33, 34, -1, - 36, -1, -1, -1, 40, -1, 42, 43, 44, -1, - -1, 47, -1, -1, -1, 51, -1, 53, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, 65, - 66, 67, 68, -1, 70, -1, 72, -1, 74, -1, - 76, -1, -1, -1, -1, 81, 82, 83, -1, -1, - -1, 87, -1, -1, -1, -1, -1, -1, 94, 95, - 96, -1, -1, -1, -1, -1, -1, -1, -1, -1, - 11, 12, 13, -1, -1, -1, -1, -1, -1, -1, - -1, 22, -1, -1, -1, -1, -1, -1, 29, -1, - -1, -1, 33, 34, -1, 36, -1, -1, -1, 40, - -1, 42, 43, 44, -1, -1, 47, -1, -1, -1, - 51, -1, 53, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, 65, 66, 67, 68, -1, 70, - -1, 72, -1, 74, 75, 76, -1, -1, -1, -1, - 81, 82, 83, -1, -1, -1, 87, -1, -1, -1, - -1, -1, -1, 94, 95, 96, -1, -1, -1, -1, + 72, -1, 74, 75, 76, -1, -1, -1, -1, 81, + 82, 83, -1, -1, -1, -1, 88, -1, -1, -1, + -1, -1, -1, 95, 96, 97, -1, -1, -1, -1, + -1, -1, -1, -1, -1, 7, -1, -1, -1, 11, + 12, 13, -1, -1, -1, -1, -1, -1, -1, -1, + 22, -1, -1, -1, -1, -1, -1, 29, -1, -1, + -1, 33, 34, -1, 36, -1, -1, -1, 40, -1, + 42, 43, 44, -1, -1, 47, -1, -1, -1, 51, + -1, 53, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, 65, 66, 67, 68, -1, 70, -1, + 72, -1, 74, -1, 76, -1, -1, -1, -1, 81, + 82, 83, -1, -1, -1, -1, 88, -1, -1, -1, + -1, -1, -1, 95, 96, 97, -1, -1, -1, -1, -1, -1, -1, -1, -1, 8, -1, -1, 11, 12, 13, -1, -1, -1, -1, -1, -1, -1, -1, 22, -1, -1, -1, -1, -1, -1, 29, -1, -1, -1, @@ -889,8 +910,18 @@ const short QQmlJSGrammar::action_check [] = { 53, -1, -1, 56, -1, -1, -1, -1, -1, -1, -1, -1, 65, 66, 67, 68, -1, 70, -1, 72, -1, 74, -1, 76, -1, -1, -1, -1, 81, 82, - 83, -1, -1, -1, 87, -1, -1, -1, -1, -1, - -1, 94, 95, 96, -1, -1, -1, -1, -1, -1, + 83, -1, -1, -1, -1, 88, -1, -1, -1, -1, + -1, -1, 95, 96, 97, -1, -1, -1, -1, -1, + -1, -1, -1, -1, 8, -1, -1, 11, 12, 13, + -1, -1, -1, -1, -1, -1, -1, -1, 22, -1, + -1, -1, -1, -1, -1, 29, -1, -1, -1, 33, + 34, -1, 36, -1, -1, -1, 40, -1, 42, 43, + 44, -1, -1, 47, -1, -1, -1, 51, -1, 53, + -1, -1, 56, -1, -1, -1, -1, -1, -1, -1, + -1, 65, 66, 67, 68, -1, 70, -1, 72, -1, + 74, -1, 76, -1, -1, -1, -1, 81, 82, 83, + -1, -1, -1, -1, 88, -1, -1, -1, -1, -1, + -1, 95, 96, 97, -1, -1, -1, -1, -1, -1, -1, -1, -1, 8, -1, -1, 11, 12, 13, -1, -1, -1, -1, -1, -1, -1, -1, 22, -1, -1, -1, -1, -1, -1, 29, -1, -1, -1, 33, 34, @@ -899,46 +930,27 @@ const short QQmlJSGrammar::action_check [] = { -1, 56, -1, -1, -1, -1, -1, -1, -1, -1, 65, 66, 67, 68, -1, 70, -1, 72, -1, 74, -1, 76, -1, -1, -1, -1, 81, 82, 83, -1, - -1, -1, 87, -1, -1, -1, -1, -1, -1, 94, - 95, 96, -1, -1, -1, -1, -1, -1, -1, -1, - -1, 8, -1, -1, 11, 12, 13, -1, -1, -1, - -1, -1, -1, -1, -1, 22, -1, -1, -1, -1, - -1, -1, 29, -1, -1, -1, 33, 34, -1, 36, - -1, -1, -1, 40, -1, 42, 43, 44, -1, -1, - 47, -1, -1, -1, 51, -1, 53, -1, -1, 56, - -1, -1, -1, -1, -1, -1, -1, -1, 65, 66, - 67, 68, -1, 70, -1, 72, -1, 74, -1, 76, - -1, -1, -1, -1, 81, 82, 83, -1, -1, -1, - 87, -1, -1, -1, -1, -1, -1, 94, 95, 96, - -1, -1, -1, -1, -1, -1, -1, -1, -1, 8, - -1, -1, 11, 12, 13, -1, -1, -1, -1, -1, - -1, -1, -1, 22, -1, -1, -1, -1, -1, -1, - 29, -1, -1, -1, 33, 34, -1, 36, -1, -1, - -1, 40, -1, 42, 43, 44, -1, -1, 47, -1, - -1, -1, 51, -1, 53, -1, -1, 56, -1, -1, - -1, -1, -1, -1, -1, -1, 65, 66, 67, 68, - -1, 70, -1, 72, -1, 74, -1, 76, -1, -1, - -1, -1, 81, 82, 83, -1, -1, -1, 87, -1, - -1, -1, -1, -1, -1, 94, 95, 96, -1, -1, - -1, -1, -1, -1, -1, -1, -1, 11, 12, 13, - -1, -1, -1, -1, -1, -1, -1, -1, 22, -1, - -1, -1, -1, -1, -1, 29, 30, -1, -1, 33, - 34, -1, 36, -1, -1, -1, 40, -1, 42, 43, - 44, -1, -1, 47, -1, -1, -1, 51, -1, 53, - -1, -1, -1, -1, -1, -1, -1, 61, -1, -1, - -1, 65, 66, 67, 68, 69, 70, -1, 72, 73, - 74, -1, 76, -1, 78, -1, -1, 81, 82, 83, - -1, -1, -1, 87, -1, -1, -1, -1, -1, -1, - 94, 95, 96, -1, -1, -1, -1, -1, -1, -1, - -1, -1, 11, 12, 13, -1, -1, -1, -1, -1, - -1, -1, -1, 22, -1, -1, -1, -1, -1, -1, - 29, 30, -1, -1, 33, 34, -1, 36, -1, -1, - -1, 40, -1, 42, 43, 44, -1, -1, 47, -1, - -1, -1, 51, -1, 53, -1, -1, -1, -1, -1, - -1, -1, 61, -1, -1, -1, 65, 66, 67, 68, - 69, 70, -1, 72, 73, 74, -1, 76, -1, 78, - -1, -1, 81, 82, 83, -1, -1, -1, 87, -1, - -1, -1, -1, -1, -1, 94, 95, 96, -1, -1, + -1, -1, -1, 88, -1, -1, -1, -1, -1, -1, + 95, 96, 97, -1, -1, -1, -1, -1, -1, -1, + -1, -1, 8, -1, -1, 11, 12, 13, -1, -1, + -1, -1, -1, -1, -1, -1, 22, -1, -1, -1, + -1, -1, -1, 29, -1, -1, -1, 33, 34, -1, + 36, -1, -1, -1, 40, -1, 42, 43, 44, -1, + -1, 47, -1, -1, -1, 51, -1, 53, -1, -1, + 56, -1, -1, -1, -1, -1, -1, -1, -1, 65, + 66, 67, 68, -1, 70, -1, 72, -1, 74, -1, + 76, -1, -1, -1, -1, 81, 82, 83, -1, -1, + -1, -1, 88, -1, -1, -1, -1, -1, -1, 95, + 96, 97, -1, -1, -1, -1, -1, -1, -1, -1, + -1, 11, 12, 13, -1, -1, -1, -1, -1, -1, + -1, -1, 22, -1, -1, -1, -1, -1, -1, 29, + 30, -1, -1, 33, 34, -1, 36, -1, -1, -1, + 40, -1, 42, 43, 44, -1, -1, 47, -1, -1, + -1, 51, -1, 53, -1, -1, -1, -1, -1, -1, + -1, 61, -1, -1, -1, 65, 66, 67, 68, 69, + 70, -1, 72, 73, 74, -1, 76, -1, 78, -1, + -1, 81, 82, 83, -1, -1, -1, -1, 88, -1, + -1, -1, -1, -1, -1, 95, 96, 97, -1, -1, -1, -1, -1, -1, -1, -1, -1, 11, 12, 13, -1, -1, -1, -1, -1, -1, -1, -1, 22, -1, -1, -1, -1, -1, -1, 29, 30, -1, -1, 33, @@ -947,38 +959,48 @@ const short QQmlJSGrammar::action_check [] = { -1, -1, -1, -1, -1, -1, -1, 61, -1, -1, -1, 65, 66, 67, 68, 69, 70, -1, 72, 73, 74, -1, 76, -1, 78, -1, -1, 81, 82, 83, - -1, -1, -1, 87, -1, -1, -1, -1, -1, -1, - 94, 95, 96, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, 88, -1, -1, -1, -1, -1, + -1, 95, 96, 97, -1, -1, -1, -1, -1, -1, + -1, -1, -1, 11, 12, 13, -1, -1, -1, -1, + -1, -1, -1, -1, 22, -1, -1, -1, -1, -1, + -1, 29, 30, -1, -1, 33, 34, -1, 36, -1, + -1, -1, 40, -1, 42, 43, 44, -1, -1, 47, + -1, -1, -1, 51, -1, 53, -1, -1, -1, -1, + -1, -1, -1, 61, -1, -1, -1, 65, 66, 67, + 68, 69, 70, -1, 72, 73, 74, -1, 76, -1, + 78, -1, -1, 81, 82, 83, -1, -1, -1, -1, + 88, -1, -1, -1, -1, -1, -1, 95, 96, 97, + -1, -1, -1, -1, -1, -1, -1, -1, -1, 4, + 5, 6, -1, -1, 9, 10, 11, -1, -1, 14, + -1, 16, -1, -1, -1, 20, 21, 22, -1, -1, + -1, -1, -1, -1, 29, 30, 31, 32, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, 43, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, 59, -1, -1, -1, -1, -1, + -1, 66, 67, 68, 69, 70, 71, -1, 73, 74, + 75, 76, 77, 78, -1, -1, 81, 82, 83, 84, + 85, 86, 87, -1, -1, -1, -1, -1, -1, -1, + 95, 96, 97, -1, -1, -1, -1, -1, -1, -1, -1, -1, 4, 5, 6, -1, -1, 9, 10, 11, -1, -1, 14, -1, 16, -1, -1, -1, 20, 21, 22, -1, -1, -1, -1, -1, -1, 29, 30, 31, 32, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, 43, -1, -1, -1, -1, -1, -1, -1, -1, + -1, 43, -1, -1, -1, 47, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 59, -1, -1, - -1, -1, -1, -1, 66, 67, 68, 69, 70, 71, + -1, -1, -1, 65, 66, 67, 68, 69, 70, 71, -1, 73, 74, 75, 76, 77, 78, -1, -1, 81, - 82, 83, 84, 85, 86, -1, -1, -1, -1, -1, - -1, -1, 94, 95, 96, -1, -1, -1, -1, -1, - -1, -1, -1, -1, 4, 5, 6, -1, -1, 9, - 10, 11, -1, -1, 14, -1, 16, -1, -1, -1, - 20, 21, 22, -1, -1, -1, -1, -1, -1, 29, - 30, 31, 32, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, 43, -1, -1, -1, 47, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, 59, - -1, -1, -1, -1, -1, 65, 66, 67, 68, 69, - 70, 71, -1, 73, 74, 75, 76, 77, 78, -1, - -1, 81, 82, 83, 84, 85, 86, -1, -1, -1, - -1, -1, -1, -1, 94, 95, 96, -1, -1, -1, - -1, -1, -1, -1, -1, -1, 4, 5, 6, -1, - -1, 9, 10, 11, -1, -1, 14, -1, 16, -1, - -1, -1, 20, 21, 22, -1, -1, -1, -1, -1, - -1, 29, 30, 31, 32, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, 43, -1, -1, -1, 47, + 82, 83, 84, 85, 86, 87, -1, -1, -1, -1, + -1, -1, -1, 95, 96, 97, -1, -1, -1, -1, + -1, -1, -1, -1, -1, 4, 5, 6, -1, -1, + 9, 10, 11, -1, -1, 14, -1, 16, -1, -1, + -1, 20, 21, 22, -1, -1, -1, -1, -1, -1, + 29, 30, 31, 32, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, 43, -1, -1, -1, 47, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, 59, -1, -1, -1, -1, -1, 65, 66, 67, - 68, 69, 70, 71, -1, 73, 74, 75, 76, 77, - 78, -1, -1, 81, 82, 83, 84, 85, 86, -1, - -1, -1, -1, -1, -1, -1, 94, 95, 96, -1, + 59, -1, -1, -1, -1, -1, 65, 66, 67, 68, + 69, 70, 71, -1, 73, 74, 75, 76, 77, 78, + -1, -1, 81, 82, 83, 84, 85, 86, 87, -1, + -1, -1, -1, -1, -1, -1, 95, 96, 97, -1, -1, -1, -1, -1, -1, -1, -1, -1, 4, 5, 6, -1, -1, 9, 10, 11, -1, -1, 14, -1, 16, -1, -1, -1, 20, 21, 22, -1, -1, -1, @@ -988,104 +1010,102 @@ const short QQmlJSGrammar::action_check [] = { -1, -1, -1, 59, -1, -1, -1, -1, -1, 65, 66, 67, 68, 69, 70, 71, -1, 73, 74, 75, 76, 77, 78, -1, -1, 81, 82, 83, 84, 85, - 86, -1, -1, -1, -1, -1, -1, -1, 94, 95, - 96, -1, -1, -1, -1, -1, -1, -1, -1, -1, - 4, -1, -1, -1, -1, 9, -1, 11, 12, 13, - 14, -1, -1, -1, -1, -1, -1, 21, 22, -1, - -1, -1, -1, -1, -1, 29, 30, -1, -1, 33, - 34, -1, 36, -1, -1, -1, 40, -1, 42, 43, - 44, -1, -1, 47, -1, -1, -1, 51, -1, 53, - -1, -1, -1, -1, -1, 59, -1, 61, -1, -1, - -1, 65, 66, 67, 68, 69, 70, 71, 72, 73, - 74, 75, 76, 77, 78, -1, -1, 81, 82, 83, - 84, 85, -1, 87, -1, -1, -1, -1, -1, -1, - 94, 95, 96, -1, -1, -1, -1, -1, -1, -1, - -1, -1, 4, -1, -1, -1, -1, 9, -1, 11, - 12, 13, 14, -1, -1, -1, -1, -1, -1, 21, - 22, -1, -1, -1, -1, -1, -1, 29, 30, -1, - -1, 33, 34, -1, 36, -1, -1, -1, 40, -1, - 42, 43, 44, -1, -1, 47, -1, -1, -1, 51, - -1, 53, -1, -1, -1, -1, -1, 59, -1, 61, - -1, -1, -1, 65, 66, 67, 68, 69, 70, 71, - 72, 73, 74, 75, 76, 77, 78, -1, -1, 81, - 82, 83, 84, 85, -1, 87, -1, -1, -1, -1, - -1, -1, 94, 95, 96, -1, -1, -1, -1, -1, - -1, -1, -1, -1, 4, 5, 6, -1, -1, 9, - 10, 11, 12, 13, 14, -1, 16, -1, -1, -1, - 20, 21, 22, -1, -1, -1, -1, -1, -1, 29, - 30, 31, 32, 33, 34, -1, 36, -1, -1, -1, + 86, 87, -1, -1, -1, -1, -1, -1, -1, 95, + 96, 97, -1, -1, -1, -1, -1, -1, -1, -1, + -1, 4, -1, -1, -1, -1, 9, -1, 11, 12, + 13, 14, -1, -1, -1, -1, -1, -1, 21, 22, + -1, -1, -1, -1, -1, -1, 29, 30, -1, -1, + 33, 34, -1, 36, -1, -1, -1, 40, -1, 42, + 43, 44, -1, -1, 47, -1, -1, -1, 51, -1, + 53, -1, -1, -1, -1, -1, 59, -1, 61, -1, + -1, -1, 65, 66, 67, 68, 69, 70, 71, 72, + 73, 74, 75, 76, 77, 78, -1, -1, 81, 82, + 83, 84, 85, 86, -1, 88, -1, -1, -1, -1, + -1, -1, 95, 96, 97, -1, -1, -1, -1, -1, + -1, -1, -1, -1, 4, -1, -1, -1, -1, 9, + -1, 11, 12, 13, 14, -1, -1, -1, -1, -1, + -1, 21, 22, -1, -1, -1, -1, -1, -1, 29, + 30, -1, -1, 33, 34, -1, 36, -1, -1, -1, 40, -1, 42, 43, 44, -1, -1, 47, -1, -1, -1, 51, -1, 53, -1, -1, -1, -1, -1, 59, -1, 61, -1, -1, -1, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, -1, - -1, 81, 82, 83, 84, 85, 86, 87, -1, -1, - -1, -1, -1, -1, 94, 95, 96, -1, -1, -1, - -1, -1, -1, -1, -1, -1, 4, 5, 6, -1, - -1, 9, 10, 11, 12, 13, 14, -1, 16, -1, - -1, -1, 20, 21, 22, -1, -1, -1, -1, -1, - -1, 29, 30, 31, 32, 33, 34, -1, 36, -1, - -1, -1, 40, -1, 42, 43, 44, -1, -1, 47, - -1, -1, -1, 51, -1, 53, -1, 55, -1, -1, - -1, 59, -1, 61, -1, -1, -1, 65, 66, 67, - 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, - 78, -1, -1, 81, 82, 83, 84, 85, 86, 87, - -1, -1, -1, -1, -1, -1, 94, 95, 96, -1, - -1, -1, -1, -1, -1, -1, -1, -1, + -1, 81, 82, 83, 84, 85, 86, -1, 88, -1, + -1, -1, -1, -1, -1, 95, 96, 97, -1, -1, + -1, -1, -1, -1, -1, -1, -1, 4, 5, 6, + -1, -1, 9, 10, 11, 12, 13, 14, -1, 16, + -1, -1, -1, 20, 21, 22, -1, -1, -1, -1, + -1, -1, 29, 30, 31, 32, 33, 34, -1, 36, + -1, -1, -1, 40, -1, 42, 43, 44, -1, -1, + 47, -1, -1, -1, 51, -1, 53, -1, -1, -1, + -1, -1, 59, -1, 61, -1, -1, -1, 65, 66, + 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, + 77, 78, -1, -1, 81, 82, 83, 84, 85, 86, + 87, 88, -1, -1, -1, -1, -1, -1, 95, 96, + 97, -1, -1, -1, -1, -1, -1, -1, -1, -1, + 4, 5, 6, -1, -1, 9, 10, 11, 12, 13, + 14, -1, 16, -1, -1, -1, 20, 21, 22, -1, + -1, -1, -1, -1, -1, 29, 30, 31, 32, 33, + 34, -1, 36, -1, -1, -1, 40, -1, 42, 43, + 44, -1, -1, 47, -1, -1, -1, 51, -1, 53, + -1, 55, -1, -1, -1, 59, -1, 61, -1, -1, + -1, 65, 66, 67, 68, 69, 70, 71, 72, 73, + 74, 75, 76, 77, 78, -1, -1, 81, 82, 83, + 84, 85, 86, 87, 88, -1, -1, -1, -1, -1, + -1, 95, 96, 97, -1, -1, -1, -1, -1, -1, + -1, -1, -1, - 77, 14, 18, 18, 18, 32, 18, 3, 32, 42, - 9, 3, 3, 18, 42, 3, 18, 18, 3, 22, - 18, 32, 32, 18, 18, 25, 32, 3, 18, 18, - 3, 18, 3, 42, 18, 14, 22, 18, 18, 22, - 22, 18, 100, 18, 18, 42, 18, 3, 105, 42, - 3, 3, 18, 14, 32, 18, 3, 25, 25, 18, - 3, 25, 3, 18, 18, 3, 103, 18, 18, 2, - -1, 3, 42, 42, 18, 14, 25, 42, 14, 2, - 42, -1, 42, 18, 42, 18, 2, 4, -1, -1, - 18, -1, -1, 18, -1, 18, -1, 54, -1, 56, - 44, 18, 18, 18, 18, -1, 54, -1, 54, 54, - 56, 56, 51, 42, 54, 51, 56, 54, 46, 56, - 45, 50, 70, 54, 54, 56, 56, 3, 54, 42, - 45, 18, 46, 59, 54, 54, 54, 50, 2, 59, - 59, 59, 54, 54, 11, 12, 78, 59, 59, 54, - 54, 56, 56, 54, 18, 2, 14, 18, 4, 54, - 54, 56, 56, 54, 54, 23, 3, 68, 58, 60, - 54, 18, 18, 14, 109, 2, 60, 2, 19, 54, - 54, 54, 43, 38, 59, 59, 59, 42, 54, 54, - 56, 18, 54, 18, 59, 54, 2, 59, 54, 58, - 54, 2, 58, 18, 54, 59, 2, 94, 2, 54, - 18, 4, 18, 2, 18, 3, 66, 18, 18, 64, - 3, 54, 18, 56, 18, 18, 54, 2, 56, 18, - 45, 54, 18, 56, 54, 14, 14, 57, 2, 47, - 19, 78, 46, 18, 44, 54, 2, 18, 57, 54, - 2, 54, 2, 56, 18, 60, 54, 54, 56, 56, - 14, -1, 18, 54, 54, 19, 18, -1, 18, 60, - 54, 18, 62, 51, 45, 59, -1, 54, -1, -1, - 54, 54, 59, 67, 54, 59, 59, 54, 2, 59, - 78, -1, 59, 63, 61, 78, 69, 71, -1, 76, - 47, 48, -1, 54, 18, 54, 92, -1, 59, 54, - 59, 54, 61, 54, 59, -1, 59, 54, 59, 54, - 65, -1, 59, 54, 59, 76, 61, -1, 59, 14, - 61, 14, 2, 76, 19, 76, 21, 5, 88, 76, - 23, -1, -1, -1, -1, -1, 14, -1, 18, -1, - -1, -1, 35, 36, -1, 23, -1, 42, 25, 26, - 27, 28, 29, 30, 31, -1, 14, 35, 36, -1, - -1, -1, -1, -1, 88, 23, 24, 25, 26, 27, - 28, 29, 30, 31, 14, -1, -1, -1, -1, -1, - -1, -1, -1, 23, 24, 25, 26, 27, 28, 29, - 30, 31, 14, -1, -1, -1, -1, -1, -1, -1, - -1, 23, 24, 25, 26, 27, 28, 29, 30, 31, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, 5, -1, -1, -1, -1, -1, -1, -1, -1, - 14, -1, -1, -1, -1, -1, -1, -1, -1, 23, + 3, 42, 9, 77, 18, 3, 25, 42, 18, 25, + 18, 105, 18, 42, 42, 3, 100, 3, 103, 3, + 14, 18, 14, 22, 42, 18, 22, 32, 3, 18, + 25, 32, 3, 3, 14, 18, 18, 18, 42, 3, + 42, 3, 42, 3, 18, 32, 25, 32, 3, 3, + 18, 42, 42, 18, 3, 18, 22, 18, 3, 18, + 18, 18, 18, 32, 42, 18, 18, 18, 18, 3, + 3, -1, 18, 2, 22, 18, 18, 18, 25, 14, + 18, 4, 14, 2, 2, 2, 14, 19, 32, 18, + 3, 19, 3, 2, 18, 18, 18, 18, 4, 18, + 18, 18, 38, -1, 18, 3, 42, 14, 3, 18, + 18, 14, 18, 3, 54, 54, 51, 54, -1, 59, + 59, 45, 59, 45, 54, 46, 56, 54, 54, 54, + 2, 45, 59, 59, 59, 2, 2, 2, 54, 54, + 56, 56, 18, 2, 51, -1, 18, -1, 51, 18, + -1, 18, 18, 18, 54, 54, 56, 56, 54, 18, + 56, 54, 54, 56, 56, 78, 54, 78, 56, 42, + 46, 109, 54, 2, 56, 2, 54, 50, 2, 54, + 78, 2, 2, 54, 18, 56, 94, 2, 78, 18, + 18, 18, 70, 68, 18, 18, 54, 18, 18, 54, + 54, 56, 56, 18, 54, 54, 64, 54, 58, 54, + 44, 58, 4, 54, 59, 56, 2, 66, 54, 47, + 56, 44, 54, 92, 54, 18, 18, 59, 58, 54, + 18, 18, 18, -1, 59, 54, 54, 54, 54, 57, + 59, 57, 59, 54, -1, 54, 54, 54, 59, 54, + 43, 60, 60, 60, 18, 60, 54, 45, 42, 46, + 11, 12, 14, 54, 62, 56, 50, 19, -1, 54, + -1, 56, 54, 54, 56, 54, 54, 54, 59, -1, + 59, 59, 59, 47, 48, 54, 54, 54, 2, 2, + 59, 59, 59, 14, 71, 76, 54, 76, 76, -1, + 69, 59, 23, -1, 18, 18, 54, 65, 76, 76, + -1, 59, 54, 54, 35, 36, -1, 59, 59, 67, + 61, 63, 54, 54, -1, 14, 54, 59, 59, 61, + 61, 59, 5, 61, 23, 5, -1, -1, -1, -1, + -1, 14, -1, -1, 14, -1, -1, -1, -1, -1, + 23, -1, -1, 23, 25, 26, 27, 28, 29, 30, + 31, -1, 35, 36, -1, 35, 36, 14, -1, -1, + -1, -1, -1, -1, 88, 88, 23, 24, 25, 26, + 27, 28, 29, 30, 31, 14, -1, -1, -1, -1, + -1, -1, -1, -1, 23, 24, 25, 26, 27, 28, + 29, 30, 31, 14, -1, -1, -1, -1, -1, -1, + -1, -1, 23, 24, 25, 26, 27, 28, 29, 30, + 31, -1, 14, -1, -1, -1, -1, 19, -1, 21, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, 35, 36, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + 42, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1}; + -1, -1, -1, -1, -1, -1, -1, -1, -1}; QT_END_NAMESPACE diff --git a/src/qml/parser/qqmljsgrammar_p.h b/src/qml/parser/qqmljsgrammar_p.h index 050ef6c288..b4f762d28b 100644 --- a/src/qml/parser/qqmljsgrammar_p.h +++ b/src/qml/parser/qqmljsgrammar_p.h @@ -61,23 +61,23 @@ class QQmlJSGrammar public: enum VariousConstants { EOF_SYMBOL = 0, - REDUCE_HERE = 105, - SHIFT_THERE = 104, + REDUCE_HERE = 106, + SHIFT_THERE = 105, T_AND = 1, T_AND_AND = 2, T_AND_EQ = 3, - T_AS = 93, + T_AS = 94, T_AUTOMATIC_SEMICOLON = 62, T_BREAK = 4, T_CASE = 5, T_CATCH = 6, T_COLON = 7, T_COMMA = 8, - T_COMMENT = 88, - T_COMPATIBILITY_SEMICOLON = 89, + T_COMMENT = 89, + T_COMPATIBILITY_SEMICOLON = 90, T_CONST = 84, T_CONTINUE = 9, - T_DEBUGGER = 85, + T_DEBUGGER = 86, T_DEFAULT = 10, T_DELETE = 11, T_DIVIDE_ = 12, @@ -88,19 +88,19 @@ public: T_EQ = 17, T_EQ_EQ = 18, T_EQ_EQ_EQ = 19, - T_ERROR = 97, + T_ERROR = 98, T_FALSE = 83, - T_FEED_JS_EXPRESSION = 101, - T_FEED_JS_PROGRAM = 103, - T_FEED_JS_SOURCE_ELEMENT = 102, - T_FEED_JS_STATEMENT = 100, - T_FEED_UI_OBJECT_MEMBER = 99, - T_FEED_UI_PROGRAM = 98, + T_FEED_JS_EXPRESSION = 102, + T_FEED_JS_PROGRAM = 104, + T_FEED_JS_SOURCE_ELEMENT = 103, + T_FEED_JS_STATEMENT = 101, + T_FEED_UI_OBJECT_MEMBER = 100, + T_FEED_UI_PROGRAM = 99, T_FINALLY = 20, T_FOR = 21, T_FUNCTION = 22, T_GE = 23, - T_GET = 95, + T_GET = 96, T_GT = 24, T_GT_GT = 25, T_GT_GT_EQ = 26, @@ -108,12 +108,13 @@ public: T_GT_GT_GT_EQ = 28, T_IDENTIFIER = 29, T_IF = 30, - T_IMPORT = 91, + T_IMPORT = 92, T_IN = 31, T_INSTANCEOF = 32, T_LBRACE = 33, T_LBRACKET = 34, T_LE = 35, + T_LET = 85, T_LPAREN = 36, T_LT = 37, T_LT_LT = 38, @@ -121,34 +122,34 @@ public: T_MINUS = 40, T_MINUS_EQ = 41, T_MINUS_MINUS = 42, - T_MULTILINE_STRING_LITERAL = 87, + T_MULTILINE_STRING_LITERAL = 88, T_NEW = 43, T_NOT = 44, T_NOT_EQ = 45, T_NOT_EQ_EQ = 46, T_NULL = 81, T_NUMERIC_LITERAL = 47, - T_ON = 94, + T_ON = 95, T_OR = 48, T_OR_EQ = 49, T_OR_OR = 50, T_PLUS = 51, T_PLUS_EQ = 52, T_PLUS_PLUS = 53, - T_PRAGMA = 92, + T_PRAGMA = 93, T_PROPERTY = 66, - T_PUBLIC = 90, + T_PUBLIC = 91, T_QUESTION = 54, T_RBRACE = 55, T_RBRACKET = 56, T_READONLY = 68, T_REMAINDER = 57, T_REMAINDER_EQ = 58, - T_RESERVED_WORD = 86, + T_RESERVED_WORD = 87, T_RETURN = 59, T_RPAREN = 60, T_SEMICOLON = 61, - T_SET = 96, + T_SET = 97, T_SIGNAL = 67, T_STAR = 63, T_STAR_EQ = 64, @@ -167,15 +168,15 @@ public: T_XOR = 79, T_XOR_EQ = 80, - ACCEPT_STATE = 674, - RULE_COUNT = 361, - STATE_COUNT = 675, - TERMINAL_COUNT = 106, + ACCEPT_STATE = 678, + RULE_COUNT = 363, + STATE_COUNT = 679, + TERMINAL_COUNT = 107, NON_TERMINAL_COUNT = 111, - GOTO_INDEX_OFFSET = 675, - GOTO_INFO_OFFSET = 3078, - GOTO_CHECK_OFFSET = 3078 + GOTO_INDEX_OFFSET = 679, + GOTO_INFO_OFFSET = 3203, + GOTO_CHECK_OFFSET = 3203 }; static const char *const spell []; diff --git a/src/qml/parser/qqmljskeywords_p.h b/src/qml/parser/qqmljskeywords_p.h index 84ebe5f210..8b789526a5 100644 --- a/src/qml/parser/qqmljskeywords_p.h +++ b/src/qml/parser/qqmljskeywords_p.h @@ -106,6 +106,13 @@ static inline int classify3(const QChar *s, bool qmlMode) { } } } + else if (s[0].unicode() == 'l') { + if (s[1].unicode() == 'e') { + if (s[2].unicode() == 't') { + return int(Lexer::T_LET); + } + } + } else if (s[0].unicode() == 'n') { if (s[1].unicode() == 'e') { if (s[2].unicode() == 'w') { @@ -278,7 +285,7 @@ static inline int classify5(const QChar *s, bool qmlMode) { if (s[2].unicode() == 'n') { if (s[3].unicode() == 's') { if (s[4].unicode() == 't') { - return qmlMode ? int(Lexer::T_CONST) : int(Lexer::T_RESERVED_WORD); + return int(Lexer::T_CONST); } } } diff --git a/src/qml/parser/qqmljsparser.cpp b/src/qml/parser/qqmljsparser.cpp index 50518a92ee..636b959097 100644 --- a/src/qml/parser/qqmljsparser.cpp +++ b/src/qml/parser/qqmljsparser.cpp @@ -914,21 +914,21 @@ case 116: { sym(1).Node = node; } break; -case 152: { +case 153: { AST::ArrayMemberExpression *node = new (pool) AST::ArrayMemberExpression(sym(1).Expression, sym(3).Expression); node->lbracketToken = loc(2); node->rbracketToken = loc(4); sym(1).Node = node; } break; -case 153: { +case 154: { AST::FieldMemberExpression *node = new (pool) AST::FieldMemberExpression(sym(1).Expression, stringRef(3)); node->dotToken = loc(2); node->identifierToken = loc(3); sym(1).Node = node; } break; -case 154: { +case 155: { AST::NewMemberExpression *node = new (pool) AST::NewMemberExpression(sym(2).Expression, sym(4).ArgumentList); node->newToken = loc(1); node->lparenToken = loc(3); @@ -936,384 +936,384 @@ case 154: { sym(1).Node = node; } break; -case 156: { +case 157: { AST::NewExpression *node = new (pool) AST::NewExpression(sym(2).Expression); node->newToken = loc(1); sym(1).Node = node; } break; -case 157: { +case 158: { AST::CallExpression *node = new (pool) AST::CallExpression(sym(1).Expression, sym(3).ArgumentList); node->lparenToken = loc(2); node->rparenToken = loc(4); sym(1).Node = node; } break; -case 158: { +case 159: { AST::CallExpression *node = new (pool) AST::CallExpression(sym(1).Expression, sym(3).ArgumentList); node->lparenToken = loc(2); node->rparenToken = loc(4); sym(1).Node = node; } break; -case 159: { +case 160: { AST::ArrayMemberExpression *node = new (pool) AST::ArrayMemberExpression(sym(1).Expression, sym(3).Expression); node->lbracketToken = loc(2); node->rbracketToken = loc(4); sym(1).Node = node; } break; -case 160: { +case 161: { AST::FieldMemberExpression *node = new (pool) AST::FieldMemberExpression(sym(1).Expression, stringRef(3)); node->dotToken = loc(2); node->identifierToken = loc(3); sym(1).Node = node; } break; -case 161: { +case 162: { sym(1).Node = 0; } break; -case 162: { +case 163: { sym(1).Node = sym(1).ArgumentList->finish(); } break; -case 163: { +case 164: { sym(1).Node = new (pool) AST::ArgumentList(sym(1).Expression); } break; -case 164: { +case 165: { AST::ArgumentList *node = new (pool) AST::ArgumentList(sym(1).ArgumentList, sym(3).Expression); node->commaToken = loc(2); sym(1).Node = node; } break; -case 168: { +case 169: { AST::PostIncrementExpression *node = new (pool) AST::PostIncrementExpression(sym(1).Expression); node->incrementToken = loc(2); sym(1).Node = node; } break; -case 169: { +case 170: { AST::PostDecrementExpression *node = new (pool) AST::PostDecrementExpression(sym(1).Expression); node->decrementToken = loc(2); sym(1).Node = node; } break; -case 171: { +case 172: { AST::DeleteExpression *node = new (pool) AST::DeleteExpression(sym(2).Expression); node->deleteToken = loc(1); sym(1).Node = node; } break; -case 172: { +case 173: { AST::VoidExpression *node = new (pool) AST::VoidExpression(sym(2).Expression); node->voidToken = loc(1); sym(1).Node = node; } break; -case 173: { +case 174: { AST::TypeOfExpression *node = new (pool) AST::TypeOfExpression(sym(2).Expression); node->typeofToken = loc(1); sym(1).Node = node; } break; -case 174: { +case 175: { AST::PreIncrementExpression *node = new (pool) AST::PreIncrementExpression(sym(2).Expression); node->incrementToken = loc(1); sym(1).Node = node; } break; -case 175: { +case 176: { AST::PreDecrementExpression *node = new (pool) AST::PreDecrementExpression(sym(2).Expression); node->decrementToken = loc(1); sym(1).Node = node; } break; -case 176: { +case 177: { AST::UnaryPlusExpression *node = new (pool) AST::UnaryPlusExpression(sym(2).Expression); node->plusToken = loc(1); sym(1).Node = node; } break; -case 177: { +case 178: { AST::UnaryMinusExpression *node = new (pool) AST::UnaryMinusExpression(sym(2).Expression); node->minusToken = loc(1); sym(1).Node = node; } break; -case 178: { +case 179: { AST::TildeExpression *node = new (pool) AST::TildeExpression(sym(2).Expression); node->tildeToken = loc(1); sym(1).Node = node; } break; -case 179: { +case 180: { AST::NotExpression *node = new (pool) AST::NotExpression(sym(2).Expression); node->notToken = loc(1); sym(1).Node = node; } break; -case 181: { +case 182: { AST::BinaryExpression *node = new (pool) AST::BinaryExpression(sym(1).Expression, QSOperator::Mul, sym(3).Expression); node->operatorToken = loc(2); sym(1).Node = node; } break; -case 182: { +case 183: { AST::BinaryExpression *node = new (pool) AST::BinaryExpression(sym(1).Expression, QSOperator::Div, sym(3).Expression); node->operatorToken = loc(2); sym(1).Node = node; } break; -case 183: { +case 184: { AST::BinaryExpression *node = new (pool) AST::BinaryExpression(sym(1).Expression, QSOperator::Mod, sym(3).Expression); node->operatorToken = loc(2); sym(1).Node = node; } break; -case 185: { +case 186: { AST::BinaryExpression *node = new (pool) AST::BinaryExpression(sym(1).Expression, QSOperator::Add, sym(3).Expression); node->operatorToken = loc(2); sym(1).Node = node; } break; -case 186: { +case 187: { AST::BinaryExpression *node = new (pool) AST::BinaryExpression(sym(1).Expression, QSOperator::Sub, sym(3).Expression); node->operatorToken = loc(2); sym(1).Node = node; } break; -case 188: { +case 189: { AST::BinaryExpression *node = new (pool) AST::BinaryExpression(sym(1).Expression, QSOperator::LShift, sym(3).Expression); node->operatorToken = loc(2); sym(1).Node = node; } break; -case 189: { +case 190: { AST::BinaryExpression *node = new (pool) AST::BinaryExpression(sym(1).Expression, QSOperator::RShift, sym(3).Expression); node->operatorToken = loc(2); sym(1).Node = node; } break; -case 190: { +case 191: { AST::BinaryExpression *node = new (pool) AST::BinaryExpression(sym(1).Expression, QSOperator::URShift, sym(3).Expression); node->operatorToken = loc(2); sym(1).Node = node; } break; -case 192: { +case 193: { AST::BinaryExpression *node = new (pool) AST::BinaryExpression(sym(1).Expression, QSOperator::Lt, sym(3).Expression); node->operatorToken = loc(2); sym(1).Node = node; } break; -case 193: { +case 194: { AST::BinaryExpression *node = new (pool) AST::BinaryExpression(sym(1).Expression, QSOperator::Gt, sym(3).Expression); node->operatorToken = loc(2); sym(1).Node = node; } break; -case 194: { +case 195: { AST::BinaryExpression *node = new (pool) AST::BinaryExpression(sym(1).Expression, QSOperator::Le, sym(3).Expression); node->operatorToken = loc(2); sym(1).Node = node; } break; -case 195: { +case 196: { AST::BinaryExpression *node = new (pool) AST::BinaryExpression(sym(1).Expression, QSOperator::Ge, sym(3).Expression); node->operatorToken = loc(2); sym(1).Node = node; } break; -case 196: { +case 197: { AST::BinaryExpression *node = new (pool) AST::BinaryExpression(sym(1).Expression, QSOperator::InstanceOf, sym(3).Expression); node->operatorToken = loc(2); sym(1).Node = node; } break; -case 197: { +case 198: { AST::BinaryExpression *node = new (pool) AST::BinaryExpression(sym(1).Expression, QSOperator::In, sym(3).Expression); node->operatorToken = loc(2); sym(1).Node = node; } break; -case 199: { +case 200: { AST::BinaryExpression *node = new (pool) AST::BinaryExpression(sym(1).Expression, QSOperator::Lt, sym(3).Expression); node->operatorToken = loc(2); sym(1).Node = node; } break; -case 200: { +case 201: { AST::BinaryExpression *node = new (pool) AST::BinaryExpression(sym(1).Expression, QSOperator::Gt, sym(3).Expression); node->operatorToken = loc(2); sym(1).Node = node; } break; -case 201: { +case 202: { AST::BinaryExpression *node = new (pool) AST::BinaryExpression(sym(1).Expression, QSOperator::Le, sym(3).Expression); node->operatorToken = loc(2); sym(1).Node = node; } break; -case 202: { +case 203: { AST::BinaryExpression *node = new (pool) AST::BinaryExpression(sym(1).Expression, QSOperator::Ge, sym(3).Expression); node->operatorToken = loc(2); sym(1).Node = node; } break; -case 203: { +case 204: { AST::BinaryExpression *node = new (pool) AST::BinaryExpression(sym(1).Expression, QSOperator::InstanceOf, sym(3).Expression); node->operatorToken = loc(2); sym(1).Node = node; } break; -case 205: { +case 206: { AST::BinaryExpression *node = new (pool) AST::BinaryExpression(sym(1).Expression, QSOperator::Equal, sym(3).Expression); node->operatorToken = loc(2); sym(1).Node = node; } break; -case 206: { +case 207: { AST::BinaryExpression *node = new (pool) AST::BinaryExpression(sym(1).Expression, QSOperator::NotEqual, sym(3).Expression); node->operatorToken = loc(2); sym(1).Node = node; } break; -case 207: { +case 208: { AST::BinaryExpression *node = new (pool) AST::BinaryExpression(sym(1).Expression, QSOperator::StrictEqual, sym(3).Expression); node->operatorToken = loc(2); sym(1).Node = node; } break; -case 208: { +case 209: { AST::BinaryExpression *node = new (pool) AST::BinaryExpression(sym(1).Expression, QSOperator::StrictNotEqual, sym(3).Expression); node->operatorToken = loc(2); sym(1).Node = node; } break; -case 210: { +case 211: { AST::BinaryExpression *node = new (pool) AST::BinaryExpression(sym(1).Expression, QSOperator::Equal, sym(3).Expression); node->operatorToken = loc(2); sym(1).Node = node; } break; -case 211: { +case 212: { AST::BinaryExpression *node = new (pool) AST::BinaryExpression(sym(1).Expression, QSOperator::NotEqual, sym(3).Expression); node->operatorToken = loc(2); sym(1).Node = node; } break; -case 212: { +case 213: { AST::BinaryExpression *node = new (pool) AST::BinaryExpression(sym(1).Expression, QSOperator::StrictEqual, sym(3).Expression); node->operatorToken = loc(2); sym(1).Node = node; } break; -case 213: { +case 214: { AST::BinaryExpression *node = new (pool) AST::BinaryExpression(sym(1).Expression, QSOperator::StrictNotEqual, sym(3).Expression); node->operatorToken = loc(2); sym(1).Node = node; } break; -case 215: { +case 216: { AST::BinaryExpression *node = new (pool) AST::BinaryExpression(sym(1).Expression, QSOperator::BitAnd, sym(3).Expression); node->operatorToken = loc(2); sym(1).Node = node; } break; -case 217: { +case 218: { AST::BinaryExpression *node = new (pool) AST::BinaryExpression(sym(1).Expression, QSOperator::BitAnd, sym(3).Expression); node->operatorToken = loc(2); sym(1).Node = node; } break; -case 219: { +case 220: { AST::BinaryExpression *node = new (pool) AST::BinaryExpression(sym(1).Expression, QSOperator::BitXor, sym(3).Expression); node->operatorToken = loc(2); sym(1).Node = node; } break; -case 221: { +case 222: { AST::BinaryExpression *node = new (pool) AST::BinaryExpression(sym(1).Expression, QSOperator::BitXor, sym(3).Expression); node->operatorToken = loc(2); sym(1).Node = node; } break; -case 223: { +case 224: { AST::BinaryExpression *node = new (pool) AST::BinaryExpression(sym(1).Expression, QSOperator::BitOr, sym(3).Expression); node->operatorToken = loc(2); sym(1).Node = node; } break; -case 225: { +case 226: { AST::BinaryExpression *node = new (pool) AST::BinaryExpression(sym(1).Expression, QSOperator::BitOr, sym(3).Expression); node->operatorToken = loc(2); sym(1).Node = node; } break; -case 227: { +case 228: { AST::BinaryExpression *node = new (pool) AST::BinaryExpression(sym(1).Expression, QSOperator::And, sym(3).Expression); node->operatorToken = loc(2); sym(1).Node = node; } break; -case 229: { +case 230: { AST::BinaryExpression *node = new (pool) AST::BinaryExpression(sym(1).Expression, QSOperator::And, sym(3).Expression); node->operatorToken = loc(2); sym(1).Node = node; } break; -case 231: { +case 232: { AST::BinaryExpression *node = new (pool) AST::BinaryExpression(sym(1).Expression, QSOperator::Or, sym(3).Expression); node->operatorToken = loc(2); sym(1).Node = node; } break; -case 233: { +case 234: { AST::BinaryExpression *node = new (pool) AST::BinaryExpression(sym(1).Expression, QSOperator::Or, sym(3).Expression); node->operatorToken = loc(2); sym(1).Node = node; } break; -case 235: { +case 236: { AST::ConditionalExpression *node = new (pool) AST::ConditionalExpression(sym(1).Expression, sym(3).Expression, sym(5).Expression); node->questionToken = loc(2); @@ -1321,7 +1321,7 @@ case 235: { sym(1).Node = node; } break; -case 237: { +case 238: { AST::ConditionalExpression *node = new (pool) AST::ConditionalExpression(sym(1).Expression, sym(3).Expression, sym(5).Expression); node->questionToken = loc(2); @@ -1329,189 +1329,200 @@ case 237: { sym(1).Node = node; } break; -case 239: { +case 240: { AST::BinaryExpression *node = new (pool) AST::BinaryExpression(sym(1).Expression, sym(2).ival, sym(3).Expression); node->operatorToken = loc(2); sym(1).Node = node; } break; -case 241: { +case 242: { AST::BinaryExpression *node = new (pool) AST::BinaryExpression(sym(1).Expression, sym(2).ival, sym(3).Expression); node->operatorToken = loc(2); sym(1).Node = node; } break; -case 242: { +case 243: { sym(1).ival = QSOperator::Assign; } break; -case 243: { +case 244: { sym(1).ival = QSOperator::InplaceMul; } break; -case 244: { +case 245: { sym(1).ival = QSOperator::InplaceDiv; } break; -case 245: { +case 246: { sym(1).ival = QSOperator::InplaceMod; } break; -case 246: { +case 247: { sym(1).ival = QSOperator::InplaceAdd; } break; -case 247: { +case 248: { sym(1).ival = QSOperator::InplaceSub; } break; -case 248: { +case 249: { sym(1).ival = QSOperator::InplaceLeftShift; } break; -case 249: { +case 250: { sym(1).ival = QSOperator::InplaceRightShift; } break; -case 250: { +case 251: { sym(1).ival = QSOperator::InplaceURightShift; } break; -case 251: { +case 252: { sym(1).ival = QSOperator::InplaceAnd; } break; -case 252: { +case 253: { sym(1).ival = QSOperator::InplaceXor; } break; -case 253: { +case 254: { sym(1).ival = QSOperator::InplaceOr; } break; -case 255: { +case 256: { AST::Expression *node = new (pool) AST::Expression(sym(1).Expression, sym(3).Expression); node->commaToken = loc(2); sym(1).Node = node; } break; -case 256: { +case 257: { sym(1).Node = 0; } break; -case 259: { +case 260: { AST::Expression *node = new (pool) AST::Expression(sym(1).Expression, sym(3).Expression); node->commaToken = loc(2); sym(1).Node = node; } break; -case 260: { +case 261: { sym(1).Node = 0; } break; -case 277: { +case 278: { AST::Block *node = new (pool) AST::Block(sym(2).StatementList); node->lbraceToken = loc(1); node->rbraceToken = loc(3); sym(1).Node = node; } break; -case 278: { +case 279: { sym(1).Node = new (pool) AST::StatementList(sym(1).Statement); } break; -case 279: { +case 280: { sym(1).Node = new (pool) AST::StatementList(sym(1).StatementList, sym(2).Statement); } break; -case 280: { +case 281: { sym(1).Node = 0; } break; -case 281: { +case 282: { sym(1).Node = sym(1).StatementList->finish (); } break; -case 283: { - AST::VariableStatement *node = new (pool) AST::VariableStatement( - sym(2).VariableDeclarationList->finish (/*readOnly=*/sym(1).ival == T_CONST)); +case 284: { + AST::VariableDeclaration::VariableScope s = AST::VariableDeclaration::FunctionScope; + if (sym(1).ival == T_LET) + s = AST::VariableDeclaration::BlockScope; + else if (sym(1).ival == T_CONST) + s = AST::VariableDeclaration::ReadOnlyBlockScope; + + AST::VariableStatement *node = new (pool) AST::VariableStatement(sym(2).VariableDeclarationList->finish(s)); node->declarationKindToken = loc(1); node->semicolonToken = loc(3); sym(1).Node = node; } break; -case 284: { +case 285: { + sym(1).ival = T_LET; +} break; + +case 286: { sym(1).ival = T_CONST; } break; -case 285: { +case 287: { sym(1).ival = T_VAR; } break; -case 286: { +case 288: { sym(1).Node = new (pool) AST::VariableDeclarationList(sym(1).VariableDeclaration); } break; -case 287: { +case 289: { AST::VariableDeclarationList *node = new (pool) AST::VariableDeclarationList( sym(1).VariableDeclarationList, sym(3).VariableDeclaration); node->commaToken = loc(2); sym(1).Node = node; } break; -case 288: { +case 290: { sym(1).Node = new (pool) AST::VariableDeclarationList(sym(1).VariableDeclaration); } break; -case 289: { +case 291: { sym(1).Node = new (pool) AST::VariableDeclarationList(sym(1).VariableDeclarationList, sym(3).VariableDeclaration); } break; -case 290: { - AST::VariableDeclaration *node = new (pool) AST::VariableDeclaration(stringRef(1), sym(2).Expression); +case 292: { + AST::VariableDeclaration::VariableScope s = AST::VariableDeclaration::FunctionScope; + AST::VariableDeclaration *node = new (pool) AST::VariableDeclaration(stringRef(1), sym(2).Expression, s); node->identifierToken = loc(1); sym(1).Node = node; } break; -case 291: { - AST::VariableDeclaration *node = new (pool) AST::VariableDeclaration(stringRef(1), sym(2).Expression); +case 293: { + AST::VariableDeclaration::VariableScope s = AST::VariableDeclaration::FunctionScope; + AST::VariableDeclaration *node = new (pool) AST::VariableDeclaration(stringRef(1), sym(2).Expression, s); node->identifierToken = loc(1); sym(1).Node = node; } break; -case 292: { +case 294: { // ### TODO: AST for initializer sym(1) = sym(2); } break; -case 293: { +case 295: { sym(1).Node = 0; } break; -case 295: { +case 297: { // ### TODO: AST for initializer sym(1) = sym(2); } break; -case 296: { +case 298: { sym(1).Node = 0; } break; -case 298: { +case 300: { AST::EmptyStatement *node = new (pool) AST::EmptyStatement(); node->semicolonToken = loc(1); sym(1).Node = node; } break; -case 300: { +case 302: { AST::ExpressionStatement *node = new (pool) AST::ExpressionStatement(sym(1).Expression); node->semicolonToken = loc(2); sym(1).Node = node; } break; -case 301: { +case 303: { AST::IfStatement *node = new (pool) AST::IfStatement(sym(3).Expression, sym(5).Statement, sym(7).Statement); node->ifToken = loc(1); node->lparenToken = loc(2); @@ -1520,7 +1531,7 @@ case 301: { sym(1).Node = node; } break; -case 302: { +case 304: { AST::IfStatement *node = new (pool) AST::IfStatement(sym(3).Expression, sym(5).Statement); node->ifToken = loc(1); node->lparenToken = loc(2); @@ -1528,7 +1539,7 @@ case 302: { sym(1).Node = node; } break; -case 305: { +case 307: { AST::DoWhileStatement *node = new (pool) AST::DoWhileStatement(sym(2).Statement, sym(5).Expression); node->doToken = loc(1); node->whileToken = loc(3); @@ -1538,7 +1549,7 @@ case 305: { sym(1).Node = node; } break; -case 306: { +case 308: { AST::WhileStatement *node = new (pool) AST::WhileStatement(sym(3).Expression, sym(5).Statement); node->whileToken = loc(1); node->lparenToken = loc(2); @@ -1546,7 +1557,7 @@ case 306: { sym(1).Node = node; } break; -case 307: { +case 309: { AST::ForStatement *node = new (pool) AST::ForStatement(sym(3).Expression, sym(5).Expression, sym(7).Expression, sym(9).Statement); node->forToken = loc(1); @@ -1557,9 +1568,10 @@ case 307: { sym(1).Node = node; } break; -case 308: { +case 310: { + AST::VariableDeclaration::VariableScope s = AST::VariableDeclaration::FunctionScope; AST::LocalForStatement *node = new (pool) AST::LocalForStatement( - sym(4).VariableDeclarationList->finish (/*readOnly=*/false), sym(6).Expression, + sym(4).VariableDeclarationList->finish(s), sym(6).Expression, sym(8).Expression, sym(10).Statement); node->forToken = loc(1); node->lparenToken = loc(2); @@ -1570,7 +1582,7 @@ case 308: { sym(1).Node = node; } break; -case 309: { +case 311: { AST:: ForEachStatement *node = new (pool) AST::ForEachStatement(sym(3).Expression, sym(5).Expression, sym(7).Statement); node->forToken = loc(1); @@ -1580,7 +1592,7 @@ case 309: { sym(1).Node = node; } break; -case 310: { +case 312: { AST::LocalForEachStatement *node = new (pool) AST::LocalForEachStatement( sym(4).VariableDeclaration, sym(6).Expression, sym(8).Statement); node->forToken = loc(1); @@ -1591,14 +1603,14 @@ case 310: { sym(1).Node = node; } break; -case 312: { +case 314: { AST::ContinueStatement *node = new (pool) AST::ContinueStatement(); node->continueToken = loc(1); node->semicolonToken = loc(2); sym(1).Node = node; } break; -case 314: { +case 316: { AST::ContinueStatement *node = new (pool) AST::ContinueStatement(stringRef(2)); node->continueToken = loc(1); node->identifierToken = loc(2); @@ -1606,14 +1618,14 @@ case 314: { sym(1).Node = node; } break; -case 316: { +case 318: { AST::BreakStatement *node = new (pool) AST::BreakStatement(QStringRef()); node->breakToken = loc(1); node->semicolonToken = loc(2); sym(1).Node = node; } break; -case 318: { +case 320: { AST::BreakStatement *node = new (pool) AST::BreakStatement(stringRef(2)); node->breakToken = loc(1); node->identifierToken = loc(2); @@ -1621,14 +1633,14 @@ case 318: { sym(1).Node = node; } break; -case 320: { +case 322: { AST::ReturnStatement *node = new (pool) AST::ReturnStatement(sym(2).Expression); node->returnToken = loc(1); node->semicolonToken = loc(3); sym(1).Node = node; } break; -case 321: { +case 323: { AST::WithStatement *node = new (pool) AST::WithStatement(sym(3).Expression, sym(5).Statement); node->withToken = loc(1); node->lparenToken = loc(2); @@ -1636,7 +1648,7 @@ case 321: { sym(1).Node = node; } break; -case 322: { +case 324: { AST::SwitchStatement *node = new (pool) AST::SwitchStatement(sym(3).Expression, sym(5).CaseBlock); node->switchToken = loc(1); node->lparenToken = loc(2); @@ -1644,83 +1656,83 @@ case 322: { sym(1).Node = node; } break; -case 323: { +case 325: { AST::CaseBlock *node = new (pool) AST::CaseBlock(sym(2).CaseClauses); node->lbraceToken = loc(1); node->rbraceToken = loc(3); sym(1).Node = node; } break; -case 324: { +case 326: { AST::CaseBlock *node = new (pool) AST::CaseBlock(sym(2).CaseClauses, sym(3).DefaultClause, sym(4).CaseClauses); node->lbraceToken = loc(1); node->rbraceToken = loc(5); sym(1).Node = node; } break; -case 325: { +case 327: { sym(1).Node = new (pool) AST::CaseClauses(sym(1).CaseClause); } break; -case 326: { +case 328: { sym(1).Node = new (pool) AST::CaseClauses(sym(1).CaseClauses, sym(2).CaseClause); } break; -case 327: { +case 329: { sym(1).Node = 0; } break; -case 328: { +case 330: { sym(1).Node = sym(1).CaseClauses->finish (); } break; -case 329: { +case 331: { AST::CaseClause *node = new (pool) AST::CaseClause(sym(2).Expression, sym(4).StatementList); node->caseToken = loc(1); node->colonToken = loc(3); sym(1).Node = node; } break; -case 330: { +case 332: { AST::DefaultClause *node = new (pool) AST::DefaultClause(sym(3).StatementList); node->defaultToken = loc(1); node->colonToken = loc(2); sym(1).Node = node; } break; -case 331: { +case 333: { AST::LabelledStatement *node = new (pool) AST::LabelledStatement(stringRef(1), sym(3).Statement); node->identifierToken = loc(1); node->colonToken = loc(2); sym(1).Node = node; } break; -case 333: { +case 335: { AST::ThrowStatement *node = new (pool) AST::ThrowStatement(sym(2).Expression); node->throwToken = loc(1); node->semicolonToken = loc(3); sym(1).Node = node; } break; -case 334: { +case 336: { AST::TryStatement *node = new (pool) AST::TryStatement(sym(2).Statement, sym(3).Catch); node->tryToken = loc(1); sym(1).Node = node; } break; -case 335: { +case 337: { AST::TryStatement *node = new (pool) AST::TryStatement(sym(2).Statement, sym(3).Finally); node->tryToken = loc(1); sym(1).Node = node; } break; -case 336: { +case 338: { AST::TryStatement *node = new (pool) AST::TryStatement(sym(2).Statement, sym(3).Catch, sym(4).Finally); node->tryToken = loc(1); sym(1).Node = node; } break; -case 337: { +case 339: { AST::Catch *node = new (pool) AST::Catch(stringRef(3), sym(5).Block); node->catchToken = loc(1); node->lparenToken = loc(2); @@ -1729,20 +1741,20 @@ case 337: { sym(1).Node = node; } break; -case 338: { +case 340: { AST::Finally *node = new (pool) AST::Finally(sym(2).Block); node->finallyToken = loc(1); sym(1).Node = node; } break; -case 340: { +case 342: { AST::DebuggerStatement *node = new (pool) AST::DebuggerStatement(); node->debuggerToken = loc(1); node->semicolonToken = loc(2); sym(1).Node = node; } break; -case 342: { +case 344: { AST::FunctionDeclaration *node = new (pool) AST::FunctionDeclaration(stringRef(2), sym(4).FormalParameterList, sym(7).FunctionBody); node->functionToken = loc(1); node->identifierToken = loc(2); @@ -1753,7 +1765,7 @@ case 342: { sym(1).Node = node; } break; -case 343: { +case 345: { AST::FunctionExpression *node = new (pool) AST::FunctionExpression(stringRef(2), sym(4).FormalParameterList, sym(7).FunctionBody); node->functionToken = loc(1); if (! stringRef(2).isNull()) @@ -1765,7 +1777,7 @@ case 343: { sym(1).Node = node; } break; -case 344: { +case 346: { AST::FunctionExpression *node = new (pool) AST::FunctionExpression(QStringRef(), sym(3).FormalParameterList, sym(6).FunctionBody); node->functionToken = loc(1); node->lparenToken = loc(2); @@ -1775,56 +1787,56 @@ case 344: { sym(1).Node = node; } break; -case 345: { +case 347: { AST::FormalParameterList *node = new (pool) AST::FormalParameterList(stringRef(1)); node->identifierToken = loc(1); sym(1).Node = node; } break; -case 346: { +case 348: { AST::FormalParameterList *node = new (pool) AST::FormalParameterList(sym(1).FormalParameterList, stringRef(3)); node->commaToken = loc(2); node->identifierToken = loc(3); sym(1).Node = node; } break; -case 347: { +case 349: { sym(1).Node = 0; } break; -case 348: { +case 350: { sym(1).Node = sym(1).FormalParameterList->finish (); } break; -case 349: { +case 351: { sym(1).Node = 0; } break; -case 351: { +case 353: { sym(1).Node = new (pool) AST::FunctionBody(sym(1).SourceElements->finish ()); } break; -case 353: { +case 355: { sym(1).Node = new (pool) AST::Program(sym(1).SourceElements->finish ()); } break; -case 354: { +case 356: { sym(1).Node = new (pool) AST::SourceElements(sym(1).SourceElement); } break; -case 355: { +case 357: { sym(1).Node = new (pool) AST::SourceElements(sym(1).SourceElements, sym(2).SourceElement); } break; -case 356: { +case 358: { sym(1).Node = new (pool) AST::StatementSourceElement(sym(1).Statement); } break; -case 357: { +case 359: { sym(1).Node = new (pool) AST::FunctionSourceElement(sym(1).FunctionDeclaration); } break; -case 358: { +case 360: { sym(1).Node = 0; } break; diff --git a/src/qml/qml/qqmlcomponent.cpp b/src/qml/qml/qqmlcomponent.cpp index a04f47e6a4..75968ffc43 100644 --- a/src/qml/qml/qqmlcomponent.cpp +++ b/src/qml/qml/qqmlcomponent.cpp @@ -1046,14 +1046,18 @@ namespace QV4 { namespace Heap { -struct QmlIncubatorObject : Object { +#define QmlIncubatorObjectMembers(class, Member) \ + Member(class, HeapValue, HeapValue, valuemap) \ + Member(class, HeapValue, HeapValue, statusChanged) \ + Member(class, Pointer, QmlContext *, qmlContext) \ + Member(class, NoMark, QQmlComponentIncubator *, incubator) \ + Member(class, NoMark, QQmlQPointer<QObject>, parent) + +DECLARE_HEAP_OBJECT(QmlIncubatorObject, Object) { + DECLARE_MARK_TABLE(QmlIncubatorObject); + void init(QQmlIncubator::IncubationMode = QQmlIncubator::Asynchronous); inline void destroy(); - QQmlComponentIncubator *incubator; - QQmlQPointer<QObject> parent; - QV4::Value valuemap; - QV4::Value statusChanged; - Pointer<Heap::QmlContext> qmlContext; }; } @@ -1069,8 +1073,6 @@ struct QmlIncubatorObject : public QV4::Object static void method_get_object(const BuiltinFunction *, Scope &scope, CallData *callData); static void method_forceCompletion(const BuiltinFunction *, Scope &scope, CallData *callData); - static void markObjects(QV4::Heap::Base *that, QV4::ExecutionEngine *e); - void statusChanged(QQmlIncubator::Status); void setInitialState(QObject *); }; @@ -1374,8 +1376,8 @@ void QQmlComponent::incubateObject(QQmlV4Function *args) r->setPrototype(p); if (!valuemap->isUndefined()) - r->d()->valuemap = valuemap; - r->d()->qmlContext = v4->qmlContext(); + r->d()->valuemap.set(scope.engine, valuemap); + r->d()->qmlContext.set(scope.engine, v4->qmlContext()); r->d()->parent = parent; QQmlIncubator *incubator = r->d()->incubator; @@ -1459,7 +1461,7 @@ void QV4::QmlIncubatorObject::method_set_statusChanged(const BuiltinFunction *, if (!o || callData->argc < 1) THROW_TYPE_ERROR(); - o->d()->statusChanged = callData->args[0]; + o->d()->statusChanged.set(scope.engine, callData->args[0]); RETURN_UNDEFINED(); } @@ -1471,10 +1473,10 @@ QQmlComponentExtension::~QQmlComponentExtension() void QV4::Heap::QmlIncubatorObject::init(QQmlIncubator::IncubationMode m) { Object::init(); - valuemap = QV4::Primitive::undefinedValue(); - statusChanged = QV4::Primitive::undefinedValue(); + valuemap.set(internalClass->engine, QV4::Primitive::undefinedValue()); + statusChanged.set(internalClass->engine, QV4::Primitive::undefinedValue()); parent.init(); - qmlContext = nullptr; + qmlContext.set(internalClass->engine, nullptr); incubator = new QQmlComponentIncubator(this, m); } @@ -1497,16 +1499,6 @@ void QV4::QmlIncubatorObject::setInitialState(QObject *o) } } -void QV4::QmlIncubatorObject::markObjects(QV4::Heap::Base *that, QV4::ExecutionEngine *e) -{ - QmlIncubatorObject::Data *o = static_cast<QmlIncubatorObject::Data *>(that); - o->valuemap.mark(e); - o->statusChanged.mark(e); - if (o->qmlContext) - o->qmlContext->mark(e); - Object::markObjects(that, e); -} - void QV4::QmlIncubatorObject::statusChanged(QQmlIncubator::Status s) { QV4::Scope scope(engine()); diff --git a/src/qml/qml/qqmlengine.cpp b/src/qml/qml/qqmlengine.cpp index a762564912..d4d21583ba 100644 --- a/src/qml/qml/qqmlengine.cpp +++ b/src/qml/qml/qqmlengine.cpp @@ -761,7 +761,7 @@ class QQmlThreadNotifierProxyObject : public QObject public: QPointer<QObject> target; - virtual int qt_metacall(QMetaObject::Call, int methodIndex, void **a) { + int qt_metacall(QMetaObject::Call, int methodIndex, void **a) override { if (!target) return -1; diff --git a/src/qml/qml/qqmllistwrapper.cpp b/src/qml/qml/qqmllistwrapper.cpp index d94f7c56e4..43677e0d78 100644 --- a/src/qml/qml/qqmllistwrapper.cpp +++ b/src/qml/qml/qqmllistwrapper.cpp @@ -140,12 +140,13 @@ ReturnedValue QmlListWrapper::getIndexed(const Managed *m, uint index, bool *has return Primitive::undefinedValue().asReturnedValue(); } -void QmlListWrapper::put(Managed *m, String *name, const Value &value) +bool QmlListWrapper::put(Managed *m, String *name, const Value &value) { // doesn't do anything. Should we throw? Q_UNUSED(m); Q_UNUSED(name); Q_UNUSED(value); + return false; } void QmlListWrapper::advanceIterator(Managed *m, ObjectIterator *it, Value *name, uint *index, Property *p, PropertyAttributes *attrs) diff --git a/src/qml/qml/qqmllistwrapper_p.h b/src/qml/qml/qqmllistwrapper_p.h index b914c681f2..84dadba01a 100644 --- a/src/qml/qml/qqmllistwrapper_p.h +++ b/src/qml/qml/qqmllistwrapper_p.h @@ -95,7 +95,7 @@ struct Q_QML_EXPORT QmlListWrapper : Object static ReturnedValue get(const Managed *m, String *name, bool *hasProperty); static ReturnedValue getIndexed(const Managed *m, uint index, bool *hasProperty); - static void put(Managed *m, String *name, const Value &value); + static bool put(Managed *m, String *name, const Value &value); static void advanceIterator(Managed *m, ObjectIterator *it, Value *name, uint *index, Property *p, PropertyAttributes *attributes); }; diff --git a/src/qml/qml/qqmltypewrapper.cpp b/src/qml/qml/qqmltypewrapper.cpp index be4ab68831..7b98096a7f 100644 --- a/src/qml/qml/qqmltypewrapper.cpp +++ b/src/qml/qml/qqmltypewrapper.cpp @@ -280,13 +280,13 @@ ReturnedValue QmlTypeWrapper::get(const Managed *m, String *name, bool *hasPrope } -void QmlTypeWrapper::put(Managed *m, String *name, const Value &value) +bool QmlTypeWrapper::put(Managed *m, String *name, const Value &value) { Q_ASSERT(m->as<QmlTypeWrapper>()); QmlTypeWrapper *w = static_cast<QmlTypeWrapper *>(m); QV4::ExecutionEngine *v4 = w->engine(); if (v4->hasException) - return; + return false; QV4::Scope scope(v4); QQmlContextData *context = v4->callingQmlContext(); @@ -297,7 +297,8 @@ void QmlTypeWrapper::put(Managed *m, String *name, const Value &value) QQmlEngine *e = scope.engine->qmlEngine(); QObject *ao = qmlAttachedPropertiesObjectById(type->attachedPropertiesId(QQmlEnginePrivate::get(e)), object); if (ao) - QV4::QObjectWrapper::setQmlProperty(v4, context, ao, name, QV4::QObjectWrapper::IgnoreRevision, value); + return QV4::QObjectWrapper::setQmlProperty(v4, context, ao, name, QV4::QObjectWrapper::IgnoreRevision, value); + return false; } else if (type && type->isSingleton()) { QQmlEngine *e = scope.engine->qmlEngine(); QQmlType::SingletonInstanceInfo *siinfo = type->singletonInstanceInfo(); @@ -305,18 +306,20 @@ void QmlTypeWrapper::put(Managed *m, String *name, const Value &value) QObject *qobjectSingleton = siinfo->qobjectApi(e); if (qobjectSingleton) { - QV4::QObjectWrapper::setQmlProperty(v4, context, qobjectSingleton, name, QV4::QObjectWrapper::IgnoreRevision, value); + return QV4::QObjectWrapper::setQmlProperty(v4, context, qobjectSingleton, name, QV4::QObjectWrapper::IgnoreRevision, value); } else if (!siinfo->scriptApi(e).isUndefined()) { QV4::ScopedObject apiprivate(scope, QJSValuePrivate::convertedToValue(v4, siinfo->scriptApi(e))); if (!apiprivate) { QString error = QLatin1String("Cannot assign to read-only property \"") + name->toQString() + QLatin1Char('\"'); v4->throwError(error); - return; + return false; } else { - apiprivate->put(name, value); + return apiprivate->put(name, value); } } } + + return false; } PropertyAttributes QmlTypeWrapper::query(const Managed *m, String *name) @@ -339,4 +342,44 @@ bool QmlTypeWrapper::isEqualTo(Managed *a, Managed *b) return false; } +ReturnedValue QmlTypeWrapper::instanceOf(const Object *typeObject, const Value &var) +{ + Q_ASSERT(typeObject->as<QV4::QmlTypeWrapper>()); + const QV4::QmlTypeWrapper *typeWrapper = static_cast<const QV4::QmlTypeWrapper *>(typeObject); + QV4::ExecutionEngine *engine = typeObject->internalClass()->engine; + QQmlEnginePrivate *qenginepriv = QQmlEnginePrivate::get(engine->qmlEngine()); + + // can only compare a QObject* against a QML type + const QObjectWrapper *wrapper = var.as<QObjectWrapper>(); + if (!wrapper) + return engine->throwTypeError(); + + // in case the wrapper outlived the QObject* + const QObject *wrapperObject = wrapper->object(); + if (!wrapperObject) + return engine->throwTypeError(); + + const int myTypeId = typeWrapper->d()->type->typeId(); + QQmlMetaObject myQmlType; + if (myTypeId == 0) { + // we're a composite type; a composite type cannot be equal to a + // non-composite object instance (Rectangle{} is never an instance of + // CustomRectangle) + QQmlData *theirDData = QQmlData::get(wrapperObject, /*create=*/false); + Q_ASSERT(theirDData); // must exist, otherwise how do we have a QObjectWrapper for it?! + if (!theirDData->compilationUnit) + return Encode(false); + + QQmlTypeData *td = qenginepriv->typeLoader.getType(typeWrapper->d()->type->sourceUrl()); + CompiledData::CompilationUnit *cu = td->compilationUnit(); + myQmlType = qenginepriv->metaObjectForType(cu->metaTypeId); + } else { + myQmlType = qenginepriv->metaObjectForType(myTypeId); + } + + const QMetaObject *theirType = wrapperObject->metaObject(); + + return QV4::Encode(QQmlMetaObject::canConvert(theirType, myQmlType)); +} + QT_END_NAMESPACE diff --git a/src/qml/qml/qqmltypewrapper_p.h b/src/qml/qml/qqmltypewrapper_p.h index 3b0ae04cc1..c584458ed4 100644 --- a/src/qml/qml/qqmltypewrapper_p.h +++ b/src/qml/qml/qqmltypewrapper_p.h @@ -100,10 +100,10 @@ struct Q_QML_EXPORT QmlTypeWrapper : Object static ReturnedValue get(const Managed *m, String *name, bool *hasProperty); - static void put(Managed *m, String *name, const Value &value); + static bool put(Managed *m, String *name, const Value &value); static PropertyAttributes query(const Managed *, String *name); static bool isEqualTo(Managed *that, Managed *o); - + static ReturnedValue instanceOf(const Object *typeObject, const Value &var); }; } diff --git a/src/qml/qml/qqmlvaluetypewrapper.cpp b/src/qml/qml/qqmlvaluetypewrapper.cpp index 41bb85c351..d262b230e2 100644 --- a/src/qml/qml/qqmlvaluetypewrapper.cpp +++ b/src/qml/qml/qqmlvaluetypewrapper.cpp @@ -409,13 +409,13 @@ ReturnedValue QQmlValueTypeWrapper::get(const Managed *m, String *name, bool *ha #undef VALUE_TYPE_ACCESSOR } -void QQmlValueTypeWrapper::put(Managed *m, String *name, const Value &value) +bool QQmlValueTypeWrapper::put(Managed *m, String *name, const Value &value) { Q_ASSERT(m->as<QQmlValueTypeWrapper>()); ExecutionEngine *v4 = static_cast<QQmlValueTypeWrapper *>(m)->engine(); Scope scope(v4); if (scope.hasException()) - return; + return false; Scoped<QQmlValueTypeWrapper> r(scope, static_cast<QQmlValueTypeWrapper *>(m)); Scoped<QQmlValueTypeReference> reference(scope, m->d()); @@ -426,7 +426,7 @@ void QQmlValueTypeWrapper::put(Managed *m, String *name, const Value &value) QMetaProperty writebackProperty = reference->d()->object->metaObject()->property(reference->d()->property); if (!writebackProperty.isWritable() || !reference->readReferenceValue()) - return; + return false; writeBackPropertyType = writebackProperty.userType(); } @@ -434,7 +434,7 @@ void QQmlValueTypeWrapper::put(Managed *m, String *name, const Value &value) const QMetaObject *metaObject = r->d()->propertyCache()->metaObject(); const QQmlPropertyData *pd = r->d()->propertyCache()->property(name, 0, 0); if (!pd) - return; + return false; if (reference) { QV4::ScopedFunctionObject f(scope, value); @@ -444,7 +444,7 @@ void QQmlValueTypeWrapper::put(Managed *m, String *name, const Value &value) QString error = QStringLiteral("Cannot assign JavaScript function to value-type property"); ScopedString e(scope, v4->newString(error)); v4->throwError(e); - return; + return false; } QQmlContextData *context = v4->callingQmlContext(); @@ -461,7 +461,7 @@ void QQmlValueTypeWrapper::put(Managed *m, String *name, const Value &value) newBinding->setSourceLocation(bindingFunction->currentLocation()); newBinding->setTarget(reference->d()->object, cacheData, pd); QQmlPropertyPrivate::setBinding(newBinding); - return; + return true; } else { QQmlPropertyPrivate::removeBinding(reference->d()->object, QQmlPropertyIndex(reference->d()->property, pd->coreIndex())); } @@ -495,6 +495,8 @@ void QQmlValueTypeWrapper::put(Managed *m, String *name, const Value &value) QMetaObject::metacall(reference->d()->object, QMetaObject::WriteProperty, reference->d()->property, a); } } + + return true; } QT_END_NAMESPACE diff --git a/src/qml/qml/qqmlvaluetypewrapper_p.h b/src/qml/qml/qqmlvaluetypewrapper_p.h index 87f9116056..c8aac719ab 100644 --- a/src/qml/qml/qqmlvaluetypewrapper_p.h +++ b/src/qml/qml/qqmlvaluetypewrapper_p.h @@ -106,7 +106,7 @@ public: bool write(QObject *target, int propertyIndex) const; static ReturnedValue get(const Managed *m, String *name, bool *hasProperty); - static void put(Managed *m, String *name, const Value &value); + static bool put(Managed *m, String *name, const Value &value); static bool isEqualTo(Managed *m, Managed *other); static PropertyAttributes query(const Managed *, String *name); static void advanceIterator(Managed *m, ObjectIterator *it, Value *name, uint *index, Property *p, PropertyAttributes *attributes); diff --git a/src/qml/qml/qqmlvmemetaobject.cpp b/src/qml/qml/qqmlvmemetaobject.cpp index 490a4e19ab..f464a099e0 100644 --- a/src/qml/qml/qqmlvmemetaobject.cpp +++ b/src/qml/qml/qqmlvmemetaobject.cpp @@ -104,8 +104,10 @@ void QQmlVMEVariantQObjectPtr::objectDestroyed(QObject *) if (v4) { QV4::Scope scope(v4); QV4::Scoped<QV4::MemberData> sp(scope, m_target->propertyAndMethodStorage.value()); - if (sp) - *(sp->data() + m_index) = QV4::Primitive::nullValue(); + if (sp) { + QV4::MemberData::Index index{ sp->d(), static_cast<uint>(m_index) }; + index.set(v4, QV4::Primitive::nullValue()); + } } m_target->activate(m_target->object, m_target->methodOffset() + m_index, 0); @@ -329,7 +331,7 @@ QQmlVMEMetaObject::QQmlVMEMetaObject(QObject *obj, if (size) { QV4::Heap::MemberData *data = QV4::MemberData::allocate(v4, size); propertyAndMethodStorage.set(v4, data); - std::fill(data->data, data->data + data->size, QV4::Encode::undefined()); + std::fill(data->values.values, data->values.values + data->values.size, QV4::Encode::undefined()); } // Need JS wrapper to ensure properties/methods are marked. @@ -364,77 +366,77 @@ void QQmlVMEMetaObject::writeProperty(int id, int v) { QV4::MemberData *md = propertyAndMethodStorageAsMemberData(); if (md) - *(md->data() + id) = QV4::Primitive::fromInt32(v); + md->set(cache->engine, id, QV4::Primitive::fromInt32(v)); } void QQmlVMEMetaObject::writeProperty(int id, bool v) { QV4::MemberData *md = propertyAndMethodStorageAsMemberData(); if (md) - *(md->data() + id) = QV4::Primitive::fromBoolean(v); + md->set(cache->engine, id, QV4::Primitive::fromBoolean(v)); } void QQmlVMEMetaObject::writeProperty(int id, double v) { QV4::MemberData *md = propertyAndMethodStorageAsMemberData(); if (md) - *(md->data() + id) = QV4::Primitive::fromDouble(v); + md->set(cache->engine, id, QV4::Primitive::fromDouble(v)); } void QQmlVMEMetaObject::writeProperty(int id, const QString& v) { QV4::MemberData *md = propertyAndMethodStorageAsMemberData(); if (md) - *(md->data() + id) = cache->engine->newString(v); + md->set(cache->engine, id, cache->engine->newString(v)); } void QQmlVMEMetaObject::writeProperty(int id, const QUrl& v) { QV4::MemberData *md = propertyAndMethodStorageAsMemberData(); if (md) - *(md->data() + id) = cache->engine->newVariantObject(QVariant::fromValue(v)); + md->set(cache->engine, id, cache->engine->newVariantObject(QVariant::fromValue(v))); } void QQmlVMEMetaObject::writeProperty(int id, const QDate& v) { QV4::MemberData *md = propertyAndMethodStorageAsMemberData(); if (md) - *(md->data() + id) = cache->engine->newVariantObject(QVariant::fromValue(v)); + md->set(cache->engine, id, cache->engine->newVariantObject(QVariant::fromValue(v))); } void QQmlVMEMetaObject::writeProperty(int id, const QDateTime& v) { QV4::MemberData *md = propertyAndMethodStorageAsMemberData(); if (md) - *(md->data() + id) = cache->engine->newVariantObject(QVariant::fromValue(v)); + md->set(cache->engine, id, cache->engine->newVariantObject(QVariant::fromValue(v))); } void QQmlVMEMetaObject::writeProperty(int id, const QPointF& v) { QV4::MemberData *md = propertyAndMethodStorageAsMemberData(); if (md) - *(md->data() + id) = cache->engine->newVariantObject(QVariant::fromValue(v)); + md->set(cache->engine, id, cache->engine->newVariantObject(QVariant::fromValue(v))); } void QQmlVMEMetaObject::writeProperty(int id, const QSizeF& v) { QV4::MemberData *md = propertyAndMethodStorageAsMemberData(); if (md) - *(md->data() + id) = cache->engine->newVariantObject(QVariant::fromValue(v)); + md->set(cache->engine, id, cache->engine->newVariantObject(QVariant::fromValue(v))); } void QQmlVMEMetaObject::writeProperty(int id, const QRectF& v) { QV4::MemberData *md = propertyAndMethodStorageAsMemberData(); if (md) - *(md->data() + id) = cache->engine->newVariantObject(QVariant::fromValue(v)); + md->set(cache->engine, id, cache->engine->newVariantObject(QVariant::fromValue(v))); } void QQmlVMEMetaObject::writeProperty(int id, QObject* v) { QV4::MemberData *md = propertyAndMethodStorageAsMemberData(); if (md) - *(md->data() + id) = QV4::QObjectWrapper::wrap(cache->engine, v); + md->set(cache->engine, id, QV4::Value::fromReturnedValue(QV4::QObjectWrapper::wrap(cache->engine, v))); QQmlVMEVariantQObjectPtr *guard = getQObjectGuardForProperty(id); if (v && !guard) { @@ -592,7 +594,7 @@ QList<QObject *> *QQmlVMEMetaObject::readPropertyAsList(int id) const if (!v || (int)v->d()->data().userType() != qMetaTypeId<QList<QObject *> >()) { QVariant variant(qVariantFromValue(QList<QObject*>())); v = cache->engine->newVariantObject(variant); - *(md->data() + id) = v; + md->set(cache->engine, id, v); } return static_cast<QList<QObject *> *>(v->d()->data().data()); } @@ -742,7 +744,7 @@ int QQmlVMEMetaObject::metaCall(QObject *o, QMetaObject::Call c, int _id, void * Q_ASSERT(fallbackMetaType != QMetaType::UnknownType); if (QV4::MemberData *md = propertyAndMethodStorageAsMemberData()) { QVariant propertyAsVariant; - if (QV4::VariantObject *v = (md->data() + id)->as<QV4::VariantObject>()) + if (const QV4::VariantObject *v = (md->data() + id)->as<QV4::VariantObject>()) propertyAsVariant = v->d()->data(); QQml_valueTypeProvider()->readValueType(propertyAsVariant, a[0], fallbackMetaType); } @@ -815,9 +817,9 @@ int QQmlVMEMetaObject::metaCall(QObject *o, QMetaObject::Call c, int _id, void * case QV4::CompiledData::Property::Quaternion: Q_ASSERT(fallbackMetaType != QMetaType::UnknownType); if (QV4::MemberData *md = propertyAndMethodStorageAsMemberData()) { - QV4::VariantObject *v = (md->data() + id)->as<QV4::VariantObject>(); + const QV4::VariantObject *v = (md->data() + id)->as<QV4::VariantObject>(); if (!v) { - *(md->data() + id) = cache->engine->newVariantObject(QVariant()); + md->set(cache->engine, id, cache->engine->newVariantObject(QVariant())); v = (md->data() + id)->as<QV4::VariantObject>(); QQml_valueTypeProvider()->initValueType(fallbackMetaType, v->d()->data()); } @@ -1028,7 +1030,7 @@ void QQmlVMEMetaObject::writeVarProperty(int id, const QV4::Value &value) // Importantly, if the current value is a scarce resource, we need to ensure that it // gets automatically released by the engine if no other references to it exist. - QV4::VariantObject *oldVariant = (md->data() + id)->as<QV4::VariantObject>(); + const QV4::VariantObject *oldVariant = (md->data() + id)->as<QV4::VariantObject>(); if (oldVariant) oldVariant->removeVmePropertyReference(); @@ -1054,7 +1056,7 @@ void QQmlVMEMetaObject::writeVarProperty(int id, const QV4::Value &value) guard->setGuardedValue(valueObject, this, id); // Write the value and emit change signal as appropriate. - *(md->data() + id) = value; + md->set(cache->engine, id, value); activate(object, methodOffset() + id, 0); } @@ -1067,7 +1069,7 @@ void QQmlVMEMetaObject::writeProperty(int id, const QVariant &value) // Importantly, if the current value is a scarce resource, we need to ensure that it // gets automatically released by the engine if no other references to it exist. - QV4::VariantObject *oldv = (md->data() + id)->as<QV4::VariantObject>(); + const QV4::VariantObject *oldv = (md->data() + id)->as<QV4::VariantObject>(); if (oldv) oldv->removeVmePropertyReference(); @@ -1081,7 +1083,7 @@ void QQmlVMEMetaObject::writeProperty(int id, const QVariant &value) // Write the value and emit change signal as appropriate. QVariant currentValue = readPropertyAsVariant(id); - *(md->data() + id) = newv; + md->set(cache->engine, id, newv); if ((currentValue.userType() != value.userType() || currentValue != value)) activate(object, methodOffset() + id, 0); } else { @@ -1093,14 +1095,14 @@ void QQmlVMEMetaObject::writeProperty(int id, const QVariant &value) } else { QV4::MemberData *md = propertyAndMethodStorageAsMemberData(); if (md) { - QV4::VariantObject *v = (md->data() + id)->as<QV4::VariantObject>(); + const QV4::VariantObject *v = (md->data() + id)->as<QV4::VariantObject>(); needActivate = (!v || v->d()->data().userType() != value.userType() || v->d()->data() != value); if (v) v->removeVmePropertyReference(); - *(md->data() + id) = cache->engine->newVariantObject(value); - v = static_cast<QV4::VariantObject *>(md->data() + id); + md->set(cache->engine, id, cache->engine->newVariantObject(value)); + v = static_cast<const QV4::VariantObject *>(md->data() + id); v->addVmePropertyReference(); } } @@ -1139,7 +1141,7 @@ void QQmlVMEMetaObject::setVmeMethod(int index, const QV4::Value &function) QV4::MemberData *md = propertyAndMethodStorageAsMemberData(); if (!md) return; - *(md->data() + methodIndex + compiledObject->nProperties) = function; + md->set(cache->engine, methodIndex + compiledObject->nProperties, function); } QV4::ReturnedValue QQmlVMEMetaObject::vmeProperty(int index) const diff --git a/src/qml/qml/qqmlxmlhttprequest.cpp b/src/qml/qml/qqmlxmlhttprequest.cpp index d0d9f080da..b18904fc73 100644 --- a/src/qml/qml/qqmlxmlhttprequest.cpp +++ b/src/qml/qml/qqmlxmlhttprequest.cpp @@ -1597,10 +1597,12 @@ struct QQmlXMLHttpRequestWrapper : Object { QQmlXMLHttpRequest *request; }; -struct QQmlXMLHttpRequestCtor : FunctionObject { - void init(ExecutionEngine *engine); +#define QQmlXMLHttpRequestCtorMembers(class, Member) \ + Member(class, Pointer, Object *, proto) - Pointer<Object> proto; +DECLARE_HEAP_OBJECT(QQmlXMLHttpRequestCtor, FunctionObject) { + DECLARE_MARK_TABLE(QQmlXMLHttpRequestCtor); + void init(ExecutionEngine *engine); }; } @@ -1614,12 +1616,7 @@ struct QQmlXMLHttpRequestWrapper : public Object struct QQmlXMLHttpRequestCtor : public FunctionObject { V4_OBJECT2(QQmlXMLHttpRequestCtor, FunctionObject) - static void markObjects(Heap::Base *that, ExecutionEngine *e) { - QQmlXMLHttpRequestCtor::Data *c = static_cast<QQmlXMLHttpRequestCtor::Data *>(that); - if (c->proto) - c->proto->mark(e); - FunctionObject::markObjects(that, e); - } + static void construct(const Managed *that, Scope &scope, QV4::CallData *) { Scoped<QQmlXMLHttpRequestCtor> ctor(scope, that->as<QQmlXMLHttpRequestCtor>()); @@ -1686,7 +1683,7 @@ void QQmlXMLHttpRequestCtor::setupProto() ExecutionEngine *v4 = engine(); Scope scope(v4); ScopedObject p(scope, v4->newObject()); - d()->proto = p->d(); + d()->proto.set(scope.engine, p->d()); // Methods p->defineDefaultProperty(QStringLiteral("open"), method_open); diff --git a/src/qml/qml/v8/qqmlbuiltinfunctions.cpp b/src/qml/qml/v8/qqmlbuiltinfunctions.cpp index 8cc0b32168..68a64a28f0 100644 --- a/src/qml/qml/v8/qqmlbuiltinfunctions.cpp +++ b/src/qml/qml/v8/qqmlbuiltinfunctions.cpp @@ -2019,7 +2019,7 @@ void GlobalExtensions::method_qsTrIdNoOp(const BuiltinFunction *, Scope &scope, void GlobalExtensions::method_gc(const BuiltinFunction *, Scope &scope, CallData *) { - scope.engine->memoryManager->runGC(); + scope.engine->memoryManager->runGC(/* forceFullCollection = */ true); scope.result = QV4::Encode::undefined(); } diff --git a/src/qml/types/qqmllistmodel.cpp b/src/qml/types/qqmllistmodel.cpp index 5e2ff9b15b..efc2828dc5 100644 --- a/src/qml/types/qqmllistmodel.cpp +++ b/src/qml/types/qqmllistmodel.cpp @@ -1333,7 +1333,7 @@ void ModelNodeMetaObject::emitDirectNotifies(const int *changedRoles, int roleCo namespace QV4 { -void ModelObject::put(Managed *m, String *name, const Value &value) +bool ModelObject::put(Managed *m, String *name, const Value &value) { ModelObject *that = static_cast<ModelObject*>(m); @@ -1347,6 +1347,7 @@ void ModelObject::put(Managed *m, String *name, const Value &value) ModelNodeMetaObject *mo = ModelNodeMetaObject::get(that->object()); if (mo->initialized()) mo->emitPropertyNotification(name->toQString().toUtf8()); + return true; } ReturnedValue ModelObject::get(const Managed *m, String *name, bool *hasProperty) diff --git a/src/qml/types/qqmllistmodel_p_p.h b/src/qml/types/qqmllistmodel_p_p.h index cdce78e542..44583df2a6 100644 --- a/src/qml/types/qqmllistmodel_p_p.h +++ b/src/qml/types/qqmllistmodel_p_p.h @@ -179,7 +179,7 @@ struct ModelObject : public QObjectWrapper { struct ModelObject : public QObjectWrapper { - static void put(Managed *m, String *name, const Value& value); + static bool put(Managed *m, String *name, const Value& value); static ReturnedValue get(const Managed *m, String *name, bool *hasProperty); static void advanceIterator(Managed *m, ObjectIterator *it, Value *name, uint *index, Property *p, PropertyAttributes *attributes); diff --git a/src/qml/types/qquickpackage.cpp b/src/qml/types/qquickpackage.cpp index 47d9f2f483..17eff5ac40 100644 --- a/src/qml/types/qquickpackage.cpp +++ b/src/qml/types/qquickpackage.cpp @@ -89,7 +89,7 @@ public: { DataGuard(QObject *obj, QList<DataGuard> *l) : list(l) { (QQmlGuard<QObject>&)*this = obj; } QList<DataGuard> *list; - void objectDestroyed(QObject *) { + void objectDestroyed(QObject *) override { // we assume priv will always be destroyed after objectDestroyed calls list->removeOne(*this); } diff --git a/src/qml/util/qqmladaptormodel.cpp b/src/qml/util/qqmladaptormodel.cpp index b9d312d41f..c77495a1a7 100644 --- a/src/qml/util/qqmladaptormodel.cpp +++ b/src/qml/util/qqmladaptormodel.cpp @@ -103,8 +103,8 @@ public: virtual QVariant value(int role) const = 0; virtual void setValue(int role, const QVariant &value) = 0; - void setValue(const QString &role, const QVariant &value); - bool resolveIndex(const QQmlAdaptorModel &model, int idx); + void setValue(const QString &role, const QVariant &value) override; + bool resolveIndex(const QQmlAdaptorModel &model, int idx) override; static QV4::ReturnedValue get_property(QV4::CallContext *ctx, uint propertyId); static QV4::ReturnedValue set_property(QV4::CallContext *ctx, uint propertyId); @@ -141,7 +141,7 @@ public: const QList<QQmlDelegateModelItem *> &items, int index, int count, - const QVector<int> &roles) const + const QVector<int> &roles) const override { bool changed = roles.isEmpty() && !watchedRoles.isEmpty(); if (!changed && !watchedRoles.isEmpty() && watchedRoleIds.isEmpty()) { @@ -185,7 +185,7 @@ public: void replaceWatchedRoles( QQmlAdaptorModel &, const QList<QByteArray> &oldRoles, - const QList<QByteArray> &newRoles) const + const QList<QByteArray> &newRoles) const override { VDMModelDelegateDataType *dataType = const_cast<VDMModelDelegateDataType *>(this); @@ -239,12 +239,12 @@ public: // QAbstractDynamicMetaObject - void objectDestroyed(QObject *) + void objectDestroyed(QObject *) override { release(); } - int metaCall(QObject *object, QMetaObject::Call call, int id, void **arguments) + int metaCall(QObject *object, QMetaObject::Call call, int id, void **arguments) override { return static_cast<QQmlDMCachedModelData *>(object)->metaCall(call, id, arguments); } @@ -415,18 +415,18 @@ public: } } - QVariant value(int role) const + QVariant value(int role) const override { return type->model->aim()->index(index, 0, type->model->rootIndex).data(role); } - void setValue(int role, const QVariant &value) + void setValue(int role, const QVariant &value) override { type->model->aim()->setData( type->model->aim()->index(index, 0, type->model->rootIndex), value, role); } - QV4::ReturnedValue get() + QV4::ReturnedValue get() override { if (type->prototype.isUndefined()) { QQmlAdaptorModelEngineData * const data = engineData(v4); @@ -449,12 +449,12 @@ public: { } - int count(const QQmlAdaptorModel &model) const + int count(const QQmlAdaptorModel &model) const override { return model.aim()->rowCount(model.rootIndex); } - void cleanup(QQmlAdaptorModel &model, QQmlDelegateModel *vdm) const + void cleanup(QQmlAdaptorModel &model, QQmlDelegateModel *vdm) const override { QAbstractItemModel * const aim = model.aim(); if (aim && vdm) { @@ -477,7 +477,7 @@ public: const_cast<VDMAbstractItemModelDataType *>(this)->release(); } - QVariant value(const QQmlAdaptorModel &model, int index, const QString &role) const + QVariant value(const QQmlAdaptorModel &model, int index, const QString &role) const override { QHash<QByteArray, int>::const_iterator it = roleNames.find(role.toUtf8()); if (it != roleNames.end()) { @@ -489,26 +489,26 @@ public: } } - QVariant parentModelIndex(const QQmlAdaptorModel &model) const + QVariant parentModelIndex(const QQmlAdaptorModel &model) const override { return model ? QVariant::fromValue(model.aim()->parent(model.rootIndex)) : QVariant(); } - QVariant modelIndex(const QQmlAdaptorModel &model, int index) const + QVariant modelIndex(const QQmlAdaptorModel &model, int index) const override { return model ? QVariant::fromValue(model.aim()->index(index, 0, model.rootIndex)) : QVariant(); } - bool canFetchMore(const QQmlAdaptorModel &model) const + bool canFetchMore(const QQmlAdaptorModel &model) const override { return model && model.aim()->canFetchMore(model.rootIndex); } - void fetchMore(QQmlAdaptorModel &model) const + void fetchMore(QQmlAdaptorModel &model) const override { if (model) model.aim()->fetchMore(model.rootIndex); @@ -518,7 +518,7 @@ public: QQmlAdaptorModel &model, QQmlDelegateModelItemMetaType *metaType, QQmlEngine *engine, - int index) const + int index) const override { VDMAbstractItemModelDataType *dataType = const_cast<VDMAbstractItemModelDataType *>(this); if (!metaObject) @@ -606,7 +606,7 @@ public: return QV4::Encode::undefined(); } - QV4::ReturnedValue get() + QV4::ReturnedValue get() override { QQmlAdaptorModelEngineData *data = engineData(v4); QV4::Scope scope(v4); @@ -617,13 +617,13 @@ public: return o.asReturnedValue(); } - void setValue(const QString &role, const QVariant &value) + void setValue(const QString &role, const QVariant &value) override { if (role == QLatin1String("modelData")) cachedData = value; } - bool resolveIndex(const QQmlAdaptorModel &model, int idx) + bool resolveIndex(const QQmlAdaptorModel &model, int idx) override { if (index == -1) { index = idx; @@ -650,12 +650,12 @@ class VDMListDelegateDataType : public QQmlAdaptorModel::Accessors public: inline VDMListDelegateDataType() {} - int count(const QQmlAdaptorModel &model) const + int count(const QQmlAdaptorModel &model) const override { return model.list.count(); } - QVariant value(const QQmlAdaptorModel &model, int index, const QString &role) const + QVariant value(const QQmlAdaptorModel &model, int index, const QString &role) const override { return role == QLatin1String("modelData") ? model.list.at(index) @@ -666,7 +666,7 @@ public: QQmlAdaptorModel &model, QQmlDelegateModelItemMetaType *metaType, QQmlEngine *, - int index) const + int index) const override { return new QQmlDMListAccessorData( metaType, @@ -693,7 +693,7 @@ public: QObject *object); QObject *modelData() const { return object; } - QObject *proxiedObject() { return object; } + QObject *proxiedObject() override { return object; } QPointer<QObject> object; }; @@ -735,12 +735,12 @@ public: free(metaObject); } - int count(const QQmlAdaptorModel &model) const + int count(const QQmlAdaptorModel &model) const override { return model.list.count(); } - QVariant value(const QQmlAdaptorModel &model, int index, const QString &role) const + QVariant value(const QQmlAdaptorModel &model, int index, const QString &role) const override { if (QObject *object = model.list.at(index).value<QObject *>()) return object->property(role.toUtf8()); @@ -751,7 +751,7 @@ public: QQmlAdaptorModel &model, QQmlDelegateModelItemMetaType *metaType, QQmlEngine *, - int index) const + int index) const override { VDMObjectDelegateDataType *dataType = const_cast<VDMObjectDelegateDataType *>(this); if (!metaObject) @@ -768,7 +768,7 @@ public: metaObject = builder.toMetaObject(); } - void cleanup(QQmlAdaptorModel &, QQmlDelegateModel *) const + void cleanup(QQmlAdaptorModel &, QQmlDelegateModel *) const override { const_cast<VDMObjectDelegateDataType *>(this)->release(); } @@ -792,7 +792,7 @@ public: m_type->release(); } - int metaCall(QObject *o, QMetaObject::Call call, int id, void **arguments) + int metaCall(QObject *o, QMetaObject::Call call, int id, void **arguments) override { Q_ASSERT(o == m_data); Q_UNUSED(o); @@ -813,7 +813,7 @@ public: } } - int createProperty(const char *name, const char *) + int createProperty(const char *name, const char *) override { if (!m_data->object) return -1; diff --git a/src/quick/items/context2d/qquickcontext2d.cpp b/src/quick/items/context2d/qquickcontext2d.cpp index ce890771d9..db9b1acbdf 100644 --- a/src/quick/items/context2d/qquickcontext2d.cpp +++ b/src/quick/items/context2d/qquickcontext2d.cpp @@ -129,8 +129,6 @@ QT_BEGIN_NAMESPACE Q_CORE_EXPORT double qstrtod(const char *s00, char const **se, bool *ok); -#define DEGREES(t) ((t) * 180.0 / M_PI) - #define CHECK_CONTEXT(r) if (!r || !r->d()->context || !r->d()->context->bufferValid()) \ THROW_GENERIC_ERROR("Not a Context2D object"); @@ -905,7 +903,7 @@ struct QQuickJSContext2DPixelData : public QV4::Object V4_NEEDS_DESTROY static QV4::ReturnedValue getIndexed(const QV4::Managed *m, uint index, bool *hasProperty); - static void putIndexed(QV4::Managed *m, uint index, const QV4::Value &value); + static bool putIndexed(QV4::Managed *m, uint index, const QV4::Value &value); static void proto_get_length(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData); }; @@ -1643,7 +1641,7 @@ void QQuickJSContext2DPrototype::method_createConicalGradient(const QV4::Builtin if (callData->argc >= 3) { qreal x = callData->args[0].toNumber(); qreal y = callData->args[1].toNumber(); - qreal angle = DEGREES(callData->args[2].toNumber()); + qreal angle = qRadiansToDegrees(callData->args[2].toNumber()); if (!qt_is_finite(x) || !qt_is_finite(y)) { THROW_DOM(DOMEXCEPTION_NOT_SUPPORTED_ERR, "createConicalGradient(): Incorrect arguments"); } @@ -3083,13 +3081,13 @@ QV4::ReturnedValue QQuickJSContext2DPixelData::getIndexed(const QV4::Managed *m, return QV4::Encode::undefined(); } -void QQuickJSContext2DPixelData::putIndexed(QV4::Managed *m, uint index, const QV4::Value &value) +bool QQuickJSContext2DPixelData::putIndexed(QV4::Managed *m, uint index, const QV4::Value &value) { Q_ASSERT(m->as<QQuickJSContext2DPixelData>()); QV4::ExecutionEngine *v4 = static_cast<QQuickJSContext2DPixelData *>(m)->engine(); QV4::Scope scope(v4); if (scope.hasException()) - return; + return false; QV4::Scoped<QQuickJSContext2DPixelData> r(scope, static_cast<QQuickJSContext2DPixelData *>(m)); @@ -3115,7 +3113,10 @@ void QQuickJSContext2DPixelData::putIndexed(QV4::Managed *m, uint index, const Q *pixel = qRgba(qRed(*pixel), qGreen(*pixel), qBlue(*pixel), v); break; } + return true; } + + return false; } /*! \qmlmethod CanvasImageData QtQuick::Context2D::createImageData(real sw, real sh) @@ -3367,7 +3368,7 @@ void QQuickContext2D::rotate(qreal angle) return; QTransform newTransform =state.matrix; - newTransform.rotate(DEGREES(angle)); + newTransform.rotate(qRadiansToDegrees(angle)); if (!newTransform.isInvertible()) { state.invertibleCTM = false; @@ -3376,7 +3377,7 @@ void QQuickContext2D::rotate(qreal angle) state.matrix = newTransform; buffer()->updateMatrix(state.matrix); - m_path = QTransform().rotate(-DEGREES(angle)).map(m_path); + m_path = QTransform().rotate(-qRadiansToDegrees(angle)).map(m_path); } void QQuickContext2D::shear(qreal h, qreal v) @@ -3773,8 +3774,8 @@ void QQuickContext2D::arc(qreal xc, qreal yc, qreal radius, qreal sar, qreal ear antiClockWise = !antiClockWise; //end hack - float sa = DEGREES(sar); - float ea = DEGREES(ear); + float sa = qRadiansToDegrees(sar); + float ea = qRadiansToDegrees(ear); double span = 0; diff --git a/src/quick/items/qquickimage.cpp b/src/quick/items/qquickimage.cpp index f71a2fbdbd..f3d7dc4b56 100644 --- a/src/quick/items/qquickimage.cpp +++ b/src/quick/items/qquickimage.cpp @@ -514,37 +514,41 @@ void QQuickImage::updatePaintedGeometry() setImplicitSize(0, 0); return; } - qreal w = widthValid() ? width() : d->pix.width(); - qreal widthScale = w / qreal(d->pix.width()); - qreal h = heightValid() ? height() : d->pix.height(); - qreal heightScale = h / qreal(d->pix.height()); + const qreal pixWidth = d->pix.width() / d->devicePixelRatio; + const qreal pixHeight = d->pix.height() / d->devicePixelRatio; + const qreal w = widthValid() ? width() : pixWidth; + const qreal widthScale = w / pixWidth; + const qreal h = heightValid() ? height() : pixHeight; + const qreal heightScale = h / pixHeight; if (widthScale <= heightScale) { d->paintedWidth = w; - d->paintedHeight = widthScale * qreal(d->pix.height()); + d->paintedHeight = widthScale * pixHeight; } else if (heightScale < widthScale) { - d->paintedWidth = heightScale * qreal(d->pix.width()); + d->paintedWidth = heightScale * pixWidth; d->paintedHeight = h; } - qreal iHeight = (widthValid() && !heightValid()) ? d->paintedHeight : d->pix.height(); - qreal iWidth = (heightValid() && !widthValid()) ? d->paintedWidth : d->pix.width(); + const qreal iHeight = (widthValid() && !heightValid()) ? d->paintedHeight : pixHeight; + const qreal iWidth = (heightValid() && !widthValid()) ? d->paintedWidth : pixWidth; setImplicitSize(iWidth, iHeight); } else if (d->fillMode == PreserveAspectCrop) { if (!d->pix.width() || !d->pix.height()) return; - qreal widthScale = width() / qreal(d->pix.width()); - qreal heightScale = height() / qreal(d->pix.height()); + const qreal pixWidth = d->pix.width() / d->devicePixelRatio; + const qreal pixHeight = d->pix.height() / d->devicePixelRatio; + qreal widthScale = width() / pixWidth; + qreal heightScale = height() / pixHeight; if (widthScale < heightScale) { widthScale = heightScale; } else if (heightScale < widthScale) { heightScale = widthScale; } - d->paintedHeight = heightScale * qreal(d->pix.height()); - d->paintedWidth = widthScale * qreal(d->pix.width()); + d->paintedHeight = heightScale * pixHeight; + d->paintedWidth = widthScale * pixWidth; } else if (d->fillMode == Pad) { - d->paintedWidth = d->pix.width(); - d->paintedHeight = d->pix.height(); + d->paintedWidth = d->pix.width() / d->devicePixelRatio; + d->paintedHeight = d->pix.height() / d->devicePixelRatio; } else { d->paintedWidth = width(); d->paintedHeight = height(); diff --git a/src/quick/items/qquickimage_p_p.h b/src/quick/items/qquickimage_p_p.h index 522dbca803..afc33def0f 100644 --- a/src/quick/items/qquickimage_p_p.h +++ b/src/quick/items/qquickimage_p_p.h @@ -58,7 +58,7 @@ QT_BEGIN_NAMESPACE class QQuickImageTextureProvider; -class QQuickImagePrivate : public QQuickImageBasePrivate +class Q_QUICK_PRIVATE_EXPORT QQuickImagePrivate : public QQuickImageBasePrivate { Q_DECLARE_PUBLIC(QQuickImage) diff --git a/src/quick/items/qquickimagebase.cpp b/src/quick/items/qquickimagebase.cpp index 22d631e917..33d69f5032 100644 --- a/src/quick/items/qquickimagebase.cpp +++ b/src/quick/items/qquickimagebase.cpp @@ -49,6 +49,30 @@ QT_BEGIN_NAMESPACE +// This function gives derived classes the chance set the devicePixelRatio +// if they're not happy with our implementation of it. +bool QQuickImageBasePrivate::updateDevicePixelRatio(qreal targetDevicePixelRatio) +{ + // QQuickImageProvider and SVG can generate a high resolution image when + // sourceSize is set (this function is only called if it's set). + // If sourceSize is not set then the provider default size will be used, as usual. + bool setDevicePixelRatio = false; + if (url.scheme() == QLatin1String("image")) { + setDevicePixelRatio = true; + } else { + QString stringUrl = url.path(QUrl::PrettyDecoded); + if (stringUrl.endsWith(QLatin1String("svg")) || + stringUrl.endsWith(QLatin1String("svgz"))) { + setDevicePixelRatio = true; + } + } + + if (setDevicePixelRatio) + devicePixelRatio = targetDevicePixelRatio; + + return setDevicePixelRatio; +} + QQuickImageBase::QQuickImageBase(QQuickItem *parent) : QQuickImplicitSizeItem(*(new QQuickImageBasePrivate), parent) { @@ -221,26 +245,11 @@ void QQuickImageBase::load() QUrl loadUrl = d->url; - // QQuickImageProvider and SVG can generate a high resolution image when - // sourceSize is set. If sourceSize is not set then the provider default size - // will be used, as usual. - bool setDevicePixelRatio = false; - if (d->sourcesize.isValid()) { - if (loadUrl.scheme() == QLatin1String("image")) { - setDevicePixelRatio = true; - } else { - QString stringUrl = loadUrl.path(QUrl::PrettyDecoded); - if (stringUrl.endsWith(QLatin1String("svg")) || - stringUrl.endsWith(QLatin1String("svgz"))) { - setDevicePixelRatio = true; - } - } - - if (setDevicePixelRatio) - d->devicePixelRatio = targetDevicePixelRatio; - } + bool updatedDevicePixelRatio = false; + if (d->sourcesize.isValid()) + updatedDevicePixelRatio = d->updateDevicePixelRatio(targetDevicePixelRatio); - if (!setDevicePixelRatio) { + if (!updatedDevicePixelRatio) { // (possible) local file: loadUrl and d->devicePixelRatio will be modified if // an "@2x" file is found. resolve2xLocalFile(d->url, targetDevicePixelRatio, &loadUrl, &d->devicePixelRatio); diff --git a/src/quick/items/qquickimagebase_p_p.h b/src/quick/items/qquickimagebase_p_p.h index d9b609c7fe..1b771166a2 100644 --- a/src/quick/items/qquickimagebase_p_p.h +++ b/src/quick/items/qquickimagebase_p_p.h @@ -59,7 +59,7 @@ QT_BEGIN_NAMESPACE class QNetworkReply; -class QQuickImageBasePrivate : public QQuickImplicitSizeItemPrivate +class Q_QUICK_PRIVATE_EXPORT QQuickImageBasePrivate : public QQuickImplicitSizeItemPrivate { Q_DECLARE_PUBLIC(QQuickImageBase) @@ -75,6 +75,8 @@ public: { } + virtual bool updateDevicePixelRatio(qreal targetDevicePixelRatio); + QQuickPixmap pix; QQuickImageBase::Status status; QUrl url; diff --git a/src/quick/items/qquickitem.cpp b/src/quick/items/qquickitem.cpp index 1a244b0dd9..539a374dd9 100644 --- a/src/quick/items/qquickitem.cpp +++ b/src/quick/items/qquickitem.cpp @@ -6746,8 +6746,27 @@ bool QQuickItem::heightValid() const } /*! - \internal - */ + \since 5.10 + + Returns the size of the item. + + \sa setSize, width, height + */ + +QSizeF QQuickItem::size() const +{ + Q_D(const QQuickItem); + return QSizeF(d->width, d->height); +} + + +/*! + \since 5.10 + + Sets the size of the item to \a size. + + \sa size, setWidth, setHeight + */ void QQuickItem::setSize(const QSizeF &size) { Q_D(QQuickItem); @@ -7867,6 +7886,7 @@ QQuickItemLayer::QQuickItemLayer(QQuickItem *item) , m_effect(0) , m_effectSource(0) , m_textureMirroring(QQuickShaderEffectSource::MirrorVertically) + , m_samples(0) { } @@ -7941,6 +7961,7 @@ void QQuickItemLayer::activate() m_effectSource->setWrapMode(m_wrapMode); m_effectSource->setFormat(m_format); m_effectSource->setTextureMirroring(m_textureMirroring); + m_effectSource->setSamples(m_samples); if (m_effectComponent) activateEffect(); @@ -8234,6 +8255,44 @@ void QQuickItemLayer::setTextureMirroring(QQuickShaderEffectSource::TextureMirro } /*! + \qmlproperty enumeration QtQuick::Item::layer.samples + \since 5.10 + + This property allows requesting multisampled rendering in the layer. + + By default multisampling is enabled whenever multisampling is + enabled for the entire window, assuming the scenegraph renderer in + use and the underlying graphics API supports this. + + By setting the value to 2, 4, etc. multisampled rendering can be requested + for a part of the scene without enabling multisampling for the entire + scene. This way multisampling is applied only to a given subtree, which can + lead to significant performance gains since multisampling is not applied to + other parts of the scene. + + \note Enabling multisampling can be potentially expensive regardless of the + layer's size, as it incurs a hardware and driver dependent performance and + memory cost. + + \note This property is only functional when support for multisample + renderbuffers and framebuffer blits is available. Otherwise the value is + silently ignored. + */ + +void QQuickItemLayer::setSamples(int count) +{ + if (m_samples == count) + return; + + m_samples = count; + + if (m_effectSource) + m_effectSource->setSamples(m_samples); + + emit samplesChanged(count); +} + +/*! \qmlproperty string QtQuick::Item::layer.samplerName Holds the name of the effect's source texture property. diff --git a/src/quick/items/qquickitem.h b/src/quick/items/qquickitem.h index c9494d91bd..f58946d01d 100644 --- a/src/quick/items/qquickitem.h +++ b/src/quick/items/qquickitem.h @@ -237,6 +237,7 @@ public: void setImplicitHeight(qreal); qreal implicitHeight() const; + QSizeF size() const; void setSize(const QSizeF &size); TransformOrigin transformOrigin() const; diff --git a/src/quick/items/qquickitem_p.h b/src/quick/items/qquickitem_p.h index c0c9bd46bd..797ba42781 100644 --- a/src/quick/items/qquickitem_p.h +++ b/src/quick/items/qquickitem_p.h @@ -152,6 +152,8 @@ class QQuickItemLayer : public QObject, public QQuickItemChangeListener Q_PROPERTY(QByteArray samplerName READ name WRITE setName NOTIFY nameChanged) Q_PROPERTY(QQmlComponent *effect READ effect WRITE setEffect NOTIFY effectChanged) Q_PROPERTY(QQuickShaderEffectSource::TextureMirroring textureMirroring READ textureMirroring WRITE setTextureMirroring NOTIFY textureMirroringChanged) + Q_PROPERTY(int samples READ samples WRITE setSamples NOTIFY samplesChanged) + public: QQuickItemLayer(QQuickItem *item); ~QQuickItemLayer(); @@ -189,6 +191,9 @@ public: QQuickShaderEffectSource::TextureMirroring textureMirroring() const { return m_textureMirroring; } void setTextureMirroring(QQuickShaderEffectSource::TextureMirroring mirroring); + int samples() const { return m_samples; } + void setSamples(int count); + QQuickShaderEffectSource *effectSource() const { return m_effectSource; } void itemGeometryChanged(QQuickItem *, QQuickGeometryChange, const QRectF &) Q_DECL_OVERRIDE; @@ -213,6 +218,7 @@ Q_SIGNALS: void formatChanged(QQuickShaderEffectSource::Format format); void sourceRectChanged(const QRectF &sourceRect); void textureMirroringChanged(QQuickShaderEffectSource::TextureMirroring mirroring); + void samplesChanged(int count); private: friend class QQuickTransformAnimatorJob; @@ -237,6 +243,7 @@ private: QQuickItem *m_effect; QQuickShaderEffectSource *m_effectSource; QQuickShaderEffectSource::TextureMirroring m_textureMirroring; + int m_samples; }; #endif diff --git a/src/quick/items/qquickitemanimation.cpp b/src/quick/items/qquickitemanimation.cpp index 9873622f41..874130b137 100644 --- a/src/quick/items/qquickitemanimation.cpp +++ b/src/quick/items/qquickitemanimation.cpp @@ -327,7 +327,7 @@ QAbstractAnimationJob* QQuickParentAnimation::transition(QQuickStateActions &act } if (scale != 0) - rotation = qAtan2(transform.m12()/scale, transform.m11()/scale) * 180/M_PI; + rotation = qRadiansToDegrees(qAtan2(transform.m12() / scale, transform.m11() / scale)); else { qmlWarning(this) << QQuickParentAnimation::tr("Unable to preserve appearance under scale of 0"); ok = false; diff --git a/src/quick/items/qquickitemsmodule.cpp b/src/quick/items/qquickitemsmodule.cpp index 5f6d44b54d..4d6ae0c3e2 100644 --- a/src/quick/items/qquickitemsmodule.cpp +++ b/src/quick/items/qquickitemsmodule.cpp @@ -385,6 +385,10 @@ static void qt_quickitems_defineModule(const char *uri, int major, int minor) qmlRegisterUncreatableType<QQuickBasePositioner, 9>(uri, 2, 9, "Positioner", QStringLiteral("Positioner is an abstract type that is only available as an attached property.")); #endif + +#if QT_CONFIG(quick_shadereffect) + qmlRegisterType<QQuickShaderEffectSource, 2>(uri, 2, 9, "ShaderEffectSource"); +#endif } static void initResources() diff --git a/src/quick/items/qquickpositioners.cpp b/src/quick/items/qquickpositioners.cpp index 05d3ae0191..70fc5fa65f 100644 --- a/src/quick/items/qquickpositioners.cpp +++ b/src/quick/items/qquickpositioners.cpp @@ -44,15 +44,23 @@ #include <QtQml/qqmlinfo.h> #include <QtCore/qcoreapplication.h> -#include <QtQuick/private/qquickstate_p.h> -#include <QtQuick/private/qquickstategroup_p.h> -#include <private/qquickstatechangescript_p.h> #include <QtQuick/private/qquicktransition_p.h> QT_BEGIN_NAMESPACE -static const QQuickItemPrivate::ChangeTypes watchedChanges - = QQuickItemPrivate::Geometry +// The default item change types that positioners are interested in. +static const QQuickItemPrivate::ChangeTypes explicitSizeItemChangeTypes = + QQuickItemPrivate::Geometry + | QQuickItemPrivate::SiblingOrder + | QQuickItemPrivate::Visibility + | QQuickItemPrivate::Destroyed; + +// The item change types for positioners that are only interested in the implicit +// size of the items they manage. These are used if useImplicitSize is true. +// useImplicitSize should be set in the constructor, before any items are added. +static const QQuickItemPrivate::ChangeTypes implicitSizeItemChangeTypes = + QQuickItemPrivate::ImplicitWidth + | QQuickItemPrivate::ImplicitHeight | QQuickItemPrivate::SiblingOrder | QQuickItemPrivate::Visibility | QQuickItemPrivate::Destroyed; @@ -60,13 +68,15 @@ static const QQuickItemPrivate::ChangeTypes watchedChanges void QQuickBasePositionerPrivate::watchChanges(QQuickItem *other) { QQuickItemPrivate *otherPrivate = QQuickItemPrivate::get(other); - otherPrivate->addItemChangeListener(this, watchedChanges); + otherPrivate->addItemChangeListener(this, useImplicitSize + ? implicitSizeItemChangeTypes : explicitSizeItemChangeTypes); } void QQuickBasePositionerPrivate::unwatchChanges(QQuickItem* other) { QQuickItemPrivate *otherPrivate = QQuickItemPrivate::get(other); - otherPrivate->removeItemChangeListener(this, watchedChanges); + otherPrivate->removeItemChangeListener(this, useImplicitSize + ? implicitSizeItemChangeTypes : explicitSizeItemChangeTypes); } @@ -326,7 +336,7 @@ void QQuickBasePositioner::prePositioning() if (wIdx < 0) { d->watchChanges(child); posItem.isNew = true; - if (!childPrivate->explicitVisible || !child->width() || !child->height()) { + if (!childPrivate->explicitVisible || !d->itemWidth(child) || !d->itemHeight(child)) { posItem.isVisible = false; posItem.index = -1; unpositionedItems.append(posItem); @@ -348,7 +358,7 @@ void QQuickBasePositioner::prePositioning() PositionedItem *item = &oldItems[wIdx]; // Items are only omitted from positioning if they are explicitly hidden // i.e. their positioning is not affected if an ancestor is hidden. - if (!childPrivate->explicitVisible || !child->width() || !child->height()) { + if (!childPrivate->explicitVisible || !d->itemWidth(child) || !d->itemHeight(child)) { item->isVisible = false; item->index = -1; unpositionedItems.append(*item); @@ -947,6 +957,7 @@ QQuickColumn::QQuickColumn(QQuickItem *parent) void QQuickColumn::doPositioning(QSizeF *contentSize) { //Precondition: All items in the positioned list have a valid item pointer and should be positioned + QQuickBasePositionerPrivate *d = static_cast<QQuickBasePositionerPrivate*>(QQuickBasePositionerPrivate::get(this)); qreal voffset = topPadding(); const qreal padding = leftPadding() + rightPadding(); contentSize->setWidth(qMax(contentSize->width(), padding)); @@ -955,9 +966,9 @@ void QQuickColumn::doPositioning(QSizeF *contentSize) PositionedItem &child = positionedItems[ii]; positionItem(child.itemX() + leftPadding() - child.leftPadding, voffset, &child); child.updatePadding(leftPadding(), topPadding(), rightPadding(), bottomPadding()); - contentSize->setWidth(qMax(contentSize->width(), child.item->width() + padding)); + contentSize->setWidth(qMax(contentSize->width(), d->itemWidth(child.item) + padding)); - voffset += child.item->height(); + voffset += d->itemHeight(child.item); voffset += spacing(); } @@ -1137,7 +1148,7 @@ public: : QQuickBasePositionerPrivate() {} - void effectiveLayoutDirectionChange() + void effectiveLayoutDirectionChange() override { Q_Q(QQuickRow); // For RTL layout the positioning changes when the width changes. @@ -1225,9 +1236,9 @@ void QQuickRow::doPositioning(QSizeF *contentSize) hoffsets << hoffset; } - contentSize->setHeight(qMax(contentSize->height(), child.item->height() + padding)); + contentSize->setHeight(qMax(contentSize->height(), d->itemHeight(child.item) + padding)); - hoffset += child.item->width(); + hoffset += d->itemWidth(child.item); hoffset += spacing(); } @@ -1248,7 +1259,7 @@ void QQuickRow::doPositioning(QSizeF *contentSize) int acc = 0; for (int ii = 0; ii < positionedItems.count(); ++ii) { PositionedItem &child = positionedItems[ii]; - hoffset = end - hoffsets[acc++] - child.item->width(); + hoffset = end - hoffsets[acc++] - d->itemWidth(child.item); positionItem(hoffset, child.itemY() + topPadding() - child.topPadding, &child); child.updatePadding(leftPadding(), topPadding(), rightPadding(), bottomPadding()); } @@ -1436,7 +1447,7 @@ public: : QQuickBasePositionerPrivate() {} - void effectiveLayoutDirectionChange() + void effectiveLayoutDirectionChange() override { Q_Q(QQuickGrid); // For RTL layout the positioning changes when the width changes. @@ -1749,10 +1760,12 @@ void QQuickGrid::doPositioning(QSizeF *contentSize) break; const PositionedItem &child = positionedItems.at(childIndex++); - if (child.item->width() > maxColWidth[j]) - maxColWidth[j] = child.item->width(); - if (child.item->height() > maxRowHeight[i]) - maxRowHeight[i] = child.item->height(); + const qreal childWidth = d->itemWidth(child.item); + const qreal childHeight = d->itemHeight(child.item); + if (childWidth > maxColWidth[j]) + maxColWidth[j] = childWidth; + if (childHeight > maxRowHeight[i]) + maxRowHeight[i] = childHeight; } } } else { @@ -1767,10 +1780,12 @@ void QQuickGrid::doPositioning(QSizeF *contentSize) break; const PositionedItem &child = positionedItems.at(childIndex++); - if (child.item->width() > maxColWidth[j]) - maxColWidth[j] = child.item->width(); - if (child.item->height() > maxRowHeight[i]) - maxRowHeight[i] = child.item->height(); + const qreal childWidth = d->itemWidth(child.item); + const qreal childHeight = d->itemHeight(child.item); + if (childWidth > maxColWidth[j]) + maxColWidth[j] = childWidth; + if (childHeight > maxRowHeight[i]) + maxRowHeight[i] = childHeight; } } } @@ -1812,20 +1827,22 @@ void QQuickGrid::doPositioning(QSizeF *contentSize) for (int i = 0; i < positionedItems.count(); ++i) { PositionedItem &child = positionedItems[i]; qreal childXOffset = xoffset; + const qreal childWidth = d->itemWidth(child.item); + const qreal childHeight = d->itemHeight(child.item); if (effectiveHAlign() == AlignRight) - childXOffset += maxColWidth[curCol] - child.item->width(); + childXOffset += maxColWidth[curCol] - childWidth; else if (hItemAlign() == AlignHCenter) - childXOffset += (maxColWidth[curCol] - child.item->width())/2.0; + childXOffset += (maxColWidth[curCol] - childWidth)/2.0; if (!d->isLeftToRight()) childXOffset -= maxColWidth[curCol]; qreal alignYOffset = yoffset; if (m_vItemAlign == AlignVCenter) - alignYOffset += (maxRowHeight[curRow] - child.item->height())/2.0; + alignYOffset += (maxRowHeight[curRow] - childHeight)/2.0; else if (m_vItemAlign == AlignBottom) - alignYOffset += maxRowHeight[curRow] - child.item->height(); + alignYOffset += maxRowHeight[curRow] - childHeight; positionItem(childXOffset, alignYOffset, &child); child.updatePadding(leftPadding(), topPadding(), rightPadding(), bottomPadding()); @@ -2023,7 +2040,7 @@ public: : QQuickBasePositionerPrivate(), flow(QQuickFlow::LeftToRight) {} - void effectiveLayoutDirectionChange() + void effectiveLayoutDirectionChange() override { Q_Q(QQuickFlow); // Don't postpone, as it might be the only trigger for visible changes. @@ -2143,15 +2160,17 @@ void QQuickFlow::doPositioning(QSizeF *contentSize) for (int i = 0; i < positionedItems.count(); ++i) { PositionedItem &child = positionedItems[i]; + const qreal childWidth = d->itemWidth(child.item); + const qreal childHeight = d->itemHeight(child.item); if (d->flow == LeftToRight) { - if (widthValid() && hoffset != hoffset1 && hoffset + child.item->width() + hoffset2 > width()) { + if (widthValid() && hoffset != hoffset1 && hoffset + childWidth + hoffset2 > width()) { hoffset = hoffset1; voffset += linemax + spacing(); linemax = 0; } } else { - if (heightValid() && voffset != voffset1 && voffset + child.item->height() + bottomPadding() > height()) { + if (heightValid() && voffset != voffset1 && voffset + childHeight + bottomPadding() > height()) { voffset = voffset1; hoffset += linemax + spacing(); linemax = 0; @@ -2168,17 +2187,17 @@ void QQuickFlow::doPositioning(QSizeF *contentSize) child.bottomPadding = bottomPadding(); } - contentSize->setWidth(qMax(contentSize->width(), hoffset + child.item->width() + hoffset2)); - contentSize->setHeight(qMax(contentSize->height(), voffset + child.item->height() + bottomPadding())); + contentSize->setWidth(qMax(contentSize->width(), hoffset + childWidth + hoffset2)); + contentSize->setHeight(qMax(contentSize->height(), voffset + childHeight + bottomPadding())); if (d->flow == LeftToRight) { - hoffset += child.item->width(); + hoffset += childWidth; hoffset += spacing(); - linemax = qMax(linemax, child.item->height()); + linemax = qMax(linemax, childHeight); } else { - voffset += child.item->height(); + voffset += childHeight; voffset += spacing(); - linemax = qMax(linemax, child.item->width()); + linemax = qMax(linemax, childWidth); } } @@ -2193,7 +2212,7 @@ void QQuickFlow::doPositioning(QSizeF *contentSize) int acc = 0; for (int i = 0; i < positionedItems.count(); ++i) { PositionedItem &child = positionedItems[i]; - hoffset = end - hoffsets[acc++] - child.item->width(); + hoffset = end - hoffsets[acc++] - d->itemWidth(child.item); positionItemX(hoffset, &child); child.leftPadding = leftPadding(); child.rightPadding = rightPadding(); @@ -2217,4 +2236,18 @@ void QQuickFlow::reportConflictingAnchors() qmlWarning(this) << "Cannot specify anchors for items inside Flow." << " Flow will not function."; } +QQuickImplicitRow::QQuickImplicitRow(QQuickItem *parent) + : QQuickRow(parent) +{ + QQuickBasePositionerPrivate *d = QQuickBasePositioner::get(this); + d->useImplicitSize = true; +} + +QQuickImplicitGrid::QQuickImplicitGrid(QQuickItem *parent) + : QQuickGrid(parent) +{ + QQuickBasePositionerPrivate *d = QQuickBasePositioner::get(this); + d->useImplicitSize = true; +} + QT_END_NAMESPACE diff --git a/src/quick/items/qquickpositioners_p.h b/src/quick/items/qquickpositioners_p.h index ae6e795794..cfe163b4c1 100644 --- a/src/quick/items/qquickpositioners_p.h +++ b/src/quick/items/qquickpositioners_p.h @@ -58,7 +58,6 @@ QT_REQUIRE_CONFIG(quick_positioners); #include "qquickimplicitsizeitem_p.h" #include "qquickitemviewtransition_p.h" -#include <QtQuick/private/qquickstate_p.h> #include <private/qpodvector_p.h> #include <QtCore/qobject.h> @@ -68,7 +67,7 @@ QT_BEGIN_NAMESPACE class QQuickBasePositionerPrivate; -class QQuickPositionerAttached : public QObject +class Q_QUICK_PRIVATE_EXPORT QQuickPositionerAttached : public QObject { Q_OBJECT @@ -133,6 +132,11 @@ public: static QQuickPositionerAttached *qmlAttachedProperties(QObject *obj); + static QQuickBasePositionerPrivate* get(QQuickBasePositioner *positioner) + { + return positioner->d_func(); + } + void updateAttachedProperties(QQuickPositionerAttached *specificProperty = 0, QQuickItem *specificPropertyOwner = 0) const; qreal padding() const; @@ -183,7 +187,7 @@ protected: virtual void doPositioning(QSizeF *contentSize)=0; virtual void reportConflictingAnchors()=0; - class PositionedItem + class Q_QUICK_PRIVATE_EXPORT PositionedItem { public : PositionedItem(QQuickItem *i); @@ -228,7 +232,7 @@ private: Q_DECLARE_PRIVATE(QQuickBasePositioner) }; -class Q_AUTOTEST_EXPORT QQuickColumn : public QQuickBasePositioner +class Q_QUICK_PRIVATE_EXPORT QQuickColumn : public QQuickBasePositioner { Q_OBJECT public: @@ -242,7 +246,7 @@ private: }; class QQuickRowPrivate; -class Q_AUTOTEST_EXPORT QQuickRow: public QQuickBasePositioner +class Q_QUICK_PRIVATE_EXPORT QQuickRow: public QQuickBasePositioner { Q_OBJECT Q_PROPERTY(Qt::LayoutDirection layoutDirection READ layoutDirection WRITE setLayoutDirection NOTIFY layoutDirectionChanged) @@ -267,7 +271,7 @@ private: }; class QQuickGridPrivate; -class Q_AUTOTEST_EXPORT QQuickGrid : public QQuickBasePositioner +class Q_QUICK_PRIVATE_EXPORT QQuickGrid : public QQuickBasePositioner { Q_OBJECT Q_PROPERTY(int rows READ rows WRITE setRows NOTIFY rowsChanged) @@ -354,7 +358,7 @@ private: }; class QQuickFlowPrivate; -class Q_AUTOTEST_EXPORT QQuickFlow: public QQuickBasePositioner +class Q_QUICK_PRIVATE_EXPORT QQuickFlow: public QQuickBasePositioner { Q_OBJECT Q_PROPERTY(Flow flow READ flow WRITE setFlow NOTIFY flowChanged) @@ -387,6 +391,22 @@ private: Q_DECLARE_PRIVATE(QQuickFlow) }; +class Q_QUICK_PRIVATE_EXPORT QQuickImplicitRow : public QQuickRow +{ + Q_OBJECT + +public: + QQuickImplicitRow(QQuickItem *parent = nullptr); +}; + +class Q_QUICK_PRIVATE_EXPORT QQuickImplicitGrid : public QQuickGrid +{ + Q_OBJECT + +public: + QQuickImplicitGrid(QQuickItem *parent = nullptr); +}; + QT_END_NAMESPACE @@ -394,6 +414,8 @@ QML_DECLARE_TYPE(QQuickColumn) QML_DECLARE_TYPE(QQuickRow) QML_DECLARE_TYPE(QQuickGrid) QML_DECLARE_TYPE(QQuickFlow) +QML_DECLARE_TYPE(QQuickImplicitRow) +QML_DECLARE_TYPE(QQuickImplicitGrid) QML_DECLARE_TYPE(QQuickBasePositioner) QML_DECLARE_TYPEINFO(QQuickBasePositioner, QML_HAS_ATTACHED_PROPERTIES) diff --git a/src/quick/items/qquickpositioners_p_p.h b/src/quick/items/qquickpositioners_p_p.h index 6dd84e6098..1a7051615c 100644 --- a/src/quick/items/qquickpositioners_p_p.h +++ b/src/quick/items/qquickpositioners_p_p.h @@ -58,9 +58,6 @@ QT_REQUIRE_CONFIG(quick_positioners); #include "qquickpositioners_p.h" #include "qquickimplicitsizeitem_p_p.h" -#include <QtQuick/private/qquickstate_p.h> -#include <private/qquicktransitionmanager_p_p.h> -#include <private/qquickstatechangescript_p.h> #include <private/qlazilyallocated_p.h> #include <QtCore/qobject.h> @@ -92,10 +89,14 @@ public: QLazilyAllocated<ExtraData> extra; QQuickBasePositionerPrivate() - : spacing(0), type(QQuickBasePositioner::None) - , transitioner(0), positioningDirty(false) - , doingPositioning(false), anchorConflict(false), layoutDirection(Qt::LeftToRight) - + : spacing(0) + , type(QQuickBasePositioner::None) + , transitioner(0) + , positioningDirty(false) + , doingPositioning(false) + , anchorConflict(false) + , useImplicitSize(false) + , layoutDirection(Qt::LeftToRight) { } @@ -122,6 +123,7 @@ public: bool positioningDirty : 1; bool doingPositioning : 1; bool anchorConflict : 1; + bool useImplicitSize : 1; Qt::LayoutDirection layoutDirection; @@ -177,6 +179,34 @@ public: { } + void itemImplicitWidthChanged(QQuickItem *) override + { + Q_ASSERT(useImplicitSize); + setPositioningDirty(); + } + + void itemImplicitHeightChanged(QQuickItem *) override + { + Q_ASSERT(useImplicitSize); + setPositioningDirty(); + } + + qreal itemWidth(QQuickItem *item) const + { + if (Q_LIKELY(!useImplicitSize)) + return item->width(); + + return item->implicitWidth(); + } + + qreal itemHeight(QQuickItem *item) const + { + if (Q_LIKELY(!useImplicitSize)) + return item->height(); + + return item->implicitHeight(); + } + inline qreal padding() const { return extra.isAllocated() ? extra->padding : 0.0; } void setTopPadding(qreal value, bool reset = false); void setLeftPadding(qreal value, bool reset = false); diff --git a/src/quick/items/qquickshadereffectsource.cpp b/src/quick/items/qquickshadereffectsource.cpp index 1b37a746d3..c782ddb5f7 100644 --- a/src/quick/items/qquickshadereffectsource.cpp +++ b/src/quick/items/qquickshadereffectsource.cpp @@ -189,6 +189,7 @@ QQuickShaderEffectSource::QQuickShaderEffectSource(QQuickItem *parent) , m_sourceItem(0) , m_textureSize(0, 0) , m_format(RGBA) + , m_samples(0) , m_live(true) , m_hideSource(false) , m_mipmap(false) @@ -582,6 +583,44 @@ void QQuickShaderEffectSource::setTextureMirroring(TextureMirroring mirroring) } /*! + \qmlproperty int QtQuick::ShaderEffectSource::samples + \since 5.10 + + This property allows requesting multisampled rendering. + + By default multisampling is enabled whenever multisampling is enabled for + the entire window, assuming the scenegraph renderer in use and the + underlying graphics API supports this. + + By setting the value to 2, 4, etc. multisampled rendering can be requested + for a part of the scene without enabling multisampling for the entire + scene. This way multisampling is applied only to a given subtree, which can + lead to significant performance gains since multisampling is not applied to + other parts of the scene. + + \note Enabling multisampling can be potentially expensive regardless of the + layer's size, as it incurs a hardware and driver dependent performance and + memory cost. + + \note This property is only functional when support for multisample + renderbuffers and framebuffer blits is available. Otherwise the value is + silently ignored. + */ +int QQuickShaderEffectSource::samples() const +{ + return m_samples; +} + +void QQuickShaderEffectSource::setSamples(int count) +{ + if (count == m_samples) + return; + m_samples = count; + update(); + emit samplesChanged(); +} + +/*! \qmlmethod QtQuick::ShaderEffectSource::scheduleUpdate() Schedules a re-rendering of the texture for the next frame. @@ -683,6 +722,7 @@ QSGNode *QQuickShaderEffectSource::updatePaintNode(QSGNode *oldNode, UpdatePaint m_texture->setHasMipmaps(m_mipmap); m_texture->setMirrorHorizontal(m_textureMirroring & MirrorHorizontally); m_texture->setMirrorVertical(m_textureMirroring & MirrorVertically); + m_texture->setSamples(m_samples); if (m_grab) m_texture->scheduleUpdate(); diff --git a/src/quick/items/qquickshadereffectsource_p.h b/src/quick/items/qquickshadereffectsource_p.h index 5e7e354feb..d9f9079a3d 100644 --- a/src/quick/items/qquickshadereffectsource_p.h +++ b/src/quick/items/qquickshadereffectsource_p.h @@ -88,6 +88,7 @@ class Q_QUICK_PRIVATE_EXPORT QQuickShaderEffectSource : public QQuickItem, publi Q_PROPERTY(bool mipmap READ mipmap WRITE setMipmap NOTIFY mipmapChanged) Q_PROPERTY(bool recursive READ recursive WRITE setRecursive NOTIFY recursiveChanged) Q_PROPERTY(TextureMirroring textureMirroring READ textureMirroring WRITE setTextureMirroring NOTIFY textureMirroringChanged REVISION 1) + Q_PROPERTY(int samples READ samples WRITE setSamples NOTIFY samplesChanged REVISION 2) public: enum WrapMode { @@ -150,6 +151,9 @@ public: Q_INVOKABLE void scheduleUpdate(); + int samples() const; + void setSamples(int count); + Q_SIGNALS: void wrapModeChanged(); void sourceItemChanged(); @@ -161,6 +165,7 @@ Q_SIGNALS: void mipmapChanged(); void recursiveChanged(); void textureMirroringChanged(); + void samplesChanged(); void scheduledUpdateCompleted(); @@ -185,6 +190,7 @@ private: QRectF m_sourceRect; QSize m_textureSize; Format m_format; + int m_samples; uint m_live : 1; uint m_hideSource : 1; uint m_mipmap : 1; diff --git a/src/quick/items/qquickstateoperations.cpp b/src/quick/items/qquickstateoperations.cpp index b40a9e2843..a4ce13a199 100644 --- a/src/quick/items/qquickstateoperations.cpp +++ b/src/quick/items/qquickstateoperations.cpp @@ -101,7 +101,7 @@ void QQuickParentChangePrivate::doChange(QQuickItem *targetParent, QQuickItem *s } if (scale != 0) - rotation = qAtan2(transform.m12()/scale, transform.m11()/scale) * 180/M_PI; + rotation = qRadiansToDegrees(qAtan2(transform.m12() / scale, transform.m11() / scale)); else { qmlWarning(q) << QQuickParentChange::tr("Unable to preserve appearance under scale of 0"); ok = false; diff --git a/src/quick/items/qquickwindow.cpp b/src/quick/items/qquickwindow.cpp index e6245f90f3..80abf82e58 100644 --- a/src/quick/items/qquickwindow.cpp +++ b/src/quick/items/qquickwindow.cpp @@ -3399,6 +3399,11 @@ void QQuickWindow::setRenderTarget(QOpenGLFramebufferObject *fbo) The specified FBO must be created in the context of the window or one that shares with it. + \note \a fboId can also be set to 0. In this case rendering will target the + default framebuffer of whichever surface is current when the scenegraph + renders. \a size must still be valid, specifying the dimensions of the + surface. + \note This function only has an effect when using the default OpenGL scene graph adaptation. diff --git a/src/quick/scenegraph/adaptations/software/qsgsoftwarelayer_p.h b/src/quick/scenegraph/adaptations/software/qsgsoftwarelayer_p.h index d3f13e40b1..9f5a22e66f 100644 --- a/src/quick/scenegraph/adaptations/software/qsgsoftwarelayer_p.h +++ b/src/quick/scenegraph/adaptations/software/qsgsoftwarelayer_p.h @@ -93,6 +93,7 @@ public: void setDevicePixelRatio(qreal ratio) override; void setMirrorHorizontal(bool mirror) override; void setMirrorVertical(bool mirror) override; + void setSamples(int) override { } public slots: void markDirtyTexture() override; diff --git a/src/quick/scenegraph/adaptations/software/qsgsoftwarepixmaprenderer.cpp b/src/quick/scenegraph/adaptations/software/qsgsoftwarepixmaprenderer.cpp index f8c1a3d90b..ad6cf39425 100644 --- a/src/quick/scenegraph/adaptations/software/qsgsoftwarepixmaprenderer.cpp +++ b/src/quick/scenegraph/adaptations/software/qsgsoftwarepixmaprenderer.cpp @@ -64,7 +64,7 @@ void QSGSoftwarePixmapRenderer::renderScene(uint) class B : public QSGBindable { public: - void bind() const { } + void bind() const override { } } bindable; QSGRenderer::renderScene(bindable); } diff --git a/src/quick/scenegraph/adaptations/software/qsgsoftwarepublicnodes.cpp b/src/quick/scenegraph/adaptations/software/qsgsoftwarepublicnodes.cpp index 1fa5234377..d754089ce4 100644 --- a/src/quick/scenegraph/adaptations/software/qsgsoftwarepublicnodes.cpp +++ b/src/quick/scenegraph/adaptations/software/qsgsoftwarepublicnodes.cpp @@ -98,10 +98,10 @@ void QSGSoftwareImageNode::paint(QPainter *painter) if (!m_cachedPixmap.isNull()) { painter->drawPixmap(m_rect, m_cachedPixmap, m_sourceRect); - } else if (QSGSoftwarePixmapTexture *pt = dynamic_cast<QSGSoftwarePixmapTexture *>(m_texture)) { + } else if (QSGSoftwarePixmapTexture *pt = qobject_cast<QSGSoftwarePixmapTexture *>(m_texture)) { const QPixmap &pm = pt->pixmap(); painter->drawPixmap(m_rect, pm, m_sourceRect); - } else if (QSGPlainTexture *pt = dynamic_cast<QSGPlainTexture *>(m_texture)) { + } else if (QSGPlainTexture *pt = qobject_cast<QSGPlainTexture *>(m_texture)) { const QImage &im = pt->image(); painter->drawImage(m_rect, im, m_sourceRect); } @@ -113,14 +113,14 @@ void QSGSoftwareImageNode::updateCachedMirroredPixmap() m_cachedPixmap = QPixmap(); } else { - if (QSGSoftwarePixmapTexture *pt = dynamic_cast<QSGSoftwarePixmapTexture *>(m_texture)) { + if (QSGSoftwarePixmapTexture *pt = qobject_cast<QSGSoftwarePixmapTexture *>(m_texture)) { QTransform mirrorTransform; if (m_transformMode.testFlag(MirrorVertically)) mirrorTransform = mirrorTransform.scale(1, -1); if (m_transformMode.testFlag(MirrorHorizontally)) mirrorTransform = mirrorTransform.scale(-1, 1); m_cachedPixmap = pt->pixmap().transformed(mirrorTransform); - } else if (QSGPlainTexture *pt = dynamic_cast<QSGPlainTexture *>(m_texture)) { + } else if (QSGPlainTexture *pt = qobject_cast<QSGPlainTexture *>(m_texture)) { m_cachedPixmap = QPixmap::fromImage(pt->image().mirrored(m_transformMode.testFlag(MirrorHorizontally), m_transformMode.testFlag(MirrorVertically))); } else { m_cachedPixmap = QPixmap(); diff --git a/src/quick/scenegraph/adaptations/software/qsgsoftwarerenderablenode.cpp b/src/quick/scenegraph/adaptations/software/qsgsoftwarerenderablenode.cpp index 59c47db0c4..52984a4310 100644 --- a/src/quick/scenegraph/adaptations/software/qsgsoftwarerenderablenode.cpp +++ b/src/quick/scenegraph/adaptations/software/qsgsoftwarerenderablenode.cpp @@ -293,10 +293,10 @@ QRegion QSGSoftwareRenderableNode::renderNode(QPainter *painter, bool forceOpaqu case QSGSoftwareRenderableNode::SimpleTexture: { QSGTexture *texture = m_handle.simpleTextureNode->texture(); - if (QSGSoftwarePixmapTexture *pt = dynamic_cast<QSGSoftwarePixmapTexture *>(texture)) { + if (QSGSoftwarePixmapTexture *pt = qobject_cast<QSGSoftwarePixmapTexture *>(texture)) { const QPixmap &pm = pt->pixmap(); painter->drawPixmap(m_handle.simpleTextureNode->rect(), pm, m_handle.simpleTextureNode->sourceRect()); - } else if (QSGPlainTexture *pt = dynamic_cast<QSGPlainTexture *>(texture)) { + } else if (QSGPlainTexture *pt = qobject_cast<QSGPlainTexture *>(texture)) { const QImage &im = pt->image(); painter->drawImage(m_handle.simpleTextureNode->rect(), im, m_handle.simpleTextureNode->sourceRect()); } diff --git a/src/quick/scenegraph/adaptations/software/qsgsoftwarerenderer.cpp b/src/quick/scenegraph/adaptations/software/qsgsoftwarerenderer.cpp index cad826fb27..85d04fe136 100644 --- a/src/quick/scenegraph/adaptations/software/qsgsoftwarerenderer.cpp +++ b/src/quick/scenegraph/adaptations/software/qsgsoftwarerenderer.cpp @@ -90,7 +90,7 @@ void QSGSoftwareRenderer::renderScene(uint) class B : public QSGBindable { public: - void bind() const { } + void bind() const override { } } bindable; QSGRenderer::renderScene(bindable); } diff --git a/src/quick/scenegraph/adaptations/software/qsgsoftwarethreadedrenderloop.cpp b/src/quick/scenegraph/adaptations/software/qsgsoftwarethreadedrenderloop.cpp index 8abbefdd48..682f89721e 100644 --- a/src/quick/scenegraph/adaptations/software/qsgsoftwarethreadedrenderloop.cpp +++ b/src/quick/scenegraph/adaptations/software/qsgsoftwarethreadedrenderloop.cpp @@ -188,8 +188,8 @@ public: delete rc; } - bool event(QEvent *e); - void run(); + bool event(QEvent *e) override; + void run() override; void syncAndRender(); void sync(bool inExpose); diff --git a/src/quick/scenegraph/coreapi/qsgrenderer.cpp b/src/quick/scenegraph/coreapi/qsgrenderer.cpp index e5d464930c..bb2671f6c3 100644 --- a/src/quick/scenegraph/coreapi/qsgrenderer.cpp +++ b/src/quick/scenegraph/coreapi/qsgrenderer.cpp @@ -134,6 +134,7 @@ QSGRenderer::QSGRenderer(QSGRenderContext *context) , m_bindable(0) , m_changed_emitted(false) , m_is_rendering(false) + , m_is_preprocessing(false) { } @@ -189,7 +190,7 @@ void QSGRenderer::renderScene(uint fboId) class B : public QSGBindable { public: - void bind() const { QOpenGLFramebufferObject::bindDefault(); } + void bind() const override { QOpenGLFramebufferObject::bindDefault(); } } bindable; renderScene(bindable); } @@ -287,6 +288,8 @@ void QSGRenderer::nodeChanged(QSGNode *node, QSGNode::DirtyState state) void QSGRenderer::preprocess() { + m_is_preprocessing = true; + QSGRootNode *root = rootNode(); Q_ASSERT(root); @@ -298,6 +301,11 @@ void QSGRenderer::preprocess() for (QSet<QSGNode *>::const_iterator it = items.constBegin(); it != items.constEnd(); ++it) { QSGNode *n = *it; + + // If we are currently preprocessing, check this node hasn't been + // deleted or something. we don't want a use-after-free! + if (m_nodes_dont_preprocess.contains(n)) // skip + continue; if (!nodeUpdater()->isNodeBlocked(n, root)) { n->preprocess(); } @@ -315,8 +323,13 @@ void QSGRenderer::preprocess() updatePassTime = frameTimer.nsecsElapsed(); Q_QUICK_SG_PROFILE_RECORD(QQuickProfiler::SceneGraphRendererFrame, QQuickProfiler::SceneGraphRendererUpdate); + + m_is_preprocessing = false; + m_nodes_dont_preprocess.clear(); } + + void QSGRenderer::addNodesToPreprocess(QSGNode *node) { for (QSGNode *c = node->firstChild(); c; c = c->nextSibling()) @@ -329,8 +342,13 @@ void QSGRenderer::removeNodesToPreprocess(QSGNode *node) { for (QSGNode *c = node->firstChild(); c; c = c->nextSibling()) removeNodesToPreprocess(c); - if (node->flags() & QSGNode::UsePreprocess) + if (node->flags() & QSGNode::UsePreprocess) { m_nodes_to_preprocess.remove(node); + + // If preprocessing *now*, mark the node as gone. + if (m_is_preprocessing) + m_nodes_dont_preprocess.insert(node); + } } diff --git a/src/quick/scenegraph/coreapi/qsgrenderer_p.h b/src/quick/scenegraph/coreapi/qsgrenderer_p.h index 4589685765..1ea2775e6f 100644 --- a/src/quick/scenegraph/coreapi/qsgrenderer_p.h +++ b/src/quick/scenegraph/coreapi/qsgrenderer_p.h @@ -118,11 +118,13 @@ private: QSGNodeUpdater *m_node_updater; QSet<QSGNode *> m_nodes_to_preprocess; + QSet<QSGNode *> m_nodes_dont_preprocess; const QSGBindable *m_bindable; uint m_changed_emitted : 1; uint m_is_rendering : 1; + uint m_is_preprocessing : 1; }; class Q_QUICK_PRIVATE_EXPORT QSGBindable diff --git a/src/quick/scenegraph/qsgadaptationlayer.cpp b/src/quick/scenegraph/qsgadaptationlayer.cpp index 412023564f..f90706affe 100644 --- a/src/quick/scenegraph/qsgadaptationlayer.cpp +++ b/src/quick/scenegraph/qsgadaptationlayer.cpp @@ -40,7 +40,6 @@ #include "qsgadaptationlayer_p.h" #include <qmath.h> -#include <QtQuick/private/qsgdistancefieldutil_p.h> #include <QtQuick/private/qsgdistancefieldglyphnode_p.h> #include <QtQuick/private/qsgcontext_p.h> #include <private/qrawfont_p.h> @@ -57,9 +56,8 @@ static QElapsedTimer qsg_render_timer; QSGDistanceFieldGlyphCache::Texture QSGDistanceFieldGlyphCache::s_emptyTexture; -QSGDistanceFieldGlyphCache::QSGDistanceFieldGlyphCache(QSGDistanceFieldGlyphCacheManager *man, QOpenGLContext *c, const QRawFont &font) - : m_manager(man) - , m_pendingGlyphs(64) +QSGDistanceFieldGlyphCache::QSGDistanceFieldGlyphCache(QOpenGLContext *c, const QRawFont &font) + : m_pendingGlyphs(64) { Q_ASSERT(font.isValid()); diff --git a/src/quick/scenegraph/qsgadaptationlayer_p.h b/src/quick/scenegraph/qsgadaptationlayer_p.h index 03a1f7f281..ba146b884f 100644 --- a/src/quick/scenegraph/qsgadaptationlayer_p.h +++ b/src/quick/scenegraph/qsgadaptationlayer_p.h @@ -73,7 +73,6 @@ QT_BEGIN_NAMESPACE class QSGNode; class QImage; class TextureReference; -class QSGDistanceFieldGlyphCacheManager; class QSGDistanceFieldGlyphNode; class QOpenGLContext; class QSGInternalImageNode; @@ -209,6 +208,7 @@ public: virtual void setDevicePixelRatio(qreal ratio) = 0; virtual void setMirrorHorizontal(bool mirror) = 0; virtual void setMirrorVertical(bool mirror) = 0; + virtual void setSamples(int samples) = 0; Q_SLOT virtual void markDirtyTexture() = 0; Q_SLOT virtual void invalidated() = 0; @@ -408,7 +408,7 @@ public: class Q_QUICK_PRIVATE_EXPORT QSGDistanceFieldGlyphCache { public: - QSGDistanceFieldGlyphCache(QSGDistanceFieldGlyphCacheManager *man, QOpenGLContext *c, const QRawFont &font); + QSGDistanceFieldGlyphCache(QOpenGLContext *c, const QRawFont &font); virtual ~QSGDistanceFieldGlyphCache(); struct Metrics { @@ -442,8 +442,6 @@ public: bool operator == (const Texture &other) const { return textureId == other.textureId; } }; - const QSGDistanceFieldGlyphCacheManager *manager() const { return m_manager; } - const QRawFont &referenceFont() const { return m_referenceFont; } qreal fontScale(qreal pixelSize) const @@ -513,8 +511,6 @@ protected: inline bool isCoreProfile() const { return m_coreProfile; } private: - QSGDistanceFieldGlyphCacheManager *m_manager; - QRawFont m_referenceFont; int m_glyphCount; diff --git a/src/quick/scenegraph/qsgcontext.cpp b/src/quick/scenegraph/qsgcontext.cpp index d52f69c7a3..ff2379ecb5 100644 --- a/src/quick/scenegraph/qsgcontext.cpp +++ b/src/quick/scenegraph/qsgcontext.cpp @@ -333,7 +333,6 @@ QSGRendererInterface *QSGContext::rendererInterface(QSGRenderContext *renderCont QSGRenderContext::QSGRenderContext(QSGContext *context) : m_sg(context) - , m_distanceFieldCacheManager(0) { } diff --git a/src/quick/scenegraph/qsgcontext_p.h b/src/quick/scenegraph/qsgcontext_p.h index 2f5d5790ee..bd10453131 100644 --- a/src/quick/scenegraph/qsgcontext_p.h +++ b/src/quick/scenegraph/qsgcontext_p.h @@ -78,7 +78,6 @@ class QSGMaterial; class QSGRenderLoop; class QSGLayer; class QQuickTextureFactory; -class QSGDistanceFieldGlyphCacheManager; class QSGContext; class QQuickPaintedItem; class QSGRendererInterface; @@ -194,7 +193,7 @@ protected: QMutex m_mutex; QHash<QQuickTextureFactory *, QSGTexture *> m_textures; QSet<QSGTexture *> m_texturesToDelete; - QSGDistanceFieldGlyphCacheManager *m_distanceFieldCacheManager; + QHash<QRawFont, QSGDistanceFieldGlyphCache*> m_glyphCaches; QSet<QFontEngine *> m_fontEnginesToClean; }; diff --git a/src/quick/scenegraph/qsgdefaultcontext.cpp b/src/quick/scenegraph/qsgdefaultcontext.cpp index 405f1d86a4..be5fec9dab 100644 --- a/src/quick/scenegraph/qsgdefaultcontext.cpp +++ b/src/quick/scenegraph/qsgdefaultcontext.cpp @@ -39,7 +39,6 @@ #include "qsgdefaultcontext_p.h" -#include <QtQuick/private/qsgdistancefieldutil_p.h> #include <QtQuick/private/qsgdefaultinternalrectanglenode_p.h> #include <QtQuick/private/qsgdefaultinternalimagenode_p.h> #include <QtQuick/private/qsgdefaultpainternode_p.h> @@ -68,13 +67,13 @@ QT_BEGIN_NAMESPACE namespace QSGMultisampleAntialiasing { class ImageNode : public QSGDefaultInternalImageNode { public: - void setAntialiasing(bool) { } + void setAntialiasing(bool) override { } }; class RectangleNode : public QSGDefaultInternalRectangleNode { public: - void setAntialiasing(bool) { } + void setAntialiasing(bool) override { } }; } diff --git a/src/quick/scenegraph/qsgdefaultdistancefieldglyphcache.cpp b/src/quick/scenegraph/qsgdefaultdistancefieldglyphcache.cpp index f0a336e229..ba25172d2f 100644 --- a/src/quick/scenegraph/qsgdefaultdistancefieldglyphcache.cpp +++ b/src/quick/scenegraph/qsgdefaultdistancefieldglyphcache.cpp @@ -42,7 +42,6 @@ #include <QtGui/private/qdistancefield_p.h> #include <QtGui/private/qopenglcontext_p.h> #include <QtQml/private/qqmlglobal_p.h> -#include <QtQuick/private/qsgdistancefieldutil_p.h> #include <qopenglfunctions.h> #include <qopenglframebufferobject.h> #include <qmath.h> @@ -60,8 +59,8 @@ DEFINE_BOOL_CONFIG_OPTION(qsgPreferFullSizeGlyphCacheTextures, QSG_PREFER_FULLSI # define QSG_DEFAULT_DISTANCEFIELD_GLYPH_CACHE_PADDING 2 #endif -QSGDefaultDistanceFieldGlyphCache::QSGDefaultDistanceFieldGlyphCache(QSGDistanceFieldGlyphCacheManager *man, QOpenGLContext *c, const QRawFont &font) - : QSGDistanceFieldGlyphCache(man, c, font) +QSGDefaultDistanceFieldGlyphCache::QSGDefaultDistanceFieldGlyphCache(QOpenGLContext *c, const QRawFont &font) + : QSGDistanceFieldGlyphCache(c, font) , m_maxTextureSize(0) , m_maxTextureCount(3) , m_blitProgram(0) diff --git a/src/quick/scenegraph/qsgdefaultdistancefieldglyphcache_p.h b/src/quick/scenegraph/qsgdefaultdistancefieldglyphcache_p.h index 57dc4a5d07..fe365495c2 100644 --- a/src/quick/scenegraph/qsgdefaultdistancefieldglyphcache_p.h +++ b/src/quick/scenegraph/qsgdefaultdistancefieldglyphcache_p.h @@ -69,7 +69,7 @@ class QOpenGLFunctions_3_2_Core; class Q_QUICK_PRIVATE_EXPORT QSGDefaultDistanceFieldGlyphCache : public QSGDistanceFieldGlyphCache { public: - QSGDefaultDistanceFieldGlyphCache(QSGDistanceFieldGlyphCacheManager *man, QOpenGLContext *c, const QRawFont &font); + QSGDefaultDistanceFieldGlyphCache(QOpenGLContext *c, const QRawFont &font); virtual ~QSGDefaultDistanceFieldGlyphCache(); void requestGlyphs(const QSet<glyph_t> &glyphs) override; diff --git a/src/quick/scenegraph/qsgdefaultglyphnode_p.cpp b/src/quick/scenegraph/qsgdefaultglyphnode_p.cpp index b001899915..edb6e92a0d 100644 --- a/src/quick/scenegraph/qsgdefaultglyphnode_p.cpp +++ b/src/quick/scenegraph/qsgdefaultglyphnode_p.cpp @@ -91,11 +91,11 @@ class QSGTextMaskShader : public QSGMaterialShader public: QSGTextMaskShader(QFontEngine::GlyphFormat glyphFormat); - virtual void updateState(const RenderState &state, QSGMaterial *newEffect, QSGMaterial *oldEffect); - virtual char const *const *attributeNames() const; + void updateState(const RenderState &state, QSGMaterial *newEffect, QSGMaterial *oldEffect) override; + char const *const *attributeNames() const override; protected: - virtual void initialize(); + void initialize() override; int m_matrix_id; int m_color_id; @@ -181,7 +181,7 @@ public: setShaderSourceFile(QOpenGLShader::Fragment, QStringLiteral(":/qt-project.org/scenegraph/shaders/8bittextmask.frag")); } - virtual void updateState(const RenderState &state, QSGMaterial *newEffect, QSGMaterial *oldEffect); + void updateState(const RenderState &state, QSGMaterial *newEffect, QSGMaterial *oldEffect) override; }; void QSG8BitTextMaskShader::updateState(const RenderState &state, QSGMaterial *newEffect, QSGMaterial *oldEffect) @@ -206,10 +206,10 @@ public: setShaderSourceFile(QOpenGLShader::Fragment, QStringLiteral(":/qt-project.org/scenegraph/shaders/24bittextmask.frag")); } - virtual void updateState(const RenderState &state, QSGMaterial *newEffect, QSGMaterial *oldEffect); - virtual void initialize(); - void activate(); - void deactivate(); + void updateState(const RenderState &state, QSGMaterial *newEffect, QSGMaterial *oldEffect) override; + void initialize() override; + void activate() override; + void deactivate() override; bool useSRGB() const; uint m_useSRGB : 1; @@ -326,10 +326,10 @@ public: setShaderSourceFile(QOpenGLShader::Fragment, QStringLiteral(":/qt-project.org/scenegraph/shaders/styledtext.frag")); } - virtual void updateState(const RenderState &state, QSGMaterial *newEffect, QSGMaterial *oldEffect); + void updateState(const RenderState &state, QSGMaterial *newEffect, QSGMaterial *oldEffect) override; private: - virtual void initialize(); + void initialize() override; int m_shift_id; int m_styleColor_id; diff --git a/src/quick/scenegraph/qsgdefaultinternalimagenode.cpp b/src/quick/scenegraph/qsgdefaultinternalimagenode.cpp index 1d54628acd..a5a6da06a7 100644 --- a/src/quick/scenegraph/qsgdefaultinternalimagenode.cpp +++ b/src/quick/scenegraph/qsgdefaultinternalimagenode.cpp @@ -50,11 +50,11 @@ class SmoothTextureMaterialShader : public QSGTextureMaterialShader public: SmoothTextureMaterialShader(); - virtual void updateState(const RenderState &state, QSGMaterial *newEffect, QSGMaterial *oldEffect); - virtual char const *const *attributeNames() const; + void updateState(const RenderState &state, QSGMaterial *newEffect, QSGMaterial *oldEffect) override; + char const *const *attributeNames() const override; protected: - virtual void initialize(); + void initialize() override; int m_pixelSizeLoc; }; diff --git a/src/quick/scenegraph/qsgdefaultinternalrectanglenode.cpp b/src/quick/scenegraph/qsgdefaultinternalrectanglenode.cpp index 94414444ba..e52dcaad52 100644 --- a/src/quick/scenegraph/qsgdefaultinternalrectanglenode.cpp +++ b/src/quick/scenegraph/qsgdefaultinternalrectanglenode.cpp @@ -55,11 +55,11 @@ class SmoothColorMaterialShader : public QSGMaterialShader public: SmoothColorMaterialShader(); - virtual void updateState(const RenderState &state, QSGMaterial *newEffect, QSGMaterial *oldEffect); - virtual char const *const *attributeNames() const; + void updateState(const RenderState &state, QSGMaterial *newEffect, QSGMaterial *oldEffect) override; + char const *const *attributeNames() const override; private: - virtual void initialize(); + void initialize() override; int m_matrixLoc; int m_opacityLoc; diff --git a/src/quick/scenegraph/qsgdefaultlayer.cpp b/src/quick/scenegraph/qsgdefaultlayer.cpp index 78037a2fde..6fa9dd6359 100644 --- a/src/quick/scenegraph/qsgdefaultlayer.cpp +++ b/src/quick/scenegraph/qsgdefaultlayer.cpp @@ -100,6 +100,7 @@ QSGDefaultLayer::QSGDefaultLayer(QSGRenderContext *context) #ifdef QSG_DEBUG_FBO_OVERLAY , m_debugOverlay(0) #endif + , m_samples(0) , m_mipmap(false) , m_live(true) , m_recursive(false) @@ -314,11 +315,20 @@ void QSGDefaultLayer::grab() QOpenGLFunctions *funcs = QOpenGLContext::currentContext()->functions(); bool deleteFboLater = false; - if (!m_fbo || m_fbo->size() != m_size || m_fbo->format().internalTextureFormat() != m_format - || (!m_fbo->format().mipmap() && m_mipmap)) - { + + int effectiveSamples = m_samples; + // By default m_samples is 0. Fall back to the context's setting in this case. + if (effectiveSamples == 0) + effectiveSamples = m_context->openglContext()->format().samples(); + + const bool needsNewFbo = !m_fbo || m_fbo->size() != m_size || m_fbo->format().internalTextureFormat() != m_format; + const bool mipmapGotEnabled = m_fbo && !m_fbo->format().mipmap() && m_mipmap; + const bool msaaGotEnabled = effectiveSamples > 1 && (!m_secondaryFbo || m_secondaryFbo->format().samples() != effectiveSamples); + const bool msaaGotDisabled = effectiveSamples <= 1 && m_secondaryFbo; + + if (needsNewFbo || mipmapGotEnabled || msaaGotEnabled || msaaGotDisabled) { if (!m_multisamplingChecked) { - if (m_context->openglContext()->format().samples() <= 1) { + if (effectiveSamples <= 1) { m_multisampling = false; } else { QOpenGLExtensions *e = static_cast<QOpenGLExtensions *>(funcs); @@ -334,7 +344,7 @@ void QSGDefaultLayer::grab() QOpenGLFramebufferObjectFormat format; format.setInternalTextureFormat(m_format); - format.setSamples(m_context->openglContext()->format().samples()); + format.setSamples(effectiveSamples); m_secondaryFbo = new QOpenGLFramebufferObject(m_size, format); m_depthStencilBuffer = m_context->depthStencilBufferForFbo(m_secondaryFbo); } else { diff --git a/src/quick/scenegraph/qsgdefaultlayer_p.h b/src/quick/scenegraph/qsgdefaultlayer_p.h index ae39994096..7b09293095 100644 --- a/src/quick/scenegraph/qsgdefaultlayer_p.h +++ b/src/quick/scenegraph/qsgdefaultlayer_p.h @@ -113,6 +113,9 @@ public: QRectF normalizedTextureSubRect() const Q_DECL_OVERRIDE; + int samples() const { return m_samples; } + void setSamples(int samples) Q_DECL_OVERRIDE { m_samples = samples; } + public Q_SLOTS: void markDirtyTexture() Q_DECL_OVERRIDE; void invalidated() Q_DECL_OVERRIDE; @@ -138,6 +141,7 @@ private: #endif QSGDefaultRenderContext *m_context; + int m_samples; uint m_mipmap : 1; uint m_live : 1; diff --git a/src/quick/scenegraph/qsgdefaultrendercontext.cpp b/src/quick/scenegraph/qsgdefaultrendercontext.cpp index 2c5b4ff5c8..7542068a53 100644 --- a/src/quick/scenegraph/qsgdefaultrendercontext.cpp +++ b/src/quick/scenegraph/qsgdefaultrendercontext.cpp @@ -45,7 +45,6 @@ #include <QtQuick/private/qsgrenderer_p.h> #include <QtQuick/private/qsgatlastexture_p.h> #include <QtQuick/private/qsgdefaultdistancefieldglyphcache_p.h> -#include <QtQuick/private/qsgdistancefieldutil_p.h> QT_BEGIN_NAMESPACE @@ -159,8 +158,8 @@ void QSGDefaultRenderContext::invalidate() delete m_depthStencilManager; m_depthStencilManager = 0; - delete m_distanceFieldCacheManager; - m_distanceFieldCacheManager = 0; + qDeleteAll(m_glyphCaches); + m_glyphCaches.clear(); if (m_gl->property(QSG_RENDERCONTEXT_PROPERTY) == QVariant::fromValue(this)) m_gl->setProperty(QSG_RENDERCONTEXT_PROPERTY, QVariant()); @@ -294,13 +293,10 @@ QT_END_NAMESPACE QSGDistanceFieldGlyphCache *QSGDefaultRenderContext::distanceFieldGlyphCache(const QRawFont &font) { - if (!m_distanceFieldCacheManager) - m_distanceFieldCacheManager = new QSGDistanceFieldGlyphCacheManager; - - QSGDistanceFieldGlyphCache *cache = m_distanceFieldCacheManager->cache(font); + QSGDistanceFieldGlyphCache *cache = m_glyphCaches.value(font, 0); if (!cache) { - cache = new QSGDefaultDistanceFieldGlyphCache(m_distanceFieldCacheManager, openglContext(), font); - m_distanceFieldCacheManager->insertCache(font, cache); + cache = new QSGDefaultDistanceFieldGlyphCache(openglContext(), font); + m_glyphCaches.insert(font, cache); } return cache; diff --git a/src/quick/scenegraph/qsgdistancefieldglyphnode.cpp b/src/quick/scenegraph/qsgdistancefieldglyphnode.cpp index 456a197ba1..32eda2d142 100644 --- a/src/quick/scenegraph/qsgdistancefieldglyphnode.cpp +++ b/src/quick/scenegraph/qsgdistancefieldglyphnode.cpp @@ -39,7 +39,6 @@ #include "qsgdistancefieldglyphnode_p.h" #include "qsgdistancefieldglyphnode_p_p.h" -#include <QtQuick/private/qsgdistancefieldutil_p.h> #include <QtQuick/private/qsgcontext_p.h> QT_BEGIN_NAMESPACE @@ -76,9 +75,6 @@ QSGDistanceFieldGlyphNode::~QSGDistanceFieldGlyphNode() m_glyph_cache->unregisterGlyphNode(this); m_glyph_cache->unregisterOwnerElement(ownerElement()); } - - while (m_nodesToDelete.count()) - delete m_nodesToDelete.takeLast(); } void QSGDistanceFieldGlyphNode::setColor(const QColor &color) @@ -158,9 +154,6 @@ void QSGDistanceFieldGlyphNode::preprocess() { Q_ASSERT(m_glyph_cache); - while (m_nodesToDelete.count()) - delete m_nodesToDelete.takeLast(); - m_glyph_cache->processPendingGlyphs(); m_glyph_cache->update(); @@ -188,13 +181,12 @@ void QSGDistanceFieldGlyphNode::updateGeometry() // Remove previously created sub glyph nodes // We assume all the children are sub glyph nodes QSGNode *subnode = firstChild(); + QSGNode *nextNode = 0; while (subnode) { - // We can't delete the node now as it might be in the preprocess list - // It will be deleted in the next preprocess - m_nodesToDelete.append(subnode); - subnode = subnode->nextSibling(); + nextNode = subnode->nextSibling(); + delete subnode; + subnode = nextNode; } - removeAllChildNodes(); QSGGeometry *g = geometry(); diff --git a/src/quick/scenegraph/qsgdistancefieldglyphnode_p.cpp b/src/quick/scenegraph/qsgdistancefieldglyphnode_p.cpp index ca91e5d85f..a67c659c99 100644 --- a/src/quick/scenegraph/qsgdistancefieldglyphnode_p.cpp +++ b/src/quick/scenegraph/qsgdistancefieldglyphnode_p.cpp @@ -38,7 +38,6 @@ ****************************************************************************/ #include "qsgdistancefieldglyphnode_p_p.h" -#include <QtQuick/private/qsgdistancefieldutil_p.h> #include <QtQuick/private/qsgtexture_p.h> #include <QtGui/qopenglfunctions.h> #include <QtGui/qsurface.h> @@ -52,13 +51,13 @@ class QSGDistanceFieldTextMaterialShader : public QSGMaterialShader public: QSGDistanceFieldTextMaterialShader(); - virtual void updateState(const RenderState &state, QSGMaterial *newEffect, QSGMaterial *oldEffect); - virtual char const *const *attributeNames() const; + void updateState(const RenderState &state, QSGMaterial *newEffect, QSGMaterial *oldEffect) override; + char const *const *attributeNames() const override; protected: - virtual void initialize(); + void initialize() override; - void updateAlphaRange(ThresholdFunc thresholdFunc, AntialiasingSpreadFunc spreadFunc); + void updateAlphaRange(); void updateColor(const QVector4D &c); void updateTextureScale(const QVector2D &ts); @@ -98,7 +97,31 @@ QSGDistanceFieldTextMaterialShader::QSGDistanceFieldTextMaterialShader() setShaderSourceFile(QOpenGLShader::Fragment, QStringLiteral(":/qt-project.org/scenegraph/shaders/distancefieldtext.frag")); } -void QSGDistanceFieldTextMaterialShader::updateAlphaRange(ThresholdFunc thresholdFunc, AntialiasingSpreadFunc spreadFunc) +static float qt_sg_envFloat(const char *name, float defaultValue) +{ + if (Q_LIKELY(!qEnvironmentVariableIsSet(name))) + return defaultValue; + bool ok = false; + const float value = qgetenv(name).toFloat(&ok); + return ok ? value : defaultValue; +} + +static float thresholdFunc(float glyphScale) +{ + static const float base = qt_sg_envFloat("QT_DF_BASE", 0.5f); + static const float baseDev = qt_sg_envFloat("QT_DF_BASEDEVIATION", 0.065f); + static const float devScaleMin = qt_sg_envFloat("QT_DF_SCALEFORMAXDEV", 0.15f); + static const float devScaleMax = qt_sg_envFloat("QT_DF_SCALEFORNODEV", 0.3f); + return base - ((qBound(devScaleMin, glyphScale, devScaleMax) - devScaleMin) / (devScaleMax - devScaleMin) * -baseDev + baseDev); +} + +static float spreadFunc(float glyphScale) +{ + static const float range = qt_sg_envFloat("QT_DF_RANGE", 0.06f); + return range / glyphScale; +} + +void QSGDistanceFieldTextMaterialShader::updateAlphaRange() { float combinedScale = m_fontScale * m_matrixScale; float base = thresholdFunc(combinedScale); @@ -169,8 +192,7 @@ void QSGDistanceFieldTextMaterialShader::updateState(const RenderState &state, Q updateRange = true; } if (updateRange) { - updateAlphaRange(material->glyphCache()->manager()->thresholdFunc(), - material->glyphCache()->manager()->antialiasingSpreadFunc()); + updateAlphaRange(); } Q_ASSERT(material->glyphCache()); @@ -261,10 +283,10 @@ class DistanceFieldStyledTextMaterialShader : public QSGDistanceFieldTextMateria public: DistanceFieldStyledTextMaterialShader(); - virtual void updateState(const RenderState &state, QSGMaterial *newEffect, QSGMaterial *oldEffect); + void updateState(const RenderState &state, QSGMaterial *newEffect, QSGMaterial *oldEffect) override; protected: - virtual void initialize(); + void initialize() override; int m_styleColor_id; }; @@ -329,12 +351,12 @@ class DistanceFieldOutlineTextMaterialShader : public DistanceFieldStyledTextMat public: DistanceFieldOutlineTextMaterialShader(); - virtual void updateState(const RenderState &state, QSGMaterial *newEffect, QSGMaterial *oldEffect); + void updateState(const RenderState &state, QSGMaterial *newEffect, QSGMaterial *oldEffect) override; protected: - virtual void initialize(); + void initialize() override; - void updateOutlineAlphaRange(ThresholdFunc thresholdFunc, AntialiasingSpreadFunc spreadFunc, int dfRadius); + void updateOutlineAlphaRange(int dfRadius); int m_outlineAlphaMax0_id; int m_outlineAlphaMax1_id; @@ -355,9 +377,7 @@ void DistanceFieldOutlineTextMaterialShader::initialize() m_outlineAlphaMax1_id = program()->uniformLocation("outlineAlphaMax1"); } -void DistanceFieldOutlineTextMaterialShader::updateOutlineAlphaRange(ThresholdFunc thresholdFunc, - AntialiasingSpreadFunc spreadFunc, - int dfRadius) +void DistanceFieldOutlineTextMaterialShader::updateOutlineAlphaRange(int dfRadius) { float combinedScale = m_fontScale * m_matrixScale; float base = thresholdFunc(combinedScale); @@ -381,9 +401,7 @@ void DistanceFieldOutlineTextMaterialShader::updateState(const RenderState &stat if (oldMaterial == 0 || material->fontScale() != oldMaterial->fontScale() || state.isMatrixDirty()) - updateOutlineAlphaRange(material->glyphCache()->manager()->thresholdFunc(), - material->glyphCache()->manager()->antialiasingSpreadFunc(), - material->glyphCache()->distanceFieldRadius()); + updateOutlineAlphaRange(material->glyphCache()->distanceFieldRadius()); } @@ -413,10 +431,10 @@ class DistanceFieldShiftedStyleTextMaterialShader : public DistanceFieldStyledTe public: DistanceFieldShiftedStyleTextMaterialShader(); - virtual void updateState(const RenderState &state, QSGMaterial *newEffect, QSGMaterial *oldEffect); + void updateState(const RenderState &state, QSGMaterial *newEffect, QSGMaterial *oldEffect) override; protected: - virtual void initialize(); + void initialize() override; void updateShift(qreal fontScale, const QPointF& shift); @@ -492,10 +510,10 @@ class QSGHiQSubPixelDistanceFieldTextMaterialShader : public QSGDistanceFieldTex public: QSGHiQSubPixelDistanceFieldTextMaterialShader(); - virtual void initialize(); - virtual void activate(); - virtual void deactivate(); - virtual void updateState(const RenderState &state, QSGMaterial *newEffect, QSGMaterial *oldEffect); + void initialize() override; + void activate() override; + void deactivate() override; + void updateState(const RenderState &state, QSGMaterial *newEffect, QSGMaterial *oldEffect) override; private: int m_fontScale_id; diff --git a/src/quick/scenegraph/qsgdistancefieldglyphnode_p.h b/src/quick/scenegraph/qsgdistancefieldglyphnode_p.h index c0c6bda718..7008f20925 100644 --- a/src/quick/scenegraph/qsgdistancefieldglyphnode_p.h +++ b/src/quick/scenegraph/qsgdistancefieldglyphnode_p.h @@ -59,7 +59,6 @@ QT_BEGIN_NAMESPACE class QSGRenderContext; -class QSGDistanceFieldGlyphCacheManager; class QSGDistanceFieldTextMaterial; class QSGDistanceFieldGlyphNode: public QSGGlyphNode, public QSGDistanceFieldGlyphConsumer { @@ -107,7 +106,6 @@ private: AntialiasingMode m_antialiasingMode; QRectF m_boundingRect; const QSGDistanceFieldGlyphCache::Texture *m_texture; - QLinkedList<QSGNode *> m_nodesToDelete; struct GlyphInfo { QVector<quint32> indexes; diff --git a/src/quick/scenegraph/qsgrenderloop.cpp b/src/quick/scenegraph/qsgrenderloop.cpp index 48288bfc62..bb581c5e36 100644 --- a/src/quick/scenegraph/qsgrenderloop.cpp +++ b/src/quick/scenegraph/qsgrenderloop.cpp @@ -139,25 +139,25 @@ public: QSGGuiThreadRenderLoop(); ~QSGGuiThreadRenderLoop(); - void show(QQuickWindow *window); - void hide(QQuickWindow *window); + void show(QQuickWindow *window) override; + void hide(QQuickWindow *window) override; - void windowDestroyed(QQuickWindow *window); + void windowDestroyed(QQuickWindow *window) override; void renderWindow(QQuickWindow *window); - void exposureChanged(QQuickWindow *window); - QImage grab(QQuickWindow *window); + void exposureChanged(QQuickWindow *window) override; + QImage grab(QQuickWindow *window) override; - void maybeUpdate(QQuickWindow *window); - void update(QQuickWindow *window) { maybeUpdate(window); } // identical for this implementation. - void handleUpdateRequest(QQuickWindow *); + void maybeUpdate(QQuickWindow *window) override; + void update(QQuickWindow *window) override { maybeUpdate(window); } // identical for this implementation. + void handleUpdateRequest(QQuickWindow *) override; - void releaseResources(QQuickWindow *) { } + void releaseResources(QQuickWindow *) override { } - QAnimationDriver *animationDriver() const { return 0; } + QAnimationDriver *animationDriver() const override { return 0; } - QSGContext *sceneGraphContext() const; - QSGRenderContext *createRenderContext(QSGContext *) const { return rc; } + QSGContext *sceneGraphContext() const override; + QSGRenderContext *createRenderContext(QSGContext *) const override { return rc; } struct WindowData { bool updatePending : 1; diff --git a/src/quick/scenegraph/qsgthreadedrenderloop.cpp b/src/quick/scenegraph/qsgthreadedrenderloop.cpp index 5fa74027c1..17a2c62a4e 100644 --- a/src/quick/scenegraph/qsgthreadedrenderloop.cpp +++ b/src/quick/scenegraph/qsgthreadedrenderloop.cpp @@ -295,8 +295,8 @@ public: void invalidateOpenGL(QQuickWindow *window, bool inDestructor, QOffscreenSurface *backupSurface); void initializeOpenGL(); - bool event(QEvent *); - void run(); + bool event(QEvent *) override; + void run() override; void syncAndRender(); void sync(bool inExpose); diff --git a/src/quick/scenegraph/scenegraph.pri b/src/quick/scenegraph/scenegraph.pri index 38c3b8dd85..c6db3df158 100644 --- a/src/quick/scenegraph/scenegraph.pri +++ b/src/quick/scenegraph/scenegraph.pri @@ -45,7 +45,6 @@ HEADERS += \ $$PWD/util/qsgtexture.h \ $$PWD/util/qsgtexture_p.h \ $$PWD/util/qsgtextureprovider.h \ - $$PWD/util/qsgdistancefieldutil_p.h \ $$PWD/util/qsgflatcolormaterial.h \ $$PWD/util/qsgsimplematerial.h \ $$PWD/util/qsgtexturematerial.h \ @@ -62,7 +61,6 @@ SOURCES += \ $$PWD/util/qsgsimpletexturenode.cpp \ $$PWD/util/qsgtexture.cpp \ $$PWD/util/qsgtextureprovider.cpp \ - $$PWD/util/qsgdistancefieldutil.cpp \ $$PWD/util/qsgflatcolormaterial.cpp \ $$PWD/util/qsgsimplematerial.cpp \ $$PWD/util/qsgtexturematerial.cpp \ diff --git a/src/quick/scenegraph/util/qsgdistancefieldutil.cpp b/src/quick/scenegraph/util/qsgdistancefieldutil.cpp deleted file mode 100644 index 9ca9cdb107..0000000000 --- a/src/quick/scenegraph/util/qsgdistancefieldutil.cpp +++ /dev/null @@ -1,95 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the QtQuick module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 3 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL3 included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 3 requirements -** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 2.0 or (at your option) the GNU General -** Public license version 3 or any later version approved by the KDE Free -** Qt Foundation. The licenses are as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-2.0.html and -** https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#include "qsgdistancefieldutil_p.h" - -#include <private/qsgadaptationlayer_p.h> -#if QT_CONFIG(opengl) -# include <QtGui/private/qopenglengineshadersource_p.h> -#endif -#include <QtQuick/private/qsgcontext_p.h> - -QT_BEGIN_NAMESPACE - -static float qt_sg_envFloat(const char *name, float defaultValue) -{ - if (Q_LIKELY(!qEnvironmentVariableIsSet(name))) - return defaultValue; - bool ok = false; - const float value = qgetenv(name).toFloat(&ok); - return ok ? value : defaultValue; -} - -static float defaultThresholdFunc(float glyphScale) -{ - static const float base = qt_sg_envFloat("QT_DF_BASE", 0.5f); - static const float baseDev = qt_sg_envFloat("QT_DF_BASEDEVIATION", 0.065f); - static const float devScaleMin = qt_sg_envFloat("QT_DF_SCALEFORMAXDEV", 0.15f); - static const float devScaleMax = qt_sg_envFloat("QT_DF_SCALEFORNODEV", 0.3f); - return base - ((qBound(devScaleMin, glyphScale, devScaleMax) - devScaleMin) / (devScaleMax - devScaleMin) * -baseDev + baseDev); -} - -static float defaultAntialiasingSpreadFunc(float glyphScale) -{ - static const float range = qt_sg_envFloat("QT_DF_RANGE", 0.06f); - return range / glyphScale; -} - -QSGDistanceFieldGlyphCacheManager::QSGDistanceFieldGlyphCacheManager() - : m_threshold_func(defaultThresholdFunc) - , m_antialiasingSpread_func(defaultAntialiasingSpreadFunc) -{ -} - -QSGDistanceFieldGlyphCacheManager::~QSGDistanceFieldGlyphCacheManager() -{ - qDeleteAll(m_caches); -} - -QSGDistanceFieldGlyphCache *QSGDistanceFieldGlyphCacheManager::cache(const QRawFont &font) -{ - return m_caches.value(font, 0); -} - -void QSGDistanceFieldGlyphCacheManager::insertCache(const QRawFont &font, QSGDistanceFieldGlyphCache *cache) -{ - m_caches.insert(font, cache); -} - -QT_END_NAMESPACE diff --git a/src/quick/scenegraph/util/qsgdistancefieldutil_p.h b/src/quick/scenegraph/util/qsgdistancefieldutil_p.h deleted file mode 100644 index ad366cb4d4..0000000000 --- a/src/quick/scenegraph/util/qsgdistancefieldutil_p.h +++ /dev/null @@ -1,91 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the QtQuick 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 QSGDISTANCEFIELDUTIL_H -#define QSGDISTANCEFIELDUTIL_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 <qrawfont.h> -#include <private/qfontengine_p.h> -#include <private/qsgadaptationlayer_p.h> - -QT_BEGIN_NAMESPACE - -typedef float (*ThresholdFunc)(float glyphScale); -typedef float (*AntialiasingSpreadFunc)(float glyphScale); - -class QOpenGLShaderProgram; -class QSGDistanceFieldGlyphCache; -class QSGContext; - -class Q_QUICK_PRIVATE_EXPORT QSGDistanceFieldGlyphCacheManager -{ -public: - QSGDistanceFieldGlyphCacheManager(); - ~QSGDistanceFieldGlyphCacheManager(); - - QSGDistanceFieldGlyphCache *cache(const QRawFont &font); - void insertCache(const QRawFont &font, QSGDistanceFieldGlyphCache *cache); - - ThresholdFunc thresholdFunc() const { return m_threshold_func; } - void setThresholdFunc(ThresholdFunc func) { m_threshold_func = func; } - - AntialiasingSpreadFunc antialiasingSpreadFunc() const { return m_antialiasingSpread_func; } - void setAntialiasingSpreadFunc(AntialiasingSpreadFunc func) { m_antialiasingSpread_func = func; } - -private: - QHash<QRawFont, QSGDistanceFieldGlyphCache *> m_caches; - - ThresholdFunc m_threshold_func; - AntialiasingSpreadFunc m_antialiasingSpread_func; -}; - -QT_END_NAMESPACE - -#endif // QSGDISTANCEFIELDUTIL_H diff --git a/src/quick/scenegraph/util/qsgflatcolormaterial.cpp b/src/quick/scenegraph/util/qsgflatcolormaterial.cpp index 8ab7669891..a0c71b5340 100644 --- a/src/quick/scenegraph/util/qsgflatcolormaterial.cpp +++ b/src/quick/scenegraph/util/qsgflatcolormaterial.cpp @@ -50,13 +50,13 @@ class FlatColorMaterialShader : public QSGMaterialShader public: FlatColorMaterialShader(); - virtual void updateState(const RenderState &state, QSGMaterial *newEffect, QSGMaterial *oldEffect); - virtual char const *const *attributeNames() const; + void updateState(const RenderState &state, QSGMaterial *newEffect, QSGMaterial *oldEffect) override; + char const *const *attributeNames() const override; static QSGMaterialType type; private: - virtual void initialize(); + void initialize() override; #if QT_CONFIG(opengl) int m_matrix_id; int m_color_id; diff --git a/src/quick/scenegraph/util/qsgvertexcolormaterial.cpp b/src/quick/scenegraph/util/qsgvertexcolormaterial.cpp index 8c305d7fd4..42c589b14a 100644 --- a/src/quick/scenegraph/util/qsgvertexcolormaterial.cpp +++ b/src/quick/scenegraph/util/qsgvertexcolormaterial.cpp @@ -48,13 +48,13 @@ class QSGVertexColorMaterialShader : public QSGMaterialShader public: QSGVertexColorMaterialShader(); - virtual void updateState(const RenderState &state, QSGMaterial *newEffect, QSGMaterial *oldEffect); - virtual char const *const *attributeNames() const; + void updateState(const RenderState &state, QSGMaterial *newEffect, QSGMaterial *oldEffect) override; + char const *const *attributeNames() const override; static QSGMaterialType type; private: - virtual void initialize(); + void initialize() override; #if QT_CONFIG(opengl) int m_matrix_id; int m_opacity_id; diff --git a/src/quick/util/qquickglobal.cpp b/src/quick/util/qquickglobal.cpp index 5a723e4432..20bb23338d 100644 --- a/src/quick/util/qquickglobal.cpp +++ b/src/quick/util/qquickglobal.cpp @@ -61,7 +61,7 @@ QT_BEGIN_NAMESPACE class QQuickColorProvider : public QQmlColorProvider { public: - QVariant colorFromString(const QString &s, bool *ok) + QVariant colorFromString(const QString &s, bool *ok) override { QColor c(s); if (c.isValid()) { @@ -73,7 +73,7 @@ public: return QVariant(); } - unsigned rgbaFromString(const QString &s, bool *ok) + unsigned rgbaFromString(const QString &s, bool *ok) override { QColor c(s); if (c.isValid()) { @@ -95,36 +95,36 @@ public: return QString(); } - QVariant fromRgbF(double r, double g, double b, double a) + QVariant fromRgbF(double r, double g, double b, double a) override { return QVariant(QColor::fromRgbF(r, g, b, a)); } - QVariant fromHslF(double h, double s, double l, double a) + QVariant fromHslF(double h, double s, double l, double a) override { return QVariant(QColor::fromHslF(h, s, l, a)); } - QVariant fromHsvF(double h, double s, double v, double a) + QVariant fromHsvF(double h, double s, double v, double a) override { return QVariant(QColor::fromHsvF(h, s, v, a)); } - QVariant lighter(const QVariant &var, qreal factor) + QVariant lighter(const QVariant &var, qreal factor) override { QColor color = var.value<QColor>(); color = color.lighter(int(qRound(factor*100.))); return QVariant::fromValue(color); } - QVariant darker(const QVariant &var, qreal factor) + QVariant darker(const QVariant &var, qreal factor) override { QColor color = var.value<QColor>(); color = color.darker(int(qRound(factor*100.))); return QVariant::fromValue(color); } - QVariant tint(const QVariant &baseVar, const QVariant &tintVar) + QVariant tint(const QVariant &baseVar, const QVariant &tintVar) override { QColor tintColor = tintVar.value<QColor>(); @@ -778,13 +778,13 @@ public: class QQuickGuiProvider : public QQmlGuiProvider { public: - QQuickApplication *application(QObject *parent) + QQuickApplication *application(QObject *parent) override { return new QQuickApplication(parent); } #if QT_CONFIG(im) - QInputMethod *inputMethod() + QInputMethod *inputMethod() override { QInputMethod *im = qGuiApp->inputMethod(); QQmlEngine::setObjectOwnership(im, QQmlEngine::CppOwnership); @@ -792,20 +792,20 @@ public: } #endif - QStyleHints *styleHints() + QStyleHints *styleHints() override { QStyleHints *sh = qGuiApp->styleHints(); QQmlEngine::setObjectOwnership(sh, QQmlEngine::CppOwnership); return sh; } - QStringList fontFamilies() + QStringList fontFamilies() override { QFontDatabase database; return database.families(); } - bool openUrlExternally(QUrl &url) + bool openUrlExternally(QUrl &url) override { #ifndef QT_NO_DESKTOPSERVICES return QDesktopServices::openUrl(url); diff --git a/src/quick/util/qquickimageprovider.cpp b/src/quick/util/qquickimageprovider.cpp index a026abe762..0ceed7f681 100644 --- a/src/quick/util/qquickimageprovider.cpp +++ b/src/quick/util/qquickimageprovider.cpp @@ -183,7 +183,12 @@ QString QQuickImageResponse::errorString() const It may be reimplemented to cancel a request in the provider side, however, it is not mandatory. - A cancelled QQuickImageResponse still needs to emit finished(). + A cancelled QQuickImageResponse still needs to emit finished() so that the + engine may clean up the QQuickImageResponse. + + \note finished() should not be emitted until the response is complete, + regardless of whether or not cancel() was called. If it is called prematurely, + the engine may destroy the response while it is still active, leading to a crash. */ void QQuickImageResponse::cancel() { @@ -192,7 +197,12 @@ void QQuickImageResponse::cancel() /*! \fn void QQuickImageResponse::finished() - Signals that the job execution has finished (be it successfully, because an error happened or because it was cancelled). + Signals that the job execution has finished (be it successfully, because an + error happened or because it was cancelled). + + \note Emission of this signal must be the final action the response performs: + once the signal is received, the response will subsequently be destroyed by + the engine. */ /*! diff --git a/src/quick/util/qquickpixmapcache.cpp b/src/quick/util/qquickpixmapcache.cpp index be27cba989..395b89c784 100644 --- a/src/quick/util/qquickpixmapcache.cpp +++ b/src/quick/util/qquickpixmapcache.cpp @@ -161,7 +161,7 @@ Q_SIGNALS: void downloadProgress(qint64, qint64); protected: - bool event(QEvent *event); + bool event(QEvent *event) override; private: Q_DISABLE_COPY(QQuickPixmapReply) @@ -199,7 +199,7 @@ public: static QQuickPixmapReader *existingInstance(QQmlEngine *engine); protected: - void run(); + void run() override; private: friend class QQuickPixmapReaderThreadObject; diff --git a/tests/auto/qml/qjsengine/tst_qjsengine.cpp b/tests/auto/qml/qjsengine/tst_qjsengine.cpp index 82bc3d0c59..39f6d80fa0 100644 --- a/tests/auto/qml/qjsengine/tst_qjsengine.cpp +++ b/tests/auto/qml/qjsengine/tst_qjsengine.cpp @@ -566,10 +566,6 @@ void tst_QJSEngine::newDate() QCOMPARE(date.isDate(), true); QCOMPARE(date.isObject(), true); QVERIFY(!date.isCallable()); - // prototype should be Date.prototype - QVERIFY(!date.prototype().isUndefined()); - QCOMPARE(date.prototype().isDate(), true); - QCOMPARE(date.prototype().strictlyEquals(eng.evaluate("Date.prototype")), true); } { @@ -578,10 +574,6 @@ void tst_QJSEngine::newDate() QVERIFY(!date.isUndefined()); QCOMPARE(date.isDate(), true); QCOMPARE(date.isObject(), true); - // prototype should be Date.prototype - QVERIFY(!date.prototype().isUndefined()); - QCOMPARE(date.prototype().isDate(), true); - QCOMPARE(date.prototype().strictlyEquals(eng.evaluate("Date.prototype")), true); QCOMPARE(date.toDateTime(), dt); } @@ -1099,7 +1091,7 @@ void tst_QJSEngine::builtinFunctionNames_data() QTest::newRow("Date.prototype.setFullYear") << QString("Date.prototype.setFullYear") << QString("setFullYear"); QTest::newRow("Date.prototype.setUTCFullYear") << QString("Date.prototype.setUTCFullYear") << QString("setUTCFullYear"); QTest::newRow("Date.prototype.toUTCString") << QString("Date.prototype.toUTCString") << QString("toUTCString"); - QTest::newRow("Date.prototype.toGMTString") << QString("Date.prototype.toGMTString") << QString("toGMTString"); + QTest::newRow("Date.prototype.toGMTString") << QString("Date.prototype.toGMTString") << QString("toUTCString"); // yes, this is per spec QTest::newRow("Error") << QString("Error") << QString("Error"); // QTest::newRow("Error.prototype.backtrace") << QString("Error.prototype.backtrace") << QString("backtrace"); @@ -1177,6 +1169,7 @@ void tst_QJSEngine::builtinFunctionNames_data() QTest::newRow("String.prototype.lastIndexOf") << QString("String.prototype.lastIndexOf") << QString("lastIndexOf"); QTest::newRow("String.prototype.localeCompare") << QString("String.prototype.localeCompare") << QString("localeCompare"); QTest::newRow("String.prototype.match") << QString("String.prototype.match") << QString("match"); + QTest::newRow("String.prototype.repeat") << QString("String.prototype.repeat") << QString("repeat"); QTest::newRow("String.prototype.replace") << QString("String.prototype.replace") << QString("replace"); QTest::newRow("String.prototype.search") << QString("String.prototype.search") << QString("search"); QTest::newRow("String.prototype.slice") << QString("String.prototype.slice") << QString("slice"); diff --git a/tests/auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp b/tests/auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp index b5df8307c0..6c9cb331a2 100644 --- a/tests/auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp +++ b/tests/auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp @@ -1,5 +1,6 @@ /**************************************************************************** ** +** Copyright (C) 2017 Crimson AS <info@crimson.no> ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** @@ -335,6 +336,9 @@ private slots: void stringify_qtbug_50592(); void instanceof_data(); void instanceof(); + void constkw_data(); + void constkw(); + void redefineGlobalProp(); void freeze_empty_object(); private: @@ -8166,6 +8170,8 @@ void tst_qqmlecmascript::stringify_qtbug_50592() QCOMPARE(obj->property("source").toString(), QString::fromLatin1("http://example.org/some_nonexistant_image.png")); } +// Tests for the JS-only instanceof. Tests for the QML extensions for +// instanceof belong in tst_qqmllanguage! void tst_qqmlecmascript::instanceof_data() { QTest::addColumn<QString>("setupCode"); @@ -8228,6 +8234,108 @@ void tst_qqmlecmascript::instanceof() } } +void tst_qqmlecmascript::constkw_data() +{ + QTest::addColumn<QString>("sourceCode"); + QTest::addColumn<bool>("exceptionExpected"); + QTest::addColumn<QVariant>("expectedValue"); + + QTest::newRow("simpleconst") + << "const v = 5\n" + "v\n" + << false + << QVariant(5); + QTest::newRow("twoconst") + << "const v = 5, i = 10\n" + "v + i\n" + << false + << QVariant(15); + QTest::newRow("constandvar") + << "const v = 5\n" + "var i = 20\n" + "v + i\n" + << false + << QVariant(25); + QTest::newRow("const-multiple-scopes-same-var") + << "const v = 3\n" + "function f() { const v = 1; return v; }\n" + "v + f()\n" + << false + << QVariant(4); + + // error cases + QTest::newRow("const-no-initializer") + << "const v\n" + << true + << QVariant("SyntaxError: Missing initializer in const declaration"); + QTest::newRow("const-no-initializer-comma") + << "const v = 1, i\n" + << true + << QVariant("SyntaxError: Missing initializer in const declaration"); + QTest::newRow("const-no-duplicate") + << "const v = 1, v = 2\n" + << true + << QVariant("SyntaxError: Identifier v has already been declared"); + QTest::newRow("const-no-duplicate-2") + << "const v = 1\n" + "const v = 2\n" + << true + << QVariant("SyntaxError: Identifier v has already been declared"); + QTest::newRow("const-no-duplicate-var") + << "const v = 1\n" + "var v = 1\n" + << true + << QVariant("SyntaxError: Identifier v has already been declared"); + QTest::newRow("var-no-duplicate-const") + << "var v = 1\n" + "const v = 1\n" + << true + << QVariant("SyntaxError: Identifier v has already been declared"); + QTest::newRow("const-no-duplicate-let") + << "const v = 1\n" + "let v = 1\n" + << true + << QVariant("SyntaxError: Identifier v has already been declared"); + QTest::newRow("let-no-duplicate-const") + << "let v = 1\n" + "const v = 1\n" + << true + << QVariant("SyntaxError: Identifier v has already been declared"); +} + +void tst_qqmlecmascript::constkw() +{ + QFETCH(QString, sourceCode); + QFETCH(bool, exceptionExpected); + QFETCH(QVariant, expectedValue); + + QJSEngine engine; + QJSValue ret = engine.evaluate(sourceCode); + + if (!exceptionExpected) { + QVERIFY2(!ret.isError(), qPrintable(ret.toString())); + QCOMPARE(ret.toVariant(), expectedValue); + } else { + QVERIFY2(ret.isError(), qPrintable(ret.toString())); + QCOMPARE(ret.toString(), expectedValue.toString()); + } +} + +// Redefine a property found on the global object. It shouldn't throw. +void tst_qqmlecmascript::redefineGlobalProp() +{ + { + QJSEngine engine; + QJSValue ret = engine.evaluate("\"use strict\"\n var toString = 1;"); + QVERIFY2(!ret.isError(), qPrintable(ret.toString())); + } + { + QJSEngine engine; + QJSValue ret = engine.evaluate("var toString = 1;"); + QVERIFY2(!ret.isError(), qPrintable(ret.toString())); + } +} + void tst_qqmlecmascript::freeze_empty_object() { // this shouldn't crash diff --git a/tests/auto/qml/qqmllanguage/data/instanceOf/CustomMouseArea.qml b/tests/auto/qml/qqmllanguage/data/instanceOf/CustomMouseArea.qml new file mode 100644 index 0000000000..f6ec5848c1 --- /dev/null +++ b/tests/auto/qml/qqmllanguage/data/instanceOf/CustomMouseArea.qml @@ -0,0 +1,6 @@ +import QtQuick 2.6 + +MouseArea { + +} + diff --git a/tests/auto/qml/qqmllanguage/data/instanceOf/CustomRectangle.qml b/tests/auto/qml/qqmllanguage/data/instanceOf/CustomRectangle.qml new file mode 100644 index 0000000000..b3fa43a671 --- /dev/null +++ b/tests/auto/qml/qqmllanguage/data/instanceOf/CustomRectangle.qml @@ -0,0 +1,4 @@ +import QtQuick 2.6 + +Rectangle { +} diff --git a/tests/auto/qml/qqmllanguage/data/instanceOf/CustomRectangleWithProp.qml b/tests/auto/qml/qqmllanguage/data/instanceOf/CustomRectangleWithProp.qml new file mode 100644 index 0000000000..cf566b9315 --- /dev/null +++ b/tests/auto/qml/qqmllanguage/data/instanceOf/CustomRectangleWithProp.qml @@ -0,0 +1,6 @@ +import QtQuick 2.6 + +Rectangle { + property int somethingCustom: 0 +} + diff --git a/tests/auto/qml/qqmllanguage/data/instanceOf/qmldir b/tests/auto/qml/qqmllanguage/data/instanceOf/qmldir new file mode 100644 index 0000000000..144c93d8e3 --- /dev/null +++ b/tests/auto/qml/qqmllanguage/data/instanceOf/qmldir @@ -0,0 +1,2 @@ +CustomRectangle 1.0 CustomRectangle.qml +CustomMouseArea 1.0 CustomMouseArea.qml diff --git a/tests/auto/qml/qqmllanguage/data/instanceof_qtqml.qml b/tests/auto/qml/qqmllanguage/data/instanceof_qtqml.qml new file mode 100644 index 0000000000..d74b172cf8 --- /dev/null +++ b/tests/auto/qml/qqmllanguage/data/instanceof_qtqml.qml @@ -0,0 +1,13 @@ +import QtQml 2.0 + +QtObject { + id: qtobjectInstance + + property Timer aTimer: Timer { + id: timerInstance + } + + property Connections aConnections: Connections { + id: connectionsInstance + } +} diff --git a/tests/auto/qml/qqmllanguage/data/instanceof_qtqml_qualified.qml b/tests/auto/qml/qqmllanguage/data/instanceof_qtqml_qualified.qml new file mode 100644 index 0000000000..a8e303363e --- /dev/null +++ b/tests/auto/qml/qqmllanguage/data/instanceof_qtqml_qualified.qml @@ -0,0 +1,13 @@ +import QtQml 2.0 as QmlImport + +QmlImport.QtObject { + id: qtobjectInstance + + property QmlImport.Timer aTimer: QmlImport.Timer { + id: timerInstance + } + + property QmlImport.Connections aConnections: QmlImport.Connections { + id: connectionsInstance + } +} diff --git a/tests/auto/qml/qqmllanguage/data/instanceof_qtquick.qml b/tests/auto/qml/qqmllanguage/data/instanceof_qtquick.qml new file mode 100644 index 0000000000..9c1808d515 --- /dev/null +++ b/tests/auto/qml/qqmllanguage/data/instanceof_qtquick.qml @@ -0,0 +1,14 @@ +import QtQuick 2.0 + +Item { + id: itemInstance + + Rectangle { + id: rectangleInstance + } + + MouseArea { + id: mouseAreaInstance + } +} + diff --git a/tests/auto/qml/qqmllanguage/data/instanceof_qtquick_composite.qml b/tests/auto/qml/qqmllanguage/data/instanceof_qtquick_composite.qml new file mode 100644 index 0000000000..78fc112805 --- /dev/null +++ b/tests/auto/qml/qqmllanguage/data/instanceof_qtquick_composite.qml @@ -0,0 +1,26 @@ +import QtQuick 2.0 +import "instanceOf" + +Item { + id: itemInstance + + Rectangle { + id: rectangleInstance + } + + MouseArea { + id: mouseAreaInstance + } + + CustomRectangle { + id: customRectangleInstance + } + CustomRectangleWithProp { + id: customRectangleWithPropInstance + } + CustomMouseArea { + id: customMouseAreaInstance + } +} + + diff --git a/tests/auto/qml/qqmllanguage/data/instanceof_qtquick_composite_qualified.qml b/tests/auto/qml/qqmllanguage/data/instanceof_qtquick_composite_qualified.qml new file mode 100644 index 0000000000..97361b7334 --- /dev/null +++ b/tests/auto/qml/qqmllanguage/data/instanceof_qtquick_composite_qualified.qml @@ -0,0 +1,27 @@ +import QtQuick 2.0 as QuickImport +import "instanceOf" as CustomImport + +QuickImport.Item { + id: itemInstance + + QuickImport.Rectangle { + id: rectangleInstance + } + + QuickImport.MouseArea { + id: mouseAreaInstance + } + + CustomImport.CustomRectangle { + id: customRectangleInstance + } + CustomImport.CustomRectangleWithProp { + id: customRectangleWithPropInstance + } + CustomImport.CustomMouseArea { + id: customMouseAreaInstance + } +} + + + diff --git a/tests/auto/qml/qqmllanguage/tst_qqmllanguage.cpp b/tests/auto/qml/qqmllanguage/tst_qqmllanguage.cpp index 750c32cc3c..e67fa18309 100644 --- a/tests/auto/qml/qqmllanguage/tst_qqmllanguage.cpp +++ b/tests/auto/qml/qqmllanguage/tst_qqmllanguage.cpp @@ -263,6 +263,9 @@ private slots: void qmlTypeCanBeResolvedByName_data(); void qmlTypeCanBeResolvedByName(); + void instanceof_data(); + void instanceof(); + private: QQmlEngine engine; QStringList defaultImportPathList; @@ -309,7 +312,7 @@ private: if (!errorfile) { \ if (qgetenv("DEBUG") != "" && !component.errors().isEmpty()) \ qWarning() << "Unexpected Errors:" << component.errors(); \ - QVERIFY(!component.isError()); \ + QVERIFY2(!component.isError(), qPrintable(component.errorString())); \ QVERIFY(component.errors().isEmpty()); \ } else { \ DETERMINE_ERRORS(errorfile,expected,actual);\ @@ -4338,6 +4341,200 @@ void tst_qqmllanguage::qmlTypeCanBeResolvedByName() QVERIFY(!o.isNull()); } +// Tests for the QML-only extensions of instanceof. Tests for the regular JS +// instanceof belong in tst_qqmlecmascript! +void tst_qqmllanguage::instanceof_data() +{ + QTest::addColumn<QUrl>("documentToTestIn"); + QTest::addColumn<QVariant>("expectedValue"); + + // so the way this works is that the name of the test tag defines the test + // to run. + // + // the expectedValue is either a boolean true or false for whether the two + // operands are indeed an instanceof each other, or a string for the + // expected error message. + + // assert that basic types don't convert to QObject + QTest::newRow("1 instanceof QtObject") + << testFileUrl("instanceof_qtqml.qml") + << QVariant("TypeError: Type error"); + QTest::newRow("true instanceof QtObject") + << testFileUrl("instanceof_qtqml.qml") + << QVariant("TypeError: Type error"); + QTest::newRow("\"foobar\" instanceof QtObject") + << testFileUrl("instanceof_qtqml.qml") + << QVariant("TypeError: Type error"); + + // assert that Managed don't either + QTest::newRow("new String(\"foobar\") instanceof QtObject") + << testFileUrl("instanceof_qtqml.qml") + << QVariant("TypeError: Type error"); + QTest::newRow("new Object() instanceof QtObject") + << testFileUrl("instanceof_qtqml.qml") + << QVariant("TypeError: Type error"); + QTest::newRow("new Date() instanceof QtObject") + << testFileUrl("instanceof_qtqml.qml") + << QVariant("TypeError: Type error"); + + // test that simple QtQml comparisons work + QTest::newRow("qtobjectInstance instanceof QtObject") + << testFileUrl("instanceof_qtqml.qml") + << QVariant(true); + QTest::newRow("qtobjectInstance instanceof Timer") + << testFileUrl("instanceof_qtqml.qml") + << QVariant(false); + QTest::newRow("timerInstance instanceof QtObject") + << testFileUrl("instanceof_qtqml.qml") + << QVariant(true); + QTest::newRow("timerInstance instanceof Timer") + << testFileUrl("instanceof_qtqml.qml") + << QVariant(true); + QTest::newRow("connectionsInstance instanceof QtObject") + << testFileUrl("instanceof_qtqml.qml") + << QVariant(true); + QTest::newRow("connectionsInstance instanceof Timer") + << testFileUrl("instanceof_qtqml.qml") + << QVariant(false); + QTest::newRow("connectionsInstance instanceof Connections") + << testFileUrl("instanceof_qtqml.qml") + << QVariant(true); + + // make sure they still work when imported with a qualifier + QTest::newRow("qtobjectInstance instanceof QmlImport.QtObject") + << testFileUrl("instanceof_qtqml_qualified.qml") + << QVariant(true); + QTest::newRow("qtobjectInstance instanceof QmlImport.Timer") + << testFileUrl("instanceof_qtqml_qualified.qml") + << QVariant(false); + QTest::newRow("timerInstance instanceof QmlImport.QtObject") + << testFileUrl("instanceof_qtqml_qualified.qml") + << QVariant(true); + QTest::newRow("timerInstance instanceof QmlImport.Timer") + << testFileUrl("instanceof_qtqml_qualified.qml") + << QVariant(true); + QTest::newRow("connectionsInstance instanceof QmlImport.QtObject") + << testFileUrl("instanceof_qtqml_qualified.qml") + << QVariant(true); + QTest::newRow("connectionsInstance instanceof QmlImport.Timer") + << testFileUrl("instanceof_qtqml_qualified.qml") + << QVariant(false); + QTest::newRow("connectionsInstance instanceof QmlImport.Connections") + << testFileUrl("instanceof_qtqml_qualified.qml") + << QVariant(true); + + // test that Quick C++ types work ok + QTest::newRow("itemInstance instanceof QtObject") + << testFileUrl("instanceof_qtquick.qml") + << QVariant(true); + QTest::newRow("itemInstance instanceof Timer") + << testFileUrl("instanceof_qtquick.qml") + << QVariant(false); + QTest::newRow("itemInstance instanceof Rectangle") + << testFileUrl("instanceof_qtquick.qml") + << QVariant(false); + QTest::newRow("rectangleInstance instanceof Item") + << testFileUrl("instanceof_qtquick.qml") + << QVariant(true); + QTest::newRow("rectangleInstance instanceof Rectangle") + << testFileUrl("instanceof_qtquick.qml") + << QVariant(true); + QTest::newRow("rectangleInstance instanceof MouseArea") + << testFileUrl("instanceof_qtquick.qml") + << QVariant(false); + QTest::newRow("mouseAreaInstance instanceof Item") + << testFileUrl("instanceof_qtquick.qml") + << QVariant(true); + QTest::newRow("mouseAreaInstance instanceof Rectangle") + << testFileUrl("instanceof_qtquick.qml") + << QVariant(false); + QTest::newRow("mouseAreaInstance instanceof MouseArea") + << testFileUrl("instanceof_qtquick.qml") + << QVariant(true); + + // test that unqualified quick composite types work ok + QTest::newRow("rectangleInstance instanceof CustomRectangle") + << testFileUrl("instanceof_qtquick_composite.qml") + << QVariant(false); + QTest::newRow("customRectangleInstance instanceof Rectangle") + << testFileUrl("instanceof_qtquick_composite.qml") + << QVariant(true); + QTest::newRow("customRectangleInstance instanceof Item") + << testFileUrl("instanceof_qtquick_composite.qml") + << QVariant(true); + QTest::newRow("customRectangleWithPropInstance instanceof CustomRectangleWithProp") + << testFileUrl("instanceof_qtquick_composite.qml") + << QVariant(true); + QTest::newRow("customRectangleWithPropInstance instanceof CustomRectangle") + << testFileUrl("instanceof_qtquick_composite.qml") + << QVariant(false); // ### XXX: QTBUG-58477 + QTest::newRow("customRectangleWithPropInstance instanceof Rectangle") + << testFileUrl("instanceof_qtquick_composite.qml") + << QVariant(true); + QTest::newRow("customRectangleInstance instanceof MouseArea") + << testFileUrl("instanceof_qtquick_composite.qml") + << QVariant(false); + QTest::newRow("customMouseAreaInstance instanceof MouseArea") + << testFileUrl("instanceof_qtquick_composite.qml") + << QVariant(true); + + // test that they still work when qualified + QTest::newRow("rectangleInstance instanceof CustomImport.CustomRectangle") + << testFileUrl("instanceof_qtquick_composite_qualified.qml") + << QVariant(false); + QTest::newRow("customRectangleInstance instanceof QuickImport.Rectangle") + << testFileUrl("instanceof_qtquick_composite_qualified.qml") + << QVariant(true); + QTest::newRow("customRectangleInstance instanceof QuickImport.Item") + << testFileUrl("instanceof_qtquick_composite_qualified.qml") + << QVariant(true); + QTest::newRow("customRectangleWithPropInstance instanceof CustomImport.CustomRectangleWithProp") + << testFileUrl("instanceof_qtquick_composite_qualified.qml") + << QVariant(true); + QTest::newRow("customRectangleWithPropInstance instanceof CustomImport.CustomRectangle") + << testFileUrl("instanceof_qtquick_composite_qualified.qml") + << QVariant(false); // ### XXX: QTBUG-58477 + QTest::newRow("customRectangleWithPropInstance instanceof QuickImport.Rectangle") + << testFileUrl("instanceof_qtquick_composite_qualified.qml") + << QVariant(true); + QTest::newRow("customRectangleInstance instanceof QuickImport.MouseArea") + << testFileUrl("instanceof_qtquick_composite_qualified.qml") + << QVariant(false); + QTest::newRow("customMouseAreaInstance instanceof QuickImport.MouseArea") + << testFileUrl("instanceof_qtquick_composite_qualified.qml") + << QVariant(true); +} + +void tst_qqmllanguage::instanceof() +{ + QFETCH(QUrl, documentToTestIn); + QFETCH(QVariant, expectedValue); + + QQmlEngine engine; + QQmlComponent component(&engine, documentToTestIn); + VERIFY_ERRORS(0); + + QScopedPointer<QObject> o(component.create()); + QVERIFY(o != 0); + + QQmlExpression expr(engine.contextForObject(o.data()), 0, QString::fromLatin1(QTest::currentDataTag())); + QVariant ret = expr.evaluate(); + + if (expectedValue.type() == QVariant::Bool) { + // no error expected + QVERIFY2(!expr.hasError(), qPrintable(expr.error().description())); + bool returnValue = ret.toBool(); + + if (QTest::currentDataTag() == QLatin1String("customRectangleWithPropInstance instanceof CustomRectangle") || + QTest::currentDataTag() == QLatin1String("customRectangleWithPropInstance instanceof CustomImport.CustomRectangle")) + QEXPECT_FAIL("", "QTBUG-58477: QML type rules are a little lax", Continue); + QCOMPARE(returnValue, expectedValue.toBool()); + } else { + QVERIFY(expr.hasError()); + QCOMPARE(expr.error().description(), expectedValue.toString()); + } +} + QTEST_MAIN(tst_qqmllanguage) #include "tst_qqmllanguage.moc" diff --git a/tests/auto/quick/nokeywords/tst_nokeywords.cpp b/tests/auto/quick/nokeywords/tst_nokeywords.cpp index ad77743ddd..e6655589a3 100644 --- a/tests/auto/quick/nokeywords/tst_nokeywords.cpp +++ b/tests/auto/quick/nokeywords/tst_nokeywords.cpp @@ -55,7 +55,6 @@ #include <QtQuick/private/qsgdefaultinternalrectanglenode_p.h> #include <QtQuick/private/qsgdepthstencilbuffer_p.h> #include <QtQuick/private/qsgdistancefieldglyphnode_p.h> -#include <QtQuick/private/qsgdistancefieldutil_p.h> #endif #include <QtQuick/private/qsggeometry_p.h> #include <QtQuick/private/qsgnode_p.h> diff --git a/tests/auto/quick/qquickimage/tst_qquickimage.cpp b/tests/auto/quick/qquickimage/tst_qquickimage.cpp index 4699f947a1..2681f1a966 100644 --- a/tests/auto/quick/qquickimage/tst_qquickimage.cpp +++ b/tests/auto/quick/qquickimage/tst_qquickimage.cpp @@ -91,6 +91,8 @@ private slots: void sourceSizeChanges(); void correctStatus(); void highdpi(); + void highDpiFillModesAndSizes_data(); + void highDpiFillModesAndSizes(); void hugeImages(); private: @@ -971,6 +973,65 @@ void tst_qquickimage::highdpi() delete obj; } +void tst_qquickimage::highDpiFillModesAndSizes_data() +{ + QTest::addColumn<QQuickImage::FillMode>("fillMode"); + QTest::addColumn<qreal>("expectedHeightAfterSettingWidthTo100"); + QTest::addColumn<qreal>("expectedImplicitHeightAfterSettingWidthTo100"); + QTest::addColumn<qreal>("expectedPaintedWidthAfterSettingWidthTo100"); + QTest::addColumn<qreal>("expectedPaintedHeightAfterSettingWidthTo100"); + + QTest::addRow("Stretch") << QQuickImage::Stretch << 150.0 << 150.0 << 100.0 << 150.0; + QTest::addRow("PreserveAspectFit") << QQuickImage::PreserveAspectFit << 100.0 << 100.0 << 100.0 << 100.0; + QTest::addRow("PreserveAspectCrop") << QQuickImage::PreserveAspectCrop << 150.0 << 150.0 << 150.0 << 150.0; + QTest::addRow("Tile") << QQuickImage::Tile << 150.0 << 150.0 << 100.0 << 150.0; + QTest::addRow("TileVertically") << QQuickImage::TileVertically << 150.0 << 150.0 << 100.0 << 150.0; + QTest::addRow("TileHorizontally") << QQuickImage::TileHorizontally << 150.0 << 150.0 << 100.0 << 150.0; + QTest::addRow("Pad") << QQuickImage::Pad << 150.0 << 150.0 << 150.0 << 150.0; +} + +void tst_qquickimage::highDpiFillModesAndSizes() +{ + QFETCH(QQuickImage::FillMode, fillMode); + QFETCH(qreal, expectedHeightAfterSettingWidthTo100); + QFETCH(qreal, expectedImplicitHeightAfterSettingWidthTo100); + QFETCH(qreal, expectedPaintedWidthAfterSettingWidthTo100); + QFETCH(qreal, expectedPaintedHeightAfterSettingWidthTo100); + + QString componentStr = "import QtQuick 2.0\nImage { source: srcImage; }"; + QQmlComponent component(&engine); + component.setData(componentStr.toLatin1(), QUrl::fromLocalFile("")); + + engine.rootContext()->setContextProperty("srcImage", testFileUrl("heart-highdpi@2x.png")); + + QScopedPointer<QQuickImage> image(qobject_cast<QQuickImage*>(component.create())); + QVERIFY(image); + QCOMPARE(image->width(), 150.0); + QCOMPARE(image->height(), 150.0); + QCOMPARE(image->paintedWidth(), 150.0); + QCOMPARE(image->paintedHeight(), 150.0); + QCOMPARE(image->implicitWidth(), 150.0); + QCOMPARE(image->implicitHeight(), 150.0); + QCOMPARE(image->paintedWidth(), 150.0); + QCOMPARE(image->paintedHeight(), 150.0); + + // The implicit size should not change when setting any fillMode here. + image->setFillMode(fillMode); + QCOMPARE(image->fillMode(), fillMode); + QCOMPARE(image->implicitWidth(), 150.0); + QCOMPARE(image->implicitHeight(), 150.0); + QCOMPARE(image->paintedWidth(), 150.0); + QCOMPARE(image->paintedHeight(), 150.0); + + image->setWidth(100.0); + QCOMPARE(image->width(), 100.0); + QCOMPARE(image->height(), expectedHeightAfterSettingWidthTo100); + QCOMPARE(image->implicitWidth(), 150.0); + QCOMPARE(image->implicitHeight(), expectedImplicitHeightAfterSettingWidthTo100); + QCOMPARE(image->paintedWidth(), expectedPaintedWidthAfterSettingWidthTo100); + QCOMPARE(image->paintedHeight(), expectedPaintedHeightAfterSettingWidthTo100); +} + void tst_qquickimage::hugeImages() { QQuickView view; diff --git a/tests/auto/quick/qquickpositioners/data/implicitGridOneItem.qml b/tests/auto/quick/qquickpositioners/data/implicitGridOneItem.qml new file mode 100644 index 0000000000..8da9fc270d --- /dev/null +++ b/tests/auto/quick/qquickpositioners/data/implicitGridOneItem.qml @@ -0,0 +1,12 @@ +import QtQuick 2.9 +import PositionerTest 1.0 + +ImplicitGrid { + columns: 2 + rows: 1 + + Text { + text: "Text" + width: parent.width + } +} diff --git a/tests/auto/quick/qquickpositioners/data/implicitRowOneItem.qml b/tests/auto/quick/qquickpositioners/data/implicitRowOneItem.qml new file mode 100644 index 0000000000..25a287cf31 --- /dev/null +++ b/tests/auto/quick/qquickpositioners/data/implicitRowOneItem.qml @@ -0,0 +1,9 @@ +import QtQuick 2.9 +import PositionerTest 1.0 + +ImplicitRow { + Text { + text: "Text" + width: parent.width + } +} diff --git a/tests/auto/quick/qquickpositioners/tst_qquickpositioners.cpp b/tests/auto/quick/qquickpositioners/tst_qquickpositioners.cpp index 1b3939401a..4c4afb7a7b 100644 --- a/tests/auto/quick/qquickpositioners/tst_qquickpositioners.cpp +++ b/tests/auto/quick/qquickpositioners/tst_qquickpositioners.cpp @@ -98,6 +98,8 @@ private slots: void test_attachedproperties(); void test_attachedproperties_data(); void test_attachedproperties_dynamic(); + void test_useImplicitSize_oneItem_data(); + void test_useImplicitSize_oneItem(); void populateTransitions_row(); void populateTransitions_row_data(); @@ -304,6 +306,8 @@ void tst_qquickpositioners::moveTransitions_flow_data() tst_qquickpositioners::tst_qquickpositioners() { + qmlRegisterType<QQuickImplicitRow>("PositionerTest", 1, 0, "ImplicitRow"); + qmlRegisterType<QQuickImplicitGrid>("PositionerTest", 1, 0, "ImplicitGrid"); } void tst_qquickpositioners::test_horizontal() @@ -4004,6 +4008,46 @@ void tst_qquickpositioners::test_attachedproperties_dynamic() } +void tst_qquickpositioners::test_useImplicitSize_oneItem_data() +{ + QTest::addColumn<QString>("positionerType"); + + QTest::newRow("Grid") << "Grid"; + QTest::newRow("Row") << "Row"; +} + +void tst_qquickpositioners::test_useImplicitSize_oneItem() +{ + QFETCH(QString, positionerType); + + QQuickView view; + view.setSource(testFileUrl(QString::fromLatin1("implicit%1OneItem.qml").arg(positionerType))); + QCOMPARE(view.status(), QQuickView::Ready); + view.show(); + QVERIFY(QTest::qWaitForWindowExposed(&view)); + + QQuickItem *positioner = view.rootObject(); + QVERIFY(positioner); + const qreal oldPositionerImplicitWidth = positioner->implicitWidth(); + + QQuickText *text = qobject_cast<QQuickText*>(positioner->childItems().first()); + QVERIFY(text); + const qreal oldTextImplicitWidth = text->implicitWidth(); + QCOMPARE(positioner->implicitWidth(), text->implicitWidth()); + + // Ensure that the implicit size of the positioner changes when the implicit size + // of one of its children changes. + text->setText(QLatin1String("Even More Text")); + const qreal textImplicitWidthIncrease = text->implicitWidth() - oldTextImplicitWidth; + QVERIFY(textImplicitWidthIncrease > 0); + QTRY_COMPARE(positioner->implicitWidth(), oldPositionerImplicitWidth + textImplicitWidthIncrease); + + // Ensure that the implicit size of the positioner does not change when the + // explicit size of one of its children changes. + text->setWidth(10); + QTRY_COMPARE(positioner->implicitWidth(), oldPositionerImplicitWidth + textImplicitWidthIncrease); +} + QQuickView *tst_qquickpositioners::createView(const QString &filename, bool wait) { QQuickView *window = new QQuickView(0); diff --git a/tests/auto/quick/qquickwindow/tst_qquickwindow.cpp b/tests/auto/quick/qquickwindow/tst_qquickwindow.cpp index 1d6547c5be..d454f9b7bc 100644 --- a/tests/auto/quick/qquickwindow/tst_qquickwindow.cpp +++ b/tests/auto/quick/qquickwindow/tst_qquickwindow.cpp @@ -1351,12 +1351,6 @@ void tst_qquickwindow::headless() if (isGL) QVERIFY(!window->isSceneGraphInitialized()); } -#if QT_CONFIG(opengl) - if (QGuiApplication::platformName() == QLatin1String("windows") - && QOpenGLContext::openGLModuleType() == QOpenGLContext::LibGLES) { - QSKIP("Crashes on Windows/ANGLE, QTBUG-42967"); - } -#endif // Destroy the native windowing system buffers window->destroy(); QVERIFY(!window->handle()); diff --git a/tests/benchmarks/qml/creation/tst_creation.cpp b/tests/benchmarks/qml/creation/tst_creation.cpp index 9fc67ada71..c0907b5dd1 100644 --- a/tests/benchmarks/qml/creation/tst_creation.cpp +++ b/tests/benchmarks/qml/creation/tst_creation.cpp @@ -385,7 +385,7 @@ void tst_creation::bindings_qml() return; } - QQuickItem *obj = dynamic_cast<QQuickItem *>(component.create()); + QQuickItem *obj = qobject_cast<QQuickItem *>(component.create()); QVERIFY(obj != nullptr); int height = 0; @@ -407,7 +407,7 @@ void tst_creation::bindings_parent_qml() return; } - QQuickItem *obj = dynamic_cast<QQuickItem *>(component.create()); + QQuickItem *obj = qobject_cast<QQuickItem *>(component.create()); QVERIFY(obj != nullptr); int height = 0; diff --git a/tests/manual/v4/TestExpectations b/tests/manual/v4/TestExpectations index 49f107452a..27498de473 100644 --- a/tests/manual/v4/TestExpectations +++ b/tests/manual/v4/TestExpectations @@ -29,3 +29,150 @@ Sbp_12.5_A9_T3 failing Sbp_12.6.1_A13_T3 failing Sbp_12.6.2_A13_T3 failing Sbp_12.6.4_A13_T3 failing + +# es6: function length attributes are configurable, wasn't in es5 +S15.1.2.2_A9.2 failing +S15.1.3.1_A5.2 failing +S15.1.3.2_A5.2 failing +S15.1.3.3_A5.2 failing +S15.1.2.3_A7.2 failing +S15.1.2.4_A2.2 failing +S15.1.2.5_A2.2 failing +S15.1.3.4_A5.2 failing +15.2.3.3-4-186 failing +S15.2.4.2_A9 failing +S15.2.4.3_A9 failing +S15.2.4.4_A9 failing +S15.2.4.5_A9 failing +S15.2.4.6_A9 failing +S15.2.4.7_A9 failing +15.3.3.2-1 failing +15.4.4.2_A4.2 +S15.3.4.2_A9 failing +S15.3.4.3_A9 failing +S15.3.4.4_A9 failing +15.3.4.5-15-2 failing +S15.4.4.2_A4.2 failing +S15.4.4.3_A4.2 failing +S15.4.4.4_A4.2 failing +S15.4.4.5_A6.2 failing +S15.4.4.6_A5.2 failing +S15.4.4.7_A6.2 failing +S15.4.4.8_A5.2 failing +S15.4.4.9_A5.2 failing +S15.4.4.10_A5.2 failing +S15.4.4.11_A7.2 failing +S15.4.4.12_A5.2 failing +S15.4.4.13_A5.2 failing +S15.5.4.10_A9 failing +S15.5.4.11_A9 failing +S15.5.4.12_A9 failing +S15.5.4.13_A9 failing +S15.5.4.14_A9 failing +S15.5.4.15_A9 failing +S15.5.4.16_A9 failing +S15.5.4.17_A9 failing +S15.5.4.18_A9 failing +S15.5.4.19_A9 failing +S15.5.4.4_A9 failing +S15.5.4.5_A9 failing +S15.5.4.6_A9 failing +S15.5.4.7_A9 failing +S15.5.4.8_A9 failing +S15.5.4.9_A9 failing +S15.9.4.2_A3_T2 failing +S15.9.4.3_A3_T2 failing +S15.9.5.2_A3_T2 failing +S15.9.5.3_A3_T2 failing +S15.9.5.4_A3_T2 failing +S15.9.5.5_A3_T2 failing +S15.9.5.1_A3_T2 failing +S15.9.5.10_A3_T2 failing +S15.9.5.11_A3_T2 failing +S15.9.5.12_A3_T2 failing +S15.9.5.13_A3_T2 failing +S15.9.5.14_A3_T2 failing +S15.9.5.15_A3_T2 failing +S15.9.5.16_A3_T2 failing +S15.9.5.17_A3_T2 failing +S15.9.5.18_A3_T2 failing +S15.9.5.19_A3_T2 failing +S15.9.5.20_A3_T2 failing +S15.9.5.21_A3_T2 failing +S15.9.5.22_A3_T2 failing +S15.9.5.23_A3_T2 failing +S15.9.5.24_A3_T2 failing +S15.9.5.25_A3_T2 failing +S15.9.5.26_A3_T2 failing +S15.9.5.27_A3_T2 failing +S15.9.5.28_A3_T2 failing +S15.9.5.29_A3_T2 failing +S15.9.5.30_A3_T2 failing +S15.9.5.31_A3_T2 failing +S15.9.5.32_A3_T2 failing +S15.9.5.33_A3_T2 failing +S15.9.5.34_A3_T2 failing +S15.9.5.35_A3_T2 failing +S15.9.5.36_A3_T2 failing +S15.9.5.37_A3_T2 failing +S15.9.5.38_A3_T2 failing +S15.9.5.39_A3_T2 failing +S15.9.5.40_A3_T2 failing +S15.9.5.41_A3_T2 failing +S15.9.5.42_A3_T2 failing +S15.9.5.6_A3_T2 failing +S15.9.5.7_A3_T2 failing +S15.9.5.8_A3_T2 failing +S15.9.5.9_A3_T2 failing +S15.10.6.2_A9 failing +S15.10.6.3_A9 failing +S15.10.6.4_A9 failing + +# es6: Object.freeze(v) on a non-object returns v, no longer TypeError +15.2.3.9-1 failing +15.2.3.9-1-1 failing +15.2.3.9-1-2 failing +15.2.3.9-1-3 failing +15.2.3.9-1-4 failing +# es6: Object.preventExtensions(O) on a non-object, no longer TypeError +15.2.3.10-1 failing +15.2.3.10-1-3 failing +15.2.3.10-1-4 failing +# es6: Object.isSealed(O) on a non-object, no longer TypeError +15.2.3.11-1 +# es6: Object.isFrozen(O) on a non-object, no longer TypeError +15.2.3.12-1 +15.2.3.12-1-3 +15.2.3.12-1-4 +# es6: Object.isExtensible(O) on a non-object, no longer TypeError +15.2.3.13-1 +15.2.3.13-1-3 +15.2.3.13-1-4 +# es6: Object.keys(O) on a non-object, no longer TypeError +15.2.3.14-1-1 +15.2.3.14-1-2 +15.2.3.14-1-3 +15.2.3.14-1 +15.2.3.14-2 +15.2.3.14-3 +# es6: Object.getOwnPropertyDescriptor(O) on a non-object, no longer TypeError +15.2.3.3-1 +15.2.3.3-1-3 +15.2.3.3-1-4 +# es6: Object.getPrototypeOf(O) on a non-object, no longer TypeError +15.2.3.2-1 +15.2.3.2-1-3 +15.2.3.2-1-4 +# es6: Object.getOwnPropertyNames(O) on a non-object, no longer TypeError +15.2.3.4-1 +15.2.3.4-1-4 +15.2.3.4-1-5 +# es6: Object.seal(O) on a non-object, no longer TypeError +15.2.3.8-1 +15.2.3.8-1-1 +15.2.3.8-1-2 +15.2.3.8-1-3 +15.2.3.8-1-4 + +# es6: Date.prototype is no longer a DateObject +15.9.5.40_1 failing diff --git a/tools/qml/main.cpp b/tools/qml/main.cpp index 8af9a1de41..53dd35da07 100644 --- a/tools/qml/main.cpp +++ b/tools/qml/main.cpp @@ -130,7 +130,7 @@ class LoaderApplication : public QGuiApplication public: LoaderApplication(int& argc, char **argv) : QGuiApplication(argc, argv) {} - bool event(QEvent *ev) + bool event(QEvent *ev) override { if (ev->type() == QEvent::FileOpen) { if (exitTimerId >= 0) { @@ -144,7 +144,7 @@ public: return true; } - void timerEvent(QTimerEvent *) { + void timerEvent(QTimerEvent *) override { noFilesGiven(); } }; diff --git a/tools/qmlimportscanner/main.cpp b/tools/qmlimportscanner/main.cpp index bac7694e17..26a83395c8 100644 --- a/tools/qmlimportscanner/main.cpp +++ b/tools/qmlimportscanner/main.cpp @@ -291,7 +291,7 @@ struct ImportCollector : public QQmlJS::Directives { QVariantList imports; - virtual void importFile(const QString &jsfile, const QString &module, int line, int column) + void importFile(const QString &jsfile, const QString &module, int line, int column) override { QVariantMap entry; entry[typeLiteral()] = QStringLiteral("javascript"); @@ -303,7 +303,7 @@ struct ImportCollector : public QQmlJS::Directives Q_UNUSED(column); } - virtual void importModule(const QString &uri, const QString &version, const QString &module, int line, int column) + void importModule(const QString &uri, const QString &version, const QString &module, int line, int column) override { QVariantMap entry; if (uri.contains(QLatin1Char('/'))) { diff --git a/tools/qmljs/qmljs.cpp b/tools/qmljs/qmljs.cpp index 14a20731c0..182547490d 100644 --- a/tools/qmljs/qmljs.cpp +++ b/tools/qmljs/qmljs.cpp @@ -69,9 +69,7 @@ static void showException(QV4::ExecutionContext *ctx, const QV4::Value &exceptio if (!e) { std::cerr << "Uncaught exception: " << qPrintable(ex->toQString()) << std::endl; } else { - QV4::ScopedString m(scope, scope.engine->newString(QStringLiteral("message"))); - QV4::ScopedValue message(scope, e->get(m)); - std::cerr << "Uncaught exception: " << qPrintable(message->toQStringNoThrow()) << std::endl; + std::cerr << "Uncaught exception: " << qPrintable(e->toQStringNoThrow()) << std::endl; } for (const QV4::StackFrame &frame : trace) { diff --git a/tools/qmlmin/main.cpp b/tools/qmlmin/main.cpp index 6877ca7442..5641e6348e 100644 --- a/tools/qmlmin/main.cpp +++ b/tools/qmlmin/main.cpp @@ -83,12 +83,12 @@ public: // // Handle the .pragma/.import directives // - virtual void pragmaLibrary() + void pragmaLibrary() override { _directives += QLatin1String(".pragma library\n"); } - virtual void importFile(const QString &jsfile, const QString &module, int line, int column) + void importFile(const QString &jsfile, const QString &module, int line, int column) override { _directives += QLatin1String(".import"); _directives += QLatin1Char('"'); @@ -101,7 +101,7 @@ public: Q_UNUSED(column); } - virtual void importModule(const QString &uri, const QString &version, const QString &module, int line, int column) + void importModule(const QString &uri, const QString &version, const QString &module, int line, int column) override { _directives += QLatin1String(".import "); _directives += uri; @@ -201,7 +201,7 @@ public: protected: void append(const QString &s); - bool parse(int startToken); + bool parse(int startToken) override; void escape(const QChar &ch, QString *out); }; @@ -409,7 +409,7 @@ public: QStringList tokenStream() const; protected: - virtual bool parse(int startToken); + bool parse(int startToken) override; }; Tokenize::Tokenize() |