diff options
Diffstat (limited to 'src')
195 files changed, 3482 insertions, 1828 deletions
diff --git a/src/3rdparty/masm/wtf/OSAllocator.h b/src/3rdparty/masm/wtf/OSAllocator.h index a12a467497..494f8bc3c7 100644 --- a/src/3rdparty/masm/wtf/OSAllocator.h +++ b/src/3rdparty/masm/wtf/OSAllocator.h @@ -45,7 +45,7 @@ public: // These methods are symmetric; reserveUncommitted allocates VM in an uncommitted state, // releaseDecommitted should be called on a region of VM allocated by a single reservation, // the memory must all currently be in a decommitted state. - static void* reserveUncommitted(size_t, Usage = UnknownUsage, bool writable = true, bool executable = false, bool includesGuardPages = false); + static void* reserveUncommitted(size_t, Usage = UnknownUsage, bool writable = true, bool executable = false); WTF_EXPORT_PRIVATE static void releaseDecommitted(void*, size_t); // These methods are symmetric; they commit or decommit a region of VM (uncommitted VM should diff --git a/src/3rdparty/masm/wtf/OSAllocatorPosix.cpp b/src/3rdparty/masm/wtf/OSAllocatorPosix.cpp index d8c8e0378f..f52c22f7fa 100644 --- a/src/3rdparty/masm/wtf/OSAllocatorPosix.cpp +++ b/src/3rdparty/masm/wtf/OSAllocatorPosix.cpp @@ -38,7 +38,7 @@ namespace WTF { -void* OSAllocator::reserveUncommitted(size_t bytes, Usage usage, bool writable, bool executable, bool includesGuardPages) +void* OSAllocator::reserveUncommitted(size_t bytes, Usage usage, bool writable, bool executable) { #if OS(QNX) // Reserve memory with PROT_NONE and MAP_LAZY so it isn't committed now. @@ -49,14 +49,13 @@ void* OSAllocator::reserveUncommitted(size_t bytes, Usage usage, bool writable, UNUSED_PARAM(usage); UNUSED_PARAM(writable); UNUSED_PARAM(executable); - UNUSED_PARAM(includesGuardPages); void* result = mmap(0, bytes, PROT_NONE, MAP_NORESERVE | MAP_PRIVATE | MAP_ANON, -1, 0); if (result == MAP_FAILED) CRASH(); madvise(result, bytes, MADV_DONTNEED); #else - void* result = reserveAndCommit(bytes, usage, writable, executable, includesGuardPages); + void* result = reserveAndCommit(bytes, usage, writable, executable); #if HAVE(MADV_FREE_REUSE) // To support the "reserve then commit" model, we have to initially decommit. while (madvise(result, bytes, MADV_FREE_REUSABLE) == -1 && errno == EAGAIN) { } diff --git a/src/3rdparty/masm/wtf/OSAllocatorWin.cpp b/src/3rdparty/masm/wtf/OSAllocatorWin.cpp index f95a4841c6..259fc67324 100644 --- a/src/3rdparty/masm/wtf/OSAllocatorWin.cpp +++ b/src/3rdparty/masm/wtf/OSAllocatorWin.cpp @@ -25,6 +25,7 @@ #include "config.h" #include "OSAllocator.h" +#include "PageBlock.h" #if OS(WINDOWS) @@ -40,7 +41,7 @@ static inline DWORD protection(bool writable, bool executable) (writable ? PAGE_READWRITE : PAGE_READONLY); } -void* OSAllocator::reserveUncommitted(size_t bytes, Usage, bool writable, bool executable, bool) +void* OSAllocator::reserveUncommitted(size_t bytes, Usage, bool writable, bool executable) { void* result = VirtualAlloc(0, bytes, MEM_RESERVE, protection(writable, executable)); if (!result) @@ -48,11 +49,20 @@ void* OSAllocator::reserveUncommitted(size_t bytes, Usage, bool writable, bool e return result; } -void* OSAllocator::reserveAndCommit(size_t bytes, Usage, bool writable, bool executable, bool) +void* OSAllocator::reserveAndCommit(size_t bytes, Usage, bool writable, bool executable, + bool includesGuardPages) { void* result = VirtualAlloc(0, bytes, MEM_RESERVE | MEM_COMMIT, protection(writable, executable)); if (!result) CRASH(); + if (includesGuardPages) { + size_t guardSize = pageSize(); + DWORD oldProtect; + if (!VirtualProtect(result, guardSize, protection(false, false), &oldProtect) || + !VirtualProtect(static_cast<char*>(result) + bytes - guardSize, guardSize, + protection(false, false), &oldProtect)) + CRASH(); + } return result; } diff --git a/src/3rdparty/masm/wtf/OSAllocatorWinRT.cpp b/src/3rdparty/masm/wtf/OSAllocatorWinRT.cpp index 7ed9f539e5..9b8f5bf46b 100644 --- a/src/3rdparty/masm/wtf/OSAllocatorWinRT.cpp +++ b/src/3rdparty/masm/wtf/OSAllocatorWinRT.cpp @@ -33,7 +33,7 @@ namespace WTF { -void* OSAllocator::reserveUncommitted(size_t bytes, Usage, bool, bool, bool) +void* OSAllocator::reserveUncommitted(size_t bytes, Usage, bool, bool) { void* result = _aligned_malloc(bytes, 16); if (!result) diff --git a/src/3rdparty/masm/wtf/PageAllocation.h b/src/3rdparty/masm/wtf/PageAllocation.h index 18d31880c0..95692be3ae 100644 --- a/src/3rdparty/masm/wtf/PageAllocation.h +++ b/src/3rdparty/masm/wtf/PageAllocation.h @@ -87,10 +87,15 @@ public: operator bool() const { return PageBlock::operator bool(); } #endif - static PageAllocation allocate(size_t size, OSAllocator::Usage usage = OSAllocator::UnknownUsage, bool writable = true, bool executable = false) + static PageAllocation allocate(size_t size, + OSAllocator::Usage usage = OSAllocator::UnknownUsage, + bool writable = true, bool executable = false, + bool includesGuardPages = false) { ASSERT(isPageAligned(size)); - return PageAllocation(OSAllocator::reserveAndCommit(size, usage, writable, executable), size); + return PageAllocation(OSAllocator::reserveAndCommit(size, usage, writable, executable, + includesGuardPages), size, + includesGuardPages); } void deallocate() @@ -103,12 +108,12 @@ public: ASSERT(tmp); ASSERT(!*this); - OSAllocator::decommitAndRelease(tmp.base(), tmp.size()); + OSAllocator::decommitAndRelease(tmp.realBase(), tmp.realSize()); } private: - PageAllocation(void* base, size_t size) - : PageBlock(base, size, false) + PageAllocation(void* base, size_t size, bool includesGuardPages = false) + : PageBlock(base, size, includesGuardPages) { } }; diff --git a/src/3rdparty/masm/wtf/PageAllocationAligned.cpp b/src/3rdparty/masm/wtf/PageAllocationAligned.cpp index bdb976b1b7..90c2fd61db 100644 --- a/src/3rdparty/masm/wtf/PageAllocationAligned.cpp +++ b/src/3rdparty/masm/wtf/PageAllocationAligned.cpp @@ -52,7 +52,7 @@ PageAllocationAligned PageAllocationAligned::allocate(size_t size, size_t alignm // Resererve with suffcient additional VM to correctly align. size_t reservationSize = size + alignmentDelta; - void* reservationBase = OSAllocator::reserveUncommitted(reservationSize, usage, writable, false); + void* reservationBase = OSAllocator::reserveUncommitted(reservationSize, usage, writable); // Select an aligned region within the reservation and commit. void* alignedBase = reinterpret_cast<uintptr_t>(reservationBase) & alignmentMask @@ -75,10 +75,11 @@ void PageAllocationAligned::deallocate() ASSERT(!*this); #if OS(DARWIN) - vm_deallocate(current_task(), reinterpret_cast<vm_address_t>(tmp.base()), tmp.size()); + vm_deallocate(current_task(), reinterpret_cast<vm_address_t>(tmp.realBase()), tmp.realSize()); #else - ASSERT(tmp.m_reservation.contains(tmp.base(), tmp.size())); - OSAllocator::decommitAndRelease(tmp.m_reservation.base(), tmp.m_reservation.size(), tmp.base(), tmp.size()); + ASSERT(tmp.m_reservation.contains(tmp.realBase(), tmp.realSize())); + OSAllocator::decommitAndRelease(tmp.m_reservation.realBase(), tmp.m_reservation.realSize(), + tmp.realBase(), tmp.realSize()); #endif } diff --git a/src/3rdparty/masm/wtf/PageBlock.h b/src/3rdparty/masm/wtf/PageBlock.h index 56e5570178..4d408e1c91 100644 --- a/src/3rdparty/masm/wtf/PageBlock.h +++ b/src/3rdparty/masm/wtf/PageBlock.h @@ -40,8 +40,13 @@ public: PageBlock(const PageBlock&); PageBlock(void*, size_t, bool hasGuardPages); + void* realBase() const { return m_realBase; } void* base() const { return m_base; } - size_t size() const { return m_size; } + size_t size() const + { + return m_size - 2 * (static_cast<char *>(m_base) - static_cast<char *>(m_realBase)); + } + size_t realSize() const { return m_size; } operator bool() const { return !!m_realBase; } diff --git a/src/3rdparty/masm/wtf/PageReservation.h b/src/3rdparty/masm/wtf/PageReservation.h index 77783ebcc4..74a136168c 100644 --- a/src/3rdparty/masm/wtf/PageReservation.h +++ b/src/3rdparty/masm/wtf/PageReservation.h @@ -104,13 +104,7 @@ public: static PageReservation reserve(size_t size, OSAllocator::Usage usage = OSAllocator::UnknownUsage, bool writable = true, bool executable = false) { ASSERT(isPageAligned(size)); - return PageReservation(OSAllocator::reserveUncommitted(size, usage, writable, executable), size, writable, executable, false); - } - - static PageReservation reserveWithGuardPages(size_t size, OSAllocator::Usage usage = OSAllocator::UnknownUsage, bool writable = true, bool executable = false) - { - ASSERT(isPageAligned(size)); - return PageReservation(OSAllocator::reserveUncommitted(size + pageSize() * 2, usage, writable, executable, true), size, writable, executable, true); + return PageReservation(OSAllocator::reserveUncommitted(size, usage, writable, executable), size, writable, executable); } void deallocate() @@ -125,12 +119,12 @@ public: ASSERT(tmp); ASSERT(!*this); - OSAllocator::releaseDecommitted(tmp.base(), tmp.size()); + OSAllocator::releaseDecommitted(tmp.realBase(), tmp.realSize()); } private: - PageReservation(void* base, size_t size, bool writable, bool executable, bool hasGuardPages) - : PageBlock(base, size, hasGuardPages) + PageReservation(void* base, size_t size, bool writable, bool executable) + : PageBlock(base, size, false) , m_committed(0) , m_writable(writable) , m_executable(executable) diff --git a/src/imports/localstorage/plugin.cpp b/src/imports/localstorage/plugin.cpp index 8b90f5a685..8133202213 100644 --- a/src/imports/localstorage/plugin.cpp +++ b/src/imports/localstorage/plugin.cpp @@ -52,6 +52,7 @@ #include <private/qv4functionobject_p.h> #include <private/qv4objectproto_p.h> #include <private/qv4scopedvalue_p.h> +#include <private/qv4objectiterator_p.h> using namespace QV4; @@ -59,7 +60,7 @@ using namespace QV4; QV4::Scoped<String> v(scope, scope.engine->newString(desc)); \ QV4::Scoped<Object> ex(scope, scope.engine->newErrorObject(v)); \ ex->put(QV4::ScopedString(scope, scope.engine->newIdentifier(QStringLiteral("code"))).getPointer(), QV4::ScopedValue(scope, Primitive::fromInt32(error))); \ - ctx->throwError(ex); \ + ctx->engine()->throwError(ex); \ return Encode::undefined(); \ } @@ -67,13 +68,13 @@ using namespace QV4; QV4::Scoped<String> v(scope, scope.engine->newString(desc)); \ QV4::Scoped<Object> ex(scope, scope.engine->newErrorObject(v)); \ ex->put(QV4::ScopedString(scope, scope.engine->newIdentifier(QStringLiteral("code"))).getPointer(), QV4::ScopedValue(scope, Primitive::fromInt32(error))); \ - args->setReturnValue(ctx->throwError(ex)); \ + args->setReturnValue(ctx->engine()->throwError(ex)); \ return; \ } #define V4THROW_REFERENCE(string) { \ QV4::Scoped<String> v(scope, scope.engine->newString(string)); \ - ctx->throwReferenceError(v); \ + ctx->engine()->throwReferenceError(v); \ return Encode::undefined(); \ } @@ -116,7 +117,7 @@ public: }; V4_OBJECT(Object) - static QQmlSqlDatabaseWrapper *create(QV8Engine *engine) + static QV4::Returned<QQmlSqlDatabaseWrapper> *create(QV8Engine *engine) { QV4::ExecutionEngine *e = QV8Engine::getV4(engine); return e->memoryManager->alloc<QQmlSqlDatabaseWrapper>(e); @@ -178,7 +179,7 @@ static ReturnedValue qmlsqldatabase_rows_setForwardOnly(CallContext *ctx) if (!r || r->d()->type != QQmlSqlDatabaseWrapper::Rows) V4THROW_REFERENCE("Not a SQLDatabase::Rows object"); if (ctx->d()->callData->argc < 1) - return ctx->throwTypeError(); + return ctx->engine()->throwTypeError(); r->d()->sqlQuery.setForwardOnly(ctx->d()->callData->args[0].toBoolean()); return Encode::undefined(); diff --git a/src/particles/qquickparticlesystem.cpp b/src/particles/qquickparticlesystem.cpp index db5d607922..be64851a19 100644 --- a/src/particles/qquickparticlesystem.cpp +++ b/src/particles/qquickparticlesystem.cpp @@ -931,19 +931,26 @@ void QQuickParticleSystem::emittersChanged() if (!m_componentComplete) return; - m_emitters.removeAll(0); - - - QList<int> previousSizes; - QList<int> newSizes; + QVector<int> previousSizes; + QVector<int> newSizes; + previousSizes.reserve(m_nextGroupId); + newSizes.reserve(m_nextGroupId); for (int i=0; i<m_nextGroupId; i++) { previousSizes << groupData[i]->size(); newSizes << 0; } - foreach (QQuickParticleEmitter* e, m_emitters) {//Populate groups and set sizes. - if (!groupIds.contains(e->group()) - || (!e->group().isEmpty() && !groupIds[e->group()])) {//or it was accidentally inserted by a failed lookup earlier + // Populate groups and set sizes. + for (int i = 0; i < m_emitters.count(); ++i) { + QQuickParticleEmitter *e = m_emitters.at(i); + if (!e) { + m_emitters.removeAt(i); + i--; + continue; + } + + if (!e->group().isEmpty() && + !groupIds.contains(e->group())) { int id = m_nextGroupId++; QQuickParticleGroupData* gd = new QQuickParticleGroupData(id, this); groupIds.insert(e->group(), id); diff --git a/src/particles/qquickv4particledata.cpp b/src/particles/qquickv4particledata.cpp index 586066ec24..90eeca7b8e 100644 --- a/src/particles/qquickv4particledata.cpp +++ b/src/particles/qquickv4particledata.cpp @@ -294,7 +294,7 @@ static QV4::ReturnedValue particleData_discard(QV4::CallContext *ctx) QV4::Scoped<QV4ParticleData> r(scope, ctx->d()->callData->thisObject); if (!r || !r->d()->datum) - return ctx->throwError(QStringLiteral("Not a valid ParticleData object")); + return ctx->engine()->throwError(QStringLiteral("Not a valid ParticleData object")); r->d()->datum->lifeSpan = 0; //Don't kill(), because it could still be in the middle of being created return QV4::Encode::undefined(); @@ -306,7 +306,7 @@ static QV4::ReturnedValue particleData_lifeLeft(QV4::CallContext *ctx) QV4::Scoped<QV4ParticleData> r(scope, ctx->d()->callData->thisObject); if (!r || !r->d()->datum) - return ctx->throwError(QStringLiteral("Not a valid ParticleData object")); + return ctx->engine()->throwError(QStringLiteral("Not a valid ParticleData object")); return QV4::Encode(r->d()->datum->lifeLeft()); } @@ -317,7 +317,7 @@ static QV4::ReturnedValue particleData_curSize(QV4::CallContext *ctx) QV4::Scoped<QV4ParticleData> r(scope, ctx->d()->callData->thisObject); if (!r || !r->d()->datum) - return ctx->throwError(QStringLiteral("Not a valid ParticleData object")); + return ctx->engine()->throwError(QStringLiteral("Not a valid ParticleData object")); return QV4::Encode(r->d()->datum->curSize()); } @@ -326,7 +326,7 @@ static QV4::ReturnedValue particleData_curSize(QV4::CallContext *ctx) QV4::Scope scope(ctx); \ QV4::Scoped<QV4ParticleData> r(scope, ctx->d()->callData->thisObject); \ if (!r || !r->d()->datum) \ - ctx->throwError(QStringLiteral("Not a valid ParticleData object")); \ + ctx->engine()->throwError(QStringLiteral("Not a valid ParticleData object")); \ \ return QV4::Encode((r->d()->datum->color. VAR )/255.0);\ }\ @@ -336,7 +336,7 @@ static QV4::ReturnedValue particleData_set_ ## NAME (QV4::CallContext *ctx)\ QV4::Scope scope(ctx); \ QV4::Scoped<QV4ParticleData> r(scope, ctx->d()->callData->thisObject); \ if (!r || !r->d()->datum)\ - ctx->throwError(QStringLiteral("Not a valid ParticleData object"));\ + ctx->engine()->throwError(QStringLiteral("Not a valid ParticleData object"));\ \ double d = ctx->d()->callData->argc ? ctx->d()->callData->args[0].toNumber() : 0; \ r->d()->datum->color. VAR = qMin(255, qMax(0, (int)floor(d * 255.0)));\ @@ -349,7 +349,7 @@ static QV4::ReturnedValue particleData_set_ ## NAME (QV4::CallContext *ctx)\ QV4::Scope scope(ctx); \ QV4::Scoped<QV4ParticleData> r(scope, ctx->d()->callData->thisObject); \ if (!r || !r->d()->datum) \ - ctx->throwError(QStringLiteral("Not a valid ParticleData object")); \ + ctx->engine()->throwError(QStringLiteral("Not a valid ParticleData object")); \ \ return QV4::Encode(r->d()->datum-> VARIABLE);\ }\ @@ -359,7 +359,7 @@ static QV4::ReturnedValue particleData_set_ ## VARIABLE (QV4::CallContext *ctx)\ QV4::Scope scope(ctx); \ QV4::Scoped<QV4ParticleData> r(scope, ctx->d()->callData->thisObject); \ if (!r || !r->d()->datum)\ - ctx->throwError(QStringLiteral("Not a valid ParticleData object"));\ + ctx->engine()->throwError(QStringLiteral("Not a valid ParticleData object"));\ \ r->d()->datum-> VARIABLE = (ctx->d()->callData->argc && ctx->d()->callData->args[0].toBoolean()) ? 1.0 : 0.0;\ return QV4::Encode::undefined(); \ @@ -370,7 +370,7 @@ static QV4::ReturnedValue particleData_set_ ## VARIABLE (QV4::CallContext *ctx)\ QV4::Scope scope(ctx); \ QV4::Scoped<QV4ParticleData> r(scope, ctx->d()->callData->thisObject); \ if (!r || !r->d()->datum) \ - ctx->throwError(QStringLiteral("Not a valid ParticleData object")); \ + ctx->engine()->throwError(QStringLiteral("Not a valid ParticleData object")); \ \ return QV4::Encode(r->d()->datum-> VARIABLE);\ }\ @@ -380,7 +380,7 @@ static QV4::ReturnedValue particleData_set_ ## VARIABLE (QV4::CallContext *ctx)\ QV4::Scope scope(ctx); \ QV4::Scoped<QV4ParticleData> r(scope, ctx->d()->callData->thisObject); \ if (!r || !r->d()->datum)\ - ctx->throwError(QStringLiteral("Not a valid ParticleData object"));\ + ctx->engine()->throwError(QStringLiteral("Not a valid ParticleData object"));\ \ r->d()->datum-> VARIABLE = ctx->d()->callData->argc ? ctx->d()->callData->args[0].toNumber() : qSNaN();\ return QV4::Encode::undefined(); \ @@ -391,7 +391,7 @@ static QV4::ReturnedValue particleData_set_ ## VARIABLE (QV4::CallContext *ctx)\ QV4::Scope scope(ctx); \ QV4::Scoped<QV4ParticleData> r(scope, ctx->d()->callData->thisObject); \ if (!r || !r->d()->datum) \ - ctx->throwError(QStringLiteral("Not a valid ParticleData object")); \ + ctx->engine()->throwError(QStringLiteral("Not a valid ParticleData object")); \ \ return QV4::Encode(r->d()->datum-> GETTER ());\ }\ @@ -401,7 +401,7 @@ static QV4::ReturnedValue particleData_set_ ## VARIABLE (QV4::CallContext *ctx)\ QV4::Scope scope(ctx); \ QV4::Scoped<QV4ParticleData> r(scope, ctx->d()->callData->thisObject); \ if (!r || !r->d()->datum)\ - ctx->throwError(QStringLiteral("Not a valid ParticleData object"));\ + ctx->engine()->throwError(QStringLiteral("Not a valid ParticleData object"));\ \ r->d()->datum-> SETTER (ctx->d()->callData->argc ? ctx->d()->callData->args[0].toNumber() : qSNaN());\ return QV4::Encode::undefined(); \ diff --git a/src/qml/compiler/qv4codegen.cpp b/src/qml/compiler/qv4codegen.cpp index a7b5326861..c66202262b 100644 --- a/src/qml/compiler/qv4codegen.cpp +++ b/src/qml/compiler/qv4codegen.cpp @@ -2861,7 +2861,7 @@ void RuntimeCodegen::throwSyntaxError(const AST::SourceLocation &loc, const QStr if (hasError) return; hasError = true; - context->throwSyntaxError(detail, _module->fileName, loc.startLine, loc.startColumn); + context->engine()->throwSyntaxError(detail, _module->fileName, loc.startLine, loc.startColumn); } void RuntimeCodegen::throwReferenceError(const AST::SourceLocation &loc, const QString &detail) @@ -2869,7 +2869,7 @@ void RuntimeCodegen::throwReferenceError(const AST::SourceLocation &loc, const Q if (hasError) return; hasError = true; - context->throwReferenceError(detail, _module->fileName, loc.startLine, loc.startColumn); + context->engine()->throwReferenceError(detail, _module->fileName, loc.startLine, loc.startColumn); } #endif // V4_BOOTSTRAP diff --git a/src/qml/compiler/qv4compileddata.cpp b/src/qml/compiler/qv4compileddata.cpp index d242fb7b3a..fbef8b8566 100644 --- a/src/qml/compiler/qv4compileddata.cpp +++ b/src/qml/compiler/qv4compileddata.cpp @@ -65,9 +65,9 @@ QV4::Function *CompilationUnit::linkToEngine(ExecutionEngine *engine) Q_ASSERT(!runtimeStrings); Q_ASSERT(data); - runtimeStrings = (QV4::StringValue *)malloc(data->stringTableSize * sizeof(QV4::StringValue)); + runtimeStrings = (QV4::String **)malloc(data->stringTableSize * sizeof(QV4::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::StringValue)); + memset(runtimeStrings, 0, data->stringTableSize * sizeof(QV4::String*)); for (uint i = 0; i < data->stringTableSize; ++i) runtimeStrings[i] = engine->newIdentifier(data->stringAt(i)); @@ -109,7 +109,7 @@ QV4::Function *CompilationUnit::linkToEngine(ExecutionEngine *engine) l->classList[j] = 0; l->level = -1; l->index = UINT_MAX; - l->name = runtimeStrings[compiledLookups[i].nameIndex].asString(); + l->name = runtimeStrings[compiledLookups[i].nameIndex]; if (type == CompiledData::Lookup::Type_IndexedGetter || type == CompiledData::Lookup::Type_IndexedSetter) l->engine = engine; } @@ -123,7 +123,7 @@ QV4::Function *CompilationUnit::linkToEngine(ExecutionEngine *engine) const CompiledData::JSClassMember *member = data->jsClassAt(i, &memberCount); QV4::InternalClass *klass = engine->objectClass; for (int j = 0; j < memberCount; ++j, ++member) - klass = klass->addMember(runtimeStrings[member->nameOffset].asString(), member->isAccessor ? QV4::Attr_Accessor : QV4::Attr_Data); + klass = klass->addMember(runtimeStrings[member->nameOffset], member->isAccessor ? QV4::Attr_Accessor : QV4::Attr_Data); runtimeClasses[i] = klass; } @@ -166,14 +166,16 @@ void CompilationUnit::unlink() void CompilationUnit::markObjects(QV4::ExecutionEngine *e) { for (uint i = 0; i < data->stringTableSize; ++i) - runtimeStrings[i].mark(e); + if (runtimeStrings[i]) + runtimeStrings[i]->mark(e); if (runtimeRegularExpressions) { for (uint i = 0; i < data->regexpTableSize; ++i) runtimeRegularExpressions[i].mark(e); } if (runtimeLookups) { for (uint i = 0; i < data->lookupTableSize; ++i) - runtimeLookups[i].name->mark(e); + if (runtimeLookups[i].name) + runtimeLookups[i].name->mark(e); } } diff --git a/src/qml/compiler/qv4compileddata_p.h b/src/qml/compiler/qv4compileddata_p.h index 6791970461..6ab7191358 100644 --- a/src/qml/compiler/qv4compileddata_p.h +++ b/src/qml/compiler/qv4compileddata_p.h @@ -588,7 +588,7 @@ struct Q_QML_PRIVATE_EXPORT CompilationUnit : public QQmlRefCount ExecutionEngine *engine; QString fileName() const { return data->stringAt(data->sourceFileIndex); } - QV4::StringValue *runtimeStrings; // Array + QV4::String **runtimeStrings; // Array QV4::Lookup *runtimeLookups; QV4::Value *runtimeRegularExpressions; QV4::InternalClass **runtimeClasses; diff --git a/src/qml/debugger/qqmlprofilerdefinitions_p.h b/src/qml/debugger/qqmlprofilerdefinitions_p.h index e8ee98433d..713134f394 100644 --- a/src/qml/debugger/qqmlprofilerdefinitions_p.h +++ b/src/qml/debugger/qqmlprofilerdefinitions_p.h @@ -107,18 +107,20 @@ struct QQmlProfilerDefinitions { }; enum SceneGraphFrameType { - SceneGraphRendererFrame, - SceneGraphAdaptationLayerFrame, - SceneGraphContextFrame, - SceneGraphRenderLoopFrame, - SceneGraphTexturePrepare, - SceneGraphTextureDeletion, - SceneGraphPolishAndSync, - SceneGraphWindowsRenderShow, - SceneGraphWindowsAnimations, - SceneGraphPolishFrame, - - MaximumSceneGraphFrameType + SceneGraphRendererFrame, // Render Thread + SceneGraphAdaptationLayerFrame, // Render Thread + SceneGraphContextFrame, // Render Thread + SceneGraphRenderLoopFrame, // Render Thread + SceneGraphTexturePrepare, // Render Thread + SceneGraphTextureDeletion, // Render Thread + SceneGraphPolishAndSync, // GUI Thread + SceneGraphWindowsRenderShow, // Unused + SceneGraphWindowsAnimations, // GUI Thread + SceneGraphPolishFrame, // GUI Thread + + MaximumSceneGraphFrameType, + NumRenderThreadFrameTypes = SceneGraphPolishAndSync, + NumGUIThreadFrameTypes = MaximumSceneGraphFrameType - NumRenderThreadFrameTypes }; typedef QV4::Profiling::MemoryType MemoryType; diff --git a/src/qml/jit/qv4assembler.cpp b/src/qml/jit/qv4assembler.cpp index ed342740ac..300f4b0fb2 100644 --- a/src/qml/jit/qv4assembler.cpp +++ b/src/qml/jit/qv4assembler.cpp @@ -214,7 +214,7 @@ Assembler::Pointer Assembler::loadStringAddress(RegisterID reg, const QString &s loadPtr(Address(Assembler::ContextRegister, qOffsetOf(QV4::ExecutionContext::Data, compilationUnit)), Assembler::ScratchRegister); loadPtr(Address(Assembler::ScratchRegister, qOffsetOf(QV4::CompiledData::CompilationUnit, runtimeStrings)), reg); const int id = _isel->registerString(string); - return Pointer(reg, id * sizeof(QV4::StringValue)); + return Pointer(reg, id * sizeof(QV4::String*)); } void Assembler::loadStringRef(RegisterID reg, const QString &string) @@ -222,7 +222,7 @@ void Assembler::loadStringRef(RegisterID reg, const QString &string) loadPtr(Address(Assembler::ContextRegister, qOffsetOf(QV4::ExecutionContext::Data, compilationUnit)), reg); loadPtr(Address(reg, qOffsetOf(QV4::CompiledData::CompilationUnit, runtimeStrings)), reg); const int id = _isel->registerString(string); - loadPtr(Address(reg, id * sizeof(QV4::StringValue)), reg); + loadPtr(Address(reg, id * sizeof(QV4::String*)), reg); } void Assembler::storeValue(QV4::Primitive value, IR::Expr *destination) diff --git a/src/qml/jsapi/qjsvalueiterator.cpp b/src/qml/jsapi/qjsvalueiterator.cpp index f7976e7cfc..cc6953cbf7 100644 --- a/src/qml/jsapi/qjsvalueiterator.cpp +++ b/src/qml/jsapi/qjsvalueiterator.cpp @@ -36,6 +36,7 @@ #include "qjsvalue_p.h" #include "private/qv4string_p.h" #include "private/qv4object_p.h" +#include "private/qv4context_p.h" QT_BEGIN_NAMESPACE @@ -51,7 +52,7 @@ QJSValueIteratorPrivate::QJSValueIteratorPrivate(const QJSValue &v) QV4::Scope scope(e); QV4::ScopedObject o(scope, jsp->value); - iterator = e->newForEachIteratorObject(e->currentContext(), o)->asReturnedValue(); + iterator = e->newForEachIteratorObject(o)->asReturnedValue(); currentName = (QV4::String *)0; nextName = (QV4::String *)0; @@ -223,7 +224,7 @@ QJSValueIterator& QJSValueIterator::operator=(QJSValue& object) QJSValuePrivate *jsp = QJSValuePrivate::get(object); QV4::Scope scope(v4); QV4::ScopedObject o(scope, jsp->value); - d_ptr->iterator = v4->newForEachIteratorObject(v4->currentContext(), o)->asReturnedValue(); + d_ptr->iterator = v4->newForEachIteratorObject(o)->asReturnedValue(); QV4::Scoped<QV4::ForEachIteratorObject> it(scope, d_ptr->iterator.value()); it->d()->it.flags = QV4::ObjectIterator::NoFlags; QV4::String *nm = 0; diff --git a/src/qml/jsruntime/jsruntime.pri b/src/qml/jsruntime/jsruntime.pri index c27aaa90d8..ef44ca6f4d 100644 --- a/src/qml/jsruntime/jsruntime.pri +++ b/src/qml/jsruntime/jsruntime.pri @@ -42,7 +42,10 @@ SOURCES += \ $$PWD/qv4qobjectwrapper.cpp \ $$PWD/qv4qmlextensions.cpp \ $$PWD/qv4vme_moth.cpp \ - $$PWD/qv4profiling.cpp + $$PWD/qv4profiling.cpp \ + $$PWD/qv4arraybuffer.cpp \ + $$PWD/qv4typedarray.cpp \ + $$PWD/qv4dataview.cpp HEADERS += \ $$PWD/qv4global_p.h \ @@ -89,7 +92,10 @@ HEADERS += \ $$PWD/qv4qobjectwrapper_p.h \ $$PWD/qv4qmlextensions_p.h \ $$PWD/qv4vme_moth_p.h \ - $$PWD/qv4profiling_p.h + $$PWD/qv4profiling_p.h \ + $$PWD/qv4arraybuffer_p.h \ + $$PWD/qv4typedarray_p.h \ + $$PWD/qv4dataview_p.h } diff --git a/src/qml/jsruntime/qv4argumentsobject.cpp b/src/qml/jsruntime/qv4argumentsobject.cpp index 4af8927a2e..e8cb788b74 100644 --- a/src/qml/jsruntime/qv4argumentsobject.cpp +++ b/src/qml/jsruntime/qv4argumentsobject.cpp @@ -134,7 +134,7 @@ bool ArgumentsObject::defineOwnProperty(ExecutionContext *ctx, uint index, const } if (ctx->d()->strictMode && !result) - return ctx->throwTypeError(); + return ctx->engine()->throwTypeError(); return result; } @@ -200,7 +200,7 @@ ReturnedValue ArgumentsGetterFunction::call(Managed *getter, CallData *callData) Scoped<ArgumentsGetterFunction> g(scope, static_cast<ArgumentsGetterFunction *>(getter)); Scoped<ArgumentsObject> o(scope, callData->thisObject.as<ArgumentsObject>()); if (!o) - return v4->currentContext()->throwTypeError(); + return v4->throwTypeError(); Q_ASSERT(g->index() < static_cast<unsigned>(o->context()->d()->callData->argc)); return o->context()->argument(g->index()); @@ -215,19 +215,19 @@ ReturnedValue ArgumentsSetterFunction::call(Managed *setter, CallData *callData) Scoped<ArgumentsSetterFunction> s(scope, static_cast<ArgumentsSetterFunction *>(setter)); Scoped<ArgumentsObject> o(scope, callData->thisObject.as<ArgumentsObject>()); if (!o) - return v4->currentContext()->throwTypeError(); + return v4->throwTypeError(); Q_ASSERT(s->index() < static_cast<unsigned>(o->context()->d()->callData->argc)); o->context()->d()->callData->args[s->index()] = callData->argc ? callData->args[0].asReturnedValue() : Encode::undefined(); return Encode::undefined(); } -void ArgumentsObject::markObjects(Managed *that, ExecutionEngine *e) +void ArgumentsObject::markObjects(HeapObject *that, ExecutionEngine *e) { - ArgumentsObject *o = static_cast<ArgumentsObject *>(that); - if (o->context()) - o->context()->mark(e); - o->mappedArguments().mark(e); + ArgumentsObject::Data *o = static_cast<ArgumentsObject::Data *>(that); + if (o->context) + o->context->mark(e); + o->mappedArguments.mark(e); Object::markObjects(that, e); } diff --git a/src/qml/jsruntime/qv4argumentsobject_p.h b/src/qml/jsruntime/qv4argumentsobject_p.h index 786cb36d0a..73c6bb26f3 100644 --- a/src/qml/jsruntime/qv4argumentsobject_p.h +++ b/src/qml/jsruntime/qv4argumentsobject_p.h @@ -106,7 +106,7 @@ struct ArgumentsObject: Object { static void putIndexed(Managed *m, uint index, const ValueRef value); static bool deleteIndexedProperty(Managed *m, uint index); static PropertyAttributes queryIndexed(const Managed *m, uint index); - static void markObjects(Managed *that, ExecutionEngine *e); + static void markObjects(HeapObject *that, ExecutionEngine *e); void fullyCreate(); }; diff --git a/src/qml/jsruntime/qv4arraybuffer.cpp b/src/qml/jsruntime/qv4arraybuffer.cpp new file mode 100644 index 0000000000..82ab2a2a87 --- /dev/null +++ b/src/qml/jsruntime/qv4arraybuffer.cpp @@ -0,0 +1,166 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the QtQml module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL21$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 or version 3 as published by the Free +** Software Foundation and appearing in the file LICENSE.LGPLv21 and +** LICENSE.LGPLv3 included in the packaging of this file. Please review the +** following information to ensure the GNU Lesser General Public License +** requirements will be met: https://www.gnu.org/licenses/lgpl.html and +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ +#include "qv4arraybuffer_p.h" +#include "qv4typedarray_p.h" +#include "qv4dataview_p.h" + +using namespace QV4; + +DEFINE_OBJECT_VTABLE(ArrayBufferCtor); +DEFINE_OBJECT_VTABLE(ArrayBuffer); + +ArrayBufferCtor::Data::Data(ExecutionContext *scope) + : FunctionObject::Data(scope, QStringLiteral("ArrayBuffer")) +{ + setVTable(staticVTable()); +} + +ReturnedValue ArrayBufferCtor::construct(Managed *m, CallData *callData) +{ + ExecutionEngine *v4 = m->engine(); + + Scope scope(v4); + ScopedValue l(scope, callData->argument(0)); + double dl = l->toInteger(); + if (v4->hasException) + return Encode::undefined(); + uint len = (uint)qBound(0., dl, (double)UINT_MAX); + if (len != dl) + return v4->throwRangeError(QLatin1String("ArrayBuffer constructor: invalid length")); + + Scoped<ArrayBuffer> a(scope, v4->memoryManager->alloc<ArrayBuffer>(v4, len)); + if (scope.engine->hasException) + return Encode::undefined(); + return a.asReturnedValue(); +} + + +ReturnedValue ArrayBufferCtor::call(Managed *that, CallData *callData) +{ + return construct(that, callData); +} + +ReturnedValue ArrayBufferCtor::method_isView(CallContext *ctx) +{ + QV4::Scope scope(ctx); + QV4::Scoped<TypedArray> a(scope, ctx->argument(0)); + if (!!a) + return Encode(true); + QV4::Scoped<DataView> v(scope, ctx->argument(0)); + if (!!v) + return Encode(true); + return Encode(true); +} + + +ArrayBuffer::Data::Data(ExecutionEngine *e, int length) + : Object::Data(e->arrayBufferClass) +{ + data = QTypedArrayData<char>::allocate(length + 1); + if (!data) { + data = 0; + e->throwRangeError(QStringLiteral("ArrayBuffer: out of memory")); + return; + } + data->size = length; + memset(data->data(), 0, length + 1); +} + +QByteArray ArrayBuffer::asByteArray() const +{ + QByteArrayDataPtr ba = { d()->data }; + ba.ptr->ref.ref(); + return QByteArray(ba); +} + +void ArrayBuffer::destroy(Managed *m) +{ + ArrayBuffer *b = static_cast<ArrayBuffer *>(m); + if (!b->d()->data->ref.deref()) + QTypedArrayData<char>::deallocate(b->d()->data); +} + + +void ArrayBufferPrototype::init(ExecutionEngine *engine, Object *ctor) +{ + Scope scope(engine); + ScopedObject o(scope); + ctor->defineReadonlyProperty(engine->id_length, Primitive::fromInt32(1)); + ctor->defineReadonlyProperty(engine->id_prototype, (o = this)); + ctor->defineDefaultProperty(QStringLiteral("isView"), ArrayBufferCtor::method_isView, 1); + defineDefaultProperty(engine->id_constructor, (o = ctor)); + defineAccessorProperty(QStringLiteral("byteLength"), method_get_byteLength, 0); + defineDefaultProperty(QStringLiteral("slice"), method_slice, 2); +} + +ReturnedValue ArrayBufferPrototype::method_get_byteLength(CallContext *ctx) +{ + Scope scope(ctx); + Scoped<ArrayBuffer> v(scope, ctx->d()->callData->thisObject); + if (!v) + return scope.engine->throwTypeError(); + + return Encode(v->d()->data->size); +} + +ReturnedValue ArrayBufferPrototype::method_slice(CallContext *ctx) +{ + Scope scope(ctx); + Scoped<ArrayBuffer> a(scope, ctx->d()->callData->thisObject); + if (!a) + return scope.engine->throwTypeError(); + + double start = ctx->d()->callData->argc > 0 ? ctx->d()->callData->args[0].toInteger() : 0; + double end = (ctx->d()->callData->argc < 2 || ctx->d()->callData->args[1].isUndefined()) ? + a->d()->data->size : ctx->d()->callData->args[1].toInteger(); + if (scope.engine->hasException) + return Encode::undefined(); + + double first = (start < 0) ? qMax(a->d()->data->size + start, 0.) : qMin(start, (double)a->d()->data->size); + double final = (end < 0) ? qMax(a->d()->data->size + end, 0.) : qMin(end, (double)a->d()->data->size); + + Scoped<FunctionObject> constructor(scope, a->get(scope.engine->id_constructor)); + if (!constructor) + return scope.engine->throwTypeError(); + + ScopedCallData callData(scope, 1); + double newLen = qMax(final - first, 0.); + callData->args[0] = QV4::Encode(newLen); + QV4::Scoped<ArrayBuffer> newBuffer(scope, constructor->construct(callData)); + if (!newBuffer || newBuffer->d()->data->size < (int)newLen) + return scope.engine->throwTypeError(); + + memcpy(newBuffer->d()->data->data(), a->d()->data->data() + (uint)first, newLen); + + return newBuffer.asReturnedValue(); +} diff --git a/src/qml/qml/v8/qv8debug_p.h b/src/qml/jsruntime/qv4arraybuffer_p.h index 75342aa070..57ee34e570 100644 --- a/src/qml/qml/v8/qv8debug_p.h +++ b/src/qml/jsruntime/qv4arraybuffer_p.h @@ -30,5 +30,64 @@ ** $QT_END_LICENSE$ ** ****************************************************************************/ +#ifndef QV4ARRAYBUFFER_H +#define QV4ARRAYBUFFER_H -//#include <private/v8-debug.h> +#include "qv4object_p.h" +#include "qv4functionobject_p.h" + +QT_BEGIN_NAMESPACE + +namespace QV4 { + +struct ArrayBufferCtor: FunctionObject +{ + struct Data : FunctionObject::Data { + Data(ExecutionContext *scope); + }; + + V4_OBJECT(FunctionObject) + + static ReturnedValue construct(Managed *m, CallData *callData); + static ReturnedValue call(Managed *that, CallData *callData); + + static ReturnedValue method_isView(CallContext *ctx); + +}; + +struct ArrayBuffer : Object +{ + struct Data : Object::Data { + Data(ExecutionEngine *e, int length); + QTypedArrayData<char> *data; + }; + V4_OBJECT(Object) + + QByteArray asByteArray() const; + uint byteLength() const { return d()->data->size; } + char *data() { + // ### detach if refcount > 1 + return d()->data->data(); + } + const char *constData() { + // ### detach if refcount > 1 + return d()->data->data(); + } + + static void destroy(Managed *m); +}; + +struct ArrayBufferPrototype: Object +{ + void init(ExecutionEngine *engine, Object *ctor); + + static ReturnedValue method_get_byteLength(CallContext *ctx); + static ReturnedValue method_slice(CallContext *ctx); +}; + + +} // namespace QV4 + +QT_END_NAMESPACE + +#endif diff --git a/src/qml/jsruntime/qv4arraydata.cpp b/src/qml/jsruntime/qv4arraydata.cpp index 35bd6e5501..5aaed1a98d 100644 --- a/src/qml/jsruntime/qv4arraydata.cpp +++ b/src/qml/jsruntime/qv4arraydata.cpp @@ -34,6 +34,7 @@ #include "qv4object_p.h" #include "qv4functionobject_p.h" #include "qv4mm_p.h" +#include "qv4runtime_p.h" using namespace QV4; @@ -212,12 +213,12 @@ void ArrayData::ensureAttributes(Object *o) } -void SimpleArrayData::markObjects(Managed *d, ExecutionEngine *e) +void SimpleArrayData::markObjects(HeapObject *d, ExecutionEngine *e) { - SimpleArrayData *dd = static_cast<SimpleArrayData *>(d); - uint l = dd->len(); + SimpleArrayData::Data *dd = static_cast<SimpleArrayData::Data *>(d); + uint l = dd->len; for (uint i = 0; i < l; ++i) - dd->data(i).mark(e); + dd->arrayData[i].mark(e); } ReturnedValue SimpleArrayData::get(const ArrayData *d, uint index) @@ -362,12 +363,12 @@ void SparseArrayData::destroy(Managed *d) delete dd->sparse(); } -void SparseArrayData::markObjects(Managed *d, ExecutionEngine *e) +void SparseArrayData::markObjects(HeapObject *d, ExecutionEngine *e) { - SparseArrayData *dd = static_cast<SparseArrayData *>(d); - uint l = dd->alloc(); + SparseArrayData::Data *dd = static_cast<SparseArrayData::Data *>(d); + uint l = dd->alloc; for (uint i = 0; i < l; ++i) - dd->arrayData()[i].mark(e); + dd->arrayData[i].mark(e); } ArrayData *SparseArrayData::reallocate(Object *o, uint n, bool enforceAttributes) @@ -746,7 +747,7 @@ void ArrayData::sort(ExecutionContext *context, Object *thisObject, const ValueR return; if (!(comparefn->isUndefined() || comparefn->asObject())) { - context->throwTypeError(); + context->engine()->throwTypeError(); return; } diff --git a/src/qml/jsruntime/qv4arraydata_p.h b/src/qml/jsruntime/qv4arraydata_p.h index b69d200665..5286be875b 100644 --- a/src/qml/jsruntime/qv4arraydata_p.h +++ b/src/qml/jsruntime/qv4arraydata_p.h @@ -172,7 +172,7 @@ struct Q_QML_EXPORT SimpleArrayData : public ArrayData static ArrayData *reallocate(Object *o, uint n, bool enforceAttributes); - static void markObjects(Managed *d, ExecutionEngine *e); + static void markObjects(HeapObject *d, ExecutionEngine *e); static ReturnedValue get(const ArrayData *d, uint index); static bool put(Object *o, uint index, ValueRef value); @@ -218,7 +218,7 @@ struct Q_QML_EXPORT SparseArrayData : public ArrayData } static void destroy(Managed *d); - static void markObjects(Managed *d, ExecutionEngine *e); + static void markObjects(HeapObject *d, ExecutionEngine *e); static ArrayData *reallocate(Object *o, uint n, bool enforceAttributes); static ReturnedValue get(const ArrayData *d, uint index); diff --git a/src/qml/jsruntime/qv4arrayobject.cpp b/src/qml/jsruntime/qv4arrayobject.cpp index 011279ae07..bbc0867c22 100644 --- a/src/qml/jsruntime/qv4arrayobject.cpp +++ b/src/qml/jsruntime/qv4arrayobject.cpp @@ -35,6 +35,7 @@ #include "qv4sparsearray_p.h" #include "qv4objectproto_p.h" #include "qv4scopedvalue_p.h" +#include "qv4runtime_p.h" using namespace QV4; @@ -57,7 +58,7 @@ ReturnedValue ArrayCtor::construct(Managed *m, CallData *callData) len = callData->args[0].asArrayLength(&ok); if (!ok) - return v4->currentContext()->throwRangeError(callData->args[0]); + return v4->throwRangeError(callData->args[0]); if (len < 0x1000) a->arrayReserve(len); @@ -285,7 +286,7 @@ ReturnedValue ArrayPrototype::method_push(CallContext *ctx) instance->put(ctx->d()->engine->id_length, ScopedValue(scope, Primitive::fromDouble(newLen))); else { ScopedString str(scope, ctx->d()->engine->newString(QStringLiteral("Array.prototype.push: Overflow"))); - return ctx->throwRangeError(str); + return ctx->engine()->throwRangeError(str); } return Encode(newLen); } @@ -690,7 +691,7 @@ ReturnedValue ArrayPrototype::method_every(CallContext *ctx) Scoped<FunctionObject> callback(scope, ctx->argument(0)); if (!callback) - return ctx->throwTypeError(); + return ctx->engine()->throwTypeError(); ScopedCallData callData(scope, 3); callData->args[2] = instance; @@ -724,7 +725,7 @@ ReturnedValue ArrayPrototype::method_some(CallContext *ctx) Scoped<FunctionObject> callback(scope, ctx->argument(0)); if (!callback) - return ctx->throwTypeError(); + return ctx->engine()->throwTypeError(); ScopedCallData callData(scope, 3); callData->thisObject = ctx->argument(1); @@ -758,7 +759,7 @@ ReturnedValue ArrayPrototype::method_forEach(CallContext *ctx) Scoped<FunctionObject> callback(scope, ctx->argument(0)); if (!callback) - return ctx->throwTypeError(); + return ctx->engine()->throwTypeError(); ScopedCallData callData(scope, 3); callData->thisObject = ctx->argument(1); @@ -789,7 +790,7 @@ ReturnedValue ArrayPrototype::method_map(CallContext *ctx) Scoped<FunctionObject> callback(scope, ctx->argument(0)); if (!callback) - return ctx->throwTypeError(); + return ctx->engine()->throwTypeError(); Scoped<ArrayObject> a(scope, ctx->d()->engine->newArrayObject()); a->arrayReserve(len); @@ -826,7 +827,7 @@ ReturnedValue ArrayPrototype::method_filter(CallContext *ctx) Scoped<FunctionObject> callback(scope, ctx->argument(0)); if (!callback) - return ctx->throwTypeError(); + return ctx->engine()->throwTypeError(); Scoped<ArrayObject> a(scope, ctx->d()->engine->newArrayObject()); a->arrayReserve(len); @@ -867,7 +868,7 @@ ReturnedValue ArrayPrototype::method_reduce(CallContext *ctx) Scoped<FunctionObject> callback(scope, ctx->argument(0)); if (!callback) - return ctx->throwTypeError(); + return ctx->engine()->throwTypeError(); uint k = 0; ScopedValue acc(scope); @@ -884,7 +885,7 @@ ReturnedValue ArrayPrototype::method_reduce(CallContext *ctx) ++k; } if (!kPresent) - return ctx->throwTypeError(); + return ctx->engine()->throwTypeError(); } ScopedCallData callData(scope, 4); @@ -917,11 +918,11 @@ ReturnedValue ArrayPrototype::method_reduceRight(CallContext *ctx) Scoped<FunctionObject> callback(scope, ctx->argument(0)); if (!callback) - return ctx->throwTypeError(); + return ctx->engine()->throwTypeError(); if (len == 0) { if (ctx->d()->callData->argc == 1) - return ctx->throwTypeError(); + return ctx->engine()->throwTypeError(); return ctx->argument(1); } @@ -939,7 +940,7 @@ ReturnedValue ArrayPrototype::method_reduceRight(CallContext *ctx) --k; } if (!kPresent) - return ctx->throwTypeError(); + return ctx->engine()->throwTypeError(); } ScopedCallData callData(scope, 4); diff --git a/src/qml/jsruntime/qv4booleanobject.cpp b/src/qml/jsruntime/qv4booleanobject.cpp index b58fcbe709..17f638426a 100644 --- a/src/qml/jsruntime/qv4booleanobject.cpp +++ b/src/qml/jsruntime/qv4booleanobject.cpp @@ -78,7 +78,7 @@ ReturnedValue BooleanPrototype::method_toString(CallContext *ctx) Scope scope(ctx); Scoped<BooleanObject> thisObject(scope, ctx->d()->callData->thisObject); if (!thisObject) - return ctx->throwTypeError(); + return ctx->engine()->throwTypeError(); result = thisObject->value().booleanValue(); } @@ -93,7 +93,7 @@ ReturnedValue BooleanPrototype::method_valueOf(CallContext *ctx) Scope scope(ctx); Scoped<BooleanObject> thisObject(scope, ctx->d()->callData->thisObject); if (!thisObject) - return ctx->throwTypeError(); + return ctx->engine()->throwTypeError(); return thisObject->value().asReturnedValue(); } diff --git a/src/qml/jsruntime/qv4context.cpp b/src/qml/jsruntime/qv4context.cpp index 5ca47a80b1..2dc8e8b608 100644 --- a/src/qml/jsruntime/qv4context.cpp +++ b/src/qml/jsruntime/qv4context.cpp @@ -48,7 +48,7 @@ DEFINE_MANAGED_VTABLE(CallContext); DEFINE_MANAGED_VTABLE(WithContext); DEFINE_MANAGED_VTABLE(GlobalContext); -HeapObject *ExecutionContext::newCallContext(FunctionObject *function, CallData *callData) +Returned<CallContext> *ExecutionContext::newCallContext(FunctionObject *function, CallData *callData) { Q_ASSERT(function->function()); @@ -78,24 +78,25 @@ HeapObject *ExecutionContext::newCallContext(FunctionObject *function, CallData std::fill(c->callData->args + c->callData->argc, c->callData->args + compiledFunction->nFormals, Primitive::undefinedValue()); c->callData->argc = qMax((uint)callData->argc, compiledFunction->nFormals); - return c; + return Returned<CallContext>::create(c); } -WithContext *ExecutionContext::newWithContext(Object *with) +Returned<WithContext> *ExecutionContext::newWithContext(Object *with) { return d()->engine->memoryManager->alloc<WithContext>(d()->engine, with); } -CatchContext *ExecutionContext::newCatchContext(String *exceptionVarName, const ValueRef exceptionValue) +Returned<CatchContext> *ExecutionContext::newCatchContext(String *exceptionVarName, const ValueRef exceptionValue) { return d()->engine->memoryManager->alloc<CatchContext>(d()->engine, exceptionVarName, exceptionValue); } -CallContext *ExecutionContext::newQmlContext(FunctionObject *f, Object *qml) +Returned<CallContext> *ExecutionContext::newQmlContext(FunctionObject *f, Object *qml) { - CallContext *c = reinterpret_cast<CallContext*>(d()->engine->memoryManager->allocManaged(requiredMemoryForExecutionContect(f, 0))); + Scope scope(this); + Scoped<CallContext> c(scope, static_cast<CallContext*>(d()->engine->memoryManager->allocManaged(requiredMemoryForExecutionContect(f, 0)))); new (c->d()) CallContext::Data(d()->engine, qml, f); - return c; + return c.asReturned(); } @@ -236,7 +237,7 @@ bool ExecutionContext::deleteProperty(String *name) } if (d()->strictMode) - throwSyntaxError(QStringLiteral("Can't delete property %1").arg(name->toQString())); + engine()->throwSyntaxError(QStringLiteral("Can't delete property %1").arg(name->toQString())); return true; } @@ -245,35 +246,35 @@ bool CallContext::needsOwnArguments() const return d()->function->needsActivation() || d()->callData->argc < static_cast<int>(d()->function->formalParameterCount()); } -void ExecutionContext::markObjects(Managed *m, ExecutionEngine *engine) +void ExecutionContext::markObjects(HeapObject *m, ExecutionEngine *engine) { - ExecutionContext *ctx = static_cast<ExecutionContext *>(m); + ExecutionContext::Data *ctx = static_cast<ExecutionContext::Data *>(m); - if (ctx->d()->outer) - ctx->d()->outer->mark(engine); + if (ctx->outer) + ctx->outer->mark(engine); // ### shouldn't need these 3 lines - ctx->d()->callData->thisObject.mark(engine); - for (int arg = 0; arg < ctx->d()->callData->argc; ++arg) - ctx->d()->callData->args[arg].mark(engine); - - if (ctx->d()->type >= Type_CallContext) { - QV4::CallContext *c = static_cast<CallContext *>(ctx); - for (unsigned local = 0, lastLocal = c->d()->function->varCount(); local < lastLocal; ++local) - c->d()->locals[local].mark(engine); - if (c->d()->activation) - c->d()->activation->mark(engine); - c->d()->function->mark(engine); - } else if (ctx->d()->type == Type_WithContext) { - WithContext *w = static_cast<WithContext *>(ctx); - w->d()->withObject->mark(engine); - } else if (ctx->d()->type == Type_CatchContext) { - CatchContext *c = static_cast<CatchContext *>(ctx); - c->d()->exceptionVarName->mark(engine); - c->d()->exceptionValue.mark(engine); - } else if (ctx->d()->type == Type_GlobalContext) { - GlobalContext *g = static_cast<GlobalContext *>(ctx); - g->d()->global->mark(engine); + ctx->callData->thisObject.mark(engine); + for (int arg = 0; arg < ctx->callData->argc; ++arg) + ctx->callData->args[arg].mark(engine); + + if (ctx->type >= Type_CallContext) { + QV4::CallContext::Data *c = static_cast<CallContext::Data *>(ctx); + for (unsigned local = 0, lastLocal = c->function->varCount(); local < lastLocal; ++local) + c->locals[local].mark(engine); + if (c->activation) + c->activation->mark(engine); + c->function->mark(engine); + } else if (ctx->type == Type_WithContext) { + WithContext::Data *w = static_cast<WithContext::Data *>(ctx); + w->withObject->mark(engine); + } else if (ctx->type == Type_CatchContext) { + CatchContext::Data *c = static_cast<CatchContext::Data *>(ctx); + c->exceptionVarName->mark(engine); + c->exceptionValue.mark(engine); + } else if (ctx->type == Type_GlobalContext) { + GlobalContext::Data *g = static_cast<GlobalContext::Data *>(ctx); + g->global->mark(engine); } } @@ -327,7 +328,7 @@ void ExecutionContext::setProperty(String *name, const ValueRef value) } if (d()->strictMode || name->equals(d()->engine->id_this.getPointer())) { ScopedValue n(scope, name->asReturnedValue()); - throwReferenceError(n); + engine()->throwReferenceError(n); return; } d()->engine->globalObject->put(name, value); @@ -394,7 +395,7 @@ ReturnedValue ExecutionContext::getProperty(String *name) } } ScopedValue n(scope, name); - return throwReferenceError(n); + return engine()->throwReferenceError(n); } ReturnedValue ExecutionContext::getPropertyAndBase(String *name, Object *&base) @@ -463,100 +464,10 @@ ReturnedValue ExecutionContext::getPropertyAndBase(String *name, Object *&base) } } ScopedValue n(scope, name); - return throwReferenceError(n); -} - - -ReturnedValue ExecutionContext::throwError(const ValueRef value) -{ - return d()->engine->throwException(value); -} - -ReturnedValue ExecutionContext::throwError(const QString &message) -{ - Scope scope(this); - ScopedValue v(scope, d()->engine->newString(message)); - v = d()->engine->newErrorObject(v); - return throwError(v); -} - -ReturnedValue ExecutionContext::throwSyntaxError(const QString &message, const QString &fileName, int line, int column) -{ - Scope scope(this); - Scoped<Object> error(scope, d()->engine->newSyntaxErrorObject(message, fileName, line, column)); - return throwError(error); -} - -ReturnedValue ExecutionContext::throwSyntaxError(const QString &message) -{ - Scope scope(this); - Scoped<Object> error(scope, d()->engine->newSyntaxErrorObject(message)); - return throwError(error); -} - -ReturnedValue ExecutionContext::throwTypeError() -{ - Scope scope(this); - Scoped<Object> error(scope, d()->engine->newTypeErrorObject(QStringLiteral("Type error"))); - return throwError(error); -} - -ReturnedValue ExecutionContext::throwTypeError(const QString &message) -{ - Scope scope(this); - Scoped<Object> error(scope, d()->engine->newTypeErrorObject(message)); - return throwError(error); -} - -ReturnedValue ExecutionContext::throwUnimplemented(const QString &message) -{ - Scope scope(this); - ScopedValue v(scope, d()->engine->newString(QStringLiteral("Unimplemented ") + message)); - v = d()->engine->newErrorObject(v); - return throwError(v); + return engine()->throwReferenceError(n); } ReturnedValue ExecutionContext::catchException(StackTrace *trace) { return d()->engine->catchException(this, trace); } - -ReturnedValue ExecutionContext::throwReferenceError(const ValueRef value) -{ - Scope scope(this); - Scoped<String> s(scope, value->toString(this)); - QString msg = s->toQString() + QStringLiteral(" is not defined"); - Scoped<Object> error(scope, d()->engine->newReferenceErrorObject(msg)); - return throwError(error); -} - -ReturnedValue ExecutionContext::throwReferenceError(const QString &message, const QString &fileName, int line, int column) -{ - Scope scope(this); - QString msg = message; - Scoped<Object> error(scope, d()->engine->newReferenceErrorObject(msg, fileName, line, column)); - return throwError(error); -} - -ReturnedValue ExecutionContext::throwRangeError(const ValueRef value) -{ - Scope scope(this); - ScopedString s(scope, value->toString(this)); - QString msg = s->toQString() + QStringLiteral(" out of range"); - ScopedObject error(scope, d()->engine->newRangeErrorObject(msg)); - return throwError(error); -} - -ReturnedValue ExecutionContext::throwRangeError(const QString &message) -{ - Scope scope(this); - ScopedObject error(scope, d()->engine->newRangeErrorObject(message)); - return throwError(error); -} - -ReturnedValue ExecutionContext::throwURIError(const ValueRef msg) -{ - Scope scope(this); - ScopedObject error(scope, d()->engine->newURIErrorObject(msg)); - return throwError(error); -} diff --git a/src/qml/jsruntime/qv4context_p.h b/src/qml/jsruntime/qv4context_p.h index 74530e7ae9..a942c12f6c 100644 --- a/src/qml/jsruntime/qv4context_p.h +++ b/src/qml/jsruntime/qv4context_p.h @@ -42,20 +42,12 @@ QT_BEGIN_NAMESPACE namespace QV4 { -struct Object; -struct ExecutionEngine; -struct DeclarativeEnvironment; -struct Lookup; -struct Function; -struct ValueRef; - namespace CompiledData { struct CompilationUnit; struct Function; } struct CallContext; -struct CallContext; struct CatchContext; struct WithContext; @@ -127,26 +119,13 @@ struct Q_QML_EXPORT ExecutionContext : public Managed engine->current = this; } - HeapObject *newCallContext(FunctionObject *f, CallData *callData); - WithContext *newWithContext(Object *with); - CatchContext *newCatchContext(String *exceptionVarName, const ValueRef exceptionValue); - CallContext *newQmlContext(FunctionObject *f, Object *qml); + Returned<CallContext> *newCallContext(FunctionObject *f, CallData *callData); + Returned<WithContext> *newWithContext(Object *with); + Returned<CatchContext> *newCatchContext(String *exceptionVarName, const ValueRef exceptionValue); + Returned<CallContext> *newQmlContext(FunctionObject *f, Object *qml); void createMutableBinding(String *name, bool deletable); - ReturnedValue throwError(const QV4::ValueRef value); - ReturnedValue throwError(const QString &message); - ReturnedValue throwSyntaxError(const QString &message); - ReturnedValue throwSyntaxError(const QString &message, const QString &fileName, int lineNumber, int column); - ReturnedValue throwTypeError(); - ReturnedValue throwTypeError(const QString &message); - ReturnedValue throwReferenceError(const ValueRef value); - ReturnedValue throwReferenceError(const QString &value, const QString &fileName, int lineNumber, int column); - ReturnedValue throwRangeError(const ValueRef value); - ReturnedValue throwRangeError(const QString &message); - ReturnedValue throwURIError(const ValueRef msg); - ReturnedValue throwUnimplemented(const QString &message); - void setProperty(String *name, const ValueRef value); ReturnedValue getProperty(String *name); ReturnedValue getPropertyAndBase(String *name, Object *&base); @@ -158,7 +137,7 @@ struct Q_QML_EXPORT ExecutionContext : public Managed inline CallContext *asCallContext(); inline const CallContext *asCallContext() const; - static void markObjects(Managed *m, ExecutionEngine *e); + static void markObjects(HeapObject *m, ExecutionEngine *e); }; struct CallContext : public ExecutionContext diff --git a/src/qml/jsruntime/qv4dataview.cpp b/src/qml/jsruntime/qv4dataview.cpp new file mode 100644 index 0000000000..11cb04e22f --- /dev/null +++ b/src/qml/jsruntime/qv4dataview.cpp @@ -0,0 +1,316 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the QtQml module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL21$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 or version 3 as published by the Free +** Software Foundation and appearing in the file LICENSE.LGPLv21 and +** LICENSE.LGPLv3 included in the packaging of this file. Please review the +** following information to ensure the GNU Lesser General Public License +** requirements will be met: https://www.gnu.org/licenses/lgpl.html and +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qv4dataview_p.h" +#include "qv4arraybuffer_p.h" + +#include "qendian.h" + +using namespace QV4; + +DEFINE_OBJECT_VTABLE(DataViewCtor); +DEFINE_OBJECT_VTABLE(DataView); + +DataViewCtor::Data::Data(ExecutionContext *scope) + : FunctionObject::Data(scope, QStringLiteral("DataView")) +{ + setVTable(staticVTable()); +} + +ReturnedValue DataViewCtor::construct(Managed *m, CallData *callData) +{ + Scope scope(m->engine()); + Scoped<ArrayBuffer> buffer(scope, callData->argument(0)); + if (!buffer) + return scope.engine->throwTypeError(); + + double bo = callData->argc > 1 ? callData->args[1].toNumber() : 0; + uint byteOffset = (uint)bo; + uint bufferLength = buffer->d()->data->size; + double bl = callData->argc < 3 || callData->args[2].isUndefined() ? (bufferLength - bo) : callData->args[2].toNumber(); + uint byteLength = (uint)bl; + if (bo != byteOffset || bl != byteLength || byteOffset + byteLength > bufferLength) + return scope.engine->throwRangeError(QStringLiteral("DataView: constructor arguments out of range")); + + Scoped<DataView> a(scope, scope.engine->memoryManager->alloc<DataView>(scope.engine)); + a->d()->buffer = buffer; + a->d()->byteLength = byteLength; + a->d()->byteOffset = byteOffset; + return a.asReturnedValue(); + +} + +ReturnedValue DataViewCtor::call(Managed *that, CallData *callData) +{ + return construct(that, callData); +} + + +DataView::Data::Data(ExecutionEngine *e) + : Object::Data(e->dataViewClass), + buffer(0), + byteLength(0), + byteOffset(0) +{ +} + + +void DataView::markObjects(HeapObject *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); + ScopedObject o(scope); + ctor->defineReadonlyProperty(engine->id_length, Primitive::fromInt32(3)); + ctor->defineReadonlyProperty(engine->id_prototype, (o = this)); + defineDefaultProperty(engine->id_constructor, (o = ctor)); + defineAccessorProperty(QStringLiteral("buffer"), method_get_buffer, 0); + defineAccessorProperty(QStringLiteral("byteLength"), method_get_byteLength, 0); + defineAccessorProperty(QStringLiteral("byteOffset"), method_get_byteOffset, 0); + + defineDefaultProperty(QStringLiteral("getInt8"), method_getChar<signed char>, 0); + defineDefaultProperty(QStringLiteral("getUInt8"), method_getChar<unsigned char>, 0); + defineDefaultProperty(QStringLiteral("getInt16"), method_get<short>, 0); + defineDefaultProperty(QStringLiteral("getUInt16"), method_get<unsigned short>, 0); + defineDefaultProperty(QStringLiteral("getInt32"), method_get<int>, 0); + defineDefaultProperty(QStringLiteral("getUInt32"), method_get<unsigned int>, 0); + defineDefaultProperty(QStringLiteral("getFloat32"), method_getFloat<float>, 0); + defineDefaultProperty(QStringLiteral("getFloat64"), method_getFloat<double>, 0); + + defineDefaultProperty(QStringLiteral("setInt8"), method_setChar<signed char>, 0); + defineDefaultProperty(QStringLiteral("setUInt8"), method_setChar<unsigned char>, 0); + defineDefaultProperty(QStringLiteral("setInt16"), method_set<short>, 0); + defineDefaultProperty(QStringLiteral("setUInt16"), method_set<unsigned short>, 0); + defineDefaultProperty(QStringLiteral("setInt32"), method_set<int>, 0); + defineDefaultProperty(QStringLiteral("setUInt32"), method_set<unsigned int>, 0); + defineDefaultProperty(QStringLiteral("setFloat32"), method_setFloat<float>, 0); + defineDefaultProperty(QStringLiteral("setFloat64"), method_setFloat<double>, 0); +} + +ReturnedValue DataViewPrototype::method_get_buffer(CallContext *ctx) +{ + Scope scope(ctx); + Scoped<DataView> v(scope, ctx->d()->callData->thisObject); + if (!v) + return scope.engine->throwTypeError(); + + return Encode(v->d()->buffer->asReturnedValue()); +} + +ReturnedValue DataViewPrototype::method_get_byteLength(CallContext *ctx) +{ + Scope scope(ctx); + Scoped<DataView> v(scope, ctx->d()->callData->thisObject); + if (!v) + return scope.engine->throwTypeError(); + + return Encode(v->d()->byteLength); +} + +ReturnedValue DataViewPrototype::method_get_byteOffset(CallContext *ctx) +{ + Scope scope(ctx); + Scoped<DataView> v(scope, ctx->d()->callData->thisObject); + if (!v) + return scope.engine->throwTypeError(); + + return Encode(v->d()->byteOffset); +} + +template <typename T> +ReturnedValue DataViewPrototype::method_getChar(CallContext *ctx) +{ + Scope scope(ctx); + Scoped<DataView> v(scope, ctx->d()->callData->thisObject); + if (!v || ctx->d()->callData->argc < 1) + return scope.engine->throwTypeError(); + double l = ctx->d()->callData->args[0].toNumber(); + uint idx = (uint)l; + if (l != idx || idx + sizeof(T) > v->d()->byteLength) + return scope.engine->throwTypeError(); + idx += v->d()->byteOffset; + + T t = T(v->d()->buffer->d()->data->data()[idx]); + + return Encode((int)t); +} + +template <typename T> +ReturnedValue DataViewPrototype::method_get(CallContext *ctx) +{ + Scope scope(ctx); + Scoped<DataView> v(scope, ctx->d()->callData->thisObject); + if (!v || ctx->d()->callData->argc < 1) + return scope.engine->throwTypeError(); + double l = ctx->d()->callData->args[0].toNumber(); + uint idx = (uint)l; + if (l != idx || idx + sizeof(T) > v->d()->byteLength) + return scope.engine->throwTypeError(); + idx += v->d()->byteOffset; + + bool littleEndian = ctx->d()->callData->argc < 2 ? false : ctx->d()->callData->args[1].toBoolean(); + + T t = littleEndian + ? qFromLittleEndian<T>((uchar *)v->d()->buffer->d()->data->data() + idx) + : qFromBigEndian<T>((uchar *)v->d()->buffer->d()->data->data() + idx); + + return Encode(t); +} + +template <typename T> +ReturnedValue DataViewPrototype::method_getFloat(CallContext *ctx) +{ + Scope scope(ctx); + Scoped<DataView> v(scope, ctx->d()->callData->thisObject); + if (!v || ctx->d()->callData->argc < 1) + return scope.engine->throwTypeError(); + double l = ctx->d()->callData->args[0].toNumber(); + uint idx = (uint)l; + if (l != idx || idx + sizeof(T) > v->d()->byteLength) + return scope.engine->throwTypeError(); + idx += v->d()->byteOffset; + + bool littleEndian = ctx->d()->callData->argc < 2 ? false : ctx->d()->callData->args[1].toBoolean(); + + if (sizeof(T) == 4) { + // float + union { + uint i; + float f; + } u; + u.i = littleEndian + ? qFromLittleEndian<uint>((uchar *)v->d()->buffer->d()->data->data() + idx) + : qFromBigEndian<uint>((uchar *)v->d()->buffer->d()->data->data() + idx); + return Encode(u.f); + } else { + Q_ASSERT(sizeof(T) == 8); + union { + quint64 i; + double d; + } u; + u.i = littleEndian + ? qFromLittleEndian<quint64>((uchar *)v->d()->buffer->d()->data->data() + idx) + : qFromBigEndian<quint64>((uchar *)v->d()->buffer->d()->data->data() + idx); + return Encode(u.d); + } +} + +template <typename T> +ReturnedValue DataViewPrototype::method_setChar(CallContext *ctx) +{ + Scope scope(ctx); + Scoped<DataView> v(scope, ctx->d()->callData->thisObject); + if (!v || ctx->d()->callData->argc < 1) + return scope.engine->throwTypeError(); + double l = ctx->d()->callData->args[0].toNumber(); + uint idx = (uint)l; + if (l != idx || idx + sizeof(T) > v->d()->byteLength) + return scope.engine->throwTypeError(); + idx += v->d()->byteOffset; + + int val = ctx->d()->callData->argc >= 2 ? ctx->d()->callData->args[1].toInt32() : 0; + v->d()->buffer->d()->data->data()[idx] = (char)val; + + return Encode::undefined(); +} + +template <typename T> +ReturnedValue DataViewPrototype::method_set(CallContext *ctx) +{ + Scope scope(ctx); + Scoped<DataView> v(scope, ctx->d()->callData->thisObject); + if (!v || ctx->d()->callData->argc < 1) + return scope.engine->throwTypeError(); + double l = ctx->d()->callData->args[0].toNumber(); + uint idx = (uint)l; + if (l != idx || idx + sizeof(T) > v->d()->byteLength) + return scope.engine->throwTypeError(); + idx += v->d()->byteOffset; + + int val = ctx->d()->callData->argc >= 2 ? ctx->d()->callData->args[1].toInt32() : 0; + + bool littleEndian = ctx->d()->callData->argc < 3 ? false : ctx->d()->callData->args[2].toBoolean(); + + if (littleEndian) + qToLittleEndian<T>(val, (uchar *)v->d()->buffer->d()->data->data() + idx); + else + qToBigEndian<T>(val, (uchar *)v->d()->buffer->d()->data->data() + idx); + + return Encode::undefined(); +} + +template <typename T> +ReturnedValue DataViewPrototype::method_setFloat(CallContext *ctx) +{ + Scope scope(ctx); + Scoped<DataView> v(scope, ctx->d()->callData->thisObject); + if (!v || ctx->d()->callData->argc < 1) + return scope.engine->throwTypeError(); + double l = ctx->d()->callData->args[0].toNumber(); + uint idx = (uint)l; + if (l != idx || idx + sizeof(T) > v->d()->byteLength) + return scope.engine->throwTypeError(); + idx += v->d()->byteOffset; + + double val = ctx->d()->callData->argc >= 2 ? ctx->d()->callData->args[1].toNumber() : qSNaN(); + bool littleEndian = ctx->d()->callData->argc < 3 ? false : ctx->d()->callData->args[2].toBoolean(); + + if (sizeof(T) == 4) { + // float + union { + uint i; + float f; + } u; + u.f = val; + if (littleEndian) + qToLittleEndian(u.i, (uchar *)v->d()->buffer->d()->data->data() + idx); + else + qToBigEndian(u.i, (uchar *)v->d()->buffer->d()->data->data() + idx); + } else { + Q_ASSERT(sizeof(T) == 8); + union { + quint64 i; + double d; + } u; + u.d = val; + if (littleEndian) + qToLittleEndian(u.i, (uchar *)v->d()->buffer->d()->data->data() + idx); + else + qToBigEndian(u.i, (uchar *)v->d()->buffer->d()->data->data() + idx); + } + return Encode::undefined(); +} diff --git a/src/qml/jsruntime/qv4dataview_p.h b/src/qml/jsruntime/qv4dataview_p.h new file mode 100644 index 0000000000..b1c2e361f4 --- /dev/null +++ b/src/qml/jsruntime/qv4dataview_p.h @@ -0,0 +1,96 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the QtQml module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL21$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 or version 3 as published by the Free +** Software Foundation and appearing in the file LICENSE.LGPLv21 and +** LICENSE.LGPLv3 included in the packaging of this file. Please review the +** following information to ensure the GNU Lesser General Public License +** requirements will be met: https://www.gnu.org/licenses/lgpl.html and +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ +#ifndef QV4DATAVIEW_H +#define QV4DATAVIEW_H + +#include "qv4object_p.h" +#include "qv4functionobject_p.h" + +QT_BEGIN_NAMESPACE + +namespace QV4 { + +struct ArrayBuffer; + +struct DataViewCtor: FunctionObject +{ + struct Data : FunctionObject::Data { + Data(ExecutionContext *scope); + }; + + V4_OBJECT(FunctionObject) + + static ReturnedValue construct(Managed *m, CallData *callData); + static ReturnedValue call(Managed *that, CallData *callData); +}; + +struct DataView : Object +{ + struct Data : Object::Data { + Data(ExecutionEngine *e); + ArrayBuffer *buffer; + uint byteLength; + uint byteOffset; + }; + V4_OBJECT(Object) + + static void markObjects(HeapObject *that, ExecutionEngine *e); +}; + +struct DataViewPrototype: Object +{ + void init(ExecutionEngine *engine, Object *ctor); + + static ReturnedValue method_get_buffer(CallContext *ctx); + static ReturnedValue method_get_byteLength(CallContext *ctx); + static ReturnedValue method_get_byteOffset(CallContext *ctx); + template <typename T> + static ReturnedValue method_getChar(CallContext *ctx); + template <typename T> + static ReturnedValue method_get(CallContext *ctx); + template <typename T> + static ReturnedValue method_getFloat(CallContext *ctx); + template <typename T> + static ReturnedValue method_setChar(CallContext *ctx); + template <typename T> + static ReturnedValue method_set(CallContext *ctx); + template <typename T> + static ReturnedValue method_setFloat(CallContext *ctx); +}; + + +} // namespace QV4 + +QT_END_NAMESPACE + +#endif diff --git a/src/qml/jsruntime/qv4dateobject.cpp b/src/qml/jsruntime/qv4dateobject.cpp index e00a705700..25727166a5 100644 --- a/src/qml/jsruntime/qv4dateobject.cpp +++ b/src/qml/jsruntime/qv4dateobject.cpp @@ -35,6 +35,8 @@ #include "qv4dateobject_p.h" #include "qv4objectproto_p.h" #include "qv4scopedvalue_p.h" +#include "qv4runtime_p.h" + #include <QtCore/qnumeric.h> #include <QtCore/qmath.h> #include <QtCore/QDateTime> @@ -762,7 +764,7 @@ double DatePrototype::getThisDate(ExecutionContext *ctx) if (DateObject *thisObject = ctx->d()->callData->thisObject.asDateObject()) return thisObject->date().asDouble(); else { - ctx->throwTypeError(); + ctx->engine()->throwTypeError(); return 0; } } @@ -998,7 +1000,7 @@ ReturnedValue DatePrototype::method_setTime(CallContext *ctx) Scope scope(ctx); Scoped<DateObject> self(scope, ctx->d()->callData->thisObject); if (!self) - return ctx->throwTypeError(); + return ctx->engine()->throwTypeError(); double t = ctx->d()->callData->argc ? ctx->d()->callData->args[0].toNumber() : qSNaN(); self->date().setDouble(TimeClip(t)); @@ -1010,7 +1012,7 @@ ReturnedValue DatePrototype::method_setMilliseconds(CallContext *ctx) Scope scope(ctx); Scoped<DateObject> self(scope, ctx->d()->callData->thisObject); if (!self) - return ctx->throwTypeError(); + return ctx->engine()->throwTypeError(); double t = LocalTime(self->date().asDouble()); double ms = ctx->d()->callData->argc ? ctx->d()->callData->args[0].toNumber() : qSNaN(); @@ -1022,7 +1024,7 @@ ReturnedValue DatePrototype::method_setUTCMilliseconds(CallContext *ctx) { DateObject *self = ctx->d()->callData->thisObject.asDateObject(); if (!self) - return ctx->throwTypeError(); + return ctx->engine()->throwTypeError(); double t = self->date().asDouble(); double ms = ctx->d()->callData->argc ? ctx->d()->callData->args[0].toNumber() : qSNaN(); @@ -1034,7 +1036,7 @@ ReturnedValue DatePrototype::method_setSeconds(CallContext *ctx) { DateObject *self = ctx->d()->callData->thisObject.asDateObject(); if (!self) - return ctx->throwTypeError(); + return ctx->engine()->throwTypeError(); double t = LocalTime(self->date().asDouble()); double sec = ctx->d()->callData->argc ? ctx->d()->callData->args[0].toNumber() : qSNaN(); @@ -1048,7 +1050,7 @@ ReturnedValue DatePrototype::method_setUTCSeconds(CallContext *ctx) { DateObject *self = ctx->d()->callData->thisObject.asDateObject(); if (!self) - return ctx->throwTypeError(); + return ctx->engine()->throwTypeError(); double t = self->date().asDouble(); double sec = ctx->d()->callData->argc ? ctx->d()->callData->args[0].toNumber() : qSNaN(); @@ -1062,7 +1064,7 @@ ReturnedValue DatePrototype::method_setMinutes(CallContext *ctx) { DateObject *self = ctx->d()->callData->thisObject.asDateObject(); if (!self) - return ctx->throwTypeError(); + return ctx->engine()->throwTypeError(); double t = LocalTime(self->date().asDouble()); double min = ctx->d()->callData->argc ? ctx->d()->callData->args[0].toNumber() : qSNaN(); @@ -1077,7 +1079,7 @@ ReturnedValue DatePrototype::method_setUTCMinutes(CallContext *ctx) { DateObject *self = ctx->d()->callData->thisObject.asDateObject(); if (!self) - return ctx->throwTypeError(); + return ctx->engine()->throwTypeError(); double t = self->date().asDouble(); double min = ctx->d()->callData->argc ? ctx->d()->callData->args[0].toNumber() : qSNaN(); @@ -1092,7 +1094,7 @@ ReturnedValue DatePrototype::method_setHours(CallContext *ctx) { DateObject *self = ctx->d()->callData->thisObject.asDateObject(); if (!self) - return ctx->throwTypeError(); + return ctx->engine()->throwTypeError(); double t = LocalTime(self->date().asDouble()); double hour = ctx->d()->callData->argc ? ctx->d()->callData->args[0].toNumber() : qSNaN(); @@ -1108,7 +1110,7 @@ ReturnedValue DatePrototype::method_setUTCHours(CallContext *ctx) { DateObject *self = ctx->d()->callData->thisObject.asDateObject(); if (!self) - return ctx->throwTypeError(); + return ctx->engine()->throwTypeError(); double t = self->date().asDouble(); double hour = ctx->d()->callData->argc ? ctx->d()->callData->args[0].toNumber() : qSNaN(); @@ -1124,7 +1126,7 @@ ReturnedValue DatePrototype::method_setDate(CallContext *ctx) { DateObject *self = ctx->d()->callData->thisObject.asDateObject(); if (!self) - return ctx->throwTypeError(); + return ctx->engine()->throwTypeError(); double t = LocalTime(self->date().asDouble()); double date = ctx->d()->callData->argc ? ctx->d()->callData->args[0].toNumber() : qSNaN(); @@ -1137,7 +1139,7 @@ ReturnedValue DatePrototype::method_setUTCDate(CallContext *ctx) { DateObject *self = ctx->d()->callData->thisObject.asDateObject(); if (!self) - return ctx->throwTypeError(); + return ctx->engine()->throwTypeError(); double t = self->date().asDouble(); double date = ctx->d()->callData->argc ? ctx->d()->callData->args[0].toNumber() : qSNaN(); @@ -1150,7 +1152,7 @@ ReturnedValue DatePrototype::method_setMonth(CallContext *ctx) { DateObject *self = ctx->d()->callData->thisObject.asDateObject(); if (!self) - return ctx->throwTypeError(); + return ctx->engine()->throwTypeError(); double t = LocalTime(self->date().asDouble()); double month = ctx->d()->callData->argc ? ctx->d()->callData->args[0].toNumber() : qSNaN(); @@ -1164,7 +1166,7 @@ ReturnedValue DatePrototype::method_setUTCMonth(CallContext *ctx) { DateObject *self = ctx->d()->callData->thisObject.asDateObject(); if (!self) - return ctx->throwTypeError(); + return ctx->engine()->throwTypeError(); double t = self->date().asDouble(); double month = ctx->d()->callData->argc ? ctx->d()->callData->args[0].toNumber() : qSNaN(); @@ -1178,7 +1180,7 @@ ReturnedValue DatePrototype::method_setYear(CallContext *ctx) { DateObject *self = ctx->d()->callData->thisObject.asDateObject(); if (!self) - return ctx->throwTypeError(); + return ctx->engine()->throwTypeError(); double t = self->date().asDouble(); if (std::isnan(t)) @@ -1204,7 +1206,7 @@ ReturnedValue DatePrototype::method_setUTCFullYear(CallContext *ctx) { DateObject *self = ctx->d()->callData->thisObject.asDateObject(); if (!self) - return ctx->throwTypeError(); + return ctx->engine()->throwTypeError(); double t = self->date().asDouble(); double year = ctx->d()->callData->argc ? ctx->d()->callData->args[0].toNumber() : qSNaN(); @@ -1219,7 +1221,7 @@ ReturnedValue DatePrototype::method_setFullYear(CallContext *ctx) { DateObject *self = ctx->d()->callData->thisObject.asDateObject(); if (!self) - return ctx->throwTypeError(); + return ctx->engine()->throwTypeError(); double t = LocalTime(self->date().asDouble()); if (std::isnan(t)) @@ -1236,7 +1238,7 @@ ReturnedValue DatePrototype::method_toUTCString(CallContext *ctx) { DateObject *self = ctx->d()->callData->thisObject.asDateObject(); if (!self) - return ctx->throwTypeError(); + return ctx->engine()->throwTypeError(); double t = self->date().asDouble(); return ctx->d()->engine->newString(ToUTCString(t))->asReturnedValue(); @@ -1259,11 +1261,11 @@ ReturnedValue DatePrototype::method_toISOString(CallContext *ctx) { DateObject *self = ctx->d()->callData->thisObject.asDateObject(); if (!self) - return ctx->throwTypeError(); + return ctx->engine()->throwTypeError(); double t = self->date().asDouble(); if (!std::isfinite(t)) - return ctx->throwRangeError(ctx->d()->callData->thisObject); + return ctx->engine()->throwRangeError(ctx->d()->callData->thisObject); QString result; int year = (int)YearFromTime(t); @@ -1307,7 +1309,7 @@ ReturnedValue DatePrototype::method_toJSON(CallContext *ctx) FunctionObject *toIso = v->asFunctionObject(); if (!toIso) - return ctx->throwTypeError(); + return ctx->engine()->throwTypeError(); ScopedCallData callData(scope, 0); callData->thisObject = ctx->d()->callData->thisObject; diff --git a/src/qml/jsruntime/qv4debugging.cpp b/src/qml/jsruntime/qv4debugging.cpp index bcf0d07719..c001b60295 100644 --- a/src/qml/jsruntime/qv4debugging.cpp +++ b/src/qml/jsruntime/qv4debugging.cpp @@ -38,6 +38,7 @@ #include "qv4instr_moth_p.h" #include "qv4runtime_p.h" #include "qv4script_p.h" +#include "qv4objectiterator_p.h" #include <iostream> #include <algorithm> diff --git a/src/qml/jsruntime/qv4engine.cpp b/src/qml/jsruntime/qv4engine.cpp index ea075f9cbd..c47420583c 100644 --- a/src/qml/jsruntime/qv4engine.cpp +++ b/src/qml/jsruntime/qv4engine.cpp @@ -61,6 +61,9 @@ #include "qv4qobjectwrapper_p.h" #include "qv4qmlextensions_p.h" #include "qv4memberdata_p.h" +#include "qv4arraybuffer_p.h" +#include "qv4dataview_p.h" +#include "qv4typedarray_p.h" #include <QtCore/QTextStream> #include <QDateTime> @@ -87,7 +90,7 @@ static QBasicAtomicInt engineSerial = Q_BASIC_ATOMIC_INITIALIZER(1); static ReturnedValue throwTypeError(CallContext *ctx) { - return ctx->throwTypeError(); + return ctx->engine()->throwTypeError(); } const int MinimumStackSize = 256; // in kbytes @@ -198,7 +201,9 @@ ExecutionEngine::ExecutionEngine(EvalISelFactory *factory) // reserve space for the JS stack // we allow it to grow to 2 times JSStackLimit, as we can overshoot due to garbage collection // and ScopedValues allocated outside of JIT'ed methods. - *jsStack = WTF::PageAllocation::allocate(2*JSStackLimit, WTF::OSAllocator::JSVMStackPages, true); + *jsStack = WTF::PageAllocation::allocate(2 * JSStackLimit, WTF::OSAllocator::JSVMStackPages, + /* writable */ true, /* executable */ false, + /* includesGuardPages */ true); jsStackBase = (Value *)jsStack->base(); jsStackTop = jsStackBase; @@ -252,6 +257,9 @@ ExecutionEngine::ExecutionEngine(EvalISelFactory *factory) id_toString = newIdentifier(QStringLiteral("toString")); id_destroy = newIdentifier(QStringLiteral("destroy")); id_valueOf = newIdentifier(QStringLiteral("valueOf")); + id_byteLength = newIdentifier(QStringLiteral("byteLength")); + id_byteOffset = newIdentifier(QStringLiteral("byteOffset")); + id_buffer = newIdentifier(QStringLiteral("buffer")); memberDataClass = InternalClass::create(this, MemberData::staticVTable(), 0); @@ -361,7 +369,27 @@ ExecutionEngine::ExecutionEngine(EvalISelFactory *factory) static_cast<URIErrorPrototype *>(uRIErrorPrototype.getPointer())->init(this, uRIErrorCtor.asObject()); static_cast<VariantPrototype *>(variantPrototype.getPointer())->init(); - static_cast<SequencePrototype *>(sequencePrototype.managed())->init(); + sequencePrototype.cast<SequencePrototype>()->init(); + + + // typed arrays + + arrayBufferCtor = memoryManager->alloc<ArrayBufferCtor>(rootContext); + Scoped<ArrayBufferPrototype> arrayBufferPrototype(scope, memoryManager->alloc<ArrayBufferPrototype>(objectClass)); + arrayBufferPrototype->init(this, arrayBufferCtor.asObject()); + arrayBufferClass = InternalClass::create(this, ArrayBuffer::staticVTable(), arrayBufferPrototype); + + dataViewCtor = memoryManager->alloc<DataViewCtor>(rootContext); + Scoped<DataViewPrototype> dataViewPrototype(scope, memoryManager->alloc<DataViewPrototype>(objectClass)); + dataViewPrototype->init(this, dataViewCtor.asObject()); + dataViewClass = InternalClass::create(this, DataView::staticVTable(), dataViewPrototype); + + for (int i = 0; i < TypedArray::NTypes; ++i) { + typedArrayCtors[i] = memoryManager->alloc<TypedArrayCtor>(rootContext, TypedArray::Type(i)); + Scoped<TypedArrayPrototype> typedArrayPrototype(scope, memoryManager->alloc<TypedArrayPrototype>(this, TypedArray::Type(i))); + typedArrayPrototype->init(this, static_cast<TypedArrayCtor *>(typedArrayCtors[i].asObject())); + typedArrayClasses[i] = InternalClass::create(this, TypedArray::staticVTable(), typedArrayPrototype); + } // // set up the global object @@ -386,6 +414,12 @@ ExecutionEngine::ExecutionEngine(EvalISelFactory *factory) globalObject->defineDefaultProperty(QStringLiteral("SyntaxError"), syntaxErrorCtor); globalObject->defineDefaultProperty(QStringLiteral("TypeError"), typeErrorCtor); globalObject->defineDefaultProperty(QStringLiteral("URIError"), uRIErrorCtor); + + globalObject->defineDefaultProperty(QStringLiteral("ArrayBuffer"), arrayBufferCtor); + globalObject->defineDefaultProperty(QStringLiteral("DataView"), dataViewCtor); + ScopedString str(scope); + for (int i = 0; i < TypedArray::NTypes; ++i) + globalObject->defineDefaultProperty((str = typedArrayCtors[i].asFunctionObject()->name())->toQString(), typedArrayCtors[i]); ScopedObject o(scope); globalObject->defineDefaultProperty(QStringLiteral("Math"), (o = memoryManager->alloc<MathObject>(QV4::InternalClass::create(this, MathObject::staticVTable(), objectPrototype)))); globalObject->defineDefaultProperty(QStringLiteral("JSON"), (o = memoryManager->alloc<JsonObject>(QV4::InternalClass::create(this, JsonObject::staticVTable(), objectPrototype)))); @@ -410,7 +444,7 @@ ExecutionEngine::ExecutionEngine(EvalISelFactory *factory) globalObject->defineDefaultProperty(QStringLiteral("unescape"), GlobalFunctions::method_unescape, 1); Scoped<String> name(scope, newString(QStringLiteral("thrower"))); - thrower = ScopedFunctionObject(scope, BuiltinFunction::create(rootContext, name.getPointer(), throwTypeError)).getPointer(); + thrower = ScopedFunctionObject(scope, BuiltinFunction::create(rootContext, name.getPointer(), ::throwTypeError)).getPointer(); } ExecutionEngine::~ExecutionEngine() @@ -474,11 +508,12 @@ InternalClass *ExecutionEngine::newClass(const InternalClass &other) ExecutionContext *ExecutionEngine::pushGlobalContext() { - GlobalContext *g = memoryManager->alloc<GlobalContext>(this); + Scope scope(this); + Scoped<GlobalContext> g(scope, memoryManager->alloc<GlobalContext>(this)); g->d()->callData = rootContext->d()->callData; - Q_ASSERT(currentContext() == g); - return g; + Q_ASSERT(currentContext() == g.getPointer()); + return g.getPointer(); } @@ -665,10 +700,10 @@ Returned<Object> *ExecutionEngine::newVariantObject(const QVariant &v) return o->asReturned<Object>(); } -Returned<Object> *ExecutionEngine::newForEachIteratorObject(ExecutionContext *ctx, Object *o) +Returned<Object> *ExecutionEngine::newForEachIteratorObject(Object *o) { Scope scope(this); - ScopedObject obj(scope, memoryManager->alloc<ForEachIteratorObject>(ctx, o)); + ScopedObject obj(scope, memoryManager->alloc<ForEachIteratorObject>(this, o)); return obj->asReturned<Object>(); } @@ -850,7 +885,7 @@ void ExecutionEngine::markObjects() Q_ASSERT(c->inUse()); if (!c->markBit()) { c->d()->markBit = 1; - c->markObjects(c, this); + c->markObjects(c->d(), this); } c = c->d()->parent; } @@ -887,6 +922,9 @@ void ExecutionEngine::markObjects() id_toString->mark(this); id_destroy->mark(this); id_valueOf->mark(this); + id_byteLength->mark(this); + id_byteOffset->mark(this); + id_buffer->mark(this); objectCtor.mark(this); stringCtor.mark(this); @@ -903,6 +941,10 @@ void ExecutionEngine::markObjects() syntaxErrorCtor.mark(this); typeErrorCtor.mark(this); uRIErrorCtor.mark(this); + arrayBufferCtor.mark(this); + dataViewCtor.mark(this); + for (int i = 0; i < TypedArray::NTypes; ++i) + typedArrayCtors[i].mark(this); sequencePrototype.mark(this); exceptionValue.mark(this); @@ -926,7 +968,7 @@ QmlExtensions *ExecutionEngine::qmlExtensions() return m_qmlExtensions; } -ReturnedValue ExecutionEngine::throwException(const ValueRef value) +ReturnedValue ExecutionEngine::throwError(const ValueRef value) { // we can get in here with an exception already set, as the runtime // doesn't check after every operation that can throw. @@ -964,6 +1006,92 @@ ReturnedValue ExecutionEngine::catchException(ExecutionContext *catchingContext, return res; } +ReturnedValue ExecutionEngine::throwError(const QString &message) +{ + Scope scope(this); + ScopedValue v(scope, newString(message)); + v = newErrorObject(v); + return throwError(v); +} + +ReturnedValue ExecutionEngine::throwSyntaxError(const QString &message, const QString &fileName, int line, int column) +{ + Scope scope(this); + Scoped<Object> error(scope, newSyntaxErrorObject(message, fileName, line, column)); + return throwError(error); +} + +ReturnedValue ExecutionEngine::throwSyntaxError(const QString &message) +{ + Scope scope(this); + Scoped<Object> error(scope, newSyntaxErrorObject(message)); + return throwError(error); +} + + +ReturnedValue ExecutionEngine::throwTypeError() +{ + Scope scope(this); + Scoped<Object> error(scope, newTypeErrorObject(QStringLiteral("Type error"))); + return throwError(error); +} + +ReturnedValue ExecutionEngine::throwTypeError(const QString &message) +{ + Scope scope(this); + Scoped<Object> error(scope, newTypeErrorObject(message)); + return throwError(error); +} + +ReturnedValue ExecutionEngine::throwReferenceError(const ValueRef value) +{ + Scope scope(this); + Scoped<String> s(scope, value->toString(this)); + QString msg = s->toQString() + QStringLiteral(" is not defined"); + Scoped<Object> error(scope, newReferenceErrorObject(msg)); + return throwError(error); +} + +ReturnedValue ExecutionEngine::throwReferenceError(const QString &message, const QString &fileName, int line, int column) +{ + Scope scope(this); + QString msg = message; + Scoped<Object> error(scope, newReferenceErrorObject(msg, fileName, line, column)); + return throwError(error); +} + +ReturnedValue ExecutionEngine::throwRangeError(const QString &message) +{ + Scope scope(this); + ScopedObject error(scope, newRangeErrorObject(message)); + return throwError(error); +} + +ReturnedValue ExecutionEngine::throwRangeError(const ValueRef value) +{ + Scope scope(this); + ScopedString s(scope, value->toString(this)); + QString msg = s->toQString() + QStringLiteral(" out of range"); + ScopedObject error(scope, newRangeErrorObject(msg)); + return throwError(error); +} + +ReturnedValue ExecutionEngine::throwURIError(const ValueRef msg) +{ + Scope scope(this); + ScopedObject error(scope, newURIErrorObject(msg)); + return throwError(error); +} + +ReturnedValue ExecutionEngine::throwUnimplemented(const QString &message) +{ + Scope scope(this); + ScopedValue v(scope, newString(QStringLiteral("Unimplemented ") + message)); + v = newErrorObject(v); + return throwError(v); +} + + QQmlError ExecutionEngine::catchExceptionAsQmlError(ExecutionContext *context) { QV4::StackTrace trace; diff --git a/src/qml/jsruntime/qv4engine_p.h b/src/qml/jsruntime/qv4engine_p.h index a4a40c2f41..1da54b1129 100644 --- a/src/qml/jsruntime/qv4engine_p.h +++ b/src/qml/jsruntime/qv4engine_p.h @@ -35,8 +35,7 @@ #include "qv4global_p.h" #include "private/qv4isel_p.h" -#include "qv4util_p.h" -#include "qv4property_p.h" +#include "qv4managed_p.h" #include <private/qintrusivelist_p.h> namespace WTF { @@ -113,7 +112,7 @@ struct ExecutionContextSaver; #define CHECK_STACK_LIMITS(v4) \ if ((v4->jsStackTop <= v4->jsStackLimit) && (reinterpret_cast<quintptr>(&v4) >= v4->cStackLimit || v4->recheckCStackLimits())) {} \ else \ - return v4->currentContext()->throwRangeError(QStringLiteral("Maximum call stack size exceeded.")) + return v4->throwRangeError(QStringLiteral("Maximum call stack size exceeded.")) struct Q_QML_EXPORT ExecutionEngine @@ -153,13 +152,13 @@ public: jsStackTop -= nValues; } - void pushForGC(Managed *m) { - *jsStackTop = Value::fromManaged(m); + void pushForGC(HeapObject *m) { + *jsStackTop = Value::fromHeapObject(m); ++jsStackTop; } - Managed *popForGC() { + HeapObject *popForGC() { --jsStackTop; - return jsStackTop->managed(); + return jsStackTop->heapObject(); } IdentifierTable *identifierTable; @@ -189,6 +188,10 @@ public: Value typeErrorCtor; Value uRIErrorCtor; Value sequencePrototype; + Value arrayBufferCtor; + Value dataViewCtor; + enum { NTypedArrayTypes = 9 }; // avoid header dependency + Value typedArrayCtors[NTypedArrayTypes]; InternalClassPool *classPool; InternalClass *emptyClass; @@ -224,6 +227,10 @@ public: InternalClass *variantClass; InternalClass *memberDataClass; + InternalClass *arrayBufferClass; + InternalClass *dataViewClass; + InternalClass *typedArrayClasses[NTypedArrayTypes]; // TypedArray::NValues, avoid including the header here + EvalFunction *evalFunction; FunctionObject *thrower; @@ -262,6 +269,9 @@ public: StringValue id_toString; StringValue id_destroy; StringValue id_valueOf; + StringValue id_byteLength; + StringValue id_byteOffset; + StringValue id_buffer; QSet<CompiledData::CompilationUnit*> compilationUnits; @@ -330,7 +340,7 @@ public: Returned<Object> *newVariantObject(const QVariant &v); - Returned<Object> *newForEachIteratorObject(ExecutionContext *ctx, Object *o); + Returned<Object> *newForEachIteratorObject(Object *o); Returned<Object> *qmlContextObject() const; @@ -354,9 +364,21 @@ public: Value exceptionValue; StackTrace exceptionStackTrace; - ReturnedValue throwException(const ValueRef value); + ReturnedValue throwError(const ValueRef value); ReturnedValue catchException(ExecutionContext *catchingContext, StackTrace *trace); + ReturnedValue throwError(const QString &message); + ReturnedValue throwSyntaxError(const QString &message); + ReturnedValue throwSyntaxError(const QString &message, const QString &fileName, int lineNumber, int column); + ReturnedValue throwTypeError(); + ReturnedValue throwTypeError(const QString &message); + ReturnedValue throwReferenceError(const ValueRef value); + ReturnedValue throwReferenceError(const QString &value, const QString &fileName, int lineNumber, int column); + ReturnedValue throwRangeError(const ValueRef value); + ReturnedValue throwRangeError(const QString &message); + ReturnedValue throwURIError(const ValueRef msg); + ReturnedValue throwUnimplemented(const QString &message); + // Use only inside catch(...) -- will re-throw if no JS exception static QQmlError catchExceptionAsQmlError(QV4::ExecutionContext *context); @@ -364,6 +386,7 @@ private: QmlExtensions *m_qmlExtensions; }; +// ### Remove me inline void Managed::mark(QV4::ExecutionEngine *engine) { @@ -371,6 +394,17 @@ void Managed::mark(QV4::ExecutionEngine *engine) if (markBit()) return; d()->markBit = 1; + engine->pushForGC(d()); +} + + +inline +void HeapObject::mark(QV4::ExecutionEngine *engine) +{ + Q_ASSERT(inUse); + if (markBit) + return; + markBit = 1; engine->pushForGC(this); } diff --git a/src/qml/jsruntime/qv4errorobject.cpp b/src/qml/jsruntime/qv4errorobject.cpp index d87083275d..ef664f2830 100644 --- a/src/qml/jsruntime/qv4errorobject.cpp +++ b/src/qml/jsruntime/qv4errorobject.cpp @@ -150,7 +150,7 @@ ReturnedValue ErrorObject::method_get_stack(CallContext *ctx) Scope scope(ctx); Scoped<ErrorObject> This(scope, ctx->d()->callData->thisObject); if (!This) - return ctx->throwTypeError(); + return ctx->engine()->throwTypeError(); if (!This->d()->stack) { QString trace; for (int i = 0; i < This->d()->stackTrace.count(); ++i) { @@ -170,11 +170,11 @@ ReturnedValue ErrorObject::method_get_stack(CallContext *ctx) return This->d()->stack->asReturnedValue(); } -void ErrorObject::markObjects(Managed *that, ExecutionEngine *e) +void ErrorObject::markObjects(HeapObject *that, ExecutionEngine *e) { - ErrorObject *This = that->asErrorObject(); - if (This->d()->stack) - This->d()->stack->mark(e); + ErrorObject::Data *This = static_cast<ErrorObject::Data *>(that); + if (This->stack) + This->stack->mark(e); Object::markObjects(that, e); } @@ -365,7 +365,7 @@ ReturnedValue ErrorPrototype::method_toString(CallContext *ctx) Object *o = ctx->d()->callData->thisObject.asObject(); if (!o) - return ctx->throwTypeError(); + return ctx->engine()->throwTypeError(); ScopedValue name(scope, o->get(ctx->d()->engine->id_name)); QString qname; diff --git a/src/qml/jsruntime/qv4errorobject_p.h b/src/qml/jsruntime/qv4errorobject_p.h index 47442ad985..ffbdafcc43 100644 --- a/src/qml/jsruntime/qv4errorobject_p.h +++ b/src/qml/jsruntime/qv4errorobject_p.h @@ -70,7 +70,7 @@ struct ErrorObject: Object { SyntaxErrorObject *asSyntaxError(); static ReturnedValue method_get_stack(CallContext *ctx); - static void markObjects(Managed *that, ExecutionEngine *e); + static void markObjects(HeapObject *that, ExecutionEngine *e); static void destroy(Managed *that) { static_cast<ErrorObject *>(that)->d()->~Data(); } }; diff --git a/src/qml/jsruntime/qv4function.cpp b/src/qml/jsruntime/qv4function.cpp index c7fe2128ce..6bc48157c0 100644 --- a/src/qml/jsruntime/qv4function.cpp +++ b/src/qml/jsruntime/qv4function.cpp @@ -58,7 +58,7 @@ Function::Function(ExecutionEngine *engine, CompiledData::CompilationUnit *unit, Scope scope(engine); ScopedString s(scope); for (int i = static_cast<int>(compiledFunction->nFormals - 1); i >= 0; --i) { - String *arg = compilationUnit->runtimeStrings[formalsIndices[i]].asString(); + String *arg = compilationUnit->runtimeStrings[formalsIndices[i]]; while (1) { InternalClass *newClass = internalClass->addMember(arg, Attr_NotConfigurable); if (newClass != internalClass) { @@ -72,7 +72,7 @@ Function::Function(ExecutionEngine *engine, CompiledData::CompilationUnit *unit, const quint32 *localsIndices = compiledFunction->localsTable(); for (quint32 i = 0; i < compiledFunction->nLocals; ++i) { - String *local = compilationUnit->runtimeStrings[localsIndices[i]].asString(); + String *local = compilationUnit->runtimeStrings[localsIndices[i]]; internalClass = internalClass->addMember(local, Attr_NotConfigurable); } } diff --git a/src/qml/jsruntime/qv4function_p.h b/src/qml/jsruntime/qv4function_p.h index 465489b83f..63bbb01e74 100644 --- a/src/qml/jsruntime/qv4function_p.h +++ b/src/qml/jsruntime/qv4function_p.h @@ -34,44 +34,12 @@ #define QV4FUNCTION_H #include "qv4global_p.h" - -#include <QtCore/QVector> -#include <QtCore/QByteArray> -#include <QtCore/qurl.h> - -#include "qv4value_p.h" #include <private/qv4compileddata_p.h> -#include <private/qv4engine_p.h> QT_BEGIN_NAMESPACE namespace QV4 { -struct String; -struct Function; -struct Object; -struct FunctionObject; -struct ExecutionContext; -struct ExecutionEngine; -class MemoryManager; - -struct ObjectPrototype; -struct StringPrototype; -struct NumberPrototype; -struct BooleanPrototype; -struct ArrayPrototype; -struct FunctionPrototype; -struct DatePrototype; -struct ErrorPrototype; -struct EvalErrorPrototype; -struct RangeErrorPrototype; -struct ReferenceErrorPrototype; -struct SyntaxErrorPrototype; -struct TypeErrorPrototype; -struct URIErrorPrototype; -struct InternalClass; -struct Lookup; - struct Q_QML_EXPORT Function { const CompiledData::Function *compiledFunction; CompiledData::CompilationUnit *compilationUnit; @@ -87,7 +55,7 @@ struct Q_QML_EXPORT Function { ~Function(); inline String *name() { - return compilationUnit->runtimeStrings[compiledFunction->nameIndex].getPointer(); + return compilationUnit->runtimeStrings[compiledFunction->nameIndex]; } inline QString sourceFile() const { return compilationUnit->fileName(); } diff --git a/src/qml/jsruntime/qv4functionobject.cpp b/src/qml/jsruntime/qv4functionobject.cpp index f3ad8ef892..deb9e62591 100644 --- a/src/qml/jsruntime/qv4functionobject.cpp +++ b/src/qml/jsruntime/qv4functionobject.cpp @@ -48,15 +48,11 @@ #include <private/qqmljsast_p.h> #include <private/qqmlcontextwrapper_p.h> #include <private/qqmlengine_p.h> -#include <qv4jsir_p.h> #include <qv4codegen_p.h> #include "private/qlocale_tools_p.h" #include <QtCore/qmath.h> #include <QtCore/QDebug> -#include <cassert> -#include <typeinfo> -#include <iostream> #include <algorithm> #include "qv4alloca_p.h" #include "qv4profiling_p.h" @@ -147,7 +143,7 @@ ReturnedValue FunctionObject::newInstance() ReturnedValue FunctionObject::construct(Managed *that, CallData *) { - that->internalClass()->engine->currentContext()->throwTypeError(); + that->internalClass()->engine->throwTypeError(); return Encode::undefined(); } @@ -156,23 +152,23 @@ ReturnedValue FunctionObject::call(Managed *, CallData *) return Encode::undefined(); } -void FunctionObject::markObjects(Managed *that, ExecutionEngine *e) +void FunctionObject::markObjects(HeapObject *that, ExecutionEngine *e) { - FunctionObject *o = static_cast<FunctionObject *>(that); - if (o->scope()) - o->scope()->mark(e); + FunctionObject::Data *o = static_cast<FunctionObject::Data *>(that); + if (o->scope) + o->scope->mark(e); Object::markObjects(that, e); } -FunctionObject *FunctionObject::createScriptFunction(ExecutionContext *scope, Function *function, bool createProto) +Returned<FunctionObject> *FunctionObject::createScriptFunction(ExecutionContext *scope, Function *function, bool createProto) { if (function->needsActivation() || function->compiledFunction->flags & CompiledData::Function::HasCatchOrWith || function->compiledFunction->nFormals > QV4::Global::ReservedArgumentCount || function->isNamedExpression()) - return scope->d()->engine->memoryManager->alloc<ScriptFunction>(scope, function); - return scope->d()->engine->memoryManager->alloc<SimpleScriptFunction>(scope, function, createProto); + return scope->d()->engine->memoryManager->alloc<ScriptFunction>(scope, function)->as<FunctionObject>(); + return scope->d()->engine->memoryManager->alloc<SimpleScriptFunction>(scope, function, createProto)->as<FunctionObject>(); } DEFINE_OBJECT_VTABLE(FunctionCtor); @@ -212,12 +208,12 @@ ReturnedValue FunctionCtor::construct(Managed *that, CallData *callData) const bool parsed = parser.parseExpression(); if (!parsed) - return v4->currentContext()->throwSyntaxError(QLatin1String("Parse error")); + return v4->throwSyntaxError(QLatin1String("Parse error")); using namespace QQmlJS::AST; FunctionExpression *fe = QQmlJS::AST::cast<FunctionExpression *>(parser.rootNode()); if (!fe) - return v4->currentContext()->throwSyntaxError(QLatin1String("Parse error")); + return v4->throwSyntaxError(QLatin1String("Parse error")); IR::Module module(v4->debugger != 0); @@ -266,7 +262,7 @@ ReturnedValue FunctionPrototype::method_toString(CallContext *ctx) { FunctionObject *fun = ctx->d()->callData->thisObject.asFunctionObject(); if (!fun) - return ctx->throwTypeError(); + return ctx->engine()->throwTypeError(); return ctx->d()->engine->newString(QStringLiteral("function() { [code] }"))->asReturnedValue(); } @@ -276,7 +272,7 @@ ReturnedValue FunctionPrototype::method_apply(CallContext *ctx) Scope scope(ctx); FunctionObject *o = ctx->d()->callData->thisObject.asFunctionObject(); if (!o) - return ctx->throwTypeError(); + return ctx->engine()->throwTypeError(); ScopedValue arg(scope, ctx->argument(1)); @@ -286,7 +282,7 @@ ReturnedValue FunctionPrototype::method_apply(CallContext *ctx) if (!arr) { len = 0; if (!arg->isNullOrUndefined()) - return ctx->throwTypeError(); + return ctx->engine()->throwTypeError(); } else { len = arr->getLength(); } @@ -318,7 +314,7 @@ ReturnedValue FunctionPrototype::method_call(CallContext *ctx) FunctionObject *o = ctx->d()->callData->thisObject.asFunctionObject(); if (!o) - return ctx->throwTypeError(); + return ctx->engine()->throwTypeError(); ScopedCallData callData(scope, ctx->d()->callData->argc ? ctx->d()->callData->argc - 1 : 0); if (ctx->d()->callData->argc) { @@ -334,7 +330,7 @@ ReturnedValue FunctionPrototype::method_bind(CallContext *ctx) Scope scope(ctx); Scoped<FunctionObject> target(scope, ctx->d()->callData->thisObject); if (!target) - return ctx->throwTypeError(); + return ctx->engine()->throwTypeError(); ScopedValue boundThis(scope, ctx->argument(0)); Members boundArgs; @@ -372,7 +368,7 @@ ReturnedValue ScriptFunction::construct(Managed *that, CallData *callData) ExecutionContext *context = v4->currentContext(); callData->thisObject = obj.asReturnedValue(); - ExecutionContext *ctx = reinterpret_cast<ExecutionContext *>(context->newCallContext(f.getPointer(), callData)); + Scoped<CallContext> ctx(scope, context->newCallContext(f.getPointer(), callData)); ExecutionContextSaver ctxSaver(context); ScopedValue result(scope, Q_V4_PROFILE(v4, ctx, f->function())); @@ -399,7 +395,7 @@ ReturnedValue ScriptFunction::call(Managed *that, CallData *callData) ExecutionContext *context = v4->currentContext(); Scope scope(context); - CallContext *ctx = reinterpret_cast<CallContext *>(context->newCallContext(f, callData)); + Scoped<CallContext> ctx(scope, context->newCallContext(f, callData)); ExecutionContextSaver ctxSaver(context); ScopedValue result(scope, Q_V4_PROFILE(v4, ctx, f->function())); @@ -543,7 +539,7 @@ BuiltinFunction::Data::Data(ExecutionContext *scope, String *name, ReturnedValue ReturnedValue BuiltinFunction::construct(Managed *f, CallData *) { - return f->internalClass()->engine->currentContext()->throwTypeError(); + return f->internalClass()->engine->throwTypeError(); } ReturnedValue BuiltinFunction::call(Managed *that, CallData *callData) @@ -641,11 +637,11 @@ ReturnedValue BoundFunction::construct(Managed *that, CallData *dd) return f->target()->construct(callData); } -void BoundFunction::markObjects(Managed *that, ExecutionEngine *e) +void BoundFunction::markObjects(HeapObject *that, ExecutionEngine *e) { - BoundFunction *o = static_cast<BoundFunction *>(that); - o->target()->mark(e); - o->boundThis().mark(e); - o->boundArgs().mark(e); + BoundFunction::Data *o = static_cast<BoundFunction::Data *>(that); + o->target->mark(e); + o->boundThis.mark(e); + 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 c8edb765de..1ff8124e6a 100644 --- a/src/qml/jsruntime/qv4functionobject_p.h +++ b/src/qml/jsruntime/qv4functionobject_p.h @@ -33,59 +33,15 @@ #ifndef QV4FUNCTIONOBJECT_H #define QV4FUNCTIONOBJECT_H -#include "qv4global_p.h" -#include "qv4runtime_p.h" -#include "qv4engine_p.h" -#include "qv4context_p.h" #include "qv4object_p.h" -#include "qv4string_p.h" -#include "qv4managed_p.h" -#include "qv4property_p.h" #include "qv4function_p.h" -#include "qv4objectiterator_p.h" +#include "qv4context_p.h" #include "qv4mm_p.h" -#include <QtCore/QString> -#include <QtCore/QHash> -#include <QtCore/QScopedPointer> -#include <cstdio> -#include <cassert> - QT_BEGIN_NAMESPACE namespace QV4 { -struct Function; -struct Object; -struct BooleanObject; -struct NumberObject; -struct StringObject; -struct ArrayObject; -struct DateObject; -struct FunctionObject; -struct ErrorObject; -struct ArgumentsObject; -struct ExecutionContext; -struct ExecutionEngine; -class MemoryManager; - -struct ObjectPrototype; -struct StringPrototype; -struct NumberPrototype; -struct BooleanPrototype; -struct ArrayPrototype; -struct FunctionPrototype; -struct DatePrototype; -struct ErrorPrototype; -struct EvalErrorPrototype; -struct RangeErrorPrototype; -struct ReferenceErrorPrototype; -struct SyntaxErrorPrototype; -struct TypeErrorPrototype; -struct URIErrorPrototype; -struct InternalClass; -struct Lookup; - struct Q_QML_EXPORT FunctionObject: Object { struct Q_QML_PRIVATE_EXPORT Data : Object::Data { Data(ExecutionContext *scope, String *name, bool createProto = false); @@ -138,7 +94,7 @@ struct Q_QML_EXPORT FunctionObject: Object { return v.asFunctionObject(); } - static FunctionObject *createScriptFunction(ExecutionContext *scope, Function *function, bool createProto = true); + static Returned<FunctionObject> *createScriptFunction(ExecutionContext *scope, Function *function, bool createProto = true); ReturnedValue protoProperty() { return memberData()[Index_Prototype].asReturnedValue(); } @@ -146,7 +102,7 @@ struct Q_QML_EXPORT FunctionObject: Object { bool strictMode() const { return d()->strictMode; } bool bindingKeyFlag() const { return d()->bindingKeyFlag; } - static void markObjects(Managed *that, ExecutionEngine *e); + static void markObjects(HeapObject *that, ExecutionEngine *e); }; template<> @@ -188,7 +144,7 @@ struct Q_QML_EXPORT BuiltinFunction: FunctionObject { }; V4_OBJECT(FunctionObject) - static BuiltinFunction *create(ExecutionContext *scope, String *name, ReturnedValue (*code)(CallContext *)) + static Returned<BuiltinFunction> *create(ExecutionContext *scope, String *name, ReturnedValue (*code)(CallContext *)) { return scope->engine()->memoryManager->alloc<BuiltinFunction>(scope, name, code); } @@ -214,7 +170,7 @@ struct IndexedBuiltinFunction: FunctionObject static ReturnedValue construct(Managed *m, CallData *) { - return m->engine()->currentContext()->throwTypeError(); + return m->engine()->throwTypeError(); } static ReturnedValue call(Managed *that, CallData *callData); @@ -253,7 +209,7 @@ struct BoundFunction: FunctionObject { }; V4_OBJECT(FunctionObject) - static BoundFunction *create(ExecutionContext *scope, FunctionObject *target, const ValueRef boundThis, const QV4::Members &boundArgs) + static Returned<BoundFunction> *create(ExecutionContext *scope, FunctionObject *target, const ValueRef boundThis, const QV4::Members &boundArgs) { return scope->engine()->memoryManager->alloc<BoundFunction>(scope, target, boundThis, boundArgs); } @@ -265,7 +221,7 @@ struct BoundFunction: FunctionObject { static ReturnedValue construct(Managed *, CallData *d); static ReturnedValue call(Managed *that, CallData *dd); - static void markObjects(Managed *that, ExecutionEngine *e); + static void markObjects(HeapObject *that, ExecutionEngine *e); }; } diff --git a/src/qml/jsruntime/qv4global_p.h b/src/qml/jsruntime/qv4global_p.h index 81f1240d89..71f217395b 100644 --- a/src/qml/jsruntime/qv4global_p.h +++ b/src/qml/jsruntime/qv4global_p.h @@ -126,6 +126,10 @@ struct ScriptFunction; struct InternalClass; struct Property; struct Value; +struct Lookup; +struct HeapObject; +struct ArrayData; +struct ManagedVTable; struct BooleanObject; struct NumberObject; @@ -146,6 +150,7 @@ struct QObjectWrapper; // It will be returned in rax on x64, [eax,edx] on x86 and [r0,r1] on arm typedef quint64 ReturnedValue; struct CallData; +struct Scope; struct ScopedValue; struct ValueRef; template<typename T> struct Scoped; diff --git a/src/qml/jsruntime/qv4globalobject.cpp b/src/qml/jsruntime/qv4globalobject.cpp index 49032e5bcf..e194460bfd 100644 --- a/src/qml/jsruntime/qv4globalobject.cpp +++ b/src/qml/jsruntime/qv4globalobject.cpp @@ -584,7 +584,7 @@ ReturnedValue GlobalFunctions::method_decodeURI(CallContext *context) if (!ok) { Scope scope(context); ScopedString s(scope, context->d()->engine->newString(QStringLiteral("malformed URI sequence"))); - return context->throwURIError(s); + return context->engine()->throwURIError(s); } return context->d()->engine->newString(out)->asReturnedValue(); @@ -602,7 +602,7 @@ ReturnedValue GlobalFunctions::method_decodeURIComponent(CallContext *context) if (!ok) { Scope scope(context); ScopedString s(scope, context->d()->engine->newString(QStringLiteral("malformed URI sequence"))); - return context->throwURIError(s); + return context->engine()->throwURIError(s); } return context->d()->engine->newString(out)->asReturnedValue(); @@ -620,7 +620,7 @@ ReturnedValue GlobalFunctions::method_encodeURI(CallContext *context) if (!ok) { Scope scope(context); ScopedString s(scope, context->d()->engine->newString(QStringLiteral("malformed URI sequence"))); - return context->throwURIError(s); + return context->engine()->throwURIError(s); } return context->d()->engine->newString(out)->asReturnedValue(); @@ -638,7 +638,7 @@ ReturnedValue GlobalFunctions::method_encodeURIComponent(CallContext *context) if (!ok) { Scope scope(context); ScopedString s(scope, context->d()->engine->newString(QStringLiteral("malformed URI sequence"))); - return context->throwURIError(s); + return context->engine()->throwURIError(s); } return context->d()->engine->newString(out)->asReturnedValue(); diff --git a/src/qml/jsruntime/qv4identifiertable.cpp b/src/qml/jsruntime/qv4identifiertable.cpp index d7ed7a8db0..5554b68db3 100644 --- a/src/qml/jsruntime/qv4identifiertable.cpp +++ b/src/qml/jsruntime/qv4identifiertable.cpp @@ -121,7 +121,8 @@ String *IdentifierTable::insertString(const QString &s) idx %= alloc; } - String *str = engine->newString(s)->getPointer(); + Returned<String> *_s = engine->newString(s); + String *str = _s->getPointer(); addEntry(str); return str; } diff --git a/src/qml/jsruntime/qv4identifiertable_p.h b/src/qml/jsruntime/qv4identifiertable_p.h index 6ae2ec06d6..cc792fa3b4 100644 --- a/src/qml/jsruntime/qv4identifiertable_p.h +++ b/src/qml/jsruntime/qv4identifiertable_p.h @@ -78,7 +78,7 @@ public: continue; entry->d()->markBit = 1; Q_ASSERT(entry->internalClass()->vtable->markObjects); - entry->internalClass()->vtable->markObjects(entry, e); + entry->internalClass()->vtable->markObjects(entry->d(), e); } } }; diff --git a/src/qml/jsruntime/qv4internalclass_p.h b/src/qml/jsruntime/qv4internalclass_p.h index 06feea1d5a..972c341992 100644 --- a/src/qml/jsruntime/qv4internalclass_p.h +++ b/src/qml/jsruntime/qv4internalclass_p.h @@ -33,9 +33,9 @@ #ifndef QV4INTERNALCLASS_H #define QV4INTERNALCLASS_H -#include <QHash> -#include <QVector> #include "qv4global_p.h" + +#include <QHash> #include <private/qqmljsmemorypool_p.h> QT_BEGIN_NAMESPACE diff --git a/src/qml/jsruntime/qv4jsonobject.cpp b/src/qml/jsruntime/qv4jsonobject.cpp index 268559dec8..74cf26c381 100644 --- a/src/qml/jsruntime/qv4jsonobject.cpp +++ b/src/qml/jsruntime/qv4jsonobject.cpp @@ -37,6 +37,8 @@ #include <qv4booleanobject_p.h> #include <qv4objectiterator_p.h> #include <qv4scopedvalue_p.h> +#include <qv4runtime_p.h> + #include <qjsondocument.h> #include <qstack.h> #include <qstringlist.h> @@ -775,7 +777,7 @@ QString Stringify::makeMember(const QString &key, ValueRef v) QString Stringify::JO(Object *o) { if (stack.contains(o)) { - ctx->throwTypeError(); + ctx->engine()->throwTypeError(); return QString(); } @@ -832,7 +834,7 @@ QString Stringify::JO(Object *o) QString Stringify::JA(ArrayObject *a) { if (stack.contains(a)) { - ctx->throwTypeError(); + ctx->engine()->throwTypeError(); return QString(); } @@ -898,7 +900,7 @@ ReturnedValue JsonObject::method_parse(CallContext *ctx) ScopedValue result(scope, parser.parse(&error)); if (error.error != QJsonParseError::NoError) { DEBUG << "parse error" << error.errorString(); - return ctx->throwSyntaxError(QStringLiteral("JSON.parse: Parse error")); + return ctx->engine()->throwSyntaxError(QStringLiteral("JSON.parse: Parse error")); } return result.asReturnedValue(); diff --git a/src/qml/jsruntime/qv4lookup.cpp b/src/qml/jsruntime/qv4lookup.cpp index 254666eca2..f7ebb62b8d 100644 --- a/src/qml/jsruntime/qv4lookup.cpp +++ b/src/qml/jsruntime/qv4lookup.cpp @@ -130,7 +130,7 @@ ReturnedValue Lookup::indexedGetterFallback(Lookup *l, const ValueRef object, co if (object->isNullOrUndefined()) { QString message = QStringLiteral("Cannot read property '%1' of %2").arg(index->toQStringNoThrow()).arg(object->toQStringNoThrow()); - return ctx->throwTypeError(message); + return ctx->engine()->throwTypeError(message); } o = RuntimeHelpers::convertToObject(ctx, object); @@ -240,7 +240,7 @@ ReturnedValue Lookup::getterGeneric(QV4::Lookup *l, const ValueRef object) switch (object->type()) { case Value::Undefined_Type: case Value::Null_Type: - return engine->currentContext()->throwTypeError(); + return engine->throwTypeError(); case Value::Boolean_Type: proto = engine->booleanClass->prototype; break; @@ -598,7 +598,7 @@ ReturnedValue Lookup::globalGetterGeneric(Lookup *l, ExecutionContext *ctx) } Scope scope(ctx); Scoped<String> n(scope, l->name); - return ctx->throwReferenceError(n); + return ctx->engine()->throwReferenceError(n); } ReturnedValue Lookup::globalGetter0(Lookup *l, ExecutionContext *ctx) diff --git a/src/qml/jsruntime/qv4managed.cpp b/src/qml/jsruntime/qv4managed.cpp index c7327addfd..93286b3945 100644 --- a/src/qml/jsruntime/qv4managed.cpp +++ b/src/qml/jsruntime/qv4managed.cpp @@ -157,7 +157,7 @@ void Managed::setVTable(const ManagedVTable *vt) d()->internalClass = internalClass()->changeVTable(vt); } -void Managed::Data::setVTable(const ManagedVTable *vt) +void HeapObject::setVTable(const ManagedVTable *vt) { Q_ASSERT(internalClass); internalClass = internalClass->changeVTable(vt); diff --git a/src/qml/jsruntime/qv4managed_p.h b/src/qml/jsruntime/qv4managed_p.h index e679017b7e..91dc0fb034 100644 --- a/src/qml/jsruntime/qv4managed_p.h +++ b/src/qml/jsruntime/qv4managed_p.h @@ -33,9 +33,6 @@ #ifndef QMLJS_MANAGED_H #define QMLJS_MANAGED_H -#include <QtCore/QString> -#include <QtCore/QVector> -#include <QtCore/QDebug> #include "qv4global_p.h" #include "qv4value_p.h" #include "qv4internalclass_p.h" @@ -45,7 +42,7 @@ QT_BEGIN_NAMESPACE namespace QV4 { #define Q_MANAGED_CHECK \ - template <typename T> inline void qt_check_for_QMANAGED_macro(const T *_q_argument) const \ + template <typename _T> inline void qt_check_for_QMANAGED_macro(const _T *_q_argument) const \ { int i = qYouForgotTheQ_MANAGED_Macro(this, _q_argument); i = i + 1; } template <typename T> @@ -66,8 +63,8 @@ inline void qYouForgotTheQ_MANAGED_Macro(T1, T2) {} typedef superClass SuperClass; \ static const QV4::ManagedVTable static_vtbl; \ static inline const QV4::ManagedVTable *staticVTable() { return &static_vtbl; } \ - template <typename T> \ - QV4::Returned<T> *asReturned() { return QV4::Returned<T>::create(this); } \ + template <typename _T> \ + QV4::Returned<_T> *asReturned() { return QV4::Returned<_T>::create(this); } \ V4_MANAGED_SIZE_TEST \ const Data *d() const { return &static_cast<const Data &>(Managed::data); } \ Data *d() { return &static_cast<Data &>(Managed::data); } @@ -78,8 +75,8 @@ inline void qYouForgotTheQ_MANAGED_Macro(T1, T2) {} typedef superClass SuperClass; \ static const QV4::ObjectVTable static_vtbl; \ static inline const QV4::ManagedVTable *staticVTable() { return &static_vtbl.managedVTable; } \ - template <typename T> \ - QV4::Returned<T> *asReturned() { return QV4::Returned<T>::create(this); } \ + template <typename _T> \ + QV4::Returned<_T> *asReturned() { return QV4::Returned<_T>::create(this); } \ V4_MANAGED_SIZE_TEST \ const Data *d() const { return &static_cast<const Data &>(Managed::data); } \ Data *d() { return &static_cast<Data &>(Managed::data); } @@ -113,7 +110,7 @@ struct ManagedVTable uint type : 8; const char *className; void (*destroy)(Managed *); - void (*markObjects)(Managed *, ExecutionEngine *e); + void (*markObjects)(HeapObject *, ExecutionEngine *e); bool (*isEqualTo)(Managed *m, Managed *other); }; @@ -180,39 +177,10 @@ const QV4::ObjectVTable classname::static_vtbl = \ struct Q_QML_PRIVATE_EXPORT Managed { struct Q_QML_PRIVATE_EXPORT Data : HeapObject { - Data() {} + Data() : HeapObject(0) {} Data(InternalClass *internal) - : internalClass(internal) - , markBit(0) - , inUse(1) - , extensible(1) - { - // #### -// Q_ASSERT(internal && internal->vtable); - } - InternalClass *internalClass; - struct { - uchar markBit : 1; - uchar inUse : 1; - uchar extensible : 1; // used by Object - uchar _unused : 1; - uchar needsActivation : 1; // used by FunctionObject - uchar strictMode : 1; // used by FunctionObject - uchar bindingKeyFlag : 1; - uchar hasAccessorProperty : 1; - uchar _type; - mutable uchar subtype; - uchar _flags; - }; - - void setVTable(const ManagedVTable *vt); - ReturnedValue asReturnedValue() const { - return reinterpret_cast<Managed *>(const_cast<Data *>(this))->asReturnedValue(); - } - - void *operator new(size_t, Managed *m) { return m; } - void *operator new(size_t, Managed::Data *m) { return m; } - void operator delete(void *, Managed::Data *) {} + : HeapObject(internal) + {} }; Data data; V4_MANAGED(Managed) @@ -326,8 +294,8 @@ public: void setVTable(const ManagedVTable *vt); - bool isEqualTo(Managed *other) - { return internalClass()->vtable->isEqualTo(this, other); } + bool isEqualTo(const Managed *other) const + { return internalClass()->vtable->isEqualTo(const_cast<Managed *>(this), const_cast<Managed *>(other)); } static bool isEqualTo(Managed *m, Managed *other); @@ -377,6 +345,20 @@ inline FunctionObject *managed_cast(Managed *m) return m ? m->asFunctionObject() : 0; } +inline Value Value::fromManaged(Managed *m) +{ + if (!m) + return QV4::Primitive::undefinedValue(); + Value v; +#if QT_POINTER_SIZE == 8 + v.m = &m->data; +#else + v.tag = Managed_Type; + v.m = &m->data; +#endif + return v; +} + } diff --git a/src/qml/jsruntime/qv4memberdata.cpp b/src/qml/jsruntime/qv4memberdata.cpp index 405594ca9b..de226305f1 100644 --- a/src/qml/jsruntime/qv4memberdata.cpp +++ b/src/qml/jsruntime/qv4memberdata.cpp @@ -38,11 +38,11 @@ using namespace QV4; DEFINE_MANAGED_VTABLE(MemberData); -void MemberData::markObjects(Managed *that, ExecutionEngine *e) +void MemberData::markObjects(HeapObject *that, ExecutionEngine *e) { - MemberData *m = static_cast<MemberData *>(that); - for (uint i = 0; i < m->d()->size; ++i) - m->d()->data[i].mark(e); + MemberData::Data *m = static_cast<MemberData::Data *>(that); + for (uint i = 0; i < m->size; ++i) + m->data[i].mark(e); } void Members::ensureIndex(QV4::ExecutionEngine *e, uint idx) @@ -57,6 +57,6 @@ void Members::ensureIndex(QV4::ExecutionEngine *e, uint idx) else new (newMemberData) MemberData(e->memberDataClass); newMemberData->d()->size = newAlloc; - m = newMemberData; + m = &newMemberData->data; } } diff --git a/src/qml/jsruntime/qv4memberdata_p.h b/src/qml/jsruntime/qv4memberdata_p.h index 83732113a9..cc7b10ff81 100644 --- a/src/qml/jsruntime/qv4memberdata_p.h +++ b/src/qml/jsruntime/qv4memberdata_p.h @@ -54,7 +54,7 @@ struct MemberData : Managed MemberData(QV4::InternalClass *ic) : Managed(ic) {} Value &operator[] (uint idx) { return d()->data[idx]; } - static void markObjects(Managed *that, ExecutionEngine *e); + static void markObjects(HeapObject *that, ExecutionEngine *e); }; struct Members : Value diff --git a/src/qml/jsruntime/qv4mm.cpp b/src/qml/jsruntime/qv4mm.cpp index b9a4a55b4a..df439e1c5e 100644 --- a/src/qml/jsruntime/qv4mm.cpp +++ b/src/qml/jsruntime/qv4mm.cpp @@ -264,9 +264,9 @@ Managed *MemoryManager::allocData(std::size_t size) static void drainMarkStack(QV4::ExecutionEngine *engine, Value *markBase) { while (engine->jsStackTop > markBase) { - Managed *m = engine->popForGC(); - Q_ASSERT (m->internalClass()->vtable->markObjects); - m->internalClass()->vtable->markObjects(m, engine); + HeapObject *h = engine->popForGC(); + Q_ASSERT (h->internalClass->vtable->markObjects); + h->internalClass->vtable->markObjects(h, engine); } } @@ -492,9 +492,9 @@ size_t MemoryManager::getUsedMem() const char *chunkStart = reinterpret_cast<char *>(i->memory.base()); char *chunkEnd = chunkStart + i->memory.size() - i->chunkSize; for (char *chunk = chunkStart; chunk <= chunkEnd; chunk += i->chunkSize) { - Managed *m = reinterpret_cast<Managed *>(chunk); + Managed::Data *m = reinterpret_cast<Managed::Data *>(chunk); Q_ASSERT((qintptr) chunk % 16 == 0); - if (m->inUse()) + if (m->inUse) usedMem += i->chunkSize; } } @@ -535,6 +535,11 @@ MemoryManager::~MemoryManager() #endif } +ExecutionEngine *MemoryManager::engine() const +{ + return m_d->engine; +} + void MemoryManager::setExecutionEngine(ExecutionEngine *engine) { m_d->engine = engine; diff --git a/src/qml/jsruntime/qv4mm_p.h b/src/qml/jsruntime/qv4mm_p.h index d5e28f7f84..f2267e5852 100644 --- a/src/qml/jsruntime/qv4mm_p.h +++ b/src/qml/jsruntime/qv4mm_p.h @@ -35,10 +35,8 @@ #define QV4GC_H #include "qv4global_p.h" -#include "qv4context_p.h" #include "qv4value_inl_p.h" - -#include <QScopedPointer> +#include "qv4scopedvalue_p.h" //#define DETAILED_MM_STATS @@ -96,57 +94,64 @@ public: } template <typename ManagedType> - ManagedType *alloc() + Returned<ManagedType> *alloc() { - ManagedType *t = static_cast<ManagedType*>(allocManaged(sizeof(typename ManagedType::Data))); + Scope scope(engine()); + Scoped<ManagedType> t(scope, static_cast<ManagedType*>(allocManaged(sizeof(typename ManagedType::Data)))); (void)new (t->d()) typename ManagedType::Data(); - return t; + return t.asReturned(); } template <typename ManagedType, typename Arg1> - ManagedType *alloc(Arg1 arg1) + Returned<ManagedType> *alloc(Arg1 arg1) { - ManagedType *t = static_cast<ManagedType*>(allocManaged(sizeof(typename ManagedType::Data))); + Scope scope(engine()); + Scoped<ManagedType> t(scope, static_cast<ManagedType*>(allocManaged(sizeof(typename ManagedType::Data)))); (void)new (t->d()) typename ManagedType::Data(arg1); - return t; + return t.asReturned(); } template <typename ManagedType, typename Arg1, typename Arg2> - ManagedType *alloc(Arg1 arg1, Arg2 arg2) + Returned<ManagedType> *alloc(Arg1 arg1, Arg2 arg2) { - ManagedType *t = static_cast<ManagedType*>(allocManaged(sizeof(typename ManagedType::Data))); + Scope scope(engine()); + Scoped<ManagedType> t(scope, static_cast<ManagedType*>(allocManaged(sizeof(typename ManagedType::Data)))); (void)new (t->d()) typename ManagedType::Data(arg1, arg2); - return t; + return t.asReturned(); } template <typename ManagedType, typename Arg1, typename Arg2, typename Arg3> - ManagedType *alloc(Arg1 arg1, Arg2 arg2, Arg3 arg3) + Returned<ManagedType> *alloc(Arg1 arg1, Arg2 arg2, Arg3 arg3) { - ManagedType *t = static_cast<ManagedType*>(allocManaged(sizeof(typename ManagedType::Data))); + Scope scope(engine()); + Scoped<ManagedType> t(scope, static_cast<ManagedType*>(allocManaged(sizeof(typename ManagedType::Data)))); (void)new (t->d()) typename ManagedType::Data(arg1, arg2, arg3); - return t; + return t.asReturned(); } template <typename ManagedType, typename Arg1, typename Arg2, typename Arg3, typename Arg4> - ManagedType *alloc(Arg1 arg1, Arg2 arg2, Arg3 arg3, Arg4 arg4) + Returned<ManagedType> *alloc(Arg1 arg1, Arg2 arg2, Arg3 arg3, Arg4 arg4) { - ManagedType *t = static_cast<ManagedType*>(allocManaged(sizeof(typename ManagedType::Data))); + Scope scope(engine()); + Scoped<ManagedType> t(scope, static_cast<ManagedType*>(allocManaged(sizeof(typename ManagedType::Data)))); (void)new (t->d()) typename ManagedType::Data(arg1, arg2, arg3, arg4); - return t; + return t.asReturned(); } template <typename ManagedType, typename Arg1, typename Arg2, typename Arg3, typename Arg4, typename Arg5> - ManagedType *alloc(Arg1 arg1, Arg2 arg2, Arg3 arg3, Arg4 arg4, Arg5 arg5) + Returned<ManagedType> *alloc(Arg1 arg1, Arg2 arg2, Arg3 arg3, Arg4 arg4, Arg5 arg5) { - ManagedType *t = static_cast<ManagedType*>(allocManaged(sizeof(typename ManagedType::Data))); + Scope scope(engine()); + Scoped<ManagedType> t(scope, static_cast<ManagedType*>(allocManaged(sizeof(typename ManagedType::Data)))); (void)new (t->d()) typename ManagedType::Data(arg1, arg2, arg3, arg4, arg5); - return t; + return t.asReturned(); } bool isGCBlocked() const; void setGCBlocked(bool blockGC); void runGC(); + ExecutionEngine *engine() const; void setExecutionEngine(ExecutionEngine *engine); void dumpStats() const; diff --git a/src/qml/jsruntime/qv4numberobject.cpp b/src/qml/jsruntime/qv4numberobject.cpp index 227ff14104..44826c94c8 100644 --- a/src/qml/jsruntime/qv4numberobject.cpp +++ b/src/qml/jsruntime/qv4numberobject.cpp @@ -32,6 +32,8 @@ ****************************************************************************/ #include "qv4numberobject_p.h" +#include "qv4runtime_p.h" + #include <QtCore/qnumeric.h> #include <QtCore/qmath.h> #include <QtCore/QDebug> @@ -99,7 +101,7 @@ inline ReturnedValue thisNumberValue(ExecutionContext *ctx) return ctx->d()->callData->thisObject.asReturnedValue(); NumberObject *n = ctx->d()->callData->thisObject.asNumberObject(); if (!n) - return ctx->throwTypeError(); + return ctx->engine()->throwTypeError(); return n->value().asReturnedValue(); } @@ -109,7 +111,7 @@ inline double thisNumber(ExecutionContext *ctx) return ctx->d()->callData->thisObject.asDouble(); NumberObject *n = ctx->d()->callData->thisObject.asNumberObject(); if (!n) - return ctx->throwTypeError(); + return ctx->engine()->throwTypeError(); return n->value().asDouble(); } @@ -122,7 +124,7 @@ ReturnedValue NumberPrototype::method_toString(CallContext *ctx) if (ctx->d()->callData->argc && !ctx->d()->callData->args[0].isUndefined()) { int radix = ctx->d()->callData->args[0].toInt32(); if (radix < 2 || radix > 36) - return ctx->throwError(QString::fromLatin1("Number.prototype.toString: %0 is not a valid radix") + return ctx->engine()->throwError(QString::fromLatin1("Number.prototype.toString: %0 is not a valid radix") .arg(radix)); if (std::isnan(num)) { @@ -195,7 +197,7 @@ ReturnedValue NumberPrototype::method_toFixed(CallContext *ctx) fdigits = 0; if (fdigits < 0 || fdigits > 20) - return ctx->throwRangeError(ctx->d()->callData->thisObject); + return ctx->engine()->throwRangeError(ctx->d()->callData->thisObject); QString str; if (std::isnan(v)) @@ -222,7 +224,7 @@ ReturnedValue NumberPrototype::method_toExponential(CallContext *ctx) fdigits = ctx->d()->callData->args[0].toInt32(); if (fdigits < 0 || fdigits > 20) { ScopedString error(scope, ctx->d()->engine->newString(QStringLiteral("Number.prototype.toExponential: fractionDigits out of range"))); - return ctx->throwRangeError(error); + return ctx->engine()->throwRangeError(error); } } @@ -247,7 +249,7 @@ ReturnedValue NumberPrototype::method_toPrecision(CallContext *ctx) double precision = ctx->d()->callData->args[0].toInt32(); if (precision < 1 || precision > 21) { ScopedString error(scope, ctx->d()->engine->newString(QStringLiteral("Number.prototype.toPrecision: precision out of range"))); - return ctx->throwRangeError(error); + return ctx->engine()->throwRangeError(error); } char str[100]; diff --git a/src/qml/jsruntime/qv4object.cpp b/src/qml/jsruntime/qv4object.cpp index 0c61d666ab..576537dcef 100644 --- a/src/qml/jsruntime/qv4object.cpp +++ b/src/qml/jsruntime/qv4object.cpp @@ -41,22 +41,9 @@ #include "qv4lookup_p.h" #include "qv4scopedvalue_p.h" #include "qv4memberdata_p.h" +#include "qv4objectiterator_p.h" -#include <private/qqmljsengine_p.h> -#include <private/qqmljslexer_p.h> -#include <private/qqmljsparser_p.h> -#include <private/qqmljsast_p.h> -#include <qv4jsir_p.h> -#include <qv4codegen_p.h> -#include "private/qlocale_tools_p.h" - -#include <QtCore/qmath.h> -#include <QtCore/QDebug> -#include <cassert> -#include <typeinfo> -#include <iostream> #include <stdint.h> -#include "qv4alloca_p.h" using namespace QV4; @@ -130,7 +117,7 @@ void Object::putValue(Property *pd, PropertyAttributes attrs, const ValueRef val reject: if (engine()->currentContext()->d()->strictMode) - engine()->currentContext()->throwTypeError(); + engine()->throwTypeError(); } void Object::defineDefaultProperty(const QString &name, ValueRef value) @@ -191,13 +178,13 @@ void Object::defineReadonlyProperty(String *name, ValueRef value) insertMember(name, value, Attr_ReadOnly); } -void Object::markObjects(Managed *that, ExecutionEngine *e) +void Object::markObjects(HeapObject *that, ExecutionEngine *e) { - Object *o = static_cast<Object *>(that); + Object::Data *o = static_cast<Object::Data *>(that); - o->memberData().mark(e); - if (o->arrayData()) - o->arrayData()->mark(e); + o->memberData.mark(e); + if (o->arrayData) + o->arrayData->mark(e); } void Object::ensureMemberIndex(uint idx) @@ -369,12 +356,12 @@ bool Object::hasOwnProperty(uint index) const ReturnedValue Object::construct(Managed *m, CallData *) { - return m->engine()->currentContext()->throwTypeError(); + return m->engine()->throwTypeError(); } ReturnedValue Object::call(Managed *m, CallData *) { - return m->engine()->currentContext()->throwTypeError(); + return m->engine()->throwTypeError(); } ReturnedValue Object::get(Managed *m, String *name, bool *hasProperty) @@ -678,7 +665,7 @@ void Object::internalPut(String *name, const ValueRef value) bool ok; uint l = value->asArrayLength(&ok); if (!ok) { - engine()->currentContext()->throwRangeError(value); + engine()->throwRangeError(value); return; } ok = setArrayLength(l); @@ -727,7 +714,7 @@ void Object::internalPut(String *name, const ValueRef value) QString message = QStringLiteral("Cannot assign to read-only property \""); message += name->toQString(); message += QLatin1Char('\"'); - engine()->currentContext()->throwTypeError(message); + engine()->throwTypeError(message); } } @@ -796,7 +783,7 @@ void Object::internalPutIndexed(uint index, const ValueRef value) reject: if (engine()->currentContext()->d()->strictMode) - engine()->currentContext()->throwTypeError(); + engine()->throwTypeError(); } // Section 8.12.7 @@ -818,7 +805,7 @@ bool Object::internalDeleteProperty(String *name) return true; } if (engine()->currentContext()->d()->strictMode) - engine()->currentContext()->throwTypeError(); + engine()->throwTypeError(); return false; } @@ -834,7 +821,7 @@ bool Object::internalDeleteIndexedProperty(uint index) return true; if (engine()->currentContext()->d()->strictMode) - engine()->currentContext()->throwTypeError(); + engine()->throwTypeError(); return false; } @@ -866,7 +853,7 @@ bool Object::__defineOwnProperty__(ExecutionContext *ctx, String *name, const Pr uint l = p.value.asArrayLength(&ok); if (!ok) { ScopedValue v(scope, p.value); - ctx->throwRangeError(v); + ctx->engine()->throwRangeError(v); return false; } succeeded = setArrayLength(l); @@ -900,7 +887,7 @@ bool Object::__defineOwnProperty__(ExecutionContext *ctx, String *name, const Pr return __defineOwnProperty__(ctx, memberIndex, name, p, attrs); reject: if (ctx->d()->strictMode) - ctx->throwTypeError(); + ctx->engine()->throwTypeError(); return false; } @@ -916,7 +903,7 @@ bool Object::__defineOwnProperty__(ExecutionContext *ctx, uint index, const Prop return defineOwnProperty2(ctx, index, p, attrs); reject: if (ctx->d()->strictMode) - ctx->throwTypeError(); + ctx->engine()->throwTypeError(); return false; } @@ -952,7 +939,7 @@ bool Object::defineOwnProperty2(ExecutionContext *ctx, uint index, const Propert return __defineOwnProperty__(ctx, index, 0, p, attrs); reject: if (ctx->d()->strictMode) - ctx->throwTypeError(); + ctx->engine()->throwTypeError(); return false; } @@ -1045,7 +1032,7 @@ bool Object::__defineOwnProperty__(ExecutionContext *ctx, uint index, String *me return true; reject: if (ctx->d()->strictMode) - ctx->throwTypeError(); + ctx->engine()->throwTypeError(); return false; } diff --git a/src/qml/jsruntime/qv4object_p.h b/src/qml/jsruntime/qv4object_p.h index 4e9d1527c2..f11220f55c 100644 --- a/src/qml/jsruntime/qv4object_p.h +++ b/src/qml/jsruntime/qv4object_p.h @@ -30,70 +30,17 @@ ** $QT_END_LICENSE$ ** ****************************************************************************/ -#ifndef QMLJS_OBJECTS_H -#define QMLJS_OBJECTS_H - -#include "qv4global_p.h" -#include "qv4runtime_p.h" -#include "qv4engine_p.h" -#include "qv4context_p.h" -#include "qv4string_p.h" +#ifndef QV4_OBJECT_H +#define QV4_OBJECT_H + #include "qv4managed_p.h" -#include "qv4property_p.h" -#include "qv4internalclass_p.h" -#include "qv4arraydata_p.h" #include "qv4memberdata_p.h" - -#include <QtCore/QString> -#include <QtCore/QHash> -#include <QtCore/QScopedPointer> -#include <cstdio> -#include <cassert> - -#ifdef _WIN32_WCE -#undef assert -#define assert(x) -#endif // _WIN32_WCE +#include "qv4arraydata_p.h" QT_BEGIN_NAMESPACE namespace QV4 { -struct Function; -struct Lookup; -struct Object; -struct ObjectIterator; -struct BooleanObject; -struct NumberObject; -struct StringObject; -struct ArrayObject; -struct DateObject; -struct FunctionObject; -struct RegExpObject; -struct ErrorObject; -struct ArgumentsObject; -struct ExecutionContext; -struct CallContext; -struct ExecutionEngine; -class MemoryManager; - -struct ObjectPrototype; -struct StringPrototype; -struct NumberPrototype; -struct BooleanPrototype; -struct ArrayPrototype; -struct FunctionPrototype; -struct DatePrototype; -struct RegExpPrototype; -struct ErrorPrototype; -struct EvalErrorPrototype; -struct RangeErrorPrototype; -struct ReferenceErrorPrototype; -struct SyntaxErrorPrototype; -struct TypeErrorPrototype; -struct URIErrorPrototype; - - struct Q_QML_EXPORT Object: Managed { struct Data : Managed::Data { Data(ExecutionEngine *engine) @@ -277,7 +224,7 @@ public: inline ReturnedValue call(CallData *d) { return vtable()->call(this, d); } protected: - static void markObjects(Managed *that, ExecutionEngine *e); + static void markObjects(HeapObject *that, ExecutionEngine *e); static ReturnedValue construct(Managed *m, CallData *); static ReturnedValue call(Managed *m, CallData *); static ReturnedValue get(Managed *m, String *name, bool *hasProperty); diff --git a/src/qml/jsruntime/qv4objectiterator.cpp b/src/qml/jsruntime/qv4objectiterator.cpp index f9038472df..e0f7087437 100644 --- a/src/qml/jsruntime/qv4objectiterator.cpp +++ b/src/qml/jsruntime/qv4objectiterator.cpp @@ -68,15 +68,15 @@ ObjectIterator::ObjectIterator(Value *scratch1, Value *scratch2, uint flags) , memberIndex(0) , flags(flags) { - object->o = (Object*)0; - current->o = (Object*)0; + object->m = 0; + current->m = 0; // Caller needs to call init! } void ObjectIterator::init(Object *o) { - object->o = o; - current->o = o; + object->m = o ? &o->data : 0; + current->m = o ? &o->data : 0; #if QT_POINTER_SIZE == 4 object->tag = QV4::Value::Managed_Type; @@ -125,10 +125,11 @@ void ObjectIterator::next(String *&name, uint *index, Property *pd, PropertyAttr return; } - if (flags & WithProtoChain) - current->o = current->objectValue()->prototype(); - else - current->o = (Object *)0; + if (flags & WithProtoChain) { + Object *proto = current->objectValue()->prototype(); + current->m = proto ? &proto->data : 0; + } else + current->m = (HeapObject *)0; arrayIndex = 0; memberIndex = 0; @@ -209,10 +210,10 @@ ReturnedValue ObjectIterator::nextPropertyNameAsString() DEFINE_OBJECT_VTABLE(ForEachIteratorObject); -void ForEachIteratorObject::markObjects(Managed *that, ExecutionEngine *e) +void ForEachIteratorObject::markObjects(HeapObject *that, ExecutionEngine *e) { - ForEachIteratorObject *o = static_cast<ForEachIteratorObject *>(that); - o->d()->workArea[0].mark(e); - o->d()->workArea[1].mark(e); + ForEachIteratorObject::Data *o = static_cast<ForEachIteratorObject::Data *>(that); + o->workArea[0].mark(e); + o->workArea[1].mark(e); Object::markObjects(that, e); } diff --git a/src/qml/jsruntime/qv4objectiterator_p.h b/src/qml/jsruntime/qv4objectiterator_p.h index 3ed73b5c08..10f75a1e0d 100644 --- a/src/qml/jsruntime/qv4objectiterator_p.h +++ b/src/qml/jsruntime/qv4objectiterator_p.h @@ -34,24 +34,12 @@ #define QV4OBJECTITERATOR_H #include "qv4global_p.h" -#include "qv4property_p.h" -#include "qv4scopedvalue_p.h" #include "qv4object_p.h" QT_BEGIN_NAMESPACE namespace QV4 { -struct SparseArrayNode; -struct Object; -struct ArrayObject; -struct PropertyAttributes; -struct ExecutionContext; -struct Property; -struct String; -struct InternalClass; -struct ForEachIteratorObject; - struct Q_QML_EXPORT ObjectIterator { enum Flags { @@ -81,8 +69,8 @@ private: struct ForEachIteratorObject: Object { struct Data : Object::Data { - Data(ExecutionContext *ctx, Object *o) - : Object::Data(ctx->engine()) + Data(ExecutionEngine *engine, Object *o) + : Object::Data(engine) , it(workArea, workArea + 1, o, ObjectIterator::EnumerableOnly|ObjectIterator::WithProtoChain) { setVTable(staticVTable()); } @@ -95,7 +83,7 @@ struct ForEachIteratorObject: Object { ReturnedValue nextPropertyName() { return d()->it.nextPropertyNameAsString(); } protected: - static void markObjects(Managed *that, ExecutionEngine *e); + static void markObjects(HeapObject *that, ExecutionEngine *e); }; diff --git a/src/qml/jsruntime/qv4objectproto.cpp b/src/qml/jsruntime/qv4objectproto.cpp index 9cbf4b204e..5a4fe253e2 100644 --- a/src/qml/jsruntime/qv4objectproto.cpp +++ b/src/qml/jsruntime/qv4objectproto.cpp @@ -36,30 +36,13 @@ #include "qv4argumentsobject_p.h" #include "qv4mm_p.h" #include "qv4scopedvalue_p.h" +#include "qv4runtime_p.h" +#include "qv4objectiterator_p.h" + #include <QtCore/qnumeric.h> #include <QtCore/qmath.h> #include <QtCore/QDateTime> #include <QtCore/QStringList> -#include <QtCore/QDebug> -#include <cassert> - -#include <private/qqmljsengine_p.h> -#include <private/qqmljslexer_p.h> -#include <private/qqmljsparser_p.h> -#include <private/qqmljsast_p.h> -#include <qv4jsir_p.h> -#include <qv4codegen_p.h> - -#ifndef Q_OS_WIN -# include <time.h> -# ifndef Q_OS_VXWORKS -# include <sys/time.h> -# else -# include "qplatformdefs.h" -# endif -#else -# include <windows.h> -#endif using namespace QV4; @@ -135,7 +118,7 @@ ReturnedValue ObjectPrototype::method_getPrototypeOf(CallContext *ctx) Scope scope(ctx); Scoped<Object> o(scope, ctx->argument(0)); if (!o) - return ctx->throwTypeError(); + return ctx->engine()->throwTypeError(); Scoped<Object> p(scope, o->prototype()); return !!p ? p->asReturnedValue() : Encode::null(); @@ -146,7 +129,7 @@ ReturnedValue ObjectPrototype::method_getOwnPropertyDescriptor(CallContext *ctx) Scope scope(ctx); Scoped<Object> O(scope, ctx->argument(0)); if (!O) - return ctx->throwTypeError(); + return ctx->engine()->throwTypeError(); if (ArgumentsObject::isNonStrictArgumentsObject(O.getPointer())) Scoped<ArgumentsObject>(scope, O)->fullyCreate(); @@ -165,7 +148,7 @@ ReturnedValue ObjectPrototype::method_getOwnPropertyNames(CallContext *context) Scope scope(context); ScopedObject O(scope, context->argument(0)); if (!O) - return context->throwTypeError(); + return context->engine()->throwTypeError(); ScopedArrayObject array(scope, getOwnPropertyNames(context->d()->engine, context->d()->callData->args[0])); return array.asReturnedValue(); @@ -176,7 +159,7 @@ ReturnedValue ObjectPrototype::method_create(CallContext *ctx) Scope scope(ctx); ScopedValue O(scope, ctx->argument(0)); if (!O->isObject() && !O->isNull()) - return ctx->throwTypeError(); + return ctx->engine()->throwTypeError(); Scoped<Object> newObject(scope, ctx->d()->engine->newObject()); newObject->setPrototype(O->asObject()); @@ -194,7 +177,7 @@ ReturnedValue ObjectPrototype::method_defineProperty(CallContext *ctx) Scope scope(ctx); Scoped<Object> O(scope, ctx->argument(0)); if (!O) - return ctx->throwTypeError(); + return ctx->engine()->throwTypeError(); Scoped<String> name(scope, ctx->argument(1), Scoped<String>::Convert); if (scope.engine->hasException) @@ -208,7 +191,7 @@ ReturnedValue ObjectPrototype::method_defineProperty(CallContext *ctx) return Encode::undefined(); if (!O->__defineOwnProperty__(ctx, name.getPointer(), pd, attrs)) - return ctx->throwTypeError(); + return ctx->engine()->throwTypeError(); return O.asReturnedValue(); } @@ -218,7 +201,7 @@ ReturnedValue ObjectPrototype::method_defineProperties(CallContext *ctx) Scope scope(ctx); Scoped<Object> O(scope, ctx->argument(0)); if (!O) - return ctx->throwTypeError(); + return ctx->engine()->throwTypeError(); Scoped<Object> o(scope, ctx->argument(1), Scoped<Object>::Convert); if (scope.engine->hasException) @@ -248,7 +231,7 @@ ReturnedValue ObjectPrototype::method_defineProperties(CallContext *ctx) else ok = O->__defineOwnProperty__(ctx, index, n, nattrs); if (!ok) - return ctx->throwTypeError(); + return ctx->engine()->throwTypeError(); } return O.asReturnedValue(); @@ -259,7 +242,7 @@ ReturnedValue ObjectPrototype::method_seal(CallContext *ctx) Scope scope(ctx); Scoped<Object> o(scope, ctx->argument(0)); if (!o) - return ctx->throwTypeError(); + return ctx->engine()->throwTypeError(); o->setExtensible(false); @@ -281,7 +264,7 @@ ReturnedValue ObjectPrototype::method_freeze(CallContext *ctx) Scope scope(ctx); Scoped<Object> o(scope, ctx->argument(0)); if (!o) - return ctx->throwTypeError(); + return ctx->engine()->throwTypeError(); if (ArgumentsObject::isNonStrictArgumentsObject(o.getPointer())) Scoped<ArgumentsObject>(scope, o)->fullyCreate(); @@ -307,7 +290,7 @@ ReturnedValue ObjectPrototype::method_preventExtensions(CallContext *ctx) Scope scope(ctx); Scoped<Object> o(scope, ctx->argument(0)); if (!o) - return ctx->throwTypeError(); + return ctx->engine()->throwTypeError(); o->setExtensible(false); return o.asReturnedValue(); @@ -318,7 +301,7 @@ ReturnedValue ObjectPrototype::method_isSealed(CallContext *ctx) Scope scope(ctx); Scoped<Object> o(scope, ctx->argument(0)); if (!o) - return ctx->throwTypeError(); + return ctx->engine()->throwTypeError(); if (o->isExtensible()) return Encode(false); @@ -347,7 +330,7 @@ ReturnedValue ObjectPrototype::method_isFrozen(CallContext *ctx) Scope scope(ctx); Scoped<Object> o(scope, ctx->argument(0)); if (!o) - return ctx->throwTypeError(); + return ctx->engine()->throwTypeError(); if (o->isExtensible()) return Encode(false); @@ -376,7 +359,7 @@ ReturnedValue ObjectPrototype::method_isExtensible(CallContext *ctx) Scope scope(ctx); Scoped<Object> o(scope, ctx->argument(0)); if (!o) - return ctx->throwTypeError(); + return ctx->engine()->throwTypeError(); return Encode((bool)o->isExtensible()); } @@ -386,7 +369,7 @@ ReturnedValue ObjectPrototype::method_keys(CallContext *ctx) Scope scope(ctx); Scoped<Object> o(scope, ctx->argument(0)); if (!o) - return ctx->throwTypeError(); + return ctx->engine()->throwTypeError(); Scoped<ArrayObject> a(scope, ctx->d()->engine->newArrayObject()); @@ -424,7 +407,7 @@ ReturnedValue ObjectPrototype::method_toLocaleString(CallContext *ctx) return Encode::undefined(); Scoped<FunctionObject> f(scope, o->get(ctx->d()->engine->id_toString)); if (!f) - return ctx->throwTypeError(); + return ctx->engine()->throwTypeError(); ScopedCallData callData(scope, 0); callData->thisObject = o; return f->call(callData); @@ -491,12 +474,12 @@ ReturnedValue ObjectPrototype::method_propertyIsEnumerable(CallContext *ctx) ReturnedValue ObjectPrototype::method_defineGetter(CallContext *ctx) { if (ctx->d()->callData->argc < 2) - return ctx->throwTypeError(); + return ctx->engine()->throwTypeError(); Scope scope(ctx); Scoped<FunctionObject> f(scope, ctx->argument(1)); if (!f) - return ctx->throwTypeError(); + return ctx->engine()->throwTypeError(); Scoped<String> prop(scope, ctx->argument(0), Scoped<String>::Convert); if (scope.engine->hasException) @@ -519,12 +502,12 @@ ReturnedValue ObjectPrototype::method_defineGetter(CallContext *ctx) ReturnedValue ObjectPrototype::method_defineSetter(CallContext *ctx) { if (ctx->d()->callData->argc < 2) - return ctx->throwTypeError(); + return ctx->engine()->throwTypeError(); Scope scope(ctx); Scoped<FunctionObject> f(scope, ctx->argument(1)); if (!f) - return ctx->throwTypeError(); + return ctx->engine()->throwTypeError(); Scoped<String> prop(scope, ctx->argument(0), Scoped<String>::Convert); if (scope.engine->hasException) @@ -549,7 +532,7 @@ ReturnedValue ObjectPrototype::method_get_proto(CallContext *ctx) Scope scope(ctx); ScopedObject o(scope, ctx->d()->callData->thisObject.asObject()); if (!o) - return ctx->throwTypeError(); + return ctx->engine()->throwTypeError(); return o->prototype()->asReturnedValue(); } @@ -559,7 +542,7 @@ ReturnedValue ObjectPrototype::method_set_proto(CallContext *ctx) Scope scope(ctx); Scoped<Object> o(scope, ctx->d()->callData->thisObject); if (!o || !ctx->d()->callData->argc) - return ctx->throwTypeError(); + return ctx->engine()->throwTypeError(); if (ctx->d()->callData->args[0].isNull()) { o->setPrototype(0); @@ -576,7 +559,7 @@ ReturnedValue ObjectPrototype::method_set_proto(CallContext *ctx) } } if (!ok) - return ctx->throwTypeError(QStringLiteral("Cyclic __proto__ value")); + return ctx->engine()->throwTypeError(QStringLiteral("Cyclic __proto__ value")); return Encode::undefined(); } @@ -585,7 +568,7 @@ void ObjectPrototype::toPropertyDescriptor(ExecutionContext *ctx, const ValueRef Scope scope(ctx); ScopedObject o(scope, v); if (!o) { - ctx->throwTypeError(); + ctx->engine()->throwTypeError(); return; } @@ -606,7 +589,7 @@ void ObjectPrototype::toPropertyDescriptor(ExecutionContext *ctx, const ValueRef if (f || get->isUndefined()) { desc->value = get; } else { - ctx->throwTypeError(); + ctx->engine()->throwTypeError(); return; } attrs->setType(PropertyAttributes::Accessor); @@ -618,7 +601,7 @@ void ObjectPrototype::toPropertyDescriptor(ExecutionContext *ctx, const ValueRef if (f || set->isUndefined()) { desc->set = set; } else { - ctx->throwTypeError(); + ctx->engine()->throwTypeError(); return; } attrs->setType(PropertyAttributes::Accessor); @@ -626,7 +609,7 @@ void ObjectPrototype::toPropertyDescriptor(ExecutionContext *ctx, const ValueRef if (o->hasProperty(ctx->d()->engine->id_writable)) { if (attrs->isAccessor()) { - ctx->throwTypeError(); + ctx->engine()->throwTypeError(); return; } attrs->setWritable((tmp = o->get(ctx->d()->engine->id_writable))->toBoolean()); @@ -636,7 +619,7 @@ void ObjectPrototype::toPropertyDescriptor(ExecutionContext *ctx, const ValueRef if (o->hasProperty(ctx->d()->engine->id_value)) { if (attrs->isAccessor()) { - ctx->throwTypeError(); + ctx->engine()->throwTypeError(); return; } desc->value = o->get(ctx->d()->engine->id_value); diff --git a/src/qml/jsruntime/qv4property_p.h b/src/qml/jsruntime/qv4property_p.h index f9b3159033..601e3446f4 100644 --- a/src/qml/jsruntime/qv4property_p.h +++ b/src/qml/jsruntime/qv4property_p.h @@ -34,7 +34,7 @@ #define QV4PROPERTYDESCRIPTOR_H #include "qv4global_p.h" -#include "qv4value_inl_p.h" +#include "qv4value_p.h" #include "qv4internalclass_p.h" QT_BEGIN_NAMESPACE diff --git a/src/qml/jsruntime/qv4qobjectwrapper.cpp b/src/qml/jsruntime/qv4qobjectwrapper.cpp index f2c30e618f..cf59fe027c 100644 --- a/src/qml/jsruntime/qv4qobjectwrapper.cpp +++ b/src/qml/jsruntime/qv4qobjectwrapper.cpp @@ -443,7 +443,7 @@ void QObjectWrapper::setProperty(QObject *object, ExecutionContext *ctx, QQmlPro if (!property->isWritable() && !property->isQList()) { QString error = QLatin1String("Cannot assign to read-only property \"") + property->name(object) + QLatin1Char('\"'); - ctx->throwTypeError(error); + ctx->engine()->throwTypeError(error); return; } @@ -459,7 +459,7 @@ void QObjectWrapper::setProperty(QObject *object, ExecutionContext *ctx, QQmlPro error += QLatin1String("[unknown property type]"); else error += QLatin1String(QMetaType::typeName(property->propType)); - ctx->throwError(error); + ctx->engine()->throwError(error); return; } } else { @@ -511,7 +511,7 @@ void QObjectWrapper::setProperty(QObject *object, ExecutionContext *ctx, QQmlPro error += QLatin1String("[unknown property type]"); else error += QLatin1String(QMetaType::typeName(property->propType)); - ctx->throwError(error); + ctx->engine()->throwError(error); return; } else if (value->asFunctionObject()) { // this is handled by the binding creation above @@ -560,7 +560,7 @@ void QObjectWrapper::setProperty(QObject *object, ExecutionContext *ctx, QQmlPro QLatin1String(valueType) + QLatin1String(" to ") + QLatin1String(targetTypeName); - ctx->throwError(error); + ctx->engine()->throwError(error); return; } } @@ -693,7 +693,7 @@ void QObjectWrapper::put(Managed *m, String *name, const ValueRef value) if (ddata && ddata->context) { QString error = QLatin1String("Cannot assign to non-existent property \"") + name->toQString() + QLatin1Char('\"'); - v4->currentContext()->throwError(error); + v4->throwError(error); } else { QV4::Object::put(m, name, value); } @@ -985,11 +985,11 @@ static void markChildQObjectsRecursively(QObject *parent, QV4::ExecutionEngine * } } -void QObjectWrapper::markObjects(Managed *that, QV4::ExecutionEngine *e) +void QObjectWrapper::markObjects(HeapObject *that, QV4::ExecutionEngine *e) { - QObjectWrapper *This = static_cast<QObjectWrapper*>(that); + QObjectWrapper::Data *This = static_cast<QObjectWrapper::Data *>(that); - if (QObject *o = This->d()->object.data()) { + if (QObject *o = This->object.data()) { QQmlVMEMetaObject *vme = QQmlVMEMetaObject::get(o); if (vme) vme->mark(e); @@ -1374,7 +1374,7 @@ static QV4::ReturnedValue CallPrecise(QObject *object, const QQmlPropertyData &d if (returnType == QMetaType::UnknownType) { QString typeName = QString::fromLatin1(unknownTypeError); QString error = QString::fromLatin1("Unknown method return type: %1").arg(typeName); - return QV8Engine::getV4(engine)->currentContext()->throwError(error); + return QV8Engine::getV4(engine)->throwError(error); } if (data.hasArguments()) { @@ -1388,12 +1388,12 @@ static QV4::ReturnedValue CallPrecise(QObject *object, const QQmlPropertyData &d if (!args) { QString typeName = QString::fromLatin1(unknownTypeError); QString error = QString::fromLatin1("Unknown method parameter type: %1").arg(typeName); - return QV8Engine::getV4(engine)->currentContext()->throwError(error); + return QV8Engine::getV4(engine)->throwError(error); } if (args[0] > callArgs->argc) { QString error = QLatin1String("Insufficient arguments"); - return QV8Engine::getV4(engine)->currentContext()->throwError(error); + return QV8Engine::getV4(engine)->throwError(error); } return CallMethod(object, data.coreIndex, returnType, args[0], args + 1, engine, callArgs); @@ -1492,7 +1492,7 @@ static QV4::ReturnedValue CallOverloaded(QObject *object, const QQmlPropertyData candidate = RelatedMethod(object, candidate, dummy); } - return QV8Engine::getV4(engine)->currentContext()->throwError(error); + return QV8Engine::getV4(engine)->throwError(error); } } @@ -1793,7 +1793,7 @@ QV4::ReturnedValue QObjectMethod::method_destroy(QV4::ExecutionContext *ctx, con if (!d()->object) return Encode::undefined(); if (QQmlData::keepAliveDuringGarbageCollection(d()->object)) - return ctx->throwError(QStringLiteral("Invalid attempt to destroy() an indestructible object")); + return ctx->engine()->throwError(QStringLiteral("Invalid attempt to destroy() an indestructible object")); int delay = 0; if (argc > 0) diff --git a/src/qml/jsruntime/qv4qobjectwrapper_p.h b/src/qml/jsruntime/qv4qobjectwrapper_p.h index 1a31b5af4b..6458f03037 100644 --- a/src/qml/jsruntime/qv4qobjectwrapper_p.h +++ b/src/qml/jsruntime/qv4qobjectwrapper_p.h @@ -108,7 +108,7 @@ private: static void put(Managed *m, String *name, const ValueRef value); static PropertyAttributes query(const Managed *, String *name); static void advanceIterator(Managed *m, ObjectIterator *it, String *&name, uint *index, Property *p, PropertyAttributes *attributes); - static void markObjects(Managed *that, QV4::ExecutionEngine *e); + static void markObjects(HeapObject *that, QV4::ExecutionEngine *e); static void destroy(Managed *that); static ReturnedValue method_connect(CallContext *ctx); diff --git a/src/qml/jsruntime/qv4regexp.cpp b/src/qml/jsruntime/qv4regexp.cpp index e84c96f417..659221b0d9 100644 --- a/src/qml/jsruntime/qv4regexp.cpp +++ b/src/qml/jsruntime/qv4regexp.cpp @@ -63,17 +63,18 @@ uint RegExp::match(const QString &string, int start, uint *matchOffsets) return JSC::Yarr::interpret(byteCode().get(), s.characters16(), string.length(), start, matchOffsets); } -RegExp* RegExp::create(ExecutionEngine* engine, const QString& pattern, bool ignoreCase, bool multiline) +Returned<RegExp> *RegExp::create(ExecutionEngine* engine, const QString& pattern, bool ignoreCase, bool multiline) { RegExpCacheKey key(pattern, ignoreCase, multiline); RegExpCache *cache = engine->regExpCache; if (cache) { if (RegExp *result = cache->value(key)) - return result; + return Returned<RegExp>::create(result); } - RegExp *result = engine->memoryManager->alloc<RegExp>(engine, pattern, ignoreCase, multiline); + Scope scope(engine); + Scoped<RegExp> result(scope, engine->memoryManager->alloc<RegExp>(engine, pattern, ignoreCase, multiline)); if (!cache) cache = engine->regExpCache = new RegExpCache; @@ -81,7 +82,7 @@ RegExp* RegExp::create(ExecutionEngine* engine, const QString& pattern, bool ign result->d()->cache = cache; cache->insert(key, result); - return result; + return result.asReturned(); } RegExp::Data::Data(ExecutionEngine* engine, const QString &pattern, bool ignoreCase, bool multiline) @@ -118,7 +119,7 @@ void RegExp::destroy(Managed *that) static_cast<RegExp*>(that)->d()->~Data(); } -void RegExp::markObjects(Managed *that, ExecutionEngine *e) +void RegExp::markObjects(HeapObject *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 e2f43bf7d7..7aad1a32f2 100644 --- a/src/qml/jsruntime/qv4regexp_p.h +++ b/src/qml/jsruntime/qv4regexp_p.h @@ -85,7 +85,7 @@ struct RegExp : public Managed bool ignoreCase() const { return d()->ignoreCase; } bool multiLine() const { return d()->multiLine; } - static RegExp* create(ExecutionEngine* engine, const QString& pattern, bool ignoreCase = false, bool multiline = false); + static Returned<RegExp> *create(ExecutionEngine* engine, const QString& pattern, bool ignoreCase = false, bool multiline = false); bool isValid() const { return d()->byteCode.get(); } @@ -94,7 +94,7 @@ struct RegExp : public Managed int captureCount() const { return subPatternCount() + 1; } static void destroy(Managed *that); - static void markObjects(Managed *that, QV4::ExecutionEngine *e); + static void markObjects(HeapObject *that, QV4::ExecutionEngine *e); friend class RegExpCache; }; diff --git a/src/qml/jsruntime/qv4regexpobject.cpp b/src/qml/jsruntime/qv4regexpobject.cpp index c48175247e..23b46c8492 100644 --- a/src/qml/jsruntime/qv4regexpobject.cpp +++ b/src/qml/jsruntime/qv4regexpobject.cpp @@ -71,7 +71,7 @@ RegExpObject::Data::Data(InternalClass *ic) Scope scope(ic->engine); Scoped<RegExpObject> o(scope, this); - o->d()->value = reinterpret_cast<RegExp *>(RegExp::create(ic->engine, QString(), false, false)); + o->d()->value = RegExp::create(ic->engine, QString(), false, false)->getPointer(); o->d()->global = false; o->init(ic->engine); } @@ -139,7 +139,7 @@ RegExpObject::Data::Data(ExecutionEngine *engine, const QRegExp &re) Scope scope(engine); Scoped<RegExpObject> o(scope, this); - o->d()->value = reinterpret_cast<RegExp *>(RegExp::create(engine, pattern, re.caseSensitivity() == Qt::CaseInsensitive, false)); + o->d()->value = RegExp::create(engine, pattern, re.caseSensitivity() == Qt::CaseInsensitive, false)->getPointer(); o->init(engine); } @@ -170,11 +170,11 @@ void RegExpObject::init(ExecutionEngine *engine) } -void RegExpObject::markObjects(Managed *that, ExecutionEngine *e) +void RegExpObject::markObjects(HeapObject *that, ExecutionEngine *e) { - RegExpObject *re = static_cast<RegExpObject*>(that); - if (re->value()) - re->value()->mark(e); + RegExpObject::Data *re = static_cast<RegExpObject::Data *>(that); + if (re->value) + re->value->mark(e); Object::markObjects(that, e); } @@ -254,7 +254,7 @@ ReturnedValue RegExpCtor::construct(Managed *m, CallData *callData) Scoped<RegExpObject> re(scope, r); if (re) { if (!f->isUndefined()) - return ctx->throwTypeError(); + return ctx->engine()->throwTypeError(); return Encode(ctx->d()->engine->newRegExpObject(re->value(), re->global())); } @@ -281,14 +281,14 @@ ReturnedValue RegExpCtor::construct(Managed *m, CallData *callData) } else if (str.at(i) == QLatin1Char('m') && !multiLine) { multiLine = true; } else { - return ctx->throwSyntaxError(QStringLiteral("Invalid flags supplied to RegExp constructor")); + return ctx->engine()->throwSyntaxError(QStringLiteral("Invalid flags supplied to RegExp constructor")); } } } - RegExp *regexp = reinterpret_cast<RegExp *>(RegExp::create(ctx->d()->engine, pattern, ignoreCase, multiLine)); + Scoped<RegExp> regexp(scope, RegExp::create(ctx->d()->engine, pattern, ignoreCase, multiLine)); if (!regexp->isValid()) - return ctx->throwSyntaxError(QStringLiteral("Invalid regular expression")); + return ctx->engine()->throwSyntaxError(QStringLiteral("Invalid regular expression")); return Encode(ctx->d()->engine->newRegExpObject(regexp, global)); } @@ -303,11 +303,11 @@ ReturnedValue RegExpCtor::call(Managed *that, CallData *callData) return construct(that, callData); } -void RegExpCtor::markObjects(Managed *that, ExecutionEngine *e) +void RegExpCtor::markObjects(HeapObject *that, ExecutionEngine *e) { - RegExpCtor *This = static_cast<RegExpCtor*>(that); - This->lastMatch().mark(e); - This->lastInput().mark(e); + RegExpCtor::Data *This = static_cast<RegExpCtor::Data *>(that); + This->lastMatch.mark(e); + This->lastInput.mark(e); FunctionObject::markObjects(that, e); } @@ -353,7 +353,7 @@ ReturnedValue RegExpPrototype::method_exec(CallContext *ctx) Scope scope(ctx); Scoped<RegExpObject> r(scope, ctx->d()->callData->thisObject.as<RegExpObject>()); if (!r) - return ctx->throwTypeError(); + return ctx->engine()->throwTypeError(); ScopedValue arg(scope, ctx->argument(0)); arg = RuntimeHelpers::toString(ctx, arg); @@ -417,7 +417,7 @@ ReturnedValue RegExpPrototype::method_toString(CallContext *ctx) Scope scope(ctx); Scoped<RegExpObject> r(scope, ctx->d()->callData->thisObject.as<RegExpObject>()); if (!r) - return ctx->throwTypeError(); + return ctx->engine()->throwTypeError(); return ctx->d()->engine->newString(r->toString())->asReturnedValue(); } @@ -427,7 +427,7 @@ ReturnedValue RegExpPrototype::method_compile(CallContext *ctx) Scope scope(ctx); Scoped<RegExpObject> r(scope, ctx->d()->callData->thisObject.as<RegExpObject>()); if (!r) - return ctx->throwTypeError(); + return ctx->engine()->throwTypeError(); ScopedCallData callData(scope, ctx->d()->callData->argc); memcpy(callData->args, ctx->d()->callData->args, ctx->d()->callData->argc*sizeof(Value)); diff --git a/src/qml/jsruntime/qv4regexpobject_p.h b/src/qml/jsruntime/qv4regexpobject_p.h index e2f8049157..cf59ca12c0 100644 --- a/src/qml/jsruntime/qv4regexpobject_p.h +++ b/src/qml/jsruntime/qv4regexpobject_p.h @@ -91,7 +91,7 @@ struct RegExpObject: Object { uint flags() const; protected: - static void markObjects(Managed *that, ExecutionEngine *e); + static void markObjects(HeapObject *that, ExecutionEngine *e); }; struct RegExpCtor: FunctionObject @@ -113,7 +113,7 @@ struct RegExpCtor: FunctionObject static ReturnedValue construct(Managed *m, CallData *callData); static ReturnedValue call(Managed *that, CallData *callData); - static void markObjects(Managed *that, ExecutionEngine *e); + static void markObjects(HeapObject *that, ExecutionEngine *e); }; struct RegExpPrototype: RegExpObject diff --git a/src/qml/jsruntime/qv4runtime.cpp b/src/qml/jsruntime/qv4runtime.cpp index f72f25bd58..b817bc594b 100644 --- a/src/qml/jsruntime/qv4runtime.cpp +++ b/src/qml/jsruntime/qv4runtime.cpp @@ -35,11 +35,11 @@ #include "qv4runtime_p.h" #ifndef V4_BOOTSTRAP #include "qv4object_p.h" -#include "qv4jsir_p.h" #include "qv4objectproto_p.h" #include "qv4globalobject_p.h" #include "qv4stringobject_p.h" #include "qv4argumentsobject_p.h" +#include "qv4objectiterator_p.h" #include "qv4lookup_p.h" #include "qv4function_p.h" #include "private/qlocale_tools_p.h" @@ -300,7 +300,7 @@ QV4::ReturnedValue Runtime::instanceof(ExecutionContext *ctx, const ValueRef lef FunctionObject *f = right->asFunctionObject(); if (!f) - return ctx->throwTypeError(); + return ctx->engine()->throwTypeError(); if (f->subtype() == FunctionObject::BoundFunction) f = static_cast<BoundFunction *>(f)->target(); @@ -311,7 +311,7 @@ QV4::ReturnedValue Runtime::instanceof(ExecutionContext *ctx, const ValueRef lef Object *o = QV4::Value::fromReturnedValue(f->protoProperty()).asObject(); if (!o) - return ctx->throwTypeError(); + return ctx->engine()->throwTypeError(); while (v) { v = v->prototype(); @@ -328,7 +328,7 @@ QV4::ReturnedValue Runtime::instanceof(ExecutionContext *ctx, const ValueRef lef QV4::ReturnedValue Runtime::in(ExecutionContext *ctx, const ValueRef left, const ValueRef right) { if (!right->isObject()) - return ctx->throwTypeError(); + return ctx->engine()->throwTypeError(); Scope scope(ctx); ScopedString s(scope, left->toString(ctx)); if (scope.hasException()) @@ -406,7 +406,7 @@ ReturnedValue RuntimeHelpers::objectDefaultValue(Object *object, int typeHint) return r->asReturnedValue(); } - return ctx->throwTypeError(); + return ctx->engine()->throwTypeError(); } @@ -417,7 +417,7 @@ Returned<Object> *RuntimeHelpers::convertToObject(ExecutionContext *ctx, const V switch (value->type()) { case Value::Undefined_Type: case Value::Null_Type: - ctx->throwTypeError(); + ctx->engine()->throwTypeError(); return 0; case Value::Boolean_Type: return ctx->engine()->newBooleanObject(value); @@ -571,7 +571,7 @@ ReturnedValue Runtime::getElement(ExecutionContext *ctx, const ValueRef object, if (object->isNullOrUndefined()) { QString message = QStringLiteral("Cannot read property '%1' of %2").arg(index->toQStringNoThrow()).arg(object->toQStringNoThrow()); - return ctx->throwTypeError(message); + return ctx->engine()->throwTypeError(message); } o = RuntimeHelpers::convertToObject(ctx, object); @@ -625,8 +625,7 @@ ReturnedValue Runtime::foreachIterator(ExecutionContext *ctx, const ValueRef in) Scoped<Object> o(scope, (Object *)0); if (!in->isNullOrUndefined()) o = in->toObject(ctx); - Scoped<Object> it(scope, ctx->engine()->newForEachIteratorObject(ctx, o)); - return it.asReturnedValue(); + return ctx->engine()->newForEachIteratorObject(o)->asReturnedValue(); } ReturnedValue Runtime::foreachNextPropertyName(const ValueRef foreach_iterator) @@ -655,7 +654,7 @@ ReturnedValue Runtime::getProperty(ExecutionContext *ctx, const ValueRef object, if (object->isNullOrUndefined()) { QString message = QStringLiteral("Cannot read property '%1' of %2").arg(name->toQString()).arg(object->toQStringNoThrow()); - return ctx->throwTypeError(message); + return ctx->engine()->throwTypeError(message); } o = RuntimeHelpers::convertToObject(ctx, object); @@ -721,7 +720,7 @@ Bool RuntimeHelpers::strictEqual(const ValueRef x, const ValueRef y) if (x->isNumber()) return y->isNumber() && x->asDouble() == y->asDouble(); if (x->isManaged()) - return y->isManaged() && x->managed()->isEqualTo(y->managed()); + return y->isManaged() && x->cast<Managed>()->isEqualTo(y->cast<Managed>()); return false; } @@ -858,6 +857,25 @@ QV4::Bool Runtime::compareLessEqual(const QV4::ValueRef l, const QV4::ValueRef r } #ifndef V4_BOOTSTRAP +Bool Runtime::compareInstanceof(ExecutionContext *ctx, const ValueRef left, const ValueRef right) +{ + TRACE2(left, right); + + Scope scope(ctx); + ScopedValue v(scope, Runtime::instanceof(ctx, left, right)); + return v->booleanValue(); +} + +uint Runtime::compareIn(ExecutionContext *ctx, const ValueRef left, const ValueRef right) +{ + TRACE2(left, right); + + Scope scope(ctx); + ScopedValue v(scope, Runtime::in(ctx, left, right)); + return v->booleanValue(); +} + + ReturnedValue Runtime::callGlobalLookup(ExecutionContext *context, uint index, CallData *callData) { Scope scope(context); @@ -866,7 +884,7 @@ ReturnedValue Runtime::callGlobalLookup(ExecutionContext *context, uint index, C Lookup *l = context->d()->lookups + index; Scoped<FunctionObject> o(scope, l->globalGetter(l, context)); if (!o) - return context->throwTypeError(); + return context->engine()->throwTypeError(); if (o.getPointer() == scope.engine->evalFunction && l->name->equals(scope.engine->id_eval)) return static_cast<EvalFunction *>(o.getPointer())->evalCall(callData, true); @@ -881,7 +899,9 @@ ReturnedValue Runtime::callActivationProperty(ExecutionContext *context, String Scope scope(context); ScopedObject base(scope); - ScopedValue func(scope, context->getPropertyAndBase(name, base.ptr->o)); + Object *baseObj = 0; + ScopedValue func(scope, context->getPropertyAndBase(name, baseObj)); + base.ptr->m = baseObj ? &baseObj->data : 0; if (scope.engine->hasException) return Encode::undefined(); @@ -894,7 +914,7 @@ ReturnedValue Runtime::callActivationProperty(ExecutionContext *context, String if (base) objectAsString = ScopedValue(scope, base.asReturnedValue())->toQStringNoThrow(); QString msg = QStringLiteral("Property '%1' of object %2 is not a function").arg(name->toQString()).arg(objectAsString); - return context->throwTypeError(msg); + return context->engine()->throwTypeError(msg); } if (o == scope.engine->evalFunction && name->equals(scope.engine->id_eval)) { @@ -912,7 +932,7 @@ ReturnedValue Runtime::callProperty(ExecutionContext *context, String *name, Cal Q_ASSERT(!callData->thisObject.isEmpty()); if (callData->thisObject.isNullOrUndefined()) { QString message = QStringLiteral("Cannot call method '%1' of %2").arg(name->toQString()).arg(callData->thisObject.toQStringNoThrow()); - return context->throwTypeError(message); + return context->engine()->throwTypeError(message); } baseObject = RuntimeHelpers::convertToObject(context, ValueRef(&callData->thisObject)); @@ -924,7 +944,7 @@ ReturnedValue Runtime::callProperty(ExecutionContext *context, String *name, Cal Scoped<FunctionObject> o(scope, baseObject->get(name)); if (!o) { QString error = QStringLiteral("Property '%1' of object %2 is not a function").arg(name->toQString(), callData->thisObject.toQStringNoThrow()); - return context->throwTypeError(error); + return context->engine()->throwTypeError(error); } return o->call(callData); @@ -936,7 +956,7 @@ ReturnedValue Runtime::callPropertyLookup(ExecutionContext *context, uint index, Value v; v = l->getter(l, callData->thisObject); if (!v.isObject()) - return context->throwTypeError(); + return context->engine()->throwTypeError(); return v.objectValue()->call(callData); } @@ -953,7 +973,7 @@ ReturnedValue Runtime::callElement(ExecutionContext *context, const ValueRef ind ScopedObject o(scope, baseObject->get(s.getPointer())); if (!o) - return context->throwTypeError(); + return context->engine()->throwTypeError(); return o->call(callData); } @@ -961,7 +981,7 @@ ReturnedValue Runtime::callElement(ExecutionContext *context, const ValueRef ind ReturnedValue Runtime::callValue(ExecutionContext *context, const ValueRef func, CallData *callData) { if (!func->isObject()) - return context->throwTypeError(); + return context->engine()->throwTypeError(); return func->objectValue()->call(callData); } @@ -975,7 +995,7 @@ ReturnedValue Runtime::constructGlobalLookup(ExecutionContext *context, uint ind Lookup *l = context->d()->lookups + index; Scoped<Object> f(scope, l->globalGetter(l, context)); if (!f) - return context->throwTypeError(); + return context->engine()->throwTypeError(); return f->construct(callData); } @@ -990,7 +1010,7 @@ ReturnedValue Runtime::constructActivationProperty(ExecutionContext *context, St Object *f = func->asObject(); if (!f) - return context->throwTypeError(); + return context->engine()->throwTypeError(); return f->construct(callData); } @@ -999,7 +1019,7 @@ ReturnedValue Runtime::constructValue(ExecutionContext *context, const ValueRef { Object *f = func->asObject(); if (!f) - return context->throwTypeError(); + return context->engine()->throwTypeError(); return f->construct(callData); } @@ -1013,7 +1033,7 @@ ReturnedValue Runtime::constructProperty(ExecutionContext *context, String *name Scoped<Object> f(scope, thisObject->get(name)); if (!f) - return context->throwTypeError(); + return context->engine()->throwTypeError(); return f->construct(callData); } @@ -1024,7 +1044,7 @@ ReturnedValue Runtime::constructPropertyLookup(ExecutionContext *context, uint i Value v; v = l->getter(l, callData->thisObject); if (!v.isObject()) - return context->throwTypeError(); + return context->engine()->throwTypeError(); return v.objectValue()->construct(callData); } @@ -1033,7 +1053,7 @@ ReturnedValue Runtime::constructPropertyLookup(ExecutionContext *context, uint i void Runtime::throwException(ExecutionContext *context, const ValueRef value) { if (!value->isEmpty()) - context->throwError(value); + context->engine()->throwError(value); } ReturnedValue Runtime::typeofValue(ExecutionContext *ctx, const ValueRef value) @@ -1099,7 +1119,7 @@ ExecutionContext *Runtime::pushWithScope(const ValueRef o, ExecutionContext *ctx { Scope scope(ctx); ScopedObject obj(scope, o->toObject(ctx)); - return reinterpret_cast<ExecutionContext *>(ctx->newWithContext(obj)); + return ctx->newWithContext(obj)->getPointer(); } ReturnedValue Runtime::unwindException(ExecutionContext *ctx) @@ -1113,7 +1133,7 @@ ExecutionContext *Runtime::pushCatchScope(ExecutionContext *ctx, String *excepti { Scope scope(ctx); ScopedValue v(scope, ctx->engine()->catchException(ctx, 0)); - return reinterpret_cast<ExecutionContext *>(ctx->newCatchContext(exceptionVarName, v)); + return ctx->newCatchContext(exceptionVarName, v)->getPointer(); } ExecutionContext *Runtime::popScope(ExecutionContext *ctx) @@ -1300,7 +1320,7 @@ ReturnedValue Runtime::getQmlQObjectProperty(ExecutionContext *ctx, const ValueR Scope scope(ctx); QV4::Scoped<QObjectWrapper> wrapper(scope, object); if (!wrapper) { - ctx->throwTypeError(QStringLiteral("Cannot read property of null")); + ctx->engine()->throwTypeError(QStringLiteral("Cannot read property of null")); return Encode::undefined(); } return QV4::QObjectWrapper::getProperty(wrapper->object(), ctx, propertyIndex, captureRequired); @@ -1323,7 +1343,7 @@ ReturnedValue Runtime::getQmlSingletonQObjectProperty(ExecutionContext *ctx, con Scope scope(ctx); QV4::Scoped<QmlTypeWrapper> wrapper(scope, object); if (!wrapper) { - ctx->throwTypeError(QStringLiteral("Cannot read property of null")); + scope.engine->throwTypeError(QStringLiteral("Cannot read property of null")); return Encode::undefined(); } return QV4::QObjectWrapper::getProperty(wrapper->singletonObject(), ctx, propertyIndex, captureRequired); @@ -1334,7 +1354,7 @@ void Runtime::setQmlQObjectProperty(ExecutionContext *ctx, const ValueRef object Scope scope(ctx); QV4::Scoped<QObjectWrapper> wrapper(scope, object); if (!wrapper) { - ctx->throwTypeError(QStringLiteral("Cannot write property of null")); + ctx->engine()->throwTypeError(QStringLiteral("Cannot write property of null")); return; } wrapper->setProperty(ctx, propertyIndex, value); diff --git a/src/qml/jsruntime/qv4runtime_p.h b/src/qml/jsruntime/qv4runtime_p.h index 6042420291..f69ea1620c 100644 --- a/src/qml/jsruntime/qv4runtime_p.h +++ b/src/qml/jsruntime/qv4runtime_p.h @@ -35,20 +35,11 @@ #include "qv4global_p.h" #include "qv4value_inl_p.h" -#include "qv4math_p.h" -#include "qv4scopedvalue_p.h" #include "qv4context_p.h" +#include "qv4math_p.h" -#include <QtCore/QString> #include <QtCore/qnumeric.h> -#include <QtCore/QDebug> -#include <QtCore/qurl.h> -#include <cmath> -#include <cassert> -#include <limits> - -//#include <wtf/MathExtras.h> QT_BEGIN_NAMESPACE @@ -470,7 +461,7 @@ inline Bool Runtime::compareEqual(const ValueRef left, const ValueRef right) if (!left->isManaged()) return false; if (left->isString() == right->isString()) - return left->managed()->isEqualTo(right->managed()); + return left->cast<Managed>()->isEqualTo(right->cast<Managed>()); } return RuntimeHelpers::equalHelper(left, right); @@ -529,27 +520,6 @@ inline Bool Runtime::compareStrictNotEqual(const ValueRef left, const ValueRef r return ! RuntimeHelpers::strictEqual(left, right); } -#ifndef V4_BOOTSTRAP -inline Bool Runtime::compareInstanceof(ExecutionContext *ctx, const ValueRef left, const ValueRef right) -{ - TRACE2(left, right); - - Scope scope(ctx); - ScopedValue v(scope, Runtime::instanceof(ctx, left, right)); - return v->booleanValue(); -} - -inline uint Runtime::compareIn(ExecutionContext *ctx, const ValueRef left, const ValueRef right) -{ - TRACE2(left, right); - - Scope scope(ctx); - ScopedValue v(scope, Runtime::in(ctx, left, right)); - return v->booleanValue(); -} - -#endif // V4_BOOTSTRAP - inline Bool Runtime::toBoolean(const ValueRef value) { return value->toBoolean(); diff --git a/src/qml/jsruntime/qv4scopedvalue_p.h b/src/qml/jsruntime/qv4scopedvalue_p.h index b1b4d5da8d..90a3bf1602 100644 --- a/src/qml/jsruntime/qv4scopedvalue_p.h +++ b/src/qml/jsruntime/qv4scopedvalue_p.h @@ -36,6 +36,7 @@ #include "qv4engine_p.h" #include "qv4value_p.h" #include "qv4persistent_p.h" +#include "qv4property_p.h" QT_BEGIN_NAMESPACE @@ -112,7 +113,7 @@ struct ScopedValue ScopedValue(const Scope &scope, HeapObject *o) { ptr = scope.engine->jsStackTop++; - ptr->m = reinterpret_cast<Managed *>(o); + ptr->m = o; #if QT_POINTER_SIZE == 4 ptr->tag = QV4::Value::Managed_Type; #endif @@ -155,7 +156,7 @@ struct ScopedValue } ScopedValue &operator=(HeapObject *o) { - ptr->m = reinterpret_cast<Managed *>(o); + ptr->m = o; #if QT_POINTER_SIZE == 4 ptr->tag = QV4::Value::Managed_Type; #endif @@ -204,7 +205,7 @@ struct Scoped inline void setPointer(Managed *p) { #if QT_POINTER_SIZE == 8 - ptr->val = (quint64)p; + ptr->val = (quint64)(p ? &p->data : 0); #else *ptr = p ? QV4::Value::fromManaged(p) : QV4::Primitive::undefinedValue(); #endif @@ -230,7 +231,7 @@ struct Scoped Scoped(const Scope &scope, HeapObject *o) { Value v; - v.m = reinterpret_cast<Managed *>(o); + v.m = o; #if QT_POINTER_SIZE == 4 v.tag = QV4::Value::Managed_Type; #endif @@ -317,7 +318,7 @@ struct Scoped Scoped<T> &operator=(HeapObject *o) { Value v; - v.m = reinterpret_cast<Managed *>(o); + v.m = o; #if QT_POINTER_SIZE == 4 v.tag = QV4::Value::Managed_Type; #endif @@ -357,14 +358,14 @@ struct Scoped } T *operator->() { - return static_cast<T *>(ptr->managed()); + return ptr->cast<T>(); } bool operator!() const { - return !ptr->managed(); + return !ptr->m; } operator void *() const { - return ptr->managed(); + return ptr->m; } T *getPointer() { @@ -379,6 +380,8 @@ struct Scoped #endif } + Returned<T> *asReturned() const { return Returned<T>::create(static_cast<typename T::Data*>(ptr->heapObject())); } + Value *ptr; }; @@ -478,7 +481,7 @@ inline Returned<T> *Value::as() template<typename T> inline TypedValue<T> &TypedValue<T>::operator =(T *t) { - m = t; + m = t ? &t->data : 0; #if QT_POINTER_SIZE == 4 tag = Managed_Type; #endif @@ -488,7 +491,7 @@ inline TypedValue<T> &TypedValue<T>::operator =(T *t) template<typename T> inline TypedValue<T> &TypedValue<T>::operator =(const Scoped<T> &v) { - m = v.ptr->managed(); + m = v.ptr->m; #if QT_POINTER_SIZE == 4 tag = Managed_Type; #endif @@ -519,7 +522,7 @@ inline TypedValue<T> &TypedValue<T>::operator=(const TypedValue<T> &t) template<typename T> inline Returned<T> * TypedValue<T>::ret() const { - return Returned<T>::create(static_cast<T *>(managed())); + return Returned<T>::create(static_cast<typename T::Data *>(heapObject())); } inline Primitive::operator ValueRef() diff --git a/src/qml/jsruntime/qv4script.cpp b/src/qml/jsruntime/qv4script.cpp index fa4b4b1894..5c0c3f32ff 100644 --- a/src/qml/jsruntime/qv4script.cpp +++ b/src/qml/jsruntime/qv4script.cpp @@ -70,7 +70,7 @@ QmlBindingWrapper::Data::Data(ExecutionContext *scope, Function *f, Object *qml) o->defineReadonlyProperty(scope->d()->engine->id_length, Primitive::fromInt32(1)); - o->d()->qmlContext = reinterpret_cast<CallContext *>(s.engine->currentContext()->newQmlContext(o, qml)); + o->d()->qmlContext = s.engine->currentContext()->newQmlContext(o, qml)->getPointer(); s.engine->popContext(); } @@ -88,7 +88,7 @@ QmlBindingWrapper::Data::Data(ExecutionContext *scope, Object *qml) o->defineReadonlyProperty(scope->d()->engine->id_length, Primitive::fromInt32(1)); - o->d()->qmlContext = reinterpret_cast<CallContext *>(s.engine->currentContext()->newQmlContext(o, qml)); + o->d()->qmlContext = s.engine->currentContext()->newQmlContext(o, qml)->getPointer(); s.engine->popContext(); } @@ -111,14 +111,14 @@ ReturnedValue QmlBindingWrapper::call(Managed *that, CallData *) return result.asReturnedValue(); } -void QmlBindingWrapper::markObjects(Managed *m, ExecutionEngine *e) +void QmlBindingWrapper::markObjects(HeapObject *m, ExecutionEngine *e) { - QmlBindingWrapper *wrapper = static_cast<QmlBindingWrapper*>(m); - if (wrapper->d()->qml) - wrapper->d()->qml->mark(e); + QmlBindingWrapper::Data *wrapper = static_cast<QmlBindingWrapper::Data *>(m); + if (wrapper->qml) + wrapper->qml->mark(e); FunctionObject::markObjects(m, e); - if (wrapper->d()->qmlContext) - wrapper->d()->qmlContext->mark(e); + if (wrapper->qmlContext) + wrapper->qmlContext->mark(e); } static ReturnedValue signalParameterGetter(QV4::CallContext *ctx, uint parameterIndex) @@ -224,7 +224,7 @@ void Script::parse() foreach (const QQmlJS::DiagnosticMessage &m, parser.diagnosticMessages()) { if (m.isError()) { - scope->throwSyntaxError(m.message, sourceFile, m.loc.startLine, m.loc.startColumn); + scope->engine()->throwSyntaxError(m.message, sourceFile, m.loc.startLine, m.loc.startColumn); return; } else { qWarning() << sourceFile << ':' << m.loc.startLine << ':' << m.loc.startColumn @@ -268,7 +268,7 @@ void Script::parse() if (!vmFunction) { // ### FIX file/line number Scoped<Object> error(valueScope, v4->newSyntaxErrorObject(QStringLiteral("Syntax error"))); - v4->currentContext()->throwError(error); + v4->throwError(error); } } diff --git a/src/qml/jsruntime/qv4script_p.h b/src/qml/jsruntime/qv4script_p.h index ed93ce49ae..f12d5ad6fc 100644 --- a/src/qml/jsruntime/qv4script_p.h +++ b/src/qml/jsruntime/qv4script_p.h @@ -82,7 +82,7 @@ struct Q_QML_EXPORT QmlBindingWrapper : FunctionObject { V4_OBJECT(FunctionObject) static ReturnedValue call(Managed *that, CallData *); - static void markObjects(Managed *m, ExecutionEngine *e); + static void markObjects(HeapObject *m, ExecutionEngine *e); CallContext *context() const { return d()->qmlContext; } diff --git a/src/qml/jsruntime/qv4sequenceobject.cpp b/src/qml/jsruntime/qv4sequenceobject.cpp index 83bfb65658..c63e634025 100644 --- a/src/qml/jsruntime/qv4sequenceobject.cpp +++ b/src/qml/jsruntime/qv4sequenceobject.cpp @@ -39,7 +39,8 @@ #include <private/qv4arrayobject_p.h> #include <private/qqmlengine_p.h> #include <private/qv4scopedvalue_p.h> -#include <private/qv4internalclass_p.h> +#include "qv4runtime_p.h" +#include "qv4objectiterator_p.h" #include <algorithm> @@ -401,7 +402,7 @@ public: QV4::Scope scope(ctx); QV4::Scoped<QQmlSequence<Container> > This(scope, ctx->d()->callData->thisObject.as<QQmlSequence<Container> >()); if (!This) - return ctx->throwTypeError(); + return ctx->engine()->throwTypeError(); if (This->d()->isReference) { if (!This->d()->object) @@ -416,7 +417,7 @@ public: QV4::Scope scope(ctx); QV4::Scoped<QQmlSequence<Container> > This(scope, ctx->d()->callData->thisObject.as<QQmlSequence<Container> >()); if (!This) - return ctx->throwTypeError(); + return ctx->engine()->throwTypeError(); quint32 newLength = ctx->d()->callData->args[0].toUInt32(); /* Qt containers have int (rather than uint) allowable indexes. */ @@ -544,7 +545,7 @@ QV4::ReturnedValue SequencePrototype::method_sort(QV4::CallContext *ctx) QV4::Scope scope(ctx); QV4::ScopedObject o(scope, ctx->d()->callData->thisObject); if (!o || !o->isListType()) - return ctx->throwTypeError(); + return ctx->engine()->throwTypeError(); if (ctx->d()->callData->argc >= 2) return o.asReturnedValue(); diff --git a/src/qml/jsruntime/qv4sequenceobject_p.h b/src/qml/jsruntime/qv4sequenceobject_p.h index be348e524c..c0848ec0ba 100644 --- a/src/qml/jsruntime/qv4sequenceobject_p.h +++ b/src/qml/jsruntime/qv4sequenceobject_p.h @@ -50,6 +50,7 @@ #include "qv4value_inl_p.h" #include "qv4object_p.h" +#include "qv4context_p.h" QT_BEGIN_NAMESPACE diff --git a/src/qml/jsruntime/qv4string.cpp b/src/qml/jsruntime/qv4string.cpp index bd8a5ffccb..4ae10f6506 100644 --- a/src/qml/jsruntime/qv4string.cpp +++ b/src/qml/jsruntime/qv4string.cpp @@ -122,12 +122,12 @@ void String::destroy(Managed *that) static_cast<String*>(that)->d()->~Data(); } -void String::markObjects(Managed *that, ExecutionEngine *e) +void String::markObjects(HeapObject *that, ExecutionEngine *e) { - String *s = static_cast<String *>(that); - if (s->d()->largestSubLength) { - s->d()->left->mark(e); - s->d()->right->mark(e); + String::Data *s = static_cast<String::Data *>(that); + if (s->largestSubLength) { + s->left->mark(e); + s->right->mark(e); } } diff --git a/src/qml/jsruntime/qv4string_p.h b/src/qml/jsruntime/qv4string_p.h index ce0e1f9d73..1e53132fe3 100644 --- a/src/qml/jsruntime/qv4string_p.h +++ b/src/qml/jsruntime/qv4string_p.h @@ -154,7 +154,7 @@ struct Q_QML_PRIVATE_EXPORT String : public Managed { protected: static void destroy(Managed *); - static void markObjects(Managed *that, ExecutionEngine *e); + static void markObjects(HeapObject *that, ExecutionEngine *e); static ReturnedValue get(Managed *m, String *name, bool *hasProperty); static ReturnedValue getIndexed(Managed *m, uint index, bool *hasProperty); static void put(Managed *m, String *name, const ValueRef value); @@ -171,20 +171,6 @@ public: static uint toArrayIndex(const QString &str); }; -#ifndef V4_BOOTSTRAP -template<> -inline String *value_cast(const Value &v) { - return v.asString(); -} - -template<> -inline ReturnedValue value_convert<String>(ExecutionEngine *e, const Value &v) -{ - return v.toString(e)->asReturnedValue(); -} - -#endif - } QT_END_NAMESPACE diff --git a/src/qml/jsruntime/qv4stringobject.cpp b/src/qml/jsruntime/qv4stringobject.cpp index 397a6efdf8..19ef7892ad 100644 --- a/src/qml/jsruntime/qv4stringobject.cpp +++ b/src/qml/jsruntime/qv4stringobject.cpp @@ -109,13 +109,13 @@ bool StringObject::deleteIndexedProperty(Managed *m, uint index) Scope scope(v4); Scoped<StringObject> o(scope, m->asStringObject()); if (!o) { - v4->currentContext()->throwTypeError(); + v4->throwTypeError(); return false; } if (index < static_cast<uint>(o->d()->value.stringValue()->toQString().length())) { if (v4->currentContext()->d()->strictMode) - v4->currentContext()->throwTypeError(); + v4->throwTypeError(); return false; } return true; @@ -149,11 +149,11 @@ void StringObject::advanceIterator(Managed *m, ObjectIterator *it, String *&name return Object::advanceIterator(m, it, name, index, p, attrs); } -void StringObject::markObjects(Managed *that, ExecutionEngine *e) +void StringObject::markObjects(HeapObject *that, ExecutionEngine *e) { - StringObject *o = static_cast<StringObject *>(that); - o->d()->value.stringValue()->mark(e); - o->d()->tmpProperty.value.mark(e); + StringObject::Data *o = static_cast<StringObject::Data *>(that); + o->value.stringValue()->mark(e); + o->tmpProperty.value.mark(e); Object::markObjects(that, e); } @@ -230,7 +230,7 @@ static QString getThisString(ExecutionContext *ctx) if (StringObject *thisString = t->asStringObject()) return thisString->d()->value.stringValue()->toQString(); if (t->isUndefined() || t->isNull()) { - ctx->throwTypeError(); + ctx->engine()->throwTypeError(); return QString(); } return t->toQString(); @@ -243,7 +243,7 @@ ReturnedValue StringPrototype::method_toString(CallContext *context) StringObject *o = context->d()->callData->thisObject.asStringObject(); if (!o) - return context->throwTypeError(); + return context->engine()->throwTypeError(); return o->d()->value.asReturnedValue(); } @@ -365,7 +365,7 @@ ReturnedValue StringPrototype::method_localeCompare(CallContext *context) ReturnedValue StringPrototype::method_match(CallContext *context) { if (context->d()->callData->thisObject.isUndefined() || context->d()->callData->thisObject.isNull()) - return context->throwTypeError(); + return context->engine()->throwTypeError(); Scope scope(context); ScopedString s(scope, context->d()->callData->thisObject.toString(context)); @@ -380,7 +380,7 @@ ReturnedValue StringPrototype::method_match(CallContext *context) if (!rx) // ### CHECK - return context->throwTypeError(); + return context->engine()->throwTypeError(); bool global = rx->global(); diff --git a/src/qml/jsruntime/qv4stringobject_p.h b/src/qml/jsruntime/qv4stringobject_p.h index 5d3c0c9ccb..28e944c791 100644 --- a/src/qml/jsruntime/qv4stringobject_p.h +++ b/src/qml/jsruntime/qv4stringobject_p.h @@ -59,7 +59,7 @@ struct StringObject: Object { protected: static void advanceIterator(Managed *m, ObjectIterator *it, String *&name, uint *index, Property *p, PropertyAttributes *attrs); - static void markObjects(Managed *that, ExecutionEngine *e); + static void markObjects(HeapObject *that, ExecutionEngine *e); }; struct StringCtor: FunctionObject diff --git a/src/qml/jsruntime/qv4typedarray.cpp b/src/qml/jsruntime/qv4typedarray.cpp new file mode 100644 index 0000000000..72823efa12 --- /dev/null +++ b/src/qml/jsruntime/qv4typedarray.cpp @@ -0,0 +1,572 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the QtQml module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL21$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 or version 3 as published by the Free +** Software Foundation and appearing in the file LICENSE.LGPLv21 and +** LICENSE.LGPLv3 included in the packaging of this file. Please review the +** following information to ensure the GNU Lesser General Public License +** requirements will be met: https://www.gnu.org/licenses/lgpl.html and +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ +#include "qv4typedarray_p.h" +#include "qv4arraybuffer_p.h" + +using namespace QV4; + +DEFINE_OBJECT_VTABLE(TypedArrayCtor); +DEFINE_OBJECT_VTABLE(TypedArrayPrototype); +DEFINE_OBJECT_VTABLE(TypedArray); + +Q_STATIC_ASSERT((int)ExecutionEngine::NTypedArrayTypes == (int)TypedArray::NTypes); + +ReturnedValue Int8ArrayRead(const char *data, int index) +{ + return Encode((int)(signed char)data[index]); +} + +void Int8ArrayWrite(ExecutionEngine *e, char *data, int index, ValueRef value) +{ + signed char v = (signed char)value->toUInt32(); + if (e->hasException) + return; + data[index] = v; +} + +ReturnedValue UInt8ArrayRead(const char *data, int index) +{ + return Encode((int)(unsigned char)data[index]); +} + +void UInt8ArrayWrite(ExecutionEngine *e, char *data, int index, ValueRef value) +{ + unsigned char v = (unsigned char)value->toUInt32(); + if (e->hasException) + return; + data[index] = v; +} + +void UInt8ClampedArrayWrite(ExecutionEngine *e, char *data, int index, ValueRef value) +{ + if (value->isInteger()) { + data[index] = (char)(unsigned char)qBound(0, value->integerValue(), 255); + return; + } + double d = value->toNumber(); + if (e->hasException) + return; + // ### is there a way to optimise this? + if (d <= 0 || std::isnan(d)) { + data[index] = 0; + return; + } + if (d >= 255) { + data[index] = 255; + return; + } + double f = floor(d); + if (f + 0.5 < d) { + data[index] = (unsigned char)(f + 1); + return; + } + if (d < f + 0.5) { + data[index] = (unsigned char)(f); + return; + } + if (int(f) % 2) { + // odd number + data[index] = (unsigned char)(f + 1); + return; + } + data[index] = (unsigned char)(f); +} + +ReturnedValue Int16ArrayRead(const char *data, int index) +{ + return Encode((int)*(short *)(data + index)); +} + +void Int16ArrayWrite(ExecutionEngine *e, char *data, int index, ValueRef value) +{ + short v = (short)value->toInt32(); + if (e->hasException) + return; + *(short *)(data + index) = v; +} + +ReturnedValue UInt16ArrayRead(const char *data, int index) +{ + return Encode((int)*(unsigned short *)(data + index)); +} + +void UInt16ArrayWrite(ExecutionEngine *e, char *data, int index, ValueRef value) +{ + unsigned short v = (unsigned short)value->toInt32(); + if (e->hasException) + return; + *(unsigned short *)(data + index) = v; +} + +ReturnedValue Int32ArrayRead(const char *data, int index) +{ + return Encode(*(int *)(data + index)); +} + +void Int32ArrayWrite(ExecutionEngine *e, char *data, int index, ValueRef value) +{ + int v = (int)value->toInt32(); + if (e->hasException) + return; + *(int *)(data + index) = v; +} + +ReturnedValue UInt32ArrayRead(const char *data, int index) +{ + return Encode(*(unsigned int *)(data + index)); +} + +void UInt32ArrayWrite(ExecutionEngine *e, char *data, int index, ValueRef value) +{ + unsigned int v = (unsigned int)value->toUInt32(); + if (e->hasException) + return; + *(unsigned int *)(data + index) = v; +} + +ReturnedValue Float32ArrayRead(const char *data, int index) +{ + return Encode(*(float *)(data + index)); +} + +void Float32ArrayWrite(ExecutionEngine *e, char *data, int index, ValueRef value) +{ + float v = value->toNumber(); + if (e->hasException) + return; + *(float *)(data + index) = v; +} + +ReturnedValue Float64ArrayRead(const char *data, int index) +{ + return Encode(*(double *)(data + index)); +} + +void Float64ArrayWrite(ExecutionEngine *e, char *data, int index, ValueRef value) +{ + double v = value->toNumber(); + if (e->hasException) + return; + *(double *)(data + index) = v; +} + +const TypedArrayOperations operations[TypedArray::NTypes] = { + { 1, "Int8Array", Int8ArrayRead, Int8ArrayWrite }, + { 1, "Uint8Array", UInt8ArrayRead, UInt8ArrayWrite }, + { 1, "Uint8ClampedArray", UInt8ArrayRead, UInt8ClampedArrayWrite }, + { 2, "Int16Array", Int16ArrayRead, Int16ArrayWrite }, + { 2, "Uint16Array", UInt16ArrayRead, UInt16ArrayWrite }, + { 4, "Int32Array", Int32ArrayRead, Int32ArrayWrite }, + { 4, "Uint32Array", UInt32ArrayRead, UInt32ArrayWrite }, + { 4, "Float32Array", Float32ArrayRead, Float32ArrayWrite }, + { 8, "Float64Array", Float64ArrayRead, Float64ArrayWrite }, +}; + + +TypedArrayCtor::Data::Data(ExecutionContext *scope, TypedArray::Type t) + : FunctionObject::Data(scope, QLatin1String(operations[t].name)) + , type(t) +{ + setVTable(staticVTable()); +} + +ReturnedValue TypedArrayCtor::construct(Managed *m, CallData *callData) +{ + Scope scope(m->engine()); + Scoped<TypedArrayCtor> that(scope, static_cast<TypedArrayCtor *>(m)); + + if (!callData->argc || !callData->args[0].isObject()) { + // ECMA 6 22.2.1.1 + double l = callData->argc ? callData->args[0].toNumber() : 0; + if (scope.engine->hasException) + return Encode::undefined(); + uint len = (uint)l; + if (l != len) + scope.engine->throwRangeError(QStringLiteral("Non integer length for typed array.")); + uint byteLength = len * operations[that->d()->type].bytesPerElement; + Scoped<ArrayBuffer> buffer(scope, scope.engine->memoryManager->alloc<ArrayBuffer>(scope.engine, byteLength)); + if (scope.engine->hasException) + return Encode::undefined(); + + Scoped<TypedArray > array(scope, scope.engine->memoryManager->alloc<TypedArray>(scope.engine, that->d()->type)); + array->d()->buffer = buffer; + array->d()->byteLength = byteLength; + array->d()->byteOffset = 0; + + return array.asReturnedValue(); + } + Scoped<TypedArray> typedArray(scope, callData->argument(0)); + if (!!typedArray) { + // ECMA 6 22.2.1.2 + Scoped<ArrayBuffer> buffer(scope, typedArray->d()->buffer); + uint srcElementSize = typedArray->d()->type->bytesPerElement; + uint destElementSize = operations[that->d()->type].bytesPerElement; + uint byteLength = typedArray->d()->byteLength; + uint destByteLength = byteLength*destElementSize/srcElementSize; + + Scoped<ArrayBuffer> newBuffer(scope, scope.engine->memoryManager->alloc<ArrayBuffer>(scope.engine, destByteLength)); + if (scope.engine->hasException) + return Encode::undefined(); + + Scoped<TypedArray > array(scope, scope.engine->memoryManager->alloc<TypedArray>(scope.engine, that->d()->type)); + array->d()->buffer = newBuffer; + array->d()->byteLength = destByteLength; + array->d()->byteOffset = 0; + + const char *src = buffer->d()->data->data() + typedArray->d()->byteOffset; + char *dest = newBuffer->d()->data->data(); + + // check if src and new type have the same size. In that case we can simply memcpy the data + if (srcElementSize == destElementSize) { + memcpy(dest, src, byteLength); + } else { + // not same size, we need to loop + uint l = typedArray->length(); + TypedArrayRead read = typedArray->d()->type->read; + TypedArrayWrite write =array->d()->type->write; + for (uint i = 0; i < l; ++i) { + Primitive val; + val.val = read(src, i*srcElementSize); + write(scope.engine, dest, i*destElementSize, val); + } + } + + return array.asReturnedValue(); + } + Scoped<ArrayBuffer> buffer(scope, callData->argument(0)); + if (!!buffer) { + // ECMA 6 22.2.1.4 + + double dbyteOffset = callData->argc > 1 ? callData->args[1].toInteger() : 0; + uint byteOffset = (uint)dbyteOffset; + uint elementSize = operations[that->d()->type].bytesPerElement; + if (dbyteOffset < 0 || (byteOffset % elementSize) || dbyteOffset > buffer->byteLength()) + return scope.engine->throwRangeError(QStringLiteral("new TypedArray: invalid byteOffset")); + + uint byteLength; + if (callData->argc < 3 || callData->args[2].isUndefined()) { + byteLength = buffer->byteLength() - byteOffset; + if (buffer->byteLength() < byteOffset || byteLength % elementSize) + return scope.engine->throwRangeError(QStringLiteral("new TypedArray: invalid length")); + } else { + double l = qBound(0., callData->args[2].toInteger(), (double)UINT_MAX); + if (scope.engine->hasException) + return Encode::undefined(); + l *= elementSize; + if (buffer->byteLength() - byteOffset < l) + return scope.engine->throwRangeError(QStringLiteral("new TypedArray: invalid length")); + byteLength = (uint)l; + } + + Scoped<TypedArray > array(scope, scope.engine->memoryManager->alloc<TypedArray>(scope.engine, that->d()->type)); + array->d()->buffer = buffer; + array->d()->byteLength = byteLength; + array->d()->byteOffset = byteOffset; + return array.asReturnedValue(); + } + + // ECMA 6 22.2.1.3 + + ScopedObject o(scope, callData->argument(0)); + uint l = (uint) qBound(0., ScopedValue(scope, o->get(scope.engine->id_length))->toInteger(), (double)UINT_MAX); + if (scope.engine->hasException) + return scope.engine->throwTypeError(); + + uint elementSize = operations[that->d()->type].bytesPerElement; + Scoped<ArrayBuffer> newBuffer(scope, scope.engine->memoryManager->alloc<ArrayBuffer>(scope.engine, l * elementSize)); + if (scope.engine->hasException) + return Encode::undefined(); + + Scoped<TypedArray > array(scope, scope.engine->memoryManager->alloc<TypedArray>(scope.engine, that->d()->type)); + array->d()->buffer = newBuffer; + array->d()->byteLength = l * elementSize; + array->d()->byteOffset = 0; + + uint idx = 0; + char *b = newBuffer->d()->data->data(); + ScopedValue val(scope); + while (idx < l) { + val = o->getIndexed(idx); + array->d()->type->write(scope.engine, b, 0, val); + if (scope.engine->hasException) + return Encode::undefined(); + ++idx; + b += elementSize; + } + + + return array.asReturnedValue(); +} + +ReturnedValue TypedArrayCtor::call(Managed *that, CallData *callData) +{ + return construct(that, callData); +} + +TypedArray::Data::Data(ExecutionEngine *e, Type t) + : Object::Data(e->typedArrayClasses[t]), + type(operations + t) +{ +} + +void TypedArray::markObjects(HeapObject *that, ExecutionEngine *e) +{ + static_cast<TypedArray::Data *>(that)->buffer->mark(e); + Object::markObjects(that, e); +} + +ReturnedValue TypedArray::getIndexed(Managed *m, uint index, bool *hasProperty) +{ + Scope scope(m->engine()); + Scoped<TypedArray> a(scope, static_cast<TypedArray *>(m)); + + uint bytesPerElement = a->d()->type->bytesPerElement; + uint byteOffset = a->d()->byteOffset + index * bytesPerElement; + if (byteOffset + bytesPerElement > (uint)a->d()->buffer->byteLength()) { + if (hasProperty) + *hasProperty = false; + return Encode::undefined(); + } + if (hasProperty) + *hasProperty = true; + return a->d()->type->read(a->d()->buffer->d()->data->data(), byteOffset); +} + +void TypedArray::putIndexed(Managed *m, uint index, const ValueRef value) +{ + if (m->engine()->hasException) + return; + + Scope scope(m->engine()); + Scoped<TypedArray> a(scope, static_cast<TypedArray *>(m)); + + uint bytesPerElement = a->d()->type->bytesPerElement; + uint byteOffset = a->d()->byteOffset + index * bytesPerElement; + if (byteOffset + bytesPerElement > (uint)a->d()->buffer->byteLength()) + goto reject; + + a->d()->type->write(scope.engine, a->d()->buffer->d()->data->data(), byteOffset, value); + return; + +reject: + if (scope.engine->currentContext()->d()->strictMode) + scope.engine->throwTypeError(); +} + +void TypedArrayPrototype::init(ExecutionEngine *engine, TypedArrayCtor *ctor) +{ + Scope scope(engine); + ScopedObject o(scope); + ctor->defineReadonlyProperty(engine->id_length, Primitive::fromInt32(3)); + ctor->defineReadonlyProperty(engine->id_prototype, (o = this)); + ctor->defineReadonlyProperty(QStringLiteral("BYTES_PER_ELEMENT"), Primitive::fromInt32(operations[ctor->d()->type].bytesPerElement)); + defineDefaultProperty(engine->id_constructor, (o = ctor)); + defineAccessorProperty(QStringLiteral("buffer"), method_get_buffer, 0); + defineAccessorProperty(QStringLiteral("byteLength"), method_get_byteLength, 0); + defineAccessorProperty(QStringLiteral("byteOffset"), method_get_byteOffset, 0); + defineAccessorProperty(QStringLiteral("length"), method_get_length, 0); + defineReadonlyProperty(QStringLiteral("BYTES_PER_ELEMENT"), Primitive::fromInt32(operations[ctor->d()->type].bytesPerElement)); + + defineDefaultProperty(QStringLiteral("set"), method_set, 1); + defineDefaultProperty(QStringLiteral("subarray"), method_subarray, 0); +} + +ReturnedValue TypedArrayPrototype::method_get_buffer(CallContext *ctx) +{ + Scope scope(ctx); + Scoped<TypedArray> v(scope, ctx->d()->callData->thisObject); + if (!v) + return scope.engine->throwTypeError(); + + return Encode(v->d()->buffer->asReturnedValue()); +} + +ReturnedValue TypedArrayPrototype::method_get_byteLength(CallContext *ctx) +{ + Scope scope(ctx); + Scoped<TypedArray> v(scope, ctx->d()->callData->thisObject); + if (!v) + return scope.engine->throwTypeError(); + + return Encode(v->d()->byteLength); +} + +ReturnedValue TypedArrayPrototype::method_get_byteOffset(CallContext *ctx) +{ + Scope scope(ctx); + Scoped<TypedArray> v(scope, ctx->d()->callData->thisObject); + if (!v) + return scope.engine->throwTypeError(); + + return Encode(v->d()->byteOffset); +} + +ReturnedValue TypedArrayPrototype::method_get_length(CallContext *ctx) +{ + Scope scope(ctx); + Scoped<TypedArray> v(scope, ctx->d()->callData->thisObject); + if (!v) + return scope.engine->throwTypeError(); + + return Encode(v->d()->byteLength/v->d()->type->bytesPerElement); +} + +ReturnedValue TypedArrayPrototype::method_set(CallContext *ctx) +{ + Scope scope(ctx); + Scoped<TypedArray> a(scope, ctx->d()->callData->thisObject); + if (!a) + return scope.engine->throwTypeError(); + Scoped<ArrayBuffer> buffer(scope, a->d()->buffer); + if (!buffer) + scope.engine->throwTypeError(); + + double doffset = ctx->d()->callData->argc >= 2 ? ctx->d()->callData->args[1].toInteger() : 0; + if (scope.engine->hasException) + return Encode::undefined(); + + if (doffset < 0 || doffset >= UINT_MAX) + return scope.engine->throwRangeError(QStringLiteral("TypedArray.set: out of range")); + uint offset = (uint)doffset; + uint elementSize = a->d()->type->bytesPerElement; + + Scoped<TypedArray> srcTypedArray(scope, ctx->d()->callData->args[0]); + if (!srcTypedArray) { + // src is a regular object + ScopedObject o(scope, ctx->d()->callData->args[0].toObject(ctx)); + if (scope.engine->hasException || !o) + return scope.engine->throwTypeError(); + + double len = ScopedValue(scope, o->get(scope.engine->id_length))->toNumber(); + uint l = (uint)len; + if (scope.engine->hasException || l != len) + return scope.engine->throwTypeError(); + + if (offset + l > a->length()) + return scope.engine->throwRangeError(QStringLiteral("TypedArray.set: out of range")); + + uint idx = 0; + char *b = buffer->d()->data->data() + a->d()->byteOffset + offset*elementSize; + ScopedValue val(scope); + while (idx < l) { + val = o->getIndexed(idx); + a->d()->type->write(scope.engine, b, 0, val); + if (scope.engine->hasException) + return Encode::undefined(); + ++idx; + b += elementSize; + } + return Encode::undefined(); + } + + // src is a typed array + Scoped<ArrayBuffer> srcBuffer(scope, srcTypedArray->d()->buffer); + if (!srcBuffer) + return scope.engine->throwTypeError(); + + uint l = srcTypedArray->length(); + if (offset + l > a->length()) + return scope.engine->throwRangeError(QStringLiteral("TypedArray.set: out of range")); + + char *dest = buffer->d()->data->data() + a->d()->byteOffset + offset*elementSize; + const char *src = srcBuffer->d()->data->data() + srcTypedArray->d()->byteOffset; + if (srcTypedArray->d()->type == a->d()->type) { + // same type of typed arrays, use memmove (as srcbuffer and buffer could be the same) + memmove(dest, src, srcTypedArray->d()->byteLength); + return Encode::undefined(); + } + + char *srcCopy = 0; + if (buffer->d() == srcBuffer->d()) { + // same buffer, need to take a temporary copy, to not run into problems + srcCopy = new char[srcTypedArray->d()->byteLength]; + memcpy(srcCopy, src, srcTypedArray->d()->byteLength); + src = srcCopy; + } + + // typed arrays of different kind, need to manually loop + uint srcElementSize = srcTypedArray->d()->type->bytesPerElement; + TypedArrayRead read = srcTypedArray->d()->type->read; + TypedArrayWrite write = a->d()->type->write; + for (uint i = 0; i < l; ++i) { + Primitive val; + val.val = read(src, i*srcElementSize); + write(scope.engine, dest, i*elementSize, val); + } + + if (srcCopy) + delete [] srcCopy; + + return Encode::undefined(); +} + +ReturnedValue TypedArrayPrototype::method_subarray(CallContext *ctx) +{ + Scope scope(ctx); + Scoped<TypedArray> a(scope, ctx->d()->callData->thisObject); + + if (!a) + return scope.engine->throwTypeError(); + + Scoped<ArrayBuffer> buffer(scope, a->d()->buffer); + if (!buffer) + return scope.engine->throwTypeError(); + + int len = a->length(); + double b = ctx->d()->callData->argc > 0 ? ctx->d()->callData->args[0].toInteger() : 0; + if (b < 0) + b = len + b; + uint begin = (uint)qBound(0., b, (double)len); + + double e = ctx->d()->callData->argc < 2 || ctx->d()->callData->args[1].isUndefined() ? len : ctx->d()->callData->args[1].toInteger(); + if (e < 0) + e = len + e; + uint end = (uint)qBound(0., e, (double)len); + if (end < begin) + end = begin; + + if (scope.engine->hasException) + return Encode::undefined(); + + int newLen = end - begin; + + Scoped<FunctionObject> constructor(scope, a->get(scope.engine->id_constructor)); + if (!constructor) + return scope.engine->throwTypeError(); + + ScopedCallData callData(scope, 3); + callData->args[0] = buffer; + callData->args[1] = Encode(a->d()->byteOffset + begin*a->d()->type->bytesPerElement); + callData->args[2] = Encode(newLen); + return constructor->construct(callData); +} diff --git a/src/qml/jsruntime/qv4typedarray_p.h b/src/qml/jsruntime/qv4typedarray_p.h new file mode 100644 index 0000000000..28847e0c85 --- /dev/null +++ b/src/qml/jsruntime/qv4typedarray_p.h @@ -0,0 +1,133 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the QtQml module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL21$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 or version 3 as published by the Free +** Software Foundation and appearing in the file LICENSE.LGPLv21 and +** LICENSE.LGPLv3 included in the packaging of this file. Please review the +** following information to ensure the GNU Lesser General Public License +** requirements will be met: https://www.gnu.org/licenses/lgpl.html and +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ +#ifndef QV4TYPEDARRAY_H +#define QV4TYPEDARRAY_H + +#include "qv4object_p.h" +#include "qv4functionobject_p.h" + +QT_BEGIN_NAMESPACE + +namespace QV4 { + +struct ArrayBuffer; + +typedef ReturnedValue (*TypedArrayRead)(const char *data, int index); +typedef void (*TypedArrayWrite)(ExecutionEngine *engine, char *data, int index, ValueRef value); + +struct TypedArrayOperations { + int bytesPerElement; + const char *name; + TypedArrayRead read; + TypedArrayWrite write; +}; + +struct TypedArray : Object +{ + enum Type { + Int8Array, + UInt8Array, + UInt8ClampedArray, + Int16Array, + UInt16Array, + Int32Array, + UInt32Array, + Float32Array, + Float64Array, + NTypes + }; + + struct Data : Object::Data { + Data(ExecutionEngine *e, Type t); + + const TypedArrayOperations *type; + ArrayBuffer *buffer; + uint byteLength; + uint byteOffset; + }; + V4_OBJECT(Object) + + uint length() const { + return d()->byteLength/d()->type->bytesPerElement; + } + + + static void markObjects(HeapObject *that, ExecutionEngine *e); + static ReturnedValue getIndexed(Managed *m, uint index, bool *hasProperty); + static void putIndexed(Managed *m, uint index, const ValueRef value); +}; + +struct TypedArrayCtor: FunctionObject +{ + struct Data : FunctionObject::Data { + Data(ExecutionContext *scope, TypedArray::Type t); + + TypedArray::Type type; + }; + + V4_OBJECT(FunctionObject) + + static ReturnedValue construct(Managed *m, CallData *callData); + static ReturnedValue call(Managed *that, CallData *callData); +}; + + +struct TypedArrayPrototype : Object +{ + struct Data : Object::Data { + Data(ExecutionEngine *e, TypedArray::Type t) + : Object::Data(e) + , type(t) + { + setVTable(staticVTable()); + } + TypedArray::Type type; + }; + V4_OBJECT(Object) + + void init(ExecutionEngine *engine, TypedArrayCtor *ctor); + + static ReturnedValue method_get_buffer(CallContext *ctx); + static ReturnedValue method_get_byteLength(CallContext *ctx); + static ReturnedValue method_get_byteOffset(CallContext *ctx); + static ReturnedValue method_get_length(CallContext *ctx); + + static ReturnedValue method_set(CallContext *ctx); + static ReturnedValue method_subarray(CallContext *ctx); +}; + +} // namespace QV4 + +QT_END_NAMESPACE + +#endif diff --git a/src/qml/jsruntime/qv4value.cpp b/src/qml/jsruntime/qv4value.cpp index 0293054457..a80cc40add 100644 --- a/src/qml/jsruntime/qv4value.cpp +++ b/src/qml/jsruntime/qv4value.cpp @@ -31,6 +31,7 @@ ** ****************************************************************************/ #include <qv4engine_p.h> +#include <qv4runtime_p.h> #ifndef V4_BOOTSTRAP #include <qv4object_p.h> #include <qv4objectproto_p.h> diff --git a/src/qml/jsruntime/qv4value_inl_p.h b/src/qml/jsruntime/qv4value_inl_p.h index 045eaccfaf..2600148417 100644 --- a/src/qml/jsruntime/qv4value_inl_p.h +++ b/src/qml/jsruntime/qv4value_inl_p.h @@ -35,18 +35,11 @@ #include <cmath> // this HAS to come -#include <QtCore/QString> -#include <QtCore/qnumeric.h> -#include "qv4global_p.h" +#include "qv4value_p.h" + #include "qv4string_p.h" -#include <QtCore/QDebug> #include "qv4managed_p.h" #include "qv4engine_p.h" -#include <private/qtqmlglobal_p.h> - -//#include <wtf/MathExtras.h> - -#include "qv4value_p.h" QT_BEGIN_NAMESPACE @@ -56,13 +49,13 @@ inline bool Value::isString() const { if (!isManaged()) return false; - return managed() && managed()->internalClass()->vtable->isString; + return m && static_cast<Managed::Data *>(m)->internalClass->vtable->isString; } inline bool Value::isObject() const { if (!isManaged()) return false; - return managed() && managed()->internalClass()->vtable->isObject; + return m && static_cast<Managed::Data *>(m)->internalClass->vtable->isObject; } inline bool Value::isPrimitive() const @@ -70,6 +63,13 @@ inline bool Value::isPrimitive() const return !isObject(); } +inline String *Value::asString() const +{ + if (isString()) + return stringValue(); + return 0; +} + inline ExecutionEngine *Value::engine() const { Managed *m = asManaged(); @@ -275,6 +275,21 @@ inline ErrorObject *Value::asErrorObject() const template<typename T> inline T *Value::as() const { Managed *m = isObject() ? managed() : 0; return m ? m->as<T>() : 0; } +#ifndef V4_BOOTSTRAP + +template<> +inline String *value_cast(const Value &v) { + return v.asString(); +} + +template<> +inline ReturnedValue value_convert<String>(ExecutionEngine *e, const Value &v) +{ + return v.toString(e)->asReturnedValue(); +} + +#endif + #endif } // namespace QV4 diff --git a/src/qml/jsruntime/qv4value_p.h b/src/qml/jsruntime/qv4value_p.h index 59a4543538..fa2d544fcf 100644 --- a/src/qml/jsruntime/qv4value_p.h +++ b/src/qml/jsruntime/qv4value_p.h @@ -44,19 +44,54 @@ namespace QV4 { typedef uint Bool; +struct Q_QML_EXPORT HeapObject { + HeapObject(InternalClass *internal) + : internalClass(internal) + , markBit(0) + , inUse(1) + , extensible(1) + { + // #### + // Q_ASSERT(internal && internal->vtable); + } + InternalClass *internalClass; + struct { + uchar markBit : 1; + uchar inUse : 1; + uchar extensible : 1; // used by Object + uchar _unused : 1; + uchar needsActivation : 1; // used by FunctionObject + uchar strictMode : 1; // used by FunctionObject + uchar bindingKeyFlag : 1; + uchar hasAccessorProperty : 1; + uchar _type; + mutable uchar subtype; + uchar _flags; + + }; + + void setVTable(const ManagedVTable *vt); + inline ReturnedValue asReturnedValue() const; + inline void mark(QV4::ExecutionEngine *engine); + + void *operator new(size_t, Managed *m) { return m; } + void *operator new(size_t, HeapObject *m) { return m; } + void operator delete(void *, HeapObject *) {} +}; + template <typename T> -struct Returned : private T +struct Returned : private HeapObject { - static Returned<T> *create(T *t) { return static_cast<Returned<T> *>(t); } - T *getPointer() { return this; } + static Returned<T> *create(T *t) { Q_ASSERT((void *)&t->data == (void *)t); return static_cast<Returned<T> *>(static_cast<HeapObject*>(t ? &t->data : 0)); } + static Returned<T> *create(typename T::Data *t) { return static_cast<Returned<T> *>(static_cast<HeapObject*>(t)); } + T *getPointer() { return reinterpret_cast<T *>(this); } template<typename X> static T *getPointer(Returned<X> *x) { return x->getPointer(); } template<typename X> Returned<X> *as() { return Returned<X>::create(Returned<X>::getPointer(this)); } - using T::asReturnedValue; -}; -struct HeapObject {}; + inline ReturnedValue asReturnedValue(); +}; struct Q_QML_PRIVATE_EXPORT Value { @@ -86,9 +121,7 @@ struct Q_QML_PRIVATE_EXPORT Value union { quint64 val; #if QT_POINTER_SIZE == 8 - Managed *m; - Object *o; - String *s; + HeapObject *m; #else double dbl; #endif @@ -100,9 +133,7 @@ struct Q_QML_PRIVATE_EXPORT Value uint uint_32; int int_32; #if QT_POINTER_SIZE == 4 - Managed *m; - Object *o; - String *s; + HeapObject *m; #endif }; #if Q_BYTE_ORDER == Q_LITTLE_ENDIAN @@ -270,12 +301,15 @@ struct Q_QML_PRIVATE_EXPORT Value } String *stringValue() const { - return s; + return m ? reinterpret_cast<String*>(m) : 0; } Object *objectValue() const { - return o; + return m ? reinterpret_cast<Object*>(m) : 0; } Managed *managed() const { + return m ? reinterpret_cast<Managed*>(m) : 0; + } + HeapObject *heapObject() const { return m; } @@ -283,7 +317,17 @@ struct Q_QML_PRIVATE_EXPORT Value return val; } - static inline Value fromManaged(Managed *o); + static inline Value fromHeapObject(HeapObject *m) + { + Value v; + v.m = m; +#if QT_POINTER_SIZE == 4 + v.tag = Managed_Type; +#endif + return v; + } + + static inline Value fromManaged(Managed *m); int toUInt16() const; inline int toInt32() const; @@ -318,6 +362,12 @@ struct Q_QML_PRIVATE_EXPORT Value inline ErrorObject *asErrorObject() const; template<typename T> inline T *as() const; + template<typename T> inline T *cast() { + return static_cast<T *>(managed()); + } + template<typename T> inline const T *cast() const { + return static_cast<const T *>(managed()); + } inline uint asArrayIndex() const; inline uint asArrayLength(bool *ok) const; @@ -342,7 +392,7 @@ struct Q_QML_PRIVATE_EXPORT Value return *this; } Value &operator=(HeapObject *o) { - m = reinterpret_cast<Managed *>(o); + m = o; return *this; } @@ -364,13 +414,6 @@ inline Managed *Value::asManaged() const return 0; } -inline String *Value::asString() const -{ - if (isString()) - return stringValue(); - return 0; -} - struct Q_QML_PRIVATE_EXPORT Primitive : public Value { inline static Primitive emptyValue(); @@ -409,20 +452,6 @@ inline Primitive Primitive::emptyValue() return v; } -inline Value Value::fromManaged(Managed *m) -{ - if (!m) - return QV4::Primitive::undefinedValue(); - Value v; -#if QT_POINTER_SIZE == 8 - v.m = m; -#else - v.tag = Managed_Type; - v.m = m; -#endif - return v; -} - template <typename T> struct TypedValue : public Value { @@ -546,11 +575,17 @@ struct ValueRef { ReturnedValue asReturnedValue() const { return ptr->val; } // ### get rid of this one! - ValueRef(Value *v) { ptr = reinterpret_cast<Value *>(v); } + ValueRef(Value *v) { ptr = v; } private: Value *ptr; }; +inline +ReturnedValue HeapObject::asReturnedValue() const +{ + return Value::fromHeapObject(const_cast<HeapObject *>(this)).asReturnedValue(); +} + template<typename T> T *value_cast(const Value &v) @@ -561,7 +596,8 @@ T *value_cast(const Value &v) template<typename T> ReturnedValue value_convert(ExecutionEngine *e, const Value &v); - +template <typename T> +ReturnedValue Returned<T>::asReturnedValue() { return Value::fromHeapObject(this).asReturnedValue(); } } diff --git a/src/qml/jsruntime/qv4vme_moth.cpp b/src/qml/jsruntime/qv4vme_moth.cpp index cd73314bce..35ac5eac5f 100644 --- a/src/qml/jsruntime/qv4vme_moth.cpp +++ b/src/qml/jsruntime/qv4vme_moth.cpp @@ -184,7 +184,7 @@ QV4::ReturnedValue VME::run(QV4::ExecutionContext *context, const uchar *code qDebug("Starting VME with context=%p and code=%p", context, code); #endif // DO_TRACE_INSTR - QV4::StringValue * const runtimeStrings = context->d()->compilationUnit->runtimeStrings; + QV4::String ** const runtimeStrings = context->d()->compilationUnit->runtimeStrings; // setup lookup scopes int scopeDepth = 0; @@ -240,7 +240,7 @@ QV4::ReturnedValue VME::run(QV4::ExecutionContext *context, const uchar *code MOTH_BEGIN_INSTR(LoadRuntimeString) // TRACE(value, "%s", instr.value.toString(context)->toQString().toUtf8().constData()); - VALUE(instr.result) = runtimeStrings[instr.stringId].asReturnedValue(); + VALUE(instr.result) = runtimeStrings[instr.stringId]->asReturnedValue(); MOTH_END_INSTR(LoadRuntimeString) MOTH_BEGIN_INSTR(LoadRegExp) diff --git a/src/qml/qml/qqmlboundsignal.cpp b/src/qml/qml/qqmlboundsignal.cpp index 26fe659616..cabb76db48 100644 --- a/src/qml/qml/qqmlboundsignal.cpp +++ b/src/qml/qml/qqmlboundsignal.cpp @@ -76,8 +76,8 @@ QQmlBoundSignalExpression::QQmlBoundSignalExpression(QObject *target, int index, const QString &handlerName, const QString ¶meterString) : QQmlJavaScriptExpression(&QQmlBoundSignalExpression_jsvtable), - m_target(target), m_index(index), + m_target(target), m_extra(new ExtraData(handlerName, parameterString, expression, fileName, line, column)) { setExpressionFunctionValid(false); @@ -88,9 +88,9 @@ QQmlBoundSignalExpression::QQmlBoundSignalExpression(QObject *target, int index, QQmlBoundSignalExpression::QQmlBoundSignalExpression(QObject *target, int index, QQmlContextData *ctxt, QObject *scope, const QV4::ValueRef &function) : QQmlJavaScriptExpression(&QQmlBoundSignalExpression_jsvtable), + m_index(index), m_v8function(function), m_target(target), - m_index(index), m_extra(0) { setExpressionFunctionValid(true); @@ -101,8 +101,8 @@ QQmlBoundSignalExpression::QQmlBoundSignalExpression(QObject *target, int index, QQmlBoundSignalExpression::QQmlBoundSignalExpression(QObject *target, int index, QQmlContextData *ctxt, QObject *scope, QV4::Function *runtimeFunction) : QQmlJavaScriptExpression(&QQmlBoundSignalExpression_jsvtable), - m_target(target), m_index(index), + m_target(target), m_extra(0) { setExpressionFunctionValid(true); diff --git a/src/qml/qml/qqmlboundsignal_p.h b/src/qml/qml/qqmlboundsignal_p.h index b9f519a920..d2fec2afc8 100644 --- a/src/qml/qml/qqmlboundsignal_p.h +++ b/src/qml/qml/qqmlboundsignal_p.h @@ -98,10 +98,10 @@ private: bool invalidParameterName() const { return m_extra.flag2(); } void setInvalidParameterName(bool v) { m_extra.setFlag2Value(v); } + int m_index; QV4::PersistentValue m_v8function; QObject *m_target; - int m_index; // only needed when !expressionFunctionValid() struct ExtraData { diff --git a/src/qml/qml/qqmlcomponent.cpp b/src/qml/qml/qqmlcomponent.cpp index 63a43966b1..980fc99b92 100644 --- a/src/qml/qml/qqmlcomponent.cpp +++ b/src/qml/qml/qqmlcomponent.cpp @@ -1090,7 +1090,7 @@ struct QmlIncubatorObject : public QV4::Object static QV4::ReturnedValue method_forceCompletion(QV4::CallContext *ctx); static void destroy(Managed *that); - static void markObjects(Managed *that, QV4::ExecutionEngine *e); + static void markObjects(QV4::HeapObject *that, QV4::ExecutionEngine *e); void statusChanged(QQmlIncubator::Status); void setInitialState(QObject *); @@ -1416,7 +1416,7 @@ QV4::ReturnedValue QmlIncubatorObject::method_get_object(QV4::CallContext *ctx) QV4::Scope scope(ctx); QV4::Scoped<QmlIncubatorObject> o(scope, ctx->d()->callData->thisObject.as<QmlIncubatorObject>()); if (!o) - return ctx->throwTypeError(); + return ctx->engine()->throwTypeError(); return QV4::QObjectWrapper::wrap(ctx->d()->engine, o->d()->incubator->object()); } @@ -1426,7 +1426,7 @@ QV4::ReturnedValue QmlIncubatorObject::method_forceCompletion(QV4::CallContext * QV4::Scope scope(ctx); QV4::Scoped<QmlIncubatorObject> o(scope, ctx->d()->callData->thisObject.as<QmlIncubatorObject>()); if (!o) - return ctx->throwTypeError(); + return ctx->engine()->throwTypeError(); o->d()->incubator->forceCompletion(); @@ -1438,7 +1438,7 @@ QV4::ReturnedValue QmlIncubatorObject::method_get_status(QV4::CallContext *ctx) QV4::Scope scope(ctx); QV4::Scoped<QmlIncubatorObject> o(scope, ctx->d()->callData->thisObject.as<QmlIncubatorObject>()); if (!o) - return ctx->throwTypeError(); + return ctx->engine()->throwTypeError(); return QV4::Encode(o->d()->incubator->status()); } @@ -1448,7 +1448,7 @@ QV4::ReturnedValue QmlIncubatorObject::method_get_statusChanged(QV4::CallContext QV4::Scope scope(ctx); QV4::Scoped<QmlIncubatorObject> o(scope, ctx->d()->callData->thisObject.as<QmlIncubatorObject>()); if (!o) - return ctx->throwTypeError(); + return ctx->engine()->throwTypeError(); return o->d()->statusChanged.asReturnedValue(); } @@ -1458,7 +1458,7 @@ QV4::ReturnedValue QmlIncubatorObject::method_set_statusChanged(QV4::CallContext QV4::Scope scope(ctx); QV4::Scoped<QmlIncubatorObject> o(scope, ctx->d()->callData->thisObject.as<QmlIncubatorObject>()); if (!o || ctx->d()->callData->argc < 1) - return ctx->throwTypeError(); + return ctx->engine()->throwTypeError(); o->d()->statusChanged = ctx->d()->callData->args[0]; @@ -1503,13 +1503,12 @@ void QmlIncubatorObject::destroy(Managed *that) static_cast<QmlIncubatorObject *>(that)->d()->~Data(); } -void QmlIncubatorObject::markObjects(QV4::Managed *that, QV4::ExecutionEngine *e) +void QmlIncubatorObject::markObjects(QV4::HeapObject *that, QV4::ExecutionEngine *e) { - QmlIncubatorObject *o = static_cast<QmlIncubatorObject *>(that); - Q_ASSERT(that->as<QmlIncubatorObject>()); - o->d()->valuemap.mark(e); - o->d()->qmlGlobal.mark(e); - o->d()->statusChanged.mark(e); + QmlIncubatorObject::Data *o = static_cast<QmlIncubatorObject::Data *>(that); + o->valuemap.mark(e); + o->qmlGlobal.mark(e); + o->statusChanged.mark(e); Object::markObjects(that, e); } diff --git a/src/qml/qml/qqmlcontextwrapper.cpp b/src/qml/qml/qqmlcontextwrapper.cpp index 0816bc05df..df62f285e3 100644 --- a/src/qml/qml/qqmlcontextwrapper.cpp +++ b/src/qml/qml/qqmlcontextwrapper.cpp @@ -291,7 +291,7 @@ void QmlContextWrapper::put(Managed *m, String *name, const ValueRef value) QString error = QLatin1String("Invalid write to global property \"") + name->toQString() + QLatin1Char('"'); Scoped<String> e(scope, v4->currentContext()->d()->engine->newString(error)); - v4->currentContext()->throwError(e); + v4->throwError(e); return; } @@ -335,7 +335,7 @@ void QmlContextWrapper::put(Managed *m, String *name, const ValueRef value) if (wrapper->d()->readOnly) { QString error = QLatin1String("Invalid write to global property \"") + name->toQString() + QLatin1Char('"'); - v4->currentContext()->throwError(error); + v4->throwError(error); return; } @@ -347,11 +347,11 @@ void QmlContextWrapper::destroy(Managed *that) static_cast<QmlContextWrapper *>(that)->d()->~Data(); } -void QmlContextWrapper::markObjects(Managed *m, ExecutionEngine *engine) +void QmlContextWrapper::markObjects(HeapObject *m, ExecutionEngine *engine) { - QmlContextWrapper *This = static_cast<QmlContextWrapper*>(m); - if (This->d()->idObjectsWrapper) - This->d()->idObjectsWrapper->mark(engine); + QmlContextWrapper::Data *This = static_cast<QmlContextWrapper::Data *>(m); + if (This->idObjectsWrapper) + This->idObjectsWrapper->mark(engine); Object::markObjects(m, engine); } @@ -465,10 +465,10 @@ ReturnedValue QQmlIdObjectsArray::getIndexed(Managed *m, uint index, bool *hasPr return QObjectWrapper::wrap(This->engine(), context->idValues[index].data()); } -void QQmlIdObjectsArray::markObjects(Managed *that, ExecutionEngine *engine) +void QQmlIdObjectsArray::markObjects(HeapObject *that, ExecutionEngine *engine) { - QQmlIdObjectsArray *This = static_cast<QQmlIdObjectsArray*>(that); - This->d()->contextWrapper->mark(engine); + QQmlIdObjectsArray::Data *This = static_cast<QQmlIdObjectsArray::Data *>(that); + This->contextWrapper->mark(engine); Object::markObjects(that, engine); } diff --git a/src/qml/qml/qqmlcontextwrapper_p.h b/src/qml/qml/qqmlcontextwrapper_p.h index cae6800f48..ae9e795a5c 100644 --- a/src/qml/qml/qqmlcontextwrapper_p.h +++ b/src/qml/qml/qqmlcontextwrapper_p.h @@ -93,7 +93,7 @@ struct Q_QML_EXPORT QmlContextWrapper : Object static ReturnedValue get(Managed *m, String *name, bool *hasProperty); static void put(Managed *m, String *name, const ValueRef value); static void destroy(Managed *that); - static void markObjects(Managed *m, ExecutionEngine *engine); + static void markObjects(HeapObject *m, ExecutionEngine *engine); static void registerQmlDependencies(ExecutionEngine *context, const CompiledData::Function *compiledFunction); @@ -111,7 +111,7 @@ struct QQmlIdObjectsArray : public Object V4_OBJECT(Object) static ReturnedValue getIndexed(Managed *m, uint index, bool *hasProperty); - static void markObjects(Managed *that, ExecutionEngine *engine); + static void markObjects(HeapObject *that, ExecutionEngine *engine); }; diff --git a/src/qml/qml/qqmllistwrapper.cpp b/src/qml/qml/qqmllistwrapper.cpp index 13e5e49b55..b62689c454 100644 --- a/src/qml/qml/qqmllistwrapper.cpp +++ b/src/qml/qml/qqmllistwrapper.cpp @@ -35,6 +35,7 @@ #include <private/qv8engine_p.h> #include <private/qqmllist_p.h> #include <private/qv4objectproto_p.h> +#include <qv4objectiterator_p.h> #include <private/qv4functionobject_p.h> diff --git a/src/qml/qml/qqmllocale_p.h b/src/qml/qml/qqmllocale_p.h index 3787517038..233624453f 100644 --- a/src/qml/qml/qqmllocale_p.h +++ b/src/qml/qml/qqmllocale_p.h @@ -137,7 +137,7 @@ struct QQmlLocaleData : public QV4::Object QV4::Object *o = ctx->d()->callData->thisObject.asObject(); QQmlLocaleData *thisObject = o ? o->as<QQmlLocaleData>() : 0; if (!thisObject) { - ctx->throwTypeError(); + ctx->engine()->throwTypeError(); return 0; } return &thisObject->d()->locale; diff --git a/src/qml/qml/qqmltypewrapper.cpp b/src/qml/qml/qqmltypewrapper.cpp index d8f282c030..ddd934c840 100644 --- a/src/qml/qml/qqmltypewrapper.cpp +++ b/src/qml/qml/qqmltypewrapper.cpp @@ -262,7 +262,7 @@ void QmlTypeWrapper::put(Managed *m, String *name, const ValueRef value) QV4::ScopedObject apiprivate(scope, QJSValuePrivate::get(siinfo->scriptApi(e))->value); if (!apiprivate) { QString error = QLatin1String("Cannot assign to read-only property \"") + name->toQString() + QLatin1Char('\"'); - v4->currentContext()->throwError(error); + v4->throwError(error); return; } else { apiprivate->put(name, value); diff --git a/src/qml/qml/qqmlvaluetypewrapper.cpp b/src/qml/qml/qqmlvaluetypewrapper.cpp index b0125b4c13..7de15eac7d 100644 --- a/src/qml/qml/qqmlvaluetypewrapper.cpp +++ b/src/qml/qml/qqmlvaluetypewrapper.cpp @@ -144,7 +144,7 @@ ReturnedValue QmlValueTypeWrapper::create(QV8Engine *v8, QObject *object, int pr Scope scope(v4); initProto(v4); - QmlValueTypeReference *r = v4->memoryManager->alloc<QmlValueTypeReference>(v8); + Scoped<QmlValueTypeReference> r(scope, v4->memoryManager->alloc<QmlValueTypeReference>(v8)); r->d()->internalClass = r->d()->internalClass->changePrototype(v4->qmlExtensions()->valueTypeWrapperPrototype); r->d()->type = type; r->d()->object = object; r->d()->property = property; return r->asReturnedValue(); @@ -156,7 +156,7 @@ ReturnedValue QmlValueTypeWrapper::create(QV8Engine *v8, const QVariant &value, Scope scope(v4); initProto(v4); - QmlValueTypeCopy *r = v4->memoryManager->alloc<QmlValueTypeCopy>(v8); + Scoped<QmlValueTypeCopy> r(scope, v4->memoryManager->alloc<QmlValueTypeCopy>(v8)); r->d()->internalClass = r->d()->internalClass->changePrototype(v4->qmlExtensions()->valueTypeWrapperPrototype); r->d()->type = type; r->d()->value = value; return r->asReturnedValue(); @@ -242,10 +242,10 @@ ReturnedValue QmlValueTypeWrapper::method_toString(CallContext *ctx) { Object *o = ctx->d()->callData->thisObject.asObject(); if (!o) - return ctx->throwTypeError(); + return ctx->engine()->throwTypeError(); QmlValueTypeWrapper *w = o->as<QmlValueTypeWrapper>(); if (!w) - return ctx->throwTypeError(); + return ctx->engine()->throwTypeError(); if (w->d()->objectType == QmlValueTypeWrapper::Reference) { QmlValueTypeReference *reference = static_cast<QmlValueTypeReference *>(w); @@ -355,7 +355,7 @@ void QmlValueTypeWrapper::put(Managed *m, String *name, const ValueRef value) // assigning a JS function to a non-var-property is not allowed. QString error = QLatin1String("Cannot assign JavaScript function to value-type property"); Scoped<String> e(scope, r->d()->v8->toString(error)); - v4->currentContext()->throwError(e); + v4->throwError(e); return; } diff --git a/src/qml/qml/qqmlxmlhttprequest.cpp b/src/qml/qml/qqmlxmlhttprequest.cpp index 0730cbc363..2acd40ae44 100644 --- a/src/qml/qml/qqmlxmlhttprequest.cpp +++ b/src/qml/qml/qqmlxmlhttprequest.cpp @@ -55,6 +55,7 @@ #include <QtCore/qxmlstream.h> #include <QtCore/qstack.h> #include <QtCore/qdebug.h> +#include <QtCore/qbuffer.h> #include <private/qv4objectproto_p.h> #include <private/qv4scopedvalue_p.h> @@ -65,7 +66,7 @@ using namespace QV4; #define V4THROW_REFERENCE(string) { \ Scoped<Object> error(scope, ctx->engine()->newReferenceErrorObject(QStringLiteral(string))); \ - return ctx->throwError(error); \ + return ctx->engine()->throwError(error); \ } QT_BEGIN_NAMESPACE @@ -420,7 +421,7 @@ ReturnedValue NodePrototype::method_get_nodeName(CallContext *ctx) Scope scope(ctx); Scoped<Node> r(scope, ctx->d()->callData->thisObject.as<Node>()); if (!r) - return ctx->throwTypeError(); + return ctx->engine()->throwTypeError(); QString name; switch (r->d()->d->type) { @@ -445,7 +446,7 @@ ReturnedValue NodePrototype::method_get_nodeValue(CallContext *ctx) Scope scope(ctx); Scoped<Node> r(scope, ctx->d()->callData->thisObject.as<Node>()); if (!r) - return ctx->throwTypeError(); + return ctx->engine()->throwTypeError(); if (r->d()->d->type == NodeImpl::Document || r->d()->d->type == NodeImpl::DocumentFragment || @@ -464,7 +465,7 @@ ReturnedValue NodePrototype::method_get_nodeType(CallContext *ctx) Scope scope(ctx); Scoped<Node> r(scope, ctx->d()->callData->thisObject.as<Node>()); if (!r) - return ctx->throwTypeError(); + return ctx->engine()->throwTypeError(); return Encode(r->d()->d->type); } @@ -474,7 +475,7 @@ ReturnedValue NodePrototype::method_get_parentNode(CallContext *ctx) Scope scope(ctx); Scoped<Node> r(scope, ctx->d()->callData->thisObject.as<Node>()); if (!r) - return ctx->throwTypeError(); + return ctx->engine()->throwTypeError(); QV8Engine *engine = ctx->d()->engine->v8Engine; @@ -489,7 +490,7 @@ ReturnedValue NodePrototype::method_get_childNodes(CallContext *ctx) Scope scope(ctx); Scoped<Node> r(scope, ctx->d()->callData->thisObject.as<Node>()); if (!r) - return ctx->throwTypeError(); + return ctx->engine()->throwTypeError(); QV8Engine *engine = ctx->d()->engine->v8Engine; @@ -501,7 +502,7 @@ ReturnedValue NodePrototype::method_get_firstChild(CallContext *ctx) Scope scope(ctx); Scoped<Node> r(scope, ctx->d()->callData->thisObject.as<Node>()); if (!r) - return ctx->throwTypeError(); + return ctx->engine()->throwTypeError(); QV8Engine *engine = ctx->d()->engine->v8Engine; @@ -516,7 +517,7 @@ ReturnedValue NodePrototype::method_get_lastChild(CallContext *ctx) Scope scope(ctx); Scoped<Node> r(scope, ctx->d()->callData->thisObject.as<Node>()); if (!r) - return ctx->throwTypeError(); + return ctx->engine()->throwTypeError(); QV8Engine *engine = ctx->d()->engine->v8Engine; @@ -531,7 +532,7 @@ ReturnedValue NodePrototype::method_get_previousSibling(CallContext *ctx) Scope scope(ctx); Scoped<Node> r(scope, ctx->d()->callData->thisObject.as<Node>()); if (!r) - return ctx->throwTypeError(); + return ctx->engine()->throwTypeError(); QV8Engine *engine = ctx->d()->engine->v8Engine; @@ -555,7 +556,7 @@ ReturnedValue NodePrototype::method_get_nextSibling(CallContext *ctx) Scope scope(ctx); Scoped<Node> r(scope, ctx->d()->callData->thisObject.as<Node>()); if (!r) - return ctx->throwTypeError(); + return ctx->engine()->throwTypeError(); QV8Engine *engine = ctx->d()->engine->v8Engine; @@ -579,7 +580,7 @@ ReturnedValue NodePrototype::method_get_attributes(CallContext *ctx) Scope scope(ctx); Scoped<Node> r(scope, ctx->d()->callData->thisObject.as<Node>()); if (!r) - return ctx->throwTypeError(); + return ctx->engine()->throwTypeError(); QV8Engine *engine = ctx->d()->engine->v8Engine; @@ -899,7 +900,7 @@ ReturnedValue NamedNodeMap::getIndexed(Managed *m, uint index, bool *hasProperty if (!r) { if (hasProperty) *hasProperty = false; - return v4->currentContext()->throwTypeError(); + return v4->throwTypeError(); } QV8Engine *engine = v4->v8Engine; @@ -1249,16 +1250,23 @@ void QQmlXMLHttpRequest::requestFromUrl(const QUrl &url) } } - if (m_method == QLatin1String("GET")) + if (m_method == QLatin1String("GET")) { m_network = networkAccessManager()->get(request); - else if (m_method == QLatin1String("HEAD")) + } else if (m_method == QLatin1String("HEAD")) { m_network = networkAccessManager()->head(request); - else if (m_method == QLatin1String("POST")) + } else if (m_method == QLatin1String("POST")) { m_network = networkAccessManager()->post(request, m_data); - else if (m_method == QLatin1String("PUT")) + } else if (m_method == QLatin1String("PUT")) { m_network = networkAccessManager()->put(request, m_data); - else if (m_method == QLatin1String("DELETE")) + } else if (m_method == QLatin1String("DELETE")) { m_network = networkAccessManager()->deleteResource(request); + } else if (m_method == QLatin1String("OPTIONS")) { + QBuffer *buffer = new QBuffer; + buffer->setData(m_data); + buffer->open(QIODevice::ReadOnly); + m_network = networkAccessManager()->sendCustomRequest(request, QByteArrayLiteral("OPTIONS"), buffer); + buffer->setParent(m_network); + } QObject::connect(m_network, SIGNAL(readyRead()), this, SLOT(readyRead())); @@ -1526,14 +1534,14 @@ void QQmlXMLHttpRequest::dispatchCallbackImpl(const ValueRef me) QV4::Scope scope(v4); Scoped<Object> o(scope, me); if (!o) { - ctx->throwError(QStringLiteral("QQmlXMLHttpRequest: internal error: empty ThisObject")); + ctx->engine()->throwError(QStringLiteral("QQmlXMLHttpRequest: internal error: empty ThisObject")); return; } ScopedString s(scope, v4->newString(QStringLiteral("ThisObject"))); Scoped<Object> thisObj(scope, o->get(s.getPointer())); if (!thisObj) { - ctx->throwError(QStringLiteral("QQmlXMLHttpRequest: internal error: empty ThisObject")); + ctx->engine()->throwError(QStringLiteral("QQmlXMLHttpRequest: internal error: empty ThisObject")); return; } @@ -1547,7 +1555,7 @@ void QQmlXMLHttpRequest::dispatchCallbackImpl(const ValueRef me) s = v4->newString(QStringLiteral("ActivationObject")); Scoped<Object> activationObject(scope, o->get(s.getPointer())); if (!activationObject) { - v4->currentContext()->throwError(QStringLiteral("QQmlXMLHttpRequest: internal error: empty ActivationObject")); + v4->throwError(QStringLiteral("QQmlXMLHttpRequest: internal error: empty ActivationObject")); return; } @@ -1631,10 +1639,10 @@ struct QQmlXMLHttpRequestCtor : public FunctionObject Object *proto; }; V4_OBJECT(FunctionObject) - static void markObjects(Managed *that, ExecutionEngine *e) { - QQmlXMLHttpRequestCtor *c = static_cast<QQmlXMLHttpRequestCtor *>(that); - if (c->d()->proto) - c->d()->proto->mark(e); + static void markObjects(HeapObject *that, ExecutionEngine *e) { + QQmlXMLHttpRequestCtor::Data *c = static_cast<QQmlXMLHttpRequestCtor::Data *>(that); + if (c->proto) + c->proto->mark(e); FunctionObject::markObjects(that, e); } static ReturnedValue construct(Managed *that, QV4::CallData *) @@ -1642,7 +1650,7 @@ struct QQmlXMLHttpRequestCtor : public FunctionObject Scope scope(that->engine()); Scoped<QQmlXMLHttpRequestCtor> ctor(scope, that->as<QQmlXMLHttpRequestCtor>()); if (!ctor) - return that->engine()->currentContext()->throwTypeError(); + return that->engine()->throwTypeError(); QV8Engine *engine = that->engine()->v8Engine; QQmlXMLHttpRequest *r = new QQmlXMLHttpRequest(engine, engine->networkAccessManager()); @@ -1724,7 +1732,8 @@ ReturnedValue QQmlXMLHttpRequestCtor::method_open(CallContext *ctx) method != QLatin1String("PUT") && method != QLatin1String("HEAD") && method != QLatin1String("POST") && - method != QLatin1String("DELETE")) + method != QLatin1String("DELETE") && + method != QLatin1String("OPTIONS")) V4THROW_DOM(DOMEXCEPTION_SYNTAX_ERR, "Unsupported HTTP method type"); // Argument 1 - URL diff --git a/src/qml/qml/v8/qqmlbuiltinfunctions.cpp b/src/qml/qml/v8/qqmlbuiltinfunctions.cpp index f222d59494..3a593d1c5b 100644 --- a/src/qml/qml/v8/qqmlbuiltinfunctions.cpp +++ b/src/qml/qml/v8/qqmlbuiltinfunctions.cpp @@ -1004,7 +1004,7 @@ ReturnedValue QtObject::method_createQmlObject(CallContext *ctx) if (component.isError()) { ScopedValue v(scope, Error::create(ctx->d()->engine, component.errors())); - return ctx->throwError(v); + return ctx->engine()->throwError(v); } if (!component.isReady()) @@ -1028,7 +1028,7 @@ ReturnedValue QtObject::method_createQmlObject(CallContext *ctx) if (component.isError()) { ScopedValue v(scope, Error::create(ctx->d()->engine, component.errors())); - return ctx->throwError(v); + return ctx->engine()->throwError(v); } Q_ASSERT(obj); @@ -1070,7 +1070,7 @@ use \l{QtQml::Qt::createQmlObject()}{Qt.createQmlObject()}. ReturnedValue QtObject::method_createComponent(CallContext *ctx) { if (ctx->d()->callData->argc < 1 || ctx->d()->callData->argc > 3) - return ctx->throwError(QStringLiteral("Qt.createComponent(): Invalid arguments")); + return ctx->engine()->throwError(QStringLiteral("Qt.createComponent(): Invalid arguments")); Scope scope(ctx); @@ -1098,13 +1098,13 @@ ReturnedValue QtObject::method_createComponent(CallContext *ctx) if (ctx->d()->callData->args[1].isInteger()) { int mode = ctx->d()->callData->args[1].integerValue(); if (mode != int(QQmlComponent::PreferSynchronous) && mode != int(QQmlComponent::Asynchronous)) - return ctx->throwError(QStringLiteral("Qt.createComponent(): Invalid arguments")); + return ctx->engine()->throwError(QStringLiteral("Qt.createComponent(): Invalid arguments")); compileMode = QQmlComponent::CompilationMode(mode); consumedCount += 1; } else { // The second argument could be the parent only if there are exactly two args if ((ctx->d()->callData->argc != 2) || !(lastArg->isObject() || lastArg->isNull())) - return ctx->throwError(QStringLiteral("Qt.createComponent(): Invalid arguments")); + return ctx->engine()->throwError(QStringLiteral("Qt.createComponent(): Invalid arguments")); } if (consumedCount < ctx->d()->callData->argc) { @@ -1113,11 +1113,11 @@ ReturnedValue QtObject::method_createComponent(CallContext *ctx) if (qobjectWrapper) parentArg = qobjectWrapper->object(); if (!parentArg) - return ctx->throwError(QStringLiteral("Qt.createComponent(): Invalid parent object")); + return ctx->engine()->throwError(QStringLiteral("Qt.createComponent(): Invalid parent object")); } else if (lastArg->isNull()) { parentArg = 0; } else { - return ctx->throwError(QStringLiteral("Qt.createComponent(): Invalid parent object")); + return ctx->engine()->throwError(QStringLiteral("Qt.createComponent(): Invalid parent object")); } } } @@ -1187,10 +1187,10 @@ ReturnedValue QQmlBindingFunction::call(Managed *that, CallData *callData) return This->d()->originalFunction->call(callData); } -void QQmlBindingFunction::markObjects(Managed *that, ExecutionEngine *e) +void QQmlBindingFunction::markObjects(HeapObject *that, ExecutionEngine *e) { - QQmlBindingFunction *This = static_cast<QQmlBindingFunction*>(that); - This->d()->originalFunction->mark(e); + QQmlBindingFunction::Data *This = static_cast<QQmlBindingFunction::Data *>(that); + This->originalFunction->mark(e); QV4::FunctionObject::markObjects(that, e); } @@ -1257,10 +1257,10 @@ ReturnedValue QtObject::method_get_platform(CallContext *ctx) // ### inefficient. Should be just a value based getter Object *o = ctx->d()->callData->thisObject.asObject(); if (!o) - return ctx->throwTypeError(); + return ctx->engine()->throwTypeError(); QtObject *qt = o->as<QtObject>(); if (!qt) - return ctx->throwTypeError(); + return ctx->engine()->throwTypeError(); if (!qt->d()->platform) // Only allocate a platform object once @@ -1274,10 +1274,10 @@ ReturnedValue QtObject::method_get_application(CallContext *ctx) // ### inefficient. Should be just a value based getter Object *o = ctx->d()->callData->thisObject.asObject(); if (!o) - return ctx->throwTypeError(); + return ctx->engine()->throwTypeError(); QtObject *qt = o->as<QtObject>(); if (!qt) - return ctx->throwTypeError(); + return ctx->engine()->throwTypeError(); if (!qt->d()->application) // Only allocate an application object once diff --git a/src/qml/qml/v8/qqmlbuiltinfunctions_p.h b/src/qml/qml/v8/qqmlbuiltinfunctions_p.h index f7728aa120..7fe7d2b914 100644 --- a/src/qml/qml/v8/qqmlbuiltinfunctions_p.h +++ b/src/qml/qml/v8/qqmlbuiltinfunctions_p.h @@ -155,7 +155,7 @@ struct QQmlBindingFunction : public QV4::FunctionObject static ReturnedValue call(Managed *that, CallData *callData); - static void markObjects(Managed *that, ExecutionEngine *e); + static void markObjects(HeapObject *that, ExecutionEngine *e); static void destroy(Managed *that) { static_cast<QQmlBindingFunction *>(that)->d()->~Data(); } diff --git a/src/qml/qml/v8/qv4domerrors_p.h b/src/qml/qml/v8/qv4domerrors_p.h index 59ed744f5e..facf7972ad 100644 --- a/src/qml/qml/v8/qv4domerrors_p.h +++ b/src/qml/qml/v8/qv4domerrors_p.h @@ -72,7 +72,7 @@ QT_BEGIN_NAMESPACE QV4::ScopedValue v(scope, scope.engine->newString(QStringLiteral(string))); \ QV4::Scoped<Object> ex(scope, scope.engine->newErrorObject(v)); \ ex->put(QV4::ScopedString(scope, scope.engine->newIdentifier(QStringLiteral("code"))).getPointer(), QV4::ScopedValue(scope, QV4::Primitive::fromInt32(error))); \ - return ctx->throwError(ex); \ + return ctx->engine()->throwError(ex); \ } namespace QV4 { diff --git a/src/qml/qml/v8/qv8engine.cpp b/src/qml/qml/v8/qv8engine.cpp index 39b816f97c..d472120b4e 100644 --- a/src/qml/qml/v8/qv8engine.cpp +++ b/src/qml/qml/v8/qv8engine.cpp @@ -305,21 +305,6 @@ QVariant QV8Engine::objectToVariant(QV4::Object *o, V8ObjectSet *visitedObjects) return result; } -static QV4::ReturnedValue arrayFromStringList(QV8Engine *engine, const QStringList &list) -{ - QV4::ExecutionEngine *e = QV8Engine::getV4(engine); - QV4::Scope scope(e); - QV4::Scoped<QV4::ArrayObject> a(scope, e->newArrayObject()); - int len = list.count(); - a->arrayReserve(len); - QV4::ScopedValue v(scope); - for (int ii = 0; ii < len; ++ii) - a->arrayPut(ii, (v = QV4::Encode(e->newString(list.at(ii))))); - - a->setArrayLengthUnchecked(len); - return a.asReturnedValue(); -} - static QV4::ReturnedValue arrayFromVariantList(QV8Engine *engine, const QVariantList &list) { QV4::ExecutionEngine *e = QV8Engine::getV4(engine); @@ -409,7 +394,7 @@ QV4::ReturnedValue QV8Engine::fromVariant(const QVariant &variant) QV4::ScopedValue retn(scope, QV4::SequencePrototype::fromVariant(m_v4Engine, variant, &succeeded)); if (succeeded) return retn.asReturnedValue(); - return arrayFromStringList(this, *reinterpret_cast<const QStringList *>(ptr)); + return QV4::Encode(m_v4Engine->newArrayObject(*reinterpret_cast<const QStringList *>(ptr))); } case QMetaType::QVariantList: return arrayFromVariantList(this, *reinterpret_cast<const QVariantList *>(ptr)); diff --git a/src/qml/qml/v8/qv8engine_p.h b/src/qml/qml/v8/qv8engine_p.h index 51e857c8a2..2379689fb3 100644 --- a/src/qml/qml/v8/qv8engine_p.h +++ b/src/qml/qml/v8/qv8engine_p.h @@ -78,10 +78,10 @@ namespace QV4 { // #define QML_GLOBAL_HANDLE_DEBUGGING #define V4THROW_ERROR(string) \ - return ctx->throwError(QString::fromUtf8(string)); + return ctx->engine()->throwError(QString::fromUtf8(string)); #define V4THROW_TYPE(string) \ - return ctx->throwTypeError(QStringLiteral(string)); + return ctx->engine()->throwTypeError(QStringLiteral(string)); #define V8_DEFINE_EXTENSION(dataclass, datafunction) \ static inline dataclass *datafunction(QV8Engine *engine) \ diff --git a/src/qml/qml/v8/v8.pri b/src/qml/qml/v8/v8.pri index b4eb706574..3d6a012481 100644 --- a/src/qml/qml/v8/v8.pri +++ b/src/qml/qml/v8/v8.pri @@ -1,5 +1,4 @@ HEADERS += \ - $$PWD/qv8debug_p.h \ $$PWD/qv8engine_p.h \ $$PWD/qv4domerrors_p.h \ $$PWD/qv4sqlerrors_p.h \ diff --git a/src/qml/types/qqmldelegatemodel.cpp b/src/qml/types/qqmldelegatemodel.cpp index 639df4f846..e150545926 100644 --- a/src/qml/types/qqmldelegatemodel.cpp +++ b/src/qml/types/qqmldelegatemodel.cpp @@ -46,6 +46,7 @@ #include <private/qv4value_inl_p.h> #include <private/qv4functionobject_p.h> +#include <qv4objectiterator_p.h> QT_BEGIN_NAMESPACE @@ -67,14 +68,14 @@ struct DelegateModelGroupFunction: QV4::FunctionObject }; V4_OBJECT(QV4::FunctionObject) - static DelegateModelGroupFunction *create(QV4::ExecutionContext *scope, uint flag, QV4::ReturnedValue (*code)(QQmlDelegateModelItem *item, uint flag, const QV4::ValueRef arg)) + static QV4::Returned<DelegateModelGroupFunction> *create(QV4::ExecutionContext *scope, uint flag, QV4::ReturnedValue (*code)(QQmlDelegateModelItem *item, uint flag, const QV4::ValueRef arg)) { return scope->engine()->memoryManager->alloc<DelegateModelGroupFunction>(scope, flag, code); } static QV4::ReturnedValue construct(QV4::Managed *m, QV4::CallData *) { - return m->engine()->currentContext()->throwTypeError(); + return m->engine()->throwTypeError(); } static QV4::ReturnedValue call(QV4::Managed *that, QV4::CallData *callData) @@ -84,7 +85,7 @@ struct DelegateModelGroupFunction: QV4::FunctionObject QV4::Scoped<DelegateModelGroupFunction> f(scope, that, QV4::Scoped<DelegateModelGroupFunction>::Cast); QV4::Scoped<QQmlDelegateModelItemObject> o(scope, callData->thisObject); if (!o) - return v4->currentContext()->throwTypeError(QStringLiteral("Not a valid VisualData object")); + return v4->throwTypeError(QStringLiteral("Not a valid VisualData object")); QV4::ScopedValue v(scope, callData->argument(0)); return f->d()->code(o->d()->item, f->d()->flag, v); @@ -1780,7 +1781,7 @@ QV4::ReturnedValue QQmlDelegateModelItem::get_model(QV4::CallContext *ctx) QV4::Scope scope(ctx); QV4::Scoped<QQmlDelegateModelItemObject> o(scope, ctx->d()->callData->thisObject.as<QQmlDelegateModelItemObject>()); if (!o) - return ctx->throwTypeError(QStringLiteral("Not a valid VisualData object")); + return ctx->engine()->throwTypeError(QStringLiteral("Not a valid VisualData object")); if (!o->d()->item->metaType->model) return QV4::Encode::undefined(); @@ -1792,7 +1793,7 @@ QV4::ReturnedValue QQmlDelegateModelItem::get_groups(QV4::CallContext *ctx) QV4::Scope scope(ctx); QV4::Scoped<QQmlDelegateModelItemObject> o(scope, ctx->d()->callData->thisObject.as<QQmlDelegateModelItemObject>()); if (!o) - return ctx->throwTypeError(QStringLiteral("Not a valid VisualData object")); + return ctx->engine()->throwTypeError(QStringLiteral("Not a valid VisualData object")); QStringList groups; for (int i = 1; i < o->d()->item->metaType->groupCount; ++i) { @@ -1808,9 +1809,9 @@ QV4::ReturnedValue QQmlDelegateModelItem::set_groups(QV4::CallContext *ctx) QV4::Scope scope(ctx); QV4::Scoped<QQmlDelegateModelItemObject> o(scope, ctx->d()->callData->thisObject.as<QQmlDelegateModelItemObject>()); if (!o) - return ctx->throwTypeError(QStringLiteral("Not a valid VisualData object")); + return ctx->engine()->throwTypeError(QStringLiteral("Not a valid VisualData object")); if (!ctx->d()->callData->argc) - return ctx->throwTypeError(); + return ctx->engine()->throwTypeError(); if (!o->d()->item->metaType->model) return QV4::Encode::undefined(); @@ -3220,7 +3221,7 @@ struct QQmlDelegateModelGroupChange : QV4::Object }; V4_OBJECT(QV4::Object) - static QQmlDelegateModelGroupChange *create(QV4::ExecutionEngine *e) { + static QV4::Returned<QQmlDelegateModelGroupChange> *create(QV4::ExecutionEngine *e) { return e->memoryManager->alloc<QQmlDelegateModelGroupChange>(e); } @@ -3228,21 +3229,21 @@ struct QQmlDelegateModelGroupChange : QV4::Object QV4::Scope scope(ctx); QV4::Scoped<QQmlDelegateModelGroupChange> that(scope, ctx->d()->callData->thisObject.as<QQmlDelegateModelGroupChange>()); if (!that) - return ctx->throwTypeError(); + return ctx->engine()->throwTypeError(); return QV4::Encode(that->d()->change.index); } static QV4::ReturnedValue method_get_count(QV4::CallContext *ctx) { QV4::Scope scope(ctx); QV4::Scoped<QQmlDelegateModelGroupChange> that(scope, ctx->d()->callData->thisObject.as<QQmlDelegateModelGroupChange>()); if (!that) - return ctx->throwTypeError(); + return ctx->engine()->throwTypeError(); return QV4::Encode(that->d()->change.count); } static QV4::ReturnedValue method_get_moveId(QV4::CallContext *ctx) { QV4::Scope scope(ctx); QV4::Scoped<QQmlDelegateModelGroupChange> that(scope, ctx->d()->callData->thisObject.as<QQmlDelegateModelGroupChange>()); if (!that) - return ctx->throwTypeError(); + return ctx->engine()->throwTypeError(); if (that->d()->change.moveId < 0) return QV4::Encode::undefined(); return QV4::Encode(that->d()->change.moveId); @@ -3267,7 +3268,7 @@ struct QQmlDelegateModelGroupChangeArray : public QV4::Object }; V4_OBJECT(QV4::Object) public: - static QQmlDelegateModelGroupChangeArray *create(QV4::ExecutionEngine *engine, const QVector<QQmlChangeSet::Change> &changes) + static QV4::Returned<QQmlDelegateModelGroupChangeArray> *create(QV4::ExecutionEngine *engine, const QVector<QQmlChangeSet::Change> &changes) { return engine->memoryManager->alloc<QQmlDelegateModelGroupChangeArray>(engine, changes); } diff --git a/src/qml/util/qqmladaptormodel.cpp b/src/qml/util/qqmladaptormodel.cpp index b147f56bfa..943947f577 100644 --- a/src/qml/util/qqmladaptormodel.cpp +++ b/src/qml/util/qqmladaptormodel.cpp @@ -60,7 +60,7 @@ static QV4::ReturnedValue get_index(QV4::CallContext *ctx) QV4::Scope scope(ctx); QV4::Scoped<QQmlDelegateModelItemObject> o(scope, ctx->d()->callData->thisObject.as<QQmlDelegateModelItemObject>()); if (!o) - return ctx->throwTypeError(QStringLiteral("Not a valid VisualData object")); + return ctx->engine()->throwTypeError(QStringLiteral("Not a valid VisualData object")); return QV4::Encode(o->d()->item->index); } @@ -192,7 +192,7 @@ public: QV4::Scope scope(ctx); QV4::Scoped<QQmlDelegateModelItemObject> o(scope, ctx->d()->callData->thisObject.as<QQmlDelegateModelItemObject>()); if (!o) - return ctx->throwTypeError(QStringLiteral("Not a valid VisualData object")); + return ctx->engine()->throwTypeError(QStringLiteral("Not a valid VisualData object")); const QQmlAdaptorModel *const model = static_cast<QQmlDMCachedModelData *>(o->d()->item)->type->model; if (o->d()->item->index >= 0 && *model) { @@ -339,7 +339,7 @@ QV4::ReturnedValue QQmlDMCachedModelData::get_property(QV4::CallContext *ctx, ui QV4::Scope scope(ctx); QV4::Scoped<QQmlDelegateModelItemObject> o(scope, ctx->d()->callData->thisObject.as<QQmlDelegateModelItemObject>()); if (!o) - return ctx->throwTypeError(QStringLiteral("Not a valid VisualData object")); + return ctx->engine()->throwTypeError(QStringLiteral("Not a valid VisualData object")); QQmlDMCachedModelData *modelData = static_cast<QQmlDMCachedModelData *>(o->d()->item); if (o->d()->item->index == -1) { @@ -359,9 +359,9 @@ QV4::ReturnedValue QQmlDMCachedModelData::set_property(QV4::CallContext *ctx, ui QV4::Scope scope(ctx); QV4::Scoped<QQmlDelegateModelItemObject> o(scope, ctx->d()->callData->thisObject.as<QQmlDelegateModelItemObject>()); if (!o) - return ctx->throwTypeError(QStringLiteral("Not a valid VisualData object")); + return ctx->engine()->throwTypeError(QStringLiteral("Not a valid VisualData object")); if (!ctx->d()->callData->argc) - return ctx->throwTypeError(); + return ctx->engine()->throwTypeError(); if (o->d()->item->index == -1) { QQmlDMCachedModelData *modelData = static_cast<QQmlDMCachedModelData *>(o->d()->item); @@ -581,7 +581,7 @@ public: QV4::Scope scope(ctx); QV4::Scoped<QQmlDelegateModelItemObject> o(scope, ctx->d()->callData->thisObject.as<QQmlDelegateModelItemObject>()); if (!o) - return ctx->throwTypeError(QStringLiteral("Not a valid VisualData object")); + return ctx->engine()->throwTypeError(QStringLiteral("Not a valid VisualData object")); return scope.engine->v8Engine->fromVariant(static_cast<QQmlDMListAccessorData *>(o->d()->item)->cachedData); } @@ -591,9 +591,9 @@ public: QV4::Scope scope(ctx); QV4::Scoped<QQmlDelegateModelItemObject> o(scope, ctx->d()->callData->thisObject.as<QQmlDelegateModelItemObject>()); if (!o) - return ctx->throwTypeError(QStringLiteral("Not a valid VisualData object")); + return ctx->engine()->throwTypeError(QStringLiteral("Not a valid VisualData object")); if (!ctx->d()->callData->argc) - return ctx->throwTypeError(); + return ctx->engine()->throwTypeError(); static_cast<QQmlDMListAccessorData *>(o->d()->item)->setModelData(scope.engine->v8Engine->toVariant(ctx->d()->callData->args[0], QVariant::Invalid)); return QV4::Encode::undefined(); diff --git a/src/quick/items/context2d/qquickcanvasitem_p.h b/src/quick/items/context2d/qquickcanvasitem_p.h index b3509a5e58..e490bdf9c3 100644 --- a/src/quick/items/context2d/qquickcanvasitem_p.h +++ b/src/quick/items/context2d/qquickcanvasitem_p.h @@ -162,12 +162,12 @@ private Q_SLOTS: void invalidateSceneGraph(); protected: - void componentComplete(); - void itemChange(QQuickItem::ItemChange, const QQuickItem::ItemChangeData &); - void updatePolish(); - QSGNode *updatePaintNode(QSGNode *, UpdatePaintNodeData *); - void geometryChanged(const QRectF &newGeometry, const QRectF &oldGeometry); - void releaseResources(); + void componentComplete() Q_DECL_OVERRIDE; + void itemChange(QQuickItem::ItemChange, const QQuickItem::ItemChangeData &) Q_DECL_OVERRIDE; + void updatePolish() Q_DECL_OVERRIDE; + QSGNode *updatePaintNode(QSGNode *, UpdatePaintNodeData *) Q_DECL_OVERRIDE; + void geometryChanged(const QRectF &newGeometry, const QRectF &oldGeometry) Q_DECL_OVERRIDE; + void releaseResources() Q_DECL_OVERRIDE; private: Q_DECLARE_PRIVATE(QQuickCanvasItem) Q_INVOKABLE void delayedCreate(); diff --git a/src/quick/items/context2d/qquickcontext2d.cpp b/src/quick/items/context2d/qquickcontext2d.cpp index 0101e0edf4..1b29cd0b02 100644 --- a/src/quick/items/context2d/qquickcontext2d.cpp +++ b/src/quick/items/context2d/qquickcontext2d.cpp @@ -908,8 +908,8 @@ struct QQuickJSContext2DImageData : public QV4::Object static QV4::ReturnedValue method_get_height(QV4::CallContext *ctx); static QV4::ReturnedValue method_get_data(QV4::CallContext *ctx); - static void markObjects(Managed *that, QV4::ExecutionEngine *engine) { - static_cast<QQuickJSContext2DImageData *>(that)->d()->pixelData.mark(engine); + static void markObjects(QV4::HeapObject *that, QV4::ExecutionEngine *engine) { + static_cast<QQuickJSContext2DImageData::Data *>(that)->pixelData.mark(engine); QV4::Object::markObjects(that, engine); } }; @@ -1301,7 +1301,7 @@ QV4::ReturnedValue QQuickJSContext2D::method_set_globalCompositeOperation(QV4::C CHECK_CONTEXT_SETTER(r) if (!ctx->d()->callData->argc) - return ctx->throwTypeError(); + return ctx->engine()->throwTypeError(); QString mode = ctx->d()->callData->args[0].toQString(); QPainter::CompositionMode cm = qt_composite_mode_from_string(mode); @@ -1853,7 +1853,7 @@ QV4::ReturnedValue QQuickJSContext2D::method_set_lineJoin(QV4::CallContext *ctx) CHECK_CONTEXT_SETTER(r) if (!ctx->d()->callData->argc) - return ctx->throwTypeError(); + return ctx->engine()->throwTypeError(); QString lineJoin = ctx->d()->callData->args[0].toQString(); Qt::PenJoinStyle join; @@ -3027,7 +3027,7 @@ QV4::ReturnedValue QQuickJSContext2DImageData::method_get_width(QV4::CallContext QV4::Scope scope(ctx); QV4::Scoped<QQuickJSContext2DImageData> imageData(scope, ctx->d()->callData->thisObject); if (!imageData) - return ctx->throwTypeError(); + return ctx->engine()->throwTypeError(); QV4::Scoped<QQuickJSContext2DPixelData> r(scope, imageData->d()->pixelData.as<QQuickJSContext2DPixelData>()); if (!r) return QV4::Encode(0); @@ -3043,7 +3043,7 @@ QV4::ReturnedValue QQuickJSContext2DImageData::method_get_height(QV4::CallContex QV4::Scope scope(ctx); QV4::Scoped<QQuickJSContext2DImageData> imageData(scope, ctx->d()->callData->thisObject); if (!imageData) - return ctx->throwTypeError(); + return ctx->engine()->throwTypeError(); QV4::Scoped<QQuickJSContext2DPixelData> r(scope, imageData->d()->pixelData.as<QQuickJSContext2DPixelData>()); if (!r) return QV4::Encode(0); @@ -3059,7 +3059,7 @@ QV4::ReturnedValue QQuickJSContext2DImageData::method_get_data(QV4::CallContext QV4::Scope scope(ctx); QV4::Scoped<QQuickJSContext2DImageData> imageData(scope, ctx->d()->callData->thisObject); if (!imageData) - return ctx->throwTypeError(); + return ctx->engine()->throwTypeError(); return imageData->d()->pixelData.asReturnedValue(); } diff --git a/src/quick/items/context2d/qquickcontext2dcommandbuffer.cpp b/src/quick/items/context2d/qquickcontext2dcommandbuffer.cpp index a52f1c8cd2..eac5e2cef8 100644 --- a/src/quick/items/context2d/qquickcontext2dcommandbuffer.cpp +++ b/src/quick/items/context2d/qquickcontext2dcommandbuffer.cpp @@ -93,7 +93,7 @@ namespace { } void paint(QPainter *p) const { p->fillRect(m_rect, m_brush); } - QRectF boundingRect() const { return m_rect; } + QRectF boundingRect() const Q_DECL_OVERRIDE { return m_rect; } private: QRectF m_rect; @@ -110,7 +110,7 @@ namespace { } void paint(QPainter *p) const { p->fillPath(m_path, m_brush); } - QRectF boundingRect() const { return m_path.boundingRect(); } + QRectF boundingRect() const Q_DECL_OVERRIDE { return m_path.boundingRect(); } private: QPainterPath m_path; @@ -128,7 +128,7 @@ namespace { void paint(QPainter *p) const { p->strokePath(m_path, m_pen); } - QRectF boundingRect() const + QRectF boundingRect() const Q_DECL_OVERRIDE { qreal d = qMax(qreal(1), m_pen.widthF()); return m_path.boundingRect().adjusted(-d, -d, d, d); @@ -150,7 +150,7 @@ namespace { void paint(QPainter *p) const { p->drawImage(m_offset, m_image); } - QRectF boundingRect() const { return QRectF(m_image.rect()).translated(m_offset); } + QRectF boundingRect() const Q_DECL_OVERRIDE { return QRectF(m_image.rect()).translated(m_offset); } private: QImage m_image; diff --git a/src/quick/items/qquickanchors_p_p.h b/src/quick/items/qquickanchors_p_p.h index d07b4369f5..cd5f32c266 100644 --- a/src/quick/items/qquickanchors_p_p.h +++ b/src/quick/items/qquickanchors_p_p.h @@ -126,8 +126,8 @@ public: void updateMe(); // QQuickItemGeometryListener interface - void itemGeometryChanged(QQuickItem *, const QRectF &, const QRectF &); - QQuickAnchorsPrivate *anchorPrivate() { return this; } + void itemGeometryChanged(QQuickItem *, const QRectF &, const QRectF &) Q_DECL_OVERRIDE; + QQuickAnchorsPrivate *anchorPrivate() Q_DECL_OVERRIDE { return this; } bool checkHValid() const; bool checkVValid() const; diff --git a/src/quick/items/qquickanimatedimage_p.h b/src/quick/items/qquickanimatedimage_p.h index 789f56e6f7..d04cbdf851 100644 --- a/src/quick/items/qquickanimatedimage_p.h +++ b/src/quick/items/qquickanimatedimage_p.h @@ -71,7 +71,7 @@ public: int frameCount() const; // Extends QQuickImage's src property - virtual void setSource(const QUrl&); + void setSource(const QUrl&) Q_DECL_OVERRIDE; virtual QSize sourceSize(); Q_SIGNALS: @@ -86,8 +86,8 @@ private Q_SLOTS: void playingStatusChanged(); protected: - virtual void load(); - void componentComplete(); + void load() Q_DECL_OVERRIDE; + void componentComplete() Q_DECL_OVERRIDE; private: Q_DISABLE_COPY(QQuickAnimatedImage) diff --git a/src/quick/items/qquickanimatedsprite.cpp b/src/quick/items/qquickanimatedsprite.cpp index f1201cf549..f144345b6c 100644 --- a/src/quick/items/qquickanimatedsprite.cpp +++ b/src/quick/items/qquickanimatedsprite.cpp @@ -54,9 +54,9 @@ class QQuickAnimatedSpriteMaterial : public QSGMaterial public: QQuickAnimatedSpriteMaterial(); ~QQuickAnimatedSpriteMaterial(); - virtual QSGMaterialType *type() const { static QSGMaterialType type; return &type; } - virtual QSGMaterialShader *createShader() const; - virtual int compare(const QSGMaterial *other) const + QSGMaterialType *type() const Q_DECL_OVERRIDE { static QSGMaterialType type; return &type; } + QSGMaterialShader *createShader() const Q_DECL_OVERRIDE; + int compare(const QSGMaterial *other) const Q_DECL_OVERRIDE { return this - static_cast<const QQuickAnimatedSpriteMaterial *>(other); } @@ -100,7 +100,7 @@ public: setShaderSourceFile(QOpenGLShader::Fragment, QStringLiteral(":/items/shaders/sprite.frag")); } - virtual void updateState(const RenderState &state, QSGMaterial *newEffect, QSGMaterial *) + void updateState(const RenderState &state, QSGMaterial *newEffect, QSGMaterial *) Q_DECL_OVERRIDE { QQuickAnimatedSpriteMaterial *m = static_cast<QQuickAnimatedSpriteMaterial *>(newEffect); m->texture->bind(); @@ -113,14 +113,14 @@ public: program()->setUniformValue(m_matrix_id, state.combinedMatrix()); } - virtual void initialize() { + void initialize() Q_DECL_OVERRIDE { m_matrix_id = program()->uniformLocation("qt_Matrix"); m_opacity_id = program()->uniformLocation("qt_Opacity"); m_animData_id = program()->uniformLocation("animData"); m_animPos_id = program()->uniformLocation("animPos"); } - virtual char const *const *attributeNames() const { + char const *const *attributeNames() const Q_DECL_OVERRIDE { static const char *attr[] = { "vPos", "vTex", @@ -388,8 +388,8 @@ void QQuickAnimatedSprite::advance(int frames) //TODO-C: May not work when running - only when paused m_curFrame += frames; while (m_curFrame < 0) - m_curFrame += m_sprite->frames(); - m_curFrame = m_curFrame % m_sprite->frames(); + m_curFrame += m_spriteEngine->maxFrames(); + m_curFrame = m_curFrame % m_spriteEngine->maxFrames(); emit currentFrameChanged(m_curFrame); } @@ -529,7 +529,6 @@ QSGGeometryNode* QQuickAnimatedSprite::buildNode() indices[5] = 2; - m_timestamp.start(); m_node = new QSGGeometryNode(); m_node->setGeometry(g); m_node->setMaterial(m_material); @@ -574,43 +573,47 @@ void QQuickAnimatedSprite::prepareNextFrame() int timeInt = m_timestamp.elapsed() + m_pauseOffset; qreal time = timeInt / 1000.; - double frameAt; //double just for modf + int frameAt; qreal progress = 0.0; int lastFrame = m_curFrame; - if (!m_paused) { + if (m_running && !m_paused) { + const int nColumns = int(m_sheetSize.width()) / m_spriteEngine->spriteWidth(); //Advance State (keeps time for psuedostates) m_spriteEngine->updateSprites(timeInt); //Advance AnimatedSprite qreal animT = m_spriteEngine->spriteStart()/1000.0; - qreal frameCount = m_spriteEngine->spriteFrames(); - qreal frameDuration = m_spriteEngine->spriteDuration()/frameCount; + const int frameCountInRow = m_spriteEngine->spriteFrames(); + const qreal frameDuration = m_spriteEngine->spriteDuration()/frameCountInRow; if (frameDuration > 0) { qreal frame = (time - animT)/(frameDuration / 1000.0); bool lastLoop = m_loops > 0 && m_curLoop == m_loops-1; //don't visually interpolate for the last frame of the last loop - qreal max = lastLoop ? frameCount - qreal(1.0) : frameCount; - frame = qBound(qreal(0.0), frame, max); - progress = modf(frame,&frameAt); - if (m_curFrame > frameAt) //went around + const int max = lastLoop ? frameCountInRow - 1 : frameCountInRow; + frame = qBound(qreal(0.0), frame, qreal(max)); + double intpart; + progress = modf(frame,&intpart); + frameAt = (int)intpart; + const int rowIndex = m_spriteEngine->spriteY()/frameHeight(); + const int newFrame = rowIndex * nColumns + frameAt; + if (m_curFrame > newFrame) //went around m_curLoop++; - m_curFrame = frameAt; + m_curFrame = newFrame; } else { m_curFrame++; - if (m_curFrame >= frameCount){ + if (m_curFrame >= m_spriteEngine->maxFrames()) { // maxFrames: total number of frames including all rows m_curFrame = 0; m_curLoop++; - m_spriteEngine->advance(); } - frameAt = m_curFrame; + frameAt = m_curFrame % nColumns; + if (frameAt == 0) + m_spriteEngine->advance(); progress = 0; } if (m_loops > 0 && m_curLoop >= m_loops) { frameAt = 0; - if (m_running) { - m_running = false; - emit runningChanged(false); - } + m_running = false; + emit runningChanged(false); } } else { frameAt = m_curFrame; diff --git a/src/quick/items/qquickanimatedsprite_p.h b/src/quick/items/qquickanimatedsprite_p.h index 0bc2c65b7c..546d239034 100644 --- a/src/quick/items/qquickanimatedsprite_p.h +++ b/src/quick/items/qquickanimatedsprite_p.h @@ -343,8 +343,8 @@ private Q_SLOTS: protected: void reset(); - void componentComplete(); - QSGNode *updatePaintNode(QSGNode *, UpdatePaintNodeData *); + void componentComplete() Q_DECL_OVERRIDE; + QSGNode *updatePaintNode(QSGNode *, UpdatePaintNodeData *) Q_DECL_OVERRIDE; private: bool isCurrentFrameChangedConnected(); void prepareNextFrame(); diff --git a/src/quick/items/qquickborderimage_p.h b/src/quick/items/qquickborderimage_p.h index 1d0898115d..a33098d3b1 100644 --- a/src/quick/items/qquickborderimage_p.h +++ b/src/quick/items/qquickborderimage_p.h @@ -66,7 +66,7 @@ public: TileMode verticalTileMode() const; void setVerticalTileMode(TileMode); - void setSource(const QUrl &url); + void setSource(const QUrl &url) Q_DECL_OVERRIDE; Q_SIGNALS: void horizontalTileModeChanged(); @@ -74,16 +74,16 @@ Q_SIGNALS: void sourceSizeChanged(); protected: - virtual void load(); - virtual void pixmapChange(); - virtual QSGNode *updatePaintNode(QSGNode *, UpdatePaintNodeData *); + void load() Q_DECL_OVERRIDE; + void pixmapChange() Q_DECL_OVERRIDE; + QSGNode *updatePaintNode(QSGNode *, UpdatePaintNodeData *) Q_DECL_OVERRIDE; private: void setGridScaledImage(const QQuickGridScaledImage& sci); private Q_SLOTS: void doUpdate(); - void requestFinished(); + void requestFinished() Q_DECL_OVERRIDE; void sciRequestFinished(); private: diff --git a/src/quick/items/qquickdrag.cpp b/src/quick/items/qquickdrag.cpp index 5641c323ab..e49347351c 100644 --- a/src/quick/items/qquickdrag.cpp +++ b/src/quick/items/qquickdrag.cpp @@ -71,7 +71,7 @@ public: { } - void itemGeometryChanged(QQuickItem *, const QRectF &, const QRectF &); + void itemGeometryChanged(QQuickItem *, const QRectF &, const QRectF &) Q_DECL_OVERRIDE; void itemParentChanged(QQuickItem *, QQuickItem *parent); void updatePosition(); void restartDrag(); diff --git a/src/quick/items/qquickdroparea_p.h b/src/quick/items/qquickdroparea_p.h index a0c985ddf7..35a5f3c880 100644 --- a/src/quick/items/qquickdroparea_p.h +++ b/src/quick/items/qquickdroparea_p.h @@ -160,10 +160,10 @@ Q_SIGNALS: void dropped(QQuickDropEvent *drop); protected: - void dragMoveEvent(QDragMoveEvent *event); - void dragEnterEvent(QDragEnterEvent *event); - void dragLeaveEvent(QDragLeaveEvent *event); - void dropEvent(QDropEvent *event); + void dragMoveEvent(QDragMoveEvent *event) Q_DECL_OVERRIDE; + void dragEnterEvent(QDragEnterEvent *event) Q_DECL_OVERRIDE; + void dragLeaveEvent(QDragLeaveEvent *event) Q_DECL_OVERRIDE; + void dropEvent(QDropEvent *event) Q_DECL_OVERRIDE; private: Q_DISABLE_COPY(QQuickDropArea) diff --git a/src/quick/items/qquickflickable.cpp b/src/quick/items/qquickflickable.cpp index 9f1de39186..f851ef1bac 100644 --- a/src/quick/items/qquickflickable.cpp +++ b/src/quick/items/qquickflickable.cpp @@ -180,7 +180,7 @@ public: } protected: - virtual void finished() { + void finished() Q_DECL_OVERRIDE { if (!flickable) return; axisData->move.setValue(axisData->transitionTo); diff --git a/src/quick/items/qquickflickable_p.h b/src/quick/items/qquickflickable_p.h index c8a1ba6984..c996d18b01 100644 --- a/src/quick/items/qquickflickable_p.h +++ b/src/quick/items/qquickflickable_p.h @@ -220,14 +220,14 @@ Q_SIGNALS: void pixelAlignedChanged(); protected: - virtual bool childMouseEventFilter(QQuickItem *, QEvent *); - virtual void mousePressEvent(QMouseEvent *event); - virtual void mouseMoveEvent(QMouseEvent *event); - virtual void mouseReleaseEvent(QMouseEvent *event); + bool childMouseEventFilter(QQuickItem *, QEvent *) Q_DECL_OVERRIDE; + void mousePressEvent(QMouseEvent *event) Q_DECL_OVERRIDE; + void mouseMoveEvent(QMouseEvent *event) Q_DECL_OVERRIDE; + void mouseReleaseEvent(QMouseEvent *event) Q_DECL_OVERRIDE; #ifndef QT_NO_WHEELEVENT - virtual void wheelEvent(QWheelEvent *event); + void wheelEvent(QWheelEvent *event) Q_DECL_OVERRIDE; #endif - virtual void timerEvent(QTimerEvent *event); + void timerEvent(QTimerEvent *event) Q_DECL_OVERRIDE; QQuickFlickableVisibleArea *visibleArea(); @@ -244,11 +244,11 @@ protected: virtual qreal maxYExtent() const; qreal vWidth() const; qreal vHeight() const; - virtual void componentComplete(); + void componentComplete() Q_DECL_OVERRIDE; virtual void viewportMoved(Qt::Orientations orient); - virtual void geometryChanged(const QRectF &newGeometry, - const QRectF &oldGeometry); - void mouseUngrabEvent(); + void geometryChanged(const QRectF &newGeometry, + const QRectF &oldGeometry) Q_DECL_OVERRIDE; + void mouseUngrabEvent() Q_DECL_OVERRIDE; bool sendMouseEvent(QQuickItem *item, QMouseEvent *event); bool xflick() const; diff --git a/src/quick/items/qquickflickable_p_p.h b/src/quick/items/qquickflickable_p_p.h index bd8c8de168..af4a4bccbf 100644 --- a/src/quick/items/qquickflickable_p_p.h +++ b/src/quick/items/qquickflickable_p_p.h @@ -80,7 +80,7 @@ public: { Velocity(QQuickFlickablePrivate *p) : parent(p) {} - virtual void setValue(qreal v) { + void setValue(qreal v) Q_DECL_OVERRIDE { if (v != value()) { QQuickTimeLineValue::setValue(v); parent->updateVelocity(); @@ -185,7 +185,7 @@ public: qreal overShootDistance(qreal size); - void itemGeometryChanged(QQuickItem *, const QRectF &, const QRectF &); + void itemGeometryChanged(QQuickItem *, const QRectF &, const QRectF &) Q_DECL_OVERRIDE; void draggingStarting(); void draggingEnding(); diff --git a/src/quick/items/qquickflipable.cpp b/src/quick/items/qquickflipable.cpp index 1d439eef05..a68457319b 100644 --- a/src/quick/items/qquickflipable.cpp +++ b/src/quick/items/qquickflipable.cpp @@ -51,7 +51,7 @@ public: transform = t; update(); } - virtual void applyTo(QMatrix4x4 *matrix) const { + void applyTo(QMatrix4x4 *matrix) const Q_DECL_OVERRIDE { *matrix *= transform; } private: @@ -64,7 +64,7 @@ class QQuickFlipablePrivate : public QQuickItemPrivate public: QQuickFlipablePrivate() : current(QQuickFlipable::Front), front(0), back(0), sideDirty(false) {} - virtual void transformChanged(); + void transformChanged() Q_DECL_OVERRIDE; void updateSide(); void setBackTransform(); diff --git a/src/quick/items/qquickflipable_p.h b/src/quick/items/qquickflipable_p.h index 0196e35315..9648b22ef6 100644 --- a/src/quick/items/qquickflipable_p.h +++ b/src/quick/items/qquickflipable_p.h @@ -72,7 +72,7 @@ Q_SIGNALS: void sideChanged(); protected: - virtual void updatePolish(); + void updatePolish() Q_DECL_OVERRIDE; private Q_SLOTS: void retransformBack(); diff --git a/src/quick/items/qquickframebufferobject.h b/src/quick/items/qquickframebufferobject.h index f6431dc38e..3c3ae77436 100644 --- a/src/quick/items/qquickframebufferobject.h +++ b/src/quick/items/qquickframebufferobject.h @@ -80,7 +80,7 @@ public: void releaseResources() Q_DECL_OVERRIDE; protected: - void geometryChanged(const QRectF &newGeometry, const QRectF &oldGeometry); + void geometryChanged(const QRectF &newGeometry, const QRectF &oldGeometry) Q_DECL_OVERRIDE; protected: QSGNode *updatePaintNode(QSGNode *, UpdatePaintNodeData *) Q_DECL_OVERRIDE; diff --git a/src/quick/items/qquickgridview.cpp b/src/quick/items/qquickgridview.cpp index 72edce4339..e3af926e22 100644 --- a/src/quick/items/qquickgridview.cpp +++ b/src/quick/items/qquickgridview.cpp @@ -115,7 +115,7 @@ public: void setPosition(qreal col, qreal row, bool immediate = false) { moveTo(pointForPosition(col, row), immediate); } - bool contains(qreal x, qreal y) const { + bool contains(qreal x, qreal y) const Q_DECL_OVERRIDE { return (x >= itemX() && x < itemX() + view->cellWidth() && y >= itemY() && y < itemY() + view->cellHeight()); } @@ -152,13 +152,13 @@ class QQuickGridViewPrivate : public QQuickItemViewPrivate Q_DECLARE_PUBLIC(QQuickGridView) public: - virtual Qt::Orientation layoutOrientation() const; - virtual bool isContentFlowReversed() const; + Qt::Orientation layoutOrientation() const Q_DECL_OVERRIDE; + bool isContentFlowReversed() const Q_DECL_OVERRIDE; - virtual qreal positionAt(int index) const; - virtual qreal endPositionAt(int index) const; - virtual qreal originPosition() const; - virtual qreal lastPosition() const; + qreal positionAt(int index) const Q_DECL_OVERRIDE; + qreal endPositionAt(int index) const Q_DECL_OVERRIDE; + qreal originPosition() const Q_DECL_OVERRIDE; + qreal lastPosition() const Q_DECL_OVERRIDE; qreal rowSize() const; qreal colSize() const; @@ -172,41 +172,41 @@ public: void resetColumns(); - virtual bool addVisibleItems(qreal fillFrom, qreal fillTo, qreal bufferFrom, qreal bufferTo, bool doBuffer); - virtual bool removeNonVisibleItems(qreal bufferFrom, qreal bufferTo); - - virtual FxViewItem *newViewItem(int index, QQuickItem *item); - virtual void initializeViewItem(FxViewItem *item); - virtual void repositionItemAt(FxViewItem *item, int index, qreal sizeBuffer); - virtual void repositionPackageItemAt(QQuickItem *item, int index); - virtual void resetFirstItemPosition(qreal pos = 0.0); - virtual void adjustFirstItem(qreal forwards, qreal backwards, int changeBeforeVisible); - - virtual void createHighlight(); - virtual void updateHighlight(); - virtual void resetHighlightPosition(); - - virtual void setPosition(qreal pos); - virtual void layoutVisibleItems(int fromModelIndex = 0); - virtual bool applyInsertionChange(const QQmlChangeSet::Change &insert, ChangeResult *changeResult, QList<FxViewItem *> *addedItems, QList<MovedItem> *movingIntoView); - virtual void translateAndTransitionItemsAfter(int afterModelIndex, const ChangeResult &insertionResult, const ChangeResult &removalResult); - virtual bool needsRefillForAddedOrRemovedIndex(int index) const; - - virtual qreal headerSize() const; - virtual qreal footerSize() const; - virtual bool showHeaderForIndex(int index) const; - virtual bool showFooterForIndex(int index) const; - virtual void updateHeader(); - virtual void updateFooter(); - - virtual void changedVisibleIndex(int newIndex); - virtual void initializeCurrentItem(); - - virtual void updateViewport(); - virtual void fixupPosition(); - virtual void fixup(AxisData &data, qreal minExtent, qreal maxExtent); - virtual bool flick(QQuickItemViewPrivate::AxisData &data, qreal minExtent, qreal maxExtent, qreal vSize, - QQuickTimeLineCallback::Callback fixupCallback, qreal velocity); + bool addVisibleItems(qreal fillFrom, qreal fillTo, qreal bufferFrom, qreal bufferTo, bool doBuffer) Q_DECL_OVERRIDE; + bool removeNonVisibleItems(qreal bufferFrom, qreal bufferTo) Q_DECL_OVERRIDE; + + FxViewItem *newViewItem(int index, QQuickItem *item) Q_DECL_OVERRIDE; + void initializeViewItem(FxViewItem *item) Q_DECL_OVERRIDE; + void repositionItemAt(FxViewItem *item, int index, qreal sizeBuffer) Q_DECL_OVERRIDE; + void repositionPackageItemAt(QQuickItem *item, int index) Q_DECL_OVERRIDE; + void resetFirstItemPosition(qreal pos = 0.0) Q_DECL_OVERRIDE; + void adjustFirstItem(qreal forwards, qreal backwards, int changeBeforeVisible) Q_DECL_OVERRIDE; + + void createHighlight() Q_DECL_OVERRIDE; + void updateHighlight() Q_DECL_OVERRIDE; + void resetHighlightPosition() Q_DECL_OVERRIDE; + + void setPosition(qreal pos) Q_DECL_OVERRIDE; + void layoutVisibleItems(int fromModelIndex = 0) Q_DECL_OVERRIDE; + bool applyInsertionChange(const QQmlChangeSet::Change &insert, ChangeResult *changeResult, QList<FxViewItem *> *addedItems, QList<MovedItem> *movingIntoView) Q_DECL_OVERRIDE; + void translateAndTransitionItemsAfter(int afterModelIndex, const ChangeResult &insertionResult, const ChangeResult &removalResult) Q_DECL_OVERRIDE; + bool needsRefillForAddedOrRemovedIndex(int index) const Q_DECL_OVERRIDE; + + qreal headerSize() const Q_DECL_OVERRIDE; + qreal footerSize() const Q_DECL_OVERRIDE; + bool showHeaderForIndex(int index) const Q_DECL_OVERRIDE; + bool showFooterForIndex(int index) const Q_DECL_OVERRIDE; + void updateHeader() Q_DECL_OVERRIDE; + void updateFooter() Q_DECL_OVERRIDE; + + void changedVisibleIndex(int newIndex) Q_DECL_OVERRIDE; + void initializeCurrentItem() Q_DECL_OVERRIDE; + + void updateViewport() Q_DECL_OVERRIDE; + void fixupPosition() Q_DECL_OVERRIDE; + void fixup(AxisData &data, qreal minExtent, qreal maxExtent) Q_DECL_OVERRIDE; + bool flick(QQuickItemViewPrivate::AxisData &data, qreal minExtent, qreal maxExtent, qreal vSize, + QQuickTimeLineCallback::Callback fixupCallback, qreal velocity) Q_DECL_OVERRIDE; QQuickGridView::Flow flow; qreal cellWidth; diff --git a/src/quick/items/qquickgridview_p.h b/src/quick/items/qquickgridview_p.h index 7468a49ac1..b835b0a070 100644 --- a/src/quick/items/qquickgridview_p.h +++ b/src/quick/items/qquickgridview_p.h @@ -65,8 +65,8 @@ public: QQuickGridView(QQuickItem *parent=0); ~QQuickGridView(); - virtual void setHighlightFollowsCurrentItem(bool); - virtual void setHighlightMoveDuration(int); + void setHighlightFollowsCurrentItem(bool) Q_DECL_OVERRIDE; + void setHighlightMoveDuration(int) Q_DECL_OVERRIDE; Flow flow() const; void setFlow(Flow); @@ -97,10 +97,10 @@ Q_SIGNALS: void snapModeChanged(); protected: - virtual void viewportMoved(Qt::Orientations); - virtual void keyPressEvent(QKeyEvent *); - virtual void geometryChanged(const QRectF &newGeometry, const QRectF &oldGeometry); - virtual void initItem(int index, QObject *item); + void viewportMoved(Qt::Orientations) Q_DECL_OVERRIDE; + void keyPressEvent(QKeyEvent *) Q_DECL_OVERRIDE; + void geometryChanged(const QRectF &newGeometry, const QRectF &oldGeometry) Q_DECL_OVERRIDE; + void initItem(int index, QObject *item) Q_DECL_OVERRIDE; }; class QQuickGridViewAttached : public QQuickItemViewAttached diff --git a/src/quick/items/qquickimage_p.h b/src/quick/items/qquickimage_p.h index b359ff779d..eef5c3901d 100644 --- a/src/quick/items/qquickimage_p.h +++ b/src/quick/items/qquickimage_p.h @@ -73,7 +73,7 @@ public: qreal paintedWidth() const; qreal paintedHeight() const; - QRectF boundingRect() const; + QRectF boundingRect() const Q_DECL_OVERRIDE; HAlignment horizontalAlignment() const; void setHorizontalAlignment(HAlignment align); @@ -81,8 +81,8 @@ public: VAlignment verticalAlignment() const; void setVerticalAlignment(VAlignment align); - bool isTextureProvider() const { return true; } - QSGTextureProvider *textureProvider() const; + bool isTextureProvider() const Q_DECL_OVERRIDE { return true; } + QSGTextureProvider *textureProvider() const Q_DECL_OVERRIDE; bool mipmap() const; void setMipmap(bool use); @@ -99,12 +99,12 @@ private Q_SLOTS: protected: QQuickImage(QQuickImagePrivate &dd, QQuickItem *parent); - void pixmapChange(); + void pixmapChange() Q_DECL_OVERRIDE; void updatePaintedGeometry(); void releaseResources() Q_DECL_OVERRIDE; - virtual void geometryChanged(const QRectF &newGeometry, const QRectF &oldGeometry); - virtual QSGNode *updatePaintNode(QSGNode *, UpdatePaintNodeData *); + void geometryChanged(const QRectF &newGeometry, const QRectF &oldGeometry) Q_DECL_OVERRIDE; + QSGNode *updatePaintNode(QSGNode *, UpdatePaintNodeData *) Q_DECL_OVERRIDE; private: Q_DISABLE_COPY(QQuickImage) diff --git a/src/quick/items/qquickimagebase_p.h b/src/quick/items/qquickimagebase_p.h index 4446268a2b..860cb2e670 100644 --- a/src/quick/items/qquickimagebase_p.h +++ b/src/quick/items/qquickimagebase_p.h @@ -91,7 +91,7 @@ Q_SIGNALS: protected: virtual void load(); - virtual void componentComplete(); + void componentComplete() Q_DECL_OVERRIDE; virtual void pixmapChange(); QQuickImageBase(QQuickImageBasePrivate &dd, QQuickItem *parent); diff --git a/src/quick/items/qquickimplicitsizeitem_p_p.h b/src/quick/items/qquickimplicitsizeitem_p_p.h index cdf768cbd9..c34e3424b0 100644 --- a/src/quick/items/qquickimplicitsizeitem_p_p.h +++ b/src/quick/items/qquickimplicitsizeitem_p_p.h @@ -60,8 +60,8 @@ public: { } - virtual void implicitWidthChanged(); - virtual void implicitHeightChanged(); + void implicitWidthChanged() Q_DECL_OVERRIDE; + void implicitHeightChanged() Q_DECL_OVERRIDE; }; QT_END_NAMESPACE diff --git a/src/quick/items/qquickitem.cpp b/src/quick/items/qquickitem.cpp index 825dd8ddfa..25f139549d 100644 --- a/src/quick/items/qquickitem.cpp +++ b/src/quick/items/qquickitem.cpp @@ -2724,8 +2724,11 @@ void QQuickItemPrivate::addChild(QQuickItem *child) #ifndef QT_NO_CURSOR QQuickItemPrivate *childPrivate = QQuickItemPrivate::get(child); - if (childPrivate->extra.isAllocated()) - incrementCursorCount(childPrivate->extra.value().numItemsWithCursor); + + // if the added child has a cursor and we do not currently have any children + // with cursors, bubble the notification up + if (childPrivate->hasCursorInChild && !hasCursorInChild) + setHasCursorInChild(true); #endif markSortedChildrenDirty(child); @@ -2747,8 +2750,10 @@ void QQuickItemPrivate::removeChild(QQuickItem *child) #ifndef QT_NO_CURSOR QQuickItemPrivate *childPrivate = QQuickItemPrivate::get(child); - if (childPrivate->extra.isAllocated()) - incrementCursorCount(-childPrivate->extra.value().numItemsWithCursor); + + // turn it off, if nothing else is using it + if (childPrivate->hasCursorInChild && hasCursorInChild) + setHasCursorInChild(false); #endif markSortedChildrenDirty(child); @@ -2843,10 +2848,8 @@ void QQuickItemPrivate::derefWindow() extra->opacityNode = 0; extra->clipNode = 0; extra->rootNode = 0; - extra->beforePaintNode = 0; } - groupNode = 0; paintNode = 0; for (int ii = 0; ii < childItems.count(); ++ii) { @@ -2952,6 +2955,7 @@ QQuickItemPrivate::QQuickItemPrivate() , isAccessible(false) , culled(false) , hasCursor(false) + , hasCursorInChild(false) , activeFocusOnTab(false) , implicitAntialiasing(false) , antialiasingValid(false) @@ -2971,7 +2975,6 @@ QQuickItemPrivate::QQuickItemPrivate() , implicitHeight(0) , baselineOffset(0) , itemNodeInstance(0) - , groupNode(0) , paintNode(0) { } @@ -6736,15 +6739,27 @@ void QQuickItem::setAcceptHoverEvents(bool enabled) d->hoverEnabled = enabled; } -void QQuickItemPrivate::incrementCursorCount(int delta) +void QQuickItemPrivate::setHasCursorInChild(bool hasCursor) { #ifndef QT_NO_CURSOR Q_Q(QQuickItem); - extra.value().numItemsWithCursor += delta; + + // if we're asked to turn it off (because of an unsetcursor call, or a node + // removal) then we should check our children and make sure it's really ok + // to turn it off. + if (!hasCursor && hasCursorInChild) { + foreach (QQuickItem *otherChild, childItems) { + QQuickItemPrivate *otherChildPrivate = QQuickItemPrivate::get(otherChild); + if (otherChildPrivate->hasCursorInChild) + return; // nope! sorry, something else wants it kept on. + } + } + + hasCursorInChild = hasCursor; QQuickItem *parent = q->parentItem(); if (parent) { QQuickItemPrivate *parentPrivate = QQuickItemPrivate::get(parent); - parentPrivate->incrementCursorCount(delta); + parentPrivate->setHasCursorInChild(hasCursor); } #endif } @@ -6807,7 +6822,7 @@ void QQuickItem::setCursor(const QCursor &cursor) } if (!d->hasCursor) { - d->incrementCursorCount(+1); + d->setHasCursorInChild(true); d->hasCursor = true; if (d->window) { QWindow *renderWindow = QQuickRenderControl::renderWindowFor(d->window); @@ -6830,7 +6845,7 @@ void QQuickItem::unsetCursor() Q_D(QQuickItem); if (!d->hasCursor) return; - d->incrementCursorCount(-1); + d->setHasCursorInChild(false); d->hasCursor = false; if (d->extra.isAllocated()) d->extra->cursor = QCursor(); @@ -7819,11 +7834,8 @@ QQuickItemPrivate::ExtraData::ExtraData() : z(0), scale(1), rotation(0), opacity(1), contents(0), screenAttached(0), layoutDirectionAttached(0), keyHandler(0), layer(0), -#ifndef QT_NO_CURSOR - numItemsWithCursor(0), -#endif effectRefCount(0), hideRefCount(0), - opacityNode(0), clipNode(0), rootNode(0), beforePaintNode(0), + opacityNode(0), clipNode(0), rootNode(0), acceptedMouseButtons(0), origin(QQuickItem::Center), transparentForPositioner(false) { diff --git a/src/quick/items/qquickitem.h b/src/quick/items/qquickitem.h index c17f6a6a7d..e93e8c1439 100644 --- a/src/quick/items/qquickitem.h +++ b/src/quick/items/qquickitem.h @@ -376,7 +376,7 @@ Q_SIGNALS: void implicitHeightChanged(); protected: - virtual bool event(QEvent *); + bool event(QEvent *) Q_DECL_OVERRIDE; bool isComponentComplete() const; virtual void itemChange(ItemChange, const ItemChangeData &); diff --git a/src/quick/items/qquickitem_p.h b/src/quick/items/qquickitem_p.h index 7ef0f903b5..02d3b820a0 100644 --- a/src/quick/items/qquickitem_p.h +++ b/src/quick/items/qquickitem_p.h @@ -92,10 +92,10 @@ public: void complete(); protected: - void itemGeometryChanged(QQuickItem *item, const QRectF &newGeometry, const QRectF &oldGeometry); - void itemDestroyed(QQuickItem *item); - void itemChildAdded(QQuickItem *, QQuickItem *); - void itemChildRemoved(QQuickItem *, QQuickItem *); + void itemGeometryChanged(QQuickItem *item, const QRectF &newGeometry, const QRectF &oldGeometry) Q_DECL_OVERRIDE; + void itemDestroyed(QQuickItem *item) Q_DECL_OVERRIDE; + void itemChildAdded(QQuickItem *, QQuickItem *) Q_DECL_OVERRIDE; + void itemChildRemoved(QQuickItem *, QQuickItem *) Q_DECL_OVERRIDE; //void itemVisibilityChanged(QQuickItem *item) private: @@ -178,11 +178,11 @@ public: QQuickShaderEffectSource *effectSource() const { return m_effectSource; } - void itemGeometryChanged(QQuickItem *, const QRectF &, const QRectF &); - void itemOpacityChanged(QQuickItem *); - void itemParentChanged(QQuickItem *, QQuickItem *); - void itemSiblingOrderChanged(QQuickItem *); - void itemVisibilityChanged(QQuickItem *); + void itemGeometryChanged(QQuickItem *, const QRectF &, const QRectF &) Q_DECL_OVERRIDE; + void itemOpacityChanged(QQuickItem *) Q_DECL_OVERRIDE; + void itemParentChanged(QQuickItem *, QQuickItem *) Q_DECL_OVERRIDE; + void itemSiblingOrderChanged(QQuickItem *) Q_DECL_OVERRIDE; + void itemVisibilityChanged(QQuickItem *) Q_DECL_OVERRIDE; void updateMatrix(); void updateGeometry(); @@ -342,7 +342,6 @@ public: mutable QQuickItemLayer *layer; #ifndef QT_NO_CURSOR QCursor cursor; - int numItemsWithCursor; #endif QPointF userTransformOriginPoint; @@ -352,7 +351,8 @@ public: QSGOpacityNode *opacityNode; QQuickDefaultClipNode *clipNode; QSGRootNode *rootNode; - QSGNode *beforePaintNode; + + QObjectList resourcesList; // Although acceptedMouseButtons is inside ExtraData, we actually store // the LeftButton flag in the extra.flag() bit. This is because it is @@ -363,7 +363,7 @@ public: QQuickItem::TransformOrigin origin:5; uint transparentForPositioner : 1; - QObjectList resourcesList; + // 26 bits padding }; QLazilyAllocated<ExtraData> extra; @@ -415,6 +415,7 @@ public: bool culled:1; bool hasCursor:1; // Bit 32 + bool hasCursorInChild:1; bool activeFocusOnTab:1; bool implicitAntialiasing:1; bool antialiasingValid:1; @@ -556,8 +557,7 @@ public: - itemNode - (opacityNode) - (clipNode) - - (effectNode) - - groupNode + - (rootNode) (shader effect source's root node) */ QSGOpacityNode *opacityNode() const { return extra.isAllocated()?extra->opacityNode:0; } @@ -565,7 +565,6 @@ public: QSGRootNode *rootNode() const { return extra.isAllocated()?extra->rootNode:0; } QSGTransformNode *itemNodeInstance; - QSGNode *groupNode; QSGNode *paintNode; virtual QSGTransformNode *createTransformNode(); @@ -579,7 +578,7 @@ public: virtual void mirrorChange() {} - void incrementCursorCount(int delta); + void setHasCursorInChild(bool hasCursor); // recursive helper to let a visual parent mark its visual children void markObjects(QV4::ExecutionEngine *e); @@ -681,8 +680,8 @@ Q_SIGNALS: void priorityChanged(); private: - virtual void keyPressed(QKeyEvent *event, bool post); - virtual void keyReleased(QKeyEvent *event, bool post); + void keyPressed(QKeyEvent *event, bool post) Q_DECL_OVERRIDE; + void keyReleased(QKeyEvent *event, bool post) Q_DECL_OVERRIDE; void setFocusNavigation(QQuickItem *currentItem, const char *dir, Qt::FocusReason reason = Qt::OtherFocusReason); }; @@ -765,7 +764,7 @@ public: return QQmlListProperty<QQuickItem>(this, d->targets); } - virtual void componentComplete(); + void componentComplete() Q_DECL_OVERRIDE; static QQuickKeysAttached *qmlAttachedProperties(QObject *); @@ -816,11 +815,11 @@ Q_SIGNALS: void volumeDownPressed(QQuickKeyEvent *event); private: - virtual void keyPressed(QKeyEvent *event, bool post); - virtual void keyReleased(QKeyEvent *event, bool post); + void keyPressed(QKeyEvent *event, bool post) Q_DECL_OVERRIDE; + void keyReleased(QKeyEvent *event, bool post) Q_DECL_OVERRIDE; #ifndef QT_NO_IM - virtual void inputMethodEvent(QInputMethodEvent *, bool post); - virtual QVariant inputMethodQuery(Qt::InputMethodQuery query) const; + void inputMethodEvent(QInputMethodEvent *, bool post) Q_DECL_OVERRIDE; + QVariant inputMethodQuery(Qt::InputMethodQuery query) const Q_DECL_OVERRIDE; #endif const QByteArray keyToSignal(int key); @@ -868,7 +867,7 @@ QSGTransformNode *QQuickItemPrivate::itemNode() itemNodeInstance->setFlag(QSGNode::OwnedByParent, false); #ifdef QSG_RUNTIME_DESCRIPTION Q_Q(QQuickItem); - qsgnode_set_description(itemNodeInstance, QString::fromLatin1("QQuickItem(%1)").arg(QString::fromLatin1(q->metaObject()->className()))); + qsgnode_set_description(itemNodeInstance, QString::fromLatin1("QQuickItem(%1:%2)").arg(QString::fromLatin1(q->metaObject()->className())).arg(q->objectName())); #endif } return itemNodeInstance; @@ -876,21 +875,14 @@ QSGTransformNode *QQuickItemPrivate::itemNode() QSGNode *QQuickItemPrivate::childContainerNode() { - if (!groupNode) { - groupNode = new QSGNode(); - if (rootNode()) - rootNode()->appendChildNode(groupNode); - else if (clipNode()) - clipNode()->appendChildNode(groupNode); - else if (opacityNode()) - opacityNode()->appendChildNode(groupNode); - else - itemNode()->appendChildNode(groupNode); -#ifdef QSG_RUNTIME_DESCRIPTION - qsgnode_set_description(groupNode, QLatin1String("group")); -#endif - } - return groupNode; + if (rootNode()) + return rootNode(); + else if (clipNode()) + return clipNode(); + else if (opacityNode()) + return opacityNode(); + else + return itemNode(); } Q_DECLARE_OPERATORS_FOR_FLAGS(QQuickItemPrivate::ChangeTypes) diff --git a/src/quick/items/qquickitemanimation.cpp b/src/quick/items/qquickitemanimation.cpp index c7c40980dc..810b487e3a 100644 --- a/src/quick/items/qquickitemanimation.cpp +++ b/src/quick/items/qquickitemanimation.cpp @@ -210,7 +210,7 @@ QAbstractAnimationJob* QQuickParentAnimation::transition(QQuickStateActions &act //### reverse should probably apply on a per-action basis bool reverse; QList<QQuickParentChange *> pc; - virtual void doAction() + void doAction() Q_DECL_OVERRIDE { for (int ii = 0; ii < actions.count(); ++ii) { const QQuickStateAction &action = actions.at(ii); diff --git a/src/quick/items/qquickitemanimation_p.h b/src/quick/items/qquickitemanimation_p.h index d16c9f8107..a1bc4b6bdf 100644 --- a/src/quick/items/qquickitemanimation_p.h +++ b/src/quick/items/qquickitemanimation_p.h @@ -69,10 +69,10 @@ Q_SIGNALS: void viaChanged(); protected: - virtual QAbstractAnimationJob* transition(QQuickStateActions &actions, + QAbstractAnimationJob* transition(QQuickStateActions &actions, QQmlProperties &modified, TransitionDirection direction, - QObject *defaultTarget = 0); + QObject *defaultTarget = 0) Q_DECL_OVERRIDE; }; class QQuickAnchorAnimationPrivate; @@ -101,10 +101,10 @@ Q_SIGNALS: void easingChanged(const QEasingCurve&); protected: - virtual QAbstractAnimationJob* transition(QQuickStateActions &actions, + QAbstractAnimationJob* transition(QQuickStateActions &actions, QQmlProperties &modified, TransitionDirection direction, - QObject *defaultTarget = 0); + QObject *defaultTarget = 0) Q_DECL_OVERRIDE; }; class QQuickItem; @@ -166,10 +166,10 @@ public: void setEndRotation(qreal); protected: - virtual QAbstractAnimationJob* transition(QQuickStateActions &actions, + QAbstractAnimationJob* transition(QQuickStateActions &actions, QQmlProperties &modified, TransitionDirection direction, - QObject *defaultTarget = 0); + QObject *defaultTarget = 0) Q_DECL_OVERRIDE; Q_SIGNALS: void durationChanged(int); void easingChanged(const QEasingCurve &); diff --git a/src/quick/items/qquickitemview_p.h b/src/quick/items/qquickitemview_p.h index 89c3bec465..3e7acdd26c 100644 --- a/src/quick/items/qquickitemview_p.h +++ b/src/quick/items/qquickitemview_p.h @@ -208,10 +208,10 @@ public: Q_INVOKABLE void positionViewAtEnd(); Q_REVISION(1) Q_INVOKABLE void forceLayout(); - virtual void setContentX(qreal pos); - virtual void setContentY(qreal pos); - virtual qreal originX() const; - virtual qreal originY() const; + void setContentX(qreal pos) Q_DECL_OVERRIDE; + void setContentY(qreal pos) Q_DECL_OVERRIDE; + qreal originX() const Q_DECL_OVERRIDE; + qreal originY() const Q_DECL_OVERRIDE; Q_SIGNALS: void modelChanged(); @@ -252,13 +252,13 @@ Q_SIGNALS: void highlightMoveDurationChanged(); protected: - virtual void updatePolish(); - virtual void componentComplete(); - virtual void geometryChanged(const QRectF &newGeometry, const QRectF &oldGeometry); - virtual qreal minYExtent() const; - virtual qreal maxYExtent() const; - virtual qreal minXExtent() const; - virtual qreal maxXExtent() const; + void updatePolish() Q_DECL_OVERRIDE; + void componentComplete() Q_DECL_OVERRIDE; + void geometryChanged(const QRectF &newGeometry, const QRectF &oldGeometry) Q_DECL_OVERRIDE; + qreal minYExtent() const Q_DECL_OVERRIDE; + qreal maxYExtent() const Q_DECL_OVERRIDE; + qreal minXExtent() const Q_DECL_OVERRIDE; + qreal maxXExtent() const Q_DECL_OVERRIDE; protected Q_SLOTS: void destroyRemoved(); diff --git a/src/quick/items/qquickitemview_p_p.h b/src/quick/items/qquickitemview_p_p.h index 76fc326367..b053b1ea6e 100644 --- a/src/quick/items/qquickitemview_p_p.h +++ b/src/quick/items/qquickitemview_p_p.h @@ -181,7 +181,7 @@ public: virtual void animationFinished(QAbstractAnimationJob *); void refill(); void refill(qreal from, qreal to); - void mirrorChange(); + void mirrorChange() Q_DECL_OVERRIDE; FxViewItem *createItem(int modelIndex, bool asynchronous = false); virtual bool releaseItem(FxViewItem *item); @@ -211,7 +211,7 @@ public: void prepareVisibleItemTransitions(); void prepareRemoveTransitions(QHash<QQmlChangeSet::MoveKey, FxViewItem *> *removedItems); bool prepareNonVisibleItemTransition(FxViewItem *item, const QRectF &viewBounds); - virtual void viewItemTransitionFinished(QQuickItemViewTransitionableItem *item); + void viewItemTransitionFinished(QQuickItemViewTransitionableItem *item) Q_DECL_OVERRIDE; int findMoveKeyIndex(QQmlChangeSet::MoveKey key, const QVector<QQmlChangeSet::Change> &changes) const; @@ -353,7 +353,7 @@ protected: virtual void updateSectionCriteria() {} virtual void updateSections() {} - virtual void itemGeometryChanged(QQuickItem *item, const QRectF &newGeometry, const QRectF &oldGeometry); + void itemGeometryChanged(QQuickItem *item, const QRectF &newGeometry, const QRectF &oldGeometry) Q_DECL_OVERRIDE; }; diff --git a/src/quick/items/qquickitemviewtransition.cpp b/src/quick/items/qquickitemviewtransition.cpp index 41ee9bb1f2..9c14133cbd 100644 --- a/src/quick/items/qquickitemviewtransition.cpp +++ b/src/quick/items/qquickitemviewtransition.cpp @@ -57,7 +57,7 @@ public: bool *m_wasDeleted; protected: - virtual void finished(); + void finished() Q_DECL_OVERRIDE; }; diff --git a/src/quick/items/qquicklistview.cpp b/src/quick/items/qquicklistview.cpp index d381fe2030..851204ccde 100644 --- a/src/quick/items/qquicklistview.cpp +++ b/src/quick/items/qquicklistview.cpp @@ -59,49 +59,49 @@ class QQuickListViewPrivate : public QQuickItemViewPrivate public: static QQuickListViewPrivate* get(QQuickListView *item) { return item->d_func(); } - virtual Qt::Orientation layoutOrientation() const; - virtual bool isContentFlowReversed() const; + Qt::Orientation layoutOrientation() const Q_DECL_OVERRIDE; + bool isContentFlowReversed() const Q_DECL_OVERRIDE; bool isRightToLeft() const; bool isBottomToTop() const; - virtual qreal positionAt(int index) const; - virtual qreal endPositionAt(int index) const; - virtual qreal originPosition() const; - virtual qreal lastPosition() const; + qreal positionAt(int index) const Q_DECL_OVERRIDE; + qreal endPositionAt(int index) const Q_DECL_OVERRIDE; + qreal originPosition() const Q_DECL_OVERRIDE; + qreal lastPosition() const Q_DECL_OVERRIDE; FxViewItem *itemBefore(int modelIndex) const; QString sectionAt(int modelIndex); qreal snapPosAt(qreal pos); FxViewItem *snapItemAt(qreal pos); - virtual void init(); - virtual void clear(); + void init() Q_DECL_OVERRIDE; + void clear() Q_DECL_OVERRIDE; - virtual bool addVisibleItems(qreal fillFrom, qreal fillTo, qreal bufferFrom, qreal bufferTo, bool doBuffer); - virtual bool removeNonVisibleItems(qreal bufferFrom, qreal bufferTo); - virtual void visibleItemsChanged(); + bool addVisibleItems(qreal fillFrom, qreal fillTo, qreal bufferFrom, qreal bufferTo, bool doBuffer) Q_DECL_OVERRIDE; + bool removeNonVisibleItems(qreal bufferFrom, qreal bufferTo) Q_DECL_OVERRIDE; + void visibleItemsChanged() Q_DECL_OVERRIDE; - virtual FxViewItem *newViewItem(int index, QQuickItem *item); - virtual void initializeViewItem(FxViewItem *item); - virtual bool releaseItem(FxViewItem *item); - virtual void repositionItemAt(FxViewItem *item, int index, qreal sizeBuffer); - virtual void repositionPackageItemAt(QQuickItem *item, int index); - virtual void resetFirstItemPosition(qreal pos = 0.0); - virtual void adjustFirstItem(qreal forwards, qreal backwards, int); - virtual void updateSizeChangesBeforeVisiblePos(FxViewItem *item, ChangeResult *removeResult); + FxViewItem *newViewItem(int index, QQuickItem *item) Q_DECL_OVERRIDE; + void initializeViewItem(FxViewItem *item) Q_DECL_OVERRIDE; + bool releaseItem(FxViewItem *item) Q_DECL_OVERRIDE; + void repositionItemAt(FxViewItem *item, int index, qreal sizeBuffer) Q_DECL_OVERRIDE; + void repositionPackageItemAt(QQuickItem *item, int index) Q_DECL_OVERRIDE; + void resetFirstItemPosition(qreal pos = 0.0) Q_DECL_OVERRIDE; + void adjustFirstItem(qreal forwards, qreal backwards, int) Q_DECL_OVERRIDE; + void updateSizeChangesBeforeVisiblePos(FxViewItem *item, ChangeResult *removeResult) Q_DECL_OVERRIDE; - virtual void createHighlight(); - virtual void updateHighlight(); - virtual void resetHighlightPosition(); + void createHighlight() Q_DECL_OVERRIDE; + void updateHighlight() Q_DECL_OVERRIDE; + void resetHighlightPosition() Q_DECL_OVERRIDE; - virtual void setPosition(qreal pos); - virtual void layoutVisibleItems(int fromModelIndex = 0); + void setPosition(qreal pos) Q_DECL_OVERRIDE; + void layoutVisibleItems(int fromModelIndex = 0) Q_DECL_OVERRIDE; - virtual bool applyInsertionChange(const QQmlChangeSet::Change &insert, ChangeResult *changeResult, QList<FxViewItem *> *addedItems, QList<MovedItem> *movingIntoView); - virtual void translateAndTransitionItemsAfter(int afterIndex, const ChangeResult &insertionResult, const ChangeResult &removalResult); + bool applyInsertionChange(const QQmlChangeSet::Change &insert, ChangeResult *changeResult, QList<FxViewItem *> *addedItems, QList<MovedItem> *movingIntoView) Q_DECL_OVERRIDE; + void translateAndTransitionItemsAfter(int afterIndex, const ChangeResult &insertionResult, const ChangeResult &removalResult) Q_DECL_OVERRIDE; - virtual void updateSectionCriteria(); - virtual void updateSections(); + void updateSectionCriteria() Q_DECL_OVERRIDE; + void updateSections() Q_DECL_OVERRIDE; QQuickItem *getSectionItem(const QString §ion); void releaseSectionItem(QQuickItem *item); void releaseSectionItems(); @@ -109,25 +109,25 @@ public: void updateCurrentSection(); void updateStickySections(); - virtual qreal headerSize() const; - virtual qreal footerSize() const; - virtual bool showHeaderForIndex(int index) const; - virtual bool showFooterForIndex(int index) const; - virtual void updateHeader(); - virtual void updateFooter(); + qreal headerSize() const Q_DECL_OVERRIDE; + qreal footerSize() const Q_DECL_OVERRIDE; + bool showHeaderForIndex(int index) const Q_DECL_OVERRIDE; + bool showFooterForIndex(int index) const Q_DECL_OVERRIDE; + void updateHeader() Q_DECL_OVERRIDE; + void updateFooter() Q_DECL_OVERRIDE; bool hasStickyHeader() const; bool hasStickyFooter() const; - virtual void changedVisibleIndex(int newIndex); - virtual void initializeCurrentItem(); + void changedVisibleIndex(int newIndex) Q_DECL_OVERRIDE; + void initializeCurrentItem() Q_DECL_OVERRIDE; void updateAverage(); - void itemGeometryChanged(QQuickItem *item, const QRectF &newGeometry, const QRectF &oldGeometry); - virtual void fixupPosition(); - virtual void fixup(AxisData &data, qreal minExtent, qreal maxExtent); - virtual bool flick(QQuickItemViewPrivate::AxisData &data, qreal minExtent, qreal maxExtent, qreal vSize, - QQuickTimeLineCallback::Callback fixupCallback, qreal velocity); + void itemGeometryChanged(QQuickItem *item, const QRectF &newGeometry, const QRectF &oldGeometry) Q_DECL_OVERRIDE; + void fixupPosition() Q_DECL_OVERRIDE; + void fixup(AxisData &data, qreal minExtent, qreal maxExtent) Q_DECL_OVERRIDE; + bool flick(QQuickItemViewPrivate::AxisData &data, qreal minExtent, qreal maxExtent, qreal vSize, + QQuickTimeLineCallback::Callback fixupCallback, qreal velocity) Q_DECL_OVERRIDE; QQuickListView::Orientation orient; qreal visiblePos; @@ -319,7 +319,7 @@ public: else item->setWidth(size); } - bool contains(qreal x, qreal y) const { + bool contains(qreal x, qreal y) const Q_DECL_OVERRIDE { return (x >= itemX() && x < itemX() + item->width() && y >= itemY() && y < itemY() + item->height()); } diff --git a/src/quick/items/qquicklistview_p.h b/src/quick/items/qquicklistview_p.h index a02fba258e..2801879b0f 100644 --- a/src/quick/items/qquicklistview_p.h +++ b/src/quick/items/qquicklistview_p.h @@ -126,7 +126,7 @@ public: QQuickViewSection *sectionCriteria(); QString currentSection() const; - virtual void setHighlightFollowsCurrentItem(bool); + void setHighlightFollowsCurrentItem(bool) Q_DECL_OVERRIDE; qreal highlightMoveVelocity() const; void setHighlightMoveVelocity(qreal); @@ -137,7 +137,7 @@ public: int highlightResizeDuration() const; void setHighlightResizeDuration(int); - virtual void setHighlightMoveDuration(int); + void setHighlightMoveDuration(int) Q_DECL_OVERRIDE; enum SnapMode { NoSnap, SnapToItem, SnapOneItem }; SnapMode snapMode() const; @@ -169,10 +169,10 @@ Q_SIGNALS: Q_REVISION(2) void footerPositioningChanged(); protected: - virtual void viewportMoved(Qt::Orientations orient); - virtual void keyPressEvent(QKeyEvent *); - virtual void geometryChanged(const QRectF &newGeometry,const QRectF &oldGeometry); - virtual void initItem(int index, QObject *item); + void viewportMoved(Qt::Orientations orient) Q_DECL_OVERRIDE; + void keyPressEvent(QKeyEvent *) Q_DECL_OVERRIDE; + void geometryChanged(const QRectF &newGeometry,const QRectF &oldGeometry) Q_DECL_OVERRIDE; + void initItem(int index, QObject *item) Q_DECL_OVERRIDE; }; class QQuickListViewAttached : public QQuickItemViewAttached diff --git a/src/quick/items/qquickloader_p.h b/src/quick/items/qquickloader_p.h index 3e0cba5865..640897d507 100644 --- a/src/quick/items/qquickloader_p.h +++ b/src/quick/items/qquickloader_p.h @@ -88,8 +88,8 @@ Q_SIGNALS: void asynchronousChanged(); protected: - void geometryChanged(const QRectF &newGeometry, const QRectF &oldGeometry); - void componentComplete(); + void geometryChanged(const QRectF &newGeometry, const QRectF &oldGeometry) Q_DECL_OVERRIDE; + void componentComplete() Q_DECL_OVERRIDE; private: void setSource(const QUrl &sourceUrl, bool needsClear); diff --git a/src/quick/items/qquickloader_p_p.h b/src/quick/items/qquickloader_p_p.h index cae42a79ad..15e144855c 100644 --- a/src/quick/items/qquickloader_p_p.h +++ b/src/quick/items/qquickloader_p_p.h @@ -62,8 +62,8 @@ public: QQuickLoaderIncubator(QQuickLoaderPrivate *l, IncubationMode mode) : QQmlIncubator(mode), loader(l) {} protected: - virtual void statusChanged(Status); - virtual void setInitialState(QObject *); + void statusChanged(Status) Q_DECL_OVERRIDE; + void setInitialState(QObject *) Q_DECL_OVERRIDE; private: QQuickLoaderPrivate *loader; @@ -78,9 +78,9 @@ public: QQuickLoaderPrivate(); ~QQuickLoaderPrivate(); - void itemGeometryChanged(QQuickItem *item, const QRectF &newGeometry, const QRectF &oldGeometry); - void itemImplicitWidthChanged(QQuickItem *); - void itemImplicitHeightChanged(QQuickItem *); + void itemGeometryChanged(QQuickItem *item, const QRectF &newGeometry, const QRectF &oldGeometry) Q_DECL_OVERRIDE; + void itemImplicitWidthChanged(QQuickItem *) Q_DECL_OVERRIDE; + void itemImplicitHeightChanged(QQuickItem *) Q_DECL_OVERRIDE; void clear(); void initResize(); void load(); @@ -91,8 +91,8 @@ public: QUrl resolveSourceUrl(QQmlV4Function *args); QV4::ReturnedValue extractInitialPropertyValues(QQmlV4Function *args, QObject *loader, bool *error); - virtual qreal getImplicitWidth() const; - virtual qreal getImplicitHeight() const; + qreal getImplicitWidth() const Q_DECL_OVERRIDE; + qreal getImplicitHeight() const Q_DECL_OVERRIDE; QUrl source; QQuickItem *item; diff --git a/src/quick/items/qquickmultipointtoucharea_p.h b/src/quick/items/qquickmultipointtoucharea_p.h index 6d3e607d08..a1569548c9 100644 --- a/src/quick/items/qquickmultipointtoucharea_p.h +++ b/src/quick/items/qquickmultipointtoucharea_p.h @@ -228,13 +228,13 @@ Q_SIGNALS: void mouseEnabledChanged(); protected: - void touchEvent(QTouchEvent *); - bool childMouseEventFilter(QQuickItem *i, QEvent *event); - void mousePressEvent(QMouseEvent *event); - void mouseReleaseEvent(QMouseEvent *event); - void mouseMoveEvent(QMouseEvent *event); - void mouseUngrabEvent(); - void touchUngrabEvent(); + void touchEvent(QTouchEvent *) Q_DECL_OVERRIDE; + bool childMouseEventFilter(QQuickItem *i, QEvent *event) Q_DECL_OVERRIDE; + void mousePressEvent(QMouseEvent *event) Q_DECL_OVERRIDE; + void mouseReleaseEvent(QMouseEvent *event) Q_DECL_OVERRIDE; + void mouseMoveEvent(QMouseEvent *event) Q_DECL_OVERRIDE; + void mouseUngrabEvent() Q_DECL_OVERRIDE; + void touchUngrabEvent() Q_DECL_OVERRIDE; void addTouchPrototype(QQuickTouchPoint* prototype); void addTouchPoint(const QTouchEvent::TouchPoint *p); @@ -248,10 +248,10 @@ protected: bool sendMouseEvent(QMouseEvent *event); bool shouldFilter(QEvent *event); void grabGesture(); - virtual QSGNode *updatePaintNode(QSGNode *, UpdatePaintNodeData *); + QSGNode *updatePaintNode(QSGNode *, UpdatePaintNodeData *) Q_DECL_OVERRIDE; #ifdef Q_OS_OSX - void hoverEnterEvent(QHoverEvent *event); - void hoverLeaveEvent(QHoverEvent *event); + void hoverEnterEvent(QHoverEvent *event) Q_DECL_OVERRIDE; + void hoverLeaveEvent(QHoverEvent *event) Q_DECL_OVERRIDE; void setTouchEventsEnabled(bool enable); #endif diff --git a/src/quick/items/qquickpainteditem.h b/src/quick/items/qquickpainteditem.h index b5e04694bf..fc14574a8d 100644 --- a/src/quick/items/qquickpainteditem.h +++ b/src/quick/items/qquickpainteditem.h @@ -107,7 +107,7 @@ Q_SIGNALS: protected: QQuickPaintedItem(QQuickPaintedItemPrivate &dd, QQuickItem *parent = 0); - virtual QSGNode *updatePaintNode(QSGNode *, UpdatePaintNodeData *); + QSGNode *updatePaintNode(QSGNode *, UpdatePaintNodeData *) Q_DECL_OVERRIDE; void releaseResources() Q_DECL_OVERRIDE; private Q_SLOTS: diff --git a/src/quick/items/qquickpathview_p.h b/src/quick/items/qquickpathview_p.h index 74ee4908b2..e57557204e 100644 --- a/src/quick/items/qquickpathview_p.h +++ b/src/quick/items/qquickpathview_p.h @@ -193,14 +193,14 @@ Q_SIGNALS: void cacheItemCountChanged(); protected: - virtual void updatePolish(); - void mousePressEvent(QMouseEvent *event); - void mouseMoveEvent(QMouseEvent *event); - void mouseReleaseEvent(QMouseEvent *); + void updatePolish() Q_DECL_OVERRIDE; + void mousePressEvent(QMouseEvent *event) Q_DECL_OVERRIDE; + void mouseMoveEvent(QMouseEvent *event) Q_DECL_OVERRIDE; + void mouseReleaseEvent(QMouseEvent *) Q_DECL_OVERRIDE; bool sendMouseEvent(QMouseEvent *event); - bool childMouseEventFilter(QQuickItem *, QEvent *); - void mouseUngrabEvent(); - void componentComplete(); + bool childMouseEventFilter(QQuickItem *, QEvent *) Q_DECL_OVERRIDE; + void mouseUngrabEvent() Q_DECL_OVERRIDE; + void componentComplete() Q_DECL_OVERRIDE; private Q_SLOTS: void refill(); diff --git a/src/quick/items/qquickpathview_p_p.h b/src/quick/items/qquickpathview_p_p.h index cd52dd10bb..7c0e651b69 100644 --- a/src/quick/items/qquickpathview_p_p.h +++ b/src/quick/items/qquickpathview_p_p.h @@ -69,7 +69,7 @@ public: void init(); - void itemGeometryChanged(QQuickItem *item, const QRectF &newGeometry, const QRectF &oldGeometry) { + void itemGeometryChanged(QQuickItem *item, const QRectF &newGeometry, const QRectF &oldGeometry) Q_DECL_OVERRIDE { if ((newGeometry.size() != oldGeometry.size()) && (!highlightItem || item != highlightItem)) { if (QQuickPathViewAttached *att = attached(item)) diff --git a/src/quick/items/qquickpincharea_p.h b/src/quick/items/qquickpincharea_p.h index b82db035e5..28db59fb55 100644 --- a/src/quick/items/qquickpincharea_p.h +++ b/src/quick/items/qquickpincharea_p.h @@ -268,15 +268,15 @@ Q_SIGNALS: void pinchFinished(QQuickPinchEvent *pinch); protected: - virtual bool childMouseEventFilter(QQuickItem *i, QEvent *e); - virtual void touchEvent(QTouchEvent *event); + bool childMouseEventFilter(QQuickItem *i, QEvent *e) Q_DECL_OVERRIDE; + void touchEvent(QTouchEvent *event) Q_DECL_OVERRIDE; - virtual void geometryChanged(const QRectF &newGeometry, - const QRectF &oldGeometry); - virtual void itemChange(ItemChange change, const ItemChangeData& value); + void geometryChanged(const QRectF &newGeometry, + const QRectF &oldGeometry) Q_DECL_OVERRIDE; + void itemChange(ItemChange change, const ItemChangeData& value) Q_DECL_OVERRIDE; #ifdef Q_OS_OSX - void hoverEnterEvent(QHoverEvent *event); - void hoverLeaveEvent(QHoverEvent *event); + void hoverEnterEvent(QHoverEvent *event) Q_DECL_OVERRIDE; + void hoverLeaveEvent(QHoverEvent *event) Q_DECL_OVERRIDE; void setTouchEventsEnabled(bool enable); #endif diff --git a/src/quick/items/qquickpositioners_p.h b/src/quick/items/qquickpositioners_p.h index 7df4ee3b9a..164ea86c71 100644 --- a/src/quick/items/qquickpositioners_p.h +++ b/src/quick/items/qquickpositioners_p.h @@ -110,10 +110,10 @@ public: protected: QQuickBasePositioner(QQuickBasePositionerPrivate &dd, PositionerType at, QQuickItem *parent); - virtual void componentComplete(); - virtual void itemChange(ItemChange, const ItemChangeData &); + void componentComplete() Q_DECL_OVERRIDE; + void itemChange(ItemChange, const ItemChangeData &) Q_DECL_OVERRIDE; - virtual void updatePolish(); + void updatePolish() Q_DECL_OVERRIDE; Q_SIGNALS: void spacingChanged(); @@ -173,8 +173,8 @@ public: QQuickColumn(QQuickItem *parent=0); protected: - virtual void doPositioning(QSizeF *contentSize); - virtual void reportConflictingAnchors(); + void doPositioning(QSizeF *contentSize) Q_DECL_OVERRIDE; + void reportConflictingAnchors() Q_DECL_OVERRIDE; private: Q_DISABLE_COPY(QQuickColumn) }; @@ -197,8 +197,8 @@ Q_SIGNALS: void effectiveLayoutDirectionChanged(); protected: - virtual void doPositioning(QSizeF *contentSize); - virtual void reportConflictingAnchors(); + void doPositioning(QSizeF *contentSize) Q_DECL_OVERRIDE; + void reportConflictingAnchors() Q_DECL_OVERRIDE; private: Q_DISABLE_COPY(QQuickRow) Q_DECLARE_PRIVATE(QQuickRow) @@ -274,8 +274,8 @@ Q_SIGNALS: Q_REVISION(1) void verticalAlignmentChanged(VAlignment alignment); protected: - virtual void doPositioning(QSizeF *contentSize); - virtual void reportConflictingAnchors(); + void doPositioning(QSizeF *contentSize) Q_DECL_OVERRIDE; + void reportConflictingAnchors() Q_DECL_OVERRIDE; private: int m_rows; @@ -316,8 +316,8 @@ Q_SIGNALS: void effectiveLayoutDirectionChanged(); protected: - virtual void doPositioning(QSizeF *contentSize); - virtual void reportConflictingAnchors(); + void doPositioning(QSizeF *contentSize) Q_DECL_OVERRIDE; + void reportConflictingAnchors() Q_DECL_OVERRIDE; protected: QQuickFlow(QQuickFlowPrivate &dd, QQuickItem *parent); private: diff --git a/src/quick/items/qquickpositioners_p_p.h b/src/quick/items/qquickpositioners_p_p.h index e77997d4e9..cdcb09cf49 100644 --- a/src/quick/items/qquickpositioners_p_p.h +++ b/src/quick/items/qquickpositioners_p_p.h @@ -98,7 +98,7 @@ public: Qt::LayoutDirection layoutDirection; - void mirrorChange() { + void mirrorChange() Q_DECL_OVERRIDE { effectiveLayoutDirectionChange(); } bool isLeftToRight() const { @@ -108,24 +108,24 @@ public: return effectiveLayoutMirror ? layoutDirection == Qt::RightToLeft : layoutDirection == Qt::LeftToRight; } - virtual void itemSiblingOrderChanged(QQuickItem* other) + void itemSiblingOrderChanged(QQuickItem* other) Q_DECL_OVERRIDE { Q_UNUSED(other); setPositioningDirty(); } - void itemGeometryChanged(QQuickItem *, const QRectF &newGeometry, const QRectF &oldGeometry) + void itemGeometryChanged(QQuickItem *, const QRectF &newGeometry, const QRectF &oldGeometry) Q_DECL_OVERRIDE { if (newGeometry.size() != oldGeometry.size()) setPositioningDirty(); } - virtual void itemVisibilityChanged(QQuickItem *) + void itemVisibilityChanged(QQuickItem *) Q_DECL_OVERRIDE { setPositioningDirty(); } - void itemDestroyed(QQuickItem *item) + void itemDestroyed(QQuickItem *item) Q_DECL_OVERRIDE { Q_Q(QQuickBasePositioner); int index = q->positionedItems.find(QQuickBasePositioner::PositionedItem(item)); diff --git a/src/quick/items/qquickrectangle_p.h b/src/quick/items/qquickrectangle_p.h index 2e9eabd1d5..18922630f8 100644 --- a/src/quick/items/qquickrectangle_p.h +++ b/src/quick/items/qquickrectangle_p.h @@ -153,7 +153,7 @@ Q_SIGNALS: void radiusChanged(); protected: - virtual QSGNode *updatePaintNode(QSGNode *, UpdatePaintNodeData *); + QSGNode *updatePaintNode(QSGNode *, UpdatePaintNodeData *) Q_DECL_OVERRIDE; private Q_SLOTS: void doUpdate(); diff --git a/src/quick/items/qquickrepeater_p.h b/src/quick/items/qquickrepeater_p.h index 159520a89d..d1ca686e78 100644 --- a/src/quick/items/qquickrepeater_p.h +++ b/src/quick/items/qquickrepeater_p.h @@ -77,8 +77,8 @@ private: void regenerate(); protected: - virtual void componentComplete(); - void itemChange(ItemChange change, const ItemChangeData &value); + void componentComplete() Q_DECL_OVERRIDE; + void itemChange(ItemChange change, const ItemChangeData &value) Q_DECL_OVERRIDE; private Q_SLOTS: void createdItem(int index, QObject *item); diff --git a/src/quick/items/qquickshadereffect_p.h b/src/quick/items/qquickshadereffect_p.h index 99e88a653d..8c5da9e5d5 100644 --- a/src/quick/items/qquickshadereffect_p.h +++ b/src/quick/items/qquickshadereffect_p.h @@ -136,7 +136,7 @@ public: QString parseLog(); - virtual bool event(QEvent *); + bool event(QEvent *) Q_DECL_OVERRIDE; Q_SIGNALS: void fragmentShaderChanged(); @@ -149,10 +149,10 @@ Q_SIGNALS: void supportsAtlasTexturesChanged(); protected: - virtual void geometryChanged(const QRectF &newGeometry, const QRectF &oldGeometry); - virtual QSGNode *updatePaintNode(QSGNode *, UpdatePaintNodeData *); - virtual void componentComplete(); - virtual void itemChange(ItemChange change, const ItemChangeData &value); + void geometryChanged(const QRectF &newGeometry, const QRectF &oldGeometry) Q_DECL_OVERRIDE; + QSGNode *updatePaintNode(QSGNode *, UpdatePaintNodeData *) Q_DECL_OVERRIDE; + void componentComplete() Q_DECL_OVERRIDE; + void itemChange(ItemChange change, const ItemChangeData &value) Q_DECL_OVERRIDE; private Q_SLOTS: void updateGeometry(); diff --git a/src/quick/items/qquickshadereffectmesh_p.h b/src/quick/items/qquickshadereffectmesh_p.h index 5bcf633fa3..684f8461d8 100644 --- a/src/quick/items/qquickshadereffectmesh_p.h +++ b/src/quick/items/qquickshadereffectmesh_p.h @@ -69,8 +69,8 @@ class QQuickGridMesh : public QQuickShaderEffectMesh Q_PROPERTY(QSize resolution READ resolution WRITE setResolution NOTIFY resolutionChanged) public: QQuickGridMesh(QObject *parent = 0); - virtual QSGGeometry *updateGeometry(QSGGeometry *geometry, const QVector<QByteArray> &attributes, const QRectF &srcRect, const QRectF &rect); - virtual QString log() const { return m_log; } + QSGGeometry *updateGeometry(QSGGeometry *geometry, const QVector<QByteArray> &attributes, const QRectF &srcRect, const QRectF &rect) Q_DECL_OVERRIDE; + QString log() const Q_DECL_OVERRIDE { return m_log; } void setResolution(const QSize &res); QSize resolution() const; diff --git a/src/quick/items/qquickshadereffectnode.cpp b/src/quick/items/qquickshadereffectnode.cpp index 43220a0e29..df379b8a3b 100644 --- a/src/quick/items/qquickshadereffectnode.cpp +++ b/src/quick/items/qquickshadereffectnode.cpp @@ -45,16 +45,16 @@ class QQuickCustomMaterialShader : public QSGMaterialShader { public: QQuickCustomMaterialShader(const QQuickShaderEffectMaterialKey &key, const QVector<QByteArray> &attributes); - virtual void deactivate(); - virtual void updateState(const RenderState &state, QSGMaterial *newEffect, QSGMaterial *oldEffect); - virtual char const *const *attributeNames() const; + void deactivate() Q_DECL_OVERRIDE; + void updateState(const RenderState &state, QSGMaterial *newEffect, QSGMaterial *oldEffect) Q_DECL_OVERRIDE; + char const *const *attributeNames() const Q_DECL_OVERRIDE; protected: friend class QQuickShaderEffectNode; - virtual void compile(); - virtual const char *vertexShader() const; - virtual const char *fragmentShader() const; + void compile() Q_DECL_OVERRIDE; + const char *vertexShader() const Q_DECL_OVERRIDE; + const char *fragmentShader() const Q_DECL_OVERRIDE; const QQuickShaderEffectMaterialKey m_key; QVector<QByteArray> m_attributes; diff --git a/src/quick/items/qquickshadereffectnode_p.h b/src/quick/items/qquickshadereffectnode_p.h index fc7c643aea..507db337aa 100644 --- a/src/quick/items/qquickshadereffectnode_p.h +++ b/src/quick/items/qquickshadereffectnode_p.h @@ -87,9 +87,9 @@ public: }; explicit QQuickShaderEffectMaterial(QQuickShaderEffectNode *node = 0); - virtual QSGMaterialType *type() const; - virtual QSGMaterialShader *createShader() const; - virtual int compare(const QSGMaterial *other) const; + QSGMaterialType *type() const Q_DECL_OVERRIDE; + QSGMaterialShader *createShader() const Q_DECL_OVERRIDE; + int compare(const QSGMaterial *other) const Q_DECL_OVERRIDE; QVector<QByteArray> attributes; QVector<UniformData> uniforms[QQuickShaderEffectMaterialKey::ShaderTypeCount]; @@ -129,7 +129,7 @@ public: QQuickShaderEffectNode(); virtual ~QQuickShaderEffectNode(); - virtual void preprocess(); + void preprocess() Q_DECL_OVERRIDE; Q_SIGNALS: void logAndStatusChanged(const QString &, int status); diff --git a/src/quick/items/qquickshadereffectsource_p.h b/src/quick/items/qquickshadereffectsource_p.h index 69e65f927f..7add0b1033 100644 --- a/src/quick/items/qquickshadereffectsource_p.h +++ b/src/quick/items/qquickshadereffectsource_p.h @@ -112,8 +112,8 @@ public: bool recursive() const; void setRecursive(bool enabled); - bool isTextureProvider() const { return true; } - QSGTextureProvider *textureProvider() const; + bool isTextureProvider() const Q_DECL_OVERRIDE { return true; } + QSGTextureProvider *textureProvider() const Q_DECL_OVERRIDE; Q_INVOKABLE void scheduleUpdate(); @@ -135,11 +135,11 @@ private Q_SLOTS: void invalidateSceneGraph(); protected: - virtual void releaseResources(); - virtual QSGNode *updatePaintNode(QSGNode *, UpdatePaintNodeData *); + void releaseResources() Q_DECL_OVERRIDE; + QSGNode *updatePaintNode(QSGNode *, UpdatePaintNodeData *) Q_DECL_OVERRIDE; - virtual void itemGeometryChanged(QQuickItem *item, const QRectF &newRect, const QRectF &oldRect); - virtual void itemChange(ItemChange change, const ItemChangeData &value); + void itemGeometryChanged(QQuickItem *item, const QRectF &newRect, const QRectF &oldRect) Q_DECL_OVERRIDE; + void itemChange(ItemChange change, const ItemChangeData &value) Q_DECL_OVERRIDE; private: void ensureTexture(); diff --git a/src/quick/items/qquicksprite_p.h b/src/quick/items/qquicksprite_p.h index 1bd625001d..a38a284201 100644 --- a/src/quick/items/qquicksprite_p.h +++ b/src/quick/items/qquicksprite_p.h @@ -138,7 +138,7 @@ public: return m_frameDurationVariation; } - int variedDuration() const; + int variedDuration() const Q_DECL_OVERRIDE; bool frameSync() const { diff --git a/src/quick/items/qquickspriteengine.cpp b/src/quick/items/qquickspriteengine.cpp index c5e70c9a8b..12020e879b 100644 --- a/src/quick/items/qquickspriteengine.cpp +++ b/src/quick/items/qquickspriteengine.cpp @@ -201,10 +201,12 @@ int QQuickSpriteEngine::spriteFrames(int sprite) extra = (m_sprites[state]->m_generatedCount - 1) - extra; - if (extra == m_sprites[state]->m_generatedCount - 1)//last state - return m_sprites[state]->frames() % m_sprites[state]->m_framesPerRow; - else - return m_sprites[state]->m_framesPerRow; + if (extra == m_sprites[state]->m_generatedCount - 1) {//last state + const int framesRemaining = m_sprites[state]->frames() % m_sprites[state]->m_framesPerRow; + if (framesRemaining > 0) + return framesRemaining; + } + return m_sprites[state]->m_framesPerRow; } int QQuickSpriteEngine::spriteDuration(int sprite)//Full duration, not per frame @@ -219,10 +221,12 @@ int QQuickSpriteEngine::spriteDuration(int sprite)//Full duration, not per frame if (m_sprites[state]->reverse()) extra = (m_sprites[state]->m_generatedCount - 1) - extra; - if (extra == m_sprites[state]->m_generatedCount - 1)//last state - return m_duration[sprite] % rowDuration; - else - return rowDuration; + if (extra == m_sprites[state]->m_generatedCount - 1) {//last state + const int durationRemaining = m_duration[sprite] % rowDuration; + if (durationRemaining > 0) + return durationRemaining; + } + return rowDuration; } int QQuickSpriteEngine::spriteY(int sprite) @@ -512,7 +516,9 @@ void QQuickStochasticEngine::start(int index, int state) else m_startTimes[index] = 0; m_goals[index] = -1; + m_addAdvance = false; restart(index); + m_addAdvance = true; } void QQuickStochasticEngine::stop(int index) diff --git a/src/quick/items/qquickspriteengine_p.h b/src/quick/items/qquickspriteengine_p.h index 1705ab3ee3..227041f181 100644 --- a/src/quick/items/qquickspriteengine_p.h +++ b/src/quick/items/qquickspriteengine_p.h @@ -268,8 +268,8 @@ public: int spriteCount();//Like state count int maxFrames(); - virtual void restart(int index=0); - virtual void advance(int index=0); + void restart(int index=0) Q_DECL_OVERRIDE; + void advance(int index=0) Q_DECL_OVERRIDE; //Similar API to QQuickPixmap for async loading convenience bool isNull() { return status() == QQuickPixmap::Null; } diff --git a/src/quick/items/qquickspritesequence.cpp b/src/quick/items/qquickspritesequence.cpp index a9a823c2ce..0bef823b3c 100644 --- a/src/quick/items/qquickspritesequence.cpp +++ b/src/quick/items/qquickspritesequence.cpp @@ -53,9 +53,9 @@ class QQuickSpriteSequenceMaterial : public QSGMaterial public: QQuickSpriteSequenceMaterial(); ~QQuickSpriteSequenceMaterial(); - virtual QSGMaterialType *type() const { static QSGMaterialType type; return &type; } - virtual QSGMaterialShader *createShader() const; - virtual int compare(const QSGMaterial *other) const + QSGMaterialType *type() const Q_DECL_OVERRIDE{ static QSGMaterialType type; return &type; } + QSGMaterialShader *createShader() const Q_DECL_OVERRIDE; + int compare(const QSGMaterial *other) const Q_DECL_OVERRIDE { return this - static_cast<const QQuickSpriteSequenceMaterial *>(other); } @@ -99,7 +99,7 @@ public: setShaderSourceFile(QOpenGLShader::Fragment, QStringLiteral(":/items/shaders/sprite.frag")); } - virtual void updateState(const RenderState &state, QSGMaterial *newEffect, QSGMaterial *) + void updateState(const RenderState &state, QSGMaterial *newEffect, QSGMaterial *) Q_DECL_OVERRIDE { QQuickSpriteSequenceMaterial *m = static_cast<QQuickSpriteSequenceMaterial *>(newEffect); m->texture->bind(); @@ -112,14 +112,14 @@ public: program()->setUniformValue(m_matrix_id, state.combinedMatrix()); } - virtual void initialize() { + void initialize() Q_DECL_OVERRIDE { m_matrix_id = program()->uniformLocation("qt_Matrix"); m_opacity_id = program()->uniformLocation("qt_Opacity"); m_animData_id = program()->uniformLocation("animData"); m_animPos_id = program()->uniformLocation("animPos"); } - virtual char const *const *attributeNames() const { + char const *const *attributeNames() const Q_DECL_OVERRIDE { static const char *attr[] = { "vPos", "vTex", diff --git a/src/quick/items/qquickspritesequence_p.h b/src/quick/items/qquickspritesequence_p.h index a32f5ead4f..3c22d8772c 100644 --- a/src/quick/items/qquickspritesequence_p.h +++ b/src/quick/items/qquickspritesequence_p.h @@ -114,7 +114,7 @@ private Q_SLOTS: protected: void reset(); - QSGNode *updatePaintNode(QSGNode *, UpdatePaintNodeData *); + QSGNode *updatePaintNode(QSGNode *, UpdatePaintNodeData *) Q_DECL_OVERRIDE; private: void prepareNextFrame(); QSGGeometryNode* buildNode(); diff --git a/src/quick/items/qquickstateoperations_p.h b/src/quick/items/qquickstateoperations_p.h index 79facf2445..a9e4be1e20 100644 --- a/src/quick/items/qquickstateoperations_p.h +++ b/src/quick/items/qquickstateoperations_p.h @@ -93,17 +93,17 @@ public: void setRotation(QQmlScriptString rotation); bool rotationIsSet() const; - virtual ActionList actions(); + ActionList actions() Q_DECL_OVERRIDE; - virtual void saveOriginals(); + void saveOriginals() Q_DECL_OVERRIDE; //virtual void copyOriginals(QQuickStateActionEvent*); - virtual void execute(Reason reason = ActualChange); - virtual bool isReversable(); - virtual void reverse(Reason reason = ActualChange); - virtual EventType type() const; - virtual bool override(QQuickStateActionEvent*other); - virtual void rewind(); - virtual void saveCurrentValues(); + void execute(Reason reason = ActualChange) Q_DECL_OVERRIDE; + bool isReversable() Q_DECL_OVERRIDE; + void reverse(Reason reason = ActualChange) Q_DECL_OVERRIDE; + EventType type() const Q_DECL_OVERRIDE; + bool override(QQuickStateActionEvent*other) Q_DECL_OVERRIDE; + void rewind() Q_DECL_OVERRIDE; + void saveCurrentValues() Q_DECL_OVERRIDE; }; class QQuickAnchorChanges; @@ -173,28 +173,28 @@ public: QQuickAnchorChanges(QObject *parent=0); ~QQuickAnchorChanges(); - virtual ActionList actions(); + ActionList actions() Q_DECL_OVERRIDE; QQuickAnchorSet *anchors(); QQuickItem *object() const; void setObject(QQuickItem *); - virtual void execute(Reason reason = ActualChange); - virtual bool isReversable(); - virtual void reverse(Reason reason = ActualChange); - virtual EventType type() const; - virtual bool override(QQuickStateActionEvent*other); - virtual bool changesBindings(); - virtual void saveOriginals(); - virtual bool needsCopy() { return true; } - virtual void copyOriginals(QQuickStateActionEvent*); - virtual void clearBindings(); - virtual void rewind(); - virtual void saveCurrentValues(); + void execute(Reason reason = ActualChange) Q_DECL_OVERRIDE; + bool isReversable() Q_DECL_OVERRIDE; + void reverse(Reason reason = ActualChange) Q_DECL_OVERRIDE; + EventType type() const Q_DECL_OVERRIDE; + bool override(QQuickStateActionEvent*other) Q_DECL_OVERRIDE; + bool changesBindings() Q_DECL_OVERRIDE; + void saveOriginals() Q_DECL_OVERRIDE; + bool needsCopy() Q_DECL_OVERRIDE { return true; } + void copyOriginals(QQuickStateActionEvent*) Q_DECL_OVERRIDE; + void clearBindings() Q_DECL_OVERRIDE; + void rewind() Q_DECL_OVERRIDE; + void saveCurrentValues() Q_DECL_OVERRIDE; QList<QQuickStateAction> additionalActions(); - virtual void saveTargetValues(); + void saveTargetValues() Q_DECL_OVERRIDE; }; QT_END_NAMESPACE diff --git a/src/quick/items/qquicktext_p.h b/src/quick/items/qquicktext_p.h index c9f64d3fab..bc1a5198e8 100644 --- a/src/quick/items/qquicktext_p.h +++ b/src/quick/items/qquicktext_p.h @@ -186,15 +186,15 @@ public: FontSizeMode fontSizeMode() const; void setFontSizeMode(FontSizeMode mode); - virtual void componentComplete(); + void componentComplete() Q_DECL_OVERRIDE; int resourcesLoading() const; // mainly for testing qreal contentWidth() const; qreal contentHeight() const; - QRectF boundingRect() const; - QRectF clipRect() const; + QRectF boundingRect() const Q_DECL_OVERRIDE; + QRectF clipRect() const Q_DECL_OVERRIDE; Q_INVOKABLE void doLayout(); RenderType renderType() const; @@ -233,18 +233,18 @@ Q_SIGNALS: void renderTypeChanged(); protected: - void mousePressEvent(QMouseEvent *event); - void mouseReleaseEvent(QMouseEvent *event); - virtual void itemChange(ItemChange change, const ItemChangeData &value); - virtual void geometryChanged(const QRectF &newGeometry, - const QRectF &oldGeometry); - virtual QSGNode *updatePaintNode(QSGNode *, UpdatePaintNodeData *); - - void updatePolish(); - - void hoverEnterEvent(QHoverEvent *event); - void hoverMoveEvent(QHoverEvent *event); - void hoverLeaveEvent(QHoverEvent *event); + void mousePressEvent(QMouseEvent *event) Q_DECL_OVERRIDE; + void mouseReleaseEvent(QMouseEvent *event) Q_DECL_OVERRIDE; + void itemChange(ItemChange change, const ItemChangeData &value) Q_DECL_OVERRIDE; + void geometryChanged(const QRectF &newGeometry, + const QRectF &oldGeometry) Q_DECL_OVERRIDE; + QSGNode *updatePaintNode(QSGNode *, UpdatePaintNodeData *) Q_DECL_OVERRIDE; + + void updatePolish() Q_DECL_OVERRIDE; + + void hoverEnterEvent(QHoverEvent *event) Q_DECL_OVERRIDE; + void hoverMoveEvent(QHoverEvent *event) Q_DECL_OVERRIDE; + void hoverLeaveEvent(QHoverEvent *event) Q_DECL_OVERRIDE; private Q_SLOTS: void q_imagesLoaded(); diff --git a/src/quick/items/qquicktext_p_p.h b/src/quick/items/qquicktext_p_p.h index 022c2ac9d5..04a78f9c21 100644 --- a/src/quick/items/qquicktext_p_p.h +++ b/src/quick/items/qquicktext_p_p.h @@ -72,7 +72,7 @@ public: void updateLayout(); bool determineHorizontalAlignment(); bool setHAlign(QQuickText::HAlignment, bool forceAlign = false); - void mirrorChange(); + void mirrorChange() Q_DECL_OVERRIDE; bool isLineLaidOutConnected(); void setLineGeometry(QTextLine &line, qreal lineWidth, qreal &height); @@ -154,8 +154,8 @@ public: static const QChar elideChar; - virtual qreal getImplicitWidth() const; - virtual qreal getImplicitHeight() const; + qreal getImplicitWidth() const Q_DECL_OVERRIDE; + qreal getImplicitHeight() const Q_DECL_OVERRIDE; void ensureDoc(); diff --git a/src/quick/items/qquicktextcontrol_p.h b/src/quick/items/qquicktextcontrol_p.h index d0af4a1cc9..2fe083f1d2 100644 --- a/src/quick/items/qquicktextcontrol_p.h +++ b/src/quick/items/qquicktextcontrol_p.h @@ -162,9 +162,9 @@ public: bool cursorOn() const; protected: - virtual void timerEvent(QTimerEvent *e); + void timerEvent(QTimerEvent *e) Q_DECL_OVERRIDE; - virtual bool event(QEvent *e); + bool event(QEvent *e) Q_DECL_OVERRIDE; private: Q_DISABLE_COPY(QQuickTextControl) diff --git a/src/quick/items/qquicktextedit.cpp b/src/quick/items/qquicktextedit.cpp index aca7150ca2..1ad37ed7dd 100644 --- a/src/quick/items/qquicktextedit.cpp +++ b/src/quick/items/qquicktextedit.cpp @@ -1232,15 +1232,21 @@ void QQuickTextEdit::setTextMargin(qreal margin) \endlist */ -#ifndef QT_NO_IM Qt::InputMethodHints QQuickTextEdit::inputMethodHints() const { +#ifdef QT_NO_IM + return Qt::ImhNone; +#else Q_D(const QQuickTextEdit); return d->inputMethodHints; +#endif // QT_NO_IM } void QQuickTextEdit::setInputMethodHints(Qt::InputMethodHints hints) { +#ifdef QT_NO_IM + Q_UNUSED(hints); +#else Q_D(QQuickTextEdit); if (hints == d->inputMethodHints) @@ -1249,8 +1255,8 @@ void QQuickTextEdit::setInputMethodHints(Qt::InputMethodHints hints) d->inputMethodHints = hints; updateInputMethod(Qt::ImHints); emit inputMethodHintsChanged(); -} #endif // QT_NO_IM +} void QQuickTextEdit::geometryChanged(const QRectF &newGeometry, const QRectF &oldGeometry) @@ -1956,7 +1962,6 @@ bool QQuickTextEdit::canRedo() const return d->document->isRedoAvailable(); } -#ifndef QT_NO_IM /*! \qmlproperty bool QtQuick::TextEdit::inputMethodComposing @@ -1971,10 +1976,13 @@ bool QQuickTextEdit::canRedo() const */ bool QQuickTextEdit::isInputMethodComposing() const { +#ifdef QT_NO_IM + return false; +#else Q_D(const QQuickTextEdit); return d->control->hasImState(); -} #endif // QT_NO_IM +} void QQuickTextEditPrivate::init() { diff --git a/src/quick/items/qquicktextedit_p.h b/src/quick/items/qquicktextedit_p.h index 54e6dd229a..ea47c3b60e 100644 --- a/src/quick/items/qquicktextedit_p.h +++ b/src/quick/items/qquicktextedit_p.h @@ -81,18 +81,14 @@ class Q_QUICK_PRIVATE_EXPORT QQuickTextEdit : public QQuickImplicitSizeItem Q_PROPERTY(bool activeFocusOnPress READ focusOnPress WRITE setFocusOnPress NOTIFY activeFocusOnPressChanged) Q_PROPERTY(bool persistentSelection READ persistentSelection WRITE setPersistentSelection NOTIFY persistentSelectionChanged) Q_PROPERTY(qreal textMargin READ textMargin WRITE setTextMargin NOTIFY textMarginChanged) -#ifndef QT_NO_IM Q_PROPERTY(Qt::InputMethodHints inputMethodHints READ inputMethodHints WRITE setInputMethodHints NOTIFY inputMethodHintsChanged) -#endif Q_PROPERTY(bool selectByKeyboard READ selectByKeyboard WRITE setSelectByKeyboard NOTIFY selectByKeyboardChanged REVISION 1) Q_PROPERTY(bool selectByMouse READ selectByMouse WRITE setSelectByMouse NOTIFY selectByMouseChanged) Q_PROPERTY(SelectionMode mouseSelectionMode READ mouseSelectionMode WRITE setMouseSelectionMode NOTIFY mouseSelectionModeChanged) Q_PROPERTY(bool canPaste READ canPaste NOTIFY canPasteChanged) Q_PROPERTY(bool canUndo READ canUndo NOTIFY canUndoChanged) Q_PROPERTY(bool canRedo READ canRedo NOTIFY canRedoChanged) -#ifndef QT_NO_IM Q_PROPERTY(bool inputMethodComposing READ isInputMethodComposing NOTIFY inputMethodComposingChanged) -#endif Q_PROPERTY(QUrl baseUrl READ baseUrl WRITE setBaseUrl RESET resetBaseUrl NOTIFY baseUrlChanged) Q_PROPERTY(RenderType renderType READ renderType WRITE setRenderType NOTIFY renderTypeChanged) Q_PROPERTY(QQuickTextDocument *textDocument READ textDocument FINAL REVISION 1) @@ -192,10 +188,8 @@ public: qreal textMargin() const; void setTextMargin(qreal margin); -#ifndef QT_NO_IM Qt::InputMethodHints inputMethodHints() const; void setInputMethodHints(Qt::InputMethodHints hints); -#endif bool selectByKeyboard() const; void setSelectByKeyboard(bool); @@ -211,7 +205,7 @@ public: bool canUndo() const; bool canRedo() const; - virtual void componentComplete(); + void componentComplete() Q_DECL_OVERRIDE; /* FROM EDIT */ void setReadOnly(bool); @@ -220,7 +214,7 @@ public: QRectF cursorRectangle() const; #ifndef QT_NO_IM - QVariant inputMethodQuery(Qt::InputMethodQuery property) const; + QVariant inputMethodQuery(Qt::InputMethodQuery property) const Q_DECL_OVERRIDE; Q_INVOKABLE QVariant inputMethodQuery(Qt::InputMethodQuery query, QVariant argument) const; #endif @@ -236,12 +230,10 @@ public: Q_INVOKABLE void moveCursorSelection(int pos); Q_INVOKABLE void moveCursorSelection(int pos, SelectionMode mode); - QRectF boundingRect() const; - QRectF clipRect() const; + QRectF boundingRect() const Q_DECL_OVERRIDE; + QRectF clipRect() const Q_DECL_OVERRIDE; -#ifndef QT_NO_IM bool isInputMethodComposing() const; -#endif RenderType renderType() const; void setRenderType(RenderType renderType); @@ -286,14 +278,10 @@ Q_SIGNALS: void canPasteChanged(); void canUndoChanged(); void canRedoChanged(); -#ifndef QT_NO_IM void inputMethodComposingChanged(); -#endif void effectiveHorizontalAlignmentChanged(); void baseUrlChanged(); -#ifndef QT_NO_IM void inputMethodHintsChanged(); -#endif void renderTypeChanged(); public Q_SLOTS: @@ -332,28 +320,28 @@ private: void updateTotalLines(); protected: - virtual void geometryChanged(const QRectF &newGeometry, - const QRectF &oldGeometry); + void geometryChanged(const QRectF &newGeometry, + const QRectF &oldGeometry) Q_DECL_OVERRIDE; - bool event(QEvent *); - void keyPressEvent(QKeyEvent *); - void keyReleaseEvent(QKeyEvent *); - void focusInEvent(QFocusEvent *event); - void focusOutEvent(QFocusEvent *event); + bool event(QEvent *) Q_DECL_OVERRIDE; + void keyPressEvent(QKeyEvent *) Q_DECL_OVERRIDE; + void keyReleaseEvent(QKeyEvent *) Q_DECL_OVERRIDE; + void focusInEvent(QFocusEvent *event) Q_DECL_OVERRIDE; + void focusOutEvent(QFocusEvent *event) Q_DECL_OVERRIDE; - void hoverEnterEvent(QHoverEvent *event); - void hoverMoveEvent(QHoverEvent *event); - void hoverLeaveEvent(QHoverEvent *event); + void hoverEnterEvent(QHoverEvent *event) Q_DECL_OVERRIDE; + void hoverMoveEvent(QHoverEvent *event) Q_DECL_OVERRIDE; + void hoverLeaveEvent(QHoverEvent *event) Q_DECL_OVERRIDE; // mouse filter? - void mousePressEvent(QMouseEvent *event); - void mouseReleaseEvent(QMouseEvent *event); - void mouseDoubleClickEvent(QMouseEvent *event); - void mouseMoveEvent(QMouseEvent *event); + void mousePressEvent(QMouseEvent *event) Q_DECL_OVERRIDE; + void mouseReleaseEvent(QMouseEvent *event) Q_DECL_OVERRIDE; + void mouseDoubleClickEvent(QMouseEvent *event) Q_DECL_OVERRIDE; + void mouseMoveEvent(QMouseEvent *event) Q_DECL_OVERRIDE; #ifndef QT_NO_IM - void inputMethodEvent(QInputMethodEvent *e); + void inputMethodEvent(QInputMethodEvent *e) Q_DECL_OVERRIDE; #endif - QSGNode *updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData *updatePaintNodeData); + QSGNode *updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData *updatePaintNodeData) Q_DECL_OVERRIDE; friend class QQuickTextUtil; friend class QQuickTextDocument; diff --git a/src/quick/items/qquicktextedit_p_p.h b/src/quick/items/qquicktextedit_p_p.h index ae00303dd1..5233413cd7 100644 --- a/src/quick/items/qquicktextedit_p_p.h +++ b/src/quick/items/qquicktextedit_p_p.h @@ -117,8 +117,8 @@ public: void relayoutDocument(); bool determineHorizontalAlignment(); bool setHAlign(QQuickTextEdit::HAlignment, bool forceAlign = false); - void mirrorChange(); - qreal getImplicitWidth() const; + void mirrorChange() Q_DECL_OVERRIDE; + qreal getImplicitWidth() const Q_DECL_OVERRIDE; Qt::LayoutDirection textDirection(const QString &text) const; bool isLinkHoveredConnected(); diff --git a/src/quick/items/qquicktextinput.cpp b/src/quick/items/qquicktextinput.cpp index 1f03fb21e2..d1bf022184 100644 --- a/src/quick/items/qquicktextinput.cpp +++ b/src/quick/items/qquicktextinput.cpp @@ -1021,6 +1021,8 @@ void QQuickDoubleValidator::resetLocaleName() } } +#endif // QT_NO_VALIDATOR + /*! \qmlproperty real QtQuick::DoubleValidator::top @@ -1099,12 +1101,19 @@ void QQuickDoubleValidator::resetLocaleName() QValidator* QQuickTextInput::validator() const { +#ifdef QT_NO_VALIDATOR + return 0; +#else Q_D(const QQuickTextInput); return d->m_validator; +#endif // QT_NO_VALIDATOR } void QQuickTextInput::setValidator(QValidator* v) { +#ifdef QT_NO_VALIDATOR + Q_UNUSED(v); +#else Q_D(QQuickTextInput); if (d->m_validator == v) return; @@ -1127,14 +1136,15 @@ void QQuickTextInput::setValidator(QValidator* v) d->checkIsValid(); emit validatorChanged(); +#endif // QT_NO_VALIDATOR } +#ifndef QT_NO_VALIDATOR void QQuickTextInput::q_validatorChanged() { Q_D(QQuickTextInput); d->checkIsValid(); } - #endif // QT_NO_VALIDATOR void QQuickTextInputPrivate::checkIsValid() @@ -1267,7 +1277,6 @@ void QQuickTextInput::setEchoMode(QQuickTextInput::EchoMode echo) emit echoModeChanged(echoMode()); } -#ifndef QT_NO_IM /*! \qmlproperty enumeration QtQuick::TextInput::inputMethodHints @@ -1316,12 +1325,19 @@ void QQuickTextInput::setEchoMode(QQuickTextInput::EchoMode echo) Qt::InputMethodHints QQuickTextInput::inputMethodHints() const { +#ifdef QT_NO_IM + return Qt::ImhNone; +#else Q_D(const QQuickTextInput); return d->inputMethodHints; +#endif // QT_NO_IM } void QQuickTextInput::setInputMethodHints(Qt::InputMethodHints hints) { +#ifdef QT_NO_IM + Q_UNUSED(hints); +#else Q_D(QQuickTextInput); if (hints == d->inputMethodHints) @@ -1330,8 +1346,8 @@ void QQuickTextInput::setInputMethodHints(Qt::InputMethodHints hints) d->inputMethodHints = hints; updateInputMethod(Qt::ImHints); emit inputMethodHintsChanged(); -} #endif // QT_NO_IM +} /*! \qmlproperty Component QtQuick::TextInput::cursorDelegate @@ -2590,7 +2606,6 @@ void QQuickTextInput::focusOutEvent(QFocusEvent *event) QQuickImplicitSizeItem::focusOutEvent(event); } -#ifndef QT_NO_IM /*! \qmlproperty bool QtQuick::TextInput::inputMethodComposing @@ -2605,10 +2620,13 @@ void QQuickTextInput::focusOutEvent(QFocusEvent *event) */ bool QQuickTextInput::isInputMethodComposing() const { +#ifdef QT_NO_IM + return false; +#else Q_D(const QQuickTextInput); return d->hasImState; -} #endif +} void QQuickTextInputPrivate::init() { diff --git a/src/quick/items/qquicktextinput_p.h b/src/quick/items/qquicktextinput_p.h index 4b94530587..0d32cb2179 100644 --- a/src/quick/items/qquicktextinput_p.h +++ b/src/quick/items/qquicktextinput_p.h @@ -74,13 +74,9 @@ class Q_QUICK_PRIVATE_EXPORT QQuickTextInput : public QQuickImplicitSizeItem Q_PROPERTY(QString selectedText READ selectedText NOTIFY selectedTextChanged) Q_PROPERTY(int maximumLength READ maxLength WRITE setMaxLength NOTIFY maximumLengthChanged) -#ifndef QT_NO_VALIDATOR Q_PROPERTY(QValidator* validator READ validator WRITE setValidator NOTIFY validatorChanged) -#endif Q_PROPERTY(QString inputMask READ inputMask WRITE setInputMask NOTIFY inputMaskChanged) -#ifndef QT_NO_IM Q_PROPERTY(Qt::InputMethodHints inputMethodHints READ inputMethodHints WRITE setInputMethodHints NOTIFY inputMethodHintsChanged) -#endif Q_PROPERTY(bool acceptableInput READ hasAcceptableInput NOTIFY acceptableInputChanged) Q_PROPERTY(EchoMode echoMode READ echoMode WRITE setEchoMode NOTIFY echoModeChanged) @@ -95,9 +91,7 @@ class Q_QUICK_PRIVATE_EXPORT QQuickTextInput : public QQuickImplicitSizeItem Q_PROPERTY(bool canPaste READ canPaste NOTIFY canPasteChanged) Q_PROPERTY(bool canUndo READ canUndo NOTIFY canUndoChanged) Q_PROPERTY(bool canRedo READ canRedo NOTIFY canRedoChanged) -#ifndef QT_NO_IM Q_PROPERTY(bool inputMethodComposing READ isInputMethodComposing NOTIFY inputMethodComposingChanged) -#endif Q_PROPERTY(qreal contentWidth READ contentWidth NOTIFY contentSizeChanged) Q_PROPERTY(qreal contentHeight READ contentHeight NOTIFY contentSizeChanged) Q_PROPERTY(RenderType renderType READ renderType WRITE setRenderType NOTIFY renderTypeChanged) @@ -106,7 +100,7 @@ public: QQuickTextInput(QQuickItem * parent=0); ~QQuickTextInput(); - void componentComplete(); + void componentComplete() Q_DECL_OVERRIDE; enum EchoMode {//To match QLineEdit::EchoMode Normal, @@ -205,10 +199,9 @@ public: int maxLength() const; void setMaxLength(int ml); -#ifndef QT_NO_VALIDATOR QValidator * validator() const; void setValidator(QValidator* v); -#endif + QString inputMask() const; void setInputMask(const QString &im); @@ -245,24 +238,22 @@ public: bool hasAcceptableInput() const; #ifndef QT_NO_IM - QVariant inputMethodQuery(Qt::InputMethodQuery property) const; + QVariant inputMethodQuery(Qt::InputMethodQuery property) const Q_DECL_OVERRIDE; Q_INVOKABLE QVariant inputMethodQuery(Qt::InputMethodQuery query, QVariant argument) const; #endif - QRectF boundingRect() const; - QRectF clipRect() const; + QRectF boundingRect() const Q_DECL_OVERRIDE; + QRectF clipRect() const Q_DECL_OVERRIDE; bool canPaste() const; bool canUndo() const; bool canRedo() const; -#ifndef QT_NO_IM bool isInputMethodComposing() const; Qt::InputMethodHints inputMethodHints() const; void setInputMethodHints(Qt::InputMethodHints hints); -#endif Q_INVOKABLE QString getText(int start, int end) const; @@ -304,34 +295,30 @@ Q_SIGNALS: void canPasteChanged(); void canUndoChanged(); void canRedoChanged(); -#ifndef QT_NO_IM void inputMethodComposingChanged(); -#endif void effectiveHorizontalAlignmentChanged(); void contentSizeChanged(); -#ifndef QT_NO_IM void inputMethodHintsChanged(); -#endif void renderTypeChanged(); protected: - virtual void geometryChanged(const QRectF &newGeometry, - const QRectF &oldGeometry); - - void mousePressEvent(QMouseEvent *event); - void mouseMoveEvent(QMouseEvent *event); - void mouseReleaseEvent(QMouseEvent *event); - void mouseDoubleClickEvent(QMouseEvent *event); - void keyPressEvent(QKeyEvent* ev); + void geometryChanged(const QRectF &newGeometry, + const QRectF &oldGeometry) Q_DECL_OVERRIDE; + + void mousePressEvent(QMouseEvent *event) Q_DECL_OVERRIDE; + void mouseMoveEvent(QMouseEvent *event) Q_DECL_OVERRIDE; + void mouseReleaseEvent(QMouseEvent *event) Q_DECL_OVERRIDE; + void mouseDoubleClickEvent(QMouseEvent *event) Q_DECL_OVERRIDE; + void keyPressEvent(QKeyEvent* ev) Q_DECL_OVERRIDE; #ifndef QT_NO_IM - void inputMethodEvent(QInputMethodEvent *); + void inputMethodEvent(QInputMethodEvent *) Q_DECL_OVERRIDE; #endif - void mouseUngrabEvent(); - bool event(QEvent *e); - void focusOutEvent(QFocusEvent *event); - void focusInEvent(QFocusEvent *event); - void timerEvent(QTimerEvent *event); - QSGNode *updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData *data); + void mouseUngrabEvent() Q_DECL_OVERRIDE; + bool event(QEvent *e) Q_DECL_OVERRIDE; + void focusOutEvent(QFocusEvent *event) Q_DECL_OVERRIDE; + void focusInEvent(QFocusEvent *event) Q_DECL_OVERRIDE; + void timerEvent(QTimerEvent *event) Q_DECL_OVERRIDE; + QSGNode *updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData *data) Q_DECL_OVERRIDE; public Q_SLOTS: void selectAll(); diff --git a/src/quick/items/qquicktextinput_p_p.h b/src/quick/items/qquicktextinput_p_p.h index 7d9f3ff9ce..9339bf9a30 100644 --- a/src/quick/items/qquicktextinput_p_p.h +++ b/src/quick/items/qquicktextinput_p_p.h @@ -145,7 +145,7 @@ public: void updateVerticalScroll(); bool determineHorizontalAlignment(); bool setHAlign(QQuickTextInput::HAlignment, bool forceAlign = false); - void mirrorChange(); + void mirrorChange() Q_DECL_OVERRIDE; bool sendMouseEventToInputContext(QMouseEvent *event); #ifndef QT_NO_IM Qt::InputMethodHints effectiveInputMethodHints() const; @@ -418,7 +418,7 @@ public: void updateLayout(); void updateBaselineOffset(); - qreal getImplicitWidth() const; + qreal getImplicitWidth() const Q_DECL_OVERRIDE; private: void removeSelectedText(); diff --git a/src/quick/items/qquicktextnodeengine.cpp b/src/quick/items/qquicktextnodeengine.cpp index 67ff79d20f..707b32755b 100644 --- a/src/quick/items/qquicktextnodeengine.cpp +++ b/src/quick/items/qquicktextnodeengine.cpp @@ -980,7 +980,18 @@ void QQuickTextNodeEngine::addTextBlock(QTextDocument *textDocument, const QText continue; QTextCharFormat charFormat = fragment.charFormat(); - setPosition(blockPosition); + QFont font(charFormat.font()); + QFontMetricsF fontMetrics(font); + + int fontHeight = fontMetrics.descent() + fontMetrics.ascent(); + int valign = charFormat.verticalAlignment(); + if (valign == QTextCharFormat::AlignSuperScript) + setPosition(QPointF(blockPosition.x(), blockPosition.y() - fontHeight / 2)); + else if (valign == QTextCharFormat::AlignSubScript) + setPosition(QPointF(blockPosition.x(), blockPosition.y() + fontHeight / 6)); + else + setPosition(blockPosition); + if (text.contains(QChar::ObjectReplacementCharacter)) { QTextFrame *frame = qobject_cast<QTextFrame *>(textDocument->objectForFormat(charFormat)); if (frame && frame->frameFormat().position() == QTextFrameFormat::InFlow) { diff --git a/src/quick/items/qquicktranslate_p.h b/src/quick/items/qquicktranslate_p.h index ca49349f74..f95e13ac35 100644 --- a/src/quick/items/qquicktranslate_p.h +++ b/src/quick/items/qquicktranslate_p.h @@ -58,7 +58,7 @@ public: qreal y() const; void setY(qreal); - void applyTo(QMatrix4x4 *matrix) const; + void applyTo(QMatrix4x4 *matrix) const Q_DECL_OVERRIDE; Q_SIGNALS: void xChanged(); @@ -94,7 +94,7 @@ public: qreal zScale() const; void setZScale(qreal); - void applyTo(QMatrix4x4 *matrix) const; + void applyTo(QMatrix4x4 *matrix) const Q_DECL_OVERRIDE; Q_SIGNALS: void originChanged(); @@ -129,7 +129,7 @@ public: void setAxis(const QVector3D &axis); void setAxis(Qt::Axis axis); - void applyTo(QMatrix4x4 *matrix) const; + void applyTo(QMatrix4x4 *matrix) const Q_DECL_OVERRIDE; Q_SIGNALS: void originChanged(); @@ -153,7 +153,7 @@ public: QMatrix4x4 matrix() const; void setMatrix(const QMatrix4x4& matrix); - void applyTo(QMatrix4x4 *matrix) const; + void applyTo(QMatrix4x4 *matrix) const Q_DECL_OVERRIDE; Q_SIGNALS: void matrixChanged(); diff --git a/src/quick/items/qquickview.cpp b/src/quick/items/qquickview.cpp index a55d056c75..ae33f9261c 100644 --- a/src/quick/items/qquickview.cpp +++ b/src/quick/items/qquickview.cpp @@ -50,15 +50,15 @@ QT_BEGIN_NAMESPACE DEFINE_OBJECT_VTABLE(QQuickRootItemMarker); -QQuickRootItemMarker *QQuickRootItemMarker::create(QQmlEngine *engine, QQuickWindow *window) +QV4::Returned<QQuickRootItemMarker> *QQuickRootItemMarker::create(QQmlEngine *engine, QQuickWindow *window) { QV4::ExecutionEngine *e = QQmlEnginePrivate::getV4Engine(engine); return e->memoryManager->alloc<QQuickRootItemMarker>(e, window); } -void QQuickRootItemMarker::markObjects(QV4::Managed *that, QV4::ExecutionEngine *e) +void QQuickRootItemMarker::markObjects(QV4::HeapObject *that, QV4::ExecutionEngine *e) { - QQuickItem *root = static_cast<QQuickRootItemMarker*>(that)->d()->window->contentItem(); + QQuickItem *root = static_cast<QQuickRootItemMarker::Data *>(that)->window->contentItem(); if (root) { QQuickItemPrivate *rootPrivate = QQuickItemPrivate::get(root); rootPrivate->markObjects(e); diff --git a/src/quick/items/qquickview.h b/src/quick/items/qquickview.h index d8017782aa..337d987243 100644 --- a/src/quick/items/qquickview.h +++ b/src/quick/items/qquickview.h @@ -90,14 +90,14 @@ private Q_SLOTS: void continueExecute(); protected: - virtual void resizeEvent(QResizeEvent *); - virtual void timerEvent(QTimerEvent*); - - virtual void keyPressEvent(QKeyEvent *); - virtual void keyReleaseEvent(QKeyEvent *); - virtual void mousePressEvent(QMouseEvent *); - virtual void mouseReleaseEvent(QMouseEvent *); - virtual void mouseMoveEvent(QMouseEvent *); + void resizeEvent(QResizeEvent *) Q_DECL_OVERRIDE; + void timerEvent(QTimerEvent*) Q_DECL_OVERRIDE; + + void keyPressEvent(QKeyEvent *) Q_DECL_OVERRIDE; + void keyReleaseEvent(QKeyEvent *) Q_DECL_OVERRIDE; + void mousePressEvent(QMouseEvent *) Q_DECL_OVERRIDE; + void mouseReleaseEvent(QMouseEvent *) Q_DECL_OVERRIDE; + void mouseMoveEvent(QMouseEvent *) Q_DECL_OVERRIDE; private: Q_DISABLE_COPY(QQuickView) Q_DECLARE_PRIVATE(QQuickView) diff --git a/src/quick/items/qquickview_p.h b/src/quick/items/qquickview_p.h index 2d3323a59c..7e39ed89b2 100644 --- a/src/quick/items/qquickview_p.h +++ b/src/quick/items/qquickview_p.h @@ -71,7 +71,7 @@ public: ~QQuickViewPrivate(); void execute(); - void itemGeometryChanged(QQuickItem *item, const QRectF &newGeometry, const QRectF &oldGeometry); + void itemGeometryChanged(QQuickItem *item, const QRectF &newGeometry, const QRectF &oldGeometry) Q_DECL_OVERRIDE; void initResize(); void updateSize(); void setRootObject(QObject *); @@ -108,9 +108,9 @@ struct QQuickRootItemMarker : public QV4::Object }; V4_OBJECT(QV4::Object) - static QQuickRootItemMarker *create(QQmlEngine *engine, QQuickWindow *window); + static QV4::Returned<QQuickRootItemMarker> *create(QQmlEngine *engine, QQuickWindow *window); - static void markObjects(Managed *that, QV4::ExecutionEngine *e); + static void markObjects(QV4::HeapObject *that, QV4::ExecutionEngine *e); }; diff --git a/src/quick/items/qquickwindow.cpp b/src/quick/items/qquickwindow.cpp index f6c1412aff..13462317a3 100644 --- a/src/quick/items/qquickwindow.cpp +++ b/src/quick/items/qquickwindow.cpp @@ -143,7 +143,7 @@ public slots: void animationStopped() { incubate(); } protected: - virtual void incubatingObjectCountChanged(int count) + void incubatingObjectCountChanged(int count) Q_DECL_OVERRIDE { if (count && !m_renderLoop->interleaveIncubation()) incubateAgain(); @@ -364,19 +364,21 @@ void QQuickWindowPrivate::renderSceneGraph(const QSize &size) animationController->advance(); emit q->beforeRendering(); runAndClearJobs(&beforeRenderingJobs); - int fboId = 0; - const qreal devicePixelRatio = q->effectiveDevicePixelRatio(); - renderer->setDeviceRect(QRect(QPoint(0, 0), size * devicePixelRatio)); - if (renderTargetId) { - fboId = renderTargetId; - renderer->setViewportRect(QRect(QPoint(0, 0), renderTargetSize)); - } else { - renderer->setViewportRect(QRect(QPoint(0, 0), size * devicePixelRatio)); - } - renderer->setProjectionMatrixToRect(QRect(QPoint(0, 0), size)); - renderer->setDevicePixelRatio(devicePixelRatio); + if (!customRenderStage || !customRenderStage->render()) { + int fboId = 0; + const qreal devicePixelRatio = q->effectiveDevicePixelRatio(); + renderer->setDeviceRect(QRect(QPoint(0, 0), size * devicePixelRatio)); + if (renderTargetId) { + fboId = renderTargetId; + renderer->setViewportRect(QRect(QPoint(0, 0), renderTargetSize)); + } else { + renderer->setViewportRect(QRect(QPoint(0, 0), size * devicePixelRatio)); + } + renderer->setProjectionMatrixToRect(QRect(QPoint(0, 0), size)); + renderer->setDevicePixelRatio(devicePixelRatio); - context->renderNextFrame(renderer, fboId); + context->renderNextFrame(renderer, fboId); + } emit q->afterRendering(); runAndClearJobs(&afterRenderingJobs); } @@ -399,6 +401,7 @@ QQuickWindowPrivate::QQuickWindowPrivate() , windowManager(0) , renderControl(0) , touchRecursionGuard(0) + , customRenderStage(0) , clearColor(Qt::white) , clearBeforeRendering(true) , persistentGLContext(true) @@ -418,6 +421,7 @@ QQuickWindowPrivate::QQuickWindowPrivate() QQuickWindowPrivate::~QQuickWindowPrivate() { + delete customRenderStage; } void QQuickWindowPrivate::init(QQuickWindow *c, QQuickRenderControl *control) @@ -1375,6 +1379,11 @@ bool QQuickWindow::event(QEvent *e) if (d->mouseGrabberItem) d->mouseGrabberItem->ungrabMouse(); break; + case QEvent::UpdateRequest: { + if (d->windowManager) + d->windowManager->handleUpdateRequest(this); + break; + } default: break; } @@ -2011,11 +2020,14 @@ bool QQuickWindowPrivate::deliverMatchingPointsToItem(QQuickItem *item, QTouchEv touchEvent.data()->setTarget(item); bool touchEventAccepted = false; + qCDebug(DBG_TOUCH) << " - considering delivering " << touchEvent << " to " << item; + // First check whether the parent wants to be a filter, // and if the parent accepts the event we are done. if (sendFilteredTouchEvent(item->parentItem(), item, event, hasFiltered)) { // If the touch was accepted (regardless by whom or in what form), // update acceptedNewPoints + qCDebug(DBG_TOUCH) << " - can't. intercepted " << touchEvent.data() << " to " << item->parentItem() << " instead of " << item; foreach (int id, matchingNewPoints) acceptedNewPoints->insert(id); return true; @@ -2026,6 +2038,7 @@ bool QQuickWindowPrivate::deliverMatchingPointsToItem(QQuickItem *item, QTouchEv itemForTouchPointId[id] = item; // Deliver the touch event to the given item + qCDebug(DBG_TOUCH) << " - actually delivering " << touchEvent << " to " << item; QCoreApplication::sendEvent(item, touchEvent.data()); touchEventAccepted = touchEvent->isAccepted(); @@ -2262,10 +2275,7 @@ QQuickItem *QQuickWindowPrivate::findCursorItem(QQuickItem *item, const QPointF return 0; } - const int numCursorsInHierarchy = itemPrivate->extra.isAllocated() ? itemPrivate->extra.value().numItemsWithCursor : 0; - const int numChildrenWithCursor = itemPrivate->hasCursor ? numCursorsInHierarchy-1 : numCursorsInHierarchy; - - if (numChildrenWithCursor > 0) { + if (itemPrivate->hasCursorInChild) { QList<QQuickItem *> children = itemPrivate->paintOrderChildItems(); for (int ii = children.count() - 1; ii >= 0; --ii) { QQuickItem *child = children.at(ii); @@ -2298,6 +2308,7 @@ bool QQuickWindowPrivate::sendFilteredTouchEvent(QQuickItem *target, QQuickItem QScopedPointer<QTouchEvent> targetEvent(touchEventForItemBounds(target, *event)); if (!targetEvent->touchPoints().isEmpty()) { if (target->childMouseEventFilter(item, targetEvent.data())) { + qCDebug(DBG_TOUCH) << " - first chance intercepted on childMouseEventFilter by " << target; QVector<int> touchIds; for (int i = 0; i < targetEvent->touchPoints().size(); ++i) touchIds.append(targetEvent->touchPoints().at(i).id()); @@ -2338,6 +2349,7 @@ bool QQuickWindowPrivate::sendFilteredTouchEvent(QQuickItem *target, QQuickItem // targetEvent is already transformed wrt local position, velocity, etc. QScopedPointer<QMouseEvent> mouseEvent(touchToMouseEvent(t, tp, event, item, false)); if (target->childMouseEventFilter(item, mouseEvent.data())) { + qCDebug(DBG_TOUCH) << " - second chance intercepted on childMouseEventFilter by " << target; if (t != QEvent::MouseButtonRelease) { itemForTouchPointId[tp.id()] = target; touchMouseId = tp.id(); @@ -2550,7 +2562,9 @@ bool QQuickWindow::sendEvent(QQuickItem *item, QEvent *e) case QEvent::TouchUpdate: case QEvent::TouchEnd: { QSet<QQuickItem*> hasFiltered; - d->sendFilteredTouchEvent(item->parentItem(), item, static_cast<QTouchEvent *>(e), &hasFiltered); + QTouchEvent *ev = static_cast<QTouchEvent *>(e); + qCDebug(DBG_TOUCH) << " - sendEvent for " << ev << " to " << item->parentItem() << " and " << item; + d->sendFilteredTouchEvent(item->parentItem(), item, ev, &hasFiltered); } break; default: @@ -2580,7 +2594,6 @@ void QQuickWindowPrivate::cleanupNodesOnShutdown(QQuickItem *item) p->extra->rootNode = 0; } - p->groupNode = 0; p->paintNode = 0; p->dirty(QQuickItemPrivate::Window); @@ -2635,6 +2648,53 @@ void QQuickWindowPrivate::updateDirtyNodes() } } +static inline QSGNode *qquickitem_before_paintNode(QQuickItemPrivate *d) +{ + const QList<QQuickItem *> childItems = d->paintOrderChildItems(); + QQuickItem *before = 0; + for (int i=0; i<childItems.size(); ++i) { + QQuickItemPrivate *dd = QQuickItemPrivate::get(childItems.at(i)); + // Perform the same check as the in buildOrderNodeList below. + if (dd->z() < 0 && (dd->explicitVisible || (dd->extra.isAllocated() && dd->extra->effectRefCount))) + before = childItems.at(i); + else + break; + } + return Q_UNLIKELY(before) ? QQuickItemPrivate::get(before)->itemNode() : 0; +} + +static QVector<QSGNode *> buildOrderedNodeList(QQuickItemPrivate *itemPriv) +{ + QList<QQuickItem *> orderedChildren = itemPriv->paintOrderChildItems(); + QVector<QSGNode *> desiredNodes; + desiredNodes.reserve(orderedChildren.size() + 1); // + 1 for the paintNode + + int ii = 0; + + for (; ii < orderedChildren.count() && orderedChildren.at(ii)->z() < 0; ++ii) { + QQuickItemPrivate *childPrivate = QQuickItemPrivate::get(orderedChildren.at(ii)); + if (!childPrivate->explicitVisible && + (!childPrivate->extra.isAllocated() || !childPrivate->extra->effectRefCount)) + continue; + + desiredNodes.append(childPrivate->itemNode()); + } + + if (itemPriv->paintNode) + desiredNodes.append(itemPriv->paintNode); + + for (; ii < orderedChildren.count(); ++ii) { + QQuickItemPrivate *childPrivate = QQuickItemPrivate::get(orderedChildren.at(ii)); + if (!childPrivate->explicitVisible && + (!childPrivate->extra.isAllocated() || !childPrivate->extra->effectRefCount)) + continue; + + desiredNodes.append(childPrivate->itemNode()); + } + + return desiredNodes; +} + void QQuickWindowPrivate::updateDirtyNode(QQuickItem *item) { QQuickItemPrivate *itemPriv = QQuickItemPrivate::get(item); @@ -2674,101 +2734,139 @@ void QQuickWindowPrivate::updateDirtyNode(QQuickItem *item) if (clipEffectivelyChanged) { QSGNode *parent = itemPriv->opacityNode() ? (QSGNode *) itemPriv->opacityNode() : - (QSGNode *)itemPriv->itemNode(); - QSGNode *child = itemPriv->rootNode() ? (QSGNode *)itemPriv->rootNode() : - (QSGNode *)itemPriv->groupNode; + (QSGNode *) itemPriv->itemNode(); + QSGNode *child = itemPriv->rootNode(); if (item->clip()) { Q_ASSERT(itemPriv->clipNode() == 0); - itemPriv->extra.value().clipNode = new QQuickDefaultClipNode(item->clipRect()); - itemPriv->clipNode()->update(); + QQuickDefaultClipNode *clip = new QQuickDefaultClipNode(item->clipRect()); + itemPriv->extra.value().clipNode = clip; + clip->update(); - if (child) + if (!child) { + parent->reparentChildNodesTo(clip); + parent->appendChildNode(clip); + } else { parent->removeChildNode(child); - parent->appendChildNode(itemPriv->clipNode()); - if (child) - itemPriv->clipNode()->appendChildNode(child); + clip->appendChildNode(child); + parent->appendChildNode(clip); + } } else { - Q_ASSERT(itemPriv->clipNode() != 0); - parent->removeChildNode(itemPriv->clipNode()); - if (child) - itemPriv->clipNode()->removeChildNode(child); + QQuickDefaultClipNode *clip = itemPriv->clipNode(); + Q_ASSERT(clip); + parent->removeChildNode(clip); + if (child) { + clip->removeChildNode(child); + parent->appendChildNode(child); + } else { + clip->reparentChildNodesTo(parent); + } + delete itemPriv->clipNode(); itemPriv->extra->clipNode = 0; - if (child) - parent->appendChildNode(child); } } - if (dirty & QQuickItemPrivate::ChildrenUpdateMask) - itemPriv->childContainerNode()->removeAllChildNodes(); - if (effectRefEffectivelyChanged) { + if (dirty & QQuickItemPrivate::ChildrenUpdateMask) + itemPriv->childContainerNode()->removeAllChildNodes(); + QSGNode *parent = itemPriv->clipNode(); if (!parent) parent = itemPriv->opacityNode(); if (!parent) parent = itemPriv->itemNode(); - QSGNode *child = itemPriv->groupNode; if (itemPriv->extra.isAllocated() && itemPriv->extra->effectRefCount) { Q_ASSERT(itemPriv->rootNode() == 0); - itemPriv->extra->rootNode = new QSGRootNode; - - if (child) - parent->removeChildNode(child); - parent->appendChildNode(itemPriv->rootNode()); - if (child) - itemPriv->rootNode()->appendChildNode(child); + QSGRootNode *root = new QSGRootNode(); + itemPriv->extra->rootNode = root; + parent->reparentChildNodesTo(root); + parent->appendChildNode(root); } else { Q_ASSERT(itemPriv->rootNode() != 0); - parent->removeChildNode(itemPriv->rootNode()); - if (child) - itemPriv->rootNode()->removeChildNode(child); + QSGRootNode *root = itemPriv->rootNode(); + parent->removeChildNode(root); + root->reparentChildNodesTo(parent); delete itemPriv->rootNode(); itemPriv->extra->rootNode = 0; - if (child) - parent->appendChildNode(child); } } if (dirty & QQuickItemPrivate::ChildrenUpdateMask) { - QSGNode *groupNode = itemPriv->groupNode; - if (groupNode) - groupNode->removeAllChildNodes(); - - QList<QQuickItem *> orderedChildren = itemPriv->paintOrderChildItems(); - int ii = 0; + QVector<QSGNode *> desiredNodes = buildOrderedNodeList(itemPriv); + + // now start making current state match the promised land of + // desiredNodes. in the case of our current state matching desiredNodes + // (though why would we get ChildrenUpdateMask with no changes?) then we + // should make no changes at all. + + // how many nodes did we process, when examining changes + int desiredNodesProcessed = 0; + + // currentNode is how far, in our present tree, we have processed. we + // make use of this later on to trim the current child list if the + // desired list is shorter. + QSGNode *groupNode = itemPriv->childContainerNode(); + QSGNode *currentNode = groupNode->firstChild(); + int added = 0; + int removed = 0; + int replaced = 0; +#if defined(CHILDRENUPDATE_DEBUG) + // This is slow! Do not do this in a normal/profiling build! + int initialCount = groupNode->childCount(); +#endif - for (; ii < orderedChildren.count() && orderedChildren.at(ii)->z() < 0; ++ii) { - QQuickItemPrivate *childPrivate = QQuickItemPrivate::get(orderedChildren.at(ii)); - if (!childPrivate->explicitVisible && - (!childPrivate->extra.isAllocated() || !childPrivate->extra->effectRefCount)) - continue; - if (childPrivate->itemNode()->parent()) - childPrivate->itemNode()->parent()->removeChildNode(childPrivate->itemNode()); + while (currentNode && desiredNodesProcessed < desiredNodes.size()) { + QSGNode *desiredNode = desiredNodes.at(desiredNodesProcessed); + + // uh oh... reality and our utopic paradise are diverging! + // we need to reconcile this... + if (currentNode != desiredNode) { + // for now, we're just removing the node from the children - + // and replacing it with the new node. + if (desiredNode->parent()) + desiredNode->parent()->removeChildNode(desiredNode); + groupNode->insertChildNodeAfter(desiredNode, currentNode); + groupNode->removeChildNode(currentNode); + replaced++; + + // since we just replaced currentNode, we also need to reset + // the pointer. + currentNode = desiredNode; + } - itemPriv->childContainerNode()->appendChildNode(childPrivate->itemNode()); + currentNode = currentNode->nextSibling(); + desiredNodesProcessed++; } - QSGNode *beforePaintNode = itemPriv->groupNode ? itemPriv->groupNode->lastChild() : 0; - if (beforePaintNode || itemPriv->extra.isAllocated()) - itemPriv->extra.value().beforePaintNode = beforePaintNode; - - if (itemPriv->paintNode) - itemPriv->childContainerNode()->appendChildNode(itemPriv->paintNode); - - for (; ii < orderedChildren.count(); ++ii) { - QQuickItemPrivate *childPrivate = QQuickItemPrivate::get(orderedChildren.at(ii)); - if (!childPrivate->explicitVisible && - (!childPrivate->extra.isAllocated() || !childPrivate->extra->effectRefCount)) - continue; - if (childPrivate->itemNode()->parent()) - childPrivate->itemNode()->parent()->removeChildNode(childPrivate->itemNode()); - - itemPriv->childContainerNode()->appendChildNode(childPrivate->itemNode()); + // if we didn't process as many nodes as in the new list, then we have + // more nodes at the end of desiredNodes to append to our list. + // this will be the case when adding new nodes, for instance. + if (desiredNodesProcessed < desiredNodes.size()) { + for (int i = desiredNodesProcessed; i < desiredNodes.size(); ++i) { + QSGNode *desiredNode = desiredNodes.at(i); + if (desiredNode->parent()) + desiredNode->parent()->removeChildNode(desiredNode); + groupNode->appendChildNode(desiredNode); + added++; + } + } else if (currentNode) { + // on the other hand, if we processed less than our current node + // tree, then nodes have been _removed_ from the scene, and we need + // to take care of that here. + while (currentNode) { + QSGNode *node = currentNode->nextSibling(); + groupNode->removeChildNode(currentNode); + currentNode = node; + removed++; + } } + +#if defined(CHILDRENUPDATE_DEBUG) + qDebug() << "Done children update for " << itemPriv << "- before:" << initialCount << "after:" << groupNode->childCount() << "added:" << added << "removed:" << removed << "replaced:" << replaced; +#endif } if ((dirty & QQuickItemPrivate::Size) && itemPriv->clipNode()) { @@ -2783,20 +2881,22 @@ void QQuickWindowPrivate::updateDirtyNode(QQuickItem *item) ? itemPriv->opacity() : qreal(0); if (opacity != 1 && !itemPriv->opacityNode()) { - itemPriv->extra.value().opacityNode = new QSGOpacityNode; + QSGOpacityNode *node = new QSGOpacityNode; + itemPriv->extra.value().opacityNode = node; QSGNode *parent = itemPriv->itemNode(); QSGNode *child = itemPriv->clipNode(); if (!child) child = itemPriv->rootNode(); - if (!child) - child = itemPriv->groupNode; - if (child) + if (child) { parent->removeChildNode(child); - parent->appendChildNode(itemPriv->opacityNode()); - if (child) - itemPriv->opacityNode()->appendChildNode(child); + node->appendChildNode(child); + parent->appendChildNode(node); + } else { + parent->reparentChildNodesTo(node); + parent->appendChildNode(node); + } } if (itemPriv->opacityNode()) itemPriv->opacityNode()->setOpacity(opacity); @@ -2813,8 +2913,9 @@ void QQuickWindowPrivate::updateDirtyNode(QQuickItem *item) itemPriv->paintNode->parent() == itemPriv->childContainerNode()); if (itemPriv->paintNode && itemPriv->paintNode->parent() == 0) { - if (itemPriv->extra.isAllocated() && itemPriv->extra->beforePaintNode) - itemPriv->childContainerNode()->insertChildNodeAfter(itemPriv->paintNode, itemPriv->extra->beforePaintNode); + QSGNode *before = qquickitem_before_paintNode(itemPriv); + if (before) + itemPriv->childContainerNode()->insertChildNodeAfter(itemPriv->paintNode, before); else itemPriv->childContainerNode()->prependChildNode(itemPriv->paintNode); } @@ -2826,37 +2927,22 @@ void QQuickWindowPrivate::updateDirtyNode(QQuickItem *item) #ifndef QT_NO_DEBUG // Check consistency. - const QSGNode *nodeChain[] = { - itemPriv->itemNodeInstance, - itemPriv->opacityNode(), - itemPriv->clipNode(), - itemPriv->rootNode(), - itemPriv->groupNode, - itemPriv->paintNode, - }; - - int ip = 0; - for (;;) { - while (ip < 5 && nodeChain[ip] == 0) - ++ip; - if (ip == 5) - break; - int ic = ip + 1; - while (ic < 5 && nodeChain[ic] == 0) - ++ic; - const QSGNode *parent = nodeChain[ip]; - const QSGNode *child = nodeChain[ic]; - if (child == 0) { - Q_ASSERT(parent == itemPriv->groupNode || parent->childCount() == 0); - } else { - Q_ASSERT(parent == itemPriv->groupNode || parent->childCount() == 1); - Q_ASSERT(child->parent() == parent); - bool containsChild = false; - for (QSGNode *n = parent->firstChild(); n; n = n->nextSibling()) - containsChild |= (n == child); - Q_ASSERT(containsChild); - } - ip = ic; + + QList<QSGNode *> nodes; + nodes << itemPriv->itemNodeInstance + << itemPriv->opacityNode() + << itemPriv->clipNode() + << itemPriv->rootNode() + << itemPriv->paintNode; + nodes.removeAll(0); + + Q_ASSERT(nodes.first() == itemPriv->itemNodeInstance); + for (int i=1; i<nodes.size(); ++i) { + QSGNode *n = nodes.at(i); + // Failing this means we messed up reparenting + Q_ASSERT(n->parent() == nodes.at(i-1)); + // Only the paintNode and the one who is childContainer may have more than one child. + Q_ASSERT(n == itemPriv->paintNode || n == itemPriv->childContainerNode() || n->childCount() == 1); } #endif @@ -2925,6 +3011,15 @@ QOpenGLContext *QQuickWindow::openglContext() const } /*! + Returns true if the scene graph has been initialized; otherwise returns false. + */ +bool QQuickWindow::isSceneGraphInitialized() const +{ + Q_D(const QQuickWindow); + return d->context != 0 && d->context->isValid(); +} + +/*! \fn void QQuickWindow::frameSwapped() This signal is emitted when the frame buffers have been swapped. diff --git a/src/quick/items/qquickwindow.h b/src/quick/items/qquickwindow.h index 3cac691963..d02423d8af 100644 --- a/src/quick/items/qquickwindow.h +++ b/src/quick/items/qquickwindow.h @@ -115,7 +115,7 @@ public: QQmlIncubationController *incubationController() const; #ifndef QT_NO_ACCESSIBILITY - virtual QAccessibleInterface *accessibleRoot() const; + QAccessibleInterface *accessibleRoot() const Q_DECL_OVERRIDE; #endif // Scene graph specific functions @@ -139,6 +139,7 @@ public: bool isPersistentSceneGraph() const; QOpenGLContext *openglContext() const; + bool isSceneGraphInitialized() const; void scheduleRenderJob(QRunnable *job, RenderStage schedule); @@ -169,25 +170,25 @@ public Q_SLOTS: protected: QQuickWindow(QQuickWindowPrivate &dd, QWindow *parent = 0); - virtual void exposeEvent(QExposeEvent *); - virtual void resizeEvent(QResizeEvent *); + void exposeEvent(QExposeEvent *) Q_DECL_OVERRIDE; + void resizeEvent(QResizeEvent *) Q_DECL_OVERRIDE; - virtual void showEvent(QShowEvent *); - virtual void hideEvent(QHideEvent *); + void showEvent(QShowEvent *) Q_DECL_OVERRIDE; + void hideEvent(QHideEvent *) Q_DECL_OVERRIDE; // TODO Qt 6: reimplement QWindow::closeEvent to emit closing - virtual void focusInEvent(QFocusEvent *); - virtual void focusOutEvent(QFocusEvent *); + void focusInEvent(QFocusEvent *) Q_DECL_OVERRIDE; + void focusOutEvent(QFocusEvent *) Q_DECL_OVERRIDE; - virtual bool event(QEvent *); - virtual void keyPressEvent(QKeyEvent *); - virtual void keyReleaseEvent(QKeyEvent *); - virtual void mousePressEvent(QMouseEvent *); - virtual void mouseReleaseEvent(QMouseEvent *); - virtual void mouseDoubleClickEvent(QMouseEvent *); - virtual void mouseMoveEvent(QMouseEvent *); + bool event(QEvent *) Q_DECL_OVERRIDE; + void keyPressEvent(QKeyEvent *) Q_DECL_OVERRIDE; + void keyReleaseEvent(QKeyEvent *) Q_DECL_OVERRIDE; + void mousePressEvent(QMouseEvent *) Q_DECL_OVERRIDE; + void mouseReleaseEvent(QMouseEvent *) Q_DECL_OVERRIDE; + void mouseDoubleClickEvent(QMouseEvent *) Q_DECL_OVERRIDE; + void mouseMoveEvent(QMouseEvent *) Q_DECL_OVERRIDE; #ifndef QT_NO_WHEELEVENT - virtual void wheelEvent(QWheelEvent *); + void wheelEvent(QWheelEvent *) Q_DECL_OVERRIDE; #endif private Q_SLOTS: diff --git a/src/quick/items/qquickwindow_p.h b/src/quick/items/qquickwindow_p.h index 6cd41950cb..10be57059c 100644 --- a/src/quick/items/qquickwindow_p.h +++ b/src/quick/items/qquickwindow_p.h @@ -89,6 +89,14 @@ class QQuickWindowIncubationController; class QOpenGLVertexArrayObjectHelper; +class Q_QUICK_PRIVATE_EXPORT QQuickCustomRenderStage +{ +public: + virtual ~QQuickCustomRenderStage() {} + virtual bool render() = 0; + virtual bool swap() = 0; +}; + class Q_QUICK_PRIVATE_EXPORT QQuickWindowPrivate : public QWindowPrivate { public: @@ -209,6 +217,7 @@ public: QQuickAnimatorController *animationController; QTouchEvent *delayedTouch; int touchRecursionGuard; + QQuickCustomRenderStage *customRenderStage; QColor clearColor; diff --git a/src/quick/items/qquickwindowmodule.cpp b/src/quick/items/qquickwindowmodule.cpp index 371abd163b..bf41bc136f 100644 --- a/src/quick/items/qquickwindowmodule.cpp +++ b/src/quick/items/qquickwindowmodule.cpp @@ -89,7 +89,7 @@ Q_SIGNALS: void visibilityChanged(QWindow::Visibility visibility); protected: - void classBegin() { + void classBegin() Q_DECL_OVERRIDE { QQmlEngine* e = qmlEngine(this); //Give QQuickView behavior when created from QML with QQmlApplicationEngine if (QCoreApplication::instance()->property("__qml_using_qqmlapplicationengine") == QVariant(true)) { @@ -105,7 +105,7 @@ protected: } } - void componentComplete() { + void componentComplete() Q_DECL_OVERRIDE { m_complete = true; if (transientParent() && !transientParent()->isVisible()) { connect(transientParent(), &QQuickWindow::visibleChanged, this, diff --git a/src/quick/scenegraph/coreapi/qsgbatchrenderer.cpp b/src/quick/scenegraph/coreapi/qsgbatchrenderer.cpp index 2f94bad75d..9675d6e48a 100644 --- a/src/quick/scenegraph/coreapi/qsgbatchrenderer.cpp +++ b/src/quick/scenegraph/coreapi/qsgbatchrenderer.cpp @@ -128,8 +128,9 @@ ShaderManager::Shader *ShaderManager::prepareMaterial(QSGMaterial *material) if (shader) return shader; - if (QSG_LOG_TIME_COMPILATION().isDebugEnabled() || QQuickProfiler::profilingSceneGraph()) + if (QSG_LOG_TIME_COMPILATION().isDebugEnabled()) qsg_renderer_timer.start(); + Q_QUICK_SG_PROFILE_START(QQuickProfiler::SceneGraphContextFrame); QSGMaterialShader *s = material->createShader(); QOpenGLContext *ctx = QOpenGLContext::currentContext(); @@ -159,8 +160,7 @@ ShaderManager::Shader *ShaderManager::prepareMaterial(QSGMaterial *material) qCDebug(QSG_LOG_TIME_COMPILATION, "shader compiled in %dms", (int) qsg_renderer_timer.elapsed()); - Q_QUICK_SG_PROFILE(QQuickProfiler::SceneGraphContextFrame, ( - qsg_renderer_timer.nsecsElapsed())); + Q_QUICK_SG_PROFILE_END(QQuickProfiler::SceneGraphContextFrame); rewrittenShaders[type] = shader; return shader; @@ -173,8 +173,9 @@ ShaderManager::Shader *ShaderManager::prepareMaterialNoRewrite(QSGMaterial *mate if (shader) return shader; - if (QSG_LOG_TIME_COMPILATION().isDebugEnabled() || QQuickProfiler::profilingSceneGraph()) + if (QSG_LOG_TIME_COMPILATION().isDebugEnabled()) qsg_renderer_timer.start(); + Q_QUICK_SG_PROFILE_START(QQuickProfiler::SceneGraphContextFrame); QSGMaterialShader *s = static_cast<QSGMaterialShader *>(material->createShader()); context->compile(s, material); @@ -190,8 +191,7 @@ ShaderManager::Shader *ShaderManager::prepareMaterialNoRewrite(QSGMaterial *mate qCDebug(QSG_LOG_TIME_COMPILATION, "shader compiled in %dms (no rewrite)", (int) qsg_renderer_timer.elapsed()); - Q_QUICK_SG_PROFILE(QQuickProfiler::SceneGraphContextFrame, ( - qsg_renderer_timer.nsecsElapsed())); + Q_QUICK_SG_PROFILE_END(QQuickProfiler::SceneGraphContextFrame); return shader; } @@ -838,8 +838,8 @@ Renderer::~Renderer() for (int i=0; i<m_batchPool.size(); ++i) qsg_wipeBatch(m_batchPool.at(i), this); } - // The shadowtree - qDeleteAll(m_nodes.values()); + foreach (Node *n, m_nodes.values()) + m_nodeAllocator.release(n); // Remaining elements... for (int i=0; i<m_elementsToDelete.size(); ++i) { @@ -847,7 +847,7 @@ Renderer::~Renderer() if (e->isRenderNode) delete static_cast<RenderNodeElement *>(e); else - delete e; + m_elementAllocator.release(e); } } @@ -986,7 +986,8 @@ void Renderer::nodeWasAdded(QSGNode *node, Node *shadowParent) if (node->isSubtreeBlocked()) return; - Node *snode = new Node(node); + Node *snode = m_nodeAllocator.allocate(); + snode->sgNode = node; m_nodes.insert(node, snode); if (shadowParent) { snode->parent = shadowParent; @@ -994,7 +995,8 @@ void Renderer::nodeWasAdded(QSGNode *node, Node *shadowParent) } if (node->type() == QSGNode::GeometryNodeType) { - snode->data = new Element(static_cast<QSGGeometryNode *>(node)); + snode->data = m_elementAllocator.allocate(); + snode->element()->setNode(static_cast<QSGGeometryNode *>(node)); } else if (node->type() == QSGNode::ClipNodeType) { snode->data = new ClipBatchRootInfo; @@ -1057,7 +1059,7 @@ void Renderer::nodeWasRemoved(Node *node) } Q_ASSERT(m_nodes.contains(node->sgNode)); - delete m_nodes.take(node->sgNode); + m_nodeAllocator.release(m_nodes.take(node->sgNode)); } void Renderer::turnNodeIntoBatchRoot(Node *node) @@ -1240,8 +1242,8 @@ void Renderer::buildRenderLists(QSGNode *node) if (node->isSubtreeBlocked()) return; - Q_ASSERT(m_nodes.contains(node)); Node *shadowNode = m_nodes.value(node); + Q_ASSERT(shadowNode); if (node->type() == QSGNode::GeometryNodeType) { QSGGeometryNode *gn = static_cast<QSGGeometryNode *>(node); @@ -1262,7 +1264,7 @@ void Renderer::buildRenderLists(QSGNode *node) } else if (node->type() == QSGNode::ClipNodeType || shadowNode->isBatchRoot) { Q_ASSERT(m_nodes.contains(node)); - BatchRootInfo *info = batchRootInfo(m_nodes.value(node)); + BatchRootInfo *info = batchRootInfo(shadowNode); if (node == m_partialRebuildRoot) { m_nextRenderOrder = info->firstOrder; QSGNODE_TRAVERSE(node) @@ -2466,7 +2468,7 @@ void Renderer::deleteRemovedElements() if (e->isRenderNode) delete static_cast<RenderNodeElement *>(e); else - delete e; + m_elementAllocator.release(e); } m_elementsToDelete.reset(); } diff --git a/src/quick/scenegraph/coreapi/qsgbatchrenderer_p.h b/src/quick/scenegraph/coreapi/qsgbatchrenderer_p.h index 5447d9ea52..29604cf820 100644 --- a/src/quick/scenegraph/coreapi/qsgbatchrenderer_p.h +++ b/src/quick/scenegraph/coreapi/qsgbatchrenderer_p.h @@ -31,8 +31,8 @@ ** ****************************************************************************/ -#ifndef ULTRARENDERER_H -#define ULTRARENDERER_H +#ifndef QSGBATCHRENDERER_P_H +#define QSGBATCHRENDERER_P_H #include <private/qsgrenderer_p.h> #include <private/qsgnodeupdater_p.h> @@ -40,6 +40,8 @@ #include <private/qsgrendernode_p.h> +#include <QtCore/QBitArray> + QT_BEGIN_NAMESPACE class QOpenGLVertexArrayObject; @@ -59,6 +61,115 @@ class Updater; class Renderer; class ShaderManager; +template <typename Type, int PageSize> class AllocatorPage +{ +public: + // The memory used by this allocator + char data[sizeof(Type) * PageSize]; + + // 'blocks' contains a list of free indices which can be allocated. + // The first available index is found in PageSize - available. + int blocks[PageSize]; + + // 'available' is the number of available instances this page has left to allocate. + int available; + + // This is not strictly needed, but useful for sanity checking and anyway + // pretty small.. + QBitArray allocated; + + AllocatorPage() + : available(PageSize) + , allocated(PageSize) + { + for (int i=0; i<PageSize; ++i) blocks[i] = i; + } + + Type *at(uint index) const + { + return (Type *) &data[index * sizeof(Type)]; + } +}; + +template <typename Type, int PageSize> class Allocator +{ +public: + Allocator() + { + pages.push_back(new AllocatorPage<Type, PageSize>()); + } + + ~Allocator() + { + qDeleteAll(pages); + } + + Type *allocate() + { + AllocatorPage<Type, PageSize> *p = 0; + for (int i=0; i<pages.size(); ++i) { + if (pages.at(i)->available > 0) { + p = pages.at(i); + break; + } + } + if (!p) { + p = new AllocatorPage<Type, PageSize>(); + pages.push_back(p); + } + uint pos = p->blocks[PageSize - p->available]; + void *mem = p->at(pos); + p->available--; + p->allocated.setBit(pos); + Type *t = new (mem) Type(); + return t; + } + + void releaseExplicit(uint pageIndex, uint index) + { + AllocatorPage<Type, PageSize> *page = pages.at(pageIndex); + if (!page->allocated.testBit(index)) + qFatal("Double delete in allocator: page=%d, index=%d", pageIndex , index); + + // Call the destructor + page->at(index)->~Type(); + + page->allocated[index] = false; + page->available++; + page->blocks[PageSize - page->available] = index; + + // Remove the pages if they are empty and they are the last ones. We need to keep the + // order of pages since we have references to their index, so we can only remove + // from the end. + while (page->available == PageSize && pages.size() > 1 && pages.back() == page) { + pages.pop_back(); + delete page; + page = pages.back(); + } + } + + void release(Type *t) + { + int pageIndex = -1; + for (int i=0; i<pages.size(); ++i) { + AllocatorPage<Type, PageSize> *p = pages.at(i); + if ((Type *) (&p->data[0]) <= t && (Type *) (&p->data[PageSize * sizeof(Type)]) > t) { + pageIndex = i; + break; + } + } + Q_ASSERT(pageIndex >= 0); + + AllocatorPage<Type, PageSize> *page = pages.at(pageIndex); + int index = (quint64(t) - quint64(&page->data[0])) / sizeof(Type); + + releaseExplicit(pageIndex, index); + } + + QVector<AllocatorPage<Type, PageSize> *> pages; +}; + + inline bool hasMaterialWithBlending(QSGGeometryNode *n) { return (n->opaqueMaterial() ? n->opaqueMaterial()->flags() & QSGMaterial::Blending @@ -149,8 +260,8 @@ struct Buffer { struct Element { - Element(QSGGeometryNode *n) - : node(n) + Element() + : node(0) , batch(0) , nextInBatch(0) , root(0) @@ -161,10 +272,15 @@ struct Element { , removed(false) , orphaned(false) , isRenderNode(false) - , isMaterialBlended(n ? hasMaterialWithBlending(n) : false) + , isMaterialBlended(false) { } + void setNode(QSGGeometryNode *n) { + node = n; + isMaterialBlended = hasMaterialWithBlending(n); + } + inline void ensureBoundsValid() { if (!boundsComputed) computeBounds(); @@ -192,8 +308,7 @@ struct Element { struct RenderNodeElement : public Element { RenderNodeElement(QSGRenderNode *rn) - : Element(0) - , renderNode(rn) + : renderNode(rn) { isRenderNode = true; } @@ -289,15 +404,14 @@ struct Batch struct Node { - Node(QSGNode *node, Node *sparent = 0) - : sgNode(node) - , parent(sparent) + Node() + : sgNode(0) + , parent(0) , data(0) , dirtyState(0) , isOpaque(false) , isBatchRoot(false) { - } QSGNode *sgNode; @@ -435,7 +549,6 @@ private: friend class Updater; - void map(Buffer *buffer, int size); void unmap(Buffer *buffer, bool isIndexBuf = false); @@ -532,6 +645,9 @@ private: QHash<Node *, uint> m_visualizeChanceSet; VisualizeMode m_visualizeMode; + + Allocator<Node, 256> m_nodeAllocator; + Allocator<Element, 64> m_elementAllocator; }; Batch *Renderer::newBatch() @@ -556,4 +672,4 @@ Batch *Renderer::newBatch() QT_END_NAMESPACE -#endif // ULTRARENDERER_H +#endif // QSGBATCHRENDERER_P_H diff --git a/src/quick/scenegraph/coreapi/qsgnode.cpp b/src/quick/scenegraph/coreapi/qsgnode.cpp index 58b6462d23..29e661c454 100644 --- a/src/quick/scenegraph/coreapi/qsgnode.cpp +++ b/src/quick/scenegraph/coreapi/qsgnode.cpp @@ -504,7 +504,7 @@ void QSGNode::insertChildNodeAfter(QSGNode *node, QSGNode *after) { //Q_ASSERT_X(!m_children.contains(node), "QSGNode::insertChildNodeAfter", "QSGNode is already a child!"); Q_ASSERT_X(!node->m_parent, "QSGNode::insertChildNodeAfter", "QSGNode already has a parent"); - Q_ASSERT_X(after && after->m_parent == this, "QSGNode::insertChildNodeBefore", "The parent of \'before\' is wrong"); + Q_ASSERT_X(after && after->m_parent == this, "QSGNode::insertChildNodeAfter", "The parent of \'after\' is wrong"); #ifndef QT_NO_DEBUG if (node->type() == QSGNode::GeometryNodeType) { @@ -575,6 +575,21 @@ void QSGNode::removeAllChildNodes() } } +/*! + * \internal + * + * Reparents all nodes of this node to \a newParent. + */ +void QSGNode::reparentChildNodesTo(QSGNode *newParent) +{ + Q_ASSERT_X(!newParent->parent(), "QSGNode::reparentChildNodesTo", "newParent is already part of a hierarchy"); + + for (QSGNode *c = firstChild(); c; c = c->nextSibling()) { + removeChildNode(c); + newParent->appendChildNode(c); + } +} + int QSGNode::childCount() const { diff --git a/src/quick/scenegraph/coreapi/qsgnode.h b/src/quick/scenegraph/coreapi/qsgnode.h index dfacd84288..059cbeebdf 100644 --- a/src/quick/scenegraph/coreapi/qsgnode.h +++ b/src/quick/scenegraph/coreapi/qsgnode.h @@ -132,6 +132,7 @@ public: void appendChildNode(QSGNode *node); void insertChildNodeBefore(QSGNode *node, QSGNode *before); void insertChildNodeAfter(QSGNode *node, QSGNode *after); + void reparentChildNodesTo(QSGNode *newParent); int childCount() const; QSGNode *childAtIndex(int i) const; diff --git a/src/quick/scenegraph/coreapi/qsgrenderer.cpp b/src/quick/scenegraph/coreapi/qsgrenderer.cpp index dd089425f6..ce86408434 100644 --- a/src/quick/scenegraph/coreapi/qsgrenderer.cpp +++ b/src/quick/scenegraph/coreapi/qsgrenderer.cpp @@ -176,10 +176,11 @@ void QSGRenderer::renderScene(const QSGBindable &bindable) m_is_rendering = true; - bool profileFrames = QSG_LOG_TIME_RENDERER().isDebugEnabled() || - QQuickProfiler::profilingSceneGraph(); + bool profileFrames = QSG_LOG_TIME_RENDERER().isDebugEnabled(); if (profileFrames) frameTimer.start(); + Q_QUICK_SG_PROFILE_START(QQuickProfiler::SceneGraphRendererFrame); + qint64 bindTime = 0; qint64 renderTime = 0; @@ -189,6 +190,7 @@ void QSGRenderer::renderScene(const QSGBindable &bindable) bindable.bind(); if (profileFrames) bindTime = frameTimer.nsecsElapsed(); + Q_QUICK_SG_PROFILE_RECORD(QQuickProfiler::SceneGraphRendererFrame); // Sanity check that attribute registers are disabled if (qsg_sanity_check) { @@ -206,6 +208,7 @@ void QSGRenderer::renderScene(const QSGBindable &bindable) render(); if (profileFrames) renderTime = frameTimer.nsecsElapsed(); + Q_QUICK_SG_PROFILE_END(QQuickProfiler::SceneGraphRendererFrame); m_is_rendering = false; m_changed_emitted = false; @@ -218,13 +221,6 @@ void QSGRenderer::renderScene(const QSGBindable &bindable) int((updatePassTime - preprocessTime) / 1000000), int((bindTime - updatePassTime) / 1000000), int((renderTime - bindTime) / 1000000)); - - Q_QUICK_SG_PROFILE(QQuickProfiler::SceneGraphRendererFrame, ( - preprocessTime, - updatePassTime - preprocessTime, - bindTime - updatePassTime, - renderTime - bindTime)); - } /*! @@ -273,15 +269,16 @@ void QSGRenderer::preprocess() } } - bool profileFrames = QSG_LOG_TIME_RENDERER().isDebugEnabled()|| - QQuickProfiler::profilingSceneGraph(); + bool profileFrames = QSG_LOG_TIME_RENDERER().isDebugEnabled(); if (profileFrames) preprocessTime = frameTimer.nsecsElapsed(); + Q_QUICK_SG_PROFILE_RECORD(QQuickProfiler::SceneGraphRendererFrame); nodeUpdater()->updateStates(root); if (profileFrames) updatePassTime = frameTimer.nsecsElapsed(); + Q_QUICK_SG_PROFILE_RECORD(QQuickProfiler::SceneGraphRendererFrame); } void QSGRenderer::addNodesToPreprocess(QSGNode *node) diff --git a/src/quick/scenegraph/qsgadaptationlayer.cpp b/src/quick/scenegraph/qsgadaptationlayer.cpp index 80234d54f5..e0b96a45b6 100644 --- a/src/quick/scenegraph/qsgadaptationlayer.cpp +++ b/src/quick/scenegraph/qsgadaptationlayer.cpp @@ -153,10 +153,10 @@ void QSGDistanceFieldGlyphCache::update() if (m_pendingGlyphs.isEmpty()) return; - bool profileFrames = QSG_LOG_TIME_GLYPH().isDebugEnabled() || - QQuickProfiler::profilingSceneGraph(); + bool profileFrames = QSG_LOG_TIME_GLYPH().isDebugEnabled(); if (profileFrames) qsg_render_timer.start(); + Q_QUICK_SG_PROFILE_START(QQuickProfiler::SceneGraphAdaptationLayerFrame); QList<QDistanceField> distanceFields; for (int i = 0; i < m_pendingGlyphs.size(); ++i) { @@ -169,6 +169,7 @@ void QSGDistanceFieldGlyphCache::update() int count = m_pendingGlyphs.size(); if (profileFrames) renderTime = qsg_render_timer.nsecsElapsed(); + Q_QUICK_SG_PROFILE_RECORD(QQuickProfiler::SceneGraphAdaptationLayerFrame); m_pendingGlyphs.reset(); @@ -183,10 +184,8 @@ void QSGDistanceFieldGlyphCache::update() int(renderTime / 1000000), int((now - (renderTime / 1000000)))); } - Q_QUICK_SG_PROFILE(QQuickProfiler::SceneGraphAdaptationLayerFrame, ( - count, - renderTime, - qsg_render_timer.nsecsElapsed() - renderTime)); + Q_QUICK_SG_PROFILE_END_WITH_PAYLOAD(QQuickProfiler::SceneGraphAdaptationLayerFrame, + (qint64)count); } void QSGDistanceFieldGlyphCache::setGlyphsPosition(const QList<GlyphPosition> &glyphs) diff --git a/src/quick/scenegraph/qsgcontext.cpp b/src/quick/scenegraph/qsgcontext.cpp index b5bdbde3ad..2a0fae9f72 100644 --- a/src/quick/scenegraph/qsgcontext.cpp +++ b/src/quick/scenegraph/qsgcontext.cpp @@ -378,6 +378,7 @@ void QSGContext::renderContextInitialized(QSGRenderContext *renderContext) QByteArray all; foreach (const QByteArray &e, exts) all += ' ' + e; qCDebug(QSG_LOG_INFO) << "GL_EXTENSIONS: " << all.constData(); qCDebug(QSG_LOG_INFO) << "Max Texture Size: " << renderContext->maxTextureSize(); + qCDebug(QSG_LOG_INFO) << "Debug context: " << format.testOption(QSurfaceFormat::DebugContext); } d->mutex.unlock(); @@ -468,8 +469,11 @@ QSurfaceFormat QSGContext::defaultSurfaceFormat() const QSurfaceFormat format = QSurfaceFormat::defaultFormat(); static bool useDepth = qEnvironmentVariableIsEmpty("QSG_NO_DEPTH_BUFFER"); static bool useStencil = qEnvironmentVariableIsEmpty("QSG_NO_STENCIL_BUFFER"); + static bool enableDebug = qEnvironmentVariableIsSet("QSG_OPENGL_DEBUG"); format.setDepthBufferSize(useDepth ? 24 : 0); format.setStencilBufferSize(useStencil ? 8 : 0); + if (enableDebug) + format.setOption(QSurfaceFormat::DebugContext); if (QQuickWindow::hasDefaultAlphaBuffer()) format.setAlphaBufferSize(8); format.setSwapBehavior(QSurfaceFormat::DoubleBuffer); diff --git a/src/quick/scenegraph/qsgcontext_p.h b/src/quick/scenegraph/qsgcontext_p.h index 184b8248d5..91788d82d4 100644 --- a/src/quick/scenegraph/qsgcontext_p.h +++ b/src/quick/scenegraph/qsgcontext_p.h @@ -93,7 +93,7 @@ public: QOpenGLContext *openglContext() const { return m_gl; } QSGContext *sceneGraphContext() const { return m_sg; } - bool isValid() const { return m_gl; } + virtual bool isValid() const { return m_gl; } virtual void initialize(QOpenGLContext *context); virtual void invalidate(); diff --git a/src/quick/scenegraph/qsgdefaultlayer.cpp b/src/quick/scenegraph/qsgdefaultlayer.cpp index 450a9fbee0..2d114aebd5 100644 --- a/src/quick/scenegraph/qsgdefaultlayer.cpp +++ b/src/quick/scenegraph/qsgdefaultlayer.cpp @@ -57,7 +57,7 @@ namespace public: BindableFbo(QOpenGLFramebufferObject *fbo, QSGDepthStencilBuffer *depthStencil); virtual ~BindableFbo(); - virtual void bind() const; + void bind() const Q_DECL_OVERRIDE; private: QOpenGLFramebufferObject *m_fbo; QSGDepthStencilBuffer *m_depthStencil; diff --git a/src/quick/scenegraph/qsgdefaultlayer_p.h b/src/quick/scenegraph/qsgdefaultlayer_p.h index 44c74d7cfd..0615045d60 100644 --- a/src/quick/scenegraph/qsgdefaultlayer_p.h +++ b/src/quick/scenegraph/qsgdefaultlayer_p.h @@ -54,7 +54,7 @@ public: QSGDefaultLayer(QSGRenderContext *context); ~QSGDefaultLayer(); - virtual bool updateTexture(); + bool updateTexture() Q_DECL_OVERRIDE; // The item's "paint node", not effect node. QSGNode *item() const { return m_item; } diff --git a/src/quick/scenegraph/qsgrenderloop.cpp b/src/quick/scenegraph/qsgrenderloop.cpp index c66915d19d..ecfbe0323c 100644 --- a/src/quick/scenegraph/qsgrenderloop.cpp +++ b/src/quick/scenegraph/qsgrenderloop.cpp @@ -347,17 +347,17 @@ void QSGGuiThreadRenderLoop::renderWindow(QQuickWindow *window) } QElapsedTimer renderTimer; qint64 renderTime = 0, syncTime = 0, polishTime = 0; - bool profileFrames = QSG_LOG_TIME_RENDERLOOP().isDebugEnabled() || - QQuickProfiler::profilingSceneGraph(); + bool profileFrames = QSG_LOG_TIME_RENDERLOOP().isDebugEnabled(); if (profileFrames) renderTimer.start(); + Q_QUICK_SG_PROFILE_START(QQuickProfiler::SceneGraphPolishFrame); cd->polishItems(); - if (profileFrames) { + if (profileFrames) polishTime = renderTimer.nsecsElapsed(); - Q_QUICK_SG_PROFILE(QQuickProfiler::SceneGraphPolishFrame, (polishTime)); - } + Q_QUICK_SG_PROFILE_SWITCH(QQuickProfiler::SceneGraphPolishFrame, + QQuickProfiler::SceneGraphRenderLoopFrame); emit window->afterAnimating(); @@ -365,11 +365,13 @@ void QSGGuiThreadRenderLoop::renderWindow(QQuickWindow *window) if (profileFrames) syncTime = renderTimer.nsecsElapsed(); + Q_QUICK_SG_PROFILE_RECORD(QQuickProfiler::SceneGraphRenderLoopFrame); cd->renderSceneGraph(window->size()); if (profileFrames) renderTime = renderTimer.nsecsElapsed(); + Q_QUICK_SG_PROFILE_RECORD(QQuickProfiler::SceneGraphRenderLoopFrame); if (data.grabOnly) { grabContent = qt_gl_read_framebuffer(window->size() * window->effectiveDevicePixelRatio(), false, false); @@ -377,13 +379,15 @@ void QSGGuiThreadRenderLoop::renderWindow(QQuickWindow *window) } if (alsoSwap && window->isVisible()) { - gl->swapBuffers(window); + if (!cd->customRenderStage || !cd->customRenderStage->swap()) + gl->swapBuffers(window); cd->fireFrameSwapped(); } qint64 swapTime = 0; if (profileFrames) swapTime = renderTimer.nsecsElapsed(); + Q_QUICK_SG_PROFILE_END(QQuickProfiler::SceneGraphRenderLoopFrame); if (QSG_LOG_TIME_RENDERLOOP().isDebugEnabled()) { static QTime lastFrameTime = QTime::currentTime(); @@ -398,11 +402,6 @@ void QSGGuiThreadRenderLoop::renderWindow(QQuickWindow *window) lastFrameTime = QTime::currentTime(); } - Q_QUICK_SG_PROFILE(QQuickProfiler::SceneGraphRenderLoopFrame, ( - syncTime - polishTime, - renderTime - syncTime, - swapTime - renderTime)); - // Might have been set during syncSceneGraph() if (data.updatePending) maybeUpdate(window); diff --git a/src/quick/scenegraph/qsgrenderloop_p.h b/src/quick/scenegraph/qsgrenderloop_p.h index e9b58c60ba..8d3214db60 100644 --- a/src/quick/scenegraph/qsgrenderloop_p.h +++ b/src/quick/scenegraph/qsgrenderloop_p.h @@ -64,6 +64,7 @@ public: virtual void update(QQuickWindow *window) = 0; virtual void maybeUpdate(QQuickWindow *window) = 0; + virtual void handleUpdateRequest(QQuickWindow *) { } virtual QAnimationDriver *animationDriver() const = 0; diff --git a/src/quick/scenegraph/qsgthreadedrenderloop.cpp b/src/quick/scenegraph/qsgthreadedrenderloop.cpp index 155b52b31a..5218552427 100644 --- a/src/quick/scenegraph/qsgthreadedrenderloop.cpp +++ b/src/quick/scenegraph/qsgthreadedrenderloop.cpp @@ -105,16 +105,6 @@ QT_BEGIN_NAMESPACE #define QSG_RT_PAD " (RT)" -static int get_env_int(const char *name, int defaultValue) -{ - QByteArray content = qgetenv(name); - - bool ok = false; - int value = content.toInt(&ok); - return ok ? value : defaultValue; -} - - static inline int qsgrl_animation_interval() { qreal refreshRate = QGuiApplication::primaryScreen()->refreshRate(); // To work around that some platforms wrongfully return 0 or something @@ -531,12 +521,12 @@ void QSGRenderThread::sync(bool inExpose) void QSGRenderThread::syncAndRender() { - bool profileFrames = QSG_LOG_TIME_RENDERLOOP().isDebugEnabled() || - QQuickProfiler::profilingSceneGraph(); + bool profileFrames = QSG_LOG_TIME_RENDERLOOP().isDebugEnabled(); if (profileFrames) { sinceLastTime = threadTimer.nsecsElapsed(); threadTimer.start(); } + Q_QUICK_SG_PROFILE_START(QQuickProfiler::SceneGraphRenderLoopFrame); QElapsedTimer waitTimer; waitTimer.start(); @@ -544,20 +534,24 @@ void QSGRenderThread::syncAndRender() qCDebug(QSG_LOG_RENDERLOOP) << QSG_RT_PAD << "syncAndRender()"; syncResultedInChanges = false; + QQuickWindowPrivate *d = QQuickWindowPrivate::get(window); - uint pending = pendingUpdate; + bool repaintRequested = (pendingUpdate & RepaintRequest) || d->customRenderStage; + bool syncRequested = pendingUpdate & SyncRequest; + bool exposeRequested = (pendingUpdate & ExposeRequest) == ExposeRequest; pendingUpdate = 0; - if (pending & SyncRequest) { + if (syncRequested) { qCDebug(QSG_LOG_RENDERLOOP) << QSG_RT_PAD << "- updatePending, doing sync"; - sync(pending == ExposeRequest); + sync(exposeRequested); } #ifndef QSG_NO_RENDER_TIMING if (profileFrames) syncTime = threadTimer.nsecsElapsed(); #endif + Q_QUICK_SG_PROFILE_RECORD(QQuickProfiler::SceneGraphRenderLoopFrame); - if (!syncResultedInChanges && ((pending & RepaintRequest) == 0)) { + if (!syncResultedInChanges && !repaintRequested) { qCDebug(QSG_LOG_RENDERLOOP) << QSG_RT_PAD << "- no changes, render aborted"; int waitTime = vsyncDelta - (int) waitTimer.elapsed(); if (waitTime > 0) @@ -567,7 +561,6 @@ void QSGRenderThread::syncAndRender() qCDebug(QSG_LOG_RENDERLOOP) << QSG_RT_PAD << "- rendering started"; - QQuickWindowPrivate *d = QQuickWindowPrivate::get(window); if (animatorDriver->isRunning()) { d->animationController->lock(); @@ -582,9 +575,12 @@ void QSGRenderThread::syncAndRender() d->renderSceneGraph(windowSize); if (profileFrames) renderTime = threadTimer.nsecsElapsed(); - gl->swapBuffers(window); + Q_QUICK_SG_PROFILE_RECORD(QQuickProfiler::SceneGraphRenderLoopFrame); + if (!d->customRenderStage || !d->customRenderStage->swap()) + gl->swapBuffers(window); d->fireFrameSwapped(); } else { + Q_QUICK_SG_PROFILE_SKIP(QQuickProfiler::SceneGraphRenderLoopFrame, 1); qCDebug(QSG_LOG_RENDERLOOP) << QSG_RT_PAD << "- window not ready, skipping render"; } @@ -595,7 +591,7 @@ void QSGRenderThread::syncAndRender() // that to avoid blocking the GUI thread in the case where it // has started rendering with a bad window, causing makeCurrent to // fail or if the window has a bad size. - if (pending == ExposeRequest) { + if (exposeRequested) { qCDebug(QSG_LOG_RENDERLOOP) << QSG_RT_PAD << "- wake Gui after initial expose"; waitCondition.wakeOne(); mutex.unlock(); @@ -609,10 +605,7 @@ void QSGRenderThread::syncAndRender() int(threadTimer.elapsed() - renderTime / 1000000)); - Q_QUICK_SG_PROFILE(QQuickProfiler::SceneGraphRenderLoopFrame, ( - syncTime, - renderTime - syncTime, - threadTimer.nsecsElapsed() - renderTime)); + Q_QUICK_SG_PROFILE_END(QQuickProfiler::SceneGraphRenderLoopFrame); } @@ -695,8 +688,6 @@ QSGThreadedRenderLoop::QSGThreadedRenderLoop() m_animation_driver = sg->createAnimationDriver(this); - m_exhaust_delay = get_env_int("QML_EXHAUST_DELAY", 5); - connect(m_animation_driver, SIGNAL(started()), this, SLOT(animationStarted())); connect(m_animation_driver, SIGNAL(stopped()), this, SLOT(animationStopped())); @@ -710,10 +701,7 @@ QSGRenderContext *QSGThreadedRenderLoop::createRenderContext(QSGContext *sg) con void QSGThreadedRenderLoop::maybePostPolishRequest(Window *w) { - if (w->timerId == 0) { - qCDebug(QSG_LOG_RENDERLOOP) << "- posting update"; - w->timerId = startTimer(m_exhaust_delay, Qt::PreciseTimer); - } + w->window->requestUpdate(); } QAnimationDriver *QSGThreadedRenderLoop::animationDriver() const @@ -863,7 +851,6 @@ void QSGThreadedRenderLoop::handleExposure(QQuickWindow *window) win.window = window; win.actualWindowFormat = window->format(); win.thread = new QSGRenderThread(this, QQuickWindowPrivate::get(window)->context); - win.timerId = 0; win.updateDuringSync = false; win.forceRenderPass = true; // also covered by polishAndSync(inExpose=true), but doesn't hurt m_windows << win; @@ -953,6 +940,14 @@ void QSGThreadedRenderLoop::handleObscurity(Window *w) } +void QSGThreadedRenderLoop::handleUpdateRequest(QQuickWindow *window) +{ + qCDebug(QSG_LOG_RENDERLOOP) << "- polish and sync update request"; + foreach (const Window &w, m_windows) + if (w.window == window) + polishAndSync(const_cast<Window *>(&w)); +} + void QSGThreadedRenderLoop::maybeUpdate(QQuickWindow *window) { Window *w = windowFor(m_windows, window); @@ -1080,8 +1075,6 @@ void QSGThreadedRenderLoop::polishAndSync(Window *w, bool inExpose) QQuickWindow *window = w->window; if (!w->thread || !w->thread->window) { qCDebug(QSG_LOG_RENDERLOOP) << "- not exposed, abort"; - killTimer(w->timerId); - w->timerId = 0; return; } @@ -1091,8 +1084,6 @@ void QSGThreadedRenderLoop::polishAndSync(Window *w, bool inExpose) w = windowFor(m_windows, window); if (!w || !w->thread || !w->thread->window) { qCDebug(QSG_LOG_RENDERLOOP) << "- removed after event flushing, abort"; - killTimer(w->timerId); - w->timerId = 0; return; } @@ -1101,16 +1092,17 @@ void QSGThreadedRenderLoop::polishAndSync(Window *w, bool inExpose) qint64 polishTime = 0; qint64 waitTime = 0; qint64 syncTime = 0; - bool profileFrames = QSG_LOG_TIME_RENDERLOOP().isDebugEnabled() || - QQuickProfiler::profilingSceneGraph(); + bool profileFrames = QSG_LOG_TIME_RENDERLOOP().isDebugEnabled(); if (profileFrames) timer.start(); + Q_QUICK_SG_PROFILE_START(QQuickProfiler::SceneGraphPolishAndSync); QQuickWindowPrivate *d = QQuickWindowPrivate::get(window); d->polishItems(); if (profileFrames) polishTime = timer.nsecsElapsed(); + Q_QUICK_SG_PROFILE_RECORD(QQuickProfiler::SceneGraphPolishAndSync); w->updateDuringSync = false; @@ -1125,6 +1117,7 @@ void QSGThreadedRenderLoop::polishAndSync(Window *w, bool inExpose) qCDebug(QSG_LOG_RENDERLOOP) << "- wait for sync"; if (profileFrames) waitTime = timer.nsecsElapsed(); + Q_QUICK_SG_PROFILE_RECORD(QQuickProfiler::SceneGraphPolishAndSync); w->thread->waitCondition.wait(&w->thread->mutex); m_lockedForSync = false; w->thread->mutex.unlock(); @@ -1132,9 +1125,7 @@ void QSGThreadedRenderLoop::polishAndSync(Window *w, bool inExpose) if (profileFrames) syncTime = timer.nsecsElapsed(); - - killTimer(w->timerId); - w->timerId = 0; + Q_QUICK_SG_PROFILE_RECORD(QQuickProfiler::SceneGraphPolishAndSync); if (m_animation_timer == 0 && m_animation_driver->isRunning()) { qCDebug(QSG_LOG_RENDERLOOP) << "- advancing animations"; @@ -1155,22 +1146,7 @@ void QSGThreadedRenderLoop::polishAndSync(Window *w, bool inExpose) << ", animations=" << (timer.nsecsElapsed() - syncTime) / 1000000 << " - (on Gui thread) " << window; - Q_QUICK_SG_PROFILE(QQuickProfiler::SceneGraphPolishAndSync, ( - polishTime, - waitTime - polishTime, - syncTime - waitTime, - timer.nsecsElapsed() - syncTime)); -} - -QSGThreadedRenderLoop::Window *QSGThreadedRenderLoop::windowForTimer(int timerId) const -{ - for (int i=0; i<m_windows.size(); ++i) { - if (m_windows.at(i).timerId == timerId) { - return const_cast<Window *>(&m_windows.at(i)); - break; - } - } - return 0; + Q_QUICK_SG_PROFILE_END(QQuickProfiler::SceneGraphPolishAndSync); } bool QSGThreadedRenderLoop::event(QEvent *e) @@ -1183,15 +1159,8 @@ bool QSGThreadedRenderLoop::event(QEvent *e) qCDebug(QSG_LOG_RENDERLOOP) << "- ticking non-visual timer"; m_animation_driver->advance(); emit timeToIncubate(); - } else { - qCDebug(QSG_LOG_RENDERLOOP) << "- polish and sync timer"; - Window *w = windowForTimer(te->timerId()); - if (w) - polishAndSync(w); - else - killTimer(te->timerId()); + return true; } - return true; } default: diff --git a/src/quick/scenegraph/qsgthreadedrenderloop_p.h b/src/quick/scenegraph/qsgthreadedrenderloop_p.h index 82f314a6af..b3db56e5f9 100644 --- a/src/quick/scenegraph/qsgthreadedrenderloop_p.h +++ b/src/quick/scenegraph/qsgthreadedrenderloop_p.h @@ -60,6 +60,8 @@ public: void update(QQuickWindow *window); void maybeUpdate(QQuickWindow *window); + void handleUpdateRequest(QQuickWindow *window); + QSGContext *sceneGraphContext() const; QSGRenderContext *createRenderContext(QSGContext *) const; @@ -80,7 +82,6 @@ private: QQuickWindow *window; QSGRenderThread *thread; QSurfaceFormat actualWindowFormat; - int timerId; uint updateDuringSync : 1; uint forceRenderPass : 1; }; @@ -89,7 +90,6 @@ private: void releaseResources(Window *window, bool inDestructor); bool checkAndResetForceUpdate(QQuickWindow *window); - Window *windowForTimer(int timerId) const; bool anyoneShowing() const; void initialize(); @@ -109,7 +109,6 @@ private: QList<Window> m_windows; int m_animation_timer; - int m_exhaust_delay; bool m_lockedForSync; }; diff --git a/src/quick/scenegraph/qsgwindowsrenderloop.cpp b/src/quick/scenegraph/qsgwindowsrenderloop.cpp index 070d6b82fd..469cd1d21b 100644 --- a/src/quick/scenegraph/qsgwindowsrenderloop.cpp +++ b/src/quick/scenegraph/qsgwindowsrenderloop.cpp @@ -53,10 +53,14 @@ extern Q_GUI_EXPORT QImage qt_gl_read_framebuffer(const QSize &size, bool alpha_ #define RLDEBUG(x) qCDebug(QSG_LOG_RENDERLOOP) << x; static QElapsedTimer qsg_render_timer; -#define QSG_RENDER_TIMING_SAMPLE(sampleName) \ +#define QSG_LOG_TIME_SAMPLE(sampleName) \ qint64 sampleName = 0; \ - if (QSG_LOG_TIME_RENDERLOOP().isDebugEnabled() || QQuickProfiler::profilingSceneGraph()) \ - sampleName = qsg_render_timer.nsecsElapsed() + if (QSG_LOG_TIME_RENDERLOOP().isDebugEnabled()) \ + sampleName = qsg_render_timer.nsecsElapsed(); \ + +#define QSG_RENDER_TIMING_SAMPLE(frameType, sampleName) \ + QSG_LOG_TIME_SAMPLE(sampleName) \ + Q_QUICK_SG_PROFILE_RECORD(frameType); QSGWindowsRenderLoop::QSGWindowsRenderLoop() @@ -346,7 +350,8 @@ void QSGWindowsRenderLoop::render() if (m_animationDriver->isRunning()) { RLDEBUG("advancing animations"); - QSG_RENDER_TIMING_SAMPLE(time_start); + QSG_LOG_TIME_SAMPLE(time_start); + Q_QUICK_SG_PROFILE_START(QQuickProfiler::SceneGraphWindowsAnimations); m_animationDriver->advance(); RLDEBUG("animations advanced"); @@ -354,8 +359,7 @@ void QSGWindowsRenderLoop::render() "animations ticked in %dms", int((qsg_render_timer.nsecsElapsed() - time_start)/1000000)); - Q_QUICK_SG_PROFILE(QQuickProfiler::SceneGraphWindowsAnimations, ( - qsg_render_timer.nsecsElapsed() - time_start)); + Q_QUICK_SG_PROFILE_END(QQuickProfiler::SceneGraphWindowsAnimations); // It is not given that animations triggered another maybeUpdate() // and thus another render pass, so to keep things running, @@ -390,27 +394,29 @@ void QSGWindowsRenderLoop::renderWindow(QQuickWindow *window) if (!windowData(window)) return; - QSG_RENDER_TIMING_SAMPLE(time_start); + QSG_LOG_TIME_SAMPLE(time_start); + Q_QUICK_SG_PROFILE_START(QQuickProfiler::SceneGraphPolishFrame); RLDEBUG(" - polishing"); d->polishItems(); - QSG_RENDER_TIMING_SAMPLE(time_polished); - - Q_QUICK_SG_PROFILE(QQuickProfiler::SceneGraphPolishFrame, (time_polished - time_start)); + QSG_LOG_TIME_SAMPLE(time_polished); + Q_QUICK_SG_PROFILE_SWITCH(QQuickProfiler::SceneGraphPolishFrame, + QQuickProfiler::SceneGraphRenderLoopFrame); emit window->afterAnimating(); RLDEBUG(" - syncing"); d->syncSceneGraph(); - QSG_RENDER_TIMING_SAMPLE(time_synced); + QSG_RENDER_TIMING_SAMPLE(QQuickProfiler::SceneGraphRenderLoopFrame, time_synced); RLDEBUG(" - rendering"); d->renderSceneGraph(window->size()); - QSG_RENDER_TIMING_SAMPLE(time_rendered); + QSG_RENDER_TIMING_SAMPLE(QQuickProfiler::SceneGraphRenderLoopFrame, time_rendered); RLDEBUG(" - swapping"); - m_gl->swapBuffers(window); - QSG_RENDER_TIMING_SAMPLE(time_swapped); + if (!d->customRenderStage || !d->customRenderStage->swap()) + m_gl->swapBuffers(window); + QSG_RENDER_TIMING_SAMPLE(QQuickProfiler::SceneGraphRenderLoopFrame, time_swapped); RLDEBUG(" - frameDone"); d->fireFrameSwapped(); @@ -423,10 +429,7 @@ void QSGWindowsRenderLoop::renderWindow(QQuickWindow *window) << ", swap=" << (time_swapped - time_rendered) / 1000000 << " - " << window; - Q_QUICK_SG_PROFILE(QQuickProfiler::SceneGraphRenderLoopFrame, ( - time_synced - time_polished, - time_rendered - time_synced, - time_swapped - time_rendered)); + Q_QUICK_SG_PROFILE_REPORT(QQuickProfiler::SceneGraphRenderLoopFrame); } QT_END_NAMESPACE diff --git a/src/quick/scenegraph/util/qsgatlastexture.cpp b/src/quick/scenegraph/util/qsgatlastexture.cpp index 5edcb5d67a..cb82d721ca 100644 --- a/src/quick/scenegraph/util/qsgatlastexture.cpp +++ b/src/quick/scenegraph/util/qsgatlastexture.cpp @@ -377,10 +377,12 @@ void Atlas::bind(QSGTexture::Filtering filtering) // Upload all pending images.. for (int i=0; i<m_pending_uploads.size(); ++i) { - bool profileFrames = QSG_LOG_TIME_TEXTURE().isDebugEnabled() || - QQuickProfiler::profilingSceneGraph(); + bool profileFrames = QSG_LOG_TIME_TEXTURE().isDebugEnabled(); if (profileFrames) qsg_renderer_timer.start(); + // Skip bind, convert, swizzle; they're irrelevant + Q_QUICK_SG_PROFILE_START(QQuickProfiler::SceneGraphTexturePrepare); + Q_QUICK_SG_PROFILE_SKIP(QQuickProfiler::SceneGraphTexturePrepare, 3); if (m_externalFormat == GL_BGRA && !m_use_bgra_fallback) { @@ -393,12 +395,10 @@ void Atlas::bind(QSGTexture::Filtering filtering) << "ms (" << m_pending_uploads.at(i)->image().width() << "x" << m_pending_uploads.at(i)->image().height() << ")"; - Q_QUICK_SG_PROFILE(QQuickProfiler::SceneGraphTexturePrepare, ( - 0, // bind (not relevant) - 0, // convert (not relevant) - 0, // swizzle (not relevant) - qsg_renderer_timer.nsecsElapsed(), // (upload all of the above) - 0)); // mipmap (not used ever...) + // Skip mipmap; unused + Q_QUICK_SG_PROFILE_RECORD(QQuickProfiler::SceneGraphTexturePrepare); + Q_QUICK_SG_PROFILE_SKIP(QQuickProfiler::SceneGraphTexturePrepare, 1); + Q_QUICK_SG_PROFILE_REPORT(QQuickProfiler::SceneGraphTexturePrepare); } GLenum f = filtering == QSGTexture::Nearest ? GL_NEAREST : GL_LINEAR; diff --git a/src/quick/scenegraph/util/qsgtexture.cpp b/src/quick/scenegraph/util/qsgtexture.cpp index fc5050014e..673323baa2 100644 --- a/src/quick/scenegraph/util/qsgtexture.cpp +++ b/src/quick/scenegraph/util/qsgtexture.cpp @@ -633,10 +633,12 @@ void QSGPlainTexture::bind() m_dirty_texture = false; - bool profileFrames = QSG_LOG_TIME_TEXTURE().isDebugEnabled() || - QQuickProfiler::profilingSceneGraph(); + bool profileFrames = QSG_LOG_TIME_TEXTURE().isDebugEnabled(); if (profileFrames) qsg_renderer_timer.start(); + Q_QUICK_SG_PROFILE_START_SYNCHRONIZED(QQuickProfiler::SceneGraphTexturePrepare, + QQuickProfiler::SceneGraphTextureDeletion); + if (m_image.isNull()) { if (m_texture_id && m_owns_texture) { @@ -645,8 +647,7 @@ void QSGPlainTexture::bind() (int) qsg_renderer_timer.elapsed(), m_texture_size.width(), m_texture_size.height()); - Q_QUICK_SG_PROFILE(QQuickProfiler::SceneGraphTextureDeletion, ( - qsg_renderer_timer.nsecsElapsed())); + Q_QUICK_SG_PROFILE_END(QQuickProfiler::SceneGraphTextureDeletion); } m_texture_id = 0; m_texture_size = QSize(); @@ -662,6 +663,7 @@ void QSGPlainTexture::bind() qint64 bindTime = 0; if (profileFrames) bindTime = qsg_renderer_timer.nsecsElapsed(); + Q_QUICK_SG_PROFILE_RECORD(QQuickProfiler::SceneGraphTexturePrepare); // ### TODO: check for out-of-memory situations... @@ -692,6 +694,7 @@ void QSGPlainTexture::bind() qint64 convertTime = 0; if (profileFrames) convertTime = qsg_renderer_timer.nsecsElapsed(); + Q_QUICK_SG_PROFILE_RECORD(QQuickProfiler::SceneGraphTexturePrepare); updateBindOptions(m_dirty_bind_options); @@ -734,12 +737,14 @@ void QSGPlainTexture::bind() qint64 swizzleTime = 0; if (profileFrames) swizzleTime = qsg_renderer_timer.nsecsElapsed(); + Q_QUICK_SG_PROFILE_RECORD(QQuickProfiler::SceneGraphTexturePrepare); funcs->glTexImage2D(GL_TEXTURE_2D, 0, internalFormat, m_texture_size.width(), m_texture_size.height(), 0, externalFormat, GL_UNSIGNED_BYTE, tmp.constBits()); qint64 uploadTime = 0; if (profileFrames) uploadTime = qsg_renderer_timer.nsecsElapsed(); + Q_QUICK_SG_PROFILE_RECORD(QQuickProfiler::SceneGraphTexturePrepare); if (mipmapFiltering() != QSGTexture::None) { funcs->glGenerateMipmap(GL_TEXTURE_2D); @@ -762,13 +767,7 @@ void QSGPlainTexture::bind() int((mipmapTime - uploadTime)/1000000), m_texture_size != m_image.size() ? " (scaled to GL_MAX_TEXTURE_SIZE)" : ""); } - - Q_QUICK_SG_PROFILE(QQuickProfiler::SceneGraphTexturePrepare, ( - bindTime, - convertTime - bindTime, - swizzleTime - convertTime, - uploadTime - swizzleTime, - qsg_renderer_timer.nsecsElapsed() - uploadTime)); + Q_QUICK_SG_PROFILE_END(QQuickProfiler::SceneGraphTexturePrepare); m_texture_rect = QRectF(0, 0, 1, 1); diff --git a/src/quick/scenegraph/util/qsgvertexcolormaterial.cpp b/src/quick/scenegraph/util/qsgvertexcolormaterial.cpp index 3a84bf6219..be24ebe76d 100644 --- a/src/quick/scenegraph/util/qsgvertexcolormaterial.cpp +++ b/src/quick/scenegraph/util/qsgvertexcolormaterial.cpp @@ -99,9 +99,12 @@ void QSGVertexColorMaterialShader::initialize() The geometry to be rendered with vertex color must have the following layout. Attribute position 0 must contain vertices. Attribute position 1 must contain colors, a tuple of 4 values with RGBA layout. Both floats in the range of 0 to 1 and unsigned bytes in - the range 0 to 255 are valid for the color values. The - QSGGeometry::defaultAttributes_ColoredPoint2D() constructs an attribute set - compatible with this material. + the range 0 to 255 are valid for the color values. + + \note The rendering pipeline expects pixels with premultiplied alpha. + + QSGGeometry::defaultAttributes_ColoredPoint2D() can be used to construct an attribute + set that is compatible with this material. The vertex color material respects both current opacity and current matrix when updating it's rendering state. diff --git a/src/quick/util/qquickanimatorjob.cpp b/src/quick/util/qquickanimatorjob.cpp index f29ec49b9f..536413bba9 100644 --- a/src/quick/util/qquickanimatorjob.cpp +++ b/src/quick/util/qquickanimatorjob.cpp @@ -405,21 +405,33 @@ void QQuickOpacityAnimatorJob::initialize(QQuickAnimatorController *controller) m_opacityNode = d->opacityNode(); if (!m_opacityNode) { m_opacityNode = new QSGOpacityNode(); - d->extra.value().opacityNode = m_opacityNode; - - QSGNode *child = d->clipNode(); - if (!child) - child = d->rootNode(); - if (!child) - child = d->groupNode; - if (child) { + /* The item node subtree is like this + * + * itemNode + * (opacityNode) optional + * (clipNode) optional + * (rootNode) optional + * children / paintNode + * + * If the opacity node doesn't exist, we need to insert it into + * the hierarchy between itemNode and clipNode or rootNode. If + * neither clip or root exists, we need to reparent all children + * from itemNode to opacityNode. + */ + QSGNode *iNode = d->itemNode(); + QSGNode *child = d->childContainerNode(); + if (child != iNode) { if (child->parent()) child->parent()->removeChildNode(child); m_opacityNode->appendChildNode(child); + iNode->appendChildNode(m_opacityNode); + } else { + iNode->reparentChildNodesTo(m_opacityNode); + iNode->appendChildNode(m_opacityNode); } - d->itemNode()->appendChildNode(m_opacityNode); + d->extra.value().opacityNode = m_opacityNode; } } diff --git a/src/quick/util/qquickpixmapcache.cpp b/src/quick/util/qquickpixmapcache.cpp index 22ed9b7486..a2a8ef03c7 100644 --- a/src/quick/util/qquickpixmapcache.cpp +++ b/src/quick/util/qquickpixmapcache.cpp @@ -831,8 +831,10 @@ void QQuickPixmapStore::unreferencePixmap(QQuickPixmapData *data) shrinkCache(-1); // Shrink the cache in case it has become larger than cache_limit - if (m_timerId == -1 && m_unreferencedPixmaps && !m_destroying) + if (m_timerId == -1 && m_unreferencedPixmaps + && !m_destroying && !QCoreApplication::closingDown()) { m_timerId = startTimer(CACHE_EXPIRE_TIME * 1000); + } } void QQuickPixmapStore::referencePixmap(QQuickPixmapData *data) diff --git a/src/quick/util/qquickprofiler.cpp b/src/quick/util/qquickprofiler.cpp index 3b34b7550b..c4441ed5dd 100644 --- a/src/quick/util/qquickprofiler.cpp +++ b/src/quick/util/qquickprofiler.cpp @@ -80,7 +80,7 @@ void QQuickProfilerData::toByteArrays(QList<QByteArray> &messages) const // RendererFrame: preprocessTime, updateTime, bindingTime, renderTime case QQuickProfiler::SceneGraphRendererFrame: ds << subtime_1 << subtime_2 << subtime_3 << subtime_4; break; // AdaptationLayerFrame: glyphCount (which is an integer), glyphRenderTime, glyphStoreTime - case QQuickProfiler::SceneGraphAdaptationLayerFrame: ds << subtime_1 << subtime_2 << subtime_3; break; + case QQuickProfiler::SceneGraphAdaptationLayerFrame: ds << subtime_3 << subtime_1 << subtime_2; break; // ContextFrame: compiling material time case QQuickProfiler::SceneGraphContextFrame: ds << subtime_1; break; // RenderLoop: syncTime, renderTime, swapTime diff --git a/src/quick/util/qquickprofiler_p.h b/src/quick/util/qquickprofiler_p.h index 62e23cd393..ea37558741 100644 --- a/src/quick/util/qquickprofiler_p.h +++ b/src/quick/util/qquickprofiler_p.h @@ -51,6 +51,7 @@ #include <QUrl> #include <QSize> #include <QMutex> +#include <QThreadStorage> QT_BEGIN_NAMESPACE @@ -63,9 +64,38 @@ QT_BEGIN_NAMESPACE #define Q_QUICK_PROFILE(feature, Method)\ Q_QUICK_PROFILE_IF_ENABLED(feature, QQuickProfiler::Method) -#define Q_QUICK_SG_PROFILE(Type, Params)\ +#define Q_QUICK_SG_PROFILE_START(Type)\ Q_QUICK_PROFILE_IF_ENABLED(QQuickProfiler::ProfileSceneGraph,\ - (QQuickProfiler::sceneGraphFrame<Type> Params)) + (QQuickProfiler::startSceneGraphFrame<Type>())) + +#define Q_QUICK_SG_PROFILE_RECORD(Type)\ + Q_QUICK_PROFILE_IF_ENABLED(QQuickProfiler::ProfileSceneGraph,\ + (QQuickProfiler::recordSceneGraphTimestamp<Type>())) + +#define Q_QUICK_SG_PROFILE_SKIP(Type, Skip)\ + Q_QUICK_PROFILE_IF_ENABLED(QQuickProfiler::ProfileSceneGraph,\ + (QQuickProfiler::skipSceneGraphTimestamps<Type, Skip>())) + +#define Q_QUICK_SG_PROFILE_START_SYNCHRONIZED(Type1, Type2)\ + Q_QUICK_PROFILE_IF_ENABLED(QQuickProfiler::ProfileSceneGraph,\ + (QQuickProfiler::startSceneGraphFrame<Type1, Type2>())) + +#define Q_QUICK_SG_PROFILE_SWITCH(Type1, Type2) \ + Q_QUICK_PROFILE_IF_ENABLED(QQuickProfiler::ProfileSceneGraph,\ + (QQuickProfiler::reportSceneGraphFrame<Type1, true, Type2>())) + +#define Q_QUICK_SG_PROFILE_REPORT(Type)\ + Q_QUICK_PROFILE_IF_ENABLED(QQuickProfiler::ProfileSceneGraph,\ + (QQuickProfiler::reportSceneGraphFrame<Type, false>())) + +#define Q_QUICK_SG_PROFILE_END(Type)\ + Q_QUICK_PROFILE_IF_ENABLED(QQuickProfiler::ProfileSceneGraph,\ + (QQuickProfiler::reportSceneGraphFrame<Type, true>())) + +#define Q_QUICK_SG_PROFILE_END_WITH_PAYLOAD(Type, Payload)\ + Q_QUICK_PROFILE_IF_ENABLED(QQuickProfiler::ProfileSceneGraph,\ + (QQuickProfiler::reportSceneGraphFrame<Type, true>(Payload))) + #define Q_QUICK_INPUT_PROFILE(Method)\ Q_QUICK_PROFILE(QQuickProfiler::ProfileInputEvents, Method) @@ -136,6 +166,39 @@ struct Q_AUTOTEST_EXPORT QQuickProfilerData Q_DECLARE_TYPEINFO(QQuickProfilerData, Q_MOVABLE_TYPE); +class QQuickProfilerSceneGraphData : public QQmlProfilerDefinitions { +private: + static const uint s_numSceneGraphTimings = 5; + + template<uint size> + struct TimingData { + qint64 values[size][s_numSceneGraphTimings + 1]; + int offsets[size]; + }; + + QThreadStorage<TimingData<NumRenderThreadFrameTypes> > renderThreadTimings; + TimingData<NumGUIThreadFrameTypes> guiThreadTimings; + +public: + template<SceneGraphFrameType type> + qint64 *timings() + { + if (type < NumRenderThreadFrameTypes) + return renderThreadTimings.localData().values[type]; + else + return guiThreadTimings.values[type - NumRenderThreadFrameTypes]; + } + + template<SceneGraphFrameType type> + int &offset() + { + if (type < NumRenderThreadFrameTypes) + return renderThreadTimings.localData().offsets[type]; + else + return guiThreadTimings.offsets[type - NumRenderThreadFrameTypes]; + } +}; + class Q_QUICK_PRIVATE_EXPORT QQuickProfiler : public QQmlAbstractProfilerAdapter { Q_OBJECT public: @@ -163,12 +226,62 @@ public: } } + template<SceneGraphFrameType FrameType1, SceneGraphFrameType FrameType2> + static void startSceneGraphFrame() + { + startSceneGraphFrame<FrameType1>(); + s_instance->m_sceneGraphData.offset<FrameType2>() = 0; + s_instance->m_sceneGraphData.timings<FrameType2>()[0] = + s_instance->m_sceneGraphData.timings<FrameType1>()[0]; + } + template<SceneGraphFrameType FrameType> - static void sceneGraphFrame(qint64 value1, qint64 value2 = -1, qint64 value3 = -1, - qint64 value4 = -1, qint64 value5 = -1) + static void startSceneGraphFrame() + { + s_instance->m_sceneGraphData.offset<FrameType>() = 0; + s_instance->m_sceneGraphData.timings<FrameType>()[0] = s_instance->timestamp(); + } + + template<SceneGraphFrameType FrameType> + static void recordSceneGraphTimestamp() + { + s_instance->m_sceneGraphData.timings<FrameType>() + [++s_instance->m_sceneGraphData.offset<FrameType>()] = s_instance->timestamp(); + } + + template<SceneGraphFrameType FrameType, uint Skip> + static void skipSceneGraphTimestamps() + { + qint64 *timings = s_instance->m_sceneGraphData.timings<FrameType>(); + const qint64 last = timings[s_instance->m_sceneGraphData.offset<FrameType>()]; + for (uint i = 0; i < Skip; ++i) + timings[++s_instance->m_sceneGraphData.offset<FrameType>()] = last; + } + + template<SceneGraphFrameType FrameType, bool Record> + static void reportSceneGraphFrame(quint64 payload = -1) + { + qint64 *timings = s_instance->m_sceneGraphData.timings<FrameType>(); + int &offset = s_instance->m_sceneGraphData.offset<FrameType>(); + if (Record) + timings[++offset] = s_instance->timestamp(); + s_instance->processMessage(QQuickProfilerData( + timings[offset], 1 << SceneGraphFrame, 1 << FrameType, + offset > 0 ? timings[1] - timings[0] : payload, + offset > 1 ? timings[2] - timings[1] : payload, + offset > 2 ? timings[3] - timings[2] : payload, + offset > 3 ? timings[4] - timings[3] : payload, + offset > 4 ? timings[5] - timings[4] : payload)); + } + + template<SceneGraphFrameType FrameType, bool Record, SceneGraphFrameType SwitchTo> + static void reportSceneGraphFrame(quint64 payload = -1) { - s_instance->processMessage(QQuickProfilerData(s_instance->timestamp(), 1 << SceneGraphFrame, - 1 << FrameType, value1, value2, value3, value4, value5)); + reportSceneGraphFrame<FrameType, Record>(payload); + s_instance->m_sceneGraphData.offset<SwitchTo>() = 0; + s_instance->m_sceneGraphData.timings<SwitchTo>()[0] = + s_instance->m_sceneGraphData.timings<FrameType>() + [s_instance->m_sceneGraphData.offset<FrameType>()]; } template<PixmapEventType PixmapState> @@ -215,6 +328,7 @@ protected: QMutex m_dataMutex; QElapsedTimer m_timer; QVarLengthArray<QQuickProfilerData> m_data; + QQuickProfilerSceneGraphData m_sceneGraphData; QQuickProfiler(QQmlProfilerService *service); diff --git a/src/quickwidgets/qquickwidget.h b/src/quickwidgets/qquickwidget.h index 530a523470..87f688c11a 100644 --- a/src/quickwidgets/qquickwidget.h +++ b/src/quickwidgets/qquickwidget.h @@ -99,6 +99,7 @@ Q_SIGNALS: void sceneGraphError(QQuickWindow::SceneGraphError error, const QString &message); private Q_SLOTS: + // ### Qt 6: make these truly private slots through Q_PRIVATE_SLOT void continueExecute(); void createFramebufferObject(); void destroyFramebufferObject(); |