From c2ca2cbf04071ffb3aee6af8d5ab9084dfa1c091 Mon Sep 17 00:00:00 2001 From: Frederik Gladhorn Date: Tue, 14 Mar 2017 10:33:14 +0100 Subject: Fix touch event delivery in childMouseEventFilter Since moving to pointer events, we would deliver all events inside the filter function. The expected behavior though is that only points that are already grabbed, pressed inside or grabbed by children would be seen by the filter function. This broke using multiple touch aware items at the same time (2 pinch areas for example). Change-Id: I42a430f196ebbcf0a83a6dc8aca319e433ad52ad Reviewed-by: Shawn Rutledge --- src/quick/items/qquickevents.cpp | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/quick/items/qquickevents.cpp b/src/quick/items/qquickevents.cpp index 70d95ccdf8..68f6dbcfa5 100644 --- a/src/quick/items/qquickevents.cpp +++ b/src/quick/items/qquickevents.cpp @@ -846,9 +846,24 @@ QTouchEvent *QQuickPointerTouchEvent::touchEventForItem(QQuickItem *item, bool i auto p = m_touchPoints.at(i); if (p->isAccepted()) continue; + // include points where item is the grabber bool isGrabber = p->grabber() == item; + // include newly pressed points inside the bounds bool isPressInside = p->state() == QQuickEventPoint::Pressed && item->contains(item->mapFromScene(p->scenePos())); - if (!(isGrabber || isPressInside || isFiltering)) + + // filtering: (childMouseEventFilter) include points that are grabbed by children of the target item + bool grabberIsChild = false; + auto parent = p->grabber(); + while (isFiltering && parent) { + if (parent == item) { + grabberIsChild = true; + break; + } + parent = parent->parentItem(); + } + bool filterRelevant = isFiltering && grabberIsChild; + + if (!(isGrabber || isPressInside || filterRelevant)) continue; const QTouchEvent::TouchPoint *tp = touchPointById(p->pointId()); -- cgit v1.2.3 From 29bf17dee1497972152566af6916fd0a20b784ee Mon Sep 17 00:00:00 2001 From: Marc Mutz Date: Wed, 22 Mar 2017 11:06:46 +0100 Subject: Fix build with GCC 7 GCC 7 warns about preprocessor macros expanding to defined(), which the masm config macros use pervasively. Fix by suppressing the warning (-Wexpansion-to-defined). Task-number: QTBUG-59647 Change-Id: I9220741cf594824472bffc2305b994b311e55832 Reviewed-by: Lars Knoll Reviewed-by: Simon Hausmann --- src/3rdparty/masm/masm-defs.pri | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'src') diff --git a/src/3rdparty/masm/masm-defs.pri b/src/3rdparty/masm/masm-defs.pri index fa0d3d3c55..c0c5f3d114 100644 --- a/src/3rdparty/masm/masm-defs.pri +++ b/src/3rdparty/masm/masm-defs.pri @@ -40,3 +40,10 @@ INCLUDEPATH += $$PWD/disassembler/udis86 INCLUDEPATH += $$_OUT_PWD CONFIG(release, debug|release): DEFINES += NDEBUG + +!intel_icc:!clang:gcc { + greaterThan(QT_GCC_MAJOR_VERSION, 6) { # GCC 7 + QMAKE_CXXFLAGS_WARN_ON += -Wno-expansion-to-defined + QMAKE_CXXFLAGS += -Wno-expansion-to-defined + } +} -- cgit v1.2.3 From 3caf24c514e7b5dfe62dc656d48282f3816dd6cc Mon Sep 17 00:00:00 2001 From: Simon Hausmann Date: Tue, 28 Mar 2017 10:24:26 +0200 Subject: Prospective fix for static builds on Windows with QtQuickCompiler Don't define QML_PARSER_EXPORT to dllimport when doing static builds. Task-number: QTBUG-59767 Change-Id: I24acb2c51f54a0cde8d2e50a935ede876e5eb5b7 Reviewed-by: Andy Shaw --- src/qml/parser/qqmljsglobal_p.h | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) (limited to 'src') diff --git a/src/qml/parser/qqmljsglobal_p.h b/src/qml/parser/qqmljsglobal_p.h index 933c8f5202..0e195994b4 100644 --- a/src/qml/parser/qqmljsglobal_p.h +++ b/src/qml/parser/qqmljsglobal_p.h @@ -67,13 +67,17 @@ #else // !QT_CREATOR # define QT_QML_BEGIN_NAMESPACE QT_BEGIN_NAMESPACE # define QT_QML_END_NAMESPACE QT_END_NAMESPACE -# if defined(QT_BUILD_QMLDEVTOOLS_LIB) || defined(QT_QMLDEVTOOLS_LIB) - // QmlDevTools is a static library -# define QML_PARSER_EXPORT -# elif defined(QT_BUILD_QML_LIB) -# define QML_PARSER_EXPORT Q_DECL_EXPORT +# ifndef QT_STATIC +# if defined(QT_BUILD_QMLDEVTOOLS_LIB) || defined(QT_QMLDEVTOOLS_LIB) + // QmlDevTools is a static library +# define QML_PARSER_EXPORT +# elif defined(QT_BUILD_QML_LIB) +# define QML_PARSER_EXPORT Q_DECL_EXPORT +# else +# define QML_PARSER_EXPORT Q_DECL_IMPORT +# endif # else -# define QML_PARSER_EXPORT Q_DECL_IMPORT +# define QML_PARSER_EXPORT # endif #endif // QT_CREATOR -- cgit v1.2.3 From a295dae1bc2e2f2d1d1a2c53a9d5faffeeac68c5 Mon Sep 17 00:00:00 2001 From: Simon Hausmann Date: Tue, 28 Mar 2017 10:55:25 +0200 Subject: Fix value type encoding constant usage when cross-compiling Our two value encodings use different masks for the upper 4 bytes. Depending on the target architecture we must use different values when generating code that uses these masks. This patch replaces the #ifdef'ed ValueTypeInternal_* enum values with two C++11 scoped enums that allows for the co-existence of both throughout the code base as well as selective use in the code generators. Change-Id: I380c8c28b84df2874cca521b78bfe7f9388ed228 Reviewed-by: Qt CI Bot Reviewed-by: Lars Knoll --- src/qml/jit/qv4assembler.cpp | 2 +- src/qml/jit/qv4assembler_p.h | 29 ++++++++++-------- src/qml/jit/qv4isel_masm.cpp | 23 +++++++------- src/qml/jsruntime/qv4engine.cpp | 2 +- src/qml/jsruntime/qv4scopedvalue_p.h | 2 +- src/qml/jsruntime/qv4value_p.h | 58 ++++++++++++++++++++++-------------- src/qml/jsruntime/qv4vme_moth.cpp | 26 ++++++++-------- 7 files changed, 80 insertions(+), 62 deletions(-) (limited to 'src') diff --git a/src/qml/jit/qv4assembler.cpp b/src/qml/jit/qv4assembler.cpp index d239ed9907..daa732810b 100644 --- a/src/qml/jit/qv4assembler.cpp +++ b/src/qml/jit/qv4assembler.cpp @@ -437,7 +437,7 @@ typename Assembler::Jump Assembler::ge // check if it's an int32: Assembler::Jump isNoInt = branch32(Assembler::NotEqual, Assembler::ScratchRegister, - Assembler::TrustedImm32(Value::Integer_Type_Internal)); + Assembler::TrustedImm32(quint32(ValueTypeInternal::Integer))); convertInt32ToDouble(toInt32Register(src, Assembler::ScratchRegister), dest); Assembler::Jump intDone = jump(); diff --git a/src/qml/jit/qv4assembler_p.h b/src/qml/jit/qv4assembler_p.h index 3e3aab9452..ad6c29dd49 100644 --- a/src/qml/jit/qv4assembler_p.h +++ b/src/qml/jit/qv4assembler_p.h @@ -153,6 +153,8 @@ struct RegisterSizeDependentAssemblerMacroAssembler::loadDouble(addr, dest); @@ -219,16 +221,16 @@ struct RegisterSizeDependentAssemblerjump(); intRange.link(as); as->move(srcReg, lowReg); - as->move(TrustedImm32(QV4::Value::Integer_Type_Internal), highReg); + as->move(TrustedImm32(quint32(QV4::Value::ValueTypeInternal_32::Integer)), highReg); done.link(as); } break; case IR::SInt32Type: as->move((RegisterID) t->index, lowReg); - as->move(TrustedImm32(QV4::Value::Integer_Type_Internal), highReg); + as->move(TrustedImm32(quint32(QV4::Value::ValueTypeInternal_32::Integer)), highReg); break; case IR::BoolType: as->move((RegisterID) t->index, lowReg); - as->move(TrustedImm32(QV4::Value::Boolean_Type_Internal), highReg); + as->move(TrustedImm32(quint32(QV4::Value::ValueTypeInternal_32::Boolean)), highReg); break; default: Q_UNREACHABLE(); @@ -319,14 +321,14 @@ struct RegisterSizeDependentAssemblerbranch32(RelationalCondition::NotEqual, TargetPlatform::ReturnValueRegister, - TrustedImm32(Value::Integer_Type_Internal)); + TrustedImm32(quint32(Value::ValueTypeInternal_32::Integer))); IR::Temp *targetTemp = target->asTemp(); if (!targetTemp || targetTemp->kind == IR::Temp::StackSlot) { as->load32(addr, TargetPlatform::ReturnValueRegister); Pointer targetAddr = as->loadAddress(TargetPlatform::ScratchRegister, target); as->store32(TargetPlatform::ReturnValueRegister, targetAddr); targetAddr.offset += 4; - as->store32(TrustedImm32(Value::Integer_Type_Internal), targetAddr); + as->store32(TrustedImm32(quint32(Value::ValueTypeInternal_32::Integer)), targetAddr); } else { as->load32(addr, (RegisterID) targetTemp->index); } @@ -384,6 +386,8 @@ struct RegisterSizeDependentAssemblerload64(addr, TargetPlatform::ReturnValueRegister); @@ -433,7 +437,7 @@ struct RegisterSizeDependentAssemblerjump(); intRange.link(as); as->zeroExtend32ToPtr(srcReg, TargetPlatform::ReturnValueRegister); - quint64 tag = QV4::Value::Integer_Type_Internal; + quint64 tag = quint64(QV4::Value::ValueTypeInternal_64::Integer); as->or64(TrustedImm64(tag << 32), TargetPlatform::ReturnValueRegister); done.link(as); @@ -442,10 +446,10 @@ struct RegisterSizeDependentAssemblertype) { case IR::SInt32Type: - tag = QV4::Value::Integer_Type_Internal; + tag = quint64(QV4::Value::ValueTypeInternal_64::Integer); break; case IR::BoolType: - tag = QV4::Value::Boolean_Type_Internal; + tag = quint64(QV4::Value::ValueTypeInternal_64::Boolean); break; default: tag = 31337; // bogus value @@ -623,7 +627,7 @@ struct RegisterSizeDependentAssemblerloadAddress(TargetPlatform::ScratchRegister, target); as->store32(TargetPlatform::ReturnValueRegister, targetAddr); targetAddr.offset += 4; - as->store32(TrustedImm32(Value::Integer_Type_Internal), targetAddr); + as->store32(TrustedImm32(quint32(Value::ValueTypeInternal_64::Integer)), targetAddr); } else { as->storeInt32(TargetPlatform::ReturnValueRegister, target); } @@ -719,8 +723,6 @@ public: return (hostOffset * RegisterSize) / QT_POINTER_SIZE; } - using RegisterSizeDependentOps = RegisterSizeDependentAssembler, MacroAssembler, JITTargetPlatform, RegisterSize>; - struct LookupCall { Address addr; uint getterSetterOffset; @@ -751,6 +753,9 @@ public: {} }; + using RegisterSizeDependentOps = RegisterSizeDependentAssembler, MacroAssembler, JITTargetPlatform, RegisterSize>; + using ValueTypeInternal = typename RegisterSizeDependentOps::ValueTypeInternal; + // V4 uses two stacks: one stack with QV4::Value items, which is checked by the garbage // collector, and one stack used by the native C/C++/ABI code. This C++ stack is not scanned // by the garbage collector, so if any JS object needs to be retained, it should be put on the @@ -1586,7 +1591,7 @@ public: Pointer tagAddr = addr; tagAddr.offset += 4; load32(tagAddr, scratchReg); - Jump inIntRange = branch32(RelationalCondition::Equal, scratchReg, TrustedImm32(QV4::Value::Integer_Type_Internal)); + Jump inIntRange = branch32(RelationalCondition::Equal, scratchReg, TrustedImm32(quint32(ValueTypeInternal::Integer))); // it's not in signed int range, so load it as a double, and truncate it down loadDouble(addr, FPGpr0); diff --git a/src/qml/jit/qv4isel_masm.cpp b/src/qml/jit/qv4isel_masm.cpp index 4a222e20f4..126fb4382b 100644 --- a/src/qml/jit/qv4isel_masm.cpp +++ b/src/qml/jit/qv4isel_masm.cpp @@ -774,10 +774,10 @@ void InstructionSelection::swapValues(IR::Expr *source, IR::Expr * quint32 tag; switch (regTemp->type) { case IR::BoolType: - tag = QV4::Value::Boolean_Type_Internal; + tag = quint32(JITAssembler::ValueTypeInternal::Boolean); break; case IR::SInt32Type: - tag = QV4::Value::Integer_Type_Internal; + tag = quint32(JITAssembler::ValueTypeInternal::Integer); break; default: tag = 31337; // bogus value @@ -925,7 +925,7 @@ void InstructionSelection::convertTypeToDouble(IR::Expr *source, I // check if it's an int32: Jump isNoInt = _as->branch32(RelationalCondition::NotEqual, JITTargetPlatform::ScratchRegister, - TrustedImm32(Value::Integer_Type_Internal)); + TrustedImm32(quint32(JITAssembler::ValueTypeInternal::Integer))); convertIntToDouble(source, target); Jump intDone = _as->jump(); @@ -1003,13 +1003,13 @@ void InstructionSelection::convertTypeToBool(IR::Expr *source, IR: // checkif it's a bool: Jump notBool = _as->branch32(RelationalCondition::NotEqual, JITTargetPlatform::ReturnValueRegister, - TrustedImm32(Value::Boolean_Type_Internal)); + TrustedImm32(quint32(JITAssembler::ValueTypeInternal::Boolean))); _as->load32(addr, JITTargetPlatform::ReturnValueRegister); Jump boolDone = _as->jump(); // check if it's an int32: notBool.link(_as); Jump fallback = _as->branch32(RelationalCondition::NotEqual, JITTargetPlatform::ReturnValueRegister, - TrustedImm32(Value::Integer_Type_Internal)); + TrustedImm32(quint32(JITAssembler::ValueTypeInternal::Integer))); _as->load32(addr, JITTargetPlatform::ReturnValueRegister); Jump isZero = _as->branch32(RelationalCondition::Equal, JITTargetPlatform::ReturnValueRegister, TrustedImm32(0)); @@ -1079,7 +1079,7 @@ void InstructionSelection::convertTypeToUInt32(IR::Expr *source, I // check if it's an int32: Jump isNoInt = _as->branch32(RelationalCondition::NotEqual, JITTargetPlatform::ScratchRegister, - TrustedImm32(Value::Integer_Type_Internal)); + TrustedImm32(quint32(JITAssembler::ValueTypeInternal::Integer))); Pointer addr = _as->loadAddress(JITTargetPlatform::ScratchRegister, source); _as->storeUInt32(_as->toInt32Register(addr, JITTargetPlatform::ScratchRegister), target); Jump intDone = _as->jump(); @@ -1195,7 +1195,8 @@ void InstructionSelection::visitCJump(IR::CJump *s) Address temp = _as->loadAddress(JITTargetPlatform::ScratchRegister, s->cond); Address tag = temp; tag.offset += QV4::Value::tagOffset(); - Jump booleanConversion = _as->branch32(RelationalCondition::NotEqual, tag, TrustedImm32(QV4::Value::Boolean_Type_Internal)); + Jump booleanConversion = _as->branch32(RelationalCondition::NotEqual, tag, + TrustedImm32(quint32(JITAssembler::ValueTypeInternal::Boolean))); Address data = temp; data.offset += QV4::Value::valueOffset(); @@ -1314,7 +1315,7 @@ int InstructionSelection::prepareCallData(IR::ExprList* args, IR:: } Pointer p = _as->stackLayout().callDataAddress(offsetof(CallData, tag)); - _as->store32(TrustedImm32(QV4::Value::Integer_Type_Internal), p); + _as->store32(TrustedImm32(quint32(JITAssembler::ValueTypeInternal::Integer)), p); p = _as->stackLayout().callDataAddress(offsetof(CallData, argc)); _as->store32(TrustedImm32(argc), p); p = _as->stackLayout().callDataAddress(offsetof(CallData, thisObject)); @@ -1456,7 +1457,7 @@ bool InstructionSelection::visitCJumpStrictNull(IR::Binop *binop, RelationalCondition cond = binop->op == IR::OpStrictEqual ? RelationalCondition::Equal : RelationalCondition::NotEqual; - const TrustedImm32 tag(QV4::Value::Null_Type_Internal); + const TrustedImm32 tag{quint32(JITAssembler::ValueTypeInternal::Null)}; _as->generateCJumpOnCompare(cond, tagReg, tag, _block, trueBlock, falseBlock); return true; } @@ -1538,7 +1539,7 @@ bool InstructionSelection::visitCJumpStrictBool(IR::Binop *binop, // check if the tag of the var operand is indicates 'boolean' _as->load32(otherAddr, JITTargetPlatform::ScratchRegister); Jump noBool = _as->branch32(RelationalCondition::NotEqual, JITTargetPlatform::ScratchRegister, - TrustedImm32(QV4::Value::Boolean_Type_Internal)); + TrustedImm32(quint32(JITAssembler::ValueTypeInternal::Boolean))); if (binop->op == IR::OpStrictEqual) _as->addPatch(falseBlock, noBool); else @@ -1588,7 +1589,7 @@ bool InstructionSelection::visitCJumpNullUndefined(IR::Type nullOr if (binop->op == IR::OpNotEqual) qSwap(trueBlock, falseBlock); - Jump isNull = _as->branch32(RelationalCondition::Equal, tagReg, TrustedImm32(int(QV4::Value::Null_Type_Internal))); + Jump isNull = _as->branch32(RelationalCondition::Equal, tagReg, TrustedImm32(quint32(JITAssembler::ValueTypeInternal::Null))); Jump isNotUndefinedTag = _as->branch32(RelationalCondition::NotEqual, tagReg, TrustedImm32(int(QV4::Value::Managed_Type_Internal))); tagAddr.offset -= 4; _as->load32(tagAddr, tagReg); diff --git a/src/qml/jsruntime/qv4engine.cpp b/src/qml/jsruntime/qv4engine.cpp index 83b00f0356..b5d4e6909b 100644 --- a/src/qml/jsruntime/qv4engine.cpp +++ b/src/qml/jsruntime/qv4engine.cpp @@ -498,7 +498,7 @@ void ExecutionEngine::initRootContext() sizeof(GlobalContext::Data) + sizeof(CallData))); r->d_unchecked()->init(this); r->d()->callData = reinterpret_cast(r->d() + 1); - r->d()->callData->tag = QV4::Value::Integer_Type_Internal; + r->d()->callData->tag = quint32(Value::ValueTypeInternal::Integer); r->d()->callData->argc = 0; r->d()->callData->thisObject = globalObject; r->d()->callData->args[0] = Encode::undefined(); diff --git a/src/qml/jsruntime/qv4scopedvalue_p.h b/src/qml/jsruntime/qv4scopedvalue_p.h index 894434be16..e9dcc9172f 100644 --- a/src/qml/jsruntime/qv4scopedvalue_p.h +++ b/src/qml/jsruntime/qv4scopedvalue_p.h @@ -368,7 +368,7 @@ struct ScopedCallData { { int size = qMax(argc, QV4::Global::ReservedArgumentCount + int(offsetof(QV4::CallData, args)/sizeof(QV4::Value))); ptr = reinterpret_cast(scope.alloc(size)); - ptr->tag = QV4::Value::Integer_Type_Internal; + ptr->tag = quint32(QV4::Value::ValueTypeInternal::Integer); ptr->argc = argc; } diff --git a/src/qml/jsruntime/qv4value_p.h b/src/qml/jsruntime/qv4value_p.h index 5662432f0d..9adad881a1 100644 --- a/src/qml/jsruntime/qv4value_p.h +++ b/src/qml/jsruntime/qv4value_p.h @@ -207,23 +207,23 @@ public: } QML_NEARLY_ALWAYS_INLINE void setInt_32(int i) { - setTagValue(Integer_Type_Internal, quint32(i)); + setTagValue(quint32(ValueTypeInternal::Integer), quint32(i)); } QML_NEARLY_ALWAYS_INLINE uint uint_32() const { return value(); } QML_NEARLY_ALWAYS_INLINE void setEmpty() { - setTagValue(Empty_Type_Internal, value()); + setTagValue(quint32(ValueTypeInternal::Empty), value()); } QML_NEARLY_ALWAYS_INLINE void setEmpty(int i) { - setTagValue(Empty_Type_Internal, quint32(i)); + setTagValue(quint32(ValueTypeInternal::Empty), quint32(i)); } QML_NEARLY_ALWAYS_INLINE void setEmpty(quint32 i) { - setTagValue(Empty_Type_Internal, i); + setTagValue(quint32(ValueTypeInternal::Empty), i); } QML_NEARLY_ALWAYS_INLINE quint32 emptyValue() @@ -266,8 +266,17 @@ public: IsDoubleTag_Shift = IsDouble_Shift - Tag_Shift, Managed_Type_Internal_64 = 0 }; + static const quint64 Immediate_Mask_64 = 0x00020000u; // bit 49 + enum class ValueTypeInternal_64 { + Empty = Immediate_Mask_64| 0, + ConvertibleToInt = Immediate_Mask_64| 0x10000u, // bit 48 + Null = ConvertibleToInt | 0x08000u, + Boolean = ConvertibleToInt | 0x04000u, + Integer = ConvertibleToInt | 0x02000u + }; + // Used only by 32-bit encoding enum Masks { SilentNaNBit = 0x00040000, @@ -275,6 +284,14 @@ public: }; static const quint64 Immediate_Mask_32 = NotDouble_Mask | 0x00020000u | SilentNaNBit; + enum class ValueTypeInternal_32 { + Empty = Immediate_Mask_32| 0, + ConvertibleToInt = Immediate_Mask_32| 0x10000u, // bit 48 + Null = ConvertibleToInt | 0x08000u, + Boolean = ConvertibleToInt | 0x04000u, + Integer = ConvertibleToInt | 0x02000u + }; + enum { Managed_Type_Internal_32 = NotDouble_Mask }; @@ -284,28 +301,23 @@ public: Managed_Type_Internal = Managed_Type_Internal_64 }; static const quint64 Immediate_Mask = Immediate_Mask_64; + using ValueTypeInternal = ValueTypeInternal_64; #else enum { Managed_Type_Internal = Managed_Type_Internal_32 }; static const quint64 Immediate_Mask = Immediate_Mask_32; + using ValueTypeInternal = ValueTypeInternal_32; #endif enum { NaN_Mask = 0x7ff80000, }; - enum ValueTypeInternal { - Empty_Type_Internal = Immediate_Mask | 0, - ConvertibleToInt = Immediate_Mask | 0x10000u, // bit 48 - Null_Type_Internal = ConvertibleToInt | 0x08000u, - Boolean_Type_Internal = ConvertibleToInt | 0x04000u, - Integer_Type_Internal = ConvertibleToInt | 0x02000u - }; // used internally in property - inline bool isEmpty() const { return tag() == Empty_Type_Internal; } - inline bool isNull() const { return tag() == Null_Type_Internal; } - inline bool isBoolean() const { return tag() == Boolean_Type_Internal; } - inline bool isInteger() const { return tag() == Integer_Type_Internal; } + inline bool isEmpty() const { return tag() == quint32(ValueTypeInternal::Empty); } + inline bool isNull() const { return tag() == quint32(ValueTypeInternal::Null); } + inline bool isBoolean() const { return tag() == quint32(ValueTypeInternal::Boolean); } + inline bool isInteger() const { return tag() == quint32(ValueTypeInternal::Integer); } inline bool isNullOrUndefined() const { return isNull() || isUndefined(); } inline bool isNumber() const { return isDouble() || isInteger(); } @@ -330,9 +342,9 @@ public: inline bool isDouble() const { return (tag() & NotDouble_Mask) != NotDouble_Mask; } inline bool isManaged() const { return tag() == Managed_Type_Internal && !isUndefined(); } inline bool isManagedOrUndefined() const { return tag() == Managed_Type_Internal; } - inline bool integerCompatible() const { return (tag() & ConvertibleToInt) == ConvertibleToInt; } + inline bool integerCompatible() const { return (tag() & quint32(ValueTypeInternal::ConvertibleToInt)) == quint32(ValueTypeInternal::ConvertibleToInt); } static inline bool integerCompatible(Value a, Value b) { - return ((a.tag() & b.tag()) & ConvertibleToInt) == ConvertibleToInt; + return ((a.tag() & b.tag()) & quint32(ValueTypeInternal::ConvertibleToInt)) == quint32(ValueTypeInternal::ConvertibleToInt); } static inline bool bothDouble(Value a, Value b) { return ((a.tag() | b.tag()) & NotDouble_Mask) != NotDouble_Mask; @@ -359,7 +371,7 @@ public: inline bool isString() const; inline bool isObject() const; inline bool isInt32() { - if (tag() == Integer_Type_Internal) + if (tag() == quint32(ValueTypeInternal::Integer)) return true; if (isDouble()) { double d = doubleValue(); @@ -372,7 +384,7 @@ public: return false; } double asDouble() const { - if (tag() == Integer_Type_Internal) + if (tag() == quint32(ValueTypeInternal::Integer)) return int_32(); return doubleValue(); } @@ -427,7 +439,7 @@ public: inline bool tryIntegerConversion() { bool b = integerCompatible(); if (b) - setTagValue(Integer_Type_Internal, value()); + setTagValue(quint32(ValueTypeInternal::Integer), value()); return b; } @@ -610,14 +622,14 @@ inline Primitive Primitive::emptyValue(uint e) inline Primitive Primitive::nullValue() { Primitive v; - v.setTagValue(Null_Type_Internal, 0); + v.setTagValue(quint32(ValueTypeInternal::Null), 0); return v; } inline Primitive Primitive::fromBoolean(bool b) { Primitive v; - v.setTagValue(Boolean_Type_Internal, b); + v.setTagValue(quint32(ValueTypeInternal::Boolean), b); return v; } @@ -639,7 +651,7 @@ inline Primitive Primitive::fromUInt32(uint i) { Primitive v; if (i < INT_MAX) { - v.setTagValue(Integer_Type_Internal, i); + v.setTagValue(quint32(ValueTypeInternal::Integer), i); } else { v.setDouble(i); } diff --git a/src/qml/jsruntime/qv4vme_moth.cpp b/src/qml/jsruntime/qv4vme_moth.cpp index 075a9a4a5d..c9b249011b 100644 --- a/src/qml/jsruntime/qv4vme_moth.cpp +++ b/src/qml/jsruntime/qv4vme_moth.cpp @@ -573,7 +573,7 @@ QV4::ReturnedValue VME::run(ExecutionEngine *engine, const uchar *code #endif // DO_TRACE_INSTR Q_ASSERT(instr.callData + instr.argc + offsetof(QV4::CallData, args)/sizeof(QV4::Value) <= stackSize); QV4::CallData *callData = reinterpret_cast(stack + instr.callData); - callData->tag = QV4::Value::Integer_Type_Internal; + callData->tag = quint32(Value::ValueTypeInternal::Integer); callData->argc = instr.argc; callData->thisObject = QV4::Primitive::undefinedValue(); STOREVALUE(instr.result, Runtime::method_callValue(engine, VALUE(instr.dest), callData)); @@ -583,7 +583,7 @@ QV4::ReturnedValue VME::run(ExecutionEngine *engine, const uchar *code TRACE(property name, "%s, args=%u, argc=%u, this=%s", qPrintable(runtimeStrings[instr.name]->toQString()), instr.callData, instr.argc, (VALUE(instr.base)).toString(context)->toQString().toUtf8().constData()); Q_ASSERT(instr.callData + instr.argc + offsetof(QV4::CallData, args)/sizeof(QV4::Value) <= stackSize); QV4::CallData *callData = reinterpret_cast(stack + instr.callData); - callData->tag = QV4::Value::Integer_Type_Internal; + callData->tag = quint32(Value::ValueTypeInternal::Integer); callData->argc = instr.argc; callData->thisObject = VALUE(instr.base); STOREVALUE(instr.result, Runtime::method_callProperty(engine, instr.name, callData)); @@ -592,7 +592,7 @@ QV4::ReturnedValue VME::run(ExecutionEngine *engine, const uchar *code MOTH_BEGIN_INSTR(CallPropertyLookup) Q_ASSERT(instr.callData + instr.argc + offsetof(QV4::CallData, args)/sizeof(QV4::Value) <= stackSize); QV4::CallData *callData = reinterpret_cast(stack + instr.callData); - callData->tag = QV4::Value::Integer_Type_Internal; + callData->tag = quint32(Value::ValueTypeInternal::Integer); callData->argc = instr.argc; callData->thisObject = VALUE(instr.base); STOREVALUE(instr.result, Runtime::method_callPropertyLookup(engine, instr.lookupIndex, callData)); @@ -602,7 +602,7 @@ QV4::ReturnedValue VME::run(ExecutionEngine *engine, const uchar *code TRACE(property name, "%s, args=%u, argc=%u, this=%s", qPrintable(runtimeStrings[instr.name]->toQString()), instr.callData, instr.argc, (VALUE(instr.base)).toString(context)->toQString().toUtf8().constData()); Q_ASSERT(instr.callData + instr.argc + offsetof(QV4::CallData, args)/sizeof(QV4::Value) <= stackSize); QV4::CallData *callData = reinterpret_cast(stack + instr.callData); - callData->tag = QV4::Value::Integer_Type_Internal; + callData->tag = quint32(Value::ValueTypeInternal::Integer); callData->argc = instr.argc; callData->thisObject = VALUE(instr.base); STOREVALUE(instr.result, Runtime::method_callQmlScopeObjectProperty(engine, instr.index, callData)); @@ -612,7 +612,7 @@ QV4::ReturnedValue VME::run(ExecutionEngine *engine, const uchar *code TRACE(property name, "%s, args=%u, argc=%u, this=%s", qPrintable(runtimeStrings[instr.name]->toQString()), instr.callData, instr.argc, (VALUE(instr.base)).toString(context)->toQString().toUtf8().constData()); Q_ASSERT(instr.callData + instr.argc + offsetof(QV4::CallData, args)/sizeof(QV4::Value) <= stackSize); QV4::CallData *callData = reinterpret_cast(stack + instr.callData); - callData->tag = QV4::Value::Integer_Type_Internal; + callData->tag = quint32(Value::ValueTypeInternal::Integer); callData->argc = instr.argc; callData->thisObject = VALUE(instr.base); STOREVALUE(instr.result, Runtime::method_callQmlContextObjectProperty(engine, instr.index, callData)); @@ -621,7 +621,7 @@ QV4::ReturnedValue VME::run(ExecutionEngine *engine, const uchar *code MOTH_BEGIN_INSTR(CallElement) Q_ASSERT(instr.callData + instr.argc + offsetof(QV4::CallData, args)/sizeof(QV4::Value) <= stackSize); QV4::CallData *callData = reinterpret_cast(stack + instr.callData); - callData->tag = QV4::Value::Integer_Type_Internal; + callData->tag = quint32(Value::ValueTypeInternal::Integer); callData->argc = instr.argc; callData->thisObject = VALUE(instr.base); STOREVALUE(instr.result, Runtime::method_callElement(engine, VALUE(instr.index), callData)); @@ -630,7 +630,7 @@ QV4::ReturnedValue VME::run(ExecutionEngine *engine, const uchar *code MOTH_BEGIN_INSTR(CallActivationProperty) Q_ASSERT(instr.callData + instr.argc + offsetof(QV4::CallData, args)/sizeof(QV4::Value) <= stackSize); QV4::CallData *callData = reinterpret_cast(stack + instr.callData); - callData->tag = QV4::Value::Integer_Type_Internal; + callData->tag = quint32(Value::ValueTypeInternal::Integer); callData->argc = instr.argc; callData->thisObject = QV4::Primitive::undefinedValue(); STOREVALUE(instr.result, Runtime::method_callActivationProperty(engine, instr.name, callData)); @@ -639,7 +639,7 @@ QV4::ReturnedValue VME::run(ExecutionEngine *engine, const uchar *code MOTH_BEGIN_INSTR(CallGlobalLookup) Q_ASSERT(instr.callData + instr.argc + offsetof(QV4::CallData, args)/sizeof(QV4::Value) <= stackSize); QV4::CallData *callData = reinterpret_cast(stack + instr.callData); - callData->tag = QV4::Value::Integer_Type_Internal; + callData->tag = quint32(Value::ValueTypeInternal::Integer); callData->argc = instr.argc; callData->thisObject = QV4::Primitive::undefinedValue(); STOREVALUE(instr.result, Runtime::method_callGlobalLookup(engine, instr.index, callData)); @@ -745,7 +745,7 @@ QV4::ReturnedValue VME::run(ExecutionEngine *engine, const uchar *code MOTH_BEGIN_INSTR(CreateValue) Q_ASSERT(instr.callData + instr.argc + offsetof(QV4::CallData, args)/sizeof(QV4::Value) <= stackSize); QV4::CallData *callData = reinterpret_cast(stack + instr.callData); - callData->tag = QV4::Value::Integer_Type_Internal; + callData->tag = quint32(Value::ValueTypeInternal::Integer); callData->argc = instr.argc; callData->thisObject = QV4::Primitive::undefinedValue(); STOREVALUE(instr.result, Runtime::method_constructValue(engine, VALUE(instr.func), callData)); @@ -754,7 +754,7 @@ QV4::ReturnedValue VME::run(ExecutionEngine *engine, const uchar *code MOTH_BEGIN_INSTR(CreateProperty) Q_ASSERT(instr.callData + instr.argc + offsetof(QV4::CallData, args)/sizeof(QV4::Value) <= stackSize); QV4::CallData *callData = reinterpret_cast(stack + instr.callData); - callData->tag = QV4::Value::Integer_Type_Internal; + callData->tag = quint32(Value::ValueTypeInternal::Integer); callData->argc = instr.argc; callData->thisObject = VALUE(instr.base); STOREVALUE(instr.result, Runtime::method_constructProperty(engine, instr.name, callData)); @@ -763,7 +763,7 @@ QV4::ReturnedValue VME::run(ExecutionEngine *engine, const uchar *code MOTH_BEGIN_INSTR(ConstructPropertyLookup) Q_ASSERT(instr.callData + instr.argc + offsetof(QV4::CallData, args)/sizeof(QV4::Value) <= stackSize); QV4::CallData *callData = reinterpret_cast(stack + instr.callData); - callData->tag = QV4::Value::Integer_Type_Internal; + callData->tag = quint32(Value::ValueTypeInternal::Integer); callData->argc = instr.argc; callData->thisObject = VALUE(instr.base); STOREVALUE(instr.result, Runtime::method_constructPropertyLookup(engine, instr.index, callData)); @@ -772,7 +772,7 @@ QV4::ReturnedValue VME::run(ExecutionEngine *engine, const uchar *code MOTH_BEGIN_INSTR(CreateActivationProperty) Q_ASSERT(instr.callData + instr.argc + offsetof(QV4::CallData, args)/sizeof(QV4::Value) <= stackSize); QV4::CallData *callData = reinterpret_cast(stack + instr.callData); - callData->tag = QV4::Value::Integer_Type_Internal; + callData->tag = quint32(Value::ValueTypeInternal::Integer); callData->argc = instr.argc; callData->thisObject = QV4::Primitive::undefinedValue(); STOREVALUE(instr.result, Runtime::method_constructActivationProperty(engine, instr.name, callData)); @@ -781,7 +781,7 @@ QV4::ReturnedValue VME::run(ExecutionEngine *engine, const uchar *code MOTH_BEGIN_INSTR(ConstructGlobalLookup) Q_ASSERT(instr.callData + instr.argc + offsetof(QV4::CallData, args)/sizeof(QV4::Value) <= stackSize); QV4::CallData *callData = reinterpret_cast(stack + instr.callData); - callData->tag = QV4::Value::Integer_Type_Internal; + callData->tag = quint32(Value::ValueTypeInternal::Integer); callData->argc = instr.argc; callData->thisObject = QV4::Primitive::undefinedValue(); STOREVALUE(instr.result, Runtime::method_constructGlobalLookup(engine, instr.index, callData)); -- cgit v1.2.3 From f7d758762e1680b1aca928e2b773803dc2515ad5 Mon Sep 17 00:00:00 2001 From: Nico Vertriest Date: Thu, 30 Mar 2017 15:25:22 +0200 Subject: Doc: add new enumeration descriptions qsgmaterial.cpp:416: warning: Undocumented enum item 'DirtyCachedMaterialData' in QSGMaterialShader::RenderState::DirtyState qsgmaterial.cpp:416: warning: Undocumented enum item 'DirtyAll' in QSGMaterialShader::RenderState::DirtyState qsgnode.cpp:104: warning: Undocumented enum item 'DirtySubtreeBlocked' in QSGNode::DirtyStateBit qsgnode.cpp:139: warning: Undocumented enum item 'RenderNodeType' in QSGNode::NodeType qsgengine.cpp:75: warning: Undocumented enum item 'TextureIsOpaque' in QSGEngine::CreateTextureOption Change-Id: Ia51d414151e42eddc5fa1198d3bad3ecbc20e30a Reviewed-by: Laszlo Agocs --- src/quick/scenegraph/coreapi/qsgmaterial.cpp | 4 ++++ src/quick/scenegraph/coreapi/qsgnode.cpp | 2 ++ src/quick/scenegraph/util/qsgengine.cpp | 2 ++ 3 files changed, 8 insertions(+) (limited to 'src') diff --git a/src/quick/scenegraph/coreapi/qsgmaterial.cpp b/src/quick/scenegraph/coreapi/qsgmaterial.cpp index 8d666d3d0b..07dc87a643 100644 --- a/src/quick/scenegraph/coreapi/qsgmaterial.cpp +++ b/src/quick/scenegraph/coreapi/qsgmaterial.cpp @@ -419,6 +419,10 @@ void QSGMaterialShader::compile() \value DirtyMatrix Used to indicate that the matrix has changed and must be updated. \value DirtyOpacity Used to indicate that the opacity has changed and must be updated. + + \value DirtyCachedMaterialData Used to indicate that the cached material data have changed and must be updated. + + \value DirtyAll Used to indicate that everything needs to be updated. */ diff --git a/src/quick/scenegraph/coreapi/qsgnode.cpp b/src/quick/scenegraph/coreapi/qsgnode.cpp index 7ef75d4b4c..7ac3914023 100644 --- a/src/quick/scenegraph/coreapi/qsgnode.cpp +++ b/src/quick/scenegraph/coreapi/qsgnode.cpp @@ -112,6 +112,7 @@ static void qt_print_node_count() \value DirtyGeometry The geometry of a QSGGeometryNode has changed. \value DirtyMaterial The material of a QSGGeometryNode has changed. \value DirtyOpacity The opacity of a QSGOpacityNode has changed. + \value DirtySubtreeBlocked The subtree has been blocked. \sa QSGNode::markDirty() */ @@ -146,6 +147,7 @@ static void qt_print_node_count() \value TransformNodeType The type of QSGTransformNode \value ClipNodeType The type of QSGClipNode \value OpacityNodeType The type of QSGOpacityNode + \value RenderNodeType The type of QSGRenderNode \sa type() */ diff --git a/src/quick/scenegraph/util/qsgengine.cpp b/src/quick/scenegraph/util/qsgengine.cpp index 09e4cdf5a7..259e45c978 100644 --- a/src/quick/scenegraph/util/qsgengine.cpp +++ b/src/quick/scenegraph/util/qsgengine.cpp @@ -84,6 +84,8 @@ QT_BEGIN_NAMESPACE will delete the GL texture when the texture object is deleted. \value TextureCanUseAtlas The image can be uploaded into a texture atlas. + + \value TextureIsOpaque The texture object is opaque. */ QSGEnginePrivate::QSGEnginePrivate() -- cgit v1.2.3 From ec465af245e90598039c4aabab9641922db34394 Mon Sep 17 00:00:00 2001 From: Simon Hausmann Date: Thu, 30 Mar 2017 15:42:34 +0200 Subject: Fix arithmetic with constants inside eval() calls on 32-bit architectures On 32-bit architectures we usually use an external constants table, which we need to make visible in the context. Change-Id: I0f7d813da1c6c893b8dd641dab5685a6db7fa9fa Reviewed-by: Robin Burchell --- src/qml/jsruntime/qv4globalobject.cpp | 1 + 1 file changed, 1 insertion(+) (limited to 'src') diff --git a/src/qml/jsruntime/qv4globalobject.cpp b/src/qml/jsruntime/qv4globalobject.cpp index 1bc91f832b..f0630660d4 100644 --- a/src/qml/jsruntime/qv4globalobject.cpp +++ b/src/qml/jsruntime/qv4globalobject.cpp @@ -394,6 +394,7 @@ void EvalFunction::evalCall(Scope &scope, CallData *callData, bool directCall) c // set the correct strict mode flag on the context ctx->d()->strictMode = false; ctx->d()->compilationUnit = function->compilationUnit; + ctx->d()->constantTable = function->compilationUnit->constants; scope.result = Q_V4_PROFILE(ctx->engine(), function); } -- cgit v1.2.3 From da6fd9c762561d41ce3372c98a555771d18241d6 Mon Sep 17 00:00:00 2001 From: Simon Hausmann Date: Tue, 28 Mar 2017 14:47:40 +0200 Subject: Fix encoding of primitive constants when cross-compiling QV4::Primitive is using host value encoding, which can differ from the target. The source of QV4::Primitive in the code generator is usually IR::Const, transformed via convertToValue(). That function becomes a template that converts to a simple target primitive type. Change-Id: If028aea9551d77d81eec306f60fd995c25b76710 Reviewed-by: Lars Knoll --- src/qml/compiler/qv4isel_util_p.h | 76 +++++++++++++++++++++++++++++++++------ src/qml/jit/qv4assembler.cpp | 12 +++---- src/qml/jit/qv4assembler_p.h | 43 +++++++++++----------- src/qml/jit/qv4isel_masm.cpp | 12 +++---- 4 files changed, 100 insertions(+), 43 deletions(-) (limited to 'src') diff --git a/src/qml/compiler/qv4isel_util_p.h b/src/qml/compiler/qv4isel_util_p.h index 1755193d32..e949e6f0ad 100644 --- a/src/qml/compiler/qv4isel_util_p.h +++ b/src/qml/compiler/qv4isel_util_p.h @@ -58,6 +58,59 @@ QT_BEGIN_NAMESPACE namespace QV4 { +struct TargetPrimitive32 { + static TargetPrimitive32 emptyValue() { TargetPrimitive32 p; p._val = quint64(Value::ValueTypeInternal_32::Empty) << 32; return p; } + static TargetPrimitive32 nullValue() { TargetPrimitive32 p; p._val = quint64(Value::ValueTypeInternal_32::Null) << 32; return p; } + static TargetPrimitive32 undefinedValue() { TargetPrimitive32 p; p._val = quint64(Value::Managed_Type_Internal_32) << 32; return p; } + static TargetPrimitive32 fromBoolean(bool b) { TargetPrimitive32 p; p._val = quint64(Value::ValueTypeInternal_32::Boolean) << 32 | quint64(b); return p; } + static TargetPrimitive32 fromInt32(int v) { TargetPrimitive32 p; p._val = quint64(Value::ValueTypeInternal_32::Integer) << 32 | quint32(v); return p; } + static TargetPrimitive32 fromDouble(double v) { + TargetPrimitive32 p; + memcpy(&p._val, &v, 8); + return p; + } + static TargetPrimitive32 fromUInt32(uint v) { + if (v < INT_MAX) + return fromInt32(qint32(v)); + return fromDouble(double(v)); + } + + quint32 value() const { return _val & quint64(~quint32(0)); } + quint32 tag() const { return _val >> 32; } + + quint64 rawValue() const { return _val; } + +private: + quint64 _val; +}; + +struct TargetPrimitive64 { + static TargetPrimitive64 emptyValue() { TargetPrimitive64 p; p._val = quint64(Value::ValueTypeInternal_64::Empty) << 32; return p; } + static TargetPrimitive64 nullValue() { TargetPrimitive64 p; p._val = quint64(Value::ValueTypeInternal_64::Null) << 32; return p; } + static TargetPrimitive64 undefinedValue() { TargetPrimitive64 p; p._val = 0; return p; } + static TargetPrimitive64 fromBoolean(bool b) { TargetPrimitive64 p; p._val = quint64(Value::ValueTypeInternal_64::Boolean) << 32 | quint64(b); return p; } + static TargetPrimitive64 fromInt32(int v) { TargetPrimitive64 p; p._val = quint64(Value::ValueTypeInternal_64::Integer) << 32 | quint32(v); return p; } + static TargetPrimitive64 fromDouble(double v) { + TargetPrimitive64 p; + memcpy(&p._val, &v, 8); + p._val ^= Value::NaNEncodeMask; + return p; + } + static TargetPrimitive64 fromUInt32(uint v) { + if (v < INT_MAX) + return fromInt32(qint32(v)); + return fromDouble(double(v)); + } + + quint32 value() const { return _val & quint64(~quint32(0)); } + quint32 tag() const { return _val >> 32; } + + quint64 rawValue() const { return _val; } + +private: + quint64 _val; +}; + inline bool canConvertToSignedInteger(double value) { int ival = (int) value; @@ -72,36 +125,37 @@ inline bool canConvertToUnsignedInteger(double value) return uval == value && !(value == 0 && isNegative(value)); } -inline Primitive convertToValue(IR::Const *c) +template +inline PrimitiveType convertToValue(IR::Const *c) { switch (c->type) { case IR::MissingType: - return Primitive::emptyValue(); + return PrimitiveType::emptyValue(); case IR::NullType: - return Primitive::nullValue(); + return PrimitiveType::nullValue(); case IR::UndefinedType: - return Primitive::undefinedValue(); + return PrimitiveType::undefinedValue(); case IR::BoolType: - return Primitive::fromBoolean(c->value != 0); + return PrimitiveType::fromBoolean(c->value != 0); case IR::SInt32Type: - return Primitive::fromInt32(int(c->value)); + return PrimitiveType::fromInt32(int(c->value)); case IR::UInt32Type: - return Primitive::fromUInt32(unsigned(c->value)); + return PrimitiveType::fromUInt32(unsigned(c->value)); case IR::DoubleType: - return Primitive::fromDouble(c->value); + return PrimitiveType::fromDouble(c->value); case IR::NumberType: { int ival = (int)c->value; if (canConvertToSignedInteger(c->value)) { - return Primitive::fromInt32(ival); + return PrimitiveType::fromInt32(ival); } else { - return Primitive::fromDouble(c->value); + return PrimitiveType::fromDouble(c->value); } } default: Q_UNREACHABLE(); } // unreachable, but the function must return something - return Primitive::undefinedValue(); + return PrimitiveType::undefinedValue(); } class ConvertTemps diff --git a/src/qml/jit/qv4assembler.cpp b/src/qml/jit/qv4assembler.cpp index daa732810b..da2cd49a63 100644 --- a/src/qml/jit/qv4assembler.cpp +++ b/src/qml/jit/qv4assembler.cpp @@ -319,15 +319,15 @@ typename Assembler::Pointer Assembler: template typename Assembler::Address Assembler::loadConstant(IR::Const *c, RegisterID baseReg) { - return loadConstant(convertToValue(c), baseReg); + return loadConstant(convertToValue(c), baseReg); } template -typename Assembler::Address Assembler::loadConstant(const Primitive &v, RegisterID baseReg) +typename Assembler::Address Assembler::loadConstant(const TargetPrimitive &v, RegisterID baseReg) { loadPtr(Address(Assembler::EngineRegister, targetStructureOffset(offsetof(QV4::EngineBase, current))), baseReg); loadPtr(Address(baseReg, targetStructureOffset(Heap::ExecutionContext::baseOffset + offsetof(Heap::ExecutionContextData, constantTable))), baseReg); - const int index = _jsGenerator->registerConstant(v.asReturnedValue()); + const int index = _jsGenerator->registerConstant(v.rawValue()); return Address(baseReg, index * sizeof(QV4::Value)); } @@ -339,7 +339,7 @@ void Assembler::loadStringRef(RegisterID reg, const QString } template -void Assembler::storeValue(QV4::Primitive value, IR::Expr *destination) +void Assembler::storeValue(TargetPrimitive value, IR::Expr *destination) { Address addr = loadAddress(ScratchRegister, destination); storeValue(value, addr); @@ -518,7 +518,7 @@ void Assembler::returnFromFunction(IR::Ret *s, RegisterInfo } else if (IR::Temp *t = s->expr->asTemp()) { RegisterSizeDependentOps::setFunctionReturnValueFromTemp(this, t); } else if (IR::Const *c = s->expr->asConst()) { - QV4::Primitive retVal = convertToValue(c); + auto retVal = convertToValue(c); RegisterSizeDependentOps::setFunctionReturnValueFromConst(this, retVal); } else { Q_UNREACHABLE(); @@ -535,7 +535,7 @@ void Assembler::returnFromFunction(IR::Ret *s, RegisterInfo ret(); exceptionReturnLabel = label(); - QV4::Primitive retVal = Primitive::undefinedValue(); + auto retVal = TargetPrimitive::undefinedValue(); RegisterSizeDependentOps::setFunctionReturnValueFromConst(this, retVal); jump(leaveStackFrame); } diff --git a/src/qml/jit/qv4assembler_p.h b/src/qml/jit/qv4assembler_p.h index ad6c29dd49..fed51e5e94 100644 --- a/src/qml/jit/qv4assembler_p.h +++ b/src/qml/jit/qv4assembler_p.h @@ -154,6 +154,7 @@ struct RegisterSizeDependentAssemblerstoreDouble(source, ptr); } - static void storeValue(JITAssembler *as, QV4::Primitive value, Address destination) + static void storeValue(JITAssembler *as, TargetPrimitive value, Address destination) { - as->store32(TrustedImm32(value.int_32()), destination); + as->store32(TrustedImm32(value.value()), destination); destination.offset += 4; as->store32(TrustedImm32(value.tag()), destination); } @@ -243,9 +244,9 @@ struct RegisterSizeDependentAssemblermove(TrustedImm32(retVal.int_32()), TargetPlatform::LowReturnValueRegister); + as->move(TrustedImm32(retVal.value()), TargetPlatform::LowReturnValueRegister); as->move(TrustedImm32(retVal.tag()), TargetPlatform::HighReturnValueRegister); } @@ -387,6 +388,7 @@ struct RegisterSizeDependentAssemblermove(TrustedImm64(retVal.rawValue()), TargetPlatform::ReturnValueRegister); } - static void storeValue(JITAssembler *as, QV4::Primitive value, Address destination) + static void storeValue(JITAssembler *as, TargetPrimitive value, Address destination) { as->store64(TrustedImm64(value.rawValue()), destination); } @@ -505,7 +507,7 @@ struct RegisterSizeDependentAssemblerloadTempAddress(temp); as->load64(addr, dest); } else { - QV4::Value undefined = QV4::Primitive::undefinedValue(); + auto undefined = TargetPrimitive::undefinedValue(); as->move(TrustedImm64(undefined.rawValue()), dest); } } @@ -518,7 +520,7 @@ struct RegisterSizeDependentAssemblerloadArgLocalAddress(dest, al); as->load64(addr, dest); } else { - QV4::Value undefined = QV4::Primitive::undefinedValue(); + auto undefined = TargetPrimitive::undefinedValue(); as->move(TrustedImm64(undefined.rawValue()), dest); } } @@ -527,7 +529,7 @@ struct RegisterSizeDependentAssembler(c); as->move(TrustedImm64(v.rawValue()), dest); } @@ -536,7 +538,7 @@ struct RegisterSizeDependentAssemblermove(TrustedImm64(undefined.rawValue()), dest); } else if (IR::Temp *t = expr->asTemp()){ loadArgumentInRegister(as, t, dest, argumentNumber); @@ -755,6 +757,7 @@ public: using RegisterSizeDependentOps = RegisterSizeDependentAssembler, MacroAssembler, JITTargetPlatform, RegisterSize>; using ValueTypeInternal = typename RegisterSizeDependentOps::ValueTypeInternal; + using TargetPrimitive = typename RegisterSizeDependentOps::TargetPrimitive; // V4 uses two stacks: one stack with QV4::Value items, which is checked by the garbage // collector, and one stack used by the native C/C++/ABI code. This C++ stack is not scanned @@ -978,7 +981,7 @@ public: Pointer loadArgLocalAddress(RegisterID baseReg, IR::ArgLocal *al); Pointer loadStringAddress(RegisterID reg, const QString &string); Address loadConstant(IR::Const *c, RegisterID baseReg); - Address loadConstant(const Primitive &v, RegisterID baseReg); + Address loadConstant(const TargetPrimitive &v, RegisterID baseReg); void loadStringRef(RegisterID reg, const QString &string); Pointer stackSlotPointer(IR::Temp *t) const { @@ -1240,12 +1243,12 @@ public: TargetConfiguration::MacroAssembler::storeDouble(fpScratchRegister, loadAddress(scratchRegister, target)); } - void storeValue(QV4::Primitive value, Address destination) + void storeValue(TargetPrimitive value, Address destination) { RegisterSizeDependentOps::storeValue(this, value, destination); } - void storeValue(QV4::Primitive value, IR::Expr* temp); + void storeValue(TargetPrimitive value, IR::Expr* temp); void enterStandardStackFrame(const RegisterInformation ®ularRegistersToSave, const RegisterInformation &fpRegistersToSave); @@ -1422,8 +1425,8 @@ public: Address tagAddr = addr; tagAddr.offset += 4; - QV4::Primitive v = convertToValue(c); - store32(TrustedImm32(v.int_32()), addr); + auto v = convertToValue(c); + store32(TrustedImm32(v.value()), addr); store32(TrustedImm32(v.tag()), tagAddr); return Pointer(addr); } @@ -1439,7 +1442,7 @@ public: { store32(reg, addr); addr.offset += 4; - store32(TrustedImm32(QV4::Primitive::fromBoolean(0).tag()), addr); + store32(TrustedImm32(TargetPrimitive::fromBoolean(0).tag()), addr); } void storeBool(RegisterID src, RegisterID dest) @@ -1483,7 +1486,7 @@ public: { store32(reg, addr); addr.offset += 4; - store32(TrustedImm32(QV4::Primitive::fromInt32(0).tag()), addr); + store32(TrustedImm32(TargetPrimitive::fromInt32(0).tag()), addr); } void storeInt32(RegisterID reg, IR::Expr *target) @@ -1552,7 +1555,7 @@ public: RegisterID toInt32Register(IR::Expr *e, RegisterID scratchReg) { if (IR::Const *c = e->asConst()) { - move(TrustedImm32(convertToValue(c).int_32()), scratchReg); + move(TrustedImm32(convertToValue(c).int_32()), scratchReg); return scratchReg; } @@ -1595,7 +1598,7 @@ public: // it's not in signed int range, so load it as a double, and truncate it down loadDouble(addr, FPGpr0); - Address inversionAddress = loadConstant(QV4::Primitive::fromDouble(double(INT_MAX) + 1), scratchReg); + Address inversionAddress = loadConstant(TargetPrimitive::fromDouble(double(INT_MAX) + 1), scratchReg); subDouble(inversionAddress, FPGpr0); Jump canNeverHappen = branchTruncateDoubleToUint32(FPGpr0, scratchReg); canNeverHappen.link(this); @@ -1675,7 +1678,7 @@ void Assembler::copyValue(Result result, IR::Expr* source) } else if (source->asTemp() || source->asArgLocal()) { RegisterSizeDependentOps::copyValueViaRegisters(this, source, result); } else if (IR::Const *c = source->asConst()) { - QV4::Primitive v = convertToValue(c); + auto v = convertToValue(c); storeValue(v, result); } else { Q_UNREACHABLE(); diff --git a/src/qml/jit/qv4isel_masm.cpp b/src/qml/jit/qv4isel_masm.cpp index 126fb4382b..dd48fdfc55 100644 --- a/src/qml/jit/qv4isel_masm.cpp +++ b/src/qml/jit/qv4isel_masm.cpp @@ -256,7 +256,7 @@ void InstructionSelection::callBuiltinDeleteName(const QString &na template void InstructionSelection::callBuiltinDeleteValue(IR::Expr *result) { - _as->storeValue(Primitive::fromBoolean(false), result); + _as->storeValue(JITAssembler::TargetPrimitive::fromBoolean(false), result); } template @@ -376,7 +376,7 @@ void InstructionSelection::callBuiltinDefineObjectLiteral(IR::Expr ++arrayValueCount; // Index - _as->storeValue(QV4::Primitive::fromUInt32(index), _as->stackLayout().argumentAddressForCall(argc++)); + _as->storeValue(JITAssembler::TargetPrimitive::fromUInt32(index), _as->stackLayout().argumentAddressForCall(argc++)); // Value _as->copyValue(_as->stackLayout().argumentAddressForCall(argc++), it->expr); @@ -400,7 +400,7 @@ void InstructionSelection::callBuiltinDefineObjectLiteral(IR::Expr ++arrayGetterSetterCount; // Index - _as->storeValue(QV4::Primitive::fromUInt32(index), _as->stackLayout().argumentAddressForCall(argc++)); + _as->storeValue(JITAssembler::TargetPrimitive::fromUInt32(index), _as->stackLayout().argumentAddressForCall(argc++)); // Getter _as->copyValue(_as->stackLayout().argumentAddressForCall(argc++), it->expr); @@ -486,7 +486,7 @@ void InstructionSelection::loadConst(IR::Const *sourceConst, IR::E _as->toUInt32Register(sourceConst, (RegisterID) targetTemp->index); } else if (targetTemp->type == IR::BoolType) { Q_ASSERT(sourceConst->type == IR::BoolType); - _as->move(TrustedImm32(convertToValue(sourceConst).int_32()), + _as->move(TrustedImm32(convertToValue(sourceConst).int_32()), (RegisterID) targetTemp->index); } else { Q_UNREACHABLE(); @@ -495,7 +495,7 @@ void InstructionSelection::loadConst(IR::Const *sourceConst, IR::E } } - _as->storeValue(convertToValue(sourceConst), target); + _as->storeValue(convertToValue(sourceConst), target); } template @@ -1320,7 +1320,7 @@ int InstructionSelection::prepareCallData(IR::ExprList* args, IR:: _as->store32(TrustedImm32(argc), p); p = _as->stackLayout().callDataAddress(offsetof(CallData, thisObject)); if (!thisObject) - _as->storeValue(QV4::Primitive::undefinedValue(), p); + _as->storeValue(JITAssembler::TargetPrimitive::undefinedValue(), p); else _as->copyValue(p, thisObject); -- cgit v1.2.3 From 9b4d31825e5f76e91af555549223ea6b33dd37e6 Mon Sep 17 00:00:00 2001 From: Ulf Hermann Date: Wed, 15 Mar 2017 12:12:22 +0100 Subject: Qml Debugger: Make sure all objects have a type QQmlMetaType::prettyTypeName() does a better job in finding a valid type name for our objects than we can do ourselves. Task-number: QTCREATORBUG-17741 Change-Id: Ie8a192aceb230e73b5295b745987692548aff641 Reviewed-by: Simon Hausmann --- .../qmltooling/qmldbg_debugger/qqmlenginedebugservice.cpp | 13 +------------ 1 file changed, 1 insertion(+), 12 deletions(-) (limited to 'src') diff --git a/src/plugins/qmltooling/qmldbg_debugger/qqmlenginedebugservice.cpp b/src/plugins/qmltooling/qmldbg_debugger/qqmlenginedebugservice.cpp index 151e44c4d4..3fb0522cd1 100644 --- a/src/plugins/qmltooling/qmldbg_debugger/qqmlenginedebugservice.cpp +++ b/src/plugins/qmltooling/qmldbg_debugger/qqmlenginedebugservice.cpp @@ -409,18 +409,7 @@ QQmlEngineDebugServiceImpl::objectData(QObject *object) rv.objectId = QQmlDebugService::idForObject(object); rv.contextId = QQmlDebugService::idForObject(qmlContext(object)); rv.parentId = QQmlDebugService::idForObject(object->parent()); - QQmlType *type = QQmlMetaType::qmlType(object->metaObject()); - if (type) { - QString typeName = type->qmlTypeName(); - int lastSlash = typeName.lastIndexOf(QLatin1Char('/')); - rv.objectType = lastSlash < 0 ? typeName : typeName.mid(lastSlash+1); - } else { - rv.objectType = QString::fromUtf8(object->metaObject()->className()); - int marker = rv.objectType.indexOf(QLatin1String("_QMLTYPE_")); - if (marker != -1) - rv.objectType = rv.objectType.left(marker); - } - + rv.objectType = QQmlMetaType::prettyTypeName(object); return rv; } -- cgit v1.2.3 From 8132d628b1568cb750a61bc95c5b0632595e2854 Mon Sep 17 00:00:00 2001 From: Joerg Bornemann Date: Thu, 23 Mar 2017 17:00:05 +0100 Subject: Simplify shortcut override handling Use QInputControl::isCommonTextEditShortcut to determine when to accept a ShortcutOverride event. This removes the code that was duplicated from QWidgetTextControl. Change-Id: Ia4a251e3870803bdb7b3943075003fddabae924b Reviewed-by: Simon Hausmann --- src/quick/items/qquicktextcontrol.cpp | 46 +---------------------------------- 1 file changed, 1 insertion(+), 45 deletions(-) (limited to 'src') diff --git a/src/quick/items/qquicktextcontrol.cpp b/src/quick/items/qquicktextcontrol.cpp index 555fd233b3..2dce3e9ec8 100644 --- a/src/quick/items/qquicktextcontrol.cpp +++ b/src/quick/items/qquicktextcontrol.cpp @@ -769,52 +769,8 @@ void QQuickTextControl::processEvent(QEvent *e, const QMatrix &matrix) case QEvent::ShortcutOverride: if (d->interactionFlags & Qt::TextEditable) { QKeyEvent* ke = static_cast(e); - if (ke->modifiers() == Qt::NoModifier - || ke->modifiers() == Qt::ShiftModifier - || ke->modifiers() == Qt::KeypadModifier) { - if (ke->key() < Qt::Key_Escape) { - ke->accept(); - } else { - switch (ke->key()) { - case Qt::Key_Return: - case Qt::Key_Enter: - case Qt::Key_Delete: - case Qt::Key_Home: - case Qt::Key_End: - case Qt::Key_Backspace: - case Qt::Key_Left: - case Qt::Key_Right: - case Qt::Key_Up: - case Qt::Key_Down: - case Qt::Key_Tab: - ke->accept(); - default: - break; - } - } -#if QT_CONFIG(shortcut) - } else if (ke == QKeySequence::Copy - || ke == QKeySequence::Paste - || ke == QKeySequence::Cut - || ke == QKeySequence::Redo - || ke == QKeySequence::Undo - || ke == QKeySequence::MoveToNextWord - || ke == QKeySequence::MoveToPreviousWord - || ke == QKeySequence::MoveToStartOfDocument - || ke == QKeySequence::MoveToEndOfDocument - || ke == QKeySequence::SelectNextWord - || ke == QKeySequence::SelectPreviousWord - || ke == QKeySequence::SelectStartOfLine - || ke == QKeySequence::SelectEndOfLine - || ke == QKeySequence::SelectStartOfBlock - || ke == QKeySequence::SelectEndOfBlock - || ke == QKeySequence::SelectStartOfDocument - || ke == QKeySequence::SelectEndOfDocument - || ke == QKeySequence::SelectAll - ) { + if (isCommonTextEditShortcut(ke)) ke->accept(); -#endif - } } break; default: -- cgit v1.2.3 From 0043fab778f2497f644c434a194b5c5eec851819 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Morten=20Johan=20S=C3=B8rvig?= Date: Thu, 30 Mar 2017 12:01:09 +0200 Subject: Fix QQuickCanvasItem::toImage() high-DPI capture Make toImage() work for devicePixelRatio > 1 by scaling the source rect. Also set the devicePixelRatio on the returned image. Task-number: QTBUG-59170 Change-Id: I0c8ccd562c1cf1e89ff37ca1806b46296480b0d0 Reviewed-by: Shawn Rutledge --- src/quick/items/context2d/qquickcanvasitem.cpp | 17 ++++++++++------- src/quick/items/context2d/qquickcontext2d.cpp | 2 +- 2 files changed, 11 insertions(+), 8 deletions(-) (limited to 'src') diff --git a/src/quick/items/context2d/qquickcanvasitem.cpp b/src/quick/items/context2d/qquickcanvasitem.cpp index da9379e7af..dab35f2a54 100644 --- a/src/quick/items/context2d/qquickcanvasitem.cpp +++ b/src/quick/items/context2d/qquickcanvasitem.cpp @@ -1104,14 +1104,17 @@ bool QQuickCanvasItem::isImageLoaded(const QUrl& url) const QImage QQuickCanvasItem::toImage(const QRectF& rect) const { Q_D(const QQuickCanvasItem); - if (d->context) { - if (rect.isEmpty()) - return d->context->toImage(canvasWindow()); - else - return d->context->toImage(rect); - } - return QImage(); + if (!d->context) + return QImage(); + + const QRectF &rectSource = rect.isEmpty() ? canvasWindow() : rect; + const qreal dpr = window() ? window()->effectiveDevicePixelRatio() : qreal(1); + const QRectF rectScaled(rectSource.topLeft() * dpr, rectSource.size() * dpr); + + QImage image = d->context->toImage(rectScaled); + image.setDevicePixelRatio(dpr); + return image; } static const char* mimeToType(const QString &mime) diff --git a/src/quick/items/context2d/qquickcontext2d.cpp b/src/quick/items/context2d/qquickcontext2d.cpp index ce890771d9..0a7db7fa97 100644 --- a/src/quick/items/context2d/qquickcontext2d.cpp +++ b/src/quick/items/context2d/qquickcontext2d.cpp @@ -962,7 +962,7 @@ static QV4::ReturnedValue qt_create_image_data(qreal w, qreal h, QV4::ExecutionE *pixelData->d()->image = QImage(w, h, QImage::Format_ARGB32); pixelData->d()->image->fill(0x00000000); } else { - Q_ASSERT(image.width() == qRound(w) && image.height() == qRound(h)); + Q_ASSERT(image.width()== qRound(w * image.devicePixelRatio()) && image.height() == qRound(h * image.devicePixelRatio())); *pixelData->d()->image = image.format() == QImage::Format_ARGB32 ? image : image.convertToFormat(QImage::Format_ARGB32); } -- cgit v1.2.3 From f261a534cc96d41cee15462795844116887bd99a Mon Sep 17 00:00:00 2001 From: Ulf Hermann Date: Fri, 31 Mar 2017 15:52:47 +0200 Subject: V4: Set correct source locations for jumps out of conditionals We always want to place the jump on the last line of the conditionally executed statement, unless we might never execute the last line. In the latter case, that is if the inner statement is again a conditional, we use some token of the outer condition. This works fine with loops, as the loop condition is actually checked after each iteration, and it's plausible to the user that we jump there. With "if" statements, it's not so great. We cannot really explain why we jump back to the "if" token after executing the conditional statement. However, we have to add some source location to the jump instruction as otherwise it uses the source location of the last statement that had one, which is rather random. Task-number: QTBUG-59204 Task-number: QTBUG-59774 Change-Id: I48e331ce1c1830f236e16b75c9201a2f490d2092 Reviewed-by: Simon Hausmann --- src/qml/compiler/qv4codegen.cpp | 37 +++++++++++++++++++++++++++++-------- 1 file changed, 29 insertions(+), 8 deletions(-) (limited to 'src') diff --git a/src/qml/compiler/qv4codegen.cpp b/src/qml/compiler/qv4codegen.cpp index a10c0730bf..fcfbdfa74b 100644 --- a/src/qml/compiler/qv4codegen.cpp +++ b/src/qml/compiler/qv4codegen.cpp @@ -92,6 +92,27 @@ static bool cjumpCanHandle(IR::AluOp op) } } +static inline void setJumpOutLocation(IR::Stmt *s, const Statement *body, + const SourceLocation &fallback) +{ + switch (body->kind) { + // Statements where we might never execute the last line. + // Use the fallback. + case Statement::Kind_ConditionalExpression: + case Statement::Kind_ForEachStatement: + case Statement::Kind_ForStatement: + case Statement::Kind_IfStatement: + case Statement::Kind_LocalForEachStatement: + case Statement::Kind_LocalForStatement: + case Statement::Kind_WhileStatement: + setLocation(s, fallback); + break; + default: + setLocation(s, body->lastSourceLocation()); + break; + } +} + Codegen::ScanFunctions::ScanFunctions(Codegen *cg, const QString &sourceCode, CompilationMode defaultProgramMode) : _cg(cg) , _sourceCode(sourceCode) @@ -2256,7 +2277,7 @@ bool Codegen::visit(DoWhileStatement *ast) _block = loopbody; statement(ast->statement); - setLocation(_block->JUMP(loopcond), ast->statement->lastSourceLocation()); + setJumpOutLocation(_block->JUMP(loopcond), ast->statement, ast->semicolonToken); _block = loopcond; condition(ast->expression, loopbody, loopend); @@ -2321,7 +2342,7 @@ bool Codegen::visit(ForEachStatement *ast) return false; move(*init, _block->TEMP(temp)); statement(ast->statement); - setLocation(_block->JUMP(foreachin), ast->lastSourceLocation()); + setJumpOutLocation(_block->JUMP(foreachin), ast->statement, ast->forToken); _block = foreachin; @@ -2360,7 +2381,7 @@ bool Codegen::visit(ForStatement *ast) _block = forbody; statement(ast->statement); - setLocation(_block->JUMP(forstep), ast->lastSourceLocation()); + setJumpOutLocation(_block->JUMP(forstep), ast->statement, ast->forToken); _block = forstep; statement(ast->expression); @@ -2386,12 +2407,12 @@ bool Codegen::visit(IfStatement *ast) _block = iftrue; statement(ast->ok); - _block->JUMP(endif); + setJumpOutLocation(_block->JUMP(endif), ast->ok, ast->ifToken); if (ast->ko) { _block = iffalse; statement(ast->ko); - _block->JUMP(endif); + setJumpOutLocation(_block->JUMP(endif), ast->ko, ast->elseToken); } _block = endif; @@ -2460,7 +2481,7 @@ bool Codegen::visit(LocalForEachStatement *ast) int temp = _block->newTemp(); move(identifier(ast->declaration->name.toString()), _block->TEMP(temp)); statement(ast->statement); - setLocation(_block->JUMP(foreachin), ast->lastSourceLocation()); + setJumpOutLocation(_block->JUMP(foreachin), ast->statement, ast->forToken); _block = foreachin; @@ -2499,7 +2520,7 @@ bool Codegen::visit(LocalForStatement *ast) _block = forbody; statement(ast->statement); - setLocation(_block->JUMP(forstep), ast->lastSourceLocation()); + setJumpOutLocation(_block->JUMP(forstep), ast->statement, ast->forToken); _block = forstep; statement(ast->expression); @@ -2800,7 +2821,7 @@ bool Codegen::visit(WhileStatement *ast) _block = whilebody; statement(ast->statement); - setLocation(_block->JUMP(whilecond), ast->lastSourceLocation()); + setJumpOutLocation(_block->JUMP(whilecond), ast->statement, ast->whileToken); _block = whileend; leaveLoop(); -- cgit v1.2.3 From e76ffb62a2ee3eb14c9bfc61244deae4bb761f8f Mon Sep 17 00:00:00 2001 From: Tasuku Suzuki Date: Thu, 30 Mar 2017 17:41:52 +0900 Subject: Fix build without features.animation Change-Id: Ie45a2f01def64941a323973ea27446e3fc85a72b Reviewed-by: Robin Burchell Reviewed-by: Paul Olav Tvete --- src/qml/qml.pro | 4 +++- src/qml/qml/qqmlengine.cpp | 4 ++++ src/qml/types/types.pri | 10 ++++++++-- 3 files changed, 15 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/src/qml/qml.pro b/src/qml/qml.pro index 8f9e4b7f83..be3956bb61 100644 --- a/src/qml/qml.pro +++ b/src/qml/qml.pro @@ -48,7 +48,9 @@ include(jit/jit.pri) include(jsruntime/jsruntime.pri) include(qml/qml.pri) include(debugger/debugger.pri) -include(animations/animations.pri) +qtConfig(animation) { + include(animations/animations.pri) +} include(types/types.pri) MODULE_PLUGIN_TYPES = \ diff --git a/src/qml/qml/qqmlengine.cpp b/src/qml/qml/qqmlengine.cpp index a762564912..0521daae81 100644 --- a/src/qml/qml/qqmlengine.cpp +++ b/src/qml/qml/qqmlengine.cpp @@ -82,7 +82,9 @@ #include #include #include +#if QT_CONFIG(animation) #include +#endif #include #include #include @@ -218,7 +220,9 @@ void QQmlEnginePrivate::registerBaseTypes(const char *uri, int versionMajor, int qmlRegisterType(uri, versionMajor, (versionMinor < 8 ? 8 : versionMinor), "Binding"); //Only available in >=2.8 qmlRegisterType(uri, versionMajor, (versionMinor < 3 ? 3 : versionMinor), "Connections"); //Only available in >=2.3 qmlRegisterType(uri, versionMajor, versionMinor,"Connections"); +#if QT_CONFIG(animation) qmlRegisterType(uri, versionMajor, versionMinor,"Timer"); +#endif qmlRegisterType(uri, versionMajor, (versionMinor < 1 ? 1 : versionMinor), "Instantiator"); //Only available in >=2.1 qmlRegisterCustomType(uri, versionMajor, versionMinor,"Connections", new QQmlConnectionsParser); qmlRegisterType(); diff --git a/src/qml/types/types.pri b/src/qml/types/types.pri index d2e5020738..e85ab5982b 100644 --- a/src/qml/types/types.pri +++ b/src/qml/types/types.pri @@ -7,7 +7,6 @@ SOURCES += \ $$PWD/qqmlmodelsmodule.cpp \ $$PWD/qqmlmodelindexvaluetype.cpp \ $$PWD/qqmlobjectmodel.cpp \ - $$PWD/qqmltimer.cpp \ $$PWD/qquickpackage.cpp \ $$PWD/qquickworkerscript.cpp \ $$PWD/qqmlinstantiator.cpp @@ -23,8 +22,15 @@ HEADERS += \ $$PWD/qqmlmodelsmodule_p.h \ $$PWD/qqmlmodelindexvaluetype_p.h \ $$PWD/qqmlobjectmodel_p.h \ - $$PWD/qqmltimer_p.h \ $$PWD/qquickpackage_p.h \ $$PWD/qquickworkerscript_p.h \ $$PWD/qqmlinstantiator_p.h \ $$PWD/qqmlinstantiator_p_p.h + +qtConfig(animation) { + SOURCES += \ + $$PWD/qqmltimer.cpp + + HEADERS += \ + $$PWD/qqmltimer_p.h +} -- cgit v1.2.3 From 7a196365726e21b8dc1718542dcc349a6b7dc5c4 Mon Sep 17 00:00:00 2001 From: Thiago Macieira Date: Sun, 2 Apr 2017 20:53:36 -0700 Subject: Fix compilation with the Intel compiler The template function isn't necessary anymore. It actually breaks the build... ARM64Assembler.h(3275): error: no instance of function template "assertUnused" matches the argument list argument types are: (bool) Assertions.h(238): note: this candidate was rejected because arguments do not match Change-Id: I27b55fdf514247549455fffd14b1c6dfe92f2b88 Reviewed-by: Simon Hausmann --- src/3rdparty/masm/wtf/Assertions.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/3rdparty/masm/wtf/Assertions.h b/src/3rdparty/masm/wtf/Assertions.h index 6263e50ed9..af65f5325c 100644 --- a/src/3rdparty/masm/wtf/Assertions.h +++ b/src/3rdparty/masm/wtf/Assertions.h @@ -233,7 +233,7 @@ WTF_EXPORT_PRIVATE void WTFInstallReportBacktraceOnCrashHook(); #define ASSERT_NOT_REACHED() ((void)0) #define NO_RETURN_DUE_TO_ASSERT -#if COMPILER(INTEL) && !OS(WINDOWS) || COMPILER(RVCT) +#if COMPILER(RVCT) template inline void assertUnused(T& x) { (void)x; } #define ASSERT_UNUSED(variable, assertion) (assertUnused(variable)) -- cgit v1.2.3 From 0577c872a33156f7bb5a74c7ff874191a8d6f170 Mon Sep 17 00:00:00 2001 From: Thiago Macieira Date: Sat, 1 Apr 2017 21:05:09 -0700 Subject: Fix Clang warning about member in template class not defined qv4isel_masm.cpp:285:44: warning: instantiation of variable 'QV4::JIT::Assembler>::Void' required here, but no definition is available [-Wundefined-var-template] Depending on qv4assembler.cpp instantiating the same template that q4isel_masm.pp required is fragile. So move the definition to the header, next to the class. Change-Id: I27b55fdf514247549455fffd14b178ec9d4b508d Reviewed-by: Simon Hausmann --- src/qml/jit/qv4assembler.cpp | 3 --- src/qml/jit/qv4assembler_p.h | 3 +++ 2 files changed, 3 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/src/qml/jit/qv4assembler.cpp b/src/qml/jit/qv4assembler.cpp index da2cd49a63..0d06b421f6 100644 --- a/src/qml/jit/qv4assembler.cpp +++ b/src/qml/jit/qv4assembler.cpp @@ -155,9 +155,6 @@ bool CompilationUnit::saveCodeToDisk(QIODevice *device, const CompiledData::Unit return true; } -template -const typename Assembler::VoidType Assembler::Void; - template Assembler::Assembler(QV4::Compiler::JSUnitGenerator *jsGenerator, IR::Function* function, QV4::ExecutableAllocator *executableAllocator) : _function(function) diff --git a/src/qml/jit/qv4assembler_p.h b/src/qml/jit/qv4assembler_p.h index fed51e5e94..0570b9be2b 100644 --- a/src/qml/jit/qv4assembler_p.h +++ b/src/qml/jit/qv4assembler_p.h @@ -1653,6 +1653,9 @@ private: QV4::Compiler::JSUnitGenerator *_jsGenerator; }; +template +const typename Assembler::VoidType Assembler::Void; + template template void Assembler::copyValue(Result result, Source source) -- cgit v1.2.3 From 9479139673a0c73cd650270aa25440b9e64aa5ef Mon Sep 17 00:00:00 2001 From: Mitch Curtis Date: Sun, 2 Apr 2017 17:15:11 +0200 Subject: Doc: remove const from QQmlListProperty getter The function cannot be const, as QQmlListProperty's constructor expects a non-const reference. Errors can result from following the docs: '': cannot convert from 'initializer list' to 'QQmlListProperty' Change-Id: I2268ab08a130181857c21340604a2251ba66967e Reviewed-by: J-P Nurmi --- src/qml/doc/src/cppintegration/definetypes.qdoc | 2 +- src/qml/doc/src/cppintegration/exposecppattributes.qdoc | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/qml/doc/src/cppintegration/definetypes.qdoc b/src/qml/doc/src/cppintegration/definetypes.qdoc index 7d4a543089..32084bd308 100644 --- a/src/qml/doc/src/cppintegration/definetypes.qdoc +++ b/src/qml/doc/src/cppintegration/definetypes.qdoc @@ -687,7 +687,7 @@ class MessageBoard : public QObject Q_PROPERTY(QQmlListProperty messages READ messages) Q_CLASSINFO("DefaultProperty", "messages") public: - QQmlListProperty messages() const; + QQmlListProperty messages(); private: QList messages; diff --git a/src/qml/doc/src/cppintegration/exposecppattributes.qdoc b/src/qml/doc/src/cppintegration/exposecppattributes.qdoc index 3bffd2eb6f..c4c58c2821 100644 --- a/src/qml/doc/src/cppintegration/exposecppattributes.qdoc +++ b/src/qml/doc/src/cppintegration/exposecppattributes.qdoc @@ -267,7 +267,7 @@ class MessageBoard : public QObject Q_OBJECT Q_PROPERTY(QQmlListProperty messages READ messages) public: - QQmlListProperty messages() const; + QQmlListProperty messages(); private: static void append_message(QQmlListProperty *list, Message *msg); -- cgit v1.2.3 From ab0c47e5ef03eab9c80246e4d5c1af53a29ab0e1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20Str=C3=B8mme?= Date: Thu, 23 Mar 2017 13:35:06 +0100 Subject: Add missing override specifiers Build failed on Android when using clang. error: '' overrides a member function but is not marked 'override' [-Werror,-Winconsistent-missing-override] Change-Id: I080f8145b5a1c12bacf99f9c08f9e78271e5837a Reviewed-by: Frederik Gladhorn --- src/quick/accessible/qaccessiblequickview_p.h | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) (limited to 'src') diff --git a/src/quick/accessible/qaccessiblequickview_p.h b/src/quick/accessible/qaccessiblequickview_p.h index fcd0bec85e..39ffcaf39c 100644 --- a/src/quick/accessible/qaccessiblequickview_p.h +++ b/src/quick/accessible/qaccessiblequickview_p.h @@ -63,21 +63,21 @@ class QAccessibleQuickWindow : public QAccessibleObject public: QAccessibleQuickWindow(QQuickWindow *object); - QAccessibleInterface *parent() const; - QAccessibleInterface *child(int index) const; + QAccessibleInterface *parent() const override; + QAccessibleInterface *child(int index) const override; QAccessibleInterface *focusChild() const override; - QAccessible::Role role() const; - QAccessible::State state() const; - QRect rect() const; + QAccessible::Role role() const override; + QAccessible::State state() const override; + QRect rect() const override; - int childCount() const; - int indexOfChild(const QAccessibleInterface *iface) const; - QString text(QAccessible::Text text) const; - QAccessibleInterface *childAt(int x, int y) const; + int childCount() const override; + int indexOfChild(const QAccessibleInterface *iface) const override; + QString text(QAccessible::Text text) const override; + QAccessibleInterface *childAt(int x, int y) const override; private: - QQuickWindow *window() const { return static_cast(object()); } + QQuickWindow *window() const override { return static_cast(object()); } QList rootItems() const; }; -- cgit v1.2.3 From 4ba040b2e73ed2846e20589a57dbefca698c5352 Mon Sep 17 00:00:00 2001 From: Mitch Curtis Date: Wed, 22 Mar 2017 14:44:46 +0100 Subject: QQuickImage: only call updatePaintedGeometry() when necessary Changes in position don't affect the size of an image, so it isn't necessary to updated the paintedWidth/Height, or set implicitSize. Change-Id: Ib10476e970a016b65c250ce735d50d68acace34b Reviewed-by: Robin Burchell Reviewed-by: J-P Nurmi Reviewed-by: Gunnar Sletta --- src/quick/items/qquickimage.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/quick/items/qquickimage.cpp b/src/quick/items/qquickimage.cpp index f3d7dc4b56..bf982117e8 100644 --- a/src/quick/items/qquickimage.cpp +++ b/src/quick/items/qquickimage.cpp @@ -559,7 +559,8 @@ void QQuickImage::updatePaintedGeometry() void QQuickImage::geometryChanged(const QRectF &newGeometry, const QRectF &oldGeometry) { QQuickImageBase::geometryChanged(newGeometry, oldGeometry); - updatePaintedGeometry(); + if (newGeometry.size() != oldGeometry.size()) + updatePaintedGeometry(); } QRectF QQuickImage::boundingRect() const -- cgit v1.2.3 From 09aa8ba83fcd68608173d949f7f4de155befb1c8 Mon Sep 17 00:00:00 2001 From: Gunnar Sletta Date: Mon, 3 Apr 2017 09:45:32 +0200 Subject: Document that wrap modes do not work with atlas textures Change-Id: Ifa417644e10b947c4ca0b9c518cfd800b63142b5 Reviewed-by: Laszlo Agocs --- src/quick/scenegraph/util/qsgtexture.cpp | 2 ++ 1 file changed, 2 insertions(+) (limited to 'src') diff --git a/src/quick/scenegraph/util/qsgtexture.cpp b/src/quick/scenegraph/util/qsgtexture.cpp index bc59c49162..591b679ec4 100644 --- a/src/quick/scenegraph/util/qsgtexture.cpp +++ b/src/quick/scenegraph/util/qsgtexture.cpp @@ -256,6 +256,8 @@ static void qt_debug_remove_texture(QSGTexture* texture) Specifies how the texture should treat texture coordinates. + \note Texture wrapping needs to be handled explicitly for atlas textures. + \value Repeat Only the factional part of the texture coordiante is used, causing values above 1 and below 0 to repeat. -- cgit v1.2.3 From 995ba6f036c333422df3dc20dfe616380fee1dd0 Mon Sep 17 00:00:00 2001 From: Stephan Binner Date: Tue, 4 Apr 2017 11:22:30 +0200 Subject: Fix warning for -no-feature-temporaryfile Change-Id: Iaa4138610834f87b2a9379e707025d2e8a0fd59c Reviewed-by: Simon Hausmann Reviewed-by: Tasuku Suzuki --- src/qml/compiler/qv4compileddata.cpp | 1 + 1 file changed, 1 insertion(+) (limited to 'src') diff --git a/src/qml/compiler/qv4compileddata.cpp b/src/qml/compiler/qv4compileddata.cpp index f1f0ec282c..77d61032f7 100644 --- a/src/qml/compiler/qv4compileddata.cpp +++ b/src/qml/compiler/qv4compileddata.cpp @@ -454,6 +454,7 @@ bool CompilationUnit::saveToDisk(const QUrl &unitUrl, QString *errorString) return true; #else + Q_UNUSED(outputFileName) *errorString = QStringLiteral("features.temporaryfile is disabled."); return false; #endif // QT_CONFIG(temporaryfile) -- cgit v1.2.3 From 638e00e4379b9c5e0662ad1cb77ff3221429841b Mon Sep 17 00:00:00 2001 From: Stephan Binner Date: Tue, 4 Apr 2017 11:25:10 +0200 Subject: Fix warning for -no-feature-settings Change-Id: I286336660581ea616a7f5949fe74cfdc6aa7c792 Reviewed-by: Simon Hausmann --- src/imports/localstorage/plugin.cpp | 2 ++ 1 file changed, 2 insertions(+) (limited to 'src') diff --git a/src/imports/localstorage/plugin.cpp b/src/imports/localstorage/plugin.cpp index 8679750842..40682dd6a8 100644 --- a/src/imports/localstorage/plugin.cpp +++ b/src/imports/localstorage/plugin.cpp @@ -770,6 +770,8 @@ void QQuickLocalStorage::openDatabaseSync(QQmlV4Function *args) } args->setReturnValue(db.asReturnedValue()); +#else + Q_UNUSED(args) #endif // settings } -- cgit v1.2.3 From 4af4741c4a833cd9527bd70accdcab655ceb3559 Mon Sep 17 00:00:00 2001 From: Lars Knoll Date: Fri, 31 Mar 2017 13:33:22 +0200 Subject: Don't waste CPU cycles when checking whether a breakpoint is active QV4::Function::sourceFile() actually malloc's a new string each time it's being called. Let's not call it unless we need its return value. Change-Id: I4e47422860549df5e1b5b19f3a68f027ff74f05a Reviewed-by: Simon Hausmann --- src/qml/jsruntime/qv4vme_moth.cpp | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) (limited to 'src') diff --git a/src/qml/jsruntime/qv4vme_moth.cpp b/src/qml/jsruntime/qv4vme_moth.cpp index c9b249011b..a74016ab0c 100644 --- a/src/qml/jsruntime/qv4vme_moth.cpp +++ b/src/qml/jsruntime/qv4vme_moth.cpp @@ -249,10 +249,11 @@ int qt_v4DebuggerHook(const char *json) return -NoSuchCommand; // Failure. } -static void qt_v4CheckForBreak(QV4::ExecutionContext *context, QV4::Value **scopes, int scopeDepth) +static void qt_v4CheckForBreak(QV4::ExecutionContext *context) { - Q_UNUSED(scopes); - Q_UNUSED(scopeDepth); + if (!qt_v4IsStepping && !qt_v4Breakpoints.size()) + return; + const int lineNumber = context->d()->lineNumber; QV4::Function *function = qt_v4ExtractFunction(context); QString engineName = function->sourceFile(); @@ -915,13 +916,13 @@ QV4::ReturnedValue VME::run(ExecutionEngine *engine, const uchar *code if (debugger && debugger->pauseAtNextOpportunity()) debugger->maybeBreakAtInstruction(); if (qt_v4IsDebugging) - qt_v4CheckForBreak(context, scopes, scopeDepth); + qt_v4CheckForBreak(context); MOTH_END_INSTR(Debug) MOTH_BEGIN_INSTR(Line) engine->current->lineNumber = instr.lineNumber; if (qt_v4IsDebugging) - qt_v4CheckForBreak(context, scopes, scopeDepth); + qt_v4CheckForBreak(context); MOTH_END_INSTR(Line) #endif // QT_NO_QML_DEBUGGER -- cgit v1.2.3 From 42e9a5e27c914c58dc9c734829f906fb7bb4f371 Mon Sep 17 00:00:00 2001 From: Laszlo Agocs Date: Tue, 4 Apr 2017 11:36:19 +0200 Subject: Make QQuickWidget cleanup work with engines that alter the context To make Scene3D in a QQuickWidget work. Task-number: QTBUG-52132 Change-Id: I686ff36d82a1c7bdfdcd7080a314bb9afdb7be88 Reviewed-by: Sean Harmer Reviewed-by: Andy Nichols --- src/quickwidgets/qquickwidget.cpp | 10 ++++++++++ 1 file changed, 10 insertions(+) (limited to 'src') diff --git a/src/quickwidgets/qquickwidget.cpp b/src/quickwidgets/qquickwidget.cpp index 5d7fb04b9f..be5837723a 100644 --- a/src/quickwidgets/qquickwidget.cpp +++ b/src/quickwidgets/qquickwidget.cpp @@ -157,6 +157,16 @@ void QQuickWidgetPrivate::invalidateRenderControl() #endif renderControl->invalidate(); + + // Many things can happen inside the above invalidate() call, including a + // change of current context. Restore if needed since some code will rely + // on the fact that this function makes and leaves the context current. +#if QT_CONFIG(opengl) + if (!useSoftwareRenderer && context) { + if (QOpenGLContext::currentContext() != context) + context->makeCurrent(offscreenSurface); + } +#endif } void QQuickWidgetPrivate::handleWindowChange() -- cgit v1.2.3 From fdb822613989c5975ba282b775e6d194467bdef4 Mon Sep 17 00:00:00 2001 From: Robin Burchell Date: Fri, 27 Jan 2017 17:13:34 +0100 Subject: TestCase: Use the new instanceof support for QML types to ensure we have an Item Using !item is not enough in a loosely-typed language like QML. Previously, passing numbers to these methods (for example) would have worked in misleading ways, or not at all. We allow Window here too as for the most part it is useful, and some tests actually use it. Change-Id: I99de081798d1c503d0b01dc99ca095654cf58aa4 Reported-by: Albert Astals Cid Reviewed-by: Simon Hausmann --- src/imports/testlib/TestCase.qml | 58 ++++++++++++++++++++++++++-------------- 1 file changed, 38 insertions(+), 20 deletions(-) (limited to 'src') diff --git a/src/imports/testlib/TestCase.qml b/src/imports/testlib/TestCase.qml index 18c70e1169..3e6eb64311 100644 --- a/src/imports/testlib/TestCase.qml +++ b/src/imports/testlib/TestCase.qml @@ -38,6 +38,7 @@ ****************************************************************************/ import QtQuick 2.0 +import QtQuick.Window 2.0 // used for qtest_verifyItem import QtTest 1.1 import "testlogger.js" as TestLogger import Qt.test.qtestroot 1.0 @@ -1085,8 +1086,8 @@ Item { function waitForRendering(item, timeout) { if (timeout === undefined) timeout = 5000 - if (!item) - qtest_fail("No item given to waitForRendering", 1) + if (!qtest_verifyItem(item, "waitForRendering")) + return return qtest_results.waitForRendering(item, timeout) } @@ -1198,8 +1199,8 @@ Item { \sa mouseRelease(), mouseClick(), mouseDoubleClick(), mouseDoubleClickSequence(), mouseMove(), mouseDrag(), mouseWheel() */ function mousePress(item, x, y, button, modifiers, delay) { - if (!item) - qtest_fail("No item given to mousePress", 1) + if (!qtest_verifyItem(item, "mousePress")) + return if (button === undefined) button = Qt.LeftButton @@ -1232,8 +1233,8 @@ Item { \sa mousePress(), mouseClick(), mouseDoubleClick(), mouseDoubleClickSequence(), mouseMove(), mouseDrag(), mouseWheel() */ function mouseRelease(item, x, y, button, modifiers, delay) { - if (!item) - qtest_fail("No item given to mouseRelease", 1) + if (!qtest_verifyItem(item, "mouseRelease")) + return if (button === undefined) button = Qt.LeftButton @@ -1268,8 +1269,8 @@ Item { \sa mousePress(), mouseClick(), mouseDoubleClick(), mouseDoubleClickSequence(), mouseMove(), mouseRelease(), mouseWheel() */ function mouseDrag(item, x, y, dx, dy, button, modifiers, delay) { - if (!item) - qtest_fail("No item given to mouseDrag", 1) + if (!qtest_verifyItem(item, "mouseDrag")) + return if (item.x === undefined || item.y === undefined) return @@ -1319,8 +1320,8 @@ Item { \sa mousePress(), mouseRelease(), mouseDoubleClick(), mouseDoubleClickSequence(), mouseMove(), mouseDrag(), mouseWheel() */ function mouseClick(item, x, y, button, modifiers, delay) { - if (!item) - qtest_fail("No item given to mouseClick", 1) + if (!qtest_verifyItem(item, "mouseClick")) + return if (button === undefined) button = Qt.LeftButton @@ -1353,8 +1354,8 @@ Item { \sa mouseDoubleClickSequence(), mousePress(), mouseRelease(), mouseClick(), mouseMove(), mouseDrag(), mouseWheel() */ function mouseDoubleClick(item, x, y, button, modifiers, delay) { - if (!item) - qtest_fail("No item given to mouseDoubleClick", 1) + if (!qtest_verifyItem(item, "mouseDoubleClick")) + return if (button === undefined) button = Qt.LeftButton @@ -1394,8 +1395,8 @@ Item { \sa mouseDoubleClick(), mousePress(), mouseRelease(), mouseClick(), mouseMove(), mouseDrag(), mouseWheel() */ function mouseDoubleClickSequence(item, x, y, button, modifiers, delay) { - if (!item) - qtest_fail("No item given to mouseDoubleClickSequence", 1) + if (!qtest_verifyItem(item, "mouseDoubleClickSequence")) + return if (button === undefined) button = Qt.LeftButton @@ -1426,8 +1427,8 @@ Item { \sa mousePress(), mouseRelease(), mouseClick(), mouseDoubleClick(), mouseDoubleClickSequence(), mouseDrag(), mouseWheel() */ function mouseMove(item, x, y, delay, buttons) { - if (!item) - qtest_fail("No item given to mouseMove", 1) + if (!qtest_verifyItem(item, "mouseMove")) + return if (delay == undefined) delay = -1 @@ -1454,8 +1455,8 @@ Item { \sa mousePress(), mouseClick(), mouseDoubleClick(), mouseDoubleClickSequence(), mouseMove(), mouseRelease(), mouseDrag(), QWheelEvent::angleDelta() */ function mouseWheel(item, x, y, xDelta, yDelta, buttons, modifiers, delay) { - if (!item) - qtest_fail("No item given to mouseWheel", 1) + if (!qtest_verifyItem(item, "mouseWheel")) + return if (delay == undefined) delay = -1 @@ -1515,8 +1516,8 @@ Item { */ function touchEvent(item) { - if (!item) - qtest_fail("No item given to touchEvent", 1) + if (!qtest_verifyItem(item, "touchEvent")) + return return { _defaultItem: item, @@ -1624,6 +1625,23 @@ Item { */ function cleanup() {} + /*! \internal */ + function qtest_verifyItem(item, method) { + try { + if (!(item instanceof Item) && + !(item instanceof Window)) { + // it's a QObject, but not a type + qtest_fail("TypeError: %1 requires an Item or Window type".arg(method), 2); + return false; + } + } catch (e) { // it's not a QObject + qtest_fail("TypeError: %1 requires an Item or Window type".arg(method), 3); + return false; + } + + return true; + } + /*! \internal */ function qtest_runInternal(prop, arg) { try { -- cgit v1.2.3 From 492303fde683262ea94fad04751b303877e90924 Mon Sep 17 00:00:00 2001 From: Tasuku Suzuki Date: Wed, 5 Apr 2017 10:50:17 +0900 Subject: Fix build without features.systemsemaphore Change-Id: I3924c3193cc0c5b8def860879cd29f5dcb2c2314 Reviewed-by: Simon Hausmann --- src/imports/imports.pro | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/imports/imports.pro b/src/imports/imports.pro index d16ac05669..a32c35e771 100644 --- a/src/imports/imports.pro +++ b/src/imports/imports.pro @@ -17,9 +17,9 @@ qtHaveModule(quick) { layouts \ qtquick2 \ window \ - sharedimage \ testlib + qtConfig(systemsemaphore): SUBDIRS += sharedimage qtConfig(quick-particles): \ SUBDIRS += particles } -- cgit v1.2.3 From af72231fe4a91226d945db9a526fb755332548eb Mon Sep 17 00:00:00 2001 From: Albert Astals Cid Date: Tue, 4 Apr 2017 16:26:20 +0200 Subject: Error out if TestCase.verify receives more than 2 parameters Change-Id: I3299f602970067aaef290d4f1c7449d3ab03fb3c Reviewed-by: Simon Hausmann Reviewed-by: Mitch Curtis --- src/imports/testlib/TestCase.qml | 3 +++ 1 file changed, 3 insertions(+) (limited to 'src') diff --git a/src/imports/testlib/TestCase.qml b/src/imports/testlib/TestCase.qml index 3e6eb64311..8c1744a2b2 100644 --- a/src/imports/testlib/TestCase.qml +++ b/src/imports/testlib/TestCase.qml @@ -444,6 +444,9 @@ Item { or \c{QVERIFY2(condition, message)} in C++. */ function verify(cond, msg) { + if (arguments.length > 2) + qtest_fail("More than two arguments given to verify(). Did you mean tryVerify() or tryCompare()?", 1) + if (msg === undefined) msg = ""; if (!qtest_results.verify(cond, msg, util.callerFile(), util.callerLine())) -- cgit v1.2.3 From fa01610d6b4e4637cf48b0fcb9fd14d7c5522a77 Mon Sep 17 00:00:00 2001 From: Mitch Curtis Date: Wed, 29 Mar 2017 13:09:29 +0200 Subject: Revert "Privately export QQuickPositionerAttached" This reverts commit 015dff255ff0f40c553b1dee43c6cff013df64eb. This is no longer necessary, as there are now no users of this type in other modules. Change-Id: I453fb7c36a9b3dc90ecb2e412164a8176f0c332b Reviewed-by: Robin Burchell --- src/quick/items/qquickpositioners_p.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/quick/items/qquickpositioners_p.h b/src/quick/items/qquickpositioners_p.h index cfe163b4c1..8dc0d90a2f 100644 --- a/src/quick/items/qquickpositioners_p.h +++ b/src/quick/items/qquickpositioners_p.h @@ -67,7 +67,7 @@ QT_BEGIN_NAMESPACE class QQuickBasePositionerPrivate; -class Q_QUICK_PRIVATE_EXPORT QQuickPositionerAttached : public QObject +class QQuickPositionerAttached : public QObject { Q_OBJECT -- cgit v1.2.3 From 315f3689866adea143b064ade6a77d6e21bcc2e3 Mon Sep 17 00:00:00 2001 From: Mitch Curtis Date: Wed, 29 Mar 2017 13:11:08 +0200 Subject: Revert "Positioners: allow distinguishing between implicit/explicit child size" This reverts commit 2556bfdab42dc0aefb34bb7cf304063c7db0ff00. This is no longer necessary, as there are now no users of this functionality in other modules. Change-Id: If92bbdb3e5e95b4103610d68d22e929cf30c4e5e Reviewed-by: J-P Nurmi Reviewed-by: Robin Burchell --- src/quick/items/qquickpositioners.cpp | 100 ++++++++++---------------------- src/quick/items/qquickpositioners_p.h | 33 ++--------- src/quick/items/qquickpositioners_p_p.h | 41 ++----------- 3 files changed, 41 insertions(+), 133 deletions(-) (limited to 'src') diff --git a/src/quick/items/qquickpositioners.cpp b/src/quick/items/qquickpositioners.cpp index 70fc5fa65f..05882d0464 100644 --- a/src/quick/items/qquickpositioners.cpp +++ b/src/quick/items/qquickpositioners.cpp @@ -48,19 +48,8 @@ QT_BEGIN_NAMESPACE -// The default item change types that positioners are interested in. -static const QQuickItemPrivate::ChangeTypes explicitSizeItemChangeTypes = - QQuickItemPrivate::Geometry - | QQuickItemPrivate::SiblingOrder - | QQuickItemPrivate::Visibility - | QQuickItemPrivate::Destroyed; - -// The item change types for positioners that are only interested in the implicit -// size of the items they manage. These are used if useImplicitSize is true. -// useImplicitSize should be set in the constructor, before any items are added. -static const QQuickItemPrivate::ChangeTypes implicitSizeItemChangeTypes = - QQuickItemPrivate::ImplicitWidth - | QQuickItemPrivate::ImplicitHeight +static const QQuickItemPrivate::ChangeTypes watchedChanges + = QQuickItemPrivate::Geometry | QQuickItemPrivate::SiblingOrder | QQuickItemPrivate::Visibility | QQuickItemPrivate::Destroyed; @@ -68,15 +57,13 @@ static const QQuickItemPrivate::ChangeTypes implicitSizeItemChangeTypes = void QQuickBasePositionerPrivate::watchChanges(QQuickItem *other) { QQuickItemPrivate *otherPrivate = QQuickItemPrivate::get(other); - otherPrivate->addItemChangeListener(this, useImplicitSize - ? implicitSizeItemChangeTypes : explicitSizeItemChangeTypes); + otherPrivate->addItemChangeListener(this, watchedChanges); } void QQuickBasePositionerPrivate::unwatchChanges(QQuickItem* other) { QQuickItemPrivate *otherPrivate = QQuickItemPrivate::get(other); - otherPrivate->removeItemChangeListener(this, useImplicitSize - ? implicitSizeItemChangeTypes : explicitSizeItemChangeTypes); + otherPrivate->removeItemChangeListener(this, watchedChanges); } @@ -336,7 +323,7 @@ void QQuickBasePositioner::prePositioning() if (wIdx < 0) { d->watchChanges(child); posItem.isNew = true; - if (!childPrivate->explicitVisible || !d->itemWidth(child) || !d->itemHeight(child)) { + if (!childPrivate->explicitVisible || !child->width() || !child->height()) { posItem.isVisible = false; posItem.index = -1; unpositionedItems.append(posItem); @@ -358,7 +345,7 @@ void QQuickBasePositioner::prePositioning() PositionedItem *item = &oldItems[wIdx]; // Items are only omitted from positioning if they are explicitly hidden // i.e. their positioning is not affected if an ancestor is hidden. - if (!childPrivate->explicitVisible || !d->itemWidth(child) || !d->itemHeight(child)) { + if (!childPrivate->explicitVisible || !child->width() || !child->height()) { item->isVisible = false; item->index = -1; unpositionedItems.append(*item); @@ -957,7 +944,6 @@ QQuickColumn::QQuickColumn(QQuickItem *parent) void QQuickColumn::doPositioning(QSizeF *contentSize) { //Precondition: All items in the positioned list have a valid item pointer and should be positioned - QQuickBasePositionerPrivate *d = static_cast(QQuickBasePositionerPrivate::get(this)); qreal voffset = topPadding(); const qreal padding = leftPadding() + rightPadding(); contentSize->setWidth(qMax(contentSize->width(), padding)); @@ -966,9 +952,9 @@ void QQuickColumn::doPositioning(QSizeF *contentSize) PositionedItem &child = positionedItems[ii]; positionItem(child.itemX() + leftPadding() - child.leftPadding, voffset, &child); child.updatePadding(leftPadding(), topPadding(), rightPadding(), bottomPadding()); - contentSize->setWidth(qMax(contentSize->width(), d->itemWidth(child.item) + padding)); + contentSize->setWidth(qMax(contentSize->width(), child.item->width() + padding)); - voffset += d->itemHeight(child.item); + voffset += child.item->height(); voffset += spacing(); } @@ -1236,9 +1222,9 @@ void QQuickRow::doPositioning(QSizeF *contentSize) hoffsets << hoffset; } - contentSize->setHeight(qMax(contentSize->height(), d->itemHeight(child.item) + padding)); + contentSize->setHeight(qMax(contentSize->height(), child.item->height() + padding)); - hoffset += d->itemWidth(child.item); + hoffset += child.item->width(); hoffset += spacing(); } @@ -1259,7 +1245,7 @@ void QQuickRow::doPositioning(QSizeF *contentSize) int acc = 0; for (int ii = 0; ii < positionedItems.count(); ++ii) { PositionedItem &child = positionedItems[ii]; - hoffset = end - hoffsets[acc++] - d->itemWidth(child.item); + hoffset = end - hoffsets[acc++] - child.item->width(); positionItem(hoffset, child.itemY() + topPadding() - child.topPadding, &child); child.updatePadding(leftPadding(), topPadding(), rightPadding(), bottomPadding()); } @@ -1760,12 +1746,10 @@ void QQuickGrid::doPositioning(QSizeF *contentSize) break; const PositionedItem &child = positionedItems.at(childIndex++); - const qreal childWidth = d->itemWidth(child.item); - const qreal childHeight = d->itemHeight(child.item); - if (childWidth > maxColWidth[j]) - maxColWidth[j] = childWidth; - if (childHeight > maxRowHeight[i]) - maxRowHeight[i] = childHeight; + if (child.item->width() > maxColWidth[j]) + maxColWidth[j] = child.item->width(); + if (child.item->height() > maxRowHeight[i]) + maxRowHeight[i] = child.item->height(); } } } else { @@ -1780,12 +1764,10 @@ void QQuickGrid::doPositioning(QSizeF *contentSize) break; const PositionedItem &child = positionedItems.at(childIndex++); - const qreal childWidth = d->itemWidth(child.item); - const qreal childHeight = d->itemHeight(child.item); - if (childWidth > maxColWidth[j]) - maxColWidth[j] = childWidth; - if (childHeight > maxRowHeight[i]) - maxRowHeight[i] = childHeight; + if (child.item->width() > maxColWidth[j]) + maxColWidth[j] = child.item->width(); + if (child.item->height() > maxRowHeight[i]) + maxRowHeight[i] = child.item->height(); } } } @@ -1827,22 +1809,20 @@ void QQuickGrid::doPositioning(QSizeF *contentSize) for (int i = 0; i < positionedItems.count(); ++i) { PositionedItem &child = positionedItems[i]; qreal childXOffset = xoffset; - const qreal childWidth = d->itemWidth(child.item); - const qreal childHeight = d->itemHeight(child.item); if (effectiveHAlign() == AlignRight) - childXOffset += maxColWidth[curCol] - childWidth; + childXOffset += maxColWidth[curCol] - child.item->width(); else if (hItemAlign() == AlignHCenter) - childXOffset += (maxColWidth[curCol] - childWidth)/2.0; + childXOffset += (maxColWidth[curCol] - child.item->width())/2.0; if (!d->isLeftToRight()) childXOffset -= maxColWidth[curCol]; qreal alignYOffset = yoffset; if (m_vItemAlign == AlignVCenter) - alignYOffset += (maxRowHeight[curRow] - childHeight)/2.0; + alignYOffset += (maxRowHeight[curRow] - child.item->height())/2.0; else if (m_vItemAlign == AlignBottom) - alignYOffset += maxRowHeight[curRow] - childHeight; + alignYOffset += maxRowHeight[curRow] - child.item->height(); positionItem(childXOffset, alignYOffset, &child); child.updatePadding(leftPadding(), topPadding(), rightPadding(), bottomPadding()); @@ -2160,17 +2140,15 @@ void QQuickFlow::doPositioning(QSizeF *contentSize) for (int i = 0; i < positionedItems.count(); ++i) { PositionedItem &child = positionedItems[i]; - const qreal childWidth = d->itemWidth(child.item); - const qreal childHeight = d->itemHeight(child.item); if (d->flow == LeftToRight) { - if (widthValid() && hoffset != hoffset1 && hoffset + childWidth + hoffset2 > width()) { + if (widthValid() && hoffset != hoffset1 && hoffset + child.item->width() + hoffset2 > width()) { hoffset = hoffset1; voffset += linemax + spacing(); linemax = 0; } } else { - if (heightValid() && voffset != voffset1 && voffset + childHeight + bottomPadding() > height()) { + if (heightValid() && voffset != voffset1 && voffset + child.item->height() + bottomPadding() > height()) { voffset = voffset1; hoffset += linemax + spacing(); linemax = 0; @@ -2187,17 +2165,17 @@ void QQuickFlow::doPositioning(QSizeF *contentSize) child.bottomPadding = bottomPadding(); } - contentSize->setWidth(qMax(contentSize->width(), hoffset + childWidth + hoffset2)); - contentSize->setHeight(qMax(contentSize->height(), voffset + childHeight + bottomPadding())); + contentSize->setWidth(qMax(contentSize->width(), hoffset + child.item->width() + hoffset2)); + contentSize->setHeight(qMax(contentSize->height(), voffset + child.item->height() + bottomPadding())); if (d->flow == LeftToRight) { - hoffset += childWidth; + hoffset += child.item->width(); hoffset += spacing(); - linemax = qMax(linemax, childHeight); + linemax = qMax(linemax, child.item->height()); } else { - voffset += childHeight; + voffset += child.item->height(); voffset += spacing(); - linemax = qMax(linemax, childWidth); + linemax = qMax(linemax, child.item->width()); } } @@ -2212,7 +2190,7 @@ void QQuickFlow::doPositioning(QSizeF *contentSize) int acc = 0; for (int i = 0; i < positionedItems.count(); ++i) { PositionedItem &child = positionedItems[i]; - hoffset = end - hoffsets[acc++] - d->itemWidth(child.item); + hoffset = end - hoffsets[acc++] - child.item->width(); positionItemX(hoffset, &child); child.leftPadding = leftPadding(); child.rightPadding = rightPadding(); @@ -2236,18 +2214,4 @@ void QQuickFlow::reportConflictingAnchors() qmlWarning(this) << "Cannot specify anchors for items inside Flow." << " Flow will not function."; } -QQuickImplicitRow::QQuickImplicitRow(QQuickItem *parent) - : QQuickRow(parent) -{ - QQuickBasePositionerPrivate *d = QQuickBasePositioner::get(this); - d->useImplicitSize = true; -} - -QQuickImplicitGrid::QQuickImplicitGrid(QQuickItem *parent) - : QQuickGrid(parent) -{ - QQuickBasePositionerPrivate *d = QQuickBasePositioner::get(this); - d->useImplicitSize = true; -} - QT_END_NAMESPACE diff --git a/src/quick/items/qquickpositioners_p.h b/src/quick/items/qquickpositioners_p.h index 8dc0d90a2f..9ae7029d69 100644 --- a/src/quick/items/qquickpositioners_p.h +++ b/src/quick/items/qquickpositioners_p.h @@ -132,11 +132,6 @@ public: static QQuickPositionerAttached *qmlAttachedProperties(QObject *obj); - static QQuickBasePositionerPrivate* get(QQuickBasePositioner *positioner) - { - return positioner->d_func(); - } - void updateAttachedProperties(QQuickPositionerAttached *specificProperty = 0, QQuickItem *specificPropertyOwner = 0) const; qreal padding() const; @@ -187,7 +182,7 @@ protected: virtual void doPositioning(QSizeF *contentSize)=0; virtual void reportConflictingAnchors()=0; - class Q_QUICK_PRIVATE_EXPORT PositionedItem + class PositionedItem { public : PositionedItem(QQuickItem *i); @@ -232,7 +227,7 @@ private: Q_DECLARE_PRIVATE(QQuickBasePositioner) }; -class Q_QUICK_PRIVATE_EXPORT QQuickColumn : public QQuickBasePositioner +class Q_AUTOTEST_EXPORT QQuickColumn : public QQuickBasePositioner { Q_OBJECT public: @@ -246,7 +241,7 @@ private: }; class QQuickRowPrivate; -class Q_QUICK_PRIVATE_EXPORT QQuickRow: public QQuickBasePositioner +class Q_AUTOTEST_EXPORT QQuickRow: public QQuickBasePositioner { Q_OBJECT Q_PROPERTY(Qt::LayoutDirection layoutDirection READ layoutDirection WRITE setLayoutDirection NOTIFY layoutDirectionChanged) @@ -271,7 +266,7 @@ private: }; class QQuickGridPrivate; -class Q_QUICK_PRIVATE_EXPORT QQuickGrid : public QQuickBasePositioner +class Q_AUTOTEST_EXPORT QQuickGrid : public QQuickBasePositioner { Q_OBJECT Q_PROPERTY(int rows READ rows WRITE setRows NOTIFY rowsChanged) @@ -358,7 +353,7 @@ private: }; class QQuickFlowPrivate; -class Q_QUICK_PRIVATE_EXPORT QQuickFlow: public QQuickBasePositioner +class Q_AUTOTEST_EXPORT QQuickFlow: public QQuickBasePositioner { Q_OBJECT Q_PROPERTY(Flow flow READ flow WRITE setFlow NOTIFY flowChanged) @@ -391,22 +386,6 @@ private: Q_DECLARE_PRIVATE(QQuickFlow) }; -class Q_QUICK_PRIVATE_EXPORT QQuickImplicitRow : public QQuickRow -{ - Q_OBJECT - -public: - QQuickImplicitRow(QQuickItem *parent = nullptr); -}; - -class Q_QUICK_PRIVATE_EXPORT QQuickImplicitGrid : public QQuickGrid -{ - Q_OBJECT - -public: - QQuickImplicitGrid(QQuickItem *parent = nullptr); -}; - QT_END_NAMESPACE @@ -414,8 +393,6 @@ QML_DECLARE_TYPE(QQuickColumn) QML_DECLARE_TYPE(QQuickRow) QML_DECLARE_TYPE(QQuickGrid) QML_DECLARE_TYPE(QQuickFlow) -QML_DECLARE_TYPE(QQuickImplicitRow) -QML_DECLARE_TYPE(QQuickImplicitGrid) QML_DECLARE_TYPE(QQuickBasePositioner) QML_DECLARE_TYPEINFO(QQuickBasePositioner, QML_HAS_ATTACHED_PROPERTIES) diff --git a/src/quick/items/qquickpositioners_p_p.h b/src/quick/items/qquickpositioners_p_p.h index 1a7051615c..0be4c56df6 100644 --- a/src/quick/items/qquickpositioners_p_p.h +++ b/src/quick/items/qquickpositioners_p_p.h @@ -89,14 +89,10 @@ public: QLazilyAllocated extra; QQuickBasePositionerPrivate() - : spacing(0) - , type(QQuickBasePositioner::None) - , transitioner(0) - , positioningDirty(false) - , doingPositioning(false) - , anchorConflict(false) - , useImplicitSize(false) - , layoutDirection(Qt::LeftToRight) + : spacing(0), type(QQuickBasePositioner::None) + , transitioner(0), positioningDirty(false) + , doingPositioning(false), anchorConflict(false), layoutDirection(Qt::LeftToRight) + { } @@ -123,7 +119,6 @@ public: bool positioningDirty : 1; bool doingPositioning : 1; bool anchorConflict : 1; - bool useImplicitSize : 1; Qt::LayoutDirection layoutDirection; @@ -179,34 +174,6 @@ public: { } - void itemImplicitWidthChanged(QQuickItem *) override - { - Q_ASSERT(useImplicitSize); - setPositioningDirty(); - } - - void itemImplicitHeightChanged(QQuickItem *) override - { - Q_ASSERT(useImplicitSize); - setPositioningDirty(); - } - - qreal itemWidth(QQuickItem *item) const - { - if (Q_LIKELY(!useImplicitSize)) - return item->width(); - - return item->implicitWidth(); - } - - qreal itemHeight(QQuickItem *item) const - { - if (Q_LIKELY(!useImplicitSize)) - return item->height(); - - return item->implicitHeight(); - } - inline qreal padding() const { return extra.isAllocated() ? extra->padding : 0.0; } void setTopPadding(qreal value, bool reset = false); void setLeftPadding(qreal value, bool reset = false); -- cgit v1.2.3 From ab00687dd24e3f7ae27c8caaf9194913869e0784 Mon Sep 17 00:00:00 2001 From: Paolo Angelelli Date: Wed, 5 Apr 2017 12:59:42 +0200 Subject: Remove revision from Drag.imageSource property Having the REVISION in the Q_PROPERTY seemingly breaks the feature. QML property revisioning does not work for attached (nor grouped) properties (QTBUG-33179). Change-Id: I770826e86936b59fb1a25885d7c6b123b5467fe2 Reviewed-by: J-P Nurmi --- src/quick/items/qquickdrag_p.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/quick/items/qquickdrag_p.h b/src/quick/items/qquickdrag_p.h index 357f72b3e7..17e9d8c690 100644 --- a/src/quick/items/qquickdrag_p.h +++ b/src/quick/items/qquickdrag_p.h @@ -248,7 +248,7 @@ class QQuickDragAttached : public QObject Q_PROPERTY(QObject *source READ source WRITE setSource NOTIFY sourceChanged RESET resetSource) Q_PROPERTY(QObject *target READ target NOTIFY targetChanged) Q_PROPERTY(QPointF hotSpot READ hotSpot WRITE setHotSpot NOTIFY hotSpotChanged) - Q_PROPERTY(QUrl imageSource READ imageSource WRITE setImageSource NOTIFY imageSourceChanged REVISION 8) + Q_PROPERTY(QUrl imageSource READ imageSource WRITE setImageSource NOTIFY imageSourceChanged) Q_PROPERTY(QStringList keys READ keys WRITE setKeys NOTIFY keysChanged) Q_PROPERTY(QVariantMap mimeData READ mimeData WRITE setMimeData NOTIFY mimeDataChanged) Q_PROPERTY(Qt::DropActions supportedActions READ supportedActions WRITE setSupportedActions NOTIFY supportedActionsChanged) -- cgit v1.2.3 From 039590bd818e23da89fa23424b4bb872db913356 Mon Sep 17 00:00:00 2001 From: Eirik Aavitsland Date: Thu, 23 Mar 2017 12:41:38 +0100 Subject: Make scaled image size calculation available to image providers When reduced size image loading is requested through Image::sourceSize, the precise calculation of the scaled size to load is somewhat complex. This commit moves that calculation into a function accessible to image providers, so that they may use the same scaling as Quick's default image loading, and avoid code duplication. This is a code restructuring only; no behavior should change. Change-Id: Ic965fb2b6c22a5d21add41b8395e3a3842697d20 Reviewed-by: Shawn Rutledge --- src/quick/util/qquickimageprovider.cpp | 37 +++++++++++++++++++++++++++++++++- src/quick/util/qquickpixmapcache.cpp | 28 +++---------------------- src/quick/util/qquickpixmapcache_p.h | 2 ++ 3 files changed, 41 insertions(+), 26 deletions(-) (limited to 'src') diff --git a/src/quick/util/qquickimageprovider.cpp b/src/quick/util/qquickimageprovider.cpp index a026abe762..56b2d7070d 100644 --- a/src/quick/util/qquickimageprovider.cpp +++ b/src/quick/util/qquickimageprovider.cpp @@ -603,7 +603,6 @@ void QQuickImageProviderOptions::setPreserveAspectRatioFit(bool preserveAspectRa d->preserveAspectRatioFit = preserveAspectRatioFit; } - QQuickImageProviderWithOptions::QQuickImageProviderWithOptions(ImageType type, Flags flags) : QQuickAsyncImageProvider() { @@ -660,5 +659,41 @@ QQuickImageResponse *QQuickImageProviderWithOptions::requestImageResponse(const return requestImageResponse(id, requestedSize); } +/*! + Returns the recommended scaled image size for loading and storage. This is + calculated according to the native pixel size of the image \a originalSize, + the requested sourceSize \a requestedSize, the image file format \a format, + and \a options. If the calculation otherwise concludes that scaled loading + is not recommended, an invalid size is returned. +*/ +QSize QQuickImageProviderWithOptions::loadSize(const QSize &originalSize, const QSize &requestedSize, const QByteArray &format, const QQuickImageProviderOptions &options) +{ + QSize res; + if ((requestedSize.width() <= 0 && requestedSize.height() <= 0) || originalSize.isEmpty()) + return res; + + const bool preserveAspectCropOrFit = options.preserveAspectRatioCrop() || options.preserveAspectRatioFit(); + const bool force_scale = (format == "svg" || format == "svgz"); + + qreal ratio = 0.0; + if (requestedSize.width() && (preserveAspectCropOrFit || force_scale || requestedSize.width() < originalSize.width())) { + ratio = qreal(requestedSize.width()) / originalSize.width(); + } + if (requestedSize.height() && (preserveAspectCropOrFit || force_scale || requestedSize.height() < originalSize.height())) { + qreal hr = qreal(requestedSize.height()) / originalSize.height(); + if (ratio == 0.0) + ratio = hr; + else if (!preserveAspectCropOrFit && (hr < ratio)) + ratio = hr; + else if (preserveAspectCropOrFit && (hr > ratio)) + ratio = hr; + } + if (ratio > 0.0) { + res.setHeight(qRound(originalSize.height() * ratio)); + res.setWidth(qRound(originalSize.width() * ratio)); + } + return res; +} + QT_END_NAMESPACE diff --git a/src/quick/util/qquickpixmapcache.cpp b/src/quick/util/qquickpixmapcache.cpp index be27cba989..4f7f4972bf 100644 --- a/src/quick/util/qquickpixmapcache.cpp +++ b/src/quick/util/qquickpixmapcache.cpp @@ -386,37 +386,15 @@ static bool readImage(const QUrl& url, QIODevice *dev, QImage *image, QString *e const QSize &requestSize, const QQuickImageProviderOptions &providerOptions, QQuickImageProviderOptions::AutoTransform *appliedTransform = nullptr) { - const bool preserveAspectCropOrFit = providerOptions.preserveAspectRatioCrop() || providerOptions.preserveAspectRatioFit(); - QImageReader imgio(dev); if (providerOptions.autoTransform() != QQuickImageProviderOptions::UsePluginDefaultTransform) imgio.setAutoTransform(providerOptions.autoTransform() == QQuickImageProviderOptions::ApplyTransform); else if (appliedTransform) *appliedTransform = imgio.autoTransform() ? QQuickImageProviderOptions::ApplyTransform : QQuickImageProviderOptions::DoNotApplyTransform; - const bool force_scale = imgio.format() == "svg" || imgio.format() == "svgz"; - - if (requestSize.width() > 0 || requestSize.height() > 0) { - QSize s = imgio.size(); - qreal ratio = 0.0; - if (requestSize.width() && (preserveAspectCropOrFit || force_scale || requestSize.width() < s.width())) { - ratio = qreal(requestSize.width())/s.width(); - } - if (requestSize.height() && (preserveAspectCropOrFit || force_scale || requestSize.height() < s.height())) { - qreal hr = qreal(requestSize.height())/s.height(); - if (ratio == 0.0) - ratio = hr; - else if (!preserveAspectCropOrFit && (hr < ratio)) - ratio = hr; - else if (preserveAspectCropOrFit && (hr > ratio)) - ratio = hr; - } - if (ratio > 0.0) { - s.setHeight(qRound(s.height() * ratio)); - s.setWidth(qRound(s.width() * ratio)); - imgio.setScaledSize(s); - } - } + QSize scSize = QQuickImageProviderWithOptions::loadSize(imgio.size(), requestSize, imgio.format(), providerOptions); + if (scSize.isValid()) + imgio.setScaledSize(scSize); if (impsize) *impsize = imgio.size(); diff --git a/src/quick/util/qquickpixmapcache_p.h b/src/quick/util/qquickpixmapcache_p.h index 93d5a1cf56..f7996eb664 100644 --- a/src/quick/util/qquickpixmapcache_p.h +++ b/src/quick/util/qquickpixmapcache_p.h @@ -204,6 +204,8 @@ public: virtual QPixmap requestPixmap(const QString &id, QSize *size, const QSize& requestedSize, const QQuickImageProviderOptions &options); virtual QQuickTextureFactory *requestTexture(const QString &id, QSize *size, const QSize &requestedSize, const QQuickImageProviderOptions &options); virtual QQuickImageResponse *requestImageResponse(const QString &id, const QSize &requestedSize, const QQuickImageProviderOptions &options); + + static QSize loadSize(const QSize &originalSize, const QSize &requestedSize, const QByteArray &format, const QQuickImageProviderOptions &options); }; QT_END_NAMESPACE -- cgit v1.2.3 From b78508f55f6ada95a51ca7d8051382178c27abce Mon Sep 17 00:00:00 2001 From: Albert Astals Cid Date: Tue, 31 Jan 2017 11:06:35 +0100 Subject: Add a TODO to make functions const As far as I can see they don't modify the QJSValue or its private at all Change-Id: I555e9dc2fa28aa90929e6f864158bbbc98dd669c Reviewed-by: Simon Hausmann --- src/qml/jsapi/qjsvalue.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/src/qml/jsapi/qjsvalue.h b/src/qml/jsapi/qjsvalue.h index ab20a2607d..56bd64eec1 100644 --- a/src/qml/jsapi/qjsvalue.h +++ b/src/qml/jsapi/qjsvalue.h @@ -133,9 +133,9 @@ public: bool deleteProperty(const QString &name); bool isCallable() const; - QJSValue call(const QJSValueList &args = QJSValueList()); - QJSValue callWithInstance(const QJSValue &instance, const QJSValueList &args = QJSValueList()); - QJSValue callAsConstructor(const QJSValueList &args = QJSValueList()); + QJSValue call(const QJSValueList &args = QJSValueList()); // ### Qt6: Make const + QJSValue callWithInstance(const QJSValue &instance, const QJSValueList &args = QJSValueList()); // ### Qt6: Make const + QJSValue callAsConstructor(const QJSValueList &args = QJSValueList()); // ### Qt6: Make const #ifdef QT_DEPRECATED QT_DEPRECATED QJSEngine *engine() const; -- cgit v1.2.3 From f2281a5339a4ce744c1832f19d0ec5e364907e38 Mon Sep 17 00:00:00 2001 From: Tasuku Suzuki Date: Mon, 3 Apr 2017 16:36:23 +0900 Subject: Fix build without features.sql Change-Id: Ia2bf444da6056e3a87ebd5245aeb8c3f819251ce Reviewed-by: Simon Hausmann --- src/imports/imports.pro | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/imports/imports.pro b/src/imports/imports.pro index a32c35e771..c03224958c 100644 --- a/src/imports/imports.pro +++ b/src/imports/imports.pro @@ -6,9 +6,9 @@ SUBDIRS += \ builtins \ qtqml \ folderlistmodel \ - localstorage \ models +qtHaveModule(sql): SUBDIRS += localstorage qtConfig(settings): SUBDIRS += settings qtConfig(statemachine): SUBDIRS += statemachine -- cgit v1.2.3 From 22c39eda8ab316c743d0beac62a9745fd82147f7 Mon Sep 17 00:00:00 2001 From: Albert Astals Cid Date: Wed, 5 Apr 2017 11:57:45 +0200 Subject: Fix crash in QQuickPixmapReader & friends In 9c50216c7bbbdb2bb51d4485286bf09e12fb5b62 I made the mistake of not copying providerOptions inside QQuickPixmapReply as is done for requestSize and url since i thought that i could just use the data pointer to access it, but that's not possible since data can get deleted in other thread so we need to copy the value Change-Id: Ie1d466b210108e1af1f0c8d3c618d4516448b73d Reviewed-by: Donald Carr Reviewed-by: Robin Burchell --- src/quick/util/qquickpixmapcache.cpp | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) (limited to 'src') diff --git a/src/quick/util/qquickpixmapcache.cpp b/src/quick/util/qquickpixmapcache.cpp index 4f7f4972bf..40a634a10e 100644 --- a/src/quick/util/qquickpixmapcache.cpp +++ b/src/quick/util/qquickpixmapcache.cpp @@ -141,6 +141,7 @@ public: QUrl url; bool loading; + QQuickImageProviderOptions providerOptions; int redirectCount; class Event : public QEvent { @@ -204,7 +205,7 @@ protected: private: friend class QQuickPixmapReaderThreadObject; void processJobs(); - void processJob(QQuickPixmapReply *, const QUrl &, const QString &, const QQuickImageProviderOptions &, QQuickImageProvider::ImageType, QQuickImageProvider *); + void processJob(QQuickPixmapReply *, const QUrl &, const QString &, QQuickImageProvider::ImageType, QQuickImageProvider *); #if QT_CONFIG(qml_network) void networkRequestDone(QNetworkReply *); #endif @@ -642,7 +643,7 @@ void QQuickPixmapReader::processJobs() PIXMAP_PROFILE(pixmapStateChanged(url)); locker.unlock(); - processJob(job, url, localFile, job->data->providerOptions, imageType, provider); + processJob(job, url, localFile, imageType, provider); locker.relock(); } } @@ -654,7 +655,6 @@ void QQuickPixmapReader::processJobs() } void QQuickPixmapReader::processJob(QQuickPixmapReply *runningJob, const QUrl &url, const QString &localFile, - const QQuickImageProviderOptions &providerOptions, QQuickImageProvider::ImageType imageType, QQuickImageProvider *provider) { // fetch @@ -685,7 +685,7 @@ void QQuickPixmapReader::processJob(QQuickPixmapReply *runningJob, const QUrl &u { QImage image; if (providerV2) { - image = providerV2->requestImage(imageId(url), &readSize, runningJob->requestSize, providerOptions); + image = providerV2->requestImage(imageId(url), &readSize, runningJob->requestSize, runningJob->providerOptions); } else { image = provider->requestImage(imageId(url), &readSize, runningJob->requestSize); } @@ -706,7 +706,7 @@ void QQuickPixmapReader::processJob(QQuickPixmapReply *runningJob, const QUrl &u { QPixmap pixmap; if (providerV2) { - pixmap = providerV2->requestPixmap(imageId(url), &readSize, runningJob->requestSize, providerOptions); + pixmap = providerV2->requestPixmap(imageId(url), &readSize, runningJob->requestSize, runningJob->providerOptions); } else { pixmap = provider->requestPixmap(imageId(url), &readSize, runningJob->requestSize); } @@ -727,7 +727,7 @@ void QQuickPixmapReader::processJob(QQuickPixmapReply *runningJob, const QUrl &u { QQuickTextureFactory *t; if (providerV2) { - t = providerV2->requestTexture(imageId(url), &readSize, runningJob->requestSize, providerOptions); + t = providerV2->requestTexture(imageId(url), &readSize, runningJob->requestSize, runningJob->providerOptions); } else { t = provider->requestTexture(imageId(url), &readSize, runningJob->requestSize); } @@ -750,7 +750,7 @@ void QQuickPixmapReader::processJob(QQuickPixmapReply *runningJob, const QUrl &u { QQuickImageResponse *response; if (providerV2) { - response = providerV2->requestImageResponse(imageId(url), runningJob->requestSize, providerOptions); + response = providerV2->requestImageResponse(imageId(url), runningJob->requestSize, runningJob->providerOptions); } else { QQuickAsyncImageProvider *asyncProvider = static_cast(provider); response = asyncProvider->requestImageResponse(imageId(url), runningJob->requestSize); @@ -772,7 +772,7 @@ void QQuickPixmapReader::processJob(QQuickPixmapReply *runningJob, const QUrl &u QFile f(localFile); QSize readSize; if (f.open(QIODevice::ReadOnly)) { - if (!readImage(url, &f, &image, &errorStr, &readSize, runningJob->requestSize, providerOptions)) + if (!readImage(url, &f, &image, &errorStr, &readSize, runningJob->requestSize, runningJob->providerOptions)) errorCode = QQuickPixmapReply::Loading; } else { errorStr = QQuickPixmap::tr("Cannot open: %1").arg(url.toString()); @@ -1053,7 +1053,7 @@ void QQuickPixmap::purgeCache() } QQuickPixmapReply::QQuickPixmapReply(QQuickPixmapData *d) -: data(d), engineForReader(0), requestSize(d->requestSize), url(d->url), loading(false), redirectCount(0) +: data(d), engineForReader(0), requestSize(d->requestSize), url(d->url), loading(false), providerOptions(d->providerOptions), redirectCount(0) { if (finishedIndex == -1) { finishedIndex = QMetaMethod::fromSignal(&QQuickPixmapReply::finished).methodIndex(); -- cgit v1.2.3 From 8b255c67b965cda334425d64a0f1fd13ace93584 Mon Sep 17 00:00:00 2001 From: "Martin T. H. Sandsmark" Date: Sun, 12 Mar 2017 15:03:56 +0100 Subject: QQuickParticleSystem: Fix crash when an Affector dies A guarded pointer wasn't checked before being de-referenced, that lead to a crash if an emitter was modified after an affector was deleted, but before updateCurrentTime() was called. Change-Id: I6cb605a711319fb77c1e2e87fa9f35427cd7797b Reviewed-by: Robin Burchell --- src/particles/qquickparticlesystem.cpp | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) (limited to 'src') diff --git a/src/particles/qquickparticlesystem.cpp b/src/particles/qquickparticlesystem.cpp index 99e278238b..6f134f08df 100644 --- a/src/particles/qquickparticlesystem.cpp +++ b/src/particles/qquickparticlesystem.cpp @@ -668,8 +668,11 @@ void QQuickParticleSystem::setPaused(bool arg) { if (m_animation && m_animation->state() != QAbstractAnimation::Stopped) m_paused ? m_animation->pause() : m_animation->resume(); if (!m_paused) { - foreach (QQuickParticlePainter *p, m_painters) - p->update(); + foreach (QQuickParticlePainter *p, m_painters) { + if (p) { + p->update(); + } + } } emit pausedChanged(arg); } @@ -873,8 +876,11 @@ void QQuickParticleSystem::emittersChanged() if (particleCount > bySysIdx.size())//New datum requests haven't updated it bySysIdx.resize(particleCount); - foreach (QQuickParticleAffector *a, m_affectors)//Groups may have changed - a->m_updateIntSet = true; + foreach (QQuickParticleAffector *a, m_affectors) {//Groups may have changed + if (a) { + a->m_updateIntSet = true; + } + } foreach (QQuickParticlePainter *p, m_painters) loadPainter(p); -- cgit v1.2.3 From 46c845826251e1da269b13219eedff4e16da7bf4 Mon Sep 17 00:00:00 2001 From: Simon Hausmann Date: Wed, 5 Apr 2017 15:50:13 +0200 Subject: Fix loading of strings when cross-compiling from 64-bit host to 32-bit The use of sizeof(Type*) is not allowed when calculating indices into pointer arrays. Change-Id: I5531efc80d0267eaceade76ad2b96d454eab9392 Reviewed-by: Lars Knoll --- src/qml/jit/qv4assembler.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/qml/jit/qv4assembler.cpp b/src/qml/jit/qv4assembler.cpp index 0d06b421f6..3b9c2904dc 100644 --- a/src/qml/jit/qv4assembler.cpp +++ b/src/qml/jit/qv4assembler.cpp @@ -310,7 +310,7 @@ typename Assembler::Pointer Assembler: loadPtr(Address(Assembler::ScratchRegister, targetStructureOffset(Heap::ExecutionContext::baseOffset + offsetof(Heap::ExecutionContextData, compilationUnit))), Assembler::ScratchRegister); loadPtr(Address(Assembler::ScratchRegister, offsetof(CompiledData::CompilationUnitBase, runtimeStrings)), reg); const int id = _jsGenerator->registerString(string); - return Pointer(reg, id * sizeof(QV4::String*)); + return Pointer(reg, id * RegisterSize); } template -- cgit v1.2.3 From 7a368aaa1cb80b540898b77640dbe64034163526 Mon Sep 17 00:00:00 2001 From: Simon Hausmann Date: Wed, 5 Apr 2017 15:52:21 +0200 Subject: Fix engine parameter passing when cross-compiling We currently use addressForArgument() only to access the incoming functions parameters in JIT generated code, which is the engine parameter. While not currently supported by the current set of cross-compiling assemblers, the use of sizeof(Type*) may become an issue in the future, so let's use the correct value right away. Change-Id: I3e44279257f595a8be2c61bcfe15070a90038eb7 Reviewed-by: Lars Knoll --- src/qml/jit/qv4isel_masm_p.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/qml/jit/qv4isel_masm_p.h b/src/qml/jit/qv4isel_masm_p.h index 5c046cb397..0992e96e8b 100644 --- a/src/qml/jit/qv4isel_masm_p.h +++ b/src/qml/jit/qv4isel_masm_p.h @@ -160,7 +160,7 @@ protected: // FramePointerRegister points to its old value on the stack, and above // it we have the return address, hence the need to step over two // values before reaching the first argument. - return Address(JITTargetPlatform::FramePointerRegister, (index + 2) * sizeof(void*)); + return Address(JITTargetPlatform::FramePointerRegister, (index + 2) * JITTargetPlatform::RegisterSize); } Pointer baseAddressForCallArguments() -- cgit v1.2.3 From 5dcd95e376b42e72d5386345dbf65dffb811f1ad Mon Sep 17 00:00:00 2001 From: Simon Hausmann Date: Wed, 5 Apr 2017 15:56:43 +0200 Subject: Fix architecture selection when cross-compiling cache files We pass essentially the values of QSysInfo::buildCpuArchitecture() to qmlcachgen as command line parameters, so our factory function must be aligned with the values returned (and documented) there. That means arm instead of armv7, arm64 instead of armv8 and i386 instead of x86. Change-Id: I89c196b6585f9ba9550c0deb17e8b529980aa448 Reviewed-by: Lars Knoll --- src/qml/jit/qv4isel_masm.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'src') diff --git a/src/qml/jit/qv4isel_masm.cpp b/src/qml/jit/qv4isel_masm.cpp index dd48fdfc55..7797f8c8db 100644 --- a/src/qml/jit/qv4isel_masm.cpp +++ b/src/qml/jit/qv4isel_masm.cpp @@ -1641,18 +1641,18 @@ Q_QML_EXPORT QV4::EvalISelFactory *createISelForArchitecture(const QString &arch using ARMv7CrossAssembler = QV4::JIT::Assembler>; using ARM64CrossAssembler = QV4::JIT::Assembler>; - if (architecture == QLatin1String("armv7")) + if (architecture == QLatin1String("arm")) return new ISelFactory; - else if (architecture == QLatin1String("armv8")) + else if (architecture == QLatin1String("arm64")) return new ISelFactory; QString hostArch; #if CPU(ARM_THUMB2) - hostArch = QStringLiteral("armv7"); + hostArch = QStringLiteral("arm"); #elif CPU(MIPS) hostArch = QStringLiteral("mips"); #elif CPU(X86) - hostArch = QStringLiteral("x86"); + hostArch = QStringLiteral("i386"); #elif CPU(X86_64) hostArch = QStringLiteral("x86_64"); #endif -- cgit v1.2.3 From fcb9a740787084f1549df6d4d93d2c3886d39acd Mon Sep 17 00:00:00 2001 From: Simon Hausmann Date: Wed, 5 Apr 2017 14:47:34 +0200 Subject: Fix loading of ahead-of-time generated cache files when cross-compiling The target ABI is something that we must include correctly at cache generation time. The corresponding qmake variable is available in qtbase now, so we can use that and embed it in the generated data. Change-Id: Icd6e44824f5151535ce9ddac27687b7877288725 Reviewed-by: Lars Knoll --- src/qml/compiler/qv4compiler.cpp | 2 +- src/qml/compiler/qv4jsir_p.h | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/qml/compiler/qv4compiler.cpp b/src/qml/compiler/qv4compiler.cpp index 64f034ddcb..e32749bbf7 100644 --- a/src/qml/compiler/qv4compiler.cpp +++ b/src/qml/compiler/qv4compiler.cpp @@ -374,7 +374,7 @@ QV4::CompiledData::Unit QV4::Compiler::JSUnitGenerator::generateHeader(QV4::Comp unit.version = QV4_DATA_STRUCTURE_VERSION; unit.qtVersion = QT_VERSION; memset(unit.md5Checksum, 0, sizeof(unit.md5Checksum)); - unit.architectureIndex = registerString(QSysInfo::buildAbi()); + unit.architectureIndex = registerString(irModule->targetABI.isEmpty() ? QSysInfo::buildAbi() : irModule->targetABI); unit.codeGeneratorIndex = registerString(codeGeneratorName); memset(unit.dependencyMD5Checksum, 0, sizeof(unit.dependencyMD5Checksum)); diff --git a/src/qml/compiler/qv4jsir_p.h b/src/qml/compiler/qv4jsir_p.h index d9192c1a3b..e3c20a4cc8 100644 --- a/src/qml/compiler/qv4jsir_p.h +++ b/src/qml/compiler/qv4jsir_p.h @@ -946,6 +946,7 @@ struct Q_QML_PRIVATE_EXPORT Module { QDateTime sourceTimeStamp; bool isQmlModule; // implies rootFunction is always 0 uint unitFlags; // flags merged into CompiledData::Unit::flags + QString targetABI; // fallback to QSysInfo::buildAbi() if empty #ifdef QT_NO_QML_DEBUGGER static const bool debugMode = false; #else -- cgit v1.2.3 From a182a659b54dddb865dd573e5411c3fe710b32fe Mon Sep 17 00:00:00 2001 From: Eirik Aavitsland Date: Thu, 23 Mar 2017 16:19:51 +0100 Subject: Use new ImageProviderWithOptions also for sync image loading When the new extended image provider api was added, only the async image loading function was changed to use it. This commit makes also the sync image loading function check for the new api, and use it if the provider implements it. Change-Id: I982e4de05b8119e1668e2b982d2d62b03a52b302 Reviewed-by: Albert Astals Cid Reviewed-by: Robin Burchell --- src/quick/util/qquickimageprovider.cpp | 8 ++++++++ src/quick/util/qquickimageprovider.h | 1 - src/quick/util/qquickpixmapcache.cpp | 13 ++++++++----- src/quick/util/qquickpixmapcache_p.h | 1 + 4 files changed, 17 insertions(+), 6 deletions(-) (limited to 'src') diff --git a/src/quick/util/qquickimageprovider.cpp b/src/quick/util/qquickimageprovider.cpp index 56b2d7070d..457691ac61 100644 --- a/src/quick/util/qquickimageprovider.cpp +++ b/src/quick/util/qquickimageprovider.cpp @@ -695,5 +695,13 @@ QSize QQuickImageProviderWithOptions::loadSize(const QSize &originalSize, const return res; } +QQuickImageProviderWithOptions *QQuickImageProviderWithOptions::checkedCast(QQuickImageProvider *provider) +{ + if (provider && provider->d && provider->d->isProviderWithOptions) + return static_cast(provider); + + return nullptr; +} + QT_END_NAMESPACE diff --git a/src/quick/util/qquickimageprovider.h b/src/quick/util/qquickimageprovider.h index c77ff95f32..681de4b6c2 100644 --- a/src/quick/util/qquickimageprovider.h +++ b/src/quick/util/qquickimageprovider.h @@ -88,7 +88,6 @@ Q_SIGNALS: class Q_QUICK_EXPORT QQuickImageProvider : public QQmlImageProviderBase { friend class QQuickImageProviderWithOptions; // ### Qt 6 Remove - friend class QQuickPixmapReader; // ### Qt 6 Remove public: QQuickImageProvider(ImageType type, Flags flags = Flags()); virtual ~QQuickImageProvider(); diff --git a/src/quick/util/qquickpixmapcache.cpp b/src/quick/util/qquickpixmapcache.cpp index 40a634a10e..20b1108cb9 100644 --- a/src/quick/util/qquickpixmapcache.cpp +++ b/src/quick/util/qquickpixmapcache.cpp @@ -671,8 +671,7 @@ void QQuickPixmapReader::processJob(QQuickPixmapReply *runningJob, const QUrl &u return; } - QQuickImageProviderWithOptions *providerV2 = provider->d->isProviderWithOptions ? static_cast(provider) - : nullptr; + QQuickImageProviderWithOptions *providerV2 = QQuickImageProviderWithOptions::checkedCast(provider); switch (imageType) { case QQuickImageProvider::Invalid: @@ -1174,6 +1173,7 @@ static QQuickPixmapData* createPixmapDataSync(QQuickPixmap *declarativePixmap, Q QQuickImageProvider::ImageType imageType = QQuickImageProvider::Invalid; QQuickImageProvider *provider = static_cast(engine->imageProvider(imageProviderId(url))); + QQuickImageProviderWithOptions *providerV2 = QQuickImageProviderWithOptions::checkedCast(provider); if (provider) imageType = provider->imageType(); @@ -1183,7 +1183,8 @@ static QQuickPixmapData* createPixmapDataSync(QQuickPixmap *declarativePixmap, Q QQuickPixmap::tr("Invalid image provider: %1").arg(url.toString())); case QQuickImageProvider::Texture: { - QQuickTextureFactory *texture = provider->requestTexture(imageId(url), &readSize, requestSize); + QQuickTextureFactory *texture = providerV2 ? providerV2->requestTexture(imageId(url), &readSize, requestSize, providerOptions) + : provider->requestTexture(imageId(url), &readSize, requestSize); if (texture) { *ok = true; return new QQuickPixmapData(declarativePixmap, url, texture, readSize, requestSize, providerOptions, QQuickImageProviderOptions::UsePluginDefaultTransform); @@ -1193,7 +1194,8 @@ static QQuickPixmapData* createPixmapDataSync(QQuickPixmap *declarativePixmap, Q case QQuickImageProvider::Image: { - QImage image = provider->requestImage(imageId(url), &readSize, requestSize); + QImage image = providerV2 ? providerV2->requestImage(imageId(url), &readSize, requestSize, providerOptions) + : provider->requestImage(imageId(url), &readSize, requestSize); if (!image.isNull()) { *ok = true; return new QQuickPixmapData(declarativePixmap, url, QQuickTextureFactory::textureFactoryForImage(image), readSize, requestSize, providerOptions, QQuickImageProviderOptions::UsePluginDefaultTransform); @@ -1202,7 +1204,8 @@ static QQuickPixmapData* createPixmapDataSync(QQuickPixmap *declarativePixmap, Q } case QQuickImageProvider::Pixmap: { - QPixmap pixmap = provider->requestPixmap(imageId(url), &readSize, requestSize); + QPixmap pixmap = providerV2 ? providerV2->requestPixmap(imageId(url), &readSize, requestSize, providerOptions) + : provider->requestPixmap(imageId(url), &readSize, requestSize); if (!pixmap.isNull()) { *ok = true; return new QQuickPixmapData(declarativePixmap, url, QQuickTextureFactory::textureFactoryForImage(pixmap.toImage()), readSize, requestSize, providerOptions, QQuickImageProviderOptions::UsePluginDefaultTransform); diff --git a/src/quick/util/qquickpixmapcache_p.h b/src/quick/util/qquickpixmapcache_p.h index f7996eb664..91fb1ed3bb 100644 --- a/src/quick/util/qquickpixmapcache_p.h +++ b/src/quick/util/qquickpixmapcache_p.h @@ -206,6 +206,7 @@ public: virtual QQuickImageResponse *requestImageResponse(const QString &id, const QSize &requestedSize, const QQuickImageProviderOptions &options); static QSize loadSize(const QSize &originalSize, const QSize &requestedSize, const QByteArray &format, const QQuickImageProviderOptions &options); + static QQuickImageProviderWithOptions *checkedCast(QQuickImageProvider *provider); }; QT_END_NAMESPACE -- cgit v1.2.3 From 0518ba4d2a1156c316a7bd251210837acd84bf48 Mon Sep 17 00:00:00 2001 From: Simon Hausmann Date: Tue, 4 Apr 2017 15:59:50 +0200 Subject: Fix shadow stack space handling when cross-compiling Both MIPS and X86-64 on Windows reserve space for four registers on the stack, that the called function may use to spill the parameters passed in registers. This needs to be handled without #ifdefs in order to support cross-compilation and from the looks of it it was also wrong on MIPS. Change-Id: If65a6a0f6f64b8536703d32e7678e30ad807f7c8 Reviewed-by: Julien Brianceau Reviewed-by: Lars Knoll --- src/qml/jit/qv4assembler_p.h | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) (limited to 'src') diff --git a/src/qml/jit/qv4assembler_p.h b/src/qml/jit/qv4assembler_p.h index 0570b9be2b..b512398966 100644 --- a/src/qml/jit/qv4assembler_p.h +++ b/src/qml/jit/qv4assembler_p.h @@ -1277,13 +1277,7 @@ public: if (argumentNumber < RegisterArgumentCount) loadArgumentInRegister(value, registerForArgument(argumentNumber), argumentNumber); else -#if OS(WINDOWS) && CPU(X86_64) - loadArgumentOnStack(value, argumentNumber); -#elif CPU(MIPS) // Stack space for 4 arguments needs to be allocated for MIPS platforms. - loadArgumentOnStack(value, argumentNumber + 4); -#else // Sanity: - loadArgumentOnStack(value, argumentNumber); -#endif + loadArgumentOnStack(value, argumentNumber); } template -- cgit v1.2.3 From 028a85f4f462093ca93ae95865eb6cbcbaec199a Mon Sep 17 00:00:00 2001 From: Simon Hausmann Date: Mon, 3 Apr 2017 15:31:57 +0200 Subject: Fix double conversion code generation when cross-compiling We can't use QV4_USE_64_BIT_VALUE_ENCODING for deciding how generate code for checking if the tag of a value contains the necessary mask to detect doubles. Change-Id: Id5a5c1b136313aa4dfd2c997898e97cd4ebaeb83 Reviewed-by: Lars Knoll --- src/qml/jit/qv4assembler.cpp | 8 +------- src/qml/jit/qv4assembler_p.h | 14 ++++++++++++++ 2 files changed, 15 insertions(+), 7 deletions(-) (limited to 'src') diff --git a/src/qml/jit/qv4assembler.cpp b/src/qml/jit/qv4assembler.cpp index 3b9c2904dc..71dabcd590 100644 --- a/src/qml/jit/qv4assembler.cpp +++ b/src/qml/jit/qv4assembler.cpp @@ -440,13 +440,7 @@ typename Assembler::Jump Assembler::ge // not an int, check if it's a double: isNoInt.link(this); -#ifdef QV4_USE_64_BIT_VALUE_ENCODING - rshift32(TrustedImm32(Value::IsDoubleTag_Shift), ScratchRegister); - Assembler::Jump isNoDbl = branch32(RelationalCondition::Equal, JITTargetPlatform::ScratchRegister, TrustedImm32(0)); -#else - and32(Assembler::TrustedImm32(Value::NotDouble_Mask), Assembler::ScratchRegister); - Assembler::Jump isNoDbl = branch32(RelationalCondition::Equal, JITTargetPlatform::ScratchRegister, TrustedImm32(Value::NotDouble_Mask)); -#endif + Assembler::Jump isNoDbl = RegisterSizeDependentOps::checkIfTagRegisterIsDouble(this, ScratchRegister); toDoubleRegister(src, dest); intDone.link(this); diff --git a/src/qml/jit/qv4assembler_p.h b/src/qml/jit/qv4assembler_p.h index b512398966..8b5b307e84 100644 --- a/src/qml/jit/qv4assembler_p.h +++ b/src/qml/jit/qv4assembler_p.h @@ -370,6 +370,13 @@ struct RegisterSizeDependentAssemblerbranchSub32(ResultCondition::NonZero, TrustedImm32(1), TargetPlatform::ScratchRegister); jump.linkTo(loop, as); } + + static Jump checkIfTagRegisterIsDouble(JITAssembler *as, RegisterID tagRegister) + { + as->and32(TrustedImm32(Value::NotDouble_Mask), tagRegister); + Jump isNoDbl = as->branch32(RelationalCondition::Equal, tagRegister, TrustedImm32(Value::NotDouble_Mask)); + return isNoDbl; + } }; template @@ -657,6 +664,13 @@ struct RegisterSizeDependentAssemblerbranchSub32(ResultCondition::NonZero, TrustedImm32(1), TargetPlatform::ScratchRegister); jump.linkTo(loop, as); } + + static Jump checkIfTagRegisterIsDouble(JITAssembler *as, RegisterID tagRegister) + { + as->rshift32(TrustedImm32(Value::IsDoubleTag_Shift), tagRegister); + Jump isNoDbl = as->branch32(RelationalCondition::Equal, tagRegister, TrustedImm32(0)); + return isNoDbl; + } }; template -- cgit v1.2.3 From 9b961334cfd81ec5fcc4dc7d2c50154cddd5f230 Mon Sep 17 00:00:00 2001 From: Simon Hausmann Date: Wed, 5 Apr 2017 12:11:25 +0200 Subject: Fix support for jsTr() and QT_TR_NOOP in list elements when caching Similar to the Qt Quick Compiler we need to do the expression simplification pass at cache generation time to extract translation calls in list elements. Change-Id: I267fc9647ab82bc83d6b087c06c0036df38238ff Reviewed-by: Lars Knoll --- src/qml/compiler/compiler.pri | 6 +- src/qml/compiler/qqmltypecompiler.cpp | 343 +----------------------------- src/qml/compiler/qqmltypecompiler_p.h | 80 ------- src/qml/compiler/qv4jssimplifier.cpp | 384 ++++++++++++++++++++++++++++++++++ src/qml/compiler/qv4jssimplifier_p.h | 154 ++++++++++++++ 5 files changed, 544 insertions(+), 423 deletions(-) create mode 100644 src/qml/compiler/qv4jssimplifier.cpp create mode 100644 src/qml/compiler/qv4jssimplifier_p.h (limited to 'src') diff --git a/src/qml/compiler/compiler.pri b/src/qml/compiler/compiler.pri index fa66d3a6e3..871f28f2d0 100644 --- a/src/qml/compiler/compiler.pri +++ b/src/qml/compiler/compiler.pri @@ -10,7 +10,8 @@ HEADERS += \ $$PWD/qv4isel_util_p.h \ $$PWD/qv4ssa_p.h \ $$PWD/qqmlirbuilder_p.h \ - $$PWD/qqmltypecompiler_p.h + $$PWD/qqmltypecompiler_p.h \ + $$PWD/qv4jssimplifier_p.h SOURCES += \ $$PWD/qv4compileddata.cpp \ @@ -19,7 +20,8 @@ SOURCES += \ $$PWD/qv4isel_p.cpp \ $$PWD/qv4jsir.cpp \ $$PWD/qv4ssa.cpp \ - $$PWD/qqmlirbuilder.cpp + $$PWD/qqmlirbuilder.cpp \ + $$PWD/qv4jssimplifier.cpp !qmldevtools_build { diff --git a/src/qml/compiler/qqmltypecompiler.cpp b/src/qml/compiler/qqmltypecompiler.cpp index a3b8784fc8..d1d22be0ac 100644 --- a/src/qml/compiler/qqmltypecompiler.cpp +++ b/src/qml/compiler/qqmltypecompiler.cpp @@ -47,6 +47,7 @@ #include #include "qqmlpropertycachecreator_p.h" +#include "qv4jssimplifier_p.h" #define COMPILE_EXCEPTION(token, desc) \ { \ @@ -144,7 +145,7 @@ QV4::CompiledData::CompilationUnit *QQmlTypeCompiler::compile() if (!jsCodeGen.generateCodeForComponents()) return nullptr; - QQmlJavaScriptBindingExpressionSimplificationPass pass(this); + QQmlJavaScriptBindingExpressionSimplificationPass pass(document->objects, &document->jsModule, &document->jsGenerator); pass.reduceTranslationBindings(); QV4::ExecutionEngine *v4 = engine->v4engine(); @@ -1429,344 +1430,4 @@ void QQmlDefaultPropertyMerger::mergeDefaultProperties(int objectIndex) } } -QQmlJavaScriptBindingExpressionSimplificationPass::QQmlJavaScriptBindingExpressionSimplificationPass(QQmlTypeCompiler *typeCompiler) - : QQmlCompilePass(typeCompiler) - , qmlObjects(*typeCompiler->qmlObjects()) - , jsModule(typeCompiler->jsIRModule()) -{ - -} - -void QQmlJavaScriptBindingExpressionSimplificationPass::reduceTranslationBindings() -{ - for (int i = 0; i < qmlObjects.count(); ++i) - reduceTranslationBindings(i); - if (!irFunctionsToRemove.isEmpty()) { - QQmlIRFunctionCleanser cleanser(compiler, irFunctionsToRemove); - cleanser.clean(); - } -} - -void QQmlJavaScriptBindingExpressionSimplificationPass::reduceTranslationBindings(int objectIndex) -{ - const QmlIR::Object *obj = qmlObjects.at(objectIndex); - - for (QmlIR::Binding *binding = obj->firstBinding(); binding; binding = binding->next) { - if (binding->type != QV4::CompiledData::Binding::Type_Script) - continue; - - const int irFunctionIndex = obj->runtimeFunctionIndices.at(binding->value.compiledScriptIndex); - QV4::IR::Function *irFunction = jsModule->functions.at(irFunctionIndex); - if (simplifyBinding(irFunction, binding)) { - irFunctionsToRemove.append(irFunctionIndex); - jsModule->functions[irFunctionIndex] = 0; - delete irFunction; - } - } -} - -void QQmlJavaScriptBindingExpressionSimplificationPass::visitMove(QV4::IR::Move *move) -{ - QV4::IR::Temp *target = move->target->asTemp(); - if (!target || target->kind != QV4::IR::Temp::VirtualRegister) { - discard(); - return; - } - - if (QV4::IR::Call *call = move->source->asCall()) { - if (QV4::IR::Name *n = call->base->asName()) { - if (n->builtin == QV4::IR::Name::builtin_invalid) { - visitFunctionCall(n->id, call->args, target); - return; - } - } - discard(); - return; - } - - if (QV4::IR::Name *n = move->source->asName()) { - if (n->builtin == QV4::IR::Name::builtin_qml_context - || n->builtin == QV4::IR::Name::builtin_qml_imported_scripts_object) { - // these are free of side-effects - return; - } - discard(); - return; - } - - if (!move->source->asTemp() && !move->source->asString() && !move->source->asConst()) { - discard(); - return; - } - - _temps[target->index] = move->source; -} - -void QQmlJavaScriptBindingExpressionSimplificationPass::visitFunctionCall(const QString *name, QV4::IR::ExprList *args, QV4::IR::Temp *target) -{ - // more than one function call? - if (_nameOfFunctionCalled) { - discard(); - return; - } - - _nameOfFunctionCalled = name; - - _functionParameters.clear(); - while (args) { - int slot; - if (QV4::IR::Temp *param = args->expr->asTemp()) { - if (param->kind != QV4::IR::Temp::VirtualRegister) { - discard(); - return; - } - slot = param->index; - _functionParameters.append(slot); - } else if (QV4::IR::Const *param = args->expr->asConst()) { - slot = --_synthesizedConsts; - Q_ASSERT(!_temps.contains(slot)); - _temps[slot] = param; - _functionParameters.append(slot); - } - args = args->next; - } - - _functionCallReturnValue = target->index; -} - -void QQmlJavaScriptBindingExpressionSimplificationPass::visitRet(QV4::IR::Ret *ret) -{ - // nothing initialized earlier? - if (_returnValueOfBindingExpression != -1) { - discard(); - return; - } - QV4::IR::Temp *target = ret->expr->asTemp(); - if (!target || target->kind != QV4::IR::Temp::VirtualRegister) { - discard(); - return; - } - _returnValueOfBindingExpression = target->index; -} - -bool QQmlJavaScriptBindingExpressionSimplificationPass::simplifyBinding(QV4::IR::Function *function, QmlIR::Binding *binding) -{ - _canSimplify = true; - _nameOfFunctionCalled = 0; - _functionParameters.clear(); - _functionCallReturnValue = -1; - _temps.clear(); - _returnValueOfBindingExpression = -1; - _synthesizedConsts = 0; - - // It would seem unlikely that function with some many basic blocks (after optimization) - // consists merely of a qsTr call or a constant value return ;-) - if (function->basicBlockCount() > 10) - return false; - - for (QV4::IR::BasicBlock *bb : function->basicBlocks()) { - for (QV4::IR::Stmt *s : bb->statements()) { - visit(s); - if (!_canSimplify) - return false; - } - } - - if (_returnValueOfBindingExpression == -1) - return false; - - if (_nameOfFunctionCalled) { - if (_functionCallReturnValue != _returnValueOfBindingExpression) - return false; - return detectTranslationCallAndConvertBinding(binding); - } - - return false; -} - -bool QQmlJavaScriptBindingExpressionSimplificationPass::detectTranslationCallAndConvertBinding(QmlIR::Binding *binding) -{ - if (*_nameOfFunctionCalled == QLatin1String("qsTr")) { - QString translation; - QV4::CompiledData::TranslationData translationData; - translationData.number = -1; - translationData.commentIndex = 0; // empty string - - QVector::ConstIterator param = _functionParameters.constBegin(); - QVector::ConstIterator end = _functionParameters.constEnd(); - if (param == end) - return false; - - QV4::IR::String *stringParam = _temps[*param]->asString(); - if (!stringParam) - return false; - - translation = *stringParam->value; - - ++param; - if (param != end) { - stringParam = _temps[*param]->asString(); - if (!stringParam) - return false; - translationData.commentIndex = compiler->registerString(*stringParam->value); - ++param; - - if (param != end) { - QV4::IR::Const *constParam = _temps[*param]->asConst(); - if (!constParam || constParam->type != QV4::IR::SInt32Type) - return false; - - translationData.number = int(constParam->value); - ++param; - } - } - - if (param != end) - return false; - - binding->type = QV4::CompiledData::Binding::Type_Translation; - binding->stringIndex = compiler->registerString(translation); - binding->value.translationData = translationData; - return true; - } else if (*_nameOfFunctionCalled == QLatin1String("qsTrId")) { - QString id; - QV4::CompiledData::TranslationData translationData; - translationData.number = -1; - translationData.commentIndex = 0; // empty string, but unused - - QVector::ConstIterator param = _functionParameters.constBegin(); - QVector::ConstIterator end = _functionParameters.constEnd(); - if (param == end) - return false; - - QV4::IR::String *stringParam = _temps[*param]->asString(); - if (!stringParam) - return false; - - id = *stringParam->value; - - ++param; - if (param != end) { - QV4::IR::Const *constParam = _temps[*param]->asConst(); - if (!constParam || constParam->type != QV4::IR::SInt32Type) - return false; - - translationData.number = int(constParam->value); - ++param; - } - - if (param != end) - return false; - - binding->type = QV4::CompiledData::Binding::Type_TranslationById; - binding->stringIndex = compiler->registerString(id); - binding->value.translationData = translationData; - return true; - } else if (*_nameOfFunctionCalled == QLatin1String("QT_TR_NOOP") || *_nameOfFunctionCalled == QLatin1String("QT_TRID_NOOP")) { - QVector::ConstIterator param = _functionParameters.constBegin(); - QVector::ConstIterator end = _functionParameters.constEnd(); - if (param == end) - return false; - - QV4::IR::String *stringParam = _temps[*param]->asString(); - if (!stringParam) - return false; - - ++param; - if (param != end) - return false; - - binding->type = QV4::CompiledData::Binding::Type_String; - binding->stringIndex = compiler->registerString(*stringParam->value); - return true; - } else if (*_nameOfFunctionCalled == QLatin1String("QT_TRANSLATE_NOOP")) { - QVector::ConstIterator param = _functionParameters.constBegin(); - QVector::ConstIterator end = _functionParameters.constEnd(); - if (param == end) - return false; - - ++param; - if (param == end) - return false; - - QV4::IR::String *stringParam = _temps[*param]->asString(); - if (!stringParam) - return false; - - ++param; - if (param != end) - return false; - - binding->type = QV4::CompiledData::Binding::Type_String; - binding->stringIndex = compiler->registerString(*stringParam->value); - return true; - } - return false; -} - -QQmlIRFunctionCleanser::QQmlIRFunctionCleanser(QQmlTypeCompiler *typeCompiler, const QVector &functionsToRemove) - : QQmlCompilePass(typeCompiler) - , module(typeCompiler->jsIRModule()) - , functionsToRemove(functionsToRemove) -{ -} - -void QQmlIRFunctionCleanser::clean() -{ - QVector newFunctions; - newFunctions.reserve(module->functions.count() - functionsToRemove.count()); - - newFunctionIndices.resize(module->functions.count()); - - for (int i = 0; i < module->functions.count(); ++i) { - QV4::IR::Function *f = module->functions.at(i); - Q_ASSERT(f || functionsToRemove.contains(i)); - if (f) { - newFunctionIndices[i] = newFunctions.count(); - newFunctions << f; - } - } - - module->functions = newFunctions; - - for (QV4::IR::Function *function : qAsConst(module->functions)) { - for (QV4::IR::BasicBlock *block : function->basicBlocks()) { - for (QV4::IR::Stmt *s : block->statements()) { - visit(s); - } - } - } - - for (QmlIR::Object *obj : qAsConst(*compiler->qmlObjects())) { - for (int i = 0; i < obj->runtimeFunctionIndices.count; ++i) - obj->runtimeFunctionIndices[i] = newFunctionIndices[obj->runtimeFunctionIndices.at(i)]; - } -} - -void QQmlIRFunctionCleanser::visit(QV4::IR::Stmt *s) -{ - - switch (s->stmtKind) { - case QV4::IR::Stmt::PhiStmt: - // nothing to do - break; - default: - STMT_VISIT_ALL_KINDS(s); - break; - } -} - -void QQmlIRFunctionCleanser::visit(QV4::IR::Expr *e) -{ - switch (e->exprKind) { - case QV4::IR::Expr::ClosureExpr: { - auto closure = e->asClosure(); - closure->value = newFunctionIndices.at(closure->value); - } break; - default: - EXPR_VISIT_ALL_KINDS(e); - break; - } -} - QT_END_NAMESPACE diff --git a/src/qml/compiler/qqmltypecompiler_p.h b/src/qml/compiler/qqmltypecompiler_p.h index 11261e3099..79fc073d8b 100644 --- a/src/qml/compiler/qqmltypecompiler_p.h +++ b/src/qml/compiler/qqmltypecompiler_p.h @@ -345,86 +345,6 @@ private: const QQmlPropertyCacheVector * const propertyCaches; }; -class QQmlJavaScriptBindingExpressionSimplificationPass : public QQmlCompilePass -{ -public: - QQmlJavaScriptBindingExpressionSimplificationPass(QQmlTypeCompiler *typeCompiler); - - void reduceTranslationBindings(); - -private: - void reduceTranslationBindings(int objectIndex); - - void visit(QV4::IR::Stmt *s) - { - switch (s->stmtKind) { - case QV4::IR::Stmt::MoveStmt: - visitMove(s->asMove()); - break; - case QV4::IR::Stmt::RetStmt: - visitRet(s->asRet()); - break; - case QV4::IR::Stmt::CJumpStmt: - discard(); - break; - case QV4::IR::Stmt::ExpStmt: - discard(); - break; - case QV4::IR::Stmt::JumpStmt: - break; - case QV4::IR::Stmt::PhiStmt: - break; - } - } - - void visitMove(QV4::IR::Move *move); - void visitRet(QV4::IR::Ret *ret); - - void visitFunctionCall(const QString *name, QV4::IR::ExprList *args, QV4::IR::Temp *target); - - void discard() { _canSimplify = false; } - - bool simplifyBinding(QV4::IR::Function *function, QmlIR::Binding *binding); - bool detectTranslationCallAndConvertBinding(QmlIR::Binding *binding); - - const QVector &qmlObjects; - QV4::IR::Module *jsModule; - - bool _canSimplify; - const QString *_nameOfFunctionCalled; - QVector _functionParameters; - int _functionCallReturnValue; - - QHash _temps; - int _returnValueOfBindingExpression; - int _synthesizedConsts; - - QVector irFunctionsToRemove; -}; - -class QQmlIRFunctionCleanser : public QQmlCompilePass -{ -public: - QQmlIRFunctionCleanser(QQmlTypeCompiler *typeCompiler, const QVector &functionsToRemove); - - void clean(); - -private: - virtual void visitMove(QV4::IR::Move *s) { - visit(s->source); - visit(s->target); - } - - void visit(QV4::IR::Stmt *s); - void visit(QV4::IR::Expr *e); - -private: - QV4::IR::Module *module; - const QVector &functionsToRemove; - - QVector newFunctionIndices; -}; - QT_END_NAMESPACE #endif // QQMLTYPECOMPILER_P_H diff --git a/src/qml/compiler/qv4jssimplifier.cpp b/src/qml/compiler/qv4jssimplifier.cpp new file mode 100644 index 0000000000..7d09218fe6 --- /dev/null +++ b/src/qml/compiler/qv4jssimplifier.cpp @@ -0,0 +1,384 @@ +/**************************************************************************** +** +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the tools applications of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qv4jssimplifier_p.h" + +QT_BEGIN_NAMESPACE + +QQmlJavaScriptBindingExpressionSimplificationPass::QQmlJavaScriptBindingExpressionSimplificationPass(const QVector &qmlObjects, QV4::IR::Module *jsModule, QV4::Compiler::JSUnitGenerator *unitGenerator) + : qmlObjects(qmlObjects) + , jsModule(jsModule) + , unitGenerator(unitGenerator) +{ + +} + +void QQmlJavaScriptBindingExpressionSimplificationPass::reduceTranslationBindings() +{ + for (int i = 0; i < qmlObjects.count(); ++i) + reduceTranslationBindings(i); + if (!irFunctionsToRemove.isEmpty()) { + QQmlIRFunctionCleanser cleanser(jsModule, qmlObjects, irFunctionsToRemove); + cleanser.clean(); + } +} + +void QQmlJavaScriptBindingExpressionSimplificationPass::reduceTranslationBindings(int objectIndex) +{ + const QmlIR::Object *obj = qmlObjects.at(objectIndex); + + for (QmlIR::Binding *binding = obj->firstBinding(); binding; binding = binding->next) { + if (binding->type != QV4::CompiledData::Binding::Type_Script) + continue; + + const int irFunctionIndex = obj->runtimeFunctionIndices.at(binding->value.compiledScriptIndex); + QV4::IR::Function *irFunction = jsModule->functions.at(irFunctionIndex); + if (simplifyBinding(irFunction, binding)) { + irFunctionsToRemove.append(irFunctionIndex); + jsModule->functions[irFunctionIndex] = 0; + delete irFunction; + } + } +} + +void QQmlJavaScriptBindingExpressionSimplificationPass::visitMove(QV4::IR::Move *move) +{ + QV4::IR::Temp *target = move->target->asTemp(); + if (!target || target->kind != QV4::IR::Temp::VirtualRegister) { + discard(); + return; + } + + if (QV4::IR::Call *call = move->source->asCall()) { + if (QV4::IR::Name *n = call->base->asName()) { + if (n->builtin == QV4::IR::Name::builtin_invalid) { + visitFunctionCall(n->id, call->args, target); + return; + } + } + discard(); + return; + } + + if (QV4::IR::Name *n = move->source->asName()) { + if (n->builtin == QV4::IR::Name::builtin_qml_context + || n->builtin == QV4::IR::Name::builtin_qml_imported_scripts_object) { + // these are free of side-effects + return; + } + discard(); + return; + } + + if (!move->source->asTemp() && !move->source->asString() && !move->source->asConst()) { + discard(); + return; + } + + _temps[target->index] = move->source; +} + +void QQmlJavaScriptBindingExpressionSimplificationPass::visitFunctionCall(const QString *name, QV4::IR::ExprList *args, QV4::IR::Temp *target) +{ + // more than one function call? + if (_nameOfFunctionCalled) { + discard(); + return; + } + + _nameOfFunctionCalled = name; + + _functionParameters.clear(); + while (args) { + int slot; + if (QV4::IR::Temp *param = args->expr->asTemp()) { + if (param->kind != QV4::IR::Temp::VirtualRegister) { + discard(); + return; + } + slot = param->index; + _functionParameters.append(slot); + } else if (QV4::IR::Const *param = args->expr->asConst()) { + slot = --_synthesizedConsts; + Q_ASSERT(!_temps.contains(slot)); + _temps[slot] = param; + _functionParameters.append(slot); + } + args = args->next; + } + + _functionCallReturnValue = target->index; +} + +void QQmlJavaScriptBindingExpressionSimplificationPass::visitRet(QV4::IR::Ret *ret) +{ + // nothing initialized earlier? + if (_returnValueOfBindingExpression != -1) { + discard(); + return; + } + QV4::IR::Temp *target = ret->expr->asTemp(); + if (!target || target->kind != QV4::IR::Temp::VirtualRegister) { + discard(); + return; + } + _returnValueOfBindingExpression = target->index; +} + +bool QQmlJavaScriptBindingExpressionSimplificationPass::simplifyBinding(QV4::IR::Function *function, QmlIR::Binding *binding) +{ + _canSimplify = true; + _nameOfFunctionCalled = 0; + _functionParameters.clear(); + _functionCallReturnValue = -1; + _temps.clear(); + _returnValueOfBindingExpression = -1; + _synthesizedConsts = 0; + + // It would seem unlikely that function with some many basic blocks (after optimization) + // consists merely of a qsTr call or a constant value return ;-) + if (function->basicBlockCount() > 10) + return false; + + for (QV4::IR::BasicBlock *bb : function->basicBlocks()) { + for (QV4::IR::Stmt *s : bb->statements()) { + visit(s); + if (!_canSimplify) + return false; + } + } + + if (_returnValueOfBindingExpression == -1) + return false; + + if (_nameOfFunctionCalled) { + if (_functionCallReturnValue != _returnValueOfBindingExpression) + return false; + return detectTranslationCallAndConvertBinding(binding); + } + + return false; +} + +bool QQmlJavaScriptBindingExpressionSimplificationPass::detectTranslationCallAndConvertBinding(QmlIR::Binding *binding) +{ + if (*_nameOfFunctionCalled == QLatin1String("qsTr")) { + QString translation; + QV4::CompiledData::TranslationData translationData; + translationData.number = -1; + translationData.commentIndex = 0; // empty string + + QVector::ConstIterator param = _functionParameters.constBegin(); + QVector::ConstIterator end = _functionParameters.constEnd(); + if (param == end) + return false; + + QV4::IR::String *stringParam = _temps[*param]->asString(); + if (!stringParam) + return false; + + translation = *stringParam->value; + + ++param; + if (param != end) { + stringParam = _temps[*param]->asString(); + if (!stringParam) + return false; + translationData.commentIndex = unitGenerator->registerString(*stringParam->value); + ++param; + + if (param != end) { + QV4::IR::Const *constParam = _temps[*param]->asConst(); + if (!constParam || constParam->type != QV4::IR::SInt32Type) + return false; + + translationData.number = int(constParam->value); + ++param; + } + } + + if (param != end) + return false; + + binding->type = QV4::CompiledData::Binding::Type_Translation; + binding->stringIndex = unitGenerator->registerString(translation); + binding->value.translationData = translationData; + return true; + } else if (*_nameOfFunctionCalled == QLatin1String("qsTrId")) { + QString id; + QV4::CompiledData::TranslationData translationData; + translationData.number = -1; + translationData.commentIndex = 0; // empty string, but unused + + QVector::ConstIterator param = _functionParameters.constBegin(); + QVector::ConstIterator end = _functionParameters.constEnd(); + if (param == end) + return false; + + QV4::IR::String *stringParam = _temps[*param]->asString(); + if (!stringParam) + return false; + + id = *stringParam->value; + + ++param; + if (param != end) { + QV4::IR::Const *constParam = _temps[*param]->asConst(); + if (!constParam || constParam->type != QV4::IR::SInt32Type) + return false; + + translationData.number = int(constParam->value); + ++param; + } + + if (param != end) + return false; + + binding->type = QV4::CompiledData::Binding::Type_TranslationById; + binding->stringIndex = unitGenerator->registerString(id); + binding->value.translationData = translationData; + return true; + } else if (*_nameOfFunctionCalled == QLatin1String("QT_TR_NOOP") || *_nameOfFunctionCalled == QLatin1String("QT_TRID_NOOP")) { + QVector::ConstIterator param = _functionParameters.constBegin(); + QVector::ConstIterator end = _functionParameters.constEnd(); + if (param == end) + return false; + + QV4::IR::String *stringParam = _temps[*param]->asString(); + if (!stringParam) + return false; + + ++param; + if (param != end) + return false; + + binding->type = QV4::CompiledData::Binding::Type_String; + binding->stringIndex = unitGenerator->registerString(*stringParam->value); + return true; + } else if (*_nameOfFunctionCalled == QLatin1String("QT_TRANSLATE_NOOP")) { + QVector::ConstIterator param = _functionParameters.constBegin(); + QVector::ConstIterator end = _functionParameters.constEnd(); + if (param == end) + return false; + + ++param; + if (param == end) + return false; + + QV4::IR::String *stringParam = _temps[*param]->asString(); + if (!stringParam) + return false; + + ++param; + if (param != end) + return false; + + binding->type = QV4::CompiledData::Binding::Type_String; + binding->stringIndex = unitGenerator->registerString(*stringParam->value); + return true; + } + return false; +} + +QQmlIRFunctionCleanser::QQmlIRFunctionCleanser(QV4::IR::Module *module, const QVector &qmlObjects, const QVector &functionsToRemove) + : module(module) + , qmlObjects(qmlObjects) + , functionsToRemove(functionsToRemove) +{ +} + +void QQmlIRFunctionCleanser::clean() +{ + QVector newFunctions; + newFunctions.reserve(module->functions.count() - functionsToRemove.count()); + + newFunctionIndices.resize(module->functions.count()); + + for (int i = 0; i < module->functions.count(); ++i) { + QV4::IR::Function *f = module->functions.at(i); + Q_ASSERT(f || functionsToRemove.contains(i)); + if (f) { + newFunctionIndices[i] = newFunctions.count(); + newFunctions << f; + } + } + + module->functions = newFunctions; + + for (QV4::IR::Function *function : qAsConst(module->functions)) { + for (QV4::IR::BasicBlock *block : function->basicBlocks()) { + for (QV4::IR::Stmt *s : block->statements()) { + visit(s); + } + } + } + + for (QmlIR::Object *obj : qmlObjects) { + for (int i = 0; i < obj->runtimeFunctionIndices.count; ++i) + obj->runtimeFunctionIndices[i] = newFunctionIndices[obj->runtimeFunctionIndices.at(i)]; + } +} + +void QQmlIRFunctionCleanser::visit(QV4::IR::Stmt *s) +{ + + switch (s->stmtKind) { + case QV4::IR::Stmt::PhiStmt: + // nothing to do + break; + default: + STMT_VISIT_ALL_KINDS(s); + break; + } +} + +void QQmlIRFunctionCleanser::visit(QV4::IR::Expr *e) +{ + switch (e->exprKind) { + case QV4::IR::Expr::ClosureExpr: { + auto closure = e->asClosure(); + closure->value = newFunctionIndices.at(closure->value); + } break; + default: + EXPR_VISIT_ALL_KINDS(e); + break; + } +} + +QT_END_NAMESPACE diff --git a/src/qml/compiler/qv4jssimplifier_p.h b/src/qml/compiler/qv4jssimplifier_p.h new file mode 100644 index 0000000000..ae8d74135c --- /dev/null +++ b/src/qml/compiler/qv4jssimplifier_p.h @@ -0,0 +1,154 @@ +/**************************************************************************** +** +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the tools applications 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 QV4JSSIMPLIFIER +#define QV4JSSIMPLIFIER + +// +// 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 "qqmlirbuilder_p.h" + +QT_BEGIN_NAMESPACE + +namespace QmlIR { +struct Document; +} + +namespace QV4 { +namespace CompiledData { +struct QmlUnit; +struct Location; +} +} + +class QQmlJavaScriptBindingExpressionSimplificationPass +{ +public: + QQmlJavaScriptBindingExpressionSimplificationPass(const QVector &qmlObjects, QV4::IR::Module *jsModule, QV4::Compiler::JSUnitGenerator *unitGenerator); + + void reduceTranslationBindings(); + +private: + void reduceTranslationBindings(int objectIndex); + + void visit(QV4::IR::Stmt *s) + { + switch (s->stmtKind) { + case QV4::IR::Stmt::MoveStmt: + visitMove(s->asMove()); + break; + case QV4::IR::Stmt::RetStmt: + visitRet(s->asRet()); + break; + case QV4::IR::Stmt::CJumpStmt: + discard(); + break; + case QV4::IR::Stmt::ExpStmt: + discard(); + break; + case QV4::IR::Stmt::JumpStmt: + break; + case QV4::IR::Stmt::PhiStmt: + break; + } + } + + void visitMove(QV4::IR::Move *move); + void visitRet(QV4::IR::Ret *ret); + + void visitFunctionCall(const QString *name, QV4::IR::ExprList *args, QV4::IR::Temp *target); + + void discard() { _canSimplify = false; } + + bool simplifyBinding(QV4::IR::Function *function, QmlIR::Binding *binding); + bool detectTranslationCallAndConvertBinding(QmlIR::Binding *binding); + + const QVector &qmlObjects; + QV4::IR::Module *jsModule; + QV4::Compiler::JSUnitGenerator *unitGenerator; + + bool _canSimplify; + const QString *_nameOfFunctionCalled; + QVector _functionParameters; + int _functionCallReturnValue; + + QHash _temps; + int _returnValueOfBindingExpression; + int _synthesizedConsts; + + QVector irFunctionsToRemove; +}; + +class QQmlIRFunctionCleanser +{ +public: + QQmlIRFunctionCleanser(QV4::IR::Module *module, const QVector &qmlObjects, const QVector &functionsToRemove); + + void clean(); + +private: + virtual void visitMove(QV4::IR::Move *s) { + visit(s->source); + visit(s->target); + } + + void visit(QV4::IR::Stmt *s); + void visit(QV4::IR::Expr *e); + +private: + QV4::IR::Module *module; + const QVector &qmlObjects; + const QVector &functionsToRemove; + + QVector newFunctionIndices; +}; + +QT_END_NAMESPACE + +#endif // QV4JSSIMPLIFIER -- cgit v1.2.3 From fd0ee94d961458760243db8ec7306206905ef4f9 Mon Sep 17 00:00:00 2001 From: Lars Knoll Date: Thu, 6 Apr 2017 13:51:12 +0200 Subject: Correctly compute the amount of variables we need to mark CallContext.locals.alloc was computed incorrectly. This number is being used to determine which memory could contain valid pointers during marking. The old code was off by 2, leading to the last two arguments not getting marked properly during GC. Fixes a regression introduced in 3a0bb11d. Task-number: QTBUG-59928 Task-number: QTBUG-59600 Change-Id: I88f58a237c9a5f02434c0d4081c4e368cd944a5b Reviewed-by: Simon Hausmann --- src/qml/jsruntime/qv4context.cpp | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/src/qml/jsruntime/qv4context.cpp b/src/qml/jsruntime/qv4context.cpp index b71e71b92f..02d3af619e 100644 --- a/src/qml/jsruntime/qv4context.cpp +++ b/src/qml/jsruntime/qv4context.cpp @@ -62,9 +62,8 @@ DEFINE_MANAGED_VTABLE(GlobalContext); Heap::CallContext *ExecutionContext::newCallContext(Function *function, CallData *callData) { - uint localsAndFormals = function->compiledFunction->nLocals + qMax(static_cast(callData->argc), function->nFormals); - size_t requiredMemory = sizeof(CallContext::Data) - sizeof(Value) + \ - sizeof(Value) * (localsAndFormals) + sizeof(CallData) - sizeof(Value); + uint localsAndFormals = function->compiledFunction->nLocals + sizeof(CallData)/sizeof(Value) - 1 + qMax(static_cast(callData->argc), function->nFormals); + size_t requiredMemory = sizeof(CallContext::Data) - sizeof(Value) + sizeof(Value) * (localsAndFormals); Heap::CallContext *c = d()->engine->memoryManager->allocManaged(requiredMemory); c->init(d()->engine, Heap::ExecutionContext::Type_CallContext); -- cgit v1.2.3 From 7c709ee4404e737bebd576c4a1782593a6ec7da0 Mon Sep 17 00:00:00 2001 From: Simon Hausmann Date: Thu, 6 Apr 2017 15:48:12 +0200 Subject: Fix locals register allocation on ARM when cross-compiling r11 needs to be saved :). This ammends ecda87091f290daec34bee6b55dd9cf920ffdcff Change-Id: Ib69712527e04b9bcec4c9e74dea43a915e2bd0f9 Reviewed-by: Robin Burchell --- src/qml/jit/qv4targetplatform_p.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/qml/jit/qv4targetplatform_p.h b/src/qml/jit/qv4targetplatform_p.h index ce6156802d..6d788f4a93 100644 --- a/src/qml/jit/qv4targetplatform_p.h +++ b/src/qml/jit/qv4targetplatform_p.h @@ -405,7 +405,7 @@ public: << RI(JSC::ARMRegisters::r9, QStringLiteral("r9"), RI::RegularRegister, RI::CalleeSaved, RI::RegAlloc) #endif << RI(JSC::ARMRegisters::r10, QStringLiteral("r10"), RI::RegularRegister, RI::CalleeSaved, RI::Predefined) -#if CPU(ARM_THUMB2) && !defined(V4_BOOTSTRAP) +#if CPU(ARM_THUMB2) || defined(V4_BOOTSTRAP) << RI(JSC::ARMRegisters::r11, QStringLiteral("r11"), RI::RegularRegister, RI::CalleeSaved, RI::Predefined) #endif << RI(JSC::ARMRegisters::d2, QStringLiteral("d2"), RI::FloatingPointRegister, RI::CallerSaved, RI::RegAlloc) -- cgit v1.2.3 From 8aa36b6cff134fba3b226cbd596ee256d2c490d2 Mon Sep 17 00:00:00 2001 From: Lars Knoll Date: Fri, 31 Mar 2017 09:28:53 +0200 Subject: Avoid stack overflows during GC runs When marking very large objects, the old code could overflow the GC stack, as it would push all it's children onto the GC stack. Be more careful about this and drain the mark stack from time to time if required. Change-Id: If11ca521f405ce63b894d4e43a83b68d33a844af Reviewed-by: Simon Hausmann --- src/qml/memory/qv4mm.cpp | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/src/qml/memory/qv4mm.cpp b/src/qml/memory/qv4mm.cpp index c025dd09a4..f117bbc10f 100644 --- a/src/qml/memory/qv4mm.cpp +++ b/src/qml/memory/qv4mm.cpp @@ -885,9 +885,21 @@ void MemoryManager::drainMarkStack(Value *markBase) ValueArray<0> *a = reinterpret_cast *>(mem); Value *v = a->values; const Value *end = v + a->alloc; - while (v < end) { - v->mark(engine); - ++v; + if (a->alloc > 32*1024) { + // drain from time to time to avoid overflows in the js stack + Value *currentBase = engine->jsStackTop; + while (v < end) { + v->mark(engine); + ++v; + if (engine->jsStackTop >= currentBase + 32*1024) + drainMarkStack(currentBase); + } + + } else { + while (v < end) { + v->mark(engine); + ++v; + } } break; } -- cgit v1.2.3 From a410cb69012603a38a07f7670e2ad1c1876f675a Mon Sep 17 00:00:00 2001 From: Lars Knoll Date: Thu, 9 Mar 2017 11:40:53 +0100 Subject: Remove assertObjectBelongsToEngine method It's only used during mark() calls, where we can be reasonably safe that the assertion holds. But mark() needs to change and become independent of the execution engine for concurrent collection, so remove the assert as a preparation. Change-Id: I52266af719afd76048d73efdcfcf96c0abc8843f Reviewed-by: Simon Hausmann --- src/qml/jsruntime/qv4engine.cpp | 6 ------ src/qml/jsruntime/qv4engine_p.h | 5 ----- 2 files changed, 11 deletions(-) (limited to 'src') diff --git a/src/qml/jsruntime/qv4engine.cpp b/src/qml/jsruntime/qv4engine.cpp index 679cd41ce0..99efa1cc13 100644 --- a/src/qml/jsruntime/qv4engine.cpp +++ b/src/qml/jsruntime/qv4engine.cpp @@ -1568,12 +1568,6 @@ QV4::ReturnedValue ExecutionEngine::metaTypeToJS(int type, const void *data) return 0; } -void ExecutionEngine::assertObjectBelongsToEngine(const Heap::Base &baseObject) -{ - Q_ASSERT(!baseObject.vtable()->isObject || static_cast(baseObject).internalClass->engine == this); - Q_UNUSED(baseObject); -} - void ExecutionEngine::failStackLimitCheck(Scope &scope) { scope.result = throwRangeError(QStringLiteral("Maximum call stack size exceeded.")); diff --git a/src/qml/jsruntime/qv4engine_p.h b/src/qml/jsruntime/qv4engine_p.h index 1160d69c6c..cf2ebe268d 100644 --- a/src/qml/jsruntime/qv4engine_p.h +++ b/src/qml/jsruntime/qv4engine_p.h @@ -483,8 +483,6 @@ public: bool metaTypeFromJS(const Value *value, int type, void *data); QV4::ReturnedValue metaTypeToJS(int type, const void *data); - void assertObjectBelongsToEngine(const Heap::Base &baseObject); - bool checkStackLimits(Scope &scope); private: @@ -553,9 +551,6 @@ void Heap::Base::mark(QV4::ExecutionEngine *engine) quintptr *bitmap = c->blackBitmap + Chunk::bitmapIndex(index); quintptr bit = Chunk::bitForIndex(index); if (!(*bitmap & bit)) { -#ifndef QT_NO_DEBUG - engine->assertObjectBelongsToEngine(*this); -#endif *bitmap |= bit; engine->pushForGC(this); } -- cgit v1.2.3 From 1e63f7c4833c19f760f4af0b7650311819d0f2b2 Mon Sep 17 00:00:00 2001 From: Lars Knoll Date: Tue, 4 Apr 2017 10:05:58 +0200 Subject: Cleanups * Only call ExecutionEngine::markObjects() on a full GC, it doesn't do anything in the incrementall case anyway. * Move the marking of child objects into it's own method for clarity * Move collection of gray items down to happen directly before we drain the mark stack Change-Id: I41067e17d483067bd1c4d60da22c5628482dae78 Reviewed-by: Simon Hausmann --- src/qml/jsruntime/qv4engine.cpp | 30 +++++----- src/qml/jsruntime/qv4engine_p.h | 2 +- src/qml/memory/qv4heap_p.h | 2 + src/qml/memory/qv4mm.cpp | 123 +++++++++++++++++++++------------------- 4 files changed, 81 insertions(+), 76 deletions(-) (limited to 'src') diff --git a/src/qml/jsruntime/qv4engine.cpp b/src/qml/jsruntime/qv4engine.cpp index 99efa1cc13..b9408be218 100644 --- a/src/qml/jsruntime/qv4engine.cpp +++ b/src/qml/jsruntime/qv4engine.cpp @@ -148,8 +148,6 @@ ExecutionEngine::ExecutionEngine(EvalISelFactory *factory) , m_profiler(0) #endif { - writeBarrierActive = true; - memoryManager = new QV4::MemoryManager(this); if (maxCallDepth == -1) { @@ -932,25 +930,23 @@ void ExecutionEngine::requireArgumentsAccessors(int n) } } -void ExecutionEngine::markObjects(bool incremental) +void ExecutionEngine::markObjects() { - if (!incremental) { - identifierTable->mark(this); + identifierTable->mark(this); - for (int i = 0; i < nArgumentsAccessors; ++i) { - const Property &pd = argumentsAccessors[i]; - if (Heap::FunctionObject *getter = pd.getter()) - getter->mark(this); - if (Heap::FunctionObject *setter = pd.setter()) - setter->mark(this); - } + for (int i = 0; i < nArgumentsAccessors; ++i) { + const Property &pd = argumentsAccessors[i]; + if (Heap::FunctionObject *getter = pd.getter()) + getter->mark(this); + if (Heap::FunctionObject *setter = pd.setter()) + setter->mark(this); + } - classPool->markObjects(this); + classPool->markObjects(this); - for (QSet::ConstIterator it = compilationUnits.constBegin(), end = compilationUnits.constEnd(); - it != end; ++it) - (*it)->markObjects(this); - } + for (QSet::ConstIterator it = compilationUnits.constBegin(), end = compilationUnits.constEnd(); + it != end; ++it) + (*it)->markObjects(this); } ReturnedValue ExecutionEngine::throwError(const Value &value) diff --git a/src/qml/jsruntime/qv4engine_p.h b/src/qml/jsruntime/qv4engine_p.h index cf2ebe268d..fdfdeada9a 100644 --- a/src/qml/jsruntime/qv4engine_p.h +++ b/src/qml/jsruntime/qv4engine_p.h @@ -446,7 +446,7 @@ public: void requireArgumentsAccessors(int n); - void markObjects(bool incremental); + void markObjects(); void initRootContext(); diff --git a/src/qml/memory/qv4heap_p.h b/src/qml/memory/qv4heap_p.h index 1347a9bd6e..6c7da91ba0 100644 --- a/src/qml/memory/qv4heap_p.h +++ b/src/qml/memory/qv4heap_p.h @@ -127,6 +127,8 @@ struct Q_QML_EXPORT Base { return Chunk::testBit(c->objectBitmap, h - c->realBase()); } + inline void markChildren(ExecutionEngine *engine); + void *operator new(size_t, Managed *m) { return m; } void *operator new(size_t, Heap::Base *m) { return m; } void operator delete(void *, Heap::Base *) {} diff --git a/src/qml/memory/qv4mm.cpp b/src/qml/memory/qv4mm.cpp index f117bbc10f..28330a93c9 100644 --- a/src/qml/memory/qv4mm.cpp +++ b/src/qml/memory/qv4mm.cpp @@ -260,6 +260,62 @@ void ChunkAllocator::free(Chunk *chunk, size_t size) } +void Heap::Base::markChildren(ExecutionEngine *engine) +{ + if (vtable()->markObjects) + vtable()->markObjects(this, engine); + if (quint64 m = vtable()->markTable) { +// qDebug() << "using mark table:" << hex << m << "for" << h; + void **mem = reinterpret_cast(this); + while (m) { + MarkFlags mark = static_cast(m & 3); + switch (mark) { + case Mark_NoMark: + break; + case Mark_Value: +// qDebug() << "marking value at " << mem; + reinterpret_cast(mem)->mark(engine); + break; + case Mark_Pointer: { +// qDebug() << "marking pointer at " << mem; + Heap::Base *p = *reinterpret_cast(mem); + if (p) + p->mark(engine); + break; + } + case Mark_ValueArray: { + Q_ASSERT(m == Mark_ValueArray); +// qDebug() << "marking Value Array at offset" << hex << (mem - reinterpret_cast(h)); + ValueArray<0> *a = reinterpret_cast *>(mem); + Value *v = a->values; + const Value *end = v + a->alloc; + if (a->alloc > 32*1024) { + // drain from time to time to avoid overflows in the js stack + Value *currentBase = engine->jsStackTop; + while (v < end) { + v->mark(engine); + ++v; + if (engine->jsStackTop >= currentBase + 32*1024) + engine->memoryManager->drainMarkStack(currentBase); + } + + } else { + while (v < end) { + v->mark(engine); + ++v; + } + } + break; + } + } + + m >>= 2; + ++mem; + } + } +} + + void Chunk::sweep() { // DEBUG << "sweeping chunk" << this << (*freeList); @@ -858,57 +914,7 @@ void MemoryManager::drainMarkStack(Value *markBase) Heap::Base *h = engine->popForGC(); ++markStackSize; Q_ASSERT(h); // at this point we should only have Heap::Base objects in this area on the stack. If not, weird things might happen. - if (h->vtable()->markObjects) - h->vtable()->markObjects(h, engine); - if (quint64 m = h->vtable()->markTable) { -// qDebug() << "using mark table:" << hex << m << "for" << h; - void **mem = reinterpret_cast(h); - while (m) { - MarkFlags mark = static_cast(m & 3); - switch (mark) { - case Mark_NoMark: - break; - case Mark_Value: -// qDebug() << "marking value at " << mem; - reinterpret_cast(mem)->mark(engine); - break; - case Mark_Pointer: { -// qDebug() << "marking pointer at " << mem; - Heap::Base *p = *reinterpret_cast(mem); - if (p) - p->mark(engine); - break; - } - case Mark_ValueArray: { - Q_ASSERT(m == Mark_ValueArray); -// qDebug() << "marking Value Array at offset" << hex << (mem - reinterpret_cast(h)); - ValueArray<0> *a = reinterpret_cast *>(mem); - Value *v = a->values; - const Value *end = v + a->alloc; - if (a->alloc > 32*1024) { - // drain from time to time to avoid overflows in the js stack - Value *currentBase = engine->jsStackTop; - while (v < end) { - v->mark(engine); - ++v; - if (engine->jsStackTop >= currentBase + 32*1024) - drainMarkStack(currentBase); - } - - } else { - while (v < end) { - v->mark(engine); - ++v; - } - } - break; - } - } - - m >>= 2; - ++mem; - } - } + h->markChildren(engine); } } @@ -918,16 +924,11 @@ void MemoryManager::mark() markStackSize = 0; - if (nextGCIsIncremental) { - // need to collect all gray items and push them onto the mark stack - blockAllocator.collectGrayItems(engine); - hugeItemAllocator.collectGrayItems(engine); - } - // qDebug() << ">>>> Mark phase:"; // qDebug() << " mark stack after gray items" << (engine->jsStackTop - markBase); - engine->markObjects(nextGCIsIncremental); + if (!nextGCIsIncremental) + engine->markObjects(); // qDebug() << " mark stack after engine->mark" << (engine->jsStackTop - markBase); @@ -969,6 +970,12 @@ void MemoryManager::mark() drainMarkStack(markBase); } + if (nextGCIsIncremental) { + // need to collect all gray items and push them onto the mark stack + blockAllocator.collectGrayItems(engine); + hugeItemAllocator.collectGrayItems(engine); + } + drainMarkStack(markBase); } -- cgit v1.2.3 From 589f8a90fa8c158ec97f32d4a9539b47ba8486a2 Mon Sep 17 00:00:00 2001 From: Lars Knoll Date: Thu, 9 Mar 2017 10:36:16 +0100 Subject: Separate the stack used for GC from the regular JS stack This is required to be able to implement concurrent or incremental garbage collection. Change-Id: Ib3c5eee3779ca2ee08a57cd3961dbcb0537bbb54 Reviewed-by: Simon Hausmann --- src/qml/compiler/qv4compileddata.cpp | 6 +- src/qml/compiler/qv4compileddata_p.h | 2 +- src/qml/jsruntime/qv4engine.cpp | 27 +++++--- src/qml/jsruntime/qv4engine_p.h | 24 +++---- src/qml/jsruntime/qv4identifiertable_p.h | 4 +- src/qml/jsruntime/qv4internalclass.cpp | 4 +- src/qml/jsruntime/qv4internalclass_p.h | 2 +- src/qml/jsruntime/qv4managed_p.h | 2 +- src/qml/jsruntime/qv4objectiterator.cpp | 8 +-- src/qml/jsruntime/qv4objectiterator_p.h | 2 +- src/qml/jsruntime/qv4persistent.cpp | 12 ++-- src/qml/jsruntime/qv4persistent_p.h | 4 +- src/qml/jsruntime/qv4qobjectwrapper.cpp | 28 ++++----- src/qml/jsruntime/qv4qobjectwrapper_p.h | 6 +- src/qml/jsruntime/qv4string.cpp | 6 +- src/qml/jsruntime/qv4string_p.h | 2 +- src/qml/jsruntime/qv4value_p.h | 2 +- src/qml/memory/qv4heap_p.h | 6 +- src/qml/memory/qv4mm.cpp | 90 +++++++++++++++------------ src/qml/memory/qv4mm_p.h | 9 ++- src/qml/memory/qv4mmdefs_p.h | 22 ++++++- src/qml/qml/qqmlvmemetaobject.cpp | 8 +-- src/qml/qml/qqmlvmemetaobject_p.h | 2 +- src/quick/items/context2d/qquickcontext2d.cpp | 6 +- src/quick/items/qquickitem.cpp | 8 +-- 25 files changed, 162 insertions(+), 130 deletions(-) (limited to 'src') diff --git a/src/qml/compiler/qv4compileddata.cpp b/src/qml/compiler/qv4compileddata.cpp index c56f08c2f0..7940e5715e 100644 --- a/src/qml/compiler/qv4compileddata.cpp +++ b/src/qml/compiler/qv4compileddata.cpp @@ -249,14 +249,14 @@ void CompilationUnit::unlink() #endif } -void CompilationUnit::markObjects(QV4::ExecutionEngine *e) +void CompilationUnit::markObjects(QV4::MarkStack *markStack) { for (uint i = 0; i < data->stringTableSize; ++i) if (runtimeStrings[i]) - runtimeStrings[i]->mark(e); + runtimeStrings[i]->mark(markStack); if (runtimeRegularExpressions) { for (uint i = 0; i < data->regexpTableSize; ++i) - runtimeRegularExpressions[i].mark(e); + runtimeRegularExpressions[i].mark(markStack); } } diff --git a/src/qml/compiler/qv4compileddata_p.h b/src/qml/compiler/qv4compileddata_p.h index 6e9121b5e3..f4ba257cf5 100644 --- a/src/qml/compiler/qv4compileddata_p.h +++ b/src/qml/compiler/qv4compileddata_p.h @@ -897,7 +897,7 @@ struct Q_QML_PRIVATE_EXPORT CompilationUnit : public CompilationUnitBase, public QV4::Function *linkToEngine(QV4::ExecutionEngine *engine); void unlink(); - void markObjects(QV4::ExecutionEngine *e); + void markObjects(MarkStack *markStack); void destroy() Q_DECL_OVERRIDE; diff --git a/src/qml/jsruntime/qv4engine.cpp b/src/qml/jsruntime/qv4engine.cpp index b9408be218..dd8cb177b4 100644 --- a/src/qml/jsruntime/qv4engine.cpp +++ b/src/qml/jsruntime/qv4engine.cpp @@ -136,6 +136,7 @@ ExecutionEngine::ExecutionEngine(EvalISelFactory *factory) , currentContext(0) , bumperPointerAllocator(new WTF::BumpPointerAllocator) , jsStack(new WTF::PageAllocation) + , gcStack(new WTF::PageAllocation) , globalCode(0) , v8Engine(0) , argumentsAccessors(0) @@ -188,18 +189,22 @@ ExecutionEngine::ExecutionEngine(EvalISelFactory *factory) iselFactory.reset(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, + // we allow it to grow to a bit more than JSStackLimit, as we can overshoot due to ScopedValues + // allocated outside of JIT'ed methods. + *jsStack = WTF::PageAllocation::allocate(JSStackLimit + 256*1024, WTF::OSAllocator::JSVMStackPages, /* writable */ true, /* executable */ false, /* includesGuardPages */ true); jsStackBase = (Value *)jsStack->base(); #ifdef V4_USE_VALGRIND - VALGRIND_MAKE_MEM_UNDEFINED(jsStackBase, 2*JSStackLimit); + VALGRIND_MAKE_MEM_UNDEFINED(jsStackBase, JSStackLimit + 256*1024); #endif jsStackTop = jsStackBase; + *gcStack = WTF::PageAllocation::allocate(GCStackLimit, WTF::OSAllocator::JSVMStackPages, + /* writable */ true, /* executable */ false, + /* includesGuardPages */ true); + exceptionValue = jsAlloca(1); globalObject = static_cast(jsAlloca(1)); jsObjects = jsAlloca(NJSObjects); @@ -493,6 +498,8 @@ ExecutionEngine::~ExecutionEngine() delete executableAllocator; jsStack->deallocate(); delete jsStack; + gcStack->deallocate(); + delete gcStack; delete [] argumentsAccessors; } @@ -930,23 +937,23 @@ void ExecutionEngine::requireArgumentsAccessors(int n) } } -void ExecutionEngine::markObjects() +void ExecutionEngine::markObjects(MarkStack *markStack) { - identifierTable->mark(this); + identifierTable->mark(markStack); for (int i = 0; i < nArgumentsAccessors; ++i) { const Property &pd = argumentsAccessors[i]; if (Heap::FunctionObject *getter = pd.getter()) - getter->mark(this); + getter->mark(markStack); if (Heap::FunctionObject *setter = pd.setter()) - setter->mark(this); + setter->mark(markStack); } - classPool->markObjects(this); + classPool->markObjects(markStack); for (QSet::ConstIterator it = compilationUnits.constBegin(), end = compilationUnits.constEnd(); it != end; ++it) - (*it)->markObjects(this); + (*it)->markObjects(markStack); } ReturnedValue ExecutionEngine::throwError(const Value &value) diff --git a/src/qml/jsruntime/qv4engine_p.h b/src/qml/jsruntime/qv4engine_p.h index fdfdeada9a..bace8b700b 100644 --- a/src/qml/jsruntime/qv4engine_p.h +++ b/src/qml/jsruntime/qv4engine_p.h @@ -108,18 +108,14 @@ public: WTF::BumpPointerAllocator *bumperPointerAllocator; // Used by Yarr Regex engine. - enum { JSStackLimit = 4*1024*1024 }; + enum { + JSStackLimit = 4*1024*1024, + GCStackLimit = 2*1024*1024 + }; WTF::PageAllocation *jsStack; Value *jsStackBase; - void pushForGC(Heap::Base *m) { - *jsStackTop = m; - ++jsStackTop; - } - Heap::Base *popForGC() { - --jsStackTop; - return jsStackTop->m(); - } + WTF::PageAllocation *gcStack; QML_NEARLY_ALWAYS_INLINE Value *jsAlloca(int nValues) { Value *ptr = jsStackTop; @@ -446,7 +442,7 @@ public: void requireArgumentsAccessors(int n); - void markObjects(); + void markObjects(MarkStack *markStack); void initRootContext(); @@ -541,7 +537,7 @@ inline ExecutionContext *ExecutionEngine::parentContext(ExecutionContext *contex } inline -void Heap::Base::mark(QV4::ExecutionEngine *engine) +void Heap::Base::mark(QV4::MarkStack *markStack) { Q_ASSERT(inUse()); const HeapItem *h = reinterpret_cast(this); @@ -552,15 +548,15 @@ void Heap::Base::mark(QV4::ExecutionEngine *engine) quintptr bit = Chunk::bitForIndex(index); if (!(*bitmap & bit)) { *bitmap |= bit; - engine->pushForGC(this); + markStack->push(this); } } -inline void Value::mark(ExecutionEngine *e) +inline void Value::mark(MarkStack *markStack) { Heap::Base *o = heapObject(); if (o) - o->mark(e); + o->mark(markStack); } #define CHECK_STACK_LIMITS(v4, scope) if ((v4)->checkStackLimits(scope)) return; \ diff --git a/src/qml/jsruntime/qv4identifiertable_p.h b/src/qml/jsruntime/qv4identifiertable_p.h index 89af5db731..b0b08f1e54 100644 --- a/src/qml/jsruntime/qv4identifiertable_p.h +++ b/src/qml/jsruntime/qv4identifiertable_p.h @@ -93,14 +93,14 @@ public: Heap::String *stringFromIdentifier(Identifier *i); - void mark(ExecutionEngine *e) { + void mark(MarkStack *markStack) { for (int i = 0; i < alloc; ++i) { Heap::String *entry = entries[i]; if (!entry || entry->isMarked()) continue; entry->setMarkBit(); Q_ASSERT(entry->vtable()->markObjects); - entry->vtable()->markObjects(entry, e); + entry->vtable()->markObjects(entry, markStack); } } }; diff --git a/src/qml/jsruntime/qv4internalclass.cpp b/src/qml/jsruntime/qv4internalclass.cpp index 9b18a5566e..3d9a672f2f 100644 --- a/src/qml/jsruntime/qv4internalclass.cpp +++ b/src/qml/jsruntime/qv4internalclass.cpp @@ -388,9 +388,9 @@ void InternalClass::destroy() } } -void InternalClassPool::markObjects(ExecutionEngine *engine) +void InternalClassPool::markObjects(MarkStack *markStack) { - Q_UNUSED(engine); + Q_UNUSED(markStack); } QT_END_NAMESPACE diff --git a/src/qml/jsruntime/qv4internalclass_p.h b/src/qml/jsruntime/qv4internalclass_p.h index 1d8ef4b0fb..a29ce5b5ff 100644 --- a/src/qml/jsruntime/qv4internalclass_p.h +++ b/src/qml/jsruntime/qv4internalclass_p.h @@ -291,7 +291,7 @@ inline uint InternalClass::find(const String *string) struct InternalClassPool : public QQmlJS::MemoryPool { - void markObjects(ExecutionEngine *engine); + void markObjects(MarkStack *markStack); }; } diff --git a/src/qml/jsruntime/qv4managed_p.h b/src/qml/jsruntime/qv4managed_p.h index 3dc54b13da..9ecc4bd087 100644 --- a/src/qml/jsruntime/qv4managed_p.h +++ b/src/qml/jsruntime/qv4managed_p.h @@ -209,7 +209,7 @@ public: bool markBit() const { return d()->isMarked(); } static void destroy(Heap::Base *) {} - static void markObjects(Heap::Base *, ExecutionEngine *) {} + static void markObjects(Heap::Base *, MarkStack *) {} Q_ALWAYS_INLINE Heap::Base *heapObject() const { return m(); diff --git a/src/qml/jsruntime/qv4objectiterator.cpp b/src/qml/jsruntime/qv4objectiterator.cpp index 59115dfe21..3427ee89fe 100644 --- a/src/qml/jsruntime/qv4objectiterator.cpp +++ b/src/qml/jsruntime/qv4objectiterator.cpp @@ -177,10 +177,10 @@ ReturnedValue ObjectIterator::nextPropertyNameAsString() DEFINE_OBJECT_VTABLE(ForEachIteratorObject); -void ForEachIteratorObject::markObjects(Heap::Base *that, ExecutionEngine *e) +void ForEachIteratorObject::markObjects(Heap::Base *that, MarkStack *markStack) { ForEachIteratorObject::Data *o = static_cast(that); - o->workArea[0].mark(e); - o->workArea[1].mark(e); - Object::markObjects(that, e); + o->workArea[0].mark(markStack); + o->workArea[1].mark(markStack); + Object::markObjects(that, markStack); } diff --git a/src/qml/jsruntime/qv4objectiterator_p.h b/src/qml/jsruntime/qv4objectiterator_p.h index 98e94a95ea..6168d59914 100644 --- a/src/qml/jsruntime/qv4objectiterator_p.h +++ b/src/qml/jsruntime/qv4objectiterator_p.h @@ -129,7 +129,7 @@ struct ForEachIteratorObject: Object { ReturnedValue nextPropertyName() { return d()->it().nextPropertyNameAsString(); } protected: - static void markObjects(Heap::Base *that, ExecutionEngine *e); + static void markObjects(Heap::Base *that, MarkStack *markStack); }; inline diff --git a/src/qml/jsruntime/qv4persistent.cpp b/src/qml/jsruntime/qv4persistent.cpp index de82bf835f..0b31c971f9 100644 --- a/src/qml/jsruntime/qv4persistent.cpp +++ b/src/qml/jsruntime/qv4persistent.cpp @@ -215,17 +215,15 @@ void PersistentValueStorage::free(Value *v) freePage(p); } -void PersistentValueStorage::mark(ExecutionEngine *e) +void PersistentValueStorage::mark(MarkStack *markStack) { - Value *markBase = e->jsStackTop; - Page *p = static_cast(firstPage); while (p) { for (int i = 0; i < kEntriesPerPage; ++i) { if (Managed *m = p->values[i].as()) - m->mark(e); + m->mark(markStack); } - e->memoryManager->drainMarkStack(markBase); + markStack->drain(); p = p->header.next; } @@ -384,11 +382,11 @@ void WeakValue::allocVal(ExecutionEngine *engine) val = engine->memoryManager->m_weakValues->allocate(); } -void WeakValue::markOnce(ExecutionEngine *e) +void WeakValue::markOnce(MarkStack *markStack) { if (!val) return; - val->mark(e); + val->mark(markStack); } void WeakValue::free() diff --git a/src/qml/jsruntime/qv4persistent_p.h b/src/qml/jsruntime/qv4persistent_p.h index c1cd1f34df..1f838f5531 100644 --- a/src/qml/jsruntime/qv4persistent_p.h +++ b/src/qml/jsruntime/qv4persistent_p.h @@ -65,7 +65,7 @@ struct Q_QML_EXPORT PersistentValueStorage Value *allocate(); static void free(Value *e); - void mark(ExecutionEngine *e); + void mark(MarkStack *markStack); struct Iterator { Iterator(void *p, int idx); @@ -203,7 +203,7 @@ public: bool isNullOrUndefined() const { return !val || val->isNullOrUndefined(); } void clear() { free(); } - void markOnce(ExecutionEngine *e); + void markOnce(MarkStack *markStack); private: Value *val; diff --git a/src/qml/jsruntime/qv4qobjectwrapper.cpp b/src/qml/jsruntime/qv4qobjectwrapper.cpp index 4f6c179026..2ac2b0b64d 100644 --- a/src/qml/jsruntime/qv4qobjectwrapper.cpp +++ b/src/qml/jsruntime/qv4qobjectwrapper.cpp @@ -539,7 +539,7 @@ ReturnedValue QObjectWrapper::wrap_slowPath(ExecutionEngine *engine, QObject *ob } } -void QObjectWrapper::markWrapper(QObject *object, ExecutionEngine *engine) +void QObjectWrapper::markWrapper(QObject *object, MarkStack *markStack) { if (QQmlData::wasDeleted(object)) return; @@ -548,10 +548,10 @@ void QObjectWrapper::markWrapper(QObject *object, ExecutionEngine *engine) if (!ddata) return; - if (ddata->jsEngineId == engine->m_engineId) - ddata->jsWrapper.markOnce(engine); - else if (engine->m_multiplyWrappedQObjects && ddata->hasTaintedV4Object) - engine->m_multiplyWrappedQObjects->mark(object, engine); + if (ddata->jsEngineId == markStack->engine->m_engineId) + ddata->jsWrapper.markOnce(markStack); + else if (markStack->engine->m_multiplyWrappedQObjects && ddata->hasTaintedV4Object) + markStack->engine->m_multiplyWrappedQObjects->mark(object, markStack); } ReturnedValue QObjectWrapper::getProperty(ExecutionEngine *engine, QObject *object, int propertyIndex, bool captureRequired) @@ -938,36 +938,36 @@ void QObjectWrapper::method_disconnect(const BuiltinFunction *, Scope &scope, Ca RETURN_UNDEFINED(); } -static void markChildQObjectsRecursively(QObject *parent, QV4::ExecutionEngine *e) +static void markChildQObjectsRecursively(QObject *parent, QV4::MarkStack *markStack) { const QObjectList &children = parent->children(); for (int i = 0; i < children.count(); ++i) { QObject *child = children.at(i); if (!child) continue; - QObjectWrapper::markWrapper(child, e); - markChildQObjectsRecursively(child, e); + QObjectWrapper::markWrapper(child, markStack); + markChildQObjectsRecursively(child, markStack); } } -void QObjectWrapper::markObjects(Heap::Base *that, QV4::ExecutionEngine *e) +void QObjectWrapper::markObjects(Heap::Base *that, QV4::MarkStack *markStack) { QObjectWrapper::Data *This = static_cast(that); if (QObject *o = This->object()) { QQmlVMEMetaObject *vme = QQmlVMEMetaObject::get(o); if (vme) - vme->mark(e); + vme->mark(markStack); // Children usually don't need to be marked, the gc keeps them alive. // But in the rare case of a "floating" QObject without a parent that // _gets_ marked (we've been called here!) then we also need to // propagate the marking down to the children recursively. if (!o->parent()) - markChildQObjectsRecursively(o, e); + markChildQObjectsRecursively(o, markStack); } - QV4::Object::markObjects(that, e); + QV4::Object::markObjects(that, markStack); } void QObjectWrapper::destroyObject(bool lastCall) @@ -2066,12 +2066,12 @@ void MultiplyWrappedQObjectMap::remove(QObject *key) erase(it); } -void MultiplyWrappedQObjectMap::mark(QObject *key, ExecutionEngine *engine) +void MultiplyWrappedQObjectMap::mark(QObject *key, MarkStack *markStack) { Iterator it = find(key); if (it == end()) return; - it->markOnce(engine); + it->markOnce(markStack); } void MultiplyWrappedQObjectMap::removeDestroyedObject(QObject *object) diff --git a/src/qml/jsruntime/qv4qobjectwrapper_p.h b/src/qml/jsruntime/qv4qobjectwrapper_p.h index c031a40211..dbb4a153e4 100644 --- a/src/qml/jsruntime/qv4qobjectwrapper_p.h +++ b/src/qml/jsruntime/qv4qobjectwrapper_p.h @@ -171,7 +171,7 @@ struct Q_QML_EXPORT QObjectWrapper : public Object static bool setQmlProperty(ExecutionEngine *engine, QQmlContextData *qmlContext, QObject *object, String *name, RevisionMode revisionMode, const Value &value); static ReturnedValue wrap(ExecutionEngine *engine, QObject *object); - static void markWrapper(QObject *object, ExecutionEngine *engine); + static void markWrapper(QObject *object, MarkStack *markStack); using Object::get; @@ -195,7 +195,7 @@ protected: static bool put(Managed *m, String *name, const Value &value); static PropertyAttributes query(const Managed *, String *name); static void advanceIterator(Managed *m, ObjectIterator *it, Value *name, uint *index, Property *p, PropertyAttributes *attributes); - static void markObjects(Heap::Base *that, QV4::ExecutionEngine *e); + static void markObjects(Heap::Base *that, QV4::MarkStack *markStack); static void method_connect(const BuiltinFunction *, Scope &scope, CallData *callData); static void method_disconnect(const BuiltinFunction *, Scope &scope, CallData *callData); @@ -295,7 +295,7 @@ public: ReturnedValue value(QObject *key) const { return QHash::value(key).value(); } Iterator erase(Iterator it); void remove(QObject *key); - void mark(QObject *key, ExecutionEngine *engine); + void mark(QObject *key, MarkStack *markStack); private Q_SLOTS: void removeDestroyedObject(QObject*); diff --git a/src/qml/jsruntime/qv4string.cpp b/src/qml/jsruntime/qv4string.cpp index cde2131aab..71f85c2d71 100644 --- a/src/qml/jsruntime/qv4string.cpp +++ b/src/qml/jsruntime/qv4string.cpp @@ -54,12 +54,12 @@ using namespace QV4; DEFINE_MANAGED_VTABLE(String); -void String::markObjects(Heap::Base *that, ExecutionEngine *e) +void String::markObjects(Heap::Base *that, MarkStack *markStack) { String::Data *s = static_cast(that); if (s->largestSubLength) { - s->left->mark(e); - s->right->mark(e); + s->left->mark(markStack); + s->right->mark(markStack); } } diff --git a/src/qml/jsruntime/qv4string_p.h b/src/qml/jsruntime/qv4string_p.h index 5b0fd292d6..71e55cbcd4 100644 --- a/src/qml/jsruntime/qv4string_p.h +++ b/src/qml/jsruntime/qv4string_p.h @@ -204,7 +204,7 @@ struct Q_QML_PRIVATE_EXPORT String : public Managed { Identifier *identifier() const { return d()->identifier; } protected: - static void markObjects(Heap::Base *that, ExecutionEngine *e); + static void markObjects(Heap::Base *that, MarkStack *markStack); static bool isEqualTo(Managed *that, Managed *o); static uint getLength(const Managed *m); #endif diff --git a/src/qml/jsruntime/qv4value_p.h b/src/qml/jsruntime/qv4value_p.h index 11d75dde99..56b4ec44a2 100644 --- a/src/qml/jsruntime/qv4value_p.h +++ b/src/qml/jsruntime/qv4value_p.h @@ -475,7 +475,7 @@ public: // Section 9.12 bool sameValue(Value other) const; - inline void mark(ExecutionEngine *e); + inline void mark(MarkStack *markStack); Value &operator =(const ScopedValue &v); Value &operator=(ReturnedValue v) { _val = v; return *this; } diff --git a/src/qml/memory/qv4heap_p.h b/src/qml/memory/qv4heap_p.h index 6c7da91ba0..a38a938588 100644 --- a/src/qml/memory/qv4heap_p.h +++ b/src/qml/memory/qv4heap_p.h @@ -83,7 +83,7 @@ struct VTable uint type : 8; const char *className; void (*destroy)(Heap::Base *); - void (*markObjects)(Heap::Base *, ExecutionEngine *e); + void (*markObjects)(Heap::Base *, MarkStack *markStack); bool (*isEqualTo)(Managed *m, Managed *other); }; @@ -97,7 +97,7 @@ struct Q_QML_EXPORT Base { const VTable *vt; inline ReturnedValue asReturnedValue() const; - inline void mark(QV4::ExecutionEngine *engine); + inline void mark(QV4::MarkStack *markStack); void setVtable(const VTable *v) { vt = v; } const VTable *vtable() const { return vt; } @@ -127,7 +127,7 @@ struct Q_QML_EXPORT Base { return Chunk::testBit(c->objectBitmap, h - c->realBase()); } - inline void markChildren(ExecutionEngine *engine); + inline void markChildren(MarkStack *markStack); void *operator new(size_t, Managed *m) { return m; } void *operator new(size_t, Heap::Base *m) { return m; } diff --git a/src/qml/memory/qv4mm.cpp b/src/qml/memory/qv4mm.cpp index 28330a93c9..aebbc07826 100644 --- a/src/qml/memory/qv4mm.cpp +++ b/src/qml/memory/qv4mm.cpp @@ -260,10 +260,10 @@ void ChunkAllocator::free(Chunk *chunk, size_t size) } -void Heap::Base::markChildren(ExecutionEngine *engine) +void Heap::Base::markChildren(MarkStack *markStack) { if (vtable()->markObjects) - vtable()->markObjects(this, engine); + vtable()->markObjects(this, markStack); if (quint64 m = vtable()->markTable) { // qDebug() << "using mark table:" << hex << m << "for" << h; void **mem = reinterpret_cast(this); @@ -274,13 +274,13 @@ void Heap::Base::markChildren(ExecutionEngine *engine) break; case Mark_Value: // qDebug() << "marking value at " << mem; - reinterpret_cast(mem)->mark(engine); + reinterpret_cast(mem)->mark(markStack); break; case Mark_Pointer: { // qDebug() << "marking pointer at " << mem; Heap::Base *p = *reinterpret_cast(mem); if (p) - p->mark(engine); + p->mark(markStack); break; } case Mark_ValueArray: { @@ -291,17 +291,20 @@ void Heap::Base::markChildren(ExecutionEngine *engine) const Value *end = v + a->alloc; if (a->alloc > 32*1024) { // drain from time to time to avoid overflows in the js stack - Value *currentBase = engine->jsStackTop; + Heap::Base **currentBase = markStack->top; while (v < end) { - v->mark(engine); + v->mark(markStack); ++v; - if (engine->jsStackTop >= currentBase + 32*1024) - engine->memoryManager->drainMarkStack(currentBase); + if (markStack->top >= currentBase + 32*1024) { + Heap::Base **oldBase = markStack->base; + markStack->base = currentBase; + markStack->drain(); + markStack->base = oldBase; + } } - } else { while (v < end) { - v->mark(engine); + v->mark(markStack); ++v; } } @@ -407,7 +410,7 @@ void Chunk::resetBlackBits() static uint nGrayItems = 0; #endif -void Chunk::collectGrayItems(ExecutionEngine *engine) +void Chunk::collectGrayItems(MarkStack *markStack) { // DEBUG << "sweeping chunk" << this << (*freeList); HeapItem *o = realBase(); @@ -428,7 +431,7 @@ void Chunk::collectGrayItems(ExecutionEngine *engine) HeapItem *itemToFree = o + index; Heap::Base *b = *itemToFree; Q_ASSERT(b->inUse()); - engine->pushForGC(b); + markStack->push(b); #ifdef MM_STATS ++nGrayItems; // qDebug() << "adding gray item" << b << "to mark stack"; @@ -676,10 +679,10 @@ void BlockAllocator::resetBlackBits() c->resetBlackBits(); } -void BlockAllocator::collectGrayItems(ExecutionEngine *engine) +void BlockAllocator::collectGrayItems(MarkStack *markStack) { for (auto c : chunks) - c->collectGrayItems(engine); + c->collectGrayItems(markStack); } @@ -750,7 +753,7 @@ void HugeItemAllocator::resetBlackBits() Chunk::clearBit(c.chunk->blackBitmap, c.chunk->first() - c.chunk->realBase()); } -void HugeItemAllocator::collectGrayItems(ExecutionEngine *engine) +void HugeItemAllocator::collectGrayItems(MarkStack *markStack) { for (auto c : chunks) // Correct for a Steele type barrier @@ -758,7 +761,7 @@ void HugeItemAllocator::collectGrayItems(ExecutionEngine *engine) Chunk::testBit(c.chunk->grayBitmap, c.chunk->first() - c.chunk->realBase())) { HeapItem *i = c.chunk->first(); Heap::Base *b = *i; - b->mark(engine); + b->mark(markStack); } } @@ -908,34 +911,35 @@ Heap::Object *MemoryManager::allocObjectWithMemberData(std::size_t size, uint nM static uint markStackSize = 0; -void MemoryManager::drainMarkStack(Value *markBase) +MarkStack::MarkStack(ExecutionEngine *engine) + : engine(engine) +{ + base = (Heap::Base **)engine->gcStack->base(); + top = base; + limit = base + ExecutionEngine::GCStackLimit/sizeof(Heap::Base)*3/4; +} + +void MarkStack::drain() { - while (engine->jsStackTop > markBase) { - Heap::Base *h = engine->popForGC(); + while (top > base) { + Heap::Base *h = pop(); ++markStackSize; Q_ASSERT(h); // at this point we should only have Heap::Base objects in this area on the stack. If not, weird things might happen. - h->markChildren(engine); + h->markChildren(this); } } -void MemoryManager::mark() +void MemoryManager::collectRoots(MarkStack *markStack) { - Value *markBase = engine->jsStackTop; - - markStackSize = 0; - -// qDebug() << ">>>> Mark phase:"; -// qDebug() << " mark stack after gray items" << (engine->jsStackTop - markBase); - if (!nextGCIsIncremental) - engine->markObjects(); + engine->markObjects(markStack); // qDebug() << " mark stack after engine->mark" << (engine->jsStackTop - markBase); - collectFromJSStack(); + collectFromJSStack(markStack); // qDebug() << " mark stack after js stack collect" << (engine->jsStackTop - markBase); - m_persistentValues->mark(engine); + m_persistentValues->mark(markStack); // qDebug() << " mark stack after persistants" << (engine->jsStackTop - markBase); @@ -964,19 +968,27 @@ void MemoryManager::mark() } if (keepAlive) - qobjectWrapper->mark(engine); + qobjectWrapper->mark(markStack); - if (engine->jsStackTop >= engine->jsStackLimit) - drainMarkStack(markBase); + if (markStack->top >= markStack->limit) + markStack->drain(); } +} + +void MemoryManager::mark() +{ + markStackSize = 0; + + MarkStack markStack(engine); + collectRoots(&markStack); if (nextGCIsIncremental) { // need to collect all gray items and push them onto the mark stack - blockAllocator.collectGrayItems(engine); - hugeItemAllocator.collectGrayItems(engine); + blockAllocator.collectGrayItems(&markStack); + hugeItemAllocator.collectGrayItems(&markStack); } - drainMarkStack(markBase); + markStack.drain(); } void MemoryManager::sweep(bool lastSweep) @@ -1242,7 +1254,7 @@ void MemoryManager::willAllocate(std::size_t size) #endif // DETAILED_MM_STATS -void MemoryManager::collectFromJSStack() const +void MemoryManager::collectFromJSStack(MarkStack *markStack) const { Value *v = engine->jsStackBase; Value *top = engine->jsStackTop; @@ -1250,7 +1262,7 @@ void MemoryManager::collectFromJSStack() const Managed *m = v->managed(); if (m && m->inUse()) // Skip pointers to already freed objects, they are bogus as well - m->mark(engine); + m->mark(markStack); ++v; } } diff --git a/src/qml/memory/qv4mm_p.h b/src/qml/memory/qv4mm_p.h index 7f02a4f929..1335ea59b6 100644 --- a/src/qml/memory/qv4mm_p.h +++ b/src/qml/memory/qv4mm_p.h @@ -156,7 +156,7 @@ struct BlockAllocator { void sweep(); void freeAll(); void resetBlackBits(); - void collectGrayItems(ExecutionEngine *engine); + void collectGrayItems(MarkStack *markStack); // bump allocations HeapItem *nextFree = 0; @@ -179,7 +179,7 @@ struct HugeItemAllocator { void sweep(); void freeAll(); void resetBlackBits(); - void collectGrayItems(ExecutionEngine *engine); + void collectGrayItems(MarkStack *markStack); size_t usedMem() const { size_t used = 0; @@ -432,8 +432,6 @@ public: // called when a JS object grows itself. Specifically: Heap::String::append void changeUnmanagedHeapSizeUsage(qptrdiff delta) { unmanagedHeapSize += delta; } - void drainMarkStack(Value *markBase); - protected: /// expects size to be aligned @@ -446,10 +444,11 @@ protected: #endif // DETAILED_MM_STATS private: - void collectFromJSStack() const; + void collectFromJSStack(MarkStack *markStack) const; void mark(); void sweep(bool lastSweep = false); bool shouldRunGC() const; + void collectRoots(MarkStack *markStack); public: QV4::ExecutionEngine *engine; diff --git a/src/qml/memory/qv4mmdefs_p.h b/src/qml/memory/qv4mmdefs_p.h index 1fc7b6a527..9512722782 100644 --- a/src/qml/memory/qv4mmdefs_p.h +++ b/src/qml/memory/qv4mmdefs_p.h @@ -59,6 +59,8 @@ QT_BEGIN_NAMESPACE namespace QV4 { +struct MarkStack; + /* * Chunks are the basic structure containing GC managed objects. * @@ -185,7 +187,7 @@ struct Chunk { void sweep(); void freeAll(); void resetBlackBits(); - void collectGrayItems(ExecutionEngine *engine); + void collectGrayItems(QV4::MarkStack *markStack); void sortIntoBins(HeapItem **bins, uint nBins); }; @@ -265,6 +267,24 @@ Q_STATIC_ASSERT(sizeof(HeapItem) == Chunk::SlotSize); Q_STATIC_ASSERT(QT_POINTER_SIZE*8 == Chunk::Bits); Q_STATIC_ASSERT((1 << Chunk::BitShift) == Chunk::Bits); +struct MarkStack {\ + MarkStack(ExecutionEngine *engine); + Heap::Base **top = 0; + Heap::Base **base = 0; + Heap::Base **limit = 0; + ExecutionEngine *engine; + void push(Heap::Base *m) { + *top = m; + ++top; + } + Heap::Base *pop() { + --top; + return *top; + } + void drain(); + +}; + // Base class for the execution engine #if defined(Q_CC_MSVC) || defined(Q_CC_GNU) diff --git a/src/qml/qml/qqmlvmemetaobject.cpp b/src/qml/qml/qqmlvmemetaobject.cpp index f464a099e0..9f86d1cae9 100644 --- a/src/qml/qml/qqmlvmemetaobject.cpp +++ b/src/qml/qml/qqmlvmemetaobject.cpp @@ -1170,16 +1170,16 @@ void QQmlVMEMetaObject::ensureQObjectWrapper() QV4::QObjectWrapper::wrap(v4, object); } -void QQmlVMEMetaObject::mark(QV4::ExecutionEngine *e) +void QQmlVMEMetaObject::mark(QV4::MarkStack *markStack) { QV4::ExecutionEngine *v4 = cache ? cache->engine : 0; - if (v4 != e) + if (v4 != markStack->engine) return; - propertyAndMethodStorage.markOnce(e); + propertyAndMethodStorage.markOnce(markStack); if (QQmlVMEMetaObject *parent = parentVMEMetaObject()) - parent->mark(e); + parent->mark(markStack); } bool QQmlVMEMetaObject::aliasTarget(int index, QObject **target, int *coreIndex, int *valueTypeIndex) const diff --git a/src/qml/qml/qqmlvmemetaobject_p.h b/src/qml/qml/qqmlvmemetaobject_p.h index bb6fede7c8..031a9a9ddd 100644 --- a/src/qml/qml/qqmlvmemetaobject_p.h +++ b/src/qml/qml/qqmlvmemetaobject_p.h @@ -203,7 +203,7 @@ public: void ensureQObjectWrapper(); - void mark(QV4::ExecutionEngine *e); + void mark(QV4::MarkStack *markStack); void connectAlias(int aliasId); diff --git a/src/quick/items/context2d/qquickcontext2d.cpp b/src/quick/items/context2d/qquickcontext2d.cpp index db9b1acbdf..a32b065318 100644 --- a/src/quick/items/context2d/qquickcontext2d.cpp +++ b/src/quick/items/context2d/qquickcontext2d.cpp @@ -927,9 +927,9 @@ struct QQuickJSContext2DImageData : public QV4::Object static void method_get_height(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData); static void method_get_data(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData); - static void markObjects(QV4::Heap::Base *that, QV4::ExecutionEngine *engine) { - static_cast(that)->pixelData.mark(engine); - QV4::Object::markObjects(that, engine); + static void markObjects(QV4::Heap::Base *that, QV4::MarkStack *markStack) { + static_cast(that)->pixelData.mark(markStack); + QV4::Object::markObjects(that, markStack); } }; diff --git a/src/quick/items/qquickitem.cpp b/src/quick/items/qquickitem.cpp index 539a374dd9..c62c0da445 100644 --- a/src/quick/items/qquickitem.cpp +++ b/src/quick/items/qquickitem.cpp @@ -8441,19 +8441,19 @@ struct QQuickItemWrapper : public QObjectWrapper { struct QQuickItemWrapper : public QV4::QObjectWrapper { V4_OBJECT2(QQuickItemWrapper, QV4::QObjectWrapper) - static void markObjects(QV4::Heap::Base *that, QV4::ExecutionEngine *e); + static void markObjects(QV4::Heap::Base *that, QV4::MarkStack *markStack); }; DEFINE_OBJECT_VTABLE(QQuickItemWrapper); -void QQuickItemWrapper::markObjects(QV4::Heap::Base *that, QV4::ExecutionEngine *e) +void QQuickItemWrapper::markObjects(QV4::Heap::Base *that, QV4::MarkStack *markStack) { QObjectWrapper::Data *This = static_cast(that); if (QQuickItem *item = static_cast(This->object())) { for (QQuickItem *child : qAsConst(QQuickItemPrivate::get(item)->childItems)) - QV4::QObjectWrapper::markWrapper(child, e); + QV4::QObjectWrapper::markWrapper(child, markStack); } - QV4::QObjectWrapper::markObjects(that, e); + QV4::QObjectWrapper::markObjects(that, markStack); } quint64 QQuickItemPrivate::_q_createJSWrapper(QV4::ExecutionEngine *engine) -- cgit v1.2.3 From b361a59c699fca02379c149cf0b9c59490a1ba62 Mon Sep 17 00:00:00 2001 From: Lars Knoll Date: Thu, 9 Mar 2017 13:32:59 +0100 Subject: Micro optimization Avoid the check whether the Value has a HeapObject if the Value is a Managed. Change-Id: I1dd42126cab57d094698402390fdcb4e427a7919 Reviewed-by: Simon Hausmann --- src/qml/jsruntime/qv4engine_p.h | 6 ++++++ src/qml/jsruntime/qv4managed_p.h | 1 + 2 files changed, 7 insertions(+) (limited to 'src') diff --git a/src/qml/jsruntime/qv4engine_p.h b/src/qml/jsruntime/qv4engine_p.h index bace8b700b..a2c774c295 100644 --- a/src/qml/jsruntime/qv4engine_p.h +++ b/src/qml/jsruntime/qv4engine_p.h @@ -559,6 +559,12 @@ inline void Value::mark(MarkStack *markStack) o->mark(markStack); } +inline void Managed::mark(MarkStack *markStack) +{ + Q_ASSERT(m()); + m()->mark(markStack); +} + #define CHECK_STACK_LIMITS(v4, scope) if ((v4)->checkStackLimits(scope)) return; \ ExecutionEngineCallDepthRecorder _executionEngineCallDepthRecorder(v4); diff --git a/src/qml/jsruntime/qv4managed_p.h b/src/qml/jsruntime/qv4managed_p.h index 9ecc4bd087..f97771831c 100644 --- a/src/qml/jsruntime/qv4managed_p.h +++ b/src/qml/jsruntime/qv4managed_p.h @@ -207,6 +207,7 @@ public: bool inUse() const { return d()->inUse(); } bool markBit() const { return d()->isMarked(); } + inline void mark(MarkStack *markStack); static void destroy(Heap::Base *) {} static void markObjects(Heap::Base *, MarkStack *) {} -- cgit v1.2.3 From 7cb4d0234587c295c4eb24f5e548799f3364d94d Mon Sep 17 00:00:00 2001 From: Simon Hausmann Date: Fri, 7 Apr 2017 12:29:53 +0200 Subject: Speed up Qml library checksumming in developer builds The use of sha1 to determine if there were any changes in the Qml library in developer builds (for cache invalidation) works well, but it results in timeouts when running tests on ARM as type compilation takes too long. This is a developer feature and we might as well use a faster hash such as Md5 that is sufficiently reliable for our purposes. Change-Id: I917ae619c73a9cc821d888f16bfcccafeb8ebacc Reviewed-by: Erik Verbruggen --- src/qml/compiler/qv4compileddata.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/qml/compiler/qv4compileddata.cpp b/src/qml/compiler/qv4compileddata.cpp index 77d61032f7..71546cc22e 100644 --- a/src/qml/compiler/qv4compileddata.cpp +++ b/src/qml/compiler/qv4compileddata.cpp @@ -739,7 +739,7 @@ static QByteArray ownLibraryChecksum() if (dladdr(reinterpret_cast(&ownLibraryChecksum), &libInfo) != 0) { QFile library(QFile::decodeName(libInfo.dli_fname)); if (library.open(QIODevice::ReadOnly)) { - QCryptographicHash hash(QCryptographicHash::Sha1); + QCryptographicHash hash(QCryptographicHash::Md5); hash.addData(&library); libraryChecksum = hash.result(); } -- cgit v1.2.3 From fdb1a7da37e2482a22ca32d52e2833bf67d90bc9 Mon Sep 17 00:00:00 2001 From: Lars Knoll Date: Tue, 4 Apr 2017 10:35:45 +0200 Subject: Cleanups: Remove Steele barrier code Remove the code related to the Steele write barrier and incremental garbage collection. This is in preparation for a fully concurrent GC, that will not have and incremental mode and will use a Yuasa write barrier. Change-Id: I155a85211c5be61e792e056321fbceaee47c0d87 Reviewed-by: Simon Hausmann --- src/qml/compiler/qv4compileddata.cpp | 10 +----- src/qml/jit/qv4assembler_p.h | 26 ++------------ src/qml/jsapi/qjsengine.cpp | 2 +- src/qml/jsruntime/qv4identifiertable.cpp | 1 - src/qml/memory/qv4mm.cpp | 62 ++++---------------------------- src/qml/memory/qv4mm_p.h | 3 +- src/qml/memory/qv4writebarrier_p.h | 38 +------------------- src/qml/qml/v8/qqmlbuiltinfunctions.cpp | 2 +- 8 files changed, 13 insertions(+), 131 deletions(-) (limited to 'src') diff --git a/src/qml/compiler/qv4compileddata.cpp b/src/qml/compiler/qv4compileddata.cpp index 7940e5715e..adc36ff1dd 100644 --- a/src/qml/compiler/qv4compileddata.cpp +++ b/src/qml/compiler/qv4compileddata.cpp @@ -125,10 +125,8 @@ QV4::Function *CompilationUnit::linkToEngine(ExecutionEngine *engine) runtimeStrings = (QV4::Heap::String **)malloc(data->stringTableSize * sizeof(QV4::Heap::String*)); // memset the strings to 0 in case a GC run happens while we're within the loop below memset(runtimeStrings, 0, data->stringTableSize * sizeof(QV4::Heap::String*)); - for (uint i = 0; i < data->stringTableSize; ++i) { + for (uint i = 0; i < data->stringTableSize; ++i) runtimeStrings[i] = engine->newIdentifier(data->stringAt(i)); - runtimeStrings[i]->setMarkBit(); - } runtimeRegularExpressions = new QV4::Value[data->regexpTableSize]; // memset the regexps to 0 in case a GC run happens while we're within the loop below @@ -144,12 +142,6 @@ QV4::Function *CompilationUnit::linkToEngine(ExecutionEngine *engine) flags |= IR::RegExp::RegExp_Multiline; QV4::Heap::RegExpObject *ro = engine->newRegExpObject(data->stringAt(re->stringIndex), flags); runtimeRegularExpressions[i] = ro; -#if WRITEBARRIER(steele) - if (engine->memoryManager->nextGCIsIncremental) { - ro->setMarkBit(); - ro->setGrayBit(); - } -#endif } if (data->lookupTableSize) { diff --git a/src/qml/jit/qv4assembler_p.h b/src/qml/jit/qv4assembler_p.h index d4a18ae886..8aa9d81ba2 100644 --- a/src/qml/jit/qv4assembler_p.h +++ b/src/qml/jit/qv4assembler_p.h @@ -189,18 +189,7 @@ struct RegisterSizeDependentAssemblerpop(TargetPlatform::EngineRegister); } -#if WRITEBARRIER(steele) - static void emitWriteBarrier(JITAssembler *as, Address addr) - { -// RegisterID test = addr.base == TargetPlatform::ReturnValueRegister ? TargetPlatform::ScratchRegister : TargetPlatform::ReturnValueRegister; - // if (engine->writeBarrier) -// as->load8(Address(TargetPlatform::EngineRegister, offsetof(EngineBase, writeBarrierActive)), test); -// typename JITAssembler::Jump jump = as->branch32(JITAssembler::Equal, test, TrustedImm32(0)); - // ### emit fence - emitSetGrayBit(as, addr.base); -// jump.link(as); - } -#elif WRITEBARRIER(none) +#if WRITEBARRIER(none) static Q_ALWAYS_INLINE void emitWriteBarrier(JITAssembler *, Address) {} #endif @@ -487,18 +476,7 @@ struct RegisterSizeDependentAssemblerpop(TargetPlatform::EngineRegister); } -#if WRITEBARRIER(steele) - static void emitWriteBarrier(JITAssembler *as, Address addr) - { -// RegisterID test = addr.base == TargetPlatform::ReturnValueRegister ? TargetPlatform::ScratchRegister : TargetPlatform::ReturnValueRegister; - // if (engine->writeBarrier) -// as->load8(Address(TargetPlatform::EngineRegister, offsetof(EngineBase, writeBarrierActive)), test); -// typename JITAssembler::Jump jump = as->branch32(JITAssembler::Equal, test, TrustedImm32(0)); - // ### emit fence - emitSetGrayBit(as, addr.base); -// jump.link(as); - } -#elif WRITEBARRIER(none) +#if WRITEBARRIER(none) static Q_ALWAYS_INLINE void emitWriteBarrier(JITAssembler *, Address) {} #endif diff --git a/src/qml/jsapi/qjsengine.cpp b/src/qml/jsapi/qjsengine.cpp index b52c859ecb..e4c150057a 100644 --- a/src/qml/jsapi/qjsengine.cpp +++ b/src/qml/jsapi/qjsengine.cpp @@ -333,7 +333,7 @@ QJSEngine::~QJSEngine() */ void QJSEngine::collectGarbage() { - d->m_v4Engine->memoryManager->runGC(/* forceFullCollection = */ true); + d->m_v4Engine->memoryManager->runGC(); } #if QT_DEPRECATED_SINCE(5, 6) diff --git a/src/qml/jsruntime/qv4identifiertable.cpp b/src/qml/jsruntime/qv4identifiertable.cpp index d3ef238716..3def6defbf 100644 --- a/src/qml/jsruntime/qv4identifiertable.cpp +++ b/src/qml/jsruntime/qv4identifiertable.cpp @@ -81,7 +81,6 @@ void IdentifierTable::addEntry(Heap::String *str) str->identifier = new Identifier; str->identifier->string = str->toQString(); str->identifier->hashValue = hash; - str->setMarkBit(); bool grow = (alloc <= size*2); diff --git a/src/qml/memory/qv4mm.cpp b/src/qml/memory/qv4mm.cpp index aebbc07826..7c57b93d9b 100644 --- a/src/qml/memory/qv4mm.cpp +++ b/src/qml/memory/qv4mm.cpp @@ -931,8 +931,7 @@ void MarkStack::drain() void MemoryManager::collectRoots(MarkStack *markStack) { - if (!nextGCIsIncremental) - engine->markObjects(markStack); + engine->markObjects(markStack); // qDebug() << " mark stack after engine->mark" << (engine->jsStackTop - markBase); @@ -982,23 +981,11 @@ void MemoryManager::mark() MarkStack markStack(engine); collectRoots(&markStack); - if (nextGCIsIncremental) { - // need to collect all gray items and push them onto the mark stack - blockAllocator.collectGrayItems(&markStack); - hugeItemAllocator.collectGrayItems(&markStack); - } - markStack.drain(); } void MemoryManager::sweep(bool lastSweep) { - if (lastSweep && nextGCIsIncremental) { - // ensure we properly clean up on destruction even if the GC is in incremental mode - blockAllocator.resetBlackBits(); - hugeItemAllocator.resetBlackBits(); - } - for (PersistentValueStorage::Iterator it = m_weakValues->begin(); it != m_weakValues->end(); ++it) { Managed *m = (*it).managed(); if (!m || m->markBit()) @@ -1077,20 +1064,13 @@ size_t dumpBins(BlockAllocator *b, bool printOutput = true) return totalSlotMem*Chunk::SlotSize; } -void MemoryManager::runGC(bool forceFullCollection) +void MemoryManager::runGC() { if (gcBlocked) { // qDebug() << "Not running GC."; return; } - if (forceFullCollection) { - // do a full GC - blockAllocator.resetBlackBits(); - hugeItemAllocator.resetBlackBits(); - nextGCIsIncremental = false; - } - QScopedValueRollback gcBlocker(gcBlocked, true); // qDebug() << "runGC"; @@ -1112,7 +1092,6 @@ void MemoryManager::runGC(bool forceFullCollection) qDebug() << " Allocations since last GC" << allocationCount; allocationCount = 0; #endif - qDebug() << "Incremental:" << nextGCIsIncremental; qDebug() << "Allocated" << totalMem << "bytes in" << blockAllocator.chunks.size() << "chunks"; qDebug() << "Fragmented memory before GC" << (totalMem - usedBefore); dumpBins(&blockAllocator); @@ -1138,10 +1117,6 @@ void MemoryManager::runGC(bool forceFullCollection) qDebug() << " unmanaged heap limit:" << unmanagedHeapSizeGCLimit; } size_t memInBins = dumpBins(&blockAllocator); -#ifdef MM_STATS - if (nextGCIsIncremental) - qDebug() << " number of gray items:" << nGrayItems; -#endif qDebug() << "Marked object in" << markTime << "us."; qDebug() << " " << markStackSize << "objects marked"; qDebug() << "Sweeped object in" << sweepTime << "us."; @@ -1164,36 +1139,11 @@ void MemoryManager::runGC(bool forceFullCollection) Q_ASSERT(blockAllocator.allocatedMem() == getUsedMem() + dumpBins(&blockAllocator, false)); } - if (!nextGCIsIncremental) - usedSlotsAfterLastFullSweep = blockAllocator.usedSlotsAfterLastSweep; + usedSlotsAfterLastFullSweep = blockAllocator.usedSlotsAfterLastSweep; -#if WRITEBARRIER(steele) - static int count = 0; - ++count; - if (aggressiveGC) { - nextGCIsIncremental = (count % 256); - } else { - size_t total = blockAllocator.totalSlots(); - size_t usedSlots = blockAllocator.usedSlotsAfterLastSweep; - if (!nextGCIsIncremental) { - // always try an incremental GC after a full one, unless there is anyway lots of memory pressure - nextGCIsIncremental = usedSlots * 4 < total * 3; - count = 0; - } else { - if (count > 16) - nextGCIsIncremental = false; - else - nextGCIsIncremental = usedSlots * 4 < total * 3; // less than 75% full - } - } -#else - nextGCIsIncremental = false; -#endif - if (!nextGCIsIncremental) { - // do a full GC - blockAllocator.resetBlackBits(); - hugeItemAllocator.resetBlackBits(); - } + // reset all black bits + blockAllocator.resetBlackBits(); + hugeItemAllocator.resetBlackBits(); } size_t MemoryManager::getUsedMem() const diff --git a/src/qml/memory/qv4mm_p.h b/src/qml/memory/qv4mm_p.h index 1335ea59b6..76ffec42de 100644 --- a/src/qml/memory/qv4mm_p.h +++ b/src/qml/memory/qv4mm_p.h @@ -422,7 +422,7 @@ public: return t->d(); } - void runGC(bool forceFullCollection = false); + void runGC(); void dumpStats() const; @@ -467,7 +467,6 @@ public: bool gcBlocked = false; bool aggressiveGC = false; bool gcStats = false; - bool nextGCIsIncremental = false; }; } diff --git a/src/qml/memory/qv4writebarrier_p.h b/src/qml/memory/qv4writebarrier_p.h index a2f85822ca..e36ea0749a 100644 --- a/src/qml/memory/qv4writebarrier_p.h +++ b/src/qml/memory/qv4writebarrier_p.h @@ -55,7 +55,6 @@ QT_BEGIN_NAMESPACE -#define WRITEBARRIER_steele -1 #define WRITEBARRIER_none 1 #define WRITEBARRIER(x) (1/WRITEBARRIER_##x == 1) @@ -78,42 +77,7 @@ enum NewValueType { // ### this needs to be filled with a real memory fence once marking is concurrent Q_ALWAYS_INLINE void fence() {} -#if WRITEBARRIER(steele) - -template -static Q_CONSTEXPR inline bool isRequired() { - return type != Primitive; -} - -inline void write(EngineBase *engine, Heap::Base *base, Value *slot, Value value) -{ - Q_UNUSED(engine); - *slot = value; - if (isRequired()) { - fence(); - base->setGrayBit(); - } -} - -inline void write(EngineBase *engine, Heap::Base *base, Value *slot, Heap::Base *value) -{ - Q_UNUSED(engine); - *slot = value; - if (isRequired()) { - fence(); - base->setGrayBit(); - } -} - -inline void write(EngineBase *engine, Heap::Base *base, Heap::Base **slot, Heap::Base *value) -{ - Q_UNUSED(engine); - *slot = value; - fence(); - base->setGrayBit(); -} - -#elif WRITEBARRIER(none) +#if WRITEBARRIER(none) template static Q_CONSTEXPR inline bool isRequired() { diff --git a/src/qml/qml/v8/qqmlbuiltinfunctions.cpp b/src/qml/qml/v8/qqmlbuiltinfunctions.cpp index 68a64a28f0..8cc0b32168 100644 --- a/src/qml/qml/v8/qqmlbuiltinfunctions.cpp +++ b/src/qml/qml/v8/qqmlbuiltinfunctions.cpp @@ -2019,7 +2019,7 @@ void GlobalExtensions::method_qsTrIdNoOp(const BuiltinFunction *, Scope &scope, void GlobalExtensions::method_gc(const BuiltinFunction *, Scope &scope, CallData *) { - scope.engine->memoryManager->runGC(/* forceFullCollection = */ true); + scope.engine->memoryManager->runGC(); scope.result = QV4::Encode::undefined(); } -- cgit v1.2.3 From 617d6dc2017f49a84e4aeb15a40d78462be62326 Mon Sep 17 00:00:00 2001 From: Filipe Azevedo Date: Wed, 14 Dec 2016 14:25:23 +0100 Subject: Fix hidpi support for opengl window grabbing MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Now set the QImage devicePixelRatio so the content is correct on all screens. Task-number: QTBUG-53795 Change-Id: If94edf901da1285afe9bb847b8973d568a2b7082 Reviewed-by: Morten Johan Sørvig Reviewed-by: Laszlo Agocs --- src/quick/items/qquickrendercontrol.cpp | 3 +++ src/quick/items/qquickwindow.cpp | 1 + src/quick/scenegraph/qsgrenderloop.cpp | 1 + src/quick/scenegraph/qsgthreadedrenderloop.cpp | 1 + src/quick/scenegraph/qsgwindowsrenderloop.cpp | 1 + src/quickwidgets/qquickwidget.cpp | 4 ---- 6 files changed, 7 insertions(+), 4 deletions(-) (limited to 'src') diff --git a/src/quick/items/qquickrendercontrol.cpp b/src/quick/items/qquickrendercontrol.cpp index 03d96aea1f..e2a20f9e7e 100644 --- a/src/quick/items/qquickrendercontrol.cpp +++ b/src/quick/items/qquickrendercontrol.cpp @@ -385,6 +385,9 @@ QImage QQuickRenderControl::grab() cd->syncSceneGraph(); render(); grabContent = qt_gl_read_framebuffer(d->window->size() * d->window->effectiveDevicePixelRatio(), false, false); + if (QQuickRenderControl::renderWindowFor(d->window)) { + grabContent.setDevicePixelRatio(d->window->effectiveDevicePixelRatio()); + } #endif } else if (d->window->rendererInterface()->graphicsApi() == QSGRendererInterface::Software) { QQuickWindowPrivate *cd = QQuickWindowPrivate::get(d->window); diff --git a/src/quick/items/qquickwindow.cpp b/src/quick/items/qquickwindow.cpp index e9108b7bda..46af829f79 100644 --- a/src/quick/items/qquickwindow.cpp +++ b/src/quick/items/qquickwindow.cpp @@ -3491,6 +3491,7 @@ QImage QQuickWindow::grabWindow() bool alpha = format().alphaBufferSize() > 0 && color().alpha() < 255; QImage image = qt_gl_read_framebuffer(size() * effectiveDevicePixelRatio(), alpha, alpha); + image.setDevicePixelRatio(effectiveDevicePixelRatio()); d->cleanupNodesOnShutdown(); d->context->invalidate(); context.doneCurrent(); diff --git a/src/quick/scenegraph/qsgrenderloop.cpp b/src/quick/scenegraph/qsgrenderloop.cpp index ec874f6ff0..64f920e417 100644 --- a/src/quick/scenegraph/qsgrenderloop.cpp +++ b/src/quick/scenegraph/qsgrenderloop.cpp @@ -423,6 +423,7 @@ void QSGGuiThreadRenderLoop::renderWindow(QQuickWindow *window) if (data.grabOnly) { bool alpha = window->format().alphaBufferSize() > 0 && window->color().alpha() != 255; grabContent = qt_gl_read_framebuffer(window->size() * window->effectiveDevicePixelRatio(), alpha, alpha); + grabContent.setDevicePixelRatio(window->effectiveDevicePixelRatio()); data.grabOnly = false; } diff --git a/src/quick/scenegraph/qsgthreadedrenderloop.cpp b/src/quick/scenegraph/qsgthreadedrenderloop.cpp index 4543782d5b..41347cf868 100644 --- a/src/quick/scenegraph/qsgthreadedrenderloop.cpp +++ b/src/quick/scenegraph/qsgthreadedrenderloop.cpp @@ -432,6 +432,7 @@ bool QSGRenderThread::event(QEvent *e) qCDebug(QSG_LOG_RENDERLOOP) << QSG_RT_PAD << "- grabbing result"; bool alpha = ce->window->format().alphaBufferSize() > 0 && ce->window->color().alpha() != 255; *ce->image = qt_gl_read_framebuffer(windowSize * ce->window->effectiveDevicePixelRatio(), alpha, alpha); + ce->image->setDevicePixelRatio(ce->window->effectiveDevicePixelRatio()); } qCDebug(QSG_LOG_RENDERLOOP) << QSG_RT_PAD << "- waking gui to handle result"; waitCondition.wakeOne(); diff --git a/src/quick/scenegraph/qsgwindowsrenderloop.cpp b/src/quick/scenegraph/qsgwindowsrenderloop.cpp index 13388c0841..209715fff6 100644 --- a/src/quick/scenegraph/qsgwindowsrenderloop.cpp +++ b/src/quick/scenegraph/qsgwindowsrenderloop.cpp @@ -326,6 +326,7 @@ QImage QSGWindowsRenderLoop::grab(QQuickWindow *window) bool alpha = window->format().alphaBufferSize() > 0 && window->color().alpha() != 255; QImage image = qt_gl_read_framebuffer(window->size() * window->effectiveDevicePixelRatio(), alpha, alpha); + image.setDevicePixelRatio(window->effectiveDevicePixelRatio()); return image; } diff --git a/src/quickwidgets/qquickwidget.cpp b/src/quickwidgets/qquickwidget.cpp index 4ed41a0c6c..c6dce6bf71 100644 --- a/src/quickwidgets/qquickwidget.cpp +++ b/src/quickwidgets/qquickwidget.cpp @@ -76,10 +76,6 @@ QT_BEGIN_NAMESPACE -#if QT_CONFIG(opengl) -extern Q_GUI_EXPORT QImage qt_gl_read_framebuffer(const QSize &size, bool alpha_format, bool include_alpha); -#endif - class QQuickWidgetRenderControl : public QQuickRenderControl { public: -- cgit v1.2.3 From d438be92dd7068fef94ce98e1ec039fe0ef4f3b3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bernhard=20=C3=9Cbelacker?= Date: Sun, 12 Feb 2017 14:10:43 +0100 Subject: Avoid access to declarativeData when isDeletingChildren is set QObject's members declarativeData and currentChildBeingDeleted share the same memory because they are inside a union. This leads to a problem when destructing mixed Widgets and QML objects. Then in QObjectPrivate::deleteChildren the member currentChildBeingDeleted is set. But unfortunatley QObjectWrapper::destroyObject retrieves the same pointer via declarativeData. This patch should avoid this by disallowing retrieval of declarativeData when isDeletingChildren is set (or at least adds a Q_ASSERT). Task-number: QTBUG-57714 Change-Id: I9ee02f79be3e8226c30076c24859b49b8dcfaecf Reviewed-by: Simon Hausmann Reviewed-by: Eirik Aavitsland --- src/qml/jsruntime/qv4qobjectwrapper_p.h | 11 ++++------- src/qml/qml/qqmldata_p.h | 8 +++++--- src/qml/qml/qqmlengine.cpp | 30 ++++++++++-------------------- src/qml/qml/qqmlobjectcreator.cpp | 4 +++- src/qml/qml/qqmlproperty.cpp | 2 +- src/qml/types/qqmldelegatemodel.cpp | 11 ++++------- 6 files changed, 27 insertions(+), 39 deletions(-) (limited to 'src') diff --git a/src/qml/jsruntime/qv4qobjectwrapper_p.h b/src/qml/jsruntime/qv4qobjectwrapper_p.h index c7c4f4dd77..3764943499 100644 --- a/src/qml/jsruntime/qv4qobjectwrapper_p.h +++ b/src/qml/jsruntime/qv4qobjectwrapper_p.h @@ -209,13 +209,10 @@ inline ReturnedValue QObjectWrapper::wrap(ExecutionEngine *engine, QObject *obje if (Q_UNLIKELY(QQmlData::wasDeleted(object))) return QV4::Encode::null(); - QObjectPrivate *priv = QObjectPrivate::get(const_cast(object)); - if (Q_LIKELY(priv->declarativeData)) { - auto ddata = static_cast(priv->declarativeData); - if (Q_LIKELY(ddata->jsEngineId == engine->m_engineId && !ddata->jsWrapper.isUndefined())) { - // We own the JS object - return ddata->jsWrapper.value(); - } + auto ddata = QQmlData::get(object); + if (Q_LIKELY(ddata && ddata->jsEngineId == engine->m_engineId && !ddata->jsWrapper.isUndefined())) { + // We own the JS object + return ddata->jsWrapper.value(); } return wrap_slowPath(engine, object); diff --git a/src/qml/qml/qqmldata_p.h b/src/qml/qml/qqmldata_p.h index e271598c2d..2083326cd5 100644 --- a/src/qml/qml/qqmldata_p.h +++ b/src/qml/qml/qqmldata_p.h @@ -201,7 +201,9 @@ public: static QQmlData *get(const QObject *object, bool create = false) { QObjectPrivate *priv = QObjectPrivate::get(const_cast(object)); - if (priv->wasDeleted) { + // If QObjectData::isDeletingChildren is set then access to QObjectPrivate::declarativeData has + // to be avoided because QObjectPrivate::currentChildBeingDeleted is in use. + if (priv->isDeletingChildren || priv->wasDeleted) { Q_ASSERT(!create); return 0; } else if (priv->declarativeData) { @@ -269,8 +271,8 @@ bool QQmlData::wasDeleted(QObject *object) if (!priv || priv->wasDeleted) return true; - return priv->declarativeData && - static_cast(priv->declarativeData)->isQueuedForDeletion; + QQmlData *ddata = QQmlData::get(object); + return ddata && ddata->isQueuedForDeletion; } QQmlNotifierEndpoint *QQmlData::notify(int index) diff --git a/src/qml/qml/qqmlengine.cpp b/src/qml/qml/qqmlengine.cpp index f1c592b632..1eb892a0de 100644 --- a/src/qml/qml/qqmlengine.cpp +++ b/src/qml/qml/qqmlengine.cpp @@ -692,9 +692,7 @@ QQmlEnginePrivate::~QQmlEnginePrivate() void QQmlPrivate::qdeclarativeelement_destructor(QObject *o) { - QObjectPrivate *p = QObjectPrivate::get(o); - if (p->declarativeData) { - QQmlData *d = static_cast(p->declarativeData); + if (QQmlData *d = QQmlData::get(o)) { if (d->ownContext && d->context) { d->context->destroy(); d->context = 0; @@ -864,13 +862,10 @@ void QQmlData::markAsDeleted(QObject *o) void QQmlData::setQueuedForDeletion(QObject *object) { if (object) { - if (QObjectPrivate *priv = QObjectPrivate::get(object)) { - if (!priv->wasDeleted && priv->declarativeData) { - QQmlData *ddata = QQmlData::get(object, false); - if (ddata->ownContext && ddata->context) - ddata->context->emitDestruction(); - ddata->isQueuedForDeletion = true; - } + if (QQmlData *ddata = QQmlData::get(object)) { + if (ddata->ownContext && ddata->context) + ddata->context->emitDestruction(); + ddata->isQueuedForDeletion = true; } } } @@ -1319,17 +1314,11 @@ QQmlContext *QQmlEngine::contextForObject(const QObject *object) if(!object) return 0; - QObjectPrivate *priv = QObjectPrivate::get(const_cast(object)); - - QQmlData *data = - static_cast(priv->declarativeData); - - if (!data) - return 0; - else if (data->outerContext) + QQmlData *data = QQmlData::get(object); + if (data && data->outerContext) return data->outerContext->asQQmlContext(); - else - return 0; + + return 0; } /*! @@ -1864,6 +1853,7 @@ void QQmlData::setPendingBindingBit(QObject *obj, int coreIndex) QQmlData *QQmlData::createQQmlData(QObjectPrivate *priv) { Q_ASSERT(priv); + Q_ASSERT(!priv->isDeletingChildren); priv->declarativeData = new QQmlData; return static_cast(priv->declarativeData); } diff --git a/src/qml/qml/qqmlobjectcreator.cpp b/src/qml/qml/qqmlobjectcreator.cpp index 09936f6e7a..3ed3ce5460 100644 --- a/src/qml/qml/qqmlobjectcreator.cpp +++ b/src/qml/qml/qqmlobjectcreator.cpp @@ -1075,7 +1075,9 @@ QObject *QQmlObjectCreator::createInstance(int index, QObject *parent, bool isCo { QQmlData *ddata = new (ddataMemory) QQmlData; ddata->ownMemory = false; - QObjectPrivate::get(instance)->declarativeData = ddata; + QObjectPrivate* p = QObjectPrivate::get(instance); + Q_ASSERT(!p->isDeletingChildren); + p->declarativeData = ddata; } const int parserStatusCast = type->parserStatusCast(); diff --git a/src/qml/qml/qqmlproperty.cpp b/src/qml/qml/qqmlproperty.cpp index 7df8336f51..cec04d25a1 100644 --- a/src/qml/qml/qqmlproperty.cpp +++ b/src/qml/qml/qqmlproperty.cpp @@ -1628,7 +1628,7 @@ QMetaMethod QQmlPropertyPrivate::findSignalByName(const QMetaObject *mo, const Q */ static inline void flush_vme_signal(const QObject *object, int index, bool indexInSignalRange) { - QQmlData *data = static_cast(QObjectPrivate::get(const_cast(object))->declarativeData); + QQmlData *data = QQmlData::get(object); if (data && data->propertyCache) { QQmlPropertyData *property = indexInSignalRange ? data->propertyCache->signal(index) : data->propertyCache->method(index); diff --git a/src/qml/types/qqmldelegatemodel.cpp b/src/qml/types/qqmldelegatemodel.cpp index d9a8b1d179..62a9c40c07 100644 --- a/src/qml/types/qqmldelegatemodel.cpp +++ b/src/qml/types/qqmldelegatemodel.cpp @@ -1959,9 +1959,8 @@ void QQmlDelegateModelItem::destroyObject() Q_ASSERT(object); Q_ASSERT(contextData); - QObjectPrivate *p = QObjectPrivate::get(object); - Q_ASSERT(p->declarativeData); - QQmlData *data = static_cast(p->declarativeData); + QQmlData *data = QQmlData::get(object); + Q_ASSERT(data); if (data->ownContext && data->context) data->context->clearContext(); object->deleteLater(); @@ -1978,10 +1977,8 @@ void QQmlDelegateModelItem::destroyObject() QQmlDelegateModelItem *QQmlDelegateModelItem::dataForObject(QObject *object) { - QObjectPrivate *p = QObjectPrivate::get(object); - QQmlContextData *context = p->declarativeData - ? static_cast(p->declarativeData)->context - : 0; + QQmlData *d = QQmlData::get(object); + QQmlContextData *context = d ? d->context : 0; for (context = context ? context->parent : 0; context; context = context->parent) { if (QQmlDelegateModelItem *cacheItem = qobject_cast( context->contextObject)) { -- cgit v1.2.3 From 37da30b83021869b2fd069ea49d72d89b16c2046 Mon Sep 17 00:00:00 2001 From: J-P Nurmi Date: Sun, 20 Nov 2016 22:23:14 +0100 Subject: Allow custom bounds behaviors for Flickable [ChangeLog][QtQuick][Flickable] Added a boundsMovement property that allows disabling the default bounce effect and implementing custom edge effects. Task-number: QTBUG-38515 Change-Id: Id00d30a863e264cdbac00fbad8189406f29484c4 Reviewed-by: Robin Burchell Reviewed-by: Shawn Rutledge --- src/quick/items/qquickflickable.cpp | 110 ++++++++++++++++++++++++++++------ src/quick/items/qquickflickable_p.h | 11 ++++ src/quick/items/qquickflickable_p_p.h | 1 + src/quick/items/qquickitemsmodule.cpp | 2 + 4 files changed, 107 insertions(+), 17 deletions(-) (limited to 'src') diff --git a/src/quick/items/qquickflickable.cpp b/src/quick/items/qquickflickable.cpp index 27d7072f03..f4dce3ea47 100644 --- a/src/quick/items/qquickflickable.cpp +++ b/src/quick/items/qquickflickable.cpp @@ -254,6 +254,7 @@ QQuickFlickablePrivate::QQuickFlickablePrivate() , flickBoost(1.0), fixupMode(Normal), vTime(0), visibleArea(0) , flickableDirection(QQuickFlickable::AutoFlickDirection) , boundsBehavior(QQuickFlickable::DragAndOvershootBounds) + , boundsMovement(QQuickFlickable::FollowBoundsBehavior) , rebound(0) { } @@ -1573,16 +1574,18 @@ void QQuickFlickablePrivate::replayDelayedPress() void QQuickFlickablePrivate::setViewportX(qreal x) { Q_Q(QQuickFlickable); - if (pixelAligned) - x = -Round(-x); - - contentItem->setX(x); - if (contentItem->x() != x) - return; // reentered + qreal effectiveX = pixelAligned ? -Round(-x) : x; const qreal maxX = q->maxXExtent(); const qreal minX = q->minXExtent(); + if (boundsMovement == int(QQuickFlickable::StopAtBounds)) + effectiveX = qBound(maxX, effectiveX, minX); + + contentItem->setX(effectiveX); + if (contentItem->x() != effectiveX) + return; // reentered + qreal overshoot = 0.0; if (x <= maxX) overshoot = maxX - x; @@ -1598,16 +1601,18 @@ void QQuickFlickablePrivate::setViewportX(qreal x) void QQuickFlickablePrivate::setViewportY(qreal y) { Q_Q(QQuickFlickable); - if (pixelAligned) - y = -Round(-y); - - contentItem->setY(y); - if (contentItem->y() != y) - return; // reentered + qreal effectiveY = pixelAligned ? -Round(-y) : y; const qreal maxY = q->maxYExtent(); const qreal minY = q->minYExtent(); + if (boundsMovement == int(QQuickFlickable::StopAtBounds)) + effectiveY = qBound(maxY, effectiveY, minY); + + contentItem->setY(effectiveY); + if (contentItem->y() != effectiveY) + return; // reentered + qreal overshoot = 0.0; if (y <= maxY) overshoot = maxY - y; @@ -1867,8 +1872,9 @@ QQmlListProperty QQuickFlickable::flickableChildren() beyond the Flickable's boundaries, or overshoot the Flickable's boundaries when flicked. - This enables the feeling that the edges of the view are soft, - rather than a hard physical boundary. + When the \l boundsMovement is \c Flickable.FollowBoundsBehavior, a value + other than \c Flickable.StopAtBounds will give a feeling that the edges of + the view are soft, rather than a hard physical boundary. The \c boundsBehavior can be one of: @@ -1884,7 +1890,7 @@ QQmlListProperty QQuickFlickable::flickableChildren() boundary when flicked. \endlist - \sa horizontalOvershoot, verticalOvershoot + \sa horizontalOvershoot, verticalOvershoot, boundsMovement */ QQuickFlickable::BoundsBehavior QQuickFlickable::boundsBehavior() const { @@ -2695,7 +2701,11 @@ void QQuickFlickablePrivate::updateVelocity() The value is negative when the content is dragged or flicked beyond the beginning, and positive when beyond the end; \c 0.0 otherwise. - \sa verticalOvershoot, boundsBehavior + Whether the values are reported for dragging and/or flicking is determined by + \l boundsBehavior. The overshoot distance is reported even when \l boundsMovement + is \c Flickable.StopAtBounds. + + \sa verticalOvershoot, boundsBehavior, boundsMovement */ qreal QQuickFlickable::horizontalOvershoot() const { @@ -2712,7 +2722,11 @@ qreal QQuickFlickable::horizontalOvershoot() const The value is negative when the content is dragged or flicked beyond the beginning, and positive when beyond the end; \c 0.0 otherwise. - \sa horizontalOvershoot, boundsBehavior + Whether the values are reported for dragging and/or flicking is determined by + \l boundsBehavior. The overshoot distance is reported even when \l boundsMovement + is \c Flickable.StopAtBounds. + + \sa horizontalOvershoot, boundsBehavior, boundsMovement */ qreal QQuickFlickable::verticalOvershoot() const { @@ -2720,4 +2734,66 @@ qreal QQuickFlickable::verticalOvershoot() const return d->vData.overshoot; } +/*! + \qmlproperty enumeration QtQuick::Flickable::boundsMovement + \since 5.10 + + This property holds whether the flickable will give a feeling that the edges of the + view are soft, rather than a hard physical boundary. + + The \c boundsMovement can be one of: + + \list + \li Flickable.StopAtBounds - this allows implementing custom edge effects where the + contents do not follow drags or flicks beyond the bounds of the flickable. The values + of \l horizontalOvershoot and \l verticalOvershoot can be utilized to implement custom + edge effects. + \li Flickable.FollowBoundsBehavior (default) - whether the contents follow drags or + flicks beyond the bounds of the flickable is determined by \l boundsBehavior. + \endlist + + The following example keeps the contents within bounds and instead applies a flip + effect when flicked over horizontal bounds: + \code + Flickable { + id: flickable + boundsMovement: Flickable.StopAtBounds + boundsBehavior: Flickable.DragAndOvershootBounds + transform: Rotation { + axis { x: 0; y: 1; z: 0 } + origin.x: flickable.width / 2 + origin.y: flickable.height / 2 + angle: Math.min(30, Math.max(-30, flickable.horizontalOvershoot)) + } + } + \endcode + + The following example keeps the contents within bounds and instead applies an opacity + effect when dragged over vertical bounds: + \code + Flickable { + boundsMovement: Flickable.StopAtBounds + boundsBehavior: Flickable.DragOverBounds + opacity: Math.max(0.5, 1.0 - Math.abs(verticalOvershoot) / height) + } + \endcode + + \sa boundsBehavior, verticalOvershoot, horizontalOvershoot +*/ +QQuickFlickable::BoundsMovement QQuickFlickable::boundsMovement() const +{ + Q_D(const QQuickFlickable); + return d->boundsMovement; +} + +void QQuickFlickable::setBoundsMovement(BoundsMovement movement) +{ + Q_D(QQuickFlickable); + if (d->boundsMovement == movement) + return; + + d->boundsMovement = movement; + emit boundsMovementChanged(); +} + QT_END_NAMESPACE diff --git a/src/quick/items/qquickflickable_p.h b/src/quick/items/qquickflickable_p.h index 52cade1472..7558ee7df8 100644 --- a/src/quick/items/qquickflickable_p.h +++ b/src/quick/items/qquickflickable_p.h @@ -80,6 +80,7 @@ class Q_QUICK_PRIVATE_EXPORT QQuickFlickable : public QQuickItem Q_PROPERTY(qreal verticalVelocity READ verticalVelocity NOTIFY verticalVelocityChanged) Q_PROPERTY(BoundsBehavior boundsBehavior READ boundsBehavior WRITE setBoundsBehavior NOTIFY boundsBehaviorChanged) + Q_PROPERTY(BoundsMovement boundsMovement READ boundsMovement WRITE setBoundsMovement NOTIFY boundsMovementChanged REVISION 10) Q_PROPERTY(QQuickTransition *rebound READ rebound WRITE setRebound NOTIFY reboundChanged) Q_PROPERTY(qreal maximumFlickVelocity READ maximumFlickVelocity WRITE setMaximumFlickVelocity NOTIFY maximumFlickVelocityChanged) Q_PROPERTY(qreal flickDeceleration READ flickDeceleration WRITE setFlickDeceleration NOTIFY flickDecelerationChanged) @@ -132,6 +133,15 @@ public: BoundsBehavior boundsBehavior() const; void setBoundsBehavior(BoundsBehavior); + enum BoundsMovement { + // StopAtBounds = 0x0, + FollowBoundsBehavior = 0x1 + }; + Q_ENUM(BoundsMovement) + + BoundsMovement boundsMovement() const; + void setBoundsMovement(BoundsMovement movement); + QQuickTransition *rebound() const; void setRebound(QQuickTransition *transition); @@ -237,6 +247,7 @@ Q_SIGNALS: void flickableDirectionChanged(); void interactiveChanged(); void boundsBehaviorChanged(); + Q_REVISION(10) void boundsMovementChanged(); void reboundChanged(); void maximumFlickVelocityChanged(); void flickDecelerationChanged(); diff --git a/src/quick/items/qquickflickable_p_p.h b/src/quick/items/qquickflickable_p_p.h index 1ceff22dfc..8609a15fcd 100644 --- a/src/quick/items/qquickflickable_p_p.h +++ b/src/quick/items/qquickflickable_p_p.h @@ -247,6 +247,7 @@ public: QQuickFlickableVisibleArea *visibleArea; QQuickFlickable::FlickableDirection flickableDirection; QQuickFlickable::BoundsBehavior boundsBehavior; + QQuickFlickable::BoundsMovement boundsMovement; QQuickTransition *rebound; void viewportAxisMoved(AxisData &data, qreal minExtent, qreal maxExtent, qreal vSize, diff --git a/src/quick/items/qquickitemsmodule.cpp b/src/quick/items/qquickitemsmodule.cpp index 4d6ae0c3e2..13f23c918a 100644 --- a/src/quick/items/qquickitemsmodule.cpp +++ b/src/quick/items/qquickitemsmodule.cpp @@ -389,6 +389,8 @@ static void qt_quickitems_defineModule(const char *uri, int major, int minor) #if QT_CONFIG(quick_shadereffect) qmlRegisterType(uri, 2, 9, "ShaderEffectSource"); #endif + + qmlRegisterType(uri, 2, 10, "Flickable"); } static void initResources() -- cgit v1.2.3 From 426e069d3952831a2a40c0aa5b0fdb3de37226f7 Mon Sep 17 00:00:00 2001 From: Leena Miettinen Date: Wed, 12 Apr 2017 09:29:21 +0200 Subject: Doc: Write URL in capital letters in text Change-Id: Ibac6a3f8ddf4b441dd8359162094eb786fda84d7 Reviewed-by: Nico Vertriest --- src/quick/util/qquickfontloader.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/quick/util/qquickfontloader.cpp b/src/quick/util/qquickfontloader.cpp index 3761a37a6d..d6e8db2426 100644 --- a/src/quick/util/qquickfontloader.cpp +++ b/src/quick/util/qquickfontloader.cpp @@ -236,7 +236,7 @@ QQuickFontLoader::~QQuickFontLoader() /*! \qmlproperty url QtQuick::FontLoader::source - The url of the font to load. + The URL of the font to load. */ QUrl QQuickFontLoader::source() const { -- cgit v1.2.3 From 7bd7b64679c3c6d32f6eb9cce05cc42f3a6272cb Mon Sep 17 00:00:00 2001 From: Leena Miettinen Date: Wed, 12 Apr 2017 09:25:51 +0200 Subject: Doc: Fix property name from "url" to "source" URL is the type of the property, not its name. Change-Id: Id76bdb70031a3cacdfd0951ff132e57a512ae208 Reviewed-by: Markus Goetz (Woboq GmbH) --- src/quick/util/qquickfontloader.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/quick/util/qquickfontloader.cpp b/src/quick/util/qquickfontloader.cpp index d6e8db2426..21e8eda365 100644 --- a/src/quick/util/qquickfontloader.cpp +++ b/src/quick/util/qquickfontloader.cpp @@ -317,7 +317,7 @@ void QQuickFontLoader::updateFontInfo(const QString& name, QQuickFontLoader::Sta \qmlproperty string QtQuick::FontLoader::name This property holds the name of the font family. - It is set automatically when a font is loaded using the \c url property. + It is set automatically when a font is loaded using the \l source property. Use this to set the \c font.family property of a \c Text item. -- cgit v1.2.3 From 568005a5d3ecd78608d619cc9dc6063276baa316 Mon Sep 17 00:00:00 2001 From: Robin Burchell Date: Thu, 13 Apr 2017 13:46:20 +0200 Subject: QQmlConnections: Don't crash (or read past bounds) if a silly prop name is given Change-Id: I156d27b21159f019a969a33e553e63fac9a3d193 Reviewed-by: Simon Hausmann --- src/qml/types/qqmlconnections.cpp | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/src/qml/types/qqmlconnections.cpp b/src/qml/types/qqmlconnections.cpp index 870aeaa6e2..66bc772279 100644 --- a/src/qml/types/qqmlconnections.cpp +++ b/src/qml/types/qqmlconnections.cpp @@ -235,14 +235,13 @@ void QQmlConnectionsParser::verifyBindings(const QV4::CompiledData::Unit *qmlUni { for (int ii = 0; ii < props.count(); ++ii) { const QV4::CompiledData::Binding *binding = props.at(ii); - QString propName = qmlUnit->stringAt(binding->propertyNameIndex); + const QString &propName = qmlUnit->stringAt(binding->propertyNameIndex); - if (!propName.startsWith(QLatin1String("on")) || !propName.at(2).isUpper()) { + if (!propName.startsWith(QLatin1String("on")) || (propName.length() < 3 || !propName.at(2).isUpper())) { error(props.at(ii), QQmlConnections::tr("Cannot assign to non-existent property \"%1\"").arg(propName)); return; } - if (binding->type >= QV4::CompiledData::Binding::Type_Object) { const QV4::CompiledData::Object *target = qmlUnit->objectAt(binding->value.objectIndex); if (!qmlUnit->stringAt(target->inheritedTypeNameIndex).isEmpty()) -- cgit v1.2.3 From 9b321d771a7fe2e0d75ebf97ce13fa877e963f99 Mon Sep 17 00:00:00 2001 From: Robin Burchell Date: Fri, 14 Apr 2017 11:03:02 +0200 Subject: QQuickFlickable: Remove an obviously stale comment These properties all have proper documentation now Change-Id: Ie65221de468cac18b916506432097843e7921fed Reviewed-by: Shawn Rutledge --- src/quick/items/qquickflickable.cpp | 12 ------------ 1 file changed, 12 deletions(-) (limited to 'src') diff --git a/src/quick/items/qquickflickable.cpp b/src/quick/items/qquickflickable.cpp index f4dce3ea47..1c732f9157 100644 --- a/src/quick/items/qquickflickable.cpp +++ b/src/quick/items/qquickflickable.cpp @@ -564,18 +564,6 @@ void QQuickFlickablePrivate::updateBeginningEnd() visibleArea->updateVisible(); } -/* -XXXTODO add docs describing moving, dragging, flicking properties, e.g. - -When the user starts dragging the Flickable, the dragging and moving properties -will be true. - -If the velocity is sufficient when the drag is ended, flicking may begin. - -The moving properties will remain true until all dragging and flicking -is finished. -*/ - /*! \qmlsignal QtQuick::Flickable::dragStarted() -- cgit v1.2.3 From aba5c059b926cc0056f89585ea8056df815fec05 Mon Sep 17 00:00:00 2001 From: Robin Burchell Date: Fri, 14 Apr 2017 12:04:30 +0200 Subject: QQuickContents: Use QRectF rather than reinventing it No major impact on benchmarks -- if anything, this improves the new delegates_item_childrenRect by 2-3 frames. Change-Id: I50fef6f0bc9531eabd1d42079886dca754e1ce2a Reviewed-by: Shawn Rutledge Reviewed-by: Michael Brasser --- src/quick/items/qquickitem.cpp | 30 +++++++++++++++--------------- src/quick/items/qquickitem_p.h | 7 ++----- 2 files changed, 17 insertions(+), 20 deletions(-) (limited to 'src') diff --git a/src/quick/items/qquickitem.cpp b/src/quick/items/qquickitem.cpp index c62c0da445..15042082fe 100644 --- a/src/quick/items/qquickitem.cpp +++ b/src/quick/items/qquickitem.cpp @@ -163,7 +163,7 @@ void QQuickTransform::update() } QQuickContents::QQuickContents(QQuickItem *item) -: m_item(item), m_x(0), m_y(0), m_width(0), m_height(0) +: m_item(item) { } @@ -176,8 +176,8 @@ QQuickContents::~QQuickContents() bool QQuickContents::calcHeight(QQuickItem *changed) { - qreal oldy = m_y; - qreal oldheight = m_height; + qreal oldy = m_contents.y(); + qreal oldheight = m_contents.height(); if (changed) { qreal top = oldy; @@ -187,8 +187,8 @@ bool QQuickContents::calcHeight(QQuickItem *changed) bottom = y + changed->height(); if (y < top) top = y; - m_y = top; - m_height = bottom - top; + m_contents.setY(top); + m_contents.setHeight(bottom - top); } else { qreal top = std::numeric_limits::max(); qreal bottom = -std::numeric_limits::max(); @@ -201,17 +201,17 @@ bool QQuickContents::calcHeight(QQuickItem *changed) top = y; } if (!children.isEmpty()) - m_y = top; - m_height = qMax(bottom - top, qreal(0.0)); + m_contents.setY(top); + m_contents.setHeight(qMax(bottom - top, qreal(0.0))); } - return (m_height != oldheight || m_y != oldy); + return (m_contents.height() != oldheight || m_contents.y() != oldy); } bool QQuickContents::calcWidth(QQuickItem *changed) { - qreal oldx = m_x; - qreal oldwidth = m_width; + qreal oldx = m_contents.x(); + qreal oldwidth = m_contents.width(); if (changed) { qreal left = oldx; @@ -221,8 +221,8 @@ bool QQuickContents::calcWidth(QQuickItem *changed) right = x + changed->width(); if (x < left) left = x; - m_x = left; - m_width = right - left; + m_contents.setX(left); + m_contents.setWidth(right - left); } else { qreal left = std::numeric_limits::max(); qreal right = -std::numeric_limits::max(); @@ -235,11 +235,11 @@ bool QQuickContents::calcWidth(QQuickItem *changed) left = x; } if (!children.isEmpty()) - m_x = left; - m_width = qMax(right - left, qreal(0.0)); + m_contents.setX(left); + m_contents.setWidth(qMax(right - left, qreal(0.0))); } - return (m_width != oldwidth || m_x != oldx); + return (m_contents.width() != oldwidth || m_contents.x() != oldx); } void QQuickContents::complete() diff --git a/src/quick/items/qquickitem_p.h b/src/quick/items/qquickitem_p.h index 797ba42781..e56d839de9 100644 --- a/src/quick/items/qquickitem_p.h +++ b/src/quick/items/qquickitem_p.h @@ -94,7 +94,7 @@ public: QQuickContents(QQuickItem *item); ~QQuickContents(); - QRectF rectF() const { return QRectF(m_x, m_y, m_width, m_height); } + QRectF rectF() const { return m_contents; } inline void calcGeometry(QQuickItem *changed = 0); void complete(); @@ -112,10 +112,7 @@ private: void updateRect(); QQuickItem *m_item; - qreal m_x; - qreal m_y; - qreal m_width; - qreal m_height; + QRectF m_contents; }; void QQuickContents::calcGeometry(QQuickItem *changed) -- cgit v1.2.3 From ad767e6656ac45cd2acbd81ae42e000d93f4d93c Mon Sep 17 00:00:00 2001 From: Robin Burchell Date: Fri, 14 Apr 2017 10:55:11 +0200 Subject: QQuickWindow: Actually mark sendEvent as deprecated ... not just in the documentation. Change-Id: I524841e253b16364b404053290db246729d72e48 Reviewed-by: Shawn Rutledge --- src/quick/items/qquickwindow.cpp | 4 ++++ src/quick/items/qquickwindow.h | 4 +++- 2 files changed, 7 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/quick/items/qquickwindow.cpp b/src/quick/items/qquickwindow.cpp index 4962016874..b3417cc727 100644 --- a/src/quick/items/qquickwindow.cpp +++ b/src/quick/items/qquickwindow.cpp @@ -2762,6 +2762,8 @@ void QQuickWindowPrivate::contextCreationFailureMessage(const QSurfaceFormat &fo #endif // !Q_OS_WIN32 } +#if QT_DEPRECATED_SINCE(5, 8) + /*! Propagates an event \a e to a QQuickItem \a item on the window. @@ -2814,6 +2816,8 @@ bool QQuickWindow::sendEvent(QQuickItem *item, QEvent *e) return false; } +#endif + void QQuickWindowPrivate::cleanupNodes() { for (int ii = 0; ii < cleanupNodeList.count(); ++ii) diff --git a/src/quick/items/qquickwindow.h b/src/quick/items/qquickwindow.h index 27a73988ae..0655ae9e7f 100644 --- a/src/quick/items/qquickwindow.h +++ b/src/quick/items/qquickwindow.h @@ -112,7 +112,9 @@ public: QQuickItem *mouseGrabberItem() const; - bool sendEvent(QQuickItem *, QEvent *); +#if QT_DEPRECATED_SINCE(5, 8) + QT_DEPRECATED bool sendEvent(QQuickItem *, QEvent *); +#endif QImage grabWindow(); #if QT_CONFIG(opengl) -- cgit v1.2.3 From fc8d503321faffa1638a8bfa161d0784e2e1325b Mon Sep 17 00:00:00 2001 From: Anton Kudryavtsev Date: Sat, 15 Apr 2017 20:52:37 +0300 Subject: QQuickText: optimize updateLayout() QString::replace(QChar, QChar) was fixed in c12f42e91b146109cc9ee5d050928672776ca1ee So no need to use pre-condition. Change-Id: I98eadfc89350194832b229afe061dc0bd01f1bc9 Reviewed-by: J-P Nurmi --- src/quick/items/qquicktext.cpp | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) (limited to 'src') diff --git a/src/quick/items/qquicktext.cpp b/src/quick/items/qquicktext.cpp index 1720377046..c8bc76aef8 100644 --- a/src/quick/items/qquicktext.cpp +++ b/src/quick/items/qquicktext.cpp @@ -274,15 +274,9 @@ void QQuickTextPrivate::updateLayout() elideLayout->clearFormats(); QString tmp = text; multilengthEos = tmp.indexOf(QLatin1Char('\x9c')); - if (multilengthEos != -1) { + if (multilengthEos != -1) tmp = tmp.mid(0, multilengthEos); - tmp.replace(QLatin1Char('\n'), QChar::LineSeparator); - } else if (tmp.contains(QLatin1Char('\n'))) { - // Replace always does a detach. Checking for the new line character first - // means iterating over those items again if found but prevents a realloc - // otherwise. - tmp.replace(QLatin1Char('\n'), QChar::LineSeparator); - } + tmp.replace(QLatin1Char('\n'), QChar::LineSeparator); layout.setText(tmp); } textHasChanged = false; -- cgit v1.2.3 From 9538cd7fbe43b1479f23a37bc8f19012981257a6 Mon Sep 17 00:00:00 2001 From: J-P Nurmi Date: Mon, 27 Feb 2017 15:17:35 +0100 Subject: QQuickAnimatorProxyJob: make sure to stop when detached from a window The previous attempt to fix this (05a88ef) had to be reverted (7fe0d1a) because Q_ASSERT(m_controller) in updateCurrentTime() failed in QQC1 auto tests. It seems that m_controller can be null when m_internalState is still State_Starting. Task-number: QTBUG-59034 Task-number: QTBUG-59953 Change-Id: I07ceec8fe4e66ba0571092b4385d8140035a4b33 Reviewed-by: Robin Burchell Reviewed-by: Aleix Pol Reviewed-by: Gunnar Sletta --- src/quick/util/qquickanimatorjob.cpp | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/src/quick/util/qquickanimatorjob.cpp b/src/quick/util/qquickanimatorjob.cpp index 89007cff1f..caf702bde5 100644 --- a/src/quick/util/qquickanimatorjob.cpp +++ b/src/quick/util/qquickanimatorjob.cpp @@ -140,6 +140,14 @@ QObject *QQuickAnimatorProxyJob::findAnimationContext(QQuickAbstractAnimation *a void QQuickAnimatorProxyJob::updateCurrentTime(int) { + if (m_internalState != State_Running) + return; + + // A proxy which is being ticked should be associated with a window, (see + // setWindow() below). If we get here when there is no more controller we + // have a problem. + Q_ASSERT(m_controller); + // We do a simple check here to see if the animator has run and stopped on // the render thread. isPendingStart() will perform a check against jobs // that have been scheduled for start, but that will not yet have entered @@ -150,8 +158,7 @@ void QQuickAnimatorProxyJob::updateCurrentTime(int) // we might get the wrong value for this update, but then we'll simply // pick it up on the next iterationm when the job is stopped and render // thread is no longer using it. - if (m_internalState == State_Running - && !m_controller->isPendingStart(m_job) + if (!m_controller->isPendingStart(m_job) && !m_job->isRunning()) { stop(); } @@ -167,9 +174,9 @@ void QQuickAnimatorProxyJob::updateState(QAbstractAnimationJob::State newState, } } else if (newState == Stopped) { - syncBackCurrentValues(); m_internalState = State_Stopped; if (m_controller) { + syncBackCurrentValues(); m_controller->cancel(m_job); } } @@ -193,6 +200,7 @@ void QQuickAnimatorProxyJob::setWindow(QQuickWindow *window) if (m_job && m_controller) m_controller->cancel(m_job); m_controller = nullptr; + stop(); } else if (!m_controller && m_job) { m_controller = QQuickWindowPrivate::get(window)->animationController; -- cgit v1.2.3 From 19fb8ce3270c183a0b4e21b0920963a5a05e2653 Mon Sep 17 00:00:00 2001 From: Stephan Binner Date: Tue, 18 Apr 2017 11:57:37 +0200 Subject: Fix warning for -no-feature-shortcut Change-Id: I2f6f38af1fb9ecc8a763f9c2d0a45200fd6374af Reviewed-by: Simon Hausmann --- src/quick/items/qquicktextinput.cpp | 2 ++ 1 file changed, 2 insertions(+) (limited to 'src') diff --git a/src/quick/items/qquicktextinput.cpp b/src/quick/items/qquicktextinput.cpp index a023ad8a8c..1edff3ff83 100644 --- a/src/quick/items/qquicktextinput.cpp +++ b/src/quick/items/qquicktextinput.cpp @@ -4403,7 +4403,9 @@ void QQuickTextInputPrivate::processKeyEvent(QKeyEvent* event) } bool unknown = false; +#if QT_CONFIG(shortcut) bool visual = cursorMoveStyle() == Qt::VisualMoveStyle; +#endif if (false) { } -- cgit v1.2.3 From 301ed17778bf5fd59c026c532d1f5e294b5746bb Mon Sep 17 00:00:00 2001 From: Stephan Binner Date: Tue, 18 Apr 2017 11:39:54 +0200 Subject: Fix warning for -no-feature-desktopservices Change-Id: Ia3a590a564ab9bde9b19c4e7955420a7d1eacb2b Reviewed-by: Simon Hausmann --- src/quick/util/qquickglobal.cpp | 1 + 1 file changed, 1 insertion(+) (limited to 'src') diff --git a/src/quick/util/qquickglobal.cpp b/src/quick/util/qquickglobal.cpp index 5a723e4432..5ba849c57f 100644 --- a/src/quick/util/qquickglobal.cpp +++ b/src/quick/util/qquickglobal.cpp @@ -810,6 +810,7 @@ public: #ifndef QT_NO_DESKTOPSERVICES return QDesktopServices::openUrl(url); #else + Q_UNUSED(url); return false; #endif } -- cgit v1.2.3 From 25b0019cf97c7d803802c7f3c69ddc18f83c9aaa Mon Sep 17 00:00:00 2001 From: Stephan Binner Date: Tue, 18 Apr 2017 11:44:56 +0200 Subject: Fix warning for -no-feature-cursor Change-Id: Idc2ab95d0ea1e556995e7bcd29b5cbcd82bc28f6 Reviewed-by: Simon Hausmann --- src/quick/items/qquickitem.cpp | 2 ++ 1 file changed, 2 insertions(+) (limited to 'src') diff --git a/src/quick/items/qquickitem.cpp b/src/quick/items/qquickitem.cpp index 1a244b0dd9..82c9f4a4c6 100644 --- a/src/quick/items/qquickitem.cpp +++ b/src/quick/items/qquickitem.cpp @@ -7160,6 +7160,8 @@ void QQuickItemPrivate::setHasCursorInChild(bool hasCursor) QQuickItemPrivate *parentPrivate = QQuickItemPrivate::get(parent); parentPrivate->setHasCursorInChild(hasCursor); } +#else + Q_UNUSED(hasCursor); #endif } -- cgit v1.2.3 From b5d26157316877faa0f581a24ae106cb4a01d195 Mon Sep 17 00:00:00 2001 From: Robin Burchell Date: Wed, 19 Apr 2017 09:00:55 +0200 Subject: QQuickShortcut: Initialize id Change-Id: If1a8b91c11ca3d84e80691e247c0281a966a2939 Task-number: QTBUG-60206 Reviewed-by: J-P Nurmi --- src/quick/util/qquickshortcut_p.h | 1 + 1 file changed, 1 insertion(+) (limited to 'src') diff --git a/src/quick/util/qquickshortcut_p.h b/src/quick/util/qquickshortcut_p.h index 93430ad893..db918058b2 100644 --- a/src/quick/util/qquickshortcut_p.h +++ b/src/quick/util/qquickshortcut_p.h @@ -111,6 +111,7 @@ protected: bool event(QEvent *event) Q_DECL_OVERRIDE; struct Shortcut { + Shortcut() : id(0) { } bool matches(QShortcutEvent *event) const; int id; QVariant userValue; -- cgit v1.2.3 From 49fa5d9b6915cba4264b090ff0ee98e5b5c5eac8 Mon Sep 17 00:00:00 2001 From: Friedemann Kleint Date: Wed, 19 Apr 2017 14:20:19 +0200 Subject: Add \since to QSGTexture::AnisotropyLevel Amends change 5ef3265cd46de6579399562429e26961d6f13885. Change-Id: I6c75273e45e235084e5aea53e83669bab85798ee Reviewed-by: Andy Nichols --- src/quick/scenegraph/util/qsgtexture.cpp | 2 ++ 1 file changed, 2 insertions(+) (limited to 'src') diff --git a/src/quick/scenegraph/util/qsgtexture.cpp b/src/quick/scenegraph/util/qsgtexture.cpp index bc59c49162..72125728a1 100644 --- a/src/quick/scenegraph/util/qsgtexture.cpp +++ b/src/quick/scenegraph/util/qsgtexture.cpp @@ -293,6 +293,8 @@ static void qt_debug_remove_texture(QSGTexture* texture) \value Anisotropy8x 8x anisotropic filtering. \value Anisotropy16x 16x anisotropic filtering. + + \since 5.9 */ /*! -- cgit v1.2.3 From 6a8a7e60ab91f958a1dd63e787a23f6e09f463b1 Mon Sep 17 00:00:00 2001 From: Robert Griebl Date: Wed, 19 Apr 2017 14:18:06 +0200 Subject: Fix for dangling object pointers in QQmlErrors This rarely happens - only seen with Delegates - when - an object is created during incubation - some error occurs in this object - the object gets deleted before the incubation run finishes Because the errors are delivered after the incubation run finished, the object() pointer of QQmlError is now a dangling pointer that will crash your application if accessed. Change-Id: Idd9fccbc58e4ada67bde3ca1aeec736aa9374789 Reviewed-by: Simon Hausmann --- src/qml/qml/qqmlerror.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/qml/qml/qqmlerror.cpp b/src/qml/qml/qqmlerror.cpp index 7a1e02eec6..64f008cd32 100644 --- a/src/qml/qml/qqmlerror.cpp +++ b/src/qml/qml/qqmlerror.cpp @@ -44,6 +44,7 @@ #include #include #include +#include #include @@ -86,7 +87,7 @@ public: quint16 line; quint16 column; QtMsgType messageType; - QObject *object; + QPointer object; }; QQmlErrorPrivate::QQmlErrorPrivate() -- cgit v1.2.3 From 749a7212e903d8e8c6f256edb1836b9449cc7fe1 Mon Sep 17 00:00:00 2001 From: Erik Verbruggen Date: Wed, 19 Apr 2017 14:29:21 +0200 Subject: QML: clear the property cache on QObjectWrapper destuction If an external QObject is exposed to an engine through a QObjectWrapper, make sure to deref and clear the propertyCache reference in the object's declarative data when the QObjectWrapper is destroyed. This makes sure that there is no dangling propertyCache pointer when the object is subsequently exposed to another engine. Task-number: QTBUG-57633 Change-Id: I37f6793d8be65b23b4e81bb4ed91db18271261b0 Reviewed-by: Simon Hausmann --- src/qml/jsruntime/qv4qobjectwrapper.cpp | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'src') diff --git a/src/qml/jsruntime/qv4qobjectwrapper.cpp b/src/qml/jsruntime/qv4qobjectwrapper.cpp index 346ca62a6f..26e72018c5 100644 --- a/src/qml/jsruntime/qv4qobjectwrapper.cpp +++ b/src/qml/jsruntime/qv4qobjectwrapper.cpp @@ -989,6 +989,10 @@ void QObjectWrapper::destroyObject(bool lastCall) // If the object is C++-owned, we still have to release the weak reference we have // to it. ddata->jsWrapper.clear(); + if (lastCall && ddata->propertyCache) { + ddata->propertyCache->release(); + ddata->propertyCache = nullptr; + } } } } -- cgit v1.2.3 From df66e9264debda2ec6838e69e620a54847c71b0a Mon Sep 17 00:00:00 2001 From: Thiago Macieira Date: Tue, 18 Apr 2017 21:06:54 -0700 Subject: Silence GCC 7 warnings about implicit fallthrough in Qt code This only deals with Qt code. MASM has a lot of those left. We should just update from upstream instead to get the fixes. qv4regalloc.cpp:660:52: warning: this statement may fall through [-Wimplicit-fallthrough=] if (leftSource->type == DoubleType || rightSource->type == DoubleType) { ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ qv4regalloc.cpp:666:13: note: here case OpBitAnd: ^~~~ Change-Id: I7814054a102a407d876ffffd14b6b0e2d6b03689 Reviewed-by: Allan Sandfeld Jensen --- src/particles/qquickimageparticle.cpp | 7 +++++++ src/qml/compiler/qv4ssa.cpp | 2 ++ src/qml/jit/qv4isel_masm.cpp | 1 + src/qml/jit/qv4regalloc.cpp | 2 ++ src/qml/jsruntime/qv4runtime.cpp | 2 ++ src/qml/jsruntime/qv4value.cpp | 3 +++ src/quick/items/qquicktextinput.cpp | 1 + src/quick/scenegraph/coreapi/qsgbatchrenderer.cpp | 2 +- src/quick/scenegraph/coreapi/qsgshaderrewriter.cpp | 1 + src/quick/scenegraph/util/qsgshadersourcebuilder.cpp | 4 +++- 10 files changed, 23 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/particles/qquickimageparticle.cpp b/src/particles/qquickimageparticle.cpp index ccfebddb0e..1919e2ff20 100644 --- a/src/particles/qquickimageparticle.cpp +++ b/src/particles/qquickimageparticle.cpp @@ -1323,6 +1323,7 @@ void QQuickImageParticle::finishBuildParticleNodes(QSGNode** node) getState(m_material)->animSheetSize = QSizeF(image.size()); if (m_spriteEngine) m_spriteEngine->setCount(m_count); + Q_FALLTHROUGH(); case Tabled: if (!m_material) m_material = TabledMaterial::createMaterial(); @@ -1355,12 +1356,15 @@ void QQuickImageParticle::finishBuildParticleNodes(QSGNode** node) getState(m_material)->colorTable = QSGPlainTexture::fromImage(colortable); fillUniformArrayFromImage(getState(m_material)->sizeTable, sizetable, UNIFORM_ARRAY_SIZE); fillUniformArrayFromImage(getState(m_material)->opacityTable, opacitytable, UNIFORM_ARRAY_SIZE); + Q_FALLTHROUGH(); case Deformable: if (!m_material) m_material = DeformableMaterial::createMaterial(); + Q_FALLTHROUGH(); case Colored: if (!m_material) m_material = ColoredMaterial::createMaterial(); + Q_FALLTHROUGH(); default://Also Simple if (!m_material) m_material = SimpleMaterial::createMaterial(); @@ -1530,6 +1534,7 @@ void QQuickImageParticle::prepareNextFrame(QSGNode **node) if (m_spriteEngine) m_spriteEngine->updateSprites(timeStamp);//fires signals if anim changed spritesUpdate(time); + Q_FALLTHROUGH(); case Tabled: case Deformable: case Colored: @@ -1691,6 +1696,7 @@ void QQuickImageParticle::initialize(int gIdx, int pIdx) writeTo->animWidth = getState(m_material)->animSheetSize.width(); writeTo->animHeight = getState(m_material)->animSheetSize.height(); } + Q_FALLTHROUGH(); case Tabled: case Deformable: //Initial Rotation @@ -1737,6 +1743,7 @@ void QQuickImageParticle::initialize(int gIdx, int pIdx) getShadowDatum(datum)->autoRotate = autoRotate; } } + Q_FALLTHROUGH(); case Colored: //Color initialization // Particle color diff --git a/src/qml/compiler/qv4ssa.cpp b/src/qml/compiler/qv4ssa.cpp index cc542e94e7..62e2833089 100644 --- a/src/qml/compiler/qv4ssa.cpp +++ b/src/qml/compiler/qv4ssa.cpp @@ -2345,6 +2345,7 @@ private: case OpIncrement: case OpDecrement: Q_ASSERT(!"Inplace operators should have been removed!"); + Q_UNREACHABLE(); default: Q_UNIMPLEMENTED(); Q_UNREACHABLE(); @@ -2645,6 +2646,7 @@ private: case OpMul: if (!targetTemp || !knownOk.contains(*targetTemp)) return false; + Q_FALLTHROUGH(); case OpBitAnd: case OpBitOr: case OpBitXor: diff --git a/src/qml/jit/qv4isel_masm.cpp b/src/qml/jit/qv4isel_masm.cpp index 7797f8c8db..4afcd1517f 100644 --- a/src/qml/jit/qv4isel_masm.cpp +++ b/src/qml/jit/qv4isel_masm.cpp @@ -994,6 +994,7 @@ void InstructionSelection::convertTypeToBool(IR::Expr *source, IR: generateRuntimeCall(_as, JITTargetPlatform::ReturnValueRegister, toBoolean, PointerToValue(source)); _as->storeBool(JITTargetPlatform::ReturnValueRegister, target); + Q_FALLTHROUGH(); case IR::VarType: default: Pointer addr = _as->loadAddress(JITTargetPlatform::ScratchRegister, source); diff --git a/src/qml/jit/qv4regalloc.cpp b/src/qml/jit/qv4regalloc.cpp index 8eafaaaa8a..d418b050c4 100644 --- a/src/qml/jit/qv4regalloc.cpp +++ b/src/qml/jit/qv4regalloc.cpp @@ -125,6 +125,7 @@ protected: *out << ri->prettyName(); break; } + Q_FALLTHROUGH(); } default: IRPrinterWithPositions::visitTemp(e); @@ -662,6 +663,7 @@ protected: // IRDecoder addUses(rightSource->asTemp(), Use::MustHaveRegister); break; } + Q_FALLTHROUGH(); #endif case OpBitAnd: case OpBitOr: diff --git a/src/qml/jsruntime/qv4runtime.cpp b/src/qml/jsruntime/qv4runtime.cpp index 43e99cf768..42bf24d7f3 100644 --- a/src/qml/jsruntime/qv4runtime.cpp +++ b/src/qml/jsruntime/qv4runtime.cpp @@ -472,6 +472,7 @@ Heap::String *RuntimeHelpers::convertToString(ExecutionEngine *engine, const Val switch (value.type()) { case Value::Empty_Type: Q_ASSERT(!"empty Value encountered"); + Q_UNREACHABLE(); case Value::Undefined_Type: return engine->id_undefined()->d(); case Value::Null_Type: @@ -504,6 +505,7 @@ static Heap::String *convert_to_string_add(ExecutionEngine *engine, const Value switch (value.type()) { case Value::Empty_Type: Q_ASSERT(!"empty Value encountered"); + Q_UNREACHABLE(); case Value::Undefined_Type: return engine->id_undefined()->d(); case Value::Null_Type: diff --git a/src/qml/jsruntime/qv4value.cpp b/src/qml/jsruntime/qv4value.cpp index e34ac9c764..f41442df7a 100644 --- a/src/qml/jsruntime/qv4value.cpp +++ b/src/qml/jsruntime/qv4value.cpp @@ -113,6 +113,7 @@ double Value::toNumberImpl() const case QV4::Value::Managed_Type: #ifdef V4_BOOTSTRAP Q_UNIMPLEMENTED(); + Q_FALLTHROUGH(); #else if (String *s = stringValue()) return RuntimeHelpers::stringToNumber(s->toQString()); @@ -140,6 +141,7 @@ QString Value::toQStringNoThrow() const switch (type()) { case Value::Empty_Type: Q_ASSERT(!"empty Value encountered"); + Q_UNREACHABLE(); case Value::Undefined_Type: return QStringLiteral("undefined"); case Value::Null_Type: @@ -193,6 +195,7 @@ QString Value::toQString() const switch (type()) { case Value::Empty_Type: Q_ASSERT(!"empty Value encountered"); + Q_UNREACHABLE(); case Value::Undefined_Type: return QStringLiteral("undefined"); case Value::Null_Type: diff --git a/src/quick/items/qquicktextinput.cpp b/src/quick/items/qquicktextinput.cpp index 1edff3ff83..f4a88a1c45 100644 --- a/src/quick/items/qquicktextinput.cpp +++ b/src/quick/items/qquicktextinput.cpp @@ -3885,6 +3885,7 @@ void QQuickTextInputPrivate::parseInputMask(const QString &maskFields) break; case '\\': escape = true; + Q_FALLTHROUGH(); default: s = true; break; diff --git a/src/quick/scenegraph/coreapi/qsgbatchrenderer.cpp b/src/quick/scenegraph/coreapi/qsgbatchrenderer.cpp index d4324bc489..14f8514289 100644 --- a/src/quick/scenegraph/coreapi/qsgbatchrenderer.cpp +++ b/src/quick/scenegraph/coreapi/qsgbatchrenderer.cpp @@ -338,7 +338,7 @@ void Updater::visitNode(Node *n) case QSGNode::RenderNodeType: if (m_added) n->renderNodeElement()->root = m_roots.last(); - // Fall through to visit children. + Q_FALLTHROUGH(); // to visit children default: SHADOWNODE_TRAVERSE(n) visitNode(child); break; diff --git a/src/quick/scenegraph/coreapi/qsgshaderrewriter.cpp b/src/quick/scenegraph/coreapi/qsgshaderrewriter.cpp index 48ab1aa52f..2b70139b37 100644 --- a/src/quick/scenegraph/coreapi/qsgshaderrewriter.cpp +++ b/src/quick/scenegraph/coreapi/qsgshaderrewriter.cpp @@ -133,6 +133,7 @@ Tokenizer::Token Tokenizer::next() pos += 3; return Token_Void; } + Q_FALLTHROUGH(); } case ';': return Token_SemiColon; diff --git a/src/quick/scenegraph/util/qsgshadersourcebuilder.cpp b/src/quick/scenegraph/util/qsgshadersourcebuilder.cpp index d8f92919cb..e134a5d4d3 100644 --- a/src/quick/scenegraph/util/qsgshadersourcebuilder.cpp +++ b/src/quick/scenegraph/util/qsgshadersourcebuilder.cpp @@ -122,6 +122,7 @@ Tokenizer::Token Tokenizer::next() case '*': if (*pos == '/') return Token_MultiLineCommentEnd; + Q_FALLTHROUGH(); case '\n': return Token_NewLine; @@ -129,6 +130,7 @@ Tokenizer::Token Tokenizer::next() case '\r': if (*pos == '\n') return Token_NewLine; + Q_FALLTHROUGH(); case '#': { if (*pos == 'v' && pos[1] == 'e' && pos[2] == 'r' && pos[3] == 's' @@ -177,7 +179,7 @@ Tokenizer::Token Tokenizer::next() pos += 3; return Token_Void; } - // Fall-thru + Q_FALLTHROUGH(); } default: // Identifier... -- cgit v1.2.3 From 1f3d52ac9d877a960bd5c1a6123bec6c6df586c3 Mon Sep 17 00:00:00 2001 From: Robin Burchell Date: Fri, 14 Apr 2017 09:59:39 +0200 Subject: QAccessibleQuickItem: Remove dead code Answer is "no, it cannot". Change-Id: I2b0a25f81b69578e9aa0b21e258d2dba5831e5ff Reviewed-by: Simon Hausmann --- src/quick/accessible/qaccessiblequickitem.cpp | 3 --- 1 file changed, 3 deletions(-) (limited to 'src') diff --git a/src/quick/accessible/qaccessiblequickitem.cpp b/src/quick/accessible/qaccessiblequickitem.cpp index fbde5d354d..2d6bb02af4 100644 --- a/src/quick/accessible/qaccessiblequickitem.cpp +++ b/src/quick/accessible/qaccessiblequickitem.cpp @@ -142,9 +142,6 @@ QAccessibleInterface *QAccessibleQuickItem::child(int index) const return 0; QQuickItem *child = children.at(index); - if (!child) // FIXME can this happen? - return 0; - return QAccessible::queryAccessibleInterface(child); } -- cgit v1.2.3 From 0745a27d82ab0b074dc2bc1c4c4f30624831b384 Mon Sep 17 00:00:00 2001 From: Robin Burchell Date: Tue, 14 Feb 2017 14:03:56 +0100 Subject: MM: Provide information about object types on sweep Helps give an idea about what kind of garbage is being tossed away. v8-bench shows no real change in performance outside "usual" variance, I didn't benchmark QV4_MM_STATS=1 but I assume there will be some penalty there. Change-Id: Ida0c5917289891279d95fd47480bd4869b42b0e6 Reviewed-by: Simon Hausmann Reviewed-by: Lars Knoll --- src/qml/memory/qv4mm.cpp | 69 ++++++++++++++++++++++++++++++++++---------- src/qml/memory/qv4mm_p.h | 6 ++-- src/qml/memory/qv4mmdefs_p.h | 4 ++- 3 files changed, 59 insertions(+), 20 deletions(-) (limited to 'src') diff --git a/src/qml/memory/qv4mm.cpp b/src/qml/memory/qv4mm.cpp index 7c57b93d9b..a0cfd5d925 100644 --- a/src/qml/memory/qv4mm.cpp +++ b/src/qml/memory/qv4mm.cpp @@ -318,8 +318,18 @@ void Heap::Base::markChildren(MarkStack *markStack) } } +// Stores a classname -> freed count mapping. +typedef QHash MMStatsHash; +Q_GLOBAL_STATIC(MMStatsHash, freedObjectStatsGlobal) -void Chunk::sweep() +// This indirection avoids sticking QHash code in each of the call sites, which +// shaves off some instructions in the case that it's unused. +static void increaseFreedCountForClass(const char *className) +{ + (*freedObjectStatsGlobal())[className]++; +} + +void Chunk::sweep(ClassDestroyStatsCallback classCountPtr) { // DEBUG << "sweeping chunk" << this << (*freeList); HeapItem *o = realBase(); @@ -349,8 +359,11 @@ void Chunk::sweep() HeapItem *itemToFree = o + index; Heap::Base *b = *itemToFree; - if (b->vtable()->destroy) { - b->vtable()->destroy(b); + const VTable *v = b->vtable(); + if (Q_UNLIKELY(classCountPtr)) + classCountPtr(v->className); + if (v->destroy) { + v->destroy(b); b->_checkIsDestroyed(); } } @@ -649,7 +662,7 @@ done: return m; } -void BlockAllocator::sweep() +void BlockAllocator::sweep(ClassDestroyStatsCallback classCountPtr) { nextFree = 0; nFree = 0; @@ -658,7 +671,7 @@ void BlockAllocator::sweep() // qDebug() << "BlockAlloc: sweep"; usedSlotsAfterLastSweep = 0; for (auto c : chunks) { - c->sweep(); + c->sweep(classCountPtr); c->sortIntoBins(freeBins, NumBins); // qDebug() << "used slots in chunk" << c << ":" << c->nUsedSlots(); usedSlotsAfterLastSweep += c->nUsedSlots(); @@ -724,22 +737,27 @@ HeapItem *HugeItemAllocator::allocate(size_t size) { return c->first(); } -static void freeHugeChunk(ChunkAllocator *chunkAllocator, const HugeItemAllocator::HugeChunk &c) +static void freeHugeChunk(ChunkAllocator *chunkAllocator, const HugeItemAllocator::HugeChunk &c, ClassDestroyStatsCallback classCountPtr) { HeapItem *itemToFree = c.chunk->first(); Heap::Base *b = *itemToFree; - if (b->vtable()->destroy) { - b->vtable()->destroy(b); + const VTable *v = b->vtable(); + if (Q_UNLIKELY(classCountPtr)) + classCountPtr(v->className); + + if (v->destroy) { + v->destroy(b); b->_checkIsDestroyed(); } chunkAllocator->free(c.chunk, c.size); } -void HugeItemAllocator::sweep() { - auto isBlack = [this] (const HugeChunk &c) { +void HugeItemAllocator::sweep(ClassDestroyStatsCallback classCountPtr) +{ + auto isBlack = [this, classCountPtr] (const HugeChunk &c) { bool b = c.chunk->first()->isBlack(); if (!b) - freeHugeChunk(chunkAllocator, c); + freeHugeChunk(chunkAllocator, c, classCountPtr); return !b; }; @@ -768,7 +786,7 @@ void HugeItemAllocator::collectGrayItems(MarkStack *markStack) void HugeItemAllocator::freeAll() { for (auto &c : chunks) { - freeHugeChunk(chunkAllocator, c); + freeHugeChunk(chunkAllocator, c, nullptr); } } @@ -984,7 +1002,7 @@ void MemoryManager::mark() markStack.drain(); } -void MemoryManager::sweep(bool lastSweep) +void MemoryManager::sweep(bool lastSweep, ClassDestroyStatsCallback classCountPtr) { for (PersistentValueStorage::Iterator it = m_weakValues->begin(); it != m_weakValues->end(); ++it) { Managed *m = (*it).managed(); @@ -1031,8 +1049,8 @@ void MemoryManager::sweep(bool lastSweep) } } - blockAllocator.sweep(); - hugeItemAllocator.sweep(); + blockAllocator.sweep(classCountPtr); + hugeItemAllocator.sweep(classCountPtr); } bool MemoryManager::shouldRunGC() const @@ -1105,7 +1123,7 @@ void MemoryManager::runGC() mark(); qint64 markTime = t.nsecsElapsed()/1000; t.restart(); - sweep(); + sweep(false, increaseFreedCountForClass); const size_t usedAfter = getUsedMem(); const size_t largeItemsAfter = getLargeItemsMem(); qint64 sweepTime = t.nsecsElapsed()/1000; @@ -1120,6 +1138,20 @@ void MemoryManager::runGC() qDebug() << "Marked object in" << markTime << "us."; qDebug() << " " << markStackSize << "objects marked"; qDebug() << "Sweeped object in" << sweepTime << "us."; + + // sort our object types by number of freed instances + MMStatsHash freedObjectStats; + std::swap(freedObjectStats, *freedObjectStatsGlobal()); + typedef std::pair ObjectStatInfo; + std::vector freedObjectsSorted; + freedObjectsSorted.reserve(freedObjectStats.count()); + for (auto it = freedObjectStats.constBegin(); it != freedObjectStats.constEnd(); ++it) { + freedObjectsSorted.push_back(std::make_pair(it.key(), it.value())); + } + std::sort(freedObjectsSorted.begin(), freedObjectsSorted.end(), [](const ObjectStatInfo &a, const ObjectStatInfo &b) { + return a.second > b.second && strcmp(a.first, b.first) < 0; + }); + qDebug() << "Used memory before GC:" << usedBefore; qDebug() << "Used memory after GC :" << usedAfter; qDebug() << "Freed up bytes :" << (usedBefore - usedAfter); @@ -1131,6 +1163,11 @@ void MemoryManager::runGC() qDebug() << "Large item memory after GC:" << largeItemsAfter; qDebug() << "Large item memory freed up:" << (largeItemsBefore - largeItemsAfter); } + + for (auto it = freedObjectsSorted.cbegin(); it != freedObjectsSorted.cend(); ++it) { + qDebug().noquote() << QString::fromLatin1("Freed JS type: %1 (%2 instances)").arg(QString::fromLatin1(it->first), QString::number(it->second)); + } + qDebug() << "======== End GC ========"; } diff --git a/src/qml/memory/qv4mm_p.h b/src/qml/memory/qv4mm_p.h index 76ffec42de..07e428b9bc 100644 --- a/src/qml/memory/qv4mm_p.h +++ b/src/qml/memory/qv4mm_p.h @@ -153,7 +153,7 @@ struct BlockAllocator { return used; } - void sweep(); + void sweep(ClassDestroyStatsCallback classCountPtr); void freeAll(); void resetBlackBits(); void collectGrayItems(MarkStack *markStack); @@ -176,7 +176,7 @@ struct HugeItemAllocator { {} HeapItem *allocate(size_t size); - void sweep(); + void sweep(ClassDestroyStatsCallback classCountPtr); void freeAll(); void resetBlackBits(); void collectGrayItems(MarkStack *markStack); @@ -446,7 +446,7 @@ protected: private: void collectFromJSStack(MarkStack *markStack) const; void mark(); - void sweep(bool lastSweep = false); + void sweep(bool lastSweep = false, ClassDestroyStatsCallback classCountPtr = nullptr); bool shouldRunGC() const; void collectRoots(MarkStack *markStack); diff --git a/src/qml/memory/qv4mmdefs_p.h b/src/qml/memory/qv4mmdefs_p.h index 9512722782..bf29b44a2c 100644 --- a/src/qml/memory/qv4mmdefs_p.h +++ b/src/qml/memory/qv4mmdefs_p.h @@ -61,6 +61,8 @@ namespace QV4 { struct MarkStack; +typedef void(*ClassDestroyStatsCallback)(const char *); + /* * Chunks are the basic structure containing GC managed objects. * @@ -184,7 +186,7 @@ struct Chunk { return usedSlots; } - void sweep(); + void sweep(ClassDestroyStatsCallback classCountPtr); void freeAll(); void resetBlackBits(); void collectGrayItems(QV4::MarkStack *markStack); -- cgit v1.2.3 From 85eaae8b4c7e3cf0cf7eb69e3ba0affb820ac08e Mon Sep 17 00:00:00 2001 From: Tasuku Suzuki Date: Mon, 3 Apr 2017 15:46:29 +0900 Subject: Fix build without features.qml-interpreter Change-Id: I5f9c00541c27377e8310d32bf045c2860eeffcb4 Reviewed-by: Oswald Buddenhagen --- src/plugins/qmltooling/qmltooling.pro | 29 ++++++++++++++++------------- src/qml/jsruntime/qv4engine.cpp | 2 +- 2 files changed, 17 insertions(+), 14 deletions(-) (limited to 'src') diff --git a/src/plugins/qmltooling/qmltooling.pro b/src/plugins/qmltooling/qmltooling.pro index 8123e2999e..27c51b53c8 100644 --- a/src/plugins/qmltooling/qmltooling.pro +++ b/src/plugins/qmltooling/qmltooling.pro @@ -1,5 +1,5 @@ TEMPLATE = subdirs -QT_FOR_CONFIG += qml +QT_FOR_CONFIG += qml-private # Utilities SUBDIRS += \ @@ -10,25 +10,28 @@ SUBDIRS += \ qmldbg_native \ qmldbg_server +qmldbg_native.depends = packetprotocol +qmldbg_server.depends = packetprotocol + qtConfig(qml-network) { SUBDIRS += \ qmldbg_local \ qmldbg_tcp } -# Services -SUBDIRS += \ - qmldbg_debugger \ - qmldbg_profiler \ - qmldbg_messages \ - qmldbg_nativedebugger +qtConfig(qml-interpreter) { + # Services + SUBDIRS += \ + qmldbg_debugger \ + qmldbg_profiler \ + qmldbg_messages \ + qmldbg_nativedebugger -qmldbg_server.depends = packetprotocol -qmldbg_native.depends = packetprotocol -qmldbg_debugger.depends = packetprotocol -qmldbg_profiler.depends = packetprotocol -qmldbg_messages.depends = packetprotocol -qmldbg_nativedebugger.depends = packetprotocol + qmldbg_debugger.depends = packetprotocol + qmldbg_profiler.depends = packetprotocol + qmldbg_messages.depends = packetprotocol + qmldbg_nativedebugger.depends = packetprotocol +} qtHaveModule(quick) { SUBDIRS += \ diff --git a/src/qml/jsruntime/qv4engine.cpp b/src/qml/jsruntime/qv4engine.cpp index b5d4e6909b..0b61c6e7e6 100644 --- a/src/qml/jsruntime/qv4engine.cpp +++ b/src/qml/jsruntime/qv4engine.cpp @@ -182,7 +182,7 @@ ExecutionEngine::ExecutionEngine(EvalISelFactory *factory) "solutions for your platform."); } #else - factory = new JIT::ISelFactory; + factory = new JIT::ISelFactory<>; #endif } iselFactory.reset(factory); -- cgit v1.2.3 From 3d05a10e40d4349b01e292dbc297036f8de38049 Mon Sep 17 00:00:00 2001 From: Lars Knoll Date: Fri, 21 Apr 2017 11:57:22 +0200 Subject: Fix GC corruption on macOS and possibly some other OSes Marking mmap'ed memory as unneeded, leads to it being zeroed out on both Linux and Windows. Unfortunately that behavior is not defined by POSIX, so BSD based OSes (and possible others as well) do not do this. We do however rely on getting zeroed out memory whenever we allocate a new Chunk for the garbage collector. To work around this, zero out memory we deallocate on those platforms. Task-number: QTBUG-59278 Task-number: QTBUG-59977 Change-Id: Idde812db8537b63b9e9df7de41620ce0df09b6de Reviewed-by: Simon Hausmann Reviewed-by: Robin Burchell --- src/qml/memory/qv4mm.cpp | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'src') diff --git a/src/qml/memory/qv4mm.cpp b/src/qml/memory/qv4mm.cpp index 27adfcb517..88912a6678 100644 --- a/src/qml/memory/qv4mm.cpp +++ b/src/qml/memory/qv4mm.cpp @@ -161,6 +161,13 @@ struct MemorySegment { size_t pageSize = WTF::pageSize(); size = (size + pageSize - 1) & ~(pageSize - 1); +#if !defined(Q_OS_LINUX) && !defined(Q_OS_WIN) + // Linux and Windows zero out pages that have been decommitted and get committed again. + // unfortunately that's not true on other OSes (e.g. BSD based ones), so zero out the + // memory before decommit, so that we can be sure that all chunks we allocate will be + // zero initialized. + memset(chunk, 0, size); +#endif pageReservation.decommit(chunk, size); } -- cgit v1.2.3 From 4397eca4e35b7818f5b251722bf07f53692c9379 Mon Sep 17 00:00:00 2001 From: Nico Vertriest Date: Fri, 21 Apr 2017 17:16:20 +0200 Subject: Doc: remove reference to no longer existing properties qquickmultipointtoucharea.cpp:170: warning: Can't link to 'horizontalDiameter' qquickmultipointtoucharea.cpp:170: warning: Can't link to 'verticalDiameter' Change-Id: Ib1cf7c634457f1557631d0e6ffdc942917746e04 Reviewed-by: Martin Smith --- src/quick/items/qquickmultipointtoucharea.cpp | 2 -- 1 file changed, 2 deletions(-) (limited to 'src') diff --git a/src/quick/items/qquickmultipointtoucharea.cpp b/src/quick/items/qquickmultipointtoucharea.cpp index 62119effb2..1882976e0c 100644 --- a/src/quick/items/qquickmultipointtoucharea.cpp +++ b/src/quick/items/qquickmultipointtoucharea.cpp @@ -176,8 +176,6 @@ void QQuickTouchPoint::setVelocity(const QVector2D &velocity) It is deprecated because a touch point is more correctly modeled as an ellipse, whereas this rectangle represents the outer bounds of the ellipse after \l rotation. - - \sa horizontalDiameter, verticalDiameter */ void QQuickTouchPoint::setArea(const QRectF &area) { -- cgit v1.2.3 From c50113aaf4515c172a1dd2eb30532de088307d78 Mon Sep 17 00:00:00 2001 From: Ville Voutilainen Date: Tue, 18 Apr 2017 16:55:20 +0300 Subject: Add support for std::vector and QVector matching the support for QList Task-number: QTBUG-60133 Change-Id: I5497dc3c4a1c3922e7147d7a20593c75a0d9d0e9 Reviewed-by: Qt CI Bot Reviewed-by: Marc Mutz Reviewed-by: Simon Hausmann --- src/qml/doc/src/cppintegration/data.qdoc | 18 ++++++++ src/qml/jsruntime/qv4sequenceobject.cpp | 77 ++++++++++++++++++++------------ 2 files changed, 67 insertions(+), 28 deletions(-) (limited to 'src') diff --git a/src/qml/doc/src/cppintegration/data.qdoc b/src/qml/doc/src/cppintegration/data.qdoc index 4523ee39d8..9cc7291583 100644 --- a/src/qml/doc/src/cppintegration/data.qdoc +++ b/src/qml/doc/src/cppintegration/data.qdoc @@ -273,10 +273,17 @@ In particular, QML currently supports: \li \c {QList} \li \c {QList} \li \c {QList} and \c{QStringList} + \li \c {QVector} + \li \c {std::vector} \li \c {QList} + \li \c {QVector} + \li \c {std::vector} \li \c {QVector} \li \c {QVector} \li \c {QVector} + \li \c {std::vector} + \li \c {std::vector} + \li \c {std::vector} \endlist These sequence types are implemented directly in terms of the underlying C++ @@ -296,6 +303,10 @@ If the sequence is returned from a Q_INVOKABLE function, access and mutation is much cheaper, as no QObject property read or write occurs; instead, the C++ sequence data is accessed and modified directly. +In both the Q_PROPERTY and return from Q_INVOKABLE cases, the elements +of a std::vector are copied. This copying may be an expensive operation, +so std::vector should be used judiciously. + Other sequence types are not supported transparently, and instead an instance of any other sequence type will be passed between QML and C++ as an opaque QVariantList. @@ -318,10 +329,17 @@ The default-constructed values for each sequence type are as follows: \row \li QList \li real value 0.0 \row \li QList \li boolean value \c {false} \row \li QList and QStringList \li empty QString +\row \li QVector \li empty QString +\row \li std::vector \li empty QString \row \li QList \li empty QUrl +\row \li QVector \li empty QUrl +\row \li std::vector \li empty QUrl \row \li QVector \li integer value 0 \row \li QVector \li real value 0.0 \row \li QVector \li boolean value \c {false} +\row \li std::vector \li integer value 0 +\row \li std::vector \li real value 0.0 +\row \li std::vector \li boolean value \c {false} \endtable If you wish to remove elements from a sequence rather than simply replace diff --git a/src/qml/jsruntime/qv4sequenceobject.cpp b/src/qml/jsruntime/qv4sequenceobject.cpp index 6d3110771e..2281fa22b6 100644 --- a/src/qml/jsruntime/qv4sequenceobject.cpp +++ b/src/qml/jsruntime/qv4sequenceobject.cpp @@ -78,13 +78,22 @@ static void generateWarning(QV4::ExecutionEngine *v4, const QString& description F(int, IntVector, QVector, 0) \ F(qreal, RealVector, QVector, 0.0) \ F(bool, BoolVector, QVector, false) \ + F(int, IntStdVector, std::vector, 0) \ + F(qreal, RealStdVector, std::vector, 0.0) \ + F(bool, BoolStdVector, std::vector, false) \ F(int, Int, QList, 0) \ F(qreal, Real, QList, 0.0) \ F(bool, Bool, QList, false) \ F(QString, String, QList, QString()) \ F(QString, QString, QStringList, QString()) \ + F(QString, StringVector, QVector, QString()) \ + F(QString, StringStdVector, std::vector, QString()) \ F(QUrl, Url, QList, QUrl()) \ + F(QUrl, UrlVector, QVector, QUrl()) \ + F(QUrl, UrlStdVector, std::vector, QUrl()) \ F(QModelIndex, QModelIndex, QModelIndexList, QModelIndex()) \ + F(QModelIndex, QModelIndexVector, QVector, QModelIndex()) \ + F(QModelIndex, QModelIndexStdVector, std::vector, QModelIndex()) \ F(QItemSelectionRange, QItemSelectionRange, QItemSelection, QItemSelectionRange()) static QV4::ReturnedValue convertElementToValue(QV4::ExecutionEngine *engine, const QString &element) @@ -263,11 +272,10 @@ public: } loadReference(); } - qint32 signedIdx = static_cast(index); - if (signedIdx < d()->container->count()) { + if (index < size_t(d()->container->size())) { if (hasProperty) *hasProperty = true; - return convertElementToValue(engine(), d()->container->at(signedIdx)); + return convertElementToValue(engine(), qAsConst(*(d()->container))[index]); } if (hasProperty) *hasProperty = false; @@ -291,24 +299,22 @@ public: loadReference(); } - qint32 signedIdx = static_cast(index); - - int count = d()->container->count(); + size_t count = size_t(d()->container->size()); typename Container::value_type element = convertValueToElement(value); - if (signedIdx == count) { - d()->container->append(element); - } else if (signedIdx < count) { - (*d()->container)[signedIdx] = element; + if (index == count) { + d()->container->push_back(element); + } else if (index < count) { + (*d()->container)[index] = element; } else { /* according to ECMA262r3 we need to insert */ /* the value at the given index, increasing length to index+1. */ - d()->container->reserve(signedIdx + 1); - while (signedIdx > count++) { - d()->container->append(typename Container::value_type()); + d()->container->reserve(index + 1); + while (index > count++) { + d()->container->push_back(typename Container::value_type()); } - d()->container->append(element); + d()->container->push_back(element); } if (d()->isReference) @@ -328,8 +334,7 @@ public: return QV4::Attr_Invalid; loadReference(); } - qint32 signedIdx = static_cast(index); - return (signedIdx < d()->container->count()) ? QV4::Attr_Data : QV4::Attr_Invalid; + return (index < size_t(d()->container->size())) ? QV4::Attr_Data : QV4::Attr_Invalid; } void containerAdvanceIterator(ObjectIterator *it, Value *name, uint *index, Property *p, PropertyAttributes *attrs) @@ -345,7 +350,7 @@ public: loadReference(); } - if (it->arrayIndex < static_cast(d()->container->count())) { + if (it->arrayIndex < static_cast(d()->container->size())) { *index = it->arrayIndex; ++it->arrayIndex; *attrs = QV4::Attr_Data; @@ -365,14 +370,13 @@ public: return false; loadReference(); } - qint32 signedIdx = static_cast(index); - if (signedIdx >= d()->container->count()) + if (index >= size_t(d()->container->size())) return false; /* according to ECMA262r3 it should be Undefined, */ /* but we cannot, so we insert a default-value instead. */ - d()->container->replace(signedIdx, typename Container::value_type()); + (*d()->container)[index] = typename Container::value_type(); if (d()->isReference) storeReference(); @@ -457,7 +461,7 @@ public: RETURN_RESULT(Encode(0)); This->loadReference(); } - RETURN_RESULT(Encode(This->d()->container->count())); + RETURN_RESULT(Encode(qint32(This->d()->container->size()))); } static void method_set_length(const BuiltinFunction *, Scope &scope, CallData *callData) @@ -479,8 +483,8 @@ public: This->loadReference(); } /* Determine whether we need to modify the sequence */ - qint32 newCount = static_cast(newLength); - qint32 count = This->d()->container->count(); + quint32 newCount = static_cast(newLength); + quint32 count = static_cast(This->d()->container->size()); if (newCount == count) { RETURN_UNDEFINED(); } else if (newCount > count) { @@ -489,14 +493,13 @@ public: /* We cannot, so we insert default-values instead. */ This->d()->container->reserve(newCount); while (newCount > count++) { - This->d()->container->append(typename Container::value_type()); + This->d()->container->push_back(typename Container::value_type()); } } else { /* according to ECMA262r3 we need to remove */ /* elements until the sequence is the required length. */ - while (newCount < count) { - count--; - This->d()->container->removeAt(count); + if (newCount < count) { + This->d()->container->erase(This->d()->container->begin() + newCount, This->d()->container->end()); } } /* write back if required. */ @@ -517,7 +520,7 @@ public: quint32 length = array->getLength(); QV4::ScopedValue v(scope); for (quint32 i = 0; i < length; ++i) - result << convertValueToElement((v = array->getIndexed(i))); + result.push_back(convertValueToElement((v = array->getIndexed(i)))); return QVariant::fromValue(result); } @@ -595,16 +598,34 @@ typedef QQmlSequence > QQmlRealVectorList; DEFINE_OBJECT_TEMPLATE_VTABLE(QQmlRealVectorList); typedef QQmlSequence > QQmlBoolVectorList; DEFINE_OBJECT_TEMPLATE_VTABLE(QQmlBoolVectorList); +typedef QQmlSequence > QQmlIntStdVectorList; +DEFINE_OBJECT_TEMPLATE_VTABLE(QQmlIntStdVectorList); +typedef QQmlSequence > QQmlRealStdVectorList; +DEFINE_OBJECT_TEMPLATE_VTABLE(QQmlRealStdVectorList); +typedef QQmlSequence > QQmlBoolStdVectorList; +DEFINE_OBJECT_TEMPLATE_VTABLE(QQmlBoolStdVectorList); typedef QQmlSequence QQmlQStringList; DEFINE_OBJECT_TEMPLATE_VTABLE(QQmlQStringList); typedef QQmlSequence > QQmlStringList; DEFINE_OBJECT_TEMPLATE_VTABLE(QQmlStringList); +typedef QQmlSequence > QQmlStringVectorList; +DEFINE_OBJECT_TEMPLATE_VTABLE(QQmlStringVectorList); +typedef QQmlSequence > QQmlStringStdVectorList; +DEFINE_OBJECT_TEMPLATE_VTABLE(QQmlStringStdVectorList); typedef QQmlSequence > QQmlIntList; DEFINE_OBJECT_TEMPLATE_VTABLE(QQmlIntList); typedef QQmlSequence > QQmlUrlList; DEFINE_OBJECT_TEMPLATE_VTABLE(QQmlUrlList); +typedef QQmlSequence > QQmlUrlVectorList; +DEFINE_OBJECT_TEMPLATE_VTABLE(QQmlUrlVectorList); +typedef QQmlSequence > QQmlUrlStdVectorList; +DEFINE_OBJECT_TEMPLATE_VTABLE(QQmlUrlStdVectorList); typedef QQmlSequence QQmlQModelIndexList; DEFINE_OBJECT_TEMPLATE_VTABLE(QQmlQModelIndexList); +typedef QQmlSequence > QQmlQModelIndexVectorList; +DEFINE_OBJECT_TEMPLATE_VTABLE(QQmlQModelIndexVectorList); +typedef QQmlSequence > QQmlQModelIndexStdVectorList; +DEFINE_OBJECT_TEMPLATE_VTABLE(QQmlQModelIndexStdVectorList); typedef QQmlSequence QQmlQItemSelectionRangeList; DEFINE_OBJECT_TEMPLATE_VTABLE(QQmlQItemSelectionRangeList); typedef QQmlSequence > QQmlBoolList; -- cgit v1.2.3 From 93bc4113f06dce4c942374d765bef20054cd1f94 Mon Sep 17 00:00:00 2001 From: Robin Burchell Date: Fri, 21 Apr 2017 16:45:56 +0200 Subject: QQuickCanvas: Fix requestAnimationFrame documentation The type here is an int, not a long. QML doesn't have a long type at all, too. Change-Id: I7aea92819f5e2afadddd7b79289a304875d4297f Reviewed-by: Shawn Rutledge --- src/quick/items/context2d/qquickcanvasitem.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/quick/items/context2d/qquickcanvasitem.cpp b/src/quick/items/context2d/qquickcanvasitem.cpp index dab35f2a54..bda3250c16 100644 --- a/src/quick/items/context2d/qquickcanvasitem.cpp +++ b/src/quick/items/context2d/qquickcanvasitem.cpp @@ -889,7 +889,7 @@ void QQuickCanvasItem::getContext(QQmlV4Function *args) } /*! - \qmlmethod long QtQuick::Canvas::requestAnimationFrame(callback) + \qmlmethod int QtQuick::Canvas::requestAnimationFrame(callback) This function schedules callback to be invoked before composing the Qt Quick scene. @@ -919,7 +919,7 @@ void QQuickCanvasItem::requestAnimationFrame(QQmlV4Function *args) } /*! - \qmlmethod QtQuick::Canvas::cancelRequestAnimationFrame(long handle) + \qmlmethod QtQuick::Canvas::cancelRequestAnimationFrame(int handle) This function will cancel the animation callback referenced by \a handle. */ -- cgit v1.2.3 From b94be73b551b31473e4239ae1d77c6e21ffbc849 Mon Sep 17 00:00:00 2001 From: Gunnar Sletta Date: Thu, 20 Apr 2017 21:37:58 +0200 Subject: Fix performance regression in animators since 5.6 The costly addition is down to that we're performing TransformJob::postSync() which we did not do before. This is superfluous though, as we do the same bit of code in preSync() and there is no way the pointers we're checking for can change between pre and post. Only missing bit is to move the invalidate(). Change-Id: I96420c14e11a5a33997ed6fac6a78695a917a8f2 Reviewed-by: Robin Burchell --- src/quick/util/qquickanimatorjob.cpp | 25 +++---------------------- src/quick/util/qquickanimatorjob_p.h | 1 - 2 files changed, 3 insertions(+), 23 deletions(-) (limited to 'src') diff --git a/src/quick/util/qquickanimatorjob.cpp b/src/quick/util/qquickanimatorjob.cpp index caf702bde5..9c9261c101 100644 --- a/src/quick/util/qquickanimatorjob.cpp +++ b/src/quick/util/qquickanimatorjob.cpp @@ -321,8 +321,10 @@ void QQuickTransformAnimatorJob::preSync() m_helper = nullptr; } - if (!m_target) + if (!m_target) { + invalidate(); return; + } if (!m_helper) { m_helper = qquick_transform_animatorjob_helper_store()->acquire(m_target); @@ -342,27 +344,6 @@ void QQuickTransformAnimatorJob::preSync() m_helper->sync(); } -void QQuickTransformAnimatorJob::postSync() -{ - Q_ASSERT((m_helper != nullptr) == (m_target != nullptr)); // If there is a target, there should also be a helper, ref: preSync - Q_ASSERT(!m_helper || m_helper->item == m_target); // If there is a helper, it should point to our target - - if (!m_target || !m_helper) { - invalidate(); - return; - } - - QQuickItemPrivate *d = QQuickItemPrivate::get(m_target); -#if QT_CONFIG(quick_shadereffect) - if (d->extra.isAllocated() - && d->extra->layer - && d->extra->layer->enabled()) { - d = QQuickItemPrivate::get(d->extra->layer->m_effectSource); - } -#endif - m_helper->node = d->itemNode(); -} - void QQuickTransformAnimatorJob::invalidate() { if (m_helper) diff --git a/src/quick/util/qquickanimatorjob_p.h b/src/quick/util/qquickanimatorjob_p.h index a3ced4c21b..777da2ee6c 100644 --- a/src/quick/util/qquickanimatorjob_p.h +++ b/src/quick/util/qquickanimatorjob_p.h @@ -235,7 +235,6 @@ public: protected: QQuickTransformAnimatorJob(); - void postSync() override; void invalidate() override; Helper *m_helper; -- cgit v1.2.3 From a9f6abde4ad71bf013ba465dd9171e9c445aae13 Mon Sep 17 00:00:00 2001 From: Robin Burchell Date: Fri, 21 Apr 2017 14:32:30 +0200 Subject: QQuickDesignerSupport: Port away from boundingRect This is undocumented and internal, as well as being virtual. It is usually (but not always) at a 0,0 position too, so I suspect that for the few items like text that aren't, this may have been incorrect. Change-Id: I948eceb5df052fdd137b37e211c244036b74299f Reviewed-by: Gunnar Sletta --- src/quick/designer/qquickdesignersupport.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/quick/designer/qquickdesignersupport.cpp b/src/quick/designer/qquickdesignersupport.cpp index 749ece8221..88971e3172 100644 --- a/src/quick/designer/qquickdesignersupport.cpp +++ b/src/quick/designer/qquickdesignersupport.cpp @@ -90,10 +90,11 @@ void QQuickDesignerSupport::refFromEffectItem(QQuickItem *referencedItem, bool h QSGRenderContext *rc = QQuickWindowPrivate::get(referencedItem->window())->context; QSGLayer *texture = rc->sceneGraphContext()->createLayer(rc); + QSizeF itemSize = referencedItem->size(); texture->setLive(true); texture->setItem(QQuickItemPrivate::get(referencedItem)->rootNode()); - texture->setRect(referencedItem->boundingRect()); - texture->setSize(referencedItem->boundingRect().size().toSize()); + texture->setRect(QRectF(QPointF(0, 0), itemSize)); + texture->setSize(itemSize.toSize()); texture->setRecursive(true); #if QT_CONFIG(opengl) #ifndef QT_OPENGL_ES -- cgit v1.2.3