Merge remote-tracking branch 'origin/5.15' into dev

Change-Id: I0376b25557ba633e5b148c6e9c467d88fae1778f
This commit is contained in:
Qt Forward Merge Bot 2019-10-17 01:00:10 +02:00
commit a298b4dc5f
31 changed files with 471 additions and 211 deletions

View File

@ -39,13 +39,13 @@
\include examples-run.qdocinc \include examples-run.qdocinc
\section1 GridView and PathView \section1 Using GridView and PathView
\e GridView and \e PathView demonstrate usage of these types to display \e GridView and \e PathView demonstrate usage of these types to display
views. views.
\snippet views/gridview/gridview-example.qml 0 \snippet views/gridview/gridview-example.qml 0
\section1 Dynamic List \section1 Using Dynamic List
\e{Dynamic List} demonstrates animation of runtime additions and removals to \e{Dynamic List} demonstrates animation of runtime additions and removals to
a \l ListView. a \l ListView.
@ -66,12 +66,12 @@
\snippet views/listview/expandingdelegates.qml 2 \snippet views/listview/expandingdelegates.qml 2
\snippet views/listview/expandingdelegates.qml 3 \snippet views/listview/expandingdelegates.qml 3
\section1 Highlight \section1 Using Highlight
\e Highlight demonstrates adding a custom highlight to a ListView. \e Highlight demonstrates adding a custom highlight to a ListView.
\snippet views/listview/highlight.qml 0 \snippet views/listview/highlight.qml 0
\section1 Highlight Ranges \section1 Using Highlight Ranges
\e{Highlight Ranges} shows the three different highlight range modes of \e{Highlight Ranges} shows the three different highlight range modes of
ListView. ListView.
@ -79,13 +79,13 @@
\snippet views/listview/highlightranges.qml 1 \snippet views/listview/highlightranges.qml 1
\snippet views/listview/highlightranges.qml 2 \snippet views/listview/highlightranges.qml 2
\section1 Sections \section1 Using Sections
\e Sections demonstrates the various section headers and footers available \e Sections demonstrates the various section headers and footers available
to \l ListView. to \l ListView.
\snippet views/listview/sections.qml 0 \snippet views/listview/sections.qml 0
\section1 Packages \section1 Using Packages
\e Packages use the \l [QML]{Package} type to transition delegates between \e Packages use the \l [QML]{Package} type to transition delegates between
two views. two views.
@ -100,13 +100,13 @@
\snippet views/package/view.qml 0 \snippet views/package/view.qml 0
\section1 ObjectModel \section1 Using ObjectModel
\e ObjectModel uses an ObjectModel for the model instead of a \l ListModel. \e ObjectModel uses an ObjectModel for the model instead of a \l ListModel.
\snippet views/objectmodel/objectmodel.qml 0 \snippet views/objectmodel/objectmodel.qml 0
\section1 Display Margins \section1 Using Display Margins
\e{Display Margins} uses delegates to display items and implements a simple \e{Display Margins} uses delegates to display items and implements a simple
header and footer components. header and footer components.

View File

@ -1631,7 +1631,7 @@ Item {
TestCase { TestCase {
name: "ItemTests" name: "ItemTests"
when: area.pressed when: windowShown
id: test1 id: test1
function test_touch() { function test_touch() {

View File

@ -1104,6 +1104,7 @@ void fillUniformArrayFromImage(float* array, const QImage& img, int size)
QQuickImageParticle::QQuickImageParticle(QQuickItem* parent) QQuickImageParticle::QQuickImageParticle(QQuickItem* parent)
: QQuickParticlePainter(parent) : QQuickParticlePainter(parent)
, m_color_variation(0.0) , m_color_variation(0.0)
, m_outgoingNode(nullptr)
, m_material(nullptr) , m_material(nullptr)
, m_alphaVariation(0.0) , m_alphaVariation(0.0)
, m_alpha(1.0) , m_alpha(1.0)
@ -1149,6 +1150,8 @@ void QQuickImageParticle::sceneGraphInvalidated()
{ {
m_nodes.clear(); m_nodes.clear();
m_material = nullptr; m_material = nullptr;
delete m_outgoingNode;
m_outgoingNode = nullptr;
} }
void QQuickImageParticle::setImage(const QUrl &image) void QQuickImageParticle::setImage(const QUrl &image)
@ -1931,8 +1934,11 @@ QSGNode *QQuickImageParticle::updatePaintNode(QSGNode *node, UpdatePaintNodeData
} }
if (m_pleaseReset){ if (m_pleaseReset){
if (node) // Cannot just destroy the node and then return null (in case image
delete node; // loading is still in progress). Rather, keep track of the old node
// until we have a new one.
delete m_outgoingNode;
m_outgoingNode = node;
node = nullptr; node = nullptr;
m_lastLevel = perfLevel; m_lastLevel = perfLevel;
@ -1946,6 +1952,9 @@ QSGNode *QQuickImageParticle::updatePaintNode(QSGNode *node, UpdatePaintNodeData
m_pleaseReset = false; m_pleaseReset = false;
m_startedImageLoading = 0;//Cancel a part-way build (may still have a pending load) m_startedImageLoading = 0;//Cancel a part-way build (may still have a pending load)
} else if (!m_material) {
delete node;
node = nullptr;
} }
if (m_system && m_system->isRunning() && !m_system->isPaused()){ if (m_system && m_system->isRunning() && !m_system->isPaused()){
@ -1959,6 +1968,11 @@ QSGNode *QQuickImageParticle::updatePaintNode(QSGNode *node, UpdatePaintNodeData
} }
} }
if (!node) {
node = m_outgoingNode;
m_outgoingNode = nullptr;
}
return node; return node;
} }

View File

@ -390,6 +390,7 @@ private:
QColor m_color; QColor m_color;
qreal m_color_variation; qreal m_color_variation;
QSGNode *m_outgoingNode;
QHash<int, QSGGeometryNode *> m_nodes; QHash<int, QSGGeometryNode *> m_nodes;
QHash<int, int> m_idxStarts;//TODO: Proper resizing will lead to needing a spriteEngine per particle - do this after sprite engine gains transparent sharing? QHash<int, int> m_idxStarts;//TODO: Proper resizing will lead to needing a spriteEngine per particle - do this after sprite engine gains transparent sharing?
QList<QPair<int, int> > m_startsIdx;//Same data, optimized for alternate retrieval QList<QPair<int, int> > m_startsIdx;//Same data, optimized for alternate retrieval

View File

@ -96,8 +96,9 @@ private:
static void printDisassembledOutputWithCalls(QByteArray processedOutput, static void printDisassembledOutputWithCalls(QByteArray processedOutput,
const QHash<const void*, const char*>& functions) const QHash<const void*, const char*>& functions)
{ {
for (QHash<const void*, const char*>::ConstIterator it = functions.begin(), end = functions.end(); const auto symbols = Runtime::symbolTable();
it != end; ++it) { const QByteArray padding(" ; ");
for (auto it = functions.begin(), end = functions.end(); it != end; ++it) {
const QByteArray ptrString = "0x" + QByteArray::number(quintptr(it.key()), 16); const QByteArray ptrString = "0x" + QByteArray::number(quintptr(it.key()), 16);
int idx = 0; int idx = 0;
while (idx >= 0) { while (idx >= 0) {
@ -107,7 +108,9 @@ static void printDisassembledOutputWithCalls(QByteArray processedOutput,
idx = processedOutput.indexOf('\n', idx); idx = processedOutput.indexOf('\n', idx);
if (idx < 0) if (idx < 0)
break; break;
processedOutput = processedOutput.insert(idx, QByteArrayLiteral(" ; ") + it.value()); const char *functionName = it.value();
processedOutput = processedOutput.insert(
idx, padding + QByteArray(functionName ? functionName : symbols[it.key()]));
} }
} }
@ -302,27 +305,29 @@ void JIT::PlatformAssemblerCommon::passPointerAsArg(void *ptr, int arg)
storePtr(TrustedImmPtr(ptr), argStackAddress(arg)); storePtr(TrustedImmPtr(ptr), argStackAddress(arg));
} }
void PlatformAssemblerCommon::callRuntime(const char *functionName, const void *funcPtr) void PlatformAssemblerCommon::callRuntime(const void *funcPtr, const char *functionName)
{ {
#ifndef QT_NO_DEBUG #ifndef QT_NO_DEBUG
Q_ASSERT(remainingArgcForCall == 0); Q_ASSERT(remainingArgcForCall == 0);
remainingArgcForCall = NoCall; remainingArgcForCall = NoCall;
#endif #endif
callRuntimeUnchecked(functionName, funcPtr); callRuntimeUnchecked(funcPtr, functionName);
if (argcOnStackForCall > 0) { if (argcOnStackForCall > 0) {
addPtr(TrustedImm32(argcOnStackForCall), StackPointerRegister); addPtr(TrustedImm32(argcOnStackForCall), StackPointerRegister);
argcOnStackForCall = 0; argcOnStackForCall = 0;
} }
} }
void PlatformAssemblerCommon::callRuntimeUnchecked(const char *functionName, const void *funcPtr) void PlatformAssemblerCommon::callRuntimeUnchecked(const void *funcPtr, const char *functionName)
{ {
Q_ASSERT(functionName || Runtime::symbolTable().contains(funcPtr));
functions.insert(funcPtr, functionName); functions.insert(funcPtr, functionName);
callAbsolute(funcPtr); callAbsolute(funcPtr);
} }
void PlatformAssemblerCommon::tailCallRuntime(const char *functionName, const void *funcPtr) void PlatformAssemblerCommon::tailCallRuntime(const void *funcPtr, const char *functionName)
{ {
Q_ASSERT(functionName || Runtime::symbolTable().contains(funcPtr));
functions.insert(funcPtr, functionName); functions.insert(funcPtr, functionName);
setTailCallArg(EngineRegister, 1); setTailCallArg(EngineRegister, 1);
setTailCallArg(CppStackFrameRegister, 0); setTailCallArg(CppStackFrameRegister, 0);

View File

@ -706,9 +706,9 @@ public:
void passCppFrameAsArg(int arg); void passCppFrameAsArg(int arg);
void passInt32AsArg(int value, int arg); void passInt32AsArg(int value, int arg);
void passPointerAsArg(void *ptr, int arg); void passPointerAsArg(void *ptr, int arg);
void callRuntime(const char *functionName, const void *funcPtr); void callRuntime(const void *funcPtr, const char *functionName = nullptr);
void callRuntimeUnchecked(const char *functionName, const void *funcPtr); void callRuntimeUnchecked(const void *funcPtr, const char *functionName = nullptr);
void tailCallRuntime(const char *functionName, const void *funcPtr); void tailCallRuntime(const void *funcPtr, const char *functionName = nullptr);
void setTailCallArg(RegisterID src, int arg); void setTailCallArg(RegisterID src, int arg);
Address jsAlloca(int slotCount); Address jsAlloca(int slotCount);
void storeInt32AsValue(int srcInt, Address destAddr); void storeInt32AsValue(int srcInt, Address destAddr);

View File

@ -61,7 +61,8 @@ namespace JIT {
#define ASM_GENERATE_RUNTIME_CALL(function, destination) \ #define ASM_GENERATE_RUNTIME_CALL(function, destination) \
pasm()->GENERATE_RUNTIME_CALL(function, destination) pasm()->GENERATE_RUNTIME_CALL(function, destination)
#define callHelper(x) PlatformAssemblerCommon::callRuntimeUnchecked(#x, reinterpret_cast<void *>(&x)) #define callHelper(x) \
PlatformAssemblerCommon::callRuntimeUnchecked(reinterpret_cast<void *>(&x), #x)
const QV4::Value::ValueTypeInternal IntegerTag = QV4::Value::ValueTypeInternal::Integer; const QV4::Value::ValueTypeInternal IntegerTag = QV4::Value::ValueTypeInternal::Integer;
@ -83,10 +84,9 @@ public:
: PlatformAssemblerCommon(constantTable) : PlatformAssemblerCommon(constantTable)
{} {}
void callRuntime(const char *functionName, const void *funcPtr, void callRuntime(const void *funcPtr, CallResultDestination dest)
CallResultDestination dest)
{ {
PlatformAssemblerCommon::callRuntime(functionName, funcPtr); PlatformAssemblerCommon::callRuntime(funcPtr);
if (dest == CallResultDestination::InAccumulator) if (dest == CallResultDestination::InAccumulator)
saveReturnValueInAccumulator(); saveReturnValueInAccumulator();
} }
@ -240,7 +240,7 @@ public:
auto isInt = branch32(Equal, TrustedImm32(Value::QT_Int), ScratchRegister2); auto isInt = branch32(Equal, TrustedImm32(Value::QT_Int), ScratchRegister2);
move(AccumulatorRegister, registerForArg(0)); move(AccumulatorRegister, registerForArg(0));
callRuntimeUnchecked("toInt32Helper", reinterpret_cast<void *>(&toInt32Helper)); callHelper(toInt32Helper);
saveReturnValueInAccumulator(); saveReturnValueInAccumulator();
isInt.link(this); isInt.link(this);
@ -383,10 +383,9 @@ public:
: PlatformAssemblerCommon(constantTable) : PlatformAssemblerCommon(constantTable)
{} {}
void callRuntime(const char *functionName, const void *funcPtr, void callRuntime(const void *funcPtr, CallResultDestination dest)
CallResultDestination dest)
{ {
PlatformAssemblerCommon::callRuntime(functionName, funcPtr); PlatformAssemblerCommon::callRuntime(funcPtr);
if (dest == CallResultDestination::InAccumulator) if (dest == CallResultDestination::InAccumulator)
saveReturnValueInAccumulator(); saveReturnValueInAccumulator();
} }
@ -491,7 +490,7 @@ public:
move(AccumulatorRegisterValue, registerForArg(0)); move(AccumulatorRegisterValue, registerForArg(0));
move(AccumulatorRegisterTag, registerForArg(1)); move(AccumulatorRegisterTag, registerForArg(1));
} }
callRuntimeUnchecked("toNumberHelper", reinterpret_cast<void *>(&toNumberHelper)); callHelper(toNumberHelper);
saveReturnValueInAccumulator(); saveReturnValueInAccumulator();
if (ArgInRegCount < 2) if (ArgInRegCount < 2)
addPtr(TrustedImm32(4 * PointerSize), StackPointerRegister); addPtr(TrustedImm32(4 * PointerSize), StackPointerRegister);
@ -548,7 +547,7 @@ public:
move(AccumulatorRegisterValue, registerForArg(0)); move(AccumulatorRegisterValue, registerForArg(0));
move(AccumulatorRegisterTag, registerForArg(1)); move(AccumulatorRegisterTag, registerForArg(1));
} }
callRuntimeUnchecked("toInt32Helper", reinterpret_cast<void *>(&toInt32Helper)); callHelper(toInt32Helper);
saveReturnValueInAccumulator(); saveReturnValueInAccumulator();
if (ArgInRegCount < 2) if (ArgInRegCount < 2)
addPtr(TrustedImm32(4 * PointerSize), StackPointerRegister); addPtr(TrustedImm32(4 * PointerSize), StackPointerRegister);
@ -570,7 +569,7 @@ public:
move(AccumulatorRegisterValue, registerForArg(0)); move(AccumulatorRegisterValue, registerForArg(0));
move(AccumulatorRegisterTag, registerForArg(1)); move(AccumulatorRegisterTag, registerForArg(1));
} }
callRuntimeUnchecked("toInt32Helper", reinterpret_cast<void *>(&toInt32Helper)); callHelper(toInt32Helper);
saveReturnValueInAccumulator(); saveReturnValueInAccumulator();
if (ArgInRegCount < 2) if (ArgInRegCount < 2)
addPtr(TrustedImm32(4 * PointerSize), StackPointerRegister); addPtr(TrustedImm32(4 * PointerSize), StackPointerRegister);
@ -1267,7 +1266,7 @@ void BaselineAssembler::cmpeqInt(int lhs)
else else
pasm()->move(PlatformAssembler::StackPointerRegister, pasm()->registerForArg(1)); pasm()->move(PlatformAssembler::StackPointerRegister, pasm()->registerForArg(1));
pasm()->pushAccumulatorAsArg(0); pasm()->pushAccumulatorAsArg(0);
pasm()->callRuntimeUnchecked("Equal", (void*)Runtime::Equal::call); pasm()->callRuntimeUnchecked((void*)Runtime::Equal::call);
pasm()->saveReturnValueInAccumulator(); pasm()->saveReturnValueInAccumulator();
if (PlatformAssembler::ArgInRegCount < 2) if (PlatformAssembler::ArgInRegCount < 2)
pasm()->addPtr(TrustedImm32(2 * PlatformAssembler::PointerSize), PlatformAssembler::StackPointerRegister); pasm()->addPtr(TrustedImm32(2 * PlatformAssembler::PointerSize), PlatformAssembler::StackPointerRegister);
@ -1291,7 +1290,7 @@ void BaselineAssembler::cmpneInt(int lhs)
else else
pasm()->move(PlatformAssembler::StackPointerRegister, pasm()->registerForArg(1)); pasm()->move(PlatformAssembler::StackPointerRegister, pasm()->registerForArg(1));
pasm()->pushAccumulatorAsArg(0); pasm()->pushAccumulatorAsArg(0);
pasm()->callRuntimeUnchecked("NotEqual", (void*)Runtime::NotEqual::call); pasm()->callRuntimeUnchecked((void*)Runtime::NotEqual::call);
pasm()->saveReturnValueInAccumulator(); pasm()->saveReturnValueInAccumulator();
if (PlatformAssembler::ArgInRegCount < 2) if (PlatformAssembler::ArgInRegCount < 2)
pasm()->addPtr(TrustedImm32(2 * PlatformAssembler::PointerSize), PlatformAssembler::StackPointerRegister); pasm()->addPtr(TrustedImm32(2 * PlatformAssembler::PointerSize), PlatformAssembler::StackPointerRegister);
@ -1305,7 +1304,7 @@ void BaselineAssembler::cmpneInt(int lhs)
done.link(pasm()); done.link(pasm());
} }
void BaselineAssembler::cmp(int cond, CmpFunc function, const char *functionName, int lhs) void BaselineAssembler::cmp(int cond, CmpFunc function, int lhs)
{ {
auto c = static_cast<PlatformAssembler::RelationalCondition>(cond); auto c = static_cast<PlatformAssembler::RelationalCondition>(cond);
auto done = pasm()->binopBothIntPath(regAddr(lhs), [this, c](){ auto done = pasm()->binopBothIntPath(regAddr(lhs), [this, c](){
@ -1321,7 +1320,7 @@ void BaselineAssembler::cmp(int cond, CmpFunc function, const char *functionName
pasm()->passAccumulatorAsArg(1); pasm()->passAccumulatorAsArg(1);
pasm()->passJSSlotAsArg(lhs, 0); pasm()->passJSSlotAsArg(lhs, 0);
callRuntime(functionName, reinterpret_cast<void*>(function), CallResultDestination::InAccumulator); callRuntime(reinterpret_cast<void*>(function), CallResultDestination::InAccumulator);
checkException(); checkException();
// done. // done.
@ -1331,50 +1330,42 @@ void BaselineAssembler::cmp(int cond, CmpFunc function, const char *functionName
void BaselineAssembler::cmpeq(int lhs) void BaselineAssembler::cmpeq(int lhs)
{ {
cmp(PlatformAssembler::Equal, &Runtime::CompareEqual::call, cmp(PlatformAssembler::Equal, &Runtime::CompareEqual::call, lhs);
"CompareEqual", lhs);
} }
void BaselineAssembler::cmpne(int lhs) void BaselineAssembler::cmpne(int lhs)
{ {
cmp(PlatformAssembler::NotEqual, &Runtime::CompareNotEqual::call, cmp(PlatformAssembler::NotEqual, &Runtime::CompareNotEqual::call, lhs);
"CompareNotEqual", lhs);
} }
void BaselineAssembler::cmpgt(int lhs) void BaselineAssembler::cmpgt(int lhs)
{ {
cmp(PlatformAssembler::GreaterThan, &Runtime::CompareGreaterThan::call, cmp(PlatformAssembler::GreaterThan, &Runtime::CompareGreaterThan::call, lhs);
"CompareGreaterThan", lhs);
} }
void BaselineAssembler::cmpge(int lhs) void BaselineAssembler::cmpge(int lhs)
{ {
cmp(PlatformAssembler::GreaterThanOrEqual, &Runtime::CompareGreaterEqual::call, cmp(PlatformAssembler::GreaterThanOrEqual, &Runtime::CompareGreaterEqual::call, lhs);
"CompareGreaterEqual", lhs);
} }
void BaselineAssembler::cmplt(int lhs) void BaselineAssembler::cmplt(int lhs)
{ {
cmp(PlatformAssembler::LessThan, &Runtime::CompareLessThan::call, cmp(PlatformAssembler::LessThan, &Runtime::CompareLessThan::call, lhs);
"CompareLessThan", lhs);
} }
void BaselineAssembler::cmple(int lhs) void BaselineAssembler::cmple(int lhs)
{ {
cmp(PlatformAssembler::LessThanOrEqual, &Runtime::CompareLessEqual::call, cmp(PlatformAssembler::LessThanOrEqual, &Runtime::CompareLessEqual::call, lhs);
"CompareLessEqual", lhs);
} }
void BaselineAssembler::cmpStrictEqual(int lhs) void BaselineAssembler::cmpStrictEqual(int lhs)
{ {
cmp(PlatformAssembler::Equal, &Runtime::CompareStrictEqual::call, cmp(PlatformAssembler::Equal, &Runtime::CompareStrictEqual::call, lhs);
"RuntimeHelpers::strictEqual", lhs);
} }
void BaselineAssembler::cmpStrictNotEqual(int lhs) void BaselineAssembler::cmpStrictNotEqual(int lhs)
{ {
cmp(PlatformAssembler::NotEqual, &Runtime::CompareStrictNotEqual::call, cmp(PlatformAssembler::NotEqual, &Runtime::CompareStrictNotEqual::call, lhs);
"RuntimeHelpers::strictNotEqual", lhs);
} }
int BaselineAssembler::jump(int offset) int BaselineAssembler::jump(int offset)
@ -1463,9 +1454,9 @@ void BaselineAssembler::passPointerAsArg(void *ptr, int arg)
pasm()->passPointerAsArg(ptr, arg); pasm()->passPointerAsArg(ptr, arg);
} }
void BaselineAssembler::callRuntime(const char *functionName, const void *funcPtr, CallResultDestination dest) void BaselineAssembler::callRuntime(const void *funcPtr, CallResultDestination dest)
{ {
pasm()->callRuntime(functionName, funcPtr, dest); pasm()->callRuntime(funcPtr, dest);
} }
void BaselineAssembler::saveAccumulatorInFrame() void BaselineAssembler::saveAccumulatorInFrame()
@ -1498,8 +1489,9 @@ void BaselineAssembler::jsTailCall(int func, int thisObject, int argc, int argv)
pasm()->storeInt32AsValue(argv, Address(tos.base, argvOffset)); pasm()->storeInt32AsValue(argv, Address(tos.base, argvOffset));
pasm()->moveReg(regAddr(thisObject), Address(tos.base, thisOffset)); pasm()->moveReg(regAddr(thisObject), Address(tos.base, thisOffset));
pasm()->moveReg(regAddr(func), Address(tos.base, funcOffset)); pasm()->moveReg(regAddr(func), Address(tos.base, funcOffset));
pasm()->tailCallRuntime("TheJitIs__Tail_Calling__ToTheRuntimeSoTheJitFrameIsMissing", pasm()->tailCallRuntime(
reinterpret_cast<void *>(TheJitIs__Tail_Calling__ToTheRuntimeSoTheJitFrameIsMissing)); reinterpret_cast<void *>(TheJitIs__Tail_Calling__ToTheRuntimeSoTheJitFrameIsMissing),
"TheJitIs__Tail_Calling__ToTheRuntimeSoTheJitFrameIsMissing");
} }
void BaselineAssembler::checkException() void BaselineAssembler::checkException()

View File

@ -62,16 +62,11 @@ QT_BEGIN_NAMESPACE
namespace QV4 { namespace QV4 {
namespace JIT { namespace JIT {
#define JIT_STRINGIFYx(s) #s
#define JIT_STRINGIFY(s) JIT_STRINGIFYx(s)
#define GENERATE_RUNTIME_CALL(function, destination) \ #define GENERATE_RUNTIME_CALL(function, destination) \
callRuntime(JIT_STRINGIFY(function), \ callRuntime(reinterpret_cast<void *>(&Runtime::function::call), \
reinterpret_cast<void *>(&Runtime::function::call), \
destination) destination)
#define GENERATE_TAIL_CALL(function) \ #define GENERATE_TAIL_CALL(function) \
tailCallRuntime(JIT_STRINGIFY(function), \ tailCallRuntime(reinterpret_cast<void *>(&function))
reinterpret_cast<void *>(&function))
class BaselineAssembler { class BaselineAssembler {
public: public:
@ -153,7 +148,7 @@ public:
void passCppFrameAsArg(int arg); void passCppFrameAsArg(int arg);
void passInt32AsArg(int value, int arg); void passInt32AsArg(int value, int arg);
void passPointerAsArg(void *ptr, int arg); void passPointerAsArg(void *ptr, int arg);
void callRuntime(const char *functionName, const void *funcPtr, CallResultDestination dest); void callRuntime(const void *funcPtr, CallResultDestination dest);
void saveAccumulatorInFrame(); void saveAccumulatorInFrame();
void loadAccumulatorFromFrame(); void loadAccumulatorFromFrame();
void jsTailCall(int func, int thisObject, int argc, int argv); void jsTailCall(int func, int thisObject, int argc, int argv);
@ -179,7 +174,7 @@ protected:
private: private:
typedef unsigned(*CmpFunc)(const Value&,const Value&); typedef unsigned(*CmpFunc)(const Value&,const Value&);
void cmp(int cond, CmpFunc function, const char *functionName, int lhs); void cmp(int cond, CmpFunc function, int lhs);
}; };
} // namespace JIT } // namespace JIT

View File

@ -2316,6 +2316,133 @@ Bool Runtime::CompareStrictNotEqual::call(const Value &left, const Value &right)
return ! RuntimeHelpers::strictEqual(left, right); return ! RuntimeHelpers::strictEqual(left, right);
} }
template<typename Operation>
static inline const void *symbol()
{
return reinterpret_cast<void *>(&Operation::call);
}
QHash<const void *, const char *> Runtime::symbolTable()
{
static const QHash<const void *, const char *> symbols({
#ifndef V4_BOOTSTRAP
{symbol<CallGlobalLookup>(), "CallGlobalLookup" },
{symbol<CallQmlContextPropertyLookup>(), "CallQmlContextPropertyLookup" },
{symbol<CallName>(), "CallName" },
{symbol<CallProperty>(), "CallProperty" },
{symbol<CallPropertyLookup>(), "CallPropertyLookup" },
{symbol<CallElement>(), "CallElement" },
{symbol<CallValue>(), "CallValue" },
{symbol<CallWithReceiver>(), "CallWithReceiver" },
{symbol<CallPossiblyDirectEval>(), "CallPossiblyDirectEval" },
{symbol<CallWithSpread>(), "CallWithSpread" },
{symbol<TailCall>(), "TailCall" },
{symbol<Construct>(), "Construct" },
{symbol<ConstructWithSpread>(), "ConstructWithSpread" },
{symbol<StoreNameStrict>(), "StoreNameStrict" },
{symbol<StoreNameSloppy>(), "StoreNameSloppy" },
{symbol<StoreProperty>(), "StoreProperty" },
{symbol<StoreElement>(), "StoreElement" },
{symbol<LoadProperty>(), "LoadProperty" },
{symbol<LoadName>(), "LoadName" },
{symbol<LoadElement>(), "LoadElement" },
{symbol<LoadSuperProperty>(), "LoadSuperProperty" },
{symbol<StoreSuperProperty>(), "StoreSuperProperty" },
{symbol<LoadSuperConstructor>(), "LoadSuperConstructor" },
{symbol<LoadGlobalLookup>(), "LoadGlobalLookup" },
{symbol<LoadQmlContextPropertyLookup>(), "LoadQmlContextPropertyLookup" },
{symbol<GetLookup>(), "GetLookup" },
{symbol<SetLookupStrict>(), "SetLookupStrict" },
{symbol<SetLookupSloppy>(), "SetLookupSloppy" },
{symbol<TypeofValue>(), "TypeofValue" },
{symbol<TypeofName>(), "TypeofName" },
{symbol<DeleteProperty_NoThrow>(), "DeleteProperty_NoThrow" },
{symbol<DeleteProperty>(), "DeleteProperty" },
{symbol<DeleteName_NoThrow>(), "DeleteName_NoThrow" },
{symbol<DeleteName>(), "DeleteName" },
{symbol<ThrowException>(), "ThrowException" },
{symbol<PushCallContext>(), "PushCallContext" },
{symbol<PushWithContext>(), "PushWithContext" },
{symbol<PushCatchContext>(), "PushCatchContext" },
{symbol<PushBlockContext>(), "PushBlockContext" },
{symbol<CloneBlockContext>(), "CloneBlockContext" },
{symbol<PushScriptContext>(), "PushScriptContext" },
{symbol<PopScriptContext>(), "PopScriptContext" },
{symbol<ThrowReferenceError>(), "ThrowReferenceError" },
{symbol<ThrowOnNullOrUndefined>(), "ThrowOnNullOrUndefined" },
{symbol<Closure>(), "Closure" },
{symbol<ConvertThisToObject>(), "ConvertThisToObject" },
{symbol<DeclareVar>(), "DeclareVar" },
{symbol<CreateMappedArgumentsObject>(), "CreateMappedArgumentsObject" },
{symbol<CreateUnmappedArgumentsObject>(), "CreateUnmappedArgumentsObject" },
{symbol<CreateRestParameter>(), "CreateRestParameter" },
{symbol<ArrayLiteral>(), "ArrayLiteral" },
{symbol<ObjectLiteral>(), "ObjectLiteral" },
{symbol<CreateClass>(), "CreateClass" },
{symbol<GetIterator>(), "GetIterator" },
{symbol<IteratorNext>(), "IteratorNext" },
{symbol<IteratorNextForYieldStar>(), "IteratorNextForYieldStar" },
{symbol<IteratorClose>(), "IteratorClose" },
{symbol<DestructureRestElement>(), "DestructureRestElement" },
{symbol<ToObject>(), "ToObject" },
{symbol<ToBoolean>(), "ToBoolean" },
{symbol<ToNumber>(), "ToNumber" },
{symbol<UMinus>(), "UMinus" },
{symbol<Instanceof>(), "Instanceof" },
{symbol<In>(), "In" },
{symbol<Add>(), "Add" },
{symbol<Sub>(), "Sub" },
{symbol<Mul>(), "Mul" },
{symbol<Div>(), "Div" },
{symbol<Mod>(), "Mod" },
{symbol<Exp>(), "Exp" },
{symbol<BitAnd>(), "BitAnd" },
{symbol<BitOr>(), "BitOr" },
{symbol<BitXor>(), "BitXor" },
{symbol<Shl>(), "Shl" },
{symbol<Shr>(), "Shr" },
{symbol<UShr>(), "UShr" },
{symbol<GreaterThan>(), "GreaterThan" },
{symbol<LessThan>(), "LessThan" },
{symbol<GreaterEqual>(), "GreaterEqual" },
{symbol<LessEqual>(), "LessEqual" },
{symbol<Equal>(), "Equal" },
{symbol<NotEqual>(), "NotEqual" },
{symbol<StrictEqual>(), "StrictEqual" },
{symbol<StrictNotEqual>(), "StrictNotEqual" },
{symbol<CompareGreaterThan>(), "CompareGreaterThan" },
{symbol<CompareLessThan>(), "CompareLessThan" },
{symbol<CompareGreaterEqual>(), "CompareGreaterEqual" },
{symbol<CompareLessEqual>(), "CompareLessEqual" },
{symbol<CompareEqual>(), "CompareEqual" },
{symbol<CompareNotEqual>(), "CompareNotEqual" },
{symbol<CompareStrictEqual>(), "CompareStrictEqual" },
{symbol<CompareStrictNotEqual>(), "CompareStrictNotEqual" },
{symbol<CompareInstanceof>(), "CompareInstanceOf" },
{symbol<CompareIn>(), "CompareIn" },
{symbol<RegexpLiteral>(), "RegexpLiteral" },
{symbol<GetTemplateObject>(), "GetTemplateObject" }
#endif
});
return symbols;
}
} // namespace QV4 } // namespace QV4
QT_END_NAMESPACE QT_END_NAMESPACE

View File

@ -501,6 +501,8 @@ struct Q_QML_PRIVATE_EXPORT Runtime {
static const int tailCall_argv = -3; static const int tailCall_argv = -3;
static const int tailCall_argc = -4; static const int tailCall_argc = -4;
}; };
static QHash<const void *, const char *> symbolTable();
}; };
static_assert(std::is_standard_layout<Runtime>::value, "Runtime needs to be standard layout in order for us to be able to use offsetof"); static_assert(std::is_standard_layout<Runtime>::value, "Runtime needs to be standard layout in order for us to be able to use offsetof");

View File

@ -298,8 +298,9 @@ protected:
case QMetaType::Int: case QMetaType::Int:
if (result.isInteger()) if (result.isInteger())
return doStore<int>(result.integerValue(), pd, flags); return doStore<int>(result.integerValue(), pd, flags);
else if (result.isNumber()) else if (result.isNumber()) {
return doStore<int>(result.doubleValue(), pd, flags); return doStore<int>(QV4::StaticValue::toInteger(result.doubleValue()), pd, flags);
}
break; break;
case QMetaType::Double: case QMetaType::Double:
if (result.isNumber()) if (result.isNumber())

View File

@ -969,6 +969,7 @@ void QQmlComponentPrivate::beginDeferred(QQmlEnginePrivate *enginePriv,
if (!state->creator->populateDeferredProperties(object, deferredData)) if (!state->creator->populateDeferredProperties(object, deferredData))
state->errors << state->creator->errors; state->errors << state->creator->errors;
deferredData->bindings.clear();
deferredState->constructionStates += state; deferredState->constructionStates += state;
} }

View File

@ -2141,6 +2141,40 @@ bool QQmlImportDatabase::importDynamicPlugin(const QString &filePath, const QStr
return true; return true;
} }
bool QQmlImportDatabase::removeDynamicPlugin(const QString &filePath)
{
StringRegisteredPluginMap *plugins = qmlEnginePluginsWithRegisteredTypes();
QMutexLocker lock(&plugins->mutex);
auto it = plugins->find(QFileInfo(filePath).absoluteFilePath());
if (it == plugins->end())
return false;
QPluginLoader *loader = it->loader;
if (!loader)
return false;
if (!loader->unload()) {
qWarning("Unloading %s failed: %s", qPrintable(it->uri),
qPrintable(loader->errorString()));
}
delete loader;
plugins->erase(it);
return true;
}
QStringList QQmlImportDatabase::dynamicPlugins() const
{
StringRegisteredPluginMap *plugins = qmlEnginePluginsWithRegisteredTypes();
QMutexLocker lock(&plugins->mutex);
QStringList results;
for (auto it = plugins->constBegin(), end = plugins->constEnd(); it != end; ++it) {
if (it->loader != nullptr)
results.append(it.key());
}
return results;
}
#endif // QT_CONFIG(library) #endif // QT_CONFIG(library)
void QQmlImportDatabase::clearDirCache() void QQmlImportDatabase::clearDirCache()

View File

@ -203,7 +203,7 @@ private:
QQmlImportsPrivate *d; QQmlImportsPrivate *d;
}; };
class QQmlImportDatabase class Q_QML_PRIVATE_EXPORT QQmlImportDatabase
{ {
Q_DECLARE_TR_FUNCTIONS(QQmlImportDatabase) Q_DECLARE_TR_FUNCTIONS(QQmlImportDatabase)
public: public:
@ -214,6 +214,8 @@ public:
#if QT_CONFIG(library) #if QT_CONFIG(library)
bool importDynamicPlugin(const QString &filePath, const QString &uri, const QString &importNamespace, int vmaj, QList<QQmlError> *errors); bool importDynamicPlugin(const QString &filePath, const QString &uri, const QString &importNamespace, int vmaj, QList<QQmlError> *errors);
bool removeDynamicPlugin(const QString &filePath);
QStringList dynamicPlugins() const;
#endif #endif
QStringList importPathList(PathType type = LocalOrRemote) const; QStringList importPathList(PathType type = LocalOrRemote) const;

View File

@ -234,73 +234,23 @@ QObject *QQmlObjectCreator::create(int subComponentIndex, QObject *parent, QQmlI
return instance; return instance;
} }
// ### unify or keep in sync with populateDeferredBinding() void QQmlObjectCreator::beginPopulateDeferred(QQmlContextData *newContext)
bool QQmlObjectCreator::populateDeferredProperties(QObject *instance, QQmlData::DeferredData *deferredData)
{ {
QQmlData *declarativeData = QQmlData::get(instance); context = newContext;
context = deferredData->context; sharedState->rootContext = newContext;
sharedState->rootContext = context;
QObject *bindingTarget = instance;
QQmlRefPointer<QQmlPropertyCache> cache = declarativeData->propertyCache;
QQmlVMEMetaObject *vmeMetaObject = QQmlVMEMetaObject::get(instance);
QObject *scopeObject = instance;
qSwap(_scopeObject, scopeObject);
QV4::Scope valueScope(v4);
Q_ASSERT(topLevelCreator); Q_ASSERT(topLevelCreator);
Q_ASSERT(!sharedState->allJavaScriptObjects); Q_ASSERT(!sharedState->allJavaScriptObjects);
QV4::Scope valueScope(v4);
sharedState->allJavaScriptObjects = valueScope.alloc(compilationUnit->totalObjectCount); sharedState->allJavaScriptObjects = valueScope.alloc(compilationUnit->totalObjectCount);
QV4::QmlContext *qmlContext = static_cast<QV4::QmlContext *>(valueScope.alloc());
qSwap(_qmlContext, qmlContext);
qSwap(_propertyCache, cache);
qSwap(_qobject, instance);
int objectIndex = deferredData->deferredIdx;
qSwap(_compiledObjectIndex, objectIndex);
const QV4::CompiledData::Object *obj = compilationUnit->objectAt(_compiledObjectIndex);
qSwap(_compiledObject, obj);
qSwap(_ddata, declarativeData);
qSwap(_bindingTarget, bindingTarget);
qSwap(_vmeMetaObject, vmeMetaObject);
setupBindings(/*applyDeferredBindings=*/true);
qSwap(_vmeMetaObject, vmeMetaObject);
qSwap(_bindingTarget, bindingTarget);
qSwap(_ddata, declarativeData);
qSwap(_compiledObject, obj);
qSwap(_compiledObjectIndex, objectIndex);
qSwap(_qobject, instance);
qSwap(_propertyCache, cache);
qSwap(_qmlContext, qmlContext);
qSwap(_scopeObject, scopeObject);
deferredData->bindings.clear();
phase = ObjectsCreated;
return errors.isEmpty();
} }
// ### unify or keep in sync with populateDeferredProperties() void QQmlObjectCreator::populateDeferred(QObject *instance, int deferredIndex,
bool QQmlObjectCreator::populateDeferredBinding(const QQmlProperty &qmlProperty, QQmlData::DeferredData *deferredData, const QV4::CompiledData::Binding *binding) const QQmlPropertyPrivate *qmlProperty,
const QV4::CompiledData::Binding *binding)
{ {
Q_ASSERT(binding->flags & QV4::CompiledData::Binding::IsDeferredBinding);
QObject *instance = qmlProperty.object();
QQmlData *declarativeData = QQmlData::get(instance); QQmlData *declarativeData = QQmlData::get(instance);
context = deferredData->context;
sharedState->rootContext = context;
QObject *bindingTarget = instance; QObject *bindingTarget = instance;
QQmlRefPointer<QQmlPropertyCache> cache = declarativeData->propertyCache; QQmlRefPointer<QQmlPropertyCache> cache = declarativeData->propertyCache;
@ -312,9 +262,6 @@ bool QQmlObjectCreator::populateDeferredBinding(const QQmlProperty &qmlProperty,
QV4::Scope valueScope(v4); QV4::Scope valueScope(v4);
Q_ASSERT(topLevelCreator); Q_ASSERT(topLevelCreator);
if (!sharedState->allJavaScriptObjects)
sharedState->allJavaScriptObjects = valueScope.alloc(compilationUnit->totalObjectCount);
QV4::QmlContext *qmlContext = static_cast<QV4::QmlContext *>(valueScope.alloc()); QV4::QmlContext *qmlContext = static_cast<QV4::QmlContext *>(valueScope.alloc());
qSwap(_qmlContext, qmlContext); qSwap(_qmlContext, qmlContext);
@ -322,7 +269,7 @@ bool QQmlObjectCreator::populateDeferredBinding(const QQmlProperty &qmlProperty,
qSwap(_propertyCache, cache); qSwap(_propertyCache, cache);
qSwap(_qobject, instance); qSwap(_qobject, instance);
int objectIndex = deferredData->deferredIdx; int objectIndex = deferredIndex;
qSwap(_compiledObjectIndex, objectIndex); qSwap(_compiledObjectIndex, objectIndex);
const QV4::CompiledData::Object *obj = compilationUnit->objectAt(_compiledObjectIndex); const QV4::CompiledData::Object *obj = compilationUnit->objectAt(_compiledObjectIndex);
@ -332,22 +279,29 @@ bool QQmlObjectCreator::populateDeferredBinding(const QQmlProperty &qmlProperty,
qSwap(_bindingTarget, bindingTarget); qSwap(_bindingTarget, bindingTarget);
qSwap(_vmeMetaObject, vmeMetaObject); qSwap(_vmeMetaObject, vmeMetaObject);
QQmlListProperty<void> savedList; if (binding) {
qSwap(_currentList, savedList); Q_ASSERT(qmlProperty);
Q_ASSERT(binding->flags & QV4::CompiledData::Binding::IsDeferredBinding);
const QQmlPropertyData &property = QQmlPropertyPrivate::get(qmlProperty)->core; QQmlListProperty<void> savedList;
qSwap(_currentList, savedList);
if (property.isQList()) { const QQmlPropertyData &property = qmlProperty->core;
void *argv[1] = { (void*)&_currentList };
QMetaObject::metacall(_qobject, QMetaObject::ReadProperty, property.coreIndex(), argv); if (property.isQList()) {
} else if (_currentList.object) { void *argv[1] = { (void*)&_currentList };
_currentList = QQmlListProperty<void>(); QMetaObject::metacall(_qobject, QMetaObject::ReadProperty, property.coreIndex(), argv);
} else if (_currentList.object) {
_currentList = QQmlListProperty<void>();
}
setPropertyBinding(&property, binding);
qSwap(_currentList, savedList);
} else {
setupBindings(/*applyDeferredBindings=*/true);
} }
setPropertyBinding(&property, binding);
qSwap(_currentList, savedList);
qSwap(_vmeMetaObject, vmeMetaObject); qSwap(_vmeMetaObject, vmeMetaObject);
qSwap(_bindingTarget, bindingTarget); qSwap(_bindingTarget, bindingTarget);
qSwap(_ddata, declarativeData); qSwap(_ddata, declarativeData);
@ -358,12 +312,29 @@ bool QQmlObjectCreator::populateDeferredBinding(const QQmlProperty &qmlProperty,
qSwap(_qmlContext, qmlContext); qSwap(_qmlContext, qmlContext);
qSwap(_scopeObject, scopeObject); qSwap(_scopeObject, scopeObject);
}
phase = ObjectsCreated; bool QQmlObjectCreator::populateDeferredProperties(QObject *instance,
const QQmlData::DeferredData *deferredData)
{
beginPopulateDeferred(deferredData->context);
populateDeferred(instance, deferredData->deferredIdx);
finalizePopulateDeferred();
return errors.isEmpty(); return errors.isEmpty();
} }
void QQmlObjectCreator::populateDeferredBinding(const QQmlProperty &qmlProperty, int deferredIndex,
const QV4::CompiledData::Binding *binding)
{
populateDeferred(qmlProperty.object(), deferredIndex, QQmlPropertyPrivate::get(qmlProperty),
binding);
}
void QQmlObjectCreator::finalizePopulateDeferred()
{
phase = ObjectsCreated;
}
void QQmlObjectCreator::setPropertyValue(const QQmlPropertyData *property, const QV4::CompiledData::Binding *binding) void QQmlObjectCreator::setPropertyValue(const QQmlPropertyData *property, const QV4::CompiledData::Binding *binding)
{ {
QQmlPropertyData::WriteFlags propertyWriteFlags = QQmlPropertyData::BypassInterceptor | QQmlPropertyData::RemoveBindingOnAliasWrite; QQmlPropertyData::WriteFlags propertyWriteFlags = QQmlPropertyData::BypassInterceptor | QQmlPropertyData::RemoveBindingOnAliasWrite;

View File

@ -112,8 +112,14 @@ public:
~QQmlObjectCreator(); ~QQmlObjectCreator();
QObject *create(int subComponentIndex = -1, QObject *parent = nullptr, QQmlInstantiationInterrupt *interrupt = nullptr); QObject *create(int subComponentIndex = -1, QObject *parent = nullptr, QQmlInstantiationInterrupt *interrupt = nullptr);
bool populateDeferredProperties(QObject *instance, QQmlData::DeferredData *deferredData);
bool populateDeferredBinding(const QQmlProperty &qmlProperty, QQmlData::DeferredData *deferredData, const QV4::CompiledData::Binding *binding); bool populateDeferredProperties(QObject *instance, const QQmlData::DeferredData *deferredData);
void beginPopulateDeferred(QQmlContextData *context);
void populateDeferredBinding(const QQmlProperty &qmlProperty, int deferredIndex,
const QV4::CompiledData::Binding *binding);
void finalizePopulateDeferred();
QQmlContextData *finalize(QQmlInstantiationInterrupt &interrupt); QQmlContextData *finalize(QQmlInstantiationInterrupt &interrupt);
void clear(); void clear();
@ -139,6 +145,11 @@ private:
bool populateInstance(int index, QObject *instance, bool populateInstance(int index, QObject *instance,
QObject *bindingTarget, const QQmlPropertyData *valueTypeProperty); QObject *bindingTarget, const QQmlPropertyData *valueTypeProperty);
// If qmlProperty and binding are null, populate all properties, otherwise only the given one.
void populateDeferred(QObject *instance, int deferredIndex,
const QQmlPropertyPrivate *qmlProperty = nullptr,
const QV4::CompiledData::Binding *binding = nullptr);
void setupBindings(bool applyDeferredBindings = false); void setupBindings(bool applyDeferredBindings = false);
bool setPropertyBinding(const QQmlPropertyData *property, const QV4::CompiledData::Binding *binding); bool setPropertyBinding(const QQmlPropertyData *property, const QV4::CompiledData::Binding *binding);
void setPropertyValue(const QQmlPropertyData *property, const QV4::CompiledData::Binding *binding); void setPropertyValue(const QQmlPropertyData *property, const QV4::CompiledData::Binding *binding);

View File

@ -62,7 +62,7 @@
#include <QtCore/qglobal.h> #include <QtCore/qglobal.h>
#include <QtCore/qvariant.h> #include <QtCore/qvariant.h>
#include <QtCore/qurl.h> #include <QtCore/qurl.h>
#include <QPointer> #include <QtCore/qpointer.h>
#include <QtCore/qmetaobject.h> #include <QtCore/qmetaobject.h>
#include <QtCore/qdebug.h> #include <QtCore/qdebug.h>

View File

@ -2060,20 +2060,19 @@ QSGNode *QQuickTextEdit::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData *
firstDirtyPos = nodeIterator->startPos(); firstDirtyPos = nodeIterator->startPos();
// ### this could be optimized if the first and last dirty nodes are not connected // ### this could be optimized if the first and last dirty nodes are not connected
// as the intermediate text nodes would usually only need to be transformed differently. // as the intermediate text nodes would usually only need to be transformed differently.
int lastDirtyPos = firstDirtyPos; QQuickTextNode *firstCleanNode = nullptr;
auto it = d->textNodeMap.constEnd(); auto it = d->textNodeMap.constEnd();
while (it != nodeIterator) { while (it != nodeIterator) {
--it; --it;
if (it->dirty()) { if (it->dirty())
lastDirtyPos = it->startPos();
break; break;
} firstCleanNode = it->textNode();
} }
do { do {
rootNode->removeChildNode(nodeIterator->textNode()); rootNode->removeChildNode(nodeIterator->textNode());
delete nodeIterator->textNode(); delete nodeIterator->textNode();
nodeIterator = d->textNodeMap.erase(nodeIterator); nodeIterator = d->textNodeMap.erase(nodeIterator);
} while (nodeIterator != d->textNodeMap.constEnd() && nodeIterator->startPos() <= lastDirtyPos); } while (nodeIterator != d->textNodeMap.constEnd() && nodeIterator->textNode() != firstCleanNode);
} }
// FIXME: the text decorations could probably be handled separately (only updated for affected textFrames) // FIXME: the text decorations could probably be handled separately (only updated for affected textFrames)

View File

@ -2259,8 +2259,8 @@ void QQuickTextInput::remove(int start, int end)
d->m_cursor -= qMin(d->m_cursor, end) - start; d->m_cursor -= qMin(d->m_cursor, end) - start;
if (d->m_selstart > start) if (d->m_selstart > start)
d->m_selstart -= qMin(d->m_selstart, end) - start; d->m_selstart -= qMin(d->m_selstart, end) - start;
if (d->m_selend > end) if (d->m_selend >= end)
d->m_selend -= qMin(d->m_selend, end) - start; d->m_selend -= end - start;
} }
d->addCommand(QQuickTextInputPrivate::Command( d->addCommand(QQuickTextInputPrivate::Command(
QQuickTextInputPrivate::SetSelection, d->m_cursor, 0, d->m_selstart, d->m_selend)); QQuickTextInputPrivate::SetSelection, d->m_cursor, 0, d->m_selstart, d->m_selend));

View File

@ -4220,16 +4220,18 @@ QQmlIncubationController *QQuickWindow::incubationController() const
The OpenGL context used for rendering the scene graph will be bound The OpenGL context used for rendering the scene graph will be bound
at this point. at this point.
When using the RHI and a graphics API other than OpenGL, the signal is When using the RHI, the signal is emitted after the preparations for the
emitted after the preparations for the frame have been done, meaning there frame have been done, meaning there is a command buffer in recording mode,
is a command buffer in recording mode, where applicable. If desired, the where applicable. If desired, the slot function connected to this signal
slot function connected to this signal can query native resources like the can query native resources like the command before via
command before via QSGRendererInterface. Note however that the recording of QSGRendererInterface. Note however that the recording of the main render
the main render pass is not yet started at this point and it is not pass is not yet started at this point and it is not possible to add
possible to add commands within that pass. Instead, use commands within that pass. Starting a pass means clearing the color, depth,
beforeRenderPassRecording() for that. However, connecting to this signal is and stencil buffers so it is not possible to achieve an underlay type of
still important if the recording of copy type of commands is desired since rendering by just connecting to this signal. Rather, connect to
those cannot be enqueued within a render pass. beforeRenderPassRecording(). However, connecting to this signal is still
important if the recording of copy type of commands is desired since those
cannot be enqueued within a render pass.
\warning This signal is emitted from the scene graph rendering thread. If your \warning This signal is emitted from the scene graph rendering thread. If your
slot function needs to finish before execution continues, you must make sure that slot function needs to finish before execution continues, you must make sure that
@ -4252,18 +4254,17 @@ QQmlIncubationController *QQuickWindow::incubationController() const
The OpenGL context used for rendering the scene graph will be bound at this point. The OpenGL context used for rendering the scene graph will be bound at this point.
When using the RHI and a graphics API other than OpenGL, the signal is When using the RHI, the signal is emitted after scene graph has added its
emitted after scene graph has added its commands to the command buffer, commands to the command buffer, which is not yet submitted to the graphics
which is not yet submitted to the graphics queue. If desired, the slot queue. If desired, the slot function connected to this signal can query
function connected to this signal can query native resources, like the native resources, like the command buffer, before via QSGRendererInterface.
command buffer, before via QSGRendererInterface. Note however that the Note however that the render pass (or passes) are already recorded at this
render pass (or passes) are already recorded at this point and it is not point and it is not possible to add more commands within the scenegraph's
possible to add more commands within the scenegraph's pass. Instead, use pass. Instead, use afterRenderPassRecording() for that. This signal has
afterRenderPassRecording() for that. This signal has therefore limited use therefore limited use and is rarely needed in an RHI-based setup. Rather,
and is rarely needed in an RHI-based setup. Rather, it is the combination it is the combination of beforeRendering() + beforeRenderPassRecording() or
of beforeRendering() + beforeRenderPassRecording() or beforeRendering() + beforeRendering() + afterRenderPassRecording() that is typically used to
afterRenderPassRecording() that is typically used to achieve under- or achieve under- or overlaying of the custom rendering.
overlaying of the custom rendering.
\warning This signal is emitted from the scene graph rendering thread. If your \warning This signal is emitted from the scene graph rendering thread. If your
slot function needs to finish before execution continues, you must make sure that slot function needs to finish before execution continues, you must make sure that

View File

@ -0,0 +1,6 @@
pragma Singleton
import dumper.Imports 1.0
Imports {
property int something: 2
}

View File

@ -17,7 +17,7 @@ HEADERS += \
imports.h imports.h
!equals(_PRO_FILE_PWD_, $$OUT_PWD) { !equals(_PRO_FILE_PWD_, $$OUT_PWD) {
cp.files = qmldir plugins.qmltypes CompositeImports.qml cp.files = qmldir plugins.qmltypes CompositeImports.qml Derived.qml
cp.path = $$OUT_PWD cp.path = $$OUT_PWD
COPIES += cp COPIES += cp
} }

View File

@ -14,4 +14,14 @@ Module {
exports: ["dumper.Imports/Imports 1.0"] exports: ["dumper.Imports/Imports 1.0"]
exportMetaObjectRevisions: [0] exportMetaObjectRevisions: [0]
} }
Component {
prototype: "Imports"
name: "dumper.Imports/Derived 1.0"
exports: ["dumper.Imports/Derived 1.0"]
exportMetaObjectRevisions: [0]
isComposite: true
isCreatable: false
isSingleton: true
Property { name: "something"; type: "int" }
}
} }

View File

@ -1,3 +1,4 @@
module dumper.Imports module dumper.Imports
plugin Imports plugin Imports
CompositeImports 1.0 CompositeImports.qml CompositeImports 1.0 CompositeImports.qml
singleton Derived 1.0 Derived.qml

View File

@ -0,0 +1,14 @@
import QtQuick 2.11
Item {
visible: true
width: 320
height: 200
property int val: other.val
Rectangle {
id: other
anchors.fill: parent;
property int val: undefined / 2
}
}

View File

@ -56,6 +56,7 @@ private slots:
void bindingOverwriting(); void bindingOverwriting();
void bindToQmlComponent(); void bindToQmlComponent();
void bindingDoesNoWeirdConversion(); void bindingDoesNoWeirdConversion();
void bindNaNToInt();
private: private:
QQmlEngine engine; QQmlEngine engine;
@ -398,6 +399,16 @@ void tst_qqmlbinding::bindingDoesNoWeirdConversion()
QVERIFY(colorLabel); QVERIFY(colorLabel);
} }
//QTBUG-72442
void tst_qqmlbinding::bindNaNToInt()
{
QQmlEngine engine;
QQmlComponent c(&engine, testFileUrl("nanPropertyToInt.qml"));
QScopedPointer<QQuickItem> item(qobject_cast<QQuickItem*>(c.create()));
QVERIFY(item != nullptr);
QCOMPARE(item->property("val").toInt(), 0);
}
QTEST_MAIN(tst_qqmlbinding) QTEST_MAIN(tst_qqmlbinding)
#include "tst_qqmlbinding.moc" #include "tst_qqmlbinding.moc"

View File

@ -32,6 +32,7 @@
#include <QtQuick/qquickview.h> #include <QtQuick/qquickview.h>
#include <QtQuick/qquickitem.h> #include <QtQuick/qquickitem.h>
#include <private/qqmlimport_p.h> #include <private/qqmlimport_p.h>
#include <private/qqmlengine_p.h>
#include "../../shared/util.h" #include "../../shared/util.h"
class tst_QQmlImport : public QQmlDataTest class tst_QQmlImport : public QQmlDataTest
@ -46,6 +47,7 @@ private slots:
void completeQmldirPaths(); void completeQmldirPaths();
void interceptQmldir(); void interceptQmldir();
void singletonVersionResolution(); void singletonVersionResolution();
void removeDynamicPlugin();
void cleanup(); void cleanup();
}; };
@ -260,6 +262,25 @@ void tst_QQmlImport::singletonVersionResolution()
} }
} }
void tst_QQmlImport::removeDynamicPlugin()
{
qmlClearTypeRegistrations();
QQmlEngine engine;
{
// Load something that adds a dynamic plugin
QQmlComponent component(&engine);
component.setData(QByteArray("import QtTest 1.0; TestResult{}"), QUrl());
QVERIFY(component.isReady());
}
QQmlImportDatabase *imports = &QQmlEnginePrivate::get(&engine)->importDatabase;
const QStringList &plugins = imports->dynamicPlugins();
QVERIFY(!plugins.isEmpty());
for (const QString &plugin : plugins)
QVERIFY(imports->removeDynamicPlugin(plugin));
QVERIFY(imports->dynamicPlugins().isEmpty());
qmlClearTypeRegistrations();
}
QTEST_MAIN(tst_QQmlImport) QTEST_MAIN(tst_QQmlImport)

View File

@ -4728,11 +4728,13 @@ static void beginDeferredOnce(QQmlEnginePrivate *enginePriv,
typedef QMultiHash<int, const QV4::CompiledData::Binding *> QV4PropertyBindingHash; typedef QMultiHash<int, const QV4::CompiledData::Binding *> QV4PropertyBindingHash;
auto it = std::reverse_iterator<QV4PropertyBindingHash::iterator>(range.second); auto it = std::reverse_iterator<QV4PropertyBindingHash::iterator>(range.second);
auto last = std::reverse_iterator<QV4PropertyBindingHash::iterator>(range.first); auto last = std::reverse_iterator<QV4PropertyBindingHash::iterator>(range.first);
state->creator->beginPopulateDeferred(deferData->context);
while (it != last) { while (it != last) {
if (!state->creator->populateDeferredBinding(property, deferData, *it)) state->creator->populateDeferredBinding(property, deferData->deferredIdx, *it);
state->errors << state->creator->errors;
++it; ++it;
} }
state->creator->finalizePopulateDeferred();
state->errors << state->creator->errors;
deferredState->constructionStates += state; deferredState->constructionStates += state;

View File

@ -0,0 +1,22 @@
import QtQuick 2.12
Item {
id: root
width: 600
height: 300
TextInput {
id: qwe
objectName: "qwe"
width: 500
height: 100
font.pixelSize: 50
text: "123456"
focus: true
}
Component.onCompleted: {
qwe.insert(0, "***")
qwe.remove(0, 3)
}
}

View File

@ -230,6 +230,7 @@ private slots:
void padding(); void padding();
void QTBUG_51115_readOnlyResetsSelection(); void QTBUG_51115_readOnlyResetsSelection();
void QTBUG_77814_InsertRemoveNoSelection();
private: private:
void simulateKey(QWindow *, int key); void simulateKey(QWindow *, int key);
@ -7003,6 +7004,18 @@ void tst_qquicktextinput::QTBUG_51115_readOnlyResetsSelection()
QCOMPARE(obj->selectedText(), QString()); QCOMPARE(obj->selectedText(), QString());
} }
void tst_qquicktextinput::QTBUG_77814_InsertRemoveNoSelection()
{
QQuickView view;
view.setSource(testFileUrl("qtbug77841.qml"));
view.show();
QVERIFY(QTest::qWaitForWindowExposed(&view));
QQuickTextInput *textInput = view.rootObject()->findChild<QQuickTextInput*>("qwe");
QVERIFY(textInput);
QCOMPARE(textInput->selectedText(), QString());
}
QTEST_MAIN(tst_qquicktextinput) QTEST_MAIN(tst_qquicktextinput)
#include "tst_qquicktextinput.moc" #include "tst_qquicktextinput.moc"

View File

@ -380,23 +380,21 @@ public:
relocatableModuleUri = uri; relocatableModuleUri = uri;
} }
const QString getExportString(QString qmlTyName, int majorVersion, int minorVersion) QString getExportString(const QQmlType &type, const QmlVersionInfo &versionInfo)
{ {
if (qmlTyName.startsWith(relocatableModuleUri + QLatin1Char('/'))) { const QString module = type.module().isEmpty() ? versionInfo.pluginImportUri
qmlTyName.remove(0, relocatableModuleUri.size() + 1); : type.module();
} const int majorVersion = type.majorVersion() >= 0 ? type.majorVersion()
if (qmlTyName.startsWith("./")) { : versionInfo.majorVersion;
qmlTyName.remove(0, 2); const int minorVersion = type.minorVersion() >= 0 ? type.minorVersion()
} : versionInfo.minorVersion;
if (qmlTyName.startsWith(QLatin1Char('/'))) {
qmlTyName.remove(0, 1); const QString versionedElement = type.elementName()
} + QString::fromLatin1(" %1.%2").arg(majorVersion).arg(minorVersion);
const QString exportString = enquote(
QString("%1 %2.%3").arg( return enquote((module == relocatableModuleUri)
qmlTyName, ? versionedElement
QString::number(majorVersion), : module + QLatin1Char('/') + versionedElement);
QString::number(minorVersion)));
return exportString;
} }
void writeMetaContent(const QMetaObject *meta, KnownAttributes *knownAttributes = nullptr) void writeMetaContent(const QMetaObject *meta, KnownAttributes *knownAttributes = nullptr)
@ -441,8 +439,9 @@ public:
} }
} }
QString getPrototypeNameForCompositeType(const QMetaObject *metaObject, QSet<QByteArray> &defaultReachableNames, QString getPrototypeNameForCompositeType(
QList<const QMetaObject *> *objectsToMerge, const QmlVersionInfo &versionInfo) const QMetaObject *metaObject, QList<const QMetaObject *> *objectsToMerge,
const QmlVersionInfo &versionInfo)
{ {
auto ty = QQmlMetaType::qmlType(metaObject); auto ty = QQmlMetaType::qmlType(metaObject);
QString prototypeName; QString prototypeName;
@ -454,24 +453,28 @@ public:
&& !objectsToMerge->contains(metaObject)) && !objectsToMerge->contains(metaObject))
objectsToMerge->append(metaObject); objectsToMerge->append(metaObject);
const QMetaObject *superMetaObject = metaObject->superClass(); const QMetaObject *superMetaObject = metaObject->superClass();
if (!superMetaObject) if (!superMetaObject) {
prototypeName = "QObject"; prototypeName = "QObject";
else } else {
QQmlType superType = QQmlMetaType::qmlType(superMetaObject);
if (superType.isValid() && !superType.isComposite())
return convertToId(superMetaObject->className());
prototypeName = getPrototypeNameForCompositeType( prototypeName = getPrototypeNameForCompositeType(
superMetaObject, defaultReachableNames, objectsToMerge, versionInfo); superMetaObject, objectsToMerge, versionInfo);
}
} else { } else {
prototypeName = convertToId(metaObject->className()); prototypeName = convertToId(metaObject->className());
} }
return prototypeName; return prototypeName;
} }
void dumpComposite(QQmlEngine *engine, const QList<QQmlType> &compositeType, QSet<QByteArray> &defaultReachableNames, const QmlVersionInfo &versionInfo) void dumpComposite(QQmlEngine *engine, const QList<QQmlType> &compositeType, const QmlVersionInfo &versionInfo)
{ {
for (const QQmlType &type : compositeType) for (const QQmlType &type : compositeType)
dumpCompositeItem(engine, type, defaultReachableNames, versionInfo); dumpCompositeItem(engine, type, versionInfo);
} }
void dumpCompositeItem(QQmlEngine *engine, const QQmlType &compositeType, QSet<QByteArray> &defaultReachableNames, const QmlVersionInfo &versionInfo) void dumpCompositeItem(QQmlEngine *engine, const QQmlType &compositeType, const QmlVersionInfo &versionInfo)
{ {
QQmlComponent e(engine, compositeType.sourceUrl()); QQmlComponent e(engine, compositeType.sourceUrl());
if (!e.isReady()) { if (!e.isReady()) {
@ -492,13 +495,17 @@ public:
QList<const QMetaObject *> objectsToMerge; QList<const QMetaObject *> objectsToMerge;
KnownAttributes knownAttributes; KnownAttributes knownAttributes;
// Get C++ base class name for the composite type // Get C++ base class name for the composite type
QString prototypeName = getPrototypeNameForCompositeType(mainMeta, defaultReachableNames, QString prototypeName = getPrototypeNameForCompositeType(mainMeta, &objectsToMerge,
&objectsToMerge, versionInfo); versionInfo);
qml->writeScriptBinding(QLatin1String("prototype"), enquote(prototypeName)); qml->writeScriptBinding(QLatin1String("prototype"), enquote(prototypeName));
QString qmlTyName = compositeType.qmlTypeName(); QString qmlTyName = compositeType.qmlTypeName();
const QString exportString = getExportString(qmlTyName, compositeType.majorVersion(), compositeType.minorVersion()); const QString exportString = getExportString(compositeType, versionInfo);
// TODO: why don't we simply output the compositeType.elementName() here?
// That would make more sense, but it would change the format quite a bit.
qml->writeScriptBinding(QLatin1String("name"), exportString); qml->writeScriptBinding(QLatin1String("name"), exportString);
qml->writeArrayBinding(QLatin1String("exports"), QStringList() << exportString); qml->writeArrayBinding(QLatin1String("exports"), QStringList() << exportString);
qml->writeArrayBinding(QLatin1String("exportMetaObjectRevisions"), QStringList() << QString::number(compositeType.minorVersion())); qml->writeArrayBinding(QLatin1String("exportMetaObjectRevisions"), QStringList() << QString::number(compositeType.minorVersion()));
qml->writeBooleanBinding(QLatin1String("isComposite"), true); qml->writeBooleanBinding(QLatin1String("isComposite"), true);
@ -565,7 +572,7 @@ public:
if (attachedType != meta) if (attachedType != meta)
attachedTypeId = convertToId(attachedType); attachedTypeId = convertToId(attachedType);
} }
const QString exportString = getExportString(type.qmlTypeName(), type.majorVersion(), type.minorVersion()); const QString exportString = getExportString(type, { QString(), -1, -1, false });
int metaObjectRevision = type.metaObjectRevision(); int metaObjectRevision = type.metaObjectRevision();
if (extendedObject) { if (extendedObject) {
// emulate custom metaobjectrevision out of import // emulate custom metaobjectrevision out of import
@ -1239,9 +1246,6 @@ int main(int argc, char *argv[])
QSet<const QMetaObject *> uncreatableMetas; QSet<const QMetaObject *> uncreatableMetas;
QSet<const QMetaObject *> singletonMetas; QSet<const QMetaObject *> singletonMetas;
// QQuickKeyEvent, QQuickPinchEvent, QQuickDropEvent are not exported
QSet<QByteArray> defaultReachableNames;
// this will hold the meta objects we want to dump information of // this will hold the meta objects we want to dump information of
QSet<const QMetaObject *> metas; QSet<const QMetaObject *> metas;
@ -1370,7 +1374,7 @@ int main(int argc, char *argv[])
QMap<QString, QList<QQmlType>>::const_iterator iter = compositeTypes.constBegin(); QMap<QString, QList<QQmlType>>::const_iterator iter = compositeTypes.constBegin();
for (; iter != compositeTypes.constEnd(); ++iter) for (; iter != compositeTypes.constEnd(); ++iter)
dumper.dumpComposite(&engine, iter.value(), defaultReachableNames, info); dumper.dumpComposite(&engine, iter.value(), info);
// define QEasingCurve as an extension of QQmlEasingValueType, this way // define QEasingCurve as an extension of QQmlEasingValueType, this way
// properties using the QEasingCurve type get useful type information. // properties using the QEasingCurve type get useful type information.