From f6fee09942de7901a708c4e16db0c7c82550e8c5 Mon Sep 17 00:00:00 2001 From: Erik Verbruggen Date: Tue, 12 Apr 2016 14:52:23 +0200 Subject: [PATCH 01/12] QML: When available, use QQmlAccessors to read properties. When a property is read from a QObject or the QML scope object, and we can statically resolve the type to qreal/QObject/int/bool/QString, and the property has an accessor declared for it, then use that accessor to do the read. This collapses the path of e.g.: Runtime::getQmlScopeObjectProperty -> QObjectWrapper::getProperty -> QObjectWrapper::getProperty -> LoadProperty -> QQmlAccessor::read (all of which do various checks for all the stuff mentioned above) to: Runtime::accessQmlScopeObjectQRealProperty -> QQmlAccessor::read which is a simple 4-line function, and doesn't need to do any check. According to valgrind, this saves 170 instructions on x86 for the simple binding: Item { width: height } Change-Id: I0761d01e8f1a3c13ecbffe2d8e0317ce9c0a4db0 Reviewed-by: Simon Hausmann --- src/qml/compiler/qv4instr_moth_p.h | 90 ++++++++++++++ src/qml/compiler/qv4isel_moth.cpp | 100 +++++++++++++++- src/qml/compiler/qv4isel_moth_p.h | 4 +- src/qml/compiler/qv4isel_p.cpp | 7 +- src/qml/compiler/qv4isel_p.h | 5 +- src/qml/compiler/qv4jsir.cpp | 12 +- src/qml/jit/qv4isel_masm.cpp | 79 ++++++++++++- src/qml/jit/qv4isel_masm_p.h | 4 +- src/qml/jit/qv4regalloc.cpp | 4 +- src/qml/jsruntime/qv4qobjectwrapper_p.h | 1 + src/qml/jsruntime/qv4runtime.cpp | 110 ++++++++++++++++++ src/qml/jsruntime/qv4runtime_p.h | 68 ++++++++++- src/qml/jsruntime/qv4runtimeapi_p.h | 21 ++++ src/qml/jsruntime/qv4vme_moth.cpp | 40 +++++++ src/qml/qml/qqmlpropertycache_p.h | 2 + .../benchmarks/qml/creation/tst_creation.cpp | 89 ++++++++++++++ 16 files changed, 616 insertions(+), 20 deletions(-) diff --git a/src/qml/compiler/qv4instr_moth_p.h b/src/qml/compiler/qv4instr_moth_p.h index 93a7170e68..93043135a4 100644 --- a/src/qml/compiler/qv4instr_moth_p.h +++ b/src/qml/compiler/qv4instr_moth_p.h @@ -81,9 +81,19 @@ QT_BEGIN_NAMESPACE F(SetLookup, setLookup) \ F(StoreQObjectProperty, storeQObjectProperty) \ F(LoadQObjectProperty, loadQObjectProperty) \ + F(LoadQRealQObjectPropertyDirectly, loadQRealQObjectPropertyDirectly) \ + F(LoadQObjectQObjectPropertyDirectly, loadQObjectQObjectPropertyDirectly) \ + F(LoadIntQObjectPropertyDirectly, loadIntQObjectPropertyDirectly) \ + F(LoadBoolQObjectPropertyDirectly, loadBoolQObjectPropertyDirectly) \ + F(LoadQStringQObjectPropertyDirectly, loadQStringQObjectPropertyDirectly) \ F(StoreScopeObjectProperty, storeScopeObjectProperty) \ F(StoreContextObjectProperty, storeContextObjectProperty) \ F(LoadScopeObjectProperty, loadScopeObjectProperty) \ + F(LoadScopeObjectQRealPropertyDirectly, loadScopeObjectQRealPropertyDirectly) \ + F(LoadScopeObjectQObjectPropertyDirectly, loadScopeObjectQObjectPropertyDirectly) \ + F(LoadScopeObjectIntPropertyDirectly, loadScopeObjectIntPropertyDirectly) \ + F(LoadScopeObjectBoolPropertyDirectly, loadScopeObjectBoolPropertyDirectly) \ + F(LoadScopeObjectQStringPropertyDirectly, loadScopeObjectQStringPropertyDirectly) \ F(LoadContextObjectProperty, loadContextObjectProperty) \ F(LoadIdObject, loadIdObject) \ F(LoadAttachedQObjectProperty, loadAttachedQObjectProperty) \ @@ -323,6 +333,36 @@ union Instr Param base; Param result; }; + struct instr_loadScopeObjectQRealPropertyDirectly { + MOTH_INSTR_HEADER + Param base; + Param result; + QQmlAccessors *accessors; + }; + struct instr_loadScopeObjectQObjectPropertyDirectly { + MOTH_INSTR_HEADER + Param base; + Param result; + QQmlAccessors *accessors; + }; + struct instr_loadScopeObjectIntPropertyDirectly { + MOTH_INSTR_HEADER + Param base; + Param result; + QQmlAccessors *accessors; + }; + struct instr_loadScopeObjectBoolPropertyDirectly { + MOTH_INSTR_HEADER + Param base; + Param result; + QQmlAccessors *accessors; + }; + struct instr_loadScopeObjectQStringPropertyDirectly { + MOTH_INSTR_HEADER + Param base; + Param result; + QQmlAccessors *accessors; + }; struct instr_loadContextObjectProperty { MOTH_INSTR_HEADER int propertyIndex; @@ -342,6 +382,46 @@ union Instr Param result; bool captureRequired; }; + struct instr_loadQRealQObjectPropertyDirectly { + MOTH_INSTR_HEADER + Param base; + Param result; + QQmlAccessors *accessors; + int coreIndex; + int notifyIndex; + }; + struct instr_loadQObjectQObjectPropertyDirectly { + MOTH_INSTR_HEADER + Param base; + Param result; + QQmlAccessors *accessors; + int coreIndex; + int notifyIndex; + }; + struct instr_loadIntQObjectPropertyDirectly { + MOTH_INSTR_HEADER + Param base; + Param result; + QQmlAccessors *accessors; + int coreIndex; + int notifyIndex; + }; + struct instr_loadBoolQObjectPropertyDirectly { + MOTH_INSTR_HEADER + Param base; + Param result; + QQmlAccessors *accessors; + int coreIndex; + int notifyIndex; + }; + struct instr_loadQStringQObjectPropertyDirectly { + MOTH_INSTR_HEADER + Param base; + Param result; + QQmlAccessors *accessors; + int coreIndex; + int notifyIndex; + }; struct instr_loadAttachedQObjectProperty { MOTH_INSTR_HEADER int propertyIndex; @@ -800,9 +880,19 @@ union Instr instr_loadProperty loadProperty; instr_getLookup getLookup; instr_loadScopeObjectProperty loadScopeObjectProperty; + instr_loadScopeObjectQRealPropertyDirectly loadScopeObjectQRealPropertyDirectly; + instr_loadScopeObjectQObjectPropertyDirectly loadScopeObjectQObjectPropertyDirectly; + instr_loadScopeObjectIntPropertyDirectly loadScopeObjectIntPropertyDirectly; + instr_loadScopeObjectBoolPropertyDirectly loadScopeObjectBoolPropertyDirectly; + instr_loadScopeObjectQStringPropertyDirectly loadScopeObjectQStringPropertyDirectly; instr_loadContextObjectProperty loadContextObjectProperty; instr_loadIdObject loadIdObject; instr_loadQObjectProperty loadQObjectProperty; + instr_loadQRealQObjectPropertyDirectly loadQRealQObjectPropertyDirectly; + instr_loadQObjectQObjectPropertyDirectly loadQObjectQObjectPropertyDirectly; + instr_loadIntQObjectPropertyDirectly loadIntQObjectPropertyDirectly; + instr_loadBoolQObjectPropertyDirectly loadBoolQObjectPropertyDirectly; + instr_loadQStringQObjectPropertyDirectly loadQStringQObjectPropertyDirectly; instr_loadAttachedQObjectProperty loadAttachedQObjectProperty; instr_storeProperty storeProperty; instr_setLookup setLookup; diff --git a/src/qml/compiler/qv4isel_moth.cpp b/src/qml/compiler/qv4isel_moth.cpp index edd8425678..b452c4b3d9 100644 --- a/src/qml/compiler/qv4isel_moth.cpp +++ b/src/qml/compiler/qv4isel_moth.cpp @@ -46,6 +46,8 @@ #include #include #include +#include "qml/qqmlaccessors_p.h" +#include "qml/qqmlpropertycache_p.h" #undef USE_TYPE_INFO @@ -737,8 +739,51 @@ void InstructionSelection::setQObjectProperty(IR::Expr *source, IR::Expr *target addInstruction(store); } -void InstructionSelection::getQmlContextProperty(IR::Expr *source, IR::Member::MemberKind kind, int index, IR::Expr *target) +void InstructionSelection::getQmlContextProperty(IR::Expr *source, IR::Member::MemberKind kind, + QQmlPropertyData *property, int index, + IR::Expr *target) { + if (property && property->hasAccessors() && property->isFullyResolved()) { + if (kind == IR::Member::MemberOfQmlScopeObject) { + if (property->propType == QMetaType::QReal) { + Instruction::LoadScopeObjectQRealPropertyDirectly load; + load.base = getParam(source); + load.accessors = property->accessors; + load.result = getResultParam(target); + addInstruction(load); + return; + } else if (property->isQObject()) { + Instruction::LoadScopeObjectQObjectPropertyDirectly load; + load.base = getParam(source); + load.accessors = property->accessors; + load.result = getResultParam(target); + addInstruction(load); + return; + } else if (property->propType == QMetaType::Int) { + Instruction::LoadScopeObjectIntPropertyDirectly load; + load.base = getParam(source); + load.accessors = property->accessors; + load.result = getResultParam(target); + addInstruction(load); + return; + } else if (property->propType == QMetaType::Bool) { + Instruction::LoadScopeObjectBoolPropertyDirectly load; + load.base = getParam(source); + load.accessors = property->accessors; + load.result = getResultParam(target); + addInstruction(load); + return; + } else if (property->propType == QMetaType::QString) { + Instruction::LoadScopeObjectQStringPropertyDirectly load; + load.base = getParam(source); + load.accessors = property->accessors; + load.result = getResultParam(target); + addInstruction(load); + return; + } + } + } + if (kind == IR::Member::MemberOfQmlScopeObject) { Instruction::LoadScopeObjectProperty load; load.base = getParam(source); @@ -762,8 +807,59 @@ void InstructionSelection::getQmlContextProperty(IR::Expr *source, IR::Member::M } } -void InstructionSelection::getQObjectProperty(IR::Expr *base, int propertyIndex, bool captureRequired, bool isSingletonProperty, int attachedPropertiesId, IR::Expr *target) +void InstructionSelection::getQObjectProperty(IR::Expr *base, QQmlPropertyData *property, bool captureRequired, bool isSingletonProperty, int attachedPropertiesId, IR::Expr *target) { + if (property && property->hasAccessors() && property->isFullyResolved()) { + if (!attachedPropertiesId && !isSingletonProperty) { + if (property->propType == QMetaType::QReal) { + Instruction::LoadQRealQObjectPropertyDirectly load; + load.base = getParam(base); + load.accessors = property->accessors; + load.coreIndex = property->coreIndex; + load.notifyIndex = captureRequired ? property->notifyIndex : -1; + load.result = getResultParam(target); + addInstruction(load); + return; + } else if (property->isQObject()) { + Instruction::LoadQObjectQObjectPropertyDirectly load; + load.base = getParam(base); + load.accessors = property->accessors; + load.coreIndex = property->coreIndex; + load.notifyIndex = captureRequired ? property->notifyIndex : -1; + load.result = getResultParam(target); + addInstruction(load); + return; + } else if (property->propType == QMetaType::Int) { + Instruction::LoadIntQObjectPropertyDirectly load; + load.base = getParam(base); + load.accessors = property->accessors; + load.coreIndex = property->coreIndex; + load.notifyIndex = captureRequired ? property->notifyIndex : -1; + load.result = getResultParam(target); + addInstruction(load); + return; + } else if (property->propType == QMetaType::Bool) { + Instruction::LoadBoolQObjectPropertyDirectly load; + load.base = getParam(base); + load.accessors = property->accessors; + load.coreIndex = property->coreIndex; + load.notifyIndex = captureRequired ? property->notifyIndex : -1; + load.result = getResultParam(target); + addInstruction(load); + return; + } else if (property->propType == QMetaType::QString) { + Instruction::LoadQStringQObjectPropertyDirectly load; + load.base = getParam(base); + load.accessors = property->accessors; + load.coreIndex = property->coreIndex; + load.notifyIndex = captureRequired ? property->notifyIndex : -1; + load.result = getResultParam(target); + addInstruction(load); + return; + } + } + } + const int propertyIndex = property->coreIndex; if (attachedPropertiesId != 0) { Instruction::LoadAttachedQObjectProperty load; load.propertyIndex = propertyIndex; diff --git a/src/qml/compiler/qv4isel_moth_p.h b/src/qml/compiler/qv4isel_moth_p.h index 29d117af38..bf3909682d 100644 --- a/src/qml/compiler/qv4isel_moth_p.h +++ b/src/qml/compiler/qv4isel_moth_p.h @@ -134,8 +134,8 @@ protected: virtual void setProperty(IR::Expr *source, IR::Expr *targetBase, const QString &targetName); virtual void setQmlContextProperty(IR::Expr *source, IR::Expr *targetBase, IR::Member::MemberKind kind, int propertyIndex); virtual void setQObjectProperty(IR::Expr *source, IR::Expr *targetBase, int propertyIndex); - virtual void getQmlContextProperty(IR::Expr *source, IR::Member::MemberKind kind, int index, IR::Expr *target); - virtual void getQObjectProperty(IR::Expr *base, int propertyIndex, bool captureRequired, bool isSingleton, int attachedPropertiesId, IR::Expr *target); + virtual void getQmlContextProperty(IR::Expr *source, IR::Member::MemberKind kind, QQmlPropertyData *property, int index, IR::Expr *target); + virtual void getQObjectProperty(IR::Expr *base, QQmlPropertyData *property, bool captureRequired, bool isSingleton, int attachedPropertiesId, IR::Expr *target); virtual void getElement(IR::Expr *base, IR::Expr *index, IR::Expr *target); virtual void setElement(IR::Expr *source, IR::Expr *targetBase, IR::Expr *targetIndex); virtual void copyValue(IR::Expr *source, IR::Expr *target); diff --git a/src/qml/compiler/qv4isel_p.cpp b/src/qml/compiler/qv4isel_p.cpp index 0ae08160ab..6ba23a0951 100644 --- a/src/qml/compiler/qv4isel_p.cpp +++ b/src/qml/compiler/qv4isel_p.cpp @@ -156,14 +156,15 @@ void IRDecoder::visitMove(IR::Move *s) } } if (m->kind == IR::Member::MemberOfQmlScopeObject || m->kind == IR::Member::MemberOfQmlContextObject) { - getQmlContextProperty(m->base, (IR::Member::MemberKind)m->kind, m->property->coreIndex, s->target); + getQmlContextProperty(m->base, (IR::Member::MemberKind)m->kind, m->property, + m->property->coreIndex, s->target); return; } - getQObjectProperty(m->base, m->property->coreIndex, captureRequired, isSingletonProperty, attachedPropertiesId, s->target); + getQObjectProperty(m->base, m->property, captureRequired, isSingletonProperty, attachedPropertiesId, s->target); #endif // V4_BOOTSTRAP return; } else if (m->kind == IR::Member::MemberOfIdObjectsArray) { - getQmlContextProperty(m->base, (IR::Member::MemberKind)m->kind, m->idIndex, s->target); + getQmlContextProperty(m->base, (IR::Member::MemberKind)m->kind, nullptr, m->idIndex, s->target); return; } else if (m->base->asTemp() || m->base->asConst() || m->base->asArgLocal()) { getProperty(m->base, *m->name, s->target); diff --git a/src/qml/compiler/qv4isel_p.h b/src/qml/compiler/qv4isel_p.h index 88d2071c52..2ee776adf4 100644 --- a/src/qml/compiler/qv4isel_p.h +++ b/src/qml/compiler/qv4isel_p.h @@ -61,6 +61,7 @@ QT_BEGIN_NAMESPACE +class QQmlAccessors; class QQmlEnginePrivate; namespace QV4 { @@ -165,8 +166,8 @@ public: // to implement by subclasses: virtual void setActivationProperty(IR::Expr *source, const QString &targetName) = 0; virtual void initClosure(IR::Closure *closure, IR::Expr *target) = 0; virtual void getProperty(IR::Expr *base, const QString &name, IR::Expr *target) = 0; - virtual void getQObjectProperty(IR::Expr *base, int propertyIndex, bool captureRequired, bool isSingletonProperty, int attachedPropertiesId, IR::Expr *target) = 0; - virtual void getQmlContextProperty(IR::Expr *source, IR::Member::MemberKind kind, int index, IR::Expr *target) = 0; + virtual void getQObjectProperty(IR::Expr *base, QQmlPropertyData *property, bool captureRequired, bool isSingletonProperty, int attachedPropertiesId, IR::Expr *target) = 0; + virtual void getQmlContextProperty(IR::Expr *source, IR::Member::MemberKind kind, QQmlPropertyData *property, int index, IR::Expr *target) = 0; virtual void setProperty(IR::Expr *source, IR::Expr *targetBase, const QString &targetName) = 0; virtual void setQmlContextProperty(IR::Expr *source, IR::Expr *targetBase, IR::Member::MemberKind kind, int propertyIndex) = 0; virtual void setQObjectProperty(IR::Expr *source, IR::Expr *targetBase, int propertyIndex) = 0; diff --git a/src/qml/compiler/qv4jsir.cpp b/src/qml/compiler/qv4jsir.cpp index b28db59190..370dfd0fae 100644 --- a/src/qml/compiler/qv4jsir.cpp +++ b/src/qml/compiler/qv4jsir.cpp @@ -927,12 +927,16 @@ void IRPrinter::visitMember(Member *e) e->base->accept(this); *out << '.' << *e->name; #ifndef V4_BOOTSTRAP - if (e->property) + if (e->property) { *out << " (meta-property " << e->property->coreIndex - << " <" << QMetaType::typeName(e->property->propType) - << ">)"; - else if (e->kind == Member::MemberOfIdObjectsArray) + << " <" << QMetaType::typeName(e->property->propType) << ">"; + if (e->property->hasAccessors() && e->property->isFullyResolved()) { + *out << ", accessible"; + } + *out << ")"; + } else if (e->kind == Member::MemberOfIdObjectsArray) { *out << "(id object " << e->idIndex << ")"; + } #endif } diff --git a/src/qml/jit/qv4isel_masm.cpp b/src/qml/jit/qv4isel_masm.cpp index 149037939b..1f5a247a17 100644 --- a/src/qml/jit/qv4isel_masm.cpp +++ b/src/qml/jit/qv4isel_masm.cpp @@ -49,6 +49,7 @@ #include "qv4assembler_p.h" #include "qv4unop_p.h" #include "qv4binop_p.h" +#include #include #include @@ -753,8 +754,39 @@ void InstructionSelection::getProperty(IR::Expr *base, const QString &name, IR:: } } -void InstructionSelection::getQmlContextProperty(IR::Expr *base, IR::Member::MemberKind kind, int index, IR::Expr *target) +void InstructionSelection::getQmlContextProperty(IR::Expr *base, IR::Member::MemberKind kind, QQmlPropertyData *property, int index, IR::Expr *target) { + if (property && property->hasAccessors() && property->isFullyResolved()) { + if (kind == IR::Member::MemberOfQmlScopeObject) { + if (property->propType == QMetaType::QReal) { + generateRuntimeCall(target, accessQmlScopeObjectQRealProperty, + Assembler::PointerToValue(base), + Assembler::TrustedImmPtr(property->accessors)); + return; + } else if (property->isQObject()) { + generateRuntimeCall(target, accessQmlScopeObjectQObjectProperty, + Assembler::PointerToValue(base), + Assembler::TrustedImmPtr(property->accessors)); + return; + } else if (property->propType == QMetaType::Int) { + generateRuntimeCall(target, accessQmlScopeObjectIntProperty, + Assembler::PointerToValue(base), + Assembler::TrustedImmPtr(property->accessors)); + return; + } else if (property->propType == QMetaType::Bool) { + generateRuntimeCall(target, accessQmlScopeObjectBoolProperty, + Assembler::PointerToValue(base), + Assembler::TrustedImmPtr(property->accessors)); + return; + } else if (property->propType == QMetaType::QString) { + generateRuntimeCall(target, accessQmlScopeObjectQStringProperty, + Assembler::PointerToValue(base), + Assembler::TrustedImmPtr(property->accessors)); + return; + } + } + } + if (kind == IR::Member::MemberOfQmlScopeObject) generateRuntimeCall(target, getQmlScopeObjectProperty, Assembler::EngineRegister, Assembler::PointerToValue(base), Assembler::TrustedImm32(index)); else if (kind == IR::Member::MemberOfQmlContextObject) @@ -765,8 +797,51 @@ void InstructionSelection::getQmlContextProperty(IR::Expr *base, IR::Member::Mem Q_ASSERT(false); } -void InstructionSelection::getQObjectProperty(IR::Expr *base, int propertyIndex, bool captureRequired, bool isSingleton, int attachedPropertiesId, IR::Expr *target) +void InstructionSelection::getQObjectProperty(IR::Expr *base, QQmlPropertyData *property, bool captureRequired, bool isSingleton, int attachedPropertiesId, IR::Expr *target) { + if (property && property->hasAccessors() && property->isFullyResolved()) { + if (!attachedPropertiesId && !isSingleton) { + const int notifyIndex = captureRequired ? property->notifyIndex : -1; + if (property->propType == QMetaType::QReal) { + generateRuntimeCall(target, accessQObjectQRealProperty, + Assembler::EngineRegister, Assembler::PointerToValue(base), + Assembler::TrustedImmPtr(property->accessors), + Assembler::TrustedImm32(property->coreIndex), + Assembler::TrustedImm32(notifyIndex)); + return; + } else if (property->isQObject()) { + generateRuntimeCall(target, accessQObjectQObjectProperty, + Assembler::EngineRegister, Assembler::PointerToValue(base), + Assembler::TrustedImmPtr(property->accessors), + Assembler::TrustedImm32(property->coreIndex), + Assembler::TrustedImm32(notifyIndex)); + return; + } else if (property->propType == QMetaType::Int) { + generateRuntimeCall(target, accessQObjectIntProperty, + Assembler::EngineRegister, Assembler::PointerToValue(base), + Assembler::TrustedImmPtr(property->accessors), + Assembler::TrustedImm32(property->coreIndex), + Assembler::TrustedImm32(notifyIndex)); + return; + } else if (property->propType == QMetaType::Bool) { + generateRuntimeCall(target, accessQObjectBoolProperty, + Assembler::EngineRegister, Assembler::PointerToValue(base), + Assembler::TrustedImmPtr(property->accessors), + Assembler::TrustedImm32(property->coreIndex), + Assembler::TrustedImm32(notifyIndex)); + return; + } else if (property->propType == QMetaType::QString) { + generateRuntimeCall(target, accessQObjectQStringProperty, + Assembler::EngineRegister, Assembler::PointerToValue(base), + Assembler::TrustedImmPtr(property->accessors), + Assembler::TrustedImm32(property->coreIndex), + Assembler::TrustedImm32(notifyIndex)); + return; + } + } + } + + const int propertyIndex = property->coreIndex; if (attachedPropertiesId != 0) generateRuntimeCall(target, getQmlAttachedProperty, Assembler::EngineRegister, Assembler::TrustedImm32(attachedPropertiesId), Assembler::TrustedImm32(propertyIndex)); else if (isSingleton) diff --git a/src/qml/jit/qv4isel_masm_p.h b/src/qml/jit/qv4isel_masm_p.h index a92196f5f7..db9d440e83 100644 --- a/src/qml/jit/qv4isel_masm_p.h +++ b/src/qml/jit/qv4isel_masm_p.h @@ -124,8 +124,8 @@ protected: virtual void setActivationProperty(IR::Expr *source, const QString &targetName); virtual void initClosure(IR::Closure *closure, IR::Expr *target); virtual void getProperty(IR::Expr *base, const QString &name, IR::Expr *target); - virtual void getQmlContextProperty(IR::Expr *source, IR::Member::MemberKind kind, int index, IR::Expr *target); - virtual void getQObjectProperty(IR::Expr *base, int propertyIndex, bool captureRequired, bool isSingleton, int attachedPropertiesId, IR::Expr *target); + virtual void getQmlContextProperty(IR::Expr *source, IR::Member::MemberKind kind, QQmlPropertyData *property, int index, IR::Expr *target); + virtual void getQObjectProperty(IR::Expr *base, QQmlPropertyData *property, bool captureRequired, bool isSingleton, int attachedPropertiesId, IR::Expr *target); virtual void setProperty(IR::Expr *source, IR::Expr *targetBase, const QString &targetName); virtual void setQmlContextProperty(IR::Expr *source, IR::Expr *targetBase, IR::Member::MemberKind kind, int propertyIndex); virtual void setQObjectProperty(IR::Expr *source, IR::Expr *targetBase, int propertyIndex); diff --git a/src/qml/jit/qv4regalloc.cpp b/src/qml/jit/qv4regalloc.cpp index 131e0a5b0a..6b5b79e458 100644 --- a/src/qml/jit/qv4regalloc.cpp +++ b/src/qml/jit/qv4regalloc.cpp @@ -528,14 +528,14 @@ protected: // IRDecoder addCall(); } - virtual void getQmlContextProperty(IR::Expr *base, IR::Member::MemberKind /*kind*/, int /*index*/, IR::Expr *target) + virtual void getQmlContextProperty(IR::Expr *base, IR::Member::MemberKind /*kind*/, QQmlPropertyData * /*property*/, int /*index*/, IR::Expr *target) { addDef(target); addUses(base->asTemp(), Use::CouldHaveRegister); addCall(); } - virtual void getQObjectProperty(IR::Expr *base, int /*propertyIndex*/, bool /*captureRequired*/, bool /*isSingleton*/, int /*attachedPropertiesId*/, IR::Expr *target) + virtual void getQObjectProperty(IR::Expr *base, QQmlPropertyData * /*property*/, bool /*captureRequired*/, bool /*isSingleton*/, int /*attachedPropertiesId*/, IR::Expr *target) { addDef(target); addUses(base->asTemp(), Use::CouldHaveRegister); diff --git a/src/qml/jsruntime/qv4qobjectwrapper_p.h b/src/qml/jsruntime/qv4qobjectwrapper_p.h index f527afbcc7..0186a8381a 100644 --- a/src/qml/jsruntime/qv4qobjectwrapper_p.h +++ b/src/qml/jsruntime/qv4qobjectwrapper_p.h @@ -59,6 +59,7 @@ #include #include #include +#include #include #include diff --git a/src/qml/jsruntime/qv4runtime.cpp b/src/qml/jsruntime/qv4runtime.cpp index 2abe6eeb06..a974909798 100644 --- a/src/qml/jsruntime/qv4runtime.cpp +++ b/src/qml/jsruntime/qv4runtime.cpp @@ -1415,6 +1415,116 @@ ReturnedValue Runtime::method_getQmlQObjectProperty(ExecutionEngine *engine, con return QV4::QObjectWrapper::getProperty(scope.engine, wrapper->object(), propertyIndex, captureRequired); } +template +static inline PropertyType getQObjectProperty(QObject *object, ExecutionEngine *engine, QQmlAccessors *accessors, int coreIndex, int notifyIndex) +{ + PropertyType t; + accessors->read(object, &t); + if (notifyIndex != -1) { + QQmlEnginePrivate *ep = engine->qmlEngine() ? QQmlEnginePrivate::get(engine->qmlEngine()) : 0; + if (ep && ep->propertyCapture) { + if (accessors->notifier) { + QQmlNotifier *n = nullptr; + accessors->notifier(object, &n); + if (n) { + ep->propertyCapture->captureProperty(n); + } + } else { + ep->propertyCapture->captureProperty(object, coreIndex, notifyIndex); + } + } + } + + return t; +} + +ReturnedValue Runtime::method_accessQObjectQRealProperty(ExecutionEngine *engine, + const Value &object, + QQmlAccessors *accessors, int coreIndex, + int notifyIndex) +{ + auto casted = object.as(); + QObject *o = casted ? casted->object() : nullptr; + if (Q_LIKELY(o)) { + return QV4::Encode(getQObjectProperty(o, engine, accessors, coreIndex, notifyIndex)); + } + engine->throwTypeError(QStringLiteral("Cannot read property of null")); + return Encode::undefined(); +} + +ReturnedValue Runtime::method_accessQObjectQObjectProperty(ExecutionEngine *engine, + const Value &object, + QQmlAccessors *accessors, int coreIndex, + int notifyIndex) +{ + auto casted = object.as(); + QObject *o = casted ? casted->object() : nullptr; + if (Q_LIKELY(o)) { + return QV4::QObjectWrapper::wrap(engine, getQObjectProperty(o, engine, accessors, + coreIndex, + notifyIndex)); + } + + engine->throwTypeError(QStringLiteral("Cannot read property of null")); + return Encode::undefined(); +} + +ReturnedValue Runtime::method_accessQObjectIntProperty(ExecutionEngine *engine, const Value &object, + QQmlAccessors *accessors, int coreIndex, + int notifyIndex) +{ + auto casted = object.as(); + QObject *o = casted ? casted->object() : nullptr; + if (Q_LIKELY(o)) { + return QV4::Encode(getQObjectProperty(o, engine, accessors, coreIndex, notifyIndex)); + } + engine->throwTypeError(QStringLiteral("Cannot read property of null")); + return Encode::undefined(); +} + +ReturnedValue Runtime::method_accessQObjectBoolProperty(ExecutionEngine *engine, const Value &object, + QQmlAccessors *accessors, int coreIndex, + int notifyIndex) +{ + auto casted = object.as(); + QObject *o = casted ? casted->object() : nullptr; + if (Q_LIKELY(o)) { + return QV4::Encode(getQObjectProperty(o, engine, accessors, coreIndex, notifyIndex)); + } + engine->throwTypeError(QStringLiteral("Cannot read property of null")); + return Encode::undefined(); +} + +ReturnedValue Runtime::method_accessQObjectQStringProperty(ExecutionEngine *engine, + const Value &object, + QQmlAccessors *accessors, int coreIndex, + int notifyIndex) +{ + auto casted = object.as(); + QObject *o = casted ? casted->object() : nullptr; + if (Q_LIKELY(o)) { + return QV4::Encode(engine->newString(getQObjectProperty(o, engine, accessors, + coreIndex, notifyIndex))); + } + engine->throwTypeError(QStringLiteral("Cannot read property of null")); + return Encode::undefined(); +} + +ReturnedValue Runtime::method_accessQmlScopeObjectQObjectProperty(const Value &context, + QQmlAccessors *accessors) +{ +#ifndef V4_BOOTSTRAP + const QmlContext &c = static_cast(context); + QObject *rv = 0; + accessors->read(c.d()->qml->scopeObject, &rv); + return QV4::QObjectWrapper::wrap(c.engine(), rv); +#else + Q_UNUSED(context); + Q_UNUSED(accessors); + return QV4::Encode::undefined(); +#endif +} + QV4::ReturnedValue Runtime::method_getQmlAttachedProperty(ExecutionEngine *engine, int attachedPropertiesId, int propertyIndex) { QObject *scopeObject = engine->qmlScopeObject(); diff --git a/src/qml/jsruntime/qv4runtime_p.h b/src/qml/jsruntime/qv4runtime_p.h index d9b46606c9..ffae55995f 100644 --- a/src/qml/jsruntime/qv4runtime_p.h +++ b/src/qml/jsruntime/qv4runtime_p.h @@ -56,8 +56,12 @@ #include "qv4engine_p.h" #include "qv4math_p.h" #include "qv4runtimeapi_p.h" -#include +#ifndef V4_BOOTSTRAP +#include +#include +#endif +#include QT_BEGIN_NAMESPACE @@ -417,6 +421,68 @@ inline Bool Runtime::method_toBoolean(const Value &value) return value.toBoolean(); } +inline ReturnedValue Runtime::method_accessQmlScopeObjectQRealProperty(const Value &context, + QQmlAccessors *accessors) +{ +#ifndef V4_BOOTSTRAP + const QmlContext &c = static_cast(context); + qreal rv = 0; + accessors->read(c.d()->qml->scopeObject, &rv); + return QV4::Encode(rv); +#else + Q_UNUSED(context); + Q_UNUSED(accessors); + return QV4::Encode::undefined(); +#endif +} + +inline ReturnedValue Runtime::method_accessQmlScopeObjectIntProperty(const Value &context, + QQmlAccessors *accessors) +{ +#ifndef V4_BOOTSTRAP + const QmlContext &c = static_cast(context); + int rv = 0; + accessors->read(c.d()->qml->scopeObject, &rv); + return QV4::Encode(rv); +#else + Q_UNUSED(context); + Q_UNUSED(accessors); + return QV4::Encode::undefined(); +#endif +} + +inline ReturnedValue Runtime::method_accessQmlScopeObjectBoolProperty(const Value &context, + QQmlAccessors *accessors) +{ +#ifndef V4_BOOTSTRAP + const QmlContext &c = static_cast(context); + bool rv = false; + accessors->read(c.d()->qml->scopeObject, &rv); + return QV4::Encode(rv); +#else + Q_UNUSED(context); + Q_UNUSED(accessors); + return QV4::Encode::undefined(); +#endif +} + +inline ReturnedValue Runtime::method_accessQmlScopeObjectQStringProperty(ExecutionEngine *engine, + const Value &context, + QQmlAccessors *accessors) +{ +#ifndef V4_BOOTSTRAP + const QmlContext &c = static_cast(context); + QString rv; + accessors->read(c.d()->qml->scopeObject, &rv); + return QV4::Encode(engine->newString(rv)); +#else + Q_UNUSED(engine); + Q_UNUSED(context); + Q_UNUSED(accessors); + return QV4::Encode::undefined(); +#endif +} + } // namespace QV4 QT_END_NAMESPACE diff --git a/src/qml/jsruntime/qv4runtimeapi_p.h b/src/qml/jsruntime/qv4runtimeapi_p.h index 9eb6a124b4..bf153223a0 100644 --- a/src/qml/jsruntime/qv4runtimeapi_p.h +++ b/src/qml/jsruntime/qv4runtimeapi_p.h @@ -156,6 +156,16 @@ struct Q_QML_PRIVATE_EXPORT Runtime { , INIT_RUNTIME_METHOD(setQmlScopeObjectProperty) , INIT_RUNTIME_METHOD(setQmlContextObjectProperty) , INIT_RUNTIME_METHOD(setQmlQObjectProperty) + , INIT_RUNTIME_METHOD(accessQObjectQRealProperty) + , INIT_RUNTIME_METHOD(accessQObjectQObjectProperty) + , INIT_RUNTIME_METHOD(accessQObjectIntProperty) + , INIT_RUNTIME_METHOD(accessQObjectBoolProperty) + , INIT_RUNTIME_METHOD(accessQObjectQStringProperty) + , INIT_RUNTIME_METHOD(accessQmlScopeObjectQRealProperty) + , INIT_RUNTIME_METHOD(accessQmlScopeObjectQObjectProperty) + , INIT_RUNTIME_METHOD(accessQmlScopeObjectIntProperty) + , INIT_RUNTIME_METHOD(accessQmlScopeObjectBoolProperty) + , INIT_RUNTIME_METHOD(accessQmlScopeObjectQStringProperty) { } // call @@ -292,6 +302,17 @@ struct Q_QML_PRIVATE_EXPORT Runtime { RUNTIME_METHOD(void, setQmlScopeObjectProperty, (ExecutionEngine *engine, const Value &context, int propertyIndex, const Value &value)); RUNTIME_METHOD(void, setQmlContextObjectProperty, (ExecutionEngine *engine, const Value &context, int propertyIndex, const Value &value)); RUNTIME_METHOD(void, setQmlQObjectProperty, (ExecutionEngine *engine, const Value &object, int propertyIndex, const Value &value)); + + RUNTIME_METHOD(ReturnedValue, accessQObjectQRealProperty, (ExecutionEngine *engine, const Value &object, QQmlAccessors *accessors, int coreIndex, int notifyIndex)); + RUNTIME_METHOD(ReturnedValue, accessQObjectQObjectProperty, (ExecutionEngine *engine, const Value &object, QQmlAccessors *accessors, int coreIndex, int notifyIndex)); + RUNTIME_METHOD(ReturnedValue, accessQObjectIntProperty, (ExecutionEngine *engine, const Value &object, QQmlAccessors *accessors, int coreIndex, int notifyIndex)); + RUNTIME_METHOD(ReturnedValue, accessQObjectBoolProperty, (ExecutionEngine *engine, const Value &object, QQmlAccessors *accessors, int coreIndex, int notifyIndex)); + RUNTIME_METHOD(ReturnedValue, accessQObjectQStringProperty, (ExecutionEngine *engine, const Value &object, QQmlAccessors *accessors, int coreIndex, int notifyIndex)); + RUNTIME_METHOD(ReturnedValue, accessQmlScopeObjectQRealProperty, (const Value &context, QQmlAccessors *accessors)); + RUNTIME_METHOD(ReturnedValue, accessQmlScopeObjectQObjectProperty, (const Value &context, QQmlAccessors *accessors)); + RUNTIME_METHOD(ReturnedValue, accessQmlScopeObjectIntProperty, (const Value &context, QQmlAccessors *accessors)); + RUNTIME_METHOD(ReturnedValue, accessQmlScopeObjectBoolProperty, (const Value &context, QQmlAccessors *accessors)); + RUNTIME_METHOD(ReturnedValue, accessQmlScopeObjectQStringProperty, (ExecutionEngine *engine, const Value &context, QQmlAccessors *accessors)); }; #undef RUNTIME_METHOD diff --git a/src/qml/jsruntime/qv4vme_moth.cpp b/src/qml/jsruntime/qv4vme_moth.cpp index ec4509a5cc..9ad21305f7 100644 --- a/src/qml/jsruntime/qv4vme_moth.cpp +++ b/src/qml/jsruntime/qv4vme_moth.cpp @@ -519,6 +519,26 @@ QV4::ReturnedValue VME::run(ExecutionEngine *engine, const uchar *code STOREVALUE(instr.result, engine->runtime.getQmlQObjectProperty(engine, VALUE(instr.base), instr.propertyIndex, instr.captureRequired)); MOTH_END_INSTR(LoadQObjectProperty) + MOTH_BEGIN_INSTR(LoadQRealQObjectPropertyDirectly) + STOREVALUE(instr.result, engine->runtime.accessQObjectQRealProperty(engine, VALUE(instr.base), instr.accessors, instr.coreIndex, instr.notifyIndex)); + MOTH_END_INSTR(LoadQRealQObjectPropertyDirectly) + + MOTH_BEGIN_INSTR(LoadQObjectQObjectPropertyDirectly) + STOREVALUE(instr.result, engine->runtime.accessQObjectQObjectProperty(engine, VALUE(instr.base), instr.accessors, instr.coreIndex, instr.notifyIndex)); + MOTH_END_INSTR(LoadQObjectQObjectPropertyDirectly) + + MOTH_BEGIN_INSTR(LoadIntQObjectPropertyDirectly) + STOREVALUE(instr.result, engine->runtime.accessQObjectIntProperty(engine, VALUE(instr.base), instr.accessors, instr.coreIndex, instr.notifyIndex)); + MOTH_END_INSTR(LoadIntQObjectPropertyDirectly) + + MOTH_BEGIN_INSTR(LoadBoolQObjectPropertyDirectly) + STOREVALUE(instr.result, engine->runtime.accessQObjectBoolProperty(engine, VALUE(instr.base), instr.accessors, instr.coreIndex, instr.notifyIndex)); + MOTH_END_INSTR(LoadQRealQObjectPropertyDirectly) + + MOTH_BEGIN_INSTR(LoadQStringQObjectPropertyDirectly) + STOREVALUE(instr.result, engine->runtime.accessQObjectQStringProperty(engine, VALUE(instr.base), instr.accessors, instr.coreIndex, instr.notifyIndex)); + MOTH_END_INSTR(LoadQStringQObjectPropertyDirectly) + MOTH_BEGIN_INSTR(StoreScopeObjectProperty) engine->runtime.setQmlScopeObjectProperty(engine, VALUE(instr.base), instr.propertyIndex, VALUE(instr.source)); CHECK_EXCEPTION; @@ -528,6 +548,26 @@ QV4::ReturnedValue VME::run(ExecutionEngine *engine, const uchar *code STOREVALUE(instr.result, engine->runtime.getQmlScopeObjectProperty(engine, VALUE(instr.base), instr.propertyIndex)); MOTH_END_INSTR(LoadScopeObjectProperty) + MOTH_BEGIN_INSTR(LoadScopeObjectQRealPropertyDirectly) + STOREVALUE(instr.result, engine->runtime.accessQmlScopeObjectQRealProperty(VALUE(instr.base), instr.accessors)); + MOTH_END_INSTR(LoadScopeObjectQRealPropertyDirectly) + + MOTH_BEGIN_INSTR(LoadScopeObjectQObjectPropertyDirectly) + STOREVALUE(instr.result, engine->runtime.accessQmlScopeObjectQObjectProperty(VALUE(instr.base), instr.accessors)); + MOTH_END_INSTR(LoadScopeObjectQObjectPropertyDirectly) + + MOTH_BEGIN_INSTR(LoadScopeObjectIntPropertyDirectly) + STOREVALUE(instr.result, engine->runtime.accessQmlScopeObjectIntProperty(VALUE(instr.base), instr.accessors)); + MOTH_END_INSTR(LoadScopeObjectIntPropertyDirectly) + + MOTH_BEGIN_INSTR(LoadScopeObjectBoolPropertyDirectly) + STOREVALUE(instr.result, engine->runtime.accessQmlScopeObjectBoolProperty(VALUE(instr.base), instr.accessors)); + MOTH_END_INSTR(LoadScopeObjectBoolPropertyDirectly) + + MOTH_BEGIN_INSTR(LoadScopeObjectQStringPropertyDirectly) + STOREVALUE(instr.result, engine->runtime.accessQmlScopeObjectQStringProperty(engine, VALUE(instr.base), instr.accessors)); + MOTH_END_INSTR(LoadScopeObjectQStringPropertyDirectly) + MOTH_BEGIN_INSTR(StoreContextObjectProperty) engine->runtime.setQmlContextObjectProperty(engine, VALUE(instr.base), instr.propertyIndex, VALUE(instr.source)); CHECK_EXCEPTION; diff --git a/src/qml/qml/qqmlpropertycache_p.h b/src/qml/qml/qqmlpropertycache_p.h index bb39a5e371..4fb84198d9 100644 --- a/src/qml/qml/qqmlpropertycache_p.h +++ b/src/qml/qml/qqmlpropertycache_p.h @@ -162,6 +162,8 @@ public: overrideIndex >= 0; } bool hasRevision() const { return !(flags & HasAccessors) && revision != 0; } + bool isFullyResolved() const { return !(flags & NotFullyResolved); } + // Returns -1 if not a value type virtual property inline int getValueTypeCoreIndex() const; diff --git a/tests/benchmarks/qml/creation/tst_creation.cpp b/tests/benchmarks/qml/creation/tst_creation.cpp index 224732913c..2c8aa04a6a 100644 --- a/tests/benchmarks/qml/creation/tst_creation.cpp +++ b/tests/benchmarks/qml/creation/tst_creation.cpp @@ -68,6 +68,12 @@ private slots: void itemtests_qml_data(); void itemtests_qml(); + void bindings_cpp(); + void bindings_cpp2(); + void bindings_qml(); + + void bindings_parent_qml(); + private: QQmlEngine engine; }; @@ -373,6 +379,89 @@ void tst_creation::itemtests_qml() QBENCHMARK { delete component.create(); } } +void tst_creation::bindings_cpp() +{ + QQuickItem item; + QMetaProperty widthProp = item.metaObject()->property(item.metaObject()->indexOfProperty("width")); + QMetaProperty heightProp = item.metaObject()->property(item.metaObject()->indexOfProperty("height")); + connect(&item, &QQuickItem::heightChanged, [&item, &widthProp, &heightProp](){ + QVariant height = heightProp.read(&item); + widthProp.write(&item, height); + }); + + int height = 0; + QBENCHMARK { + item.setHeight(++height); + } +} + +void tst_creation::bindings_cpp2() +{ + QQuickItem item; + int widthProp = item.metaObject()->indexOfProperty("width"); + int heightProp = item.metaObject()->indexOfProperty("height"); + connect(&item, &QQuickItem::heightChanged, [&item, widthProp, heightProp](){ + + qreal height = -1; + void *args[] = { &height, 0 }; + QMetaObject::metacall(&item, QMetaObject::ReadProperty, heightProp, args); + + int flags = 0; + int status = -1; + void *argv[] = { &height, 0, &status, &flags }; + QMetaObject::metacall(&item, QMetaObject::WriteProperty, widthProp, argv); + }); + + int height = 0; + QBENCHMARK { + item.setHeight(++height); + } +} + +void tst_creation::bindings_qml() +{ + QByteArray data = "import QtQuick 2.0\nItem { width: height }"; + + QQmlComponent component(&engine); + component.setData(data, QUrl()); + if (!component.isReady()) { + qWarning() << "Unable to create component: " << component.errorString(); + return; + } + + QQuickItem *obj = dynamic_cast(component.create()); + QVERIFY(obj != nullptr); + + int height = 0; + QBENCHMARK { + obj->setHeight(++height); + } + + delete obj; +} + +void tst_creation::bindings_parent_qml() +{ + QByteArray data = "import QtQuick 2.0\nItem { Item { width: parent.height }}"; + + QQmlComponent component(&engine); + component.setData(data, QUrl()); + if (!component.isReady()) { + qWarning() << "Unable to create component: " << component.errorString(); + return; + } + + QQuickItem *obj = dynamic_cast(component.create()); + QVERIFY(obj != nullptr); + + int height = 0; + QBENCHMARK { + obj->setHeight(++height); + } + + delete obj; +} + QTEST_MAIN(tst_creation) #include "tst_creation.moc" From d146a75bf0d5307c63a8d495a691a973f6807a32 Mon Sep 17 00:00:00 2001 From: Frank Meerkoetter Date: Fri, 1 Apr 2016 20:39:28 +0200 Subject: [PATCH 02/12] Do not convert from latin1 over and over again Change-Id: I448c0f3b6e651fc57e1bbd40a5fcd59559da2915 Reviewed-by: Simon Hausmann --- src/qml/types/qqmllistmodel.cpp | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/src/qml/types/qqmllistmodel.cpp b/src/qml/types/qqmllistmodel.cpp index 60175ef310..9cbda4516e 100644 --- a/src/qml/types/qqmllistmodel.cpp +++ b/src/qml/types/qqmllistmodel.cpp @@ -79,13 +79,16 @@ static bool isMemoryUsed(const char *mem) static QString roleTypeName(ListLayout::Role::DataType t) { - QString result; - const char *roleTypeNames[] = { "String", "Number", "Bool", "List", "QObject", "VariantMap", "DateTime" }; + static const QString roleTypeNames[] = { + QStringLiteral("String"), QStringLiteral("Number"), QStringLiteral("Bool"), + QStringLiteral("List"), QStringLiteral("QObject"), QStringLiteral("VariantMap"), + QStringLiteral("DateTime") + }; if (t > ListLayout::Role::Invalid && t < ListLayout::Role::MaxDataType) - result = QString::fromLatin1(roleTypeNames[t]); + return roleTypeNames[t]; - return result; + return QString(); } const ListLayout::Role &ListLayout::getRoleOrCreate(const QString &key, Role::DataType type) From 8a546b889e14aad7202dc198bc9fe942ef7e94a6 Mon Sep 17 00:00:00 2001 From: Michael Brasser Date: Tue, 12 Apr 2016 20:15:42 -0500 Subject: [PATCH 03/12] Update DelayedFunctionCall to use an array object. Change-Id: I9ffaa95ab58eff14abaf3573f5aa0d351ac0624d Reviewed-by: Simon Hausmann --- src/qml/qml/qqmldelayedcallqueue.cpp | 20 ++++++++++++++------ src/qml/qml/qqmldelayedcallqueue_p.h | 2 +- 2 files changed, 15 insertions(+), 7 deletions(-) diff --git a/src/qml/qml/qqmldelayedcallqueue.cpp b/src/qml/qml/qqmldelayedcallqueue.cpp index 250d5f20f3..8d0fb22866 100644 --- a/src/qml/qml/qqmldelayedcallqueue.cpp +++ b/src/qml/qml/qqmldelayedcallqueue.cpp @@ -62,12 +62,13 @@ void QQmlDelayedCallQueue::DelayedFunctionCall::execute(QV4::ExecutionEngine *en QV4::Scope scope(engine); - const int argCount = m_args.count(); + QV4::ArrayObject *array = m_args.as(); + const int argCount = array ? array->getLength() : 0; QV4::ScopedCallData callData(scope, argCount); callData->thisObject = QV4::Encode::undefined(); for (int i = 0; i < argCount; i++) { - callData->args[i] = m_args[i].value(); + callData->args[i] = array->getIndexed(i); } const QV4::FunctionObject *callback = m_function.as(); @@ -175,11 +176,18 @@ QV4::ReturnedValue QQmlDelayedCallQueue::addUniquelyAndExecuteLater(QV4::CallCon void QQmlDelayedCallQueue::storeAnyArguments(DelayedFunctionCall &dfc, const QV4::CallData *callData, int offset, QV4::ExecutionEngine *engine) { - dfc.m_args.clear(); - dfc.m_args.reserve(callData->argc - offset); - for (int j = offset; j < callData->argc; j++) { - dfc.m_args.append(QV4::PersistentValue(engine, callData->args[j])); + const int length = callData->argc - offset; + if (length == 0) { + dfc.m_args.clear(); + return; } + QV4::Scope scope(engine); + QV4::ScopedArrayObject array(scope, engine->newArrayObject(length)); + int i = 0; + for (int j = offset; j < callData->argc; ++i, ++j) { + array->putIndexed(i, callData->args[j]); + } + dfc.m_args.set(engine, array); } void QQmlDelayedCallQueue::executeAllExpired_Later() diff --git a/src/qml/qml/qqmldelayedcallqueue_p.h b/src/qml/qml/qqmldelayedcallqueue_p.h index 7eb014cfdf..ef899170a2 100644 --- a/src/qml/qml/qqmldelayedcallqueue_p.h +++ b/src/qml/qml/qqmldelayedcallqueue_p.h @@ -85,7 +85,7 @@ private: void execute(QV4::ExecutionEngine *engine) const; QV4::PersistentValue m_function; - QList m_args; + QV4::PersistentValue m_args; QQmlGuard m_objectGuard; bool m_guarded; }; From 8b7418ca1cd31aaf65ed57946fa5019ed7533b5a Mon Sep 17 00:00:00 2001 From: Frank Meerkoetter Date: Sun, 17 Apr 2016 21:30:07 +0200 Subject: [PATCH 04/12] Cleanup. It is fine to call delete(0) Change-Id: Ie42891136932fca99ae6237208618a3b3c2424d1 Reviewed-by: Robin Burchell --- src/qml/qml/qqmlxmlhttprequest.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/qml/qml/qqmlxmlhttprequest.cpp b/src/qml/qml/qqmlxmlhttprequest.cpp index af94ec757c..eebaf27901 100644 --- a/src/qml/qml/qqmlxmlhttprequest.cpp +++ b/src/qml/qml/qqmlxmlhttprequest.cpp @@ -160,7 +160,7 @@ class DocumentImpl : public QQmlRefCount, public NodeImpl public: DocumentImpl() : root(0) { type = Document; } virtual ~DocumentImpl() { - if (root) delete root; + delete root; } QString version; From 91ad820fdca711d52117c4142b91b038d7df754f Mon Sep 17 00:00:00 2001 From: Friedemann Kleint Date: Fri, 15 Apr 2016 10:43:43 +0200 Subject: [PATCH 05/12] QQuickTextInput: Add some QChar::unicode() calls to brush over deprecation warning. Change-Id: Ifb6d499975cf2b7fd7c0d936cfb7daa633be5677 Reviewed-by: hjk --- src/quick/items/qquicktextinput.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/quick/items/qquicktextinput.cpp b/src/quick/items/qquicktextinput.cpp index fec9beedf6..8bf854aac2 100644 --- a/src/quick/items/qquicktextinput.cpp +++ b/src/quick/items/qquicktextinput.cpp @@ -2809,7 +2809,7 @@ void QQuickTextInputPrivate::updateDisplayText(bool forceUpdate) // characters) QChar* uc = str.data(); for (int i = 0; i < (int)str.length(); ++i) { - if ((uc[i] < 0x20 && uc[i] != 0x09) + if ((uc[i].unicode() < 0x20 && uc[i] != QChar::Tabulation) || uc[i] == QChar::LineSeparator || uc[i] == QChar::ParagraphSeparator || uc[i] == QChar::ObjectReplacementCharacter) From bdfc7ea605771192bf00ec234ed0f6149c24a084 Mon Sep 17 00:00:00 2001 From: Frank Meerkoetter Date: Sun, 17 Apr 2016 21:28:53 +0200 Subject: [PATCH 06/12] Cleanup dead fwd declaration Change-Id: I339b2234e64eaab2d2e73c1d3cb37e2d0b60fe3b Reviewed-by: Robin Burchell --- src/imports/statemachine/statemachine.h | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/imports/statemachine/statemachine.h b/src/imports/statemachine/statemachine.h index 8a05acfbde..59a810f387 100644 --- a/src/imports/statemachine/statemachine.h +++ b/src/imports/statemachine/statemachine.h @@ -48,8 +48,6 @@ QT_BEGIN_NAMESPACE -class QQmlOpenMetaObject; - class StateMachine : public QStateMachine, public QQmlParserStatus { Q_OBJECT From b69b7094d2906ca5412ce9291c347107f0b142eb Mon Sep 17 00:00:00 2001 From: Frank Meerkoetter Date: Sun, 17 Apr 2016 21:29:25 +0200 Subject: [PATCH 07/12] Replace handwritten loops with qDeleteAll Change-Id: Ifb54fbd7d4a32dc23404e78a58c421a8be9e0e9a Reviewed-by: Robin Burchell --- src/qml/qml/qqmlxmlhttprequest.cpp | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/qml/qml/qqmlxmlhttprequest.cpp b/src/qml/qml/qqmlxmlhttprequest.cpp index eebaf27901..e9644839d1 100644 --- a/src/qml/qml/qqmlxmlhttprequest.cpp +++ b/src/qml/qml/qqmlxmlhttprequest.cpp @@ -117,10 +117,8 @@ class NodeImpl public: NodeImpl() : type(Element), document(0), parent(0) {} virtual ~NodeImpl() { - for (int ii = 0; ii < children.count(); ++ii) - delete children.at(ii); - for (int ii = 0; ii < attributes.count(); ++ii) - delete attributes.at(ii); + qDeleteAll(children); + qDeleteAll(attributes); } // These numbers are copied from the Node IDL definition From 6345e6cf26ebbefb81ce8b5debb9594830848ef1 Mon Sep 17 00:00:00 2001 From: Frank Meerkoetter Date: Sat, 16 Apr 2016 20:21:35 +0200 Subject: [PATCH 08/12] Remove unused QPointerValuePair template Change-Id: I93bc5951d555f799bb956020433d3087504e8f9f Reviewed-by: Robin Burchell Reviewed-by: Simon Hausmann --- src/qml/qml/ftw/ftw.pri | 1 - src/qml/qml/ftw/qpointervaluepair_p.h | 194 ----------------------- src/qml/qml/qqmlabstractbinding_p.h | 1 - src/qml/qml/qqmlbinding_p.h | 1 - src/qml/qml/qqmlexpression_p.h | 1 - src/qml/qml/qqmljavascriptexpression_p.h | 1 - 6 files changed, 199 deletions(-) delete mode 100644 src/qml/qml/ftw/qpointervaluepair_p.h diff --git a/src/qml/qml/ftw/ftw.pri b/src/qml/qml/ftw/ftw.pri index a671cfa12d..addf1d9ff8 100644 --- a/src/qml/qml/ftw/ftw.pri +++ b/src/qml/qml/ftw/ftw.pri @@ -11,7 +11,6 @@ HEADERS += \ $$PWD/qdeletewatcher_p.h \ $$PWD/qrecyclepool_p.h \ $$PWD/qflagpointer_p.h \ - $$PWD/qpointervaluepair_p.h \ $$PWD/qlazilyallocated_p.h \ $$PWD/qqmlnullablevalue_p.h \ diff --git a/src/qml/qml/ftw/qpointervaluepair_p.h b/src/qml/qml/ftw/qpointervaluepair_p.h deleted file mode 100644 index 3d0644039f..0000000000 --- a/src/qml/qml/ftw/qpointervaluepair_p.h +++ /dev/null @@ -1,194 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the QtQml module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 3 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL3 included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 3 requirements -** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 2.0 or (at your option) the GNU General -** Public license version 3 or any later version approved by the KDE Free -** Qt Foundation. The licenses are as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-2.0.html and -** https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#ifndef QPOINTERVALUEPAIR_P_H -#define QPOINTERVALUEPAIR_P_H - -// -// W A R N I N G -// ------------- -// -// This file is not part of the Qt API. It exists purely as an -// implementation detail. This header file may change from version to -// version without notice, or even be removed. -// -// We mean it. -// - -#include -#include - -QT_BEGIN_NAMESPACE - -// QPointerValuePair is intended to help reduce the memory consumption of a class. -// In the common case, QPointerValuePair behaves like a pointer. In this mode, it -// consumes the same memory as a regular pointer. -// Additionally, QPointerValuePair can store an arbitrary value type in *addition* -// to the pointer. In this case, it uses slightly more memory than the pointer and -// value type combined. -// Consequently, this class is most useful in cases where a pointer is always stored -// and a value type is rarely stored. -template -class QPointerValuePair { -public: - inline QPointerValuePair(); - inline QPointerValuePair(P *); - inline ~QPointerValuePair(); - - inline bool isNull() const; - - inline bool flag() const; - inline void setFlag(); - inline void clearFlag(); - inline void setFlagValue(bool); - - inline QPointerValuePair &operator=(P *); - - inline P *operator->() const; - inline P *operator*() const; - - inline bool hasValue() const; - inline V &value(); - inline const V *constValue() const; - -private: - struct Value { P *pointer; V value; }; - QBiPointer d; -}; - -template -QPointerValuePair::QPointerValuePair() -{ -} - -template -QPointerValuePair::QPointerValuePair(P *p) -: d(p) -{ -} - -template -QPointerValuePair::~QPointerValuePair() -{ - if (d.isT2()) delete d.asT2(); -} - -template -bool QPointerValuePair::isNull() const -{ - if (d.isT1()) return 0 == d.asT1(); - else return d.asT2()->pointer == 0; -} - -template -bool QPointerValuePair::flag() const -{ - return d.flag(); -} - -template -void QPointerValuePair::setFlag() -{ - d.setFlag(); -} - -template -void QPointerValuePair::clearFlag() -{ - d.clearFlag(); -} - -template -void QPointerValuePair::setFlagValue(bool v) -{ - d.setFlagValue(v); -} - -template -QPointerValuePair &QPointerValuePair::operator=(P *o) -{ - if (d.isT1()) d = o; - else d.asT2()->pointer = o; - return *this; -} - -template -P *QPointerValuePair::operator->() const -{ - if (d.isT1()) return d.asT1(); - else return d.asT2()->pointer; -} - -template -P *QPointerValuePair::operator*() const -{ - if (d.isT1()) return d.asT1(); - else return d.asT2()->pointer; -} - -template -bool QPointerValuePair::hasValue() const -{ - return d.isT2(); -} - -template -V &QPointerValuePair::value() -{ - if (d.isT1()) { - P *p = d.asT1(); - Value *value = new Value; - value->pointer = p; - d = value; - } - - return d.asT2()->value; -} - -// Will return null if hasValue() == false -template -const V *QPointerValuePair::constValue() const -{ - if (d.isT2()) return &d.asT2()->value; - else return 0; -} - -QT_END_NAMESPACE - -#endif // QPOINTERVALUEPAIR_P_H diff --git a/src/qml/qml/qqmlabstractbinding_p.h b/src/qml/qml/qqmlabstractbinding_p.h index 674178153a..45221a4bcd 100644 --- a/src/qml/qml/qqmlabstractbinding_p.h +++ b/src/qml/qml/qqmlabstractbinding_p.h @@ -55,7 +55,6 @@ #include #include #include -#include QT_BEGIN_NAMESPACE diff --git a/src/qml/qml/qqmlbinding_p.h b/src/qml/qml/qqmlbinding_p.h index 86db88cdf0..45c360f07e 100644 --- a/src/qml/qml/qqmlbinding_p.h +++ b/src/qml/qml/qqmlbinding_p.h @@ -61,7 +61,6 @@ #include #include -#include #include #include diff --git a/src/qml/qml/qqmlexpression_p.h b/src/qml/qml/qqmlexpression_p.h index 3d1df55a2d..ccc629a3a3 100644 --- a/src/qml/qml/qqmlexpression_p.h +++ b/src/qml/qml/qqmlexpression_p.h @@ -57,7 +57,6 @@ #include #include #include -#include #include QT_BEGIN_NAMESPACE diff --git a/src/qml/qml/qqmljavascriptexpression_p.h b/src/qml/qml/qqmljavascriptexpression_p.h index 64cb1bb242..94479f6c5e 100644 --- a/src/qml/qml/qqmljavascriptexpression_p.h +++ b/src/qml/qml/qqmljavascriptexpression_p.h @@ -54,7 +54,6 @@ #include #include #include -#include QT_BEGIN_NAMESPACE From 3b3ab6853c704b9bac5926dcf83bcdbbfaf2107f Mon Sep 17 00:00:00 2001 From: Frank Meerkoetter Date: Mon, 18 Apr 2016 21:45:35 +0200 Subject: [PATCH 09/12] Mark overrides of QQmlExtensionPlugin Clearly state that we want to override registerTypes of QQmlExtensionPlugin. Change-Id: I0acf76115d47d7166ccb813a811dd757d514e6e2 Reviewed-by: Simon Hausmann --- src/imports/folderlistmodel/plugin.cpp | 2 +- src/imports/layouts/plugin.cpp | 2 +- src/imports/localstorage/plugin.cpp | 2 +- src/imports/models/plugin.cpp | 2 +- src/imports/particles/plugin.cpp | 2 +- src/imports/qtquick2/plugin.cpp | 2 +- src/imports/settings/plugin.cpp | 2 +- src/imports/statemachine/plugin.cpp | 2 +- src/imports/testlib/main.cpp | 2 +- src/imports/window/plugin.cpp | 2 +- src/imports/xmllistmodel/plugin.cpp | 2 +- 11 files changed, 11 insertions(+), 11 deletions(-) diff --git a/src/imports/folderlistmodel/plugin.cpp b/src/imports/folderlistmodel/plugin.cpp index c60538673b..38de232dc0 100644 --- a/src/imports/folderlistmodel/plugin.cpp +++ b/src/imports/folderlistmodel/plugin.cpp @@ -59,7 +59,7 @@ class QmlFolderListModelPlugin : public QQmlExtensionPlugin public: QmlFolderListModelPlugin(QObject *parent = 0) : QQmlExtensionPlugin(parent) { initResources(); } - virtual void registerTypes(const char *uri) + void registerTypes(const char *uri) Q_DECL_OVERRIDE { Q_ASSERT(QLatin1String(uri) == QLatin1String("Qt.labs.folderlistmodel")); #ifndef QT_NO_DIRMODEL diff --git a/src/imports/layouts/plugin.cpp b/src/imports/layouts/plugin.cpp index 248b12ac31..64d687cf3b 100644 --- a/src/imports/layouts/plugin.cpp +++ b/src/imports/layouts/plugin.cpp @@ -61,7 +61,7 @@ public: { initResources(); } - virtual void registerTypes(const char *uri) + void registerTypes(const char *uri) Q_DECL_OVERRIDE { Q_ASSERT(QLatin1String(uri) == QLatin1String("QtQuick.Layouts")); Q_UNUSED(uri); diff --git a/src/imports/localstorage/plugin.cpp b/src/imports/localstorage/plugin.cpp index da1817d309..8780dcc757 100644 --- a/src/imports/localstorage/plugin.cpp +++ b/src/imports/localstorage/plugin.cpp @@ -761,7 +761,7 @@ public: { initResources(); } - void registerTypes(const char *uri) + void registerTypes(const char *uri) Q_DECL_OVERRIDE { Q_ASSERT(QLatin1String(uri) == "QtQuick.LocalStorage"); qmlRegisterSingletonType(uri, 2, 0, "LocalStorage", module_api_factory); diff --git a/src/imports/models/plugin.cpp b/src/imports/models/plugin.cpp index 9f96ace8fe..046d69cbc5 100644 --- a/src/imports/models/plugin.cpp +++ b/src/imports/models/plugin.cpp @@ -78,7 +78,7 @@ class QtQmlModelsPlugin : public QQmlExtensionPlugin Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QQmlExtensionInterface/1.0") public: QtQmlModelsPlugin(QObject *parent = 0) : QQmlExtensionPlugin(parent) { initResources(); } - virtual void registerTypes(const char *uri) + void registerTypes(const char *uri) Q_DECL_OVERRIDE { Q_ASSERT(QLatin1String(uri) == QLatin1String("QtQml.Models")); Q_UNUSED(uri); diff --git a/src/imports/particles/plugin.cpp b/src/imports/particles/plugin.cpp index 0698f34020..22eea16d4c 100644 --- a/src/imports/particles/plugin.cpp +++ b/src/imports/particles/plugin.cpp @@ -57,7 +57,7 @@ class QtQuick2ParticlesPlugin : public QQmlExtensionPlugin Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QQmlExtensionInterface/1.0") public: QtQuick2ParticlesPlugin(QObject *parent = 0) : QQmlExtensionPlugin(parent) { initResources(); } - virtual void registerTypes(const char *uri) + void registerTypes(const char *uri) Q_DECL_OVERRIDE { Q_ASSERT(QLatin1String(uri) == QLatin1String("QtQuick.Particles")); Q_UNUSED(uri); diff --git a/src/imports/qtquick2/plugin.cpp b/src/imports/qtquick2/plugin.cpp index 315ad0ce58..1e3ff255f8 100644 --- a/src/imports/qtquick2/plugin.cpp +++ b/src/imports/qtquick2/plugin.cpp @@ -57,7 +57,7 @@ class QtQuick2Plugin : public QQmlExtensionPlugin Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QQmlExtensionInterface/1.0") public: QtQuick2Plugin(QObject *parent = 0) : QQmlExtensionPlugin(parent) { initResources(); } - virtual void registerTypes(const char *uri) + void registerTypes(const char *uri) Q_DECL_OVERRIDE { Q_ASSERT(QLatin1String(uri) == QLatin1String("QtQuick")); Q_UNUSED(uri); diff --git a/src/imports/settings/plugin.cpp b/src/imports/settings/plugin.cpp index c97c2b066e..ce498774d2 100644 --- a/src/imports/settings/plugin.cpp +++ b/src/imports/settings/plugin.cpp @@ -58,7 +58,7 @@ class QmlSettingsPlugin : public QQmlExtensionPlugin public: QmlSettingsPlugin(QObject *parent = 0) : QQmlExtensionPlugin(parent) { initResources(); } - virtual void registerTypes(const char *uri) + void registerTypes(const char *uri) Q_DECL_OVERRIDE { Q_ASSERT(QByteArray(uri) == QByteArray("Qt.labs.settings")); qmlRegisterType(uri, 1, 0, "Settings"); diff --git a/src/imports/statemachine/plugin.cpp b/src/imports/statemachine/plugin.cpp index db79751b69..c061607f40 100644 --- a/src/imports/statemachine/plugin.cpp +++ b/src/imports/statemachine/plugin.cpp @@ -63,7 +63,7 @@ class QtQmlStateMachinePlugin : public QQmlExtensionPlugin public: QtQmlStateMachinePlugin(QObject *parent = 0) : QQmlExtensionPlugin(parent) { initResources(); } - void registerTypes(const char *uri) + void registerTypes(const char *uri) Q_DECL_OVERRIDE { qmlRegisterType(uri, 1, 0, "State"); qmlRegisterType(uri, 1, 0, "StateMachine"); diff --git a/src/imports/testlib/main.cpp b/src/imports/testlib/main.cpp index 26ce79c92b..1809477bfc 100644 --- a/src/imports/testlib/main.cpp +++ b/src/imports/testlib/main.cpp @@ -151,7 +151,7 @@ class QTestQmlModule : public QQmlExtensionPlugin public: QTestQmlModule(QObject *parent = 0) : QQmlExtensionPlugin(parent) { initResources(); } - virtual void registerTypes(const char *uri) + void registerTypes(const char *uri) Q_DECL_OVERRIDE { Q_ASSERT(QLatin1String(uri) == QLatin1String("QtTest")); qmlRegisterType(uri,1,0,"TestResult"); diff --git a/src/imports/window/plugin.cpp b/src/imports/window/plugin.cpp index a0a5724e34..b85ccc6dc7 100644 --- a/src/imports/window/plugin.cpp +++ b/src/imports/window/plugin.cpp @@ -73,7 +73,7 @@ class QtQuick2WindowPlugin : public QQmlExtensionPlugin Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QQmlExtensionInterface/1.0") public: QtQuick2WindowPlugin(QObject *parent = 0) : QQmlExtensionPlugin(parent) { initResources(); } - virtual void registerTypes(const char *uri) + void registerTypes(const char *uri) Q_DECL_OVERRIDE { Q_ASSERT(QLatin1String(uri) == QLatin1String("QtQuick.Window")); Q_UNUSED(uri); diff --git a/src/imports/xmllistmodel/plugin.cpp b/src/imports/xmllistmodel/plugin.cpp index e983b494e1..ca676c36b0 100644 --- a/src/imports/xmllistmodel/plugin.cpp +++ b/src/imports/xmllistmodel/plugin.cpp @@ -58,7 +58,7 @@ class QmlXmlListModelPlugin : public QQmlExtensionPlugin public: QmlXmlListModelPlugin(QObject *parent = 0) : QQmlExtensionPlugin(parent) { initResources(); } - virtual void registerTypes(const char *uri) + void registerTypes(const char *uri) Q_DECL_OVERRIDE { Q_ASSERT(QLatin1String(uri) == QLatin1String("QtQuick.XmlListModel")); qmlRegisterType(uri,2,0,"XmlListModel"); From 0c7a5165f3b3c9d2f271da4fe3cb49f09844a56e Mon Sep 17 00:00:00 2001 From: Frank Meerkoetter Date: Mon, 18 Apr 2016 21:43:46 +0200 Subject: [PATCH 10/12] Remove empty method The base type already provides an empty implementation of that method. Change-Id: I942db101343b1d4bb6de16ada189d969834a6cae Reviewed-by: Simon Hausmann --- src/imports/testlib/main.cpp | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/imports/testlib/main.cpp b/src/imports/testlib/main.cpp index 1809477bfc..1632d7ba64 100644 --- a/src/imports/testlib/main.cpp +++ b/src/imports/testlib/main.cpp @@ -159,10 +159,6 @@ public: qmlRegisterType(uri,1,0,"TestEvent"); qmlRegisterType(uri,1,0,"TestUtil"); } - - void initializeEngine(QQmlEngine *, const char *) - { - } }; QT_END_NAMESPACE From 223516ae2f7131cc7f8972e9afdeca970d85473d Mon Sep 17 00:00:00 2001 From: Erik Verbruggen Date: Wed, 6 Apr 2016 11:23:11 +0200 Subject: [PATCH 11/12] V4: make QQmlEnginePrivate::dereferenceScarceResources inlinable. Done by giving the "expensive" part its own function, that's even unlikely to be called anyway. Change-Id: I35621fb0a764879f9339b9e23f210c66971ff5b7 Reviewed-by: Simon Hausmann --- src/qml/qml/qqmlengine.cpp | 30 +++++++++--------------------- src/qml/qml/qqmlengine_p.h | 22 ++++++++++++++++++++++ 2 files changed, 31 insertions(+), 21 deletions(-) diff --git a/src/qml/qml/qqmlengine.cpp b/src/qml/qml/qqmlengine.cpp index 63d3feee1e..99ae367773 100644 --- a/src/qml/qml/qqmlengine.cpp +++ b/src/qml/qml/qqmlengine.cpp @@ -1900,28 +1900,16 @@ void QQmlEnginePrivate::warning(QQmlEnginePrivate *engine, const QList 0); - scarceResourcesRefCount -= 1; - - // if the refcount is zero, then evaluation of the "top level" - // expression must have completed. We can safely release the - // scarce resources. - if (Q_UNLIKELY(scarceResourcesRefCount == 0)) { - // iterate through the list and release them all. - // note that the actual SRD is owned by the JS engine, - // so we cannot delete the SRD; but we can free the - // memory used by the variant in the SRD. - QV4::ExecutionEngine *engine = QV8Engine::getV4(v8engine()); - while (QV4::ExecutionEngine::ScarceResourceData *sr = engine->scarceResources.first()) { - sr->data = QVariant(); - engine->scarceResources.remove(sr); - } + // iterate through the list and release them all. + // note that the actual SRD is owned by the JS engine, + // so we cannot delete the SRD; but we can free the + // memory used by the variant in the SRD. + QV4::ExecutionEngine *engine = QV8Engine::getV4(v8engine()); + while (QV4::ExecutionEngine::ScarceResourceData *sr = engine->scarceResources.first()) { + sr->data = QVariant(); + engine->scarceResources.remove(sr); } } diff --git a/src/qml/qml/qqmlengine_p.h b/src/qml/qml/qqmlengine_p.h index 92eadb0540..440840d3c9 100644 --- a/src/qml/qml/qqmlengine_p.h +++ b/src/qml/qml/qqmlengine_p.h @@ -267,6 +267,8 @@ private: struct Deletable { Deletable():next(0) {} virtual ~Deletable() {} Deletable *next; }; QFieldList toDeleteInEngineThread; void doDeleteInEngineThread(); + + void cleanupScarceResources(); }; /* @@ -279,6 +281,26 @@ inline void QQmlEnginePrivate::referenceScarceResources() scarceResourcesRefCount += 1; } +/* + This function should be called after evaluation of the js expression is + complete, and so the scarce resources may be freed safely. + */ +inline void QQmlEnginePrivate::dereferenceScarceResources() +{ + Q_ASSERT(scarceResourcesRefCount > 0); + scarceResourcesRefCount -= 1; + + // if the refcount is zero, then evaluation of the "top level" + // expression must have completed. We can safely release the + // scarce resources. + if (scarceResourcesRefCount == 0) { + QV4::ExecutionEngine *engine = QV8Engine::getV4(v8engine()); + if (Q_UNLIKELY(!engine->scarceResources.isEmpty())) { + cleanupScarceResources(); + } + } +} + /*! Returns true if the calling thread is the QQmlEngine thread. */ From 26ecc82374c476ee417ab04c455022f76909ba51 Mon Sep 17 00:00:00 2001 From: Michael Brasser Date: Tue, 12 Apr 2016 21:52:50 -0500 Subject: [PATCH 12/12] Add string search functions from ECMAScript 2015. Change-Id: I46d5e42186d9f1b2994778de967610725b0e0633 Reviewed-by: Lars Knoll --- src/qml/doc/src/javascript/functionlist.qdoc | 3 + src/qml/jsruntime/qv4stringobject.cpp | 80 ++++++++++++++++++++ src/qml/jsruntime/qv4stringobject_p.h | 3 + tests/auto/qml/qjsengine/tst_qjsengine.cpp | 3 + 4 files changed, 89 insertions(+) diff --git a/src/qml/doc/src/javascript/functionlist.qdoc b/src/qml/doc/src/javascript/functionlist.qdoc index 7f0e844b65..8b9c33f994 100644 --- a/src/qml/doc/src/javascript/functionlist.qdoc +++ b/src/qml/doc/src/javascript/functionlist.qdoc @@ -174,6 +174,8 @@ \li charAt(pos) \li charCodeAt(pos) \li concat([string1 [, string2 [, ...]]]) + \li endsWith(searchString [, endPosition ]) // ECMAScript 6: Added in Qt 5.8 + \li includes(searchString [, position ]) // ECMAScript 6: Added in 5.8 \li indexOf(searchString ,position) \li lastIndexOf(searchString, position) \li localeCompare(that) @@ -182,6 +184,7 @@ \li search(regexp) \li slice(start, end) \li split(separator, limit) + \li startsWith(searchString [, position ]) // ECMAScript 6: Added in Qt 5.8 \li substring(start, end) \li toLowerCase() \li toLocaleLowerCase() diff --git a/src/qml/jsruntime/qv4stringobject.cpp b/src/qml/jsruntime/qv4stringobject.cpp index b874766655..b4f04bbc76 100644 --- a/src/qml/jsruntime/qv4stringobject.cpp +++ b/src/qml/jsruntime/qv4stringobject.cpp @@ -196,7 +196,9 @@ void StringPrototype::init(ExecutionEngine *engine, Object *ctor) defineDefaultProperty(QStringLiteral("charAt"), method_charAt, 1); defineDefaultProperty(QStringLiteral("charCodeAt"), method_charCodeAt, 1); defineDefaultProperty(QStringLiteral("concat"), method_concat, 1); + defineDefaultProperty(QStringLiteral("endsWith"), method_endsWith, 1); defineDefaultProperty(QStringLiteral("indexOf"), method_indexOf, 1); + defineDefaultProperty(QStringLiteral("includes"), method_includes, 1); defineDefaultProperty(QStringLiteral("lastIndexOf"), method_lastIndexOf, 1); defineDefaultProperty(QStringLiteral("localeCompare"), method_localeCompare, 1); defineDefaultProperty(QStringLiteral("match"), method_match, 1); @@ -204,6 +206,7 @@ void StringPrototype::init(ExecutionEngine *engine, Object *ctor) defineDefaultProperty(QStringLiteral("search"), method_search, 1); defineDefaultProperty(QStringLiteral("slice"), method_slice, 2); defineDefaultProperty(QStringLiteral("split"), method_split, 2); + defineDefaultProperty(QStringLiteral("startsWith"), method_startsWith, 1); defineDefaultProperty(QStringLiteral("substr"), method_substr, 2); defineDefaultProperty(QStringLiteral("substring"), method_substring, 2); defineDefaultProperty(QStringLiteral("toLowerCase"), method_toLowerCase); @@ -293,6 +296,30 @@ ReturnedValue StringPrototype::method_concat(CallContext *context) return context->d()->engine->newString(value)->asReturnedValue(); } +ReturnedValue StringPrototype::method_endsWith(CallContext *context) +{ + QString value = getThisString(context); + if (context->d()->engine->hasException) + return Encode::undefined(); + + QString searchString; + if (context->argc()) { + if (context->args()[0].as()) + return context->engine()->throwTypeError(); + searchString = context->args()[0].toQString(); + } + + int pos = value.length(); + if (context->argc() > 1) + pos = (int) context->args()[1].toInteger(); + + if (pos == value.length()) + return Encode(value.endsWith(searchString)); + + QStringRef stringToSearch = value.leftRef(pos); + return Encode(stringToSearch.endsWith(searchString)); +} + ReturnedValue StringPrototype::method_indexOf(CallContext *context) { QString value = getThisString(context); @@ -314,6 +341,35 @@ ReturnedValue StringPrototype::method_indexOf(CallContext *context) return Encode(index); } +ReturnedValue StringPrototype::method_includes(CallContext *context) +{ + QString value = getThisString(context); + if (context->d()->engine->hasException) + return Encode::undefined(); + + QString searchString; + if (context->argc()) { + if (context->args()[0].as()) + return context->engine()->throwTypeError(); + searchString = context->args()[0].toQString(); + } + + int pos = 0; + if (context->argc() > 1) { + Scope scope(context); + ScopedValue posArg(scope, context->argument(1)); + pos = (int) posArg->toInteger(); + if (!posArg->isInteger() && posArg->isNumber() && qIsInf(posArg->toNumber())) + pos = value.length(); + } + + if (pos == 0) + return Encode(value.contains(searchString)); + + QStringRef stringToSearch = value.midRef(pos); + return Encode(stringToSearch.contains(searchString)); +} + ReturnedValue StringPrototype::method_lastIndexOf(CallContext *context) { Scope scope(context); @@ -716,6 +772,30 @@ ReturnedValue StringPrototype::method_split(CallContext *ctx) return array.asReturnedValue(); } +ReturnedValue StringPrototype::method_startsWith(CallContext *context) +{ + QString value = getThisString(context); + if (context->d()->engine->hasException) + return Encode::undefined(); + + QString searchString; + if (context->argc()) { + if (context->args()[0].as()) + return context->engine()->throwTypeError(); + searchString = context->args()[0].toQString(); + } + + int pos = 0; + if (context->argc() > 1) + pos = (int) context->args()[1].toInteger(); + + if (pos == 0) + return Encode(value.startsWith(searchString)); + + QStringRef stringToSearch = value.midRef(pos); + return Encode(stringToSearch.startsWith(searchString)); +} + ReturnedValue StringPrototype::method_substr(CallContext *context) { const QString value = getThisString(context); diff --git a/src/qml/jsruntime/qv4stringobject_p.h b/src/qml/jsruntime/qv4stringobject_p.h index 3930a011e6..fb229d4aff 100644 --- a/src/qml/jsruntime/qv4stringobject_p.h +++ b/src/qml/jsruntime/qv4stringobject_p.h @@ -115,7 +115,9 @@ struct StringPrototype: StringObject static ReturnedValue method_charAt(CallContext *context); static ReturnedValue method_charCodeAt(CallContext *context); static ReturnedValue method_concat(CallContext *context); + static ReturnedValue method_endsWith(CallContext *ctx); static ReturnedValue method_indexOf(CallContext *context); + static ReturnedValue method_includes(CallContext *context); static ReturnedValue method_lastIndexOf(CallContext *context); static ReturnedValue method_localeCompare(CallContext *context); static ReturnedValue method_match(CallContext *context); @@ -123,6 +125,7 @@ struct StringPrototype: StringObject static ReturnedValue method_search(CallContext *ctx); static ReturnedValue method_slice(CallContext *ctx); static ReturnedValue method_split(CallContext *ctx); + static ReturnedValue method_startsWith(CallContext *ctx); static ReturnedValue method_substr(CallContext *context); static ReturnedValue method_substring(CallContext *context); static ReturnedValue method_toLowerCase(CallContext *ctx); diff --git a/tests/auto/qml/qjsengine/tst_qjsengine.cpp b/tests/auto/qml/qjsengine/tst_qjsengine.cpp index 253b050b15..c535258c19 100644 --- a/tests/auto/qml/qjsengine/tst_qjsengine.cpp +++ b/tests/auto/qml/qjsengine/tst_qjsengine.cpp @@ -1057,6 +1057,8 @@ void tst_QJSEngine::builtinFunctionNames_data() QTest::newRow("String.prototype.charAt") << QString("String.prototype.charAt") << QString("charAt"); QTest::newRow("String.prototype.charCodeAt") << QString("String.prototype.charCodeAt") << QString("charCodeAt"); QTest::newRow("String.prototype.concat") << QString("String.prototype.concat") << QString("concat"); + QTest::newRow("String.prototype.endsWith") << QString("String.prototype.endsWith") << QString("endsWith"); + QTest::newRow("String.prototype.includes") << QString("String.prototype.includes") << QString("includes"); QTest::newRow("String.prototype.indexOf") << QString("String.prototype.indexOf") << QString("indexOf"); QTest::newRow("String.prototype.lastIndexOf") << QString("String.prototype.lastIndexOf") << QString("lastIndexOf"); QTest::newRow("String.prototype.localeCompare") << QString("String.prototype.localeCompare") << QString("localeCompare"); @@ -1065,6 +1067,7 @@ void tst_QJSEngine::builtinFunctionNames_data() QTest::newRow("String.prototype.search") << QString("String.prototype.search") << QString("search"); QTest::newRow("String.prototype.slice") << QString("String.prototype.slice") << QString("slice"); QTest::newRow("String.prototype.split") << QString("String.prototype.split") << QString("split"); + QTest::newRow("String.prototype.startsWith") << QString("String.prototype.startsWith") << QString("startsWith"); QTest::newRow("String.prototype.substring") << QString("String.prototype.substring") << QString("substring"); QTest::newRow("String.prototype.toLowerCase") << QString("String.prototype.toLowerCase") << QString("toLowerCase"); QTest::newRow("String.prototype.toLocaleLowerCase") << QString("String.prototype.toLocaleLowerCase") << QString("toLocaleLowerCase");