diff options
Diffstat (limited to 'src')
36 files changed, 493 insertions, 386 deletions
diff --git a/src/imports/xmllistmodel/qqmlxmllistmodel.cpp b/src/imports/xmllistmodel/qqmlxmllistmodel.cpp index fc9f73a881..a013e8cf69 100644 --- a/src/imports/xmllistmodel/qqmlxmllistmodel.cpp +++ b/src/imports/xmllistmodel/qqmlxmllistmodel.cpp @@ -1152,8 +1152,6 @@ void QQuickXmlListModel::queryCompleted(const QQuickXmlQueryResult &result) int origCount = d->size; bool sizeChanged = result.size != d->size; - d->size = result.size; - d->data = result.data; d->keyRoleResultsCache = result.keyRoleResultsCache; if (d->src.isEmpty() && d->xml.isEmpty()) d->status = Null; @@ -1174,6 +1172,8 @@ void QQuickXmlListModel::queryCompleted(const QQuickXmlQueryResult &result) beginRemoveRows(QModelIndex(), 0, origCount - 1); endRemoveRows(); } + d->size = result.size; + d->data = result.data; if (d->size > 0) { beginInsertRows(QModelIndex(), 0, d->size - 1); endInsertRows(); @@ -1187,6 +1187,8 @@ void QQuickXmlListModel::queryCompleted(const QQuickXmlQueryResult &result) endRemoveRows(); } } + d->size = result.size; + d->data = result.data; for (int i=0; i<result.inserted.count(); i++) { const int index = result.inserted[i].first; const int count = result.inserted[i].second; diff --git a/src/qml/compiler/qv4bytecodegenerator.cpp b/src/qml/compiler/qv4bytecodegenerator.cpp index 05bbf25292..efa4b36f05 100644 --- a/src/qml/compiler/qv4bytecodegenerator.cpp +++ b/src/qml/compiler/qv4bytecodegenerator.cpp @@ -76,14 +76,18 @@ void BytecodeGenerator::packInstruction(I &i) type -= MOTH_NUM_INSTRUCTIONS(); int instructionsAsInts[sizeof(Instr)/sizeof(int)]; int nMembers = Moth::InstrInfo::argumentCount[static_cast<int>(i.type)]; - memcpy(instructionsAsInts, i.packed + 1, nMembers*sizeof(int)); + for (int j = 0; j < nMembers; ++j) { + instructionsAsInts[j] = qFromLittleEndian<qint32>(i.packed + 1 + j * sizeof(int)); + } enum { Normal, Wide } width = Normal; for (int n = 0; n < nMembers; ++n) { - if (width == Normal && (static_cast<char>(instructionsAsInts[n]) != instructionsAsInts[n])) + if (width == Normal && (static_cast<qint8>(instructionsAsInts[n]) != instructionsAsInts[n])) { width = Wide; + break; + } } char *code = i.packed; switch (width) { @@ -91,7 +95,7 @@ void BytecodeGenerator::packInstruction(I &i) *reinterpret_cast<uchar *>(code) = type; ++code; for (int n = 0; n < nMembers; ++n) { - char v = static_cast<char>(instructionsAsInts[n]); + qint8 v = static_cast<qint8>(instructionsAsInts[n]); memcpy(code, &v, 1); code += 1; } @@ -113,17 +117,17 @@ void BytecodeGenerator::adjustJumpOffsets() continue; Q_ASSERT(i.linkedLabel != -1 && labels.at(i.linkedLabel) != -1); const auto &linkedInstruction = instructions.at(labels.at(i.linkedLabel)); - char *c = i.packed + i.offsetForJump; + qint8 *c = reinterpret_cast<qint8*>(i.packed + i.offsetForJump); int jumpOffset = linkedInstruction.position - (i.position + i.size); // qDebug() << "adjusting jump offset for instruction" << index << i.position << i.size << "offsetForJump" << i.offsetForJump << "target" // << labels.at(i.linkedLabel) << linkedInstruction.position << "jumpOffset" << jumpOffset; uchar type = *reinterpret_cast<const uchar *>(i.packed); if (type >= MOTH_NUM_INSTRUCTIONS()) { Q_ASSERT(i.offsetForJump == i.size - 4); - memcpy(c, &jumpOffset, sizeof(int)); + qToLittleEndian<qint32>(jumpOffset, c); } else { Q_ASSERT(i.offsetForJump == i.size - 1); - char o = jumpOffset; + qint8 o = jumpOffset; Q_ASSERT(o == jumpOffset); *c = o; } @@ -196,7 +200,8 @@ QT_WARNING_POP const int pos = instructions.size(); - int s = Moth::InstrInfo::argumentCount[static_cast<int>(type)]*sizeof(int); + const int argCount = Moth::InstrInfo::argumentCount[static_cast<int>(type)]; + int s = argCount*sizeof(int); if (offsetOfOffset != -1) offsetOfOffset += 1; I instr{type, static_cast<short>(s + 1), 0, currentLine, offsetOfOffset, -1, "\0\0" }; @@ -204,7 +209,12 @@ QT_WARNING_POP *reinterpret_cast<uchar *>(code) = static_cast<uchar>(MOTH_NUM_INSTRUCTIONS() + static_cast<int>(type)); ++code; Q_ASSERT(MOTH_NUM_INSTRUCTIONS() + static_cast<int>(type) < 256); - memcpy(code, &i, s); + + for (int j = 0; j < argCount; ++j) { + qToLittleEndian<qint32>(i.argumentsAsInts[j], code); + code += sizeof(int); + } + instructions.append(instr); return pos; diff --git a/src/qml/compiler/qv4instr_moth_p.h b/src/qml/compiler/qv4instr_moth_p.h index a9de71e7ad..eb25aad110 100644 --- a/src/qml/compiler/qv4instr_moth_p.h +++ b/src/qml/compiler/qv4instr_moth_p.h @@ -356,7 +356,7 @@ QT_BEGIN_NAMESPACE nargs, #define MOTH_DECODE_ARG(arg, type, nargs, offset) \ - arg = reinterpret_cast<const type *>(code)[-nargs + offset]; + arg = qFromLittleEndian<type>(reinterpret_cast<const type *>(code)[-nargs + offset]); #define MOTH_ADJUST_CODE(type, nargs) \ code += static_cast<quintptr>(nargs*sizeof(type) + 1) @@ -366,9 +366,9 @@ QT_BEGIN_NAMESPACE MOTH_ADJUST_CODE(int, nargs); \ MOTH_DECODE_ARGS(name, int, nargs, __VA_ARGS__) \ goto op_main_##name; \ - op_char_##name: \ - MOTH_ADJUST_CODE(char, nargs); \ - MOTH_DECODE_ARGS(name, char, nargs, __VA_ARGS__) \ + op_byte_##name: \ + MOTH_ADJUST_CODE(qint8, nargs); \ + MOTH_DECODE_ARGS(name, qint8, nargs, __VA_ARGS__) \ op_main_##name: \ ; \ @@ -380,10 +380,10 @@ QT_BEGIN_NAMESPACE MOTH_ADJUST_CODE(int, nargs); \ MOTH_DECODE_ARGS(name, int, nargs, __VA_ARGS__) \ goto op_main_##name; \ - op_char_##name: \ + op_byte_##name: \ base_ptr = code; \ - MOTH_ADJUST_CODE(char, nargs); \ - MOTH_DECODE_ARGS(name, char, nargs, __VA_ARGS__) \ + MOTH_ADJUST_CODE(qint8, nargs); \ + MOTH_DECODE_ARGS(name, qint8, nargs, __VA_ARGS__) \ op_main_##name: \ ; \ @@ -408,7 +408,7 @@ QT_BEGIN_NAMESPACE #define COLLECT_LABELS(instr) \ INSTR_##instr(GET_LABEL) #define GET_LABEL_INSTRUCTION(name, ...) \ - &&op_char_##name, + &&op_byte_##name, #define COLLECT_LABELS_WIDE(instr) \ INSTR_##instr(GET_LABEL_WIDE) #define GET_LABEL_WIDE_INSTRUCTION(name, ...) \ @@ -428,7 +428,7 @@ QT_BEGIN_NAMESPACE #define MOTH_INSTR_CASE_AND_JUMP(instr) \ INSTR_##instr(GET_CASE_AND_JUMP) #define GET_CASE_AND_JUMP_INSTRUCTION(name, ...) \ - case static_cast<uchar>(Instr::Type::name): goto op_char_##name; + case static_cast<uchar>(Instr::Type::name): goto op_byte_##name; #define MOTH_INSTR_CASE_AND_JUMP_WIDE(instr) \ INSTR_##instr(GET_CASE_AND_JUMP_WIDE) #define GET_CASE_AND_JUMP_WIDE_INSTRUCTION(name, ...) \ @@ -486,6 +486,8 @@ union Instr FOR_EACH_MOTH_INSTR(MOTH_EMIT_STRUCTS) FOR_EACH_MOTH_INSTR(MOTH_EMIT_INSTR_MEMBERS) + + int argumentsAsInts[4]; }; struct InstrInfo diff --git a/src/qml/configure.json b/src/qml/configure.json index a589e9f950..723bd740fc 100644 --- a/src/qml/configure.json +++ b/src/qml/configure.json @@ -24,6 +24,7 @@ "label": "QML network support", "purpose": "Provides network transparency.", "section": "QML", + "condition": "features.network", "output": [ "publicFeature" ] }, "qml-debug": { diff --git a/src/qml/jit/qv4assembler.cpp b/src/qml/jit/qv4assembler.cpp index b0470ed89d..956ee76623 100644 --- a/src/qml/jit/qv4assembler.cpp +++ b/src/qml/jit/qv4assembler.cpp @@ -52,15 +52,6 @@ #undef ENABLE_ALL_ASSEMBLERS_FOR_REFACTORING_PURPOSES -#ifdef Q_STATIC_ASSERT_FOR_SANE_COMPILERS -# undef Q_STATIC_ASSERT_FOR_SANE_COMPILERS -#endif -#if defined(Q_CC_MSVC) && _MSC_VER < 1900 -# define Q_STATIC_ASSERT_FOR_SANE_COMPILERS(x) // insane -#else -# define Q_STATIC_ASSERT_FOR_SANE_COMPILERS(x) Q_STATIC_ASSERT(x) -#endif - #ifdef V4_ENABLE_JIT QT_BEGIN_NAMESPACE @@ -89,6 +80,7 @@ struct PlatformAssembler_X86_64_SysV : JSC::MacroAssembler<JSC::MacroAssemblerX8 static const RegisterID NoRegister = RegisterID(-1); static const RegisterID ReturnValueRegister = RegisterID::eax; + static const RegisterID ReturnValueRegisterValue = ReturnValueRegister; static const RegisterID AccumulatorRegister = RegisterID::eax; static const RegisterID AccumulatorRegisterValue = AccumulatorRegister; static const RegisterID ScratchRegister = RegisterID::r10; @@ -125,7 +117,6 @@ struct PlatformAssembler_X86_64_SysV : JSC::MacroAssembler<JSC::MacroAssemblerX8 push(EngineRegister); move(Arg0Reg, CppStackFrameRegister); move(Arg1Reg, EngineRegister); - loadPtr(Address(CppStackFrameRegister, offsetof(CppStackFrame, jsFrame)), JSStackFrameRegister); } void generatePlatformFunctionExit() @@ -167,6 +158,7 @@ struct PlatformAssembler_Win64 : JSC::MacroAssembler<JSC::MacroAssemblerX86_64> static const RegisterID NoRegister = RegisterID(-1); static const RegisterID ReturnValueRegister = RegisterID::eax; + static const RegisterID ReturnValueRegisterValue = ReturnValueRegister; static const RegisterID AccumulatorRegister = RegisterID::eax; static const RegisterID AccumulatorRegisterValue = AccumulatorRegister; static const RegisterID ScratchRegister = RegisterID::r10; @@ -203,7 +195,6 @@ struct PlatformAssembler_Win64 : JSC::MacroAssembler<JSC::MacroAssemblerX86_64> push(EngineRegister); move(Arg0Reg, CppStackFrameRegister); move(Arg1Reg, EngineRegister); - loadPtr(Address(CppStackFrameRegister, offsetof(CppStackFrame, jsFrame)), JSStackFrameRegister); } void generatePlatformFunctionExit() @@ -285,7 +276,6 @@ struct PlatformAssembler_X86_All : JSC::MacroAssembler<JSC::MacroAssemblerX86> push(EngineRegister); loadPtr(Address(FramePointerRegister, 2 * PointerSize), CppStackFrameRegister); loadPtr(Address(FramePointerRegister, 3 * PointerSize), EngineRegister); - loadPtr(Address(CppStackFrameRegister, offsetof(CppStackFrame, jsFrame)), JSStackFrameRegister); } void generatePlatformFunctionExit() @@ -328,6 +318,7 @@ struct PlatformAssembler_ARM64 : JSC::MacroAssembler<JSC::MacroAssemblerARM64> static const RegisterID NoRegister = RegisterID(-1); static const RegisterID ReturnValueRegister = JSC::ARM64Registers::x0; + static const RegisterID ReturnValueRegisterValue = ReturnValueRegister; static const RegisterID AccumulatorRegister = JSC::ARM64Registers::x9; static const RegisterID AccumulatorRegisterValue = AccumulatorRegister; static const RegisterID ScratchRegister = JSC::ARM64Registers::x10; @@ -689,6 +680,11 @@ struct PlatformAssembler64 : PlatformAssemblerCommon move(TrustedImm64(value), AccumulatorRegister); } + void storeHeapObject(RegisterID source, Address addr) + { + store64(source, addr); + } + void generateCatchTrampoline() { PlatformAssemblerCommon::generateCatchTrampoline([this](){loadUndefined();}); @@ -715,25 +711,66 @@ struct PlatformAssembler64 : PlatformAssemblerCommon void toNumber() { + urshift64(AccumulatorRegister, TrustedImm32(Value::QuickType_Shift), ScratchRegister); + auto isNumber = branch32(GreaterThanOrEqual, ScratchRegister, TrustedImm32(Value::QT_Int)); + move(AccumulatorRegister, registerForArg(0)); callHelper(toNumberHelper); move(ReturnValueRegister, AccumulatorRegister); + + isNumber.link(this); + } + + void toInt32LhsAcc(Address lhs, RegisterID lhsTarget) + { + load64(lhs, lhsTarget); + urshift64(lhsTarget, TrustedImm32(Value::QuickType_Shift), ScratchRegister2); + auto lhsIsInt = branch32(Equal, TrustedImm32(Value::QT_Int), ScratchRegister2); + + pushAligned(AccumulatorRegister); + move(lhsTarget, registerForArg(0)); + callHelper(toInt32Helper); + move(ReturnValueRegister, lhsTarget); + popAligned(AccumulatorRegister); + + lhsIsInt.link(this); + urshift64(AccumulatorRegister, TrustedImm32(Value::QuickType_Shift), ScratchRegister2); + auto isInt = branch32(Equal, TrustedImm32(Value::QT_Int), ScratchRegister2); + + pushAligned(lhsTarget); + move(AccumulatorRegister, registerForArg(0)); + callHelper(toInt32Helper); + move(ReturnValueRegister, AccumulatorRegister); + popAligned(lhsTarget); + + isInt.link(this); } void toInt32() { + urshift64(AccumulatorRegister, TrustedImm32(Value::QuickType_Shift), ScratchRegister2); + auto isInt = branch32(Equal, TrustedImm32(Value::QT_Int), ScratchRegister2); + move(AccumulatorRegister, registerForArg(0)); callRuntime("toInt32Helper", reinterpret_cast<void *>(&toInt32Helper), Assembler::ResultInAccumulator); + + isInt.link(this); } void regToInt32(Address srcReg, RegisterID targetReg) { + load64(srcReg, targetReg); + urshift64(targetReg, TrustedImm32(Value::QuickType_Shift), ScratchRegister2); + auto isInt = branch32(Equal, TrustedImm32(Value::QT_Int), ScratchRegister2); + pushAligned(AccumulatorRegister); - load64(srcReg, registerForArg(0)); + move(targetReg, registerForArg(0)); callHelper(toInt32Helper); move(ReturnValueRegister, targetReg); popAligned(AccumulatorRegister); + + isInt.link(this); } void isNullOrUndefined() @@ -750,6 +787,12 @@ struct PlatformAssembler64 : PlatformAssemblerCommon isUndef.link(this); } + Jump isIntOrBool() + { + urshift64(AccumulatorRegister, TrustedImm32(Value::IsIntegerOrBool_Shift), ScratchRegister); + return branch32(Equal, TrustedImm32(3), ScratchRegister); + } + void jumpStrictEqualStackSlotInt(int lhs, int rhs, int offset) { Address lhsAddr(JSStackFrameRegister, lhs * int(sizeof(Value))); @@ -909,6 +952,14 @@ struct PlatformAssembler32 : PlatformAssemblerCommon move(TrustedImm32(Value::fromReturnedValue(value).tag()), AccumulatorRegisterTag); } + void storeHeapObject(RegisterID source, Address addr) + { + store32(source, addr); + addr.offset += 4; + store32(TrustedImm32(0), addr); + } + + void generateCatchTrampoline() { PlatformAssemblerCommon::generateCatchTrampoline([this](){loadUndefined();}); @@ -916,6 +967,9 @@ struct PlatformAssembler32 : PlatformAssemblerCommon void toNumber() { + urshift32(AccumulatorRegisterTag, TrustedImm32(Value::QuickType_Shift - 32), ScratchRegister); + auto isNumber = branch32(GreaterThanOrEqual, ScratchRegister, TrustedImm32(Value::QT_Int)); + if (ArgInRegCount < 2) { push(AccumulatorRegisterTag); push(AccumulatorRegisterValue); @@ -929,10 +983,68 @@ struct PlatformAssembler32 : PlatformAssemblerCommon move(ReturnValueRegisterTag, AccumulatorRegisterTag); if (ArgInRegCount < 2) addPtr(TrustedImm32(2 * PointerSize), StackPointerRegister); + + isNumber.link(this); + } + + void toInt32LhsAcc(Address lhs, RegisterID lhsTarget) + { + bool accumulatorNeedsSaving = AccumulatorRegisterValue == ReturnValueRegisterValue + || AccumulatorRegisterTag == ReturnValueRegisterTag; + lhs.offset += 4; + load32(lhs, lhsTarget); + lhs.offset -= 4; + auto lhsIsNotInt = branch32(NotEqual, TrustedImm32(int(IntegerTag)), lhsTarget); + load32(lhs, lhsTarget); + auto lhsIsInt = jump(); + + lhsIsNotInt.link(this); + if (accumulatorNeedsSaving) { + push(AccumulatorRegisterTag); + push(AccumulatorRegisterValue); + } + if (ArgInRegCount < 2) { + push(lhsTarget); + load32(lhs, lhsTarget); + push(lhsTarget); + } else { + move(lhsTarget, registerForArg(1)); + load32(lhs, registerForArg(0)); + } + callHelper(toInt32Helper); + move(ReturnValueRegisterValue, lhsTarget); + if (ArgInRegCount < 2) + addPtr(TrustedImm32(2 * PointerSize), StackPointerRegister); + if (accumulatorNeedsSaving) { + pop(AccumulatorRegisterValue); + pop(AccumulatorRegisterTag); + } + lhsIsInt.link(this); + + auto rhsIsInt = branch32(Equal, TrustedImm32(int(IntegerTag)), AccumulatorRegisterTag); + + pushAligned(lhsTarget); + if (ArgInRegCount < 2) { + push(AccumulatorRegisterTag); + push(AccumulatorRegisterValue); + } else { + move(AccumulatorRegisterValue, registerForArg(0)); + move(AccumulatorRegisterTag, registerForArg(1)); + } + callRuntime("toInt32Helper", reinterpret_cast<void *>(&toInt32Helper), + Assembler::ResultInAccumulator); + if (ArgInRegCount < 2) + addPtr(TrustedImm32(2 * PointerSize), StackPointerRegister); + popAligned(lhsTarget); + + rhsIsInt.link(this); } void toInt32() { + urshift32(AccumulatorRegisterTag, TrustedImm32(Value::QuickType_Shift - 32), ScratchRegister); + auto isInt = branch32(Equal, TrustedImm32(Value::QT_Int), ScratchRegister); + if (ArgInRegCount < 2) { push(AccumulatorRegisterTag); push(AccumulatorRegisterValue); @@ -944,6 +1056,8 @@ struct PlatformAssembler32 : PlatformAssemblerCommon Assembler::ResultInAccumulator); if (ArgInRegCount < 2) addPtr(TrustedImm32(2 * PointerSize), StackPointerRegister); + + isInt.link(this); } void regToInt32(Address srcReg, RegisterID targetReg) @@ -990,6 +1104,12 @@ struct PlatformAssembler32 : PlatformAssemblerCommon done.link(this); } + Jump isIntOrBool() + { + urshift32(AccumulatorRegisterTag, TrustedImm32(Value::IsIntegerOrBool_Shift - 32), ScratchRegister); + return branch32(Equal, TrustedImm32(3), ScratchRegister); + } + void pushValue(ReturnedValue v) { push(TrustedImm32(v >> 32)); @@ -1321,6 +1441,11 @@ void Assembler::loadValue(ReturnedValue value) pasm()->loadValue(value); } +void JIT::Assembler::storeHeapObject(int reg) +{ + pasm()->storeHeapObject(PlatformAssembler::ReturnValueRegisterValue, regAddr(reg)); +} + void Assembler::toNumber() { pasm()->toNumber(); @@ -1432,10 +1557,7 @@ void Assembler::add(int lhs) void Assembler::bitAnd(int lhs) { PlatformAssembler::Address lhsAddr = regAddr(lhs); - pasm()->regToInt32(lhsAddr, PlatformAssembler::ScratchRegister); - pasm()->pushAligned(PlatformAssembler::ScratchRegister); - pasm()->toInt32(); - pasm()->popAligned(PlatformAssembler::ScratchRegister); + pasm()->toInt32LhsAcc(lhsAddr, PlatformAssembler::ScratchRegister); pasm()->and32(PlatformAssembler::ScratchRegister, PlatformAssembler::AccumulatorRegisterValue); pasm()->setAccumulatorTag(IntegerTag); } @@ -1443,10 +1565,7 @@ void Assembler::bitAnd(int lhs) void Assembler::bitOr(int lhs) { PlatformAssembler::Address lhsAddr = regAddr(lhs); - pasm()->regToInt32(lhsAddr, PlatformAssembler::ScratchRegister); - pasm()->pushAligned(PlatformAssembler::ScratchRegister); - pasm()->toInt32(); - pasm()->popAligned(PlatformAssembler::ScratchRegister); + pasm()->toInt32LhsAcc(lhsAddr, PlatformAssembler::ScratchRegister); pasm()->or32(PlatformAssembler::ScratchRegister, PlatformAssembler::AccumulatorRegisterValue); pasm()->setAccumulatorTag(IntegerTag); } @@ -1454,10 +1573,7 @@ void Assembler::bitOr(int lhs) void Assembler::bitXor(int lhs) { PlatformAssembler::Address lhsAddr = regAddr(lhs); - pasm()->regToInt32(lhsAddr, PlatformAssembler::ScratchRegister); - pasm()->pushAligned(PlatformAssembler::ScratchRegister); - pasm()->toInt32(); - pasm()->popAligned(PlatformAssembler::ScratchRegister); + pasm()->toInt32LhsAcc(lhsAddr, PlatformAssembler::ScratchRegister); pasm()->xor32(PlatformAssembler::ScratchRegister, PlatformAssembler::AccumulatorRegisterValue); pasm()->setAccumulatorTag(IntegerTag); } @@ -1465,13 +1581,10 @@ void Assembler::bitXor(int lhs) void Assembler::ushr(int lhs) { PlatformAssembler::Address lhsAddr = regAddr(lhs); - pasm()->regToInt32(lhsAddr, PlatformAssembler::ScratchRegister); - pasm()->pushAligned(PlatformAssembler::ScratchRegister); - pasm()->toInt32(); - pasm()->and32(TrustedImm32(0x1f), PlatformAssembler::AccumulatorRegisterValue, - PlatformAssembler::ScratchRegister); - pasm()->popAligned(PlatformAssembler::AccumulatorRegisterValue); - pasm()->urshift32(PlatformAssembler::ScratchRegister, PlatformAssembler::AccumulatorRegisterValue); + pasm()->toInt32LhsAcc(lhsAddr, PlatformAssembler::ScratchRegister); + pasm()->and32(TrustedImm32(0x1f), PlatformAssembler::AccumulatorRegisterValue); + pasm()->urshift32(PlatformAssembler::AccumulatorRegisterValue, PlatformAssembler::ScratchRegister); + pasm()->move(PlatformAssembler::ScratchRegister, PlatformAssembler::AccumulatorRegisterValue); auto doubleEncode = pasm()->branch32(PlatformAssembler::LessThan, PlatformAssembler::AccumulatorRegisterValue, TrustedImm32(0)); @@ -1489,26 +1602,20 @@ void Assembler::ushr(int lhs) void Assembler::shr(int lhs) { PlatformAssembler::Address lhsAddr = regAddr(lhs); - pasm()->regToInt32(lhsAddr, PlatformAssembler::ScratchRegister); - pasm()->pushAligned(PlatformAssembler::ScratchRegister); - pasm()->toInt32(); - pasm()->and32(TrustedImm32(0x1f), PlatformAssembler::AccumulatorRegisterValue, - PlatformAssembler::ScratchRegister); - pasm()->popAligned(PlatformAssembler::AccumulatorRegisterValue); - pasm()->rshift32(PlatformAssembler::ScratchRegister, PlatformAssembler::AccumulatorRegisterValue); + pasm()->toInt32LhsAcc(lhsAddr, PlatformAssembler::ScratchRegister); + pasm()->and32(TrustedImm32(0x1f), PlatformAssembler::AccumulatorRegisterValue); + pasm()->rshift32(PlatformAssembler::AccumulatorRegisterValue, PlatformAssembler::ScratchRegister); + pasm()->move(PlatformAssembler::ScratchRegister, PlatformAssembler::AccumulatorRegisterValue); pasm()->setAccumulatorTag(IntegerTag); } void Assembler::shl(int lhs) { PlatformAssembler::Address lhsAddr = regAddr(lhs); - pasm()->regToInt32(lhsAddr, PlatformAssembler::ScratchRegister); - pasm()->pushAligned(PlatformAssembler::ScratchRegister); - pasm()->toInt32(); - pasm()->and32(TrustedImm32(0x1f), PlatformAssembler::AccumulatorRegisterValue, - PlatformAssembler::ScratchRegister); - pasm()->popAligned(PlatformAssembler::AccumulatorRegisterValue); - pasm()->lshift32(PlatformAssembler::ScratchRegister, PlatformAssembler::AccumulatorRegisterValue); + pasm()->toInt32LhsAcc(lhsAddr, PlatformAssembler::ScratchRegister); + pasm()->and32(TrustedImm32(0x1f), PlatformAssembler::AccumulatorRegisterValue); + pasm()->lshift32(PlatformAssembler::AccumulatorRegisterValue, PlatformAssembler::ScratchRegister); + pasm()->move(PlatformAssembler::ScratchRegister, PlatformAssembler::AccumulatorRegisterValue); pasm()->setAccumulatorTag(IntegerTag); } @@ -1537,27 +1644,32 @@ void Assembler::ushrConst(int rhs) { rhs &= 0x1f; pasm()->toInt32(); - if (rhs) // shift with 0 can act weird + if (rhs) { + // a non zero shift will always give a number encodable as an int pasm()->urshift32(TrustedImm32(rhs), PlatformAssembler::AccumulatorRegisterValue); - auto doubleEncode = pasm()->branch32(PlatformAssembler::LessThan, - PlatformAssembler::AccumulatorRegisterValue, - TrustedImm32(0)); - pasm()->setAccumulatorTag(IntegerTag); - auto done = pasm()->jump(); + pasm()->setAccumulatorTag(IntegerTag); + } else { + // shift with 0 can lead to a negative result + auto doubleEncode = pasm()->branch32(PlatformAssembler::LessThan, + PlatformAssembler::AccumulatorRegisterValue, + TrustedImm32(0)); + pasm()->setAccumulatorTag(IntegerTag); + auto done = pasm()->jump(); - doubleEncode.link(pasm()); - pasm()->convertUInt32ToDouble(PlatformAssembler::AccumulatorRegisterValue, - PlatformAssembler::FPScratchRegister, - PlatformAssembler::ScratchRegister); - pasm()->encodeDoubleIntoAccumulator(PlatformAssembler::FPScratchRegister); - done.link(pasm()); + doubleEncode.link(pasm()); + pasm()->convertUInt32ToDouble(PlatformAssembler::AccumulatorRegisterValue, + PlatformAssembler::FPScratchRegister, + PlatformAssembler::ScratchRegister); + pasm()->encodeDoubleIntoAccumulator(PlatformAssembler::FPScratchRegister); + done.link(pasm()); + } } void Assembler::shrConst(int rhs) { rhs &= 0x1f; pasm()->toInt32(); - if (rhs) // shift with 0 can act weird + if (rhs) pasm()->rshift32(TrustedImm32(rhs), PlatformAssembler::AccumulatorRegisterValue); pasm()->setAccumulatorTag(IntegerTag); } @@ -1566,7 +1678,7 @@ void Assembler::shlConst(int rhs) { rhs &= 0x1f; pasm()->toInt32(); - if (rhs) // shift with 0 can act weird + if (rhs) pasm()->lshift32(TrustedImm32(rhs), PlatformAssembler::AccumulatorRegisterValue); pasm()->setAccumulatorTag(IntegerTag); } @@ -1652,6 +1764,7 @@ void Assembler::cmpneNull() void Assembler::cmpeqInt(int lhs) { + auto isIntOrBool = pasm()->isIntOrBool(); saveAccumulatorInFrame(); pasm()->pushValueAligned(Encode(lhs)); if (PlatformAssembler::ArgInRegCount < 2) @@ -1663,10 +1776,18 @@ void Assembler::cmpeqInt(int lhs) if (PlatformAssembler::ArgInRegCount < 2) pasm()->addPtr(TrustedImm32(2 * PlatformAssembler::PointerSize), PlatformAssembler::StackPointerRegister); pasm()->popValueAligned(); + auto done = pasm()->jump(); + isIntOrBool.link(pasm()); + pasm()->compare32(PlatformAssembler::Equal, PlatformAssembler::AccumulatorRegisterValue, + TrustedImm32(lhs), + PlatformAssembler::AccumulatorRegisterValue); + pasm()->setAccumulatorTag(QV4::Value::ValueTypeInternal::Boolean); + done.link(pasm()); } void Assembler::cmpneInt(int lhs) { + auto isIntOrBool = pasm()->isIntOrBool(); saveAccumulatorInFrame(); pasm()->pushValueAligned(Encode(lhs)); if (PlatformAssembler::ArgInRegCount < 2) @@ -1678,6 +1799,13 @@ void Assembler::cmpneInt(int lhs) if (PlatformAssembler::ArgInRegCount < 2) pasm()->addPtr(TrustedImm32(2 * PlatformAssembler::PointerSize), PlatformAssembler::StackPointerRegister); pasm()->popValueAligned(); + auto done = pasm()->jump(); + isIntOrBool.link(pasm()); + pasm()->compare32(PlatformAssembler::NotEqual, PlatformAssembler::AccumulatorRegisterValue, + TrustedImm32(lhs), + PlatformAssembler::AccumulatorRegisterValue); + pasm()->setAccumulatorTag(QV4::Value::ValueTypeInternal::Boolean); + done.link(pasm()); } void Assembler::cmp(int cond, CmpFunc function, const char *functionName, int lhs) @@ -1956,7 +2084,7 @@ void Assembler::gotoCatchException() void Assembler::getException() { - Q_STATIC_ASSERT_FOR_SANE_COMPILERS(sizeof(QV4::EngineBase::hasException) == 1); + Q_STATIC_ASSERT(sizeof(QV4::EngineBase::hasException) == 1); Address hasExceptionAddr(PlatformAssembler::EngineRegister, offsetof(EngineBase, hasException)); @@ -1981,7 +2109,7 @@ void Assembler::setException() pasm()->loadPtr(addr, PlatformAssembler::ScratchRegister); pasm()->storeAccumulator(Address(PlatformAssembler::ScratchRegister)); addr.offset = offsetof(EngineBase, hasException); - Q_STATIC_ASSERT_FOR_SANE_COMPILERS(sizeof(QV4::EngineBase::hasException) == 1); + Q_STATIC_ASSERT(sizeof(QV4::EngineBase::hasException) == 1); pasm()->store8(TrustedImm32(1), addr); } diff --git a/src/qml/jit/qv4assembler_p.h b/src/qml/jit/qv4assembler_p.h index 5cd64096b1..37d4232a17 100644 --- a/src/qml/jit/qv4assembler_p.h +++ b/src/qml/jit/qv4assembler_p.h @@ -95,6 +95,7 @@ public: void storeLocal(int index, int level = 0); void loadString(int stringId); void loadValue(ReturnedValue value); + void storeHeapObject(int reg); // numeric ops void unot(); diff --git a/src/qml/jit/qv4jit.cpp b/src/qml/jit/qv4jit.cpp index 42ee1ff5df..1ab45d6765 100644 --- a/src/qml/jit/qv4jit.cpp +++ b/src/qml/jit/qv4jit.cpp @@ -570,17 +570,12 @@ void BaselineJIT::generate_ThrowException() void BaselineJIT::generate_GetException() { as->getException(); } void BaselineJIT::generate_SetException() { as->setException(); } -static void createCallContextHelper(Value *stack, CppStackFrame *frame) -{ - stack[CallData::Context] = ExecutionContext::newCallContext(frame); -} - void BaselineJIT::generate_CreateCallContext() { - as->prepareCallWithArgCount(2); - as->passCppFrameAsArg(1); - as->passRegAsArg(0, 0); - JIT_GENERATE_RUNTIME_CALL(createCallContextHelper, Assembler::IgnoreResult); + as->prepareCallWithArgCount(1); + as->passCppFrameAsArg(0); + JIT_GENERATE_RUNTIME_CALL(ExecutionContext::newCallContext, Assembler::IgnoreResult); // keeps result in return value register + as->storeHeapObject(CallData::Context); } void BaselineJIT::generate_PushCatchContext(int name, int reg) { as->pushCatchContext(name, reg); } @@ -951,6 +946,11 @@ void BaselineJIT::collectLabelsInBytecode() { MOTH_JUMP_TABLE; + const auto addLabel = [&](int offset) { + Q_ASSERT(offset >= 0 && offset < static_cast<int>(function->compiledFunction->codeSize)); + labels.push_back(offset); + }; + const char *code = reinterpret_cast<const char *>(function->codeData); const char *start = code; const char *end = code + function->compiledFunction->codeSize; @@ -1088,7 +1088,7 @@ void BaselineJIT::collectLabelsInBytecode() MOTH_END_INSTR(CallGlobalLookup) MOTH_BEGIN_INSTR(SetExceptionHandler) - labels.push_back(code - start + offset); + addLabel(code - start + offset); MOTH_END_INSTR(SetExceptionHandler) MOTH_BEGIN_INSTR(ThrowException) @@ -1155,15 +1155,15 @@ void BaselineJIT::collectLabelsInBytecode() MOTH_END_INSTR(Construct) MOTH_BEGIN_INSTR(Jump) - labels.push_back(code - start + offset); + addLabel(code - start + offset); MOTH_END_INSTR(Jump) MOTH_BEGIN_INSTR(JumpTrue) - labels.push_back(code - start + offset); + addLabel(code - start + offset); MOTH_END_INSTR(JumpTrue) MOTH_BEGIN_INSTR(JumpFalse) - labels.push_back(code - start + offset); + addLabel(code - start + offset); MOTH_END_INSTR(JumpFalse) MOTH_BEGIN_INSTR(CmpEqNull) @@ -1209,11 +1209,11 @@ void BaselineJIT::collectLabelsInBytecode() MOTH_END_INSTR(CmpInstanceOf) MOTH_BEGIN_INSTR(JumpStrictEqualStackSlotInt) - labels.push_back(code - start + offset); + addLabel(code - start + offset); MOTH_END_INSTR(JumpStrictEqualStackSlotInt) MOTH_BEGIN_INSTR(JumpStrictNotEqualStackSlotInt) - labels.push_back(code - start + offset); + addLabel(code - start + offset); MOTH_END_INSTR(JumpStrictNotEqualStackSlotInt) MOTH_BEGIN_INSTR(UNot) diff --git a/src/qml/jsruntime/qv4arraydata_p.h b/src/qml/jsruntime/qv4arraydata_p.h index db9db5a220..46986c5e6f 100644 --- a/src/qml/jsruntime/qv4arraydata_p.h +++ b/src/qml/jsruntime/qv4arraydata_p.h @@ -142,7 +142,7 @@ DECLARE_HEAP_OBJECT(ArrayData, Base) { uint mappedIndex(uint index) const; }; -V4_ASSERT_IS_TRIVIAL(ArrayData) +Q_STATIC_ASSERT(std::is_trivial< ArrayData >::value); struct SimpleArrayData : public ArrayData { uint mappedIndex(uint index) const { index += offset; if (index >= values.alloc) index -= values.alloc; return index; } @@ -157,7 +157,7 @@ struct SimpleArrayData : public ArrayData { return attrs ? attrs[i] : Attr_Data; } }; -V4_ASSERT_IS_TRIVIAL(SimpleArrayData) +Q_STATIC_ASSERT(std::is_trivial< SimpleArrayData >::value); struct SparseArrayData : public ArrayData { void destroy() { diff --git a/src/qml/jsruntime/qv4context_p.h b/src/qml/jsruntime/qv4context_p.h index 4efd0bc899..dfac5534be 100644 --- a/src/qml/jsruntime/qv4context_p.h +++ b/src/qml/jsruntime/qv4context_p.h @@ -143,7 +143,7 @@ DECLARE_HEAP_OBJECT(ExecutionContext, Base) { quint8 padding_[4]; #endif }; -V4_ASSERT_IS_TRIVIAL(ExecutionContext) +Q_STATIC_ASSERT(std::is_trivial< ExecutionContext >::value); Q_STATIC_ASSERT(sizeof(ExecutionContext) == sizeof(Base) + sizeof(ExecutionContextData) + QT_POINTER_SIZE); Q_STATIC_ASSERT(std::is_standard_layout<ExecutionContextData>::value); @@ -170,7 +170,7 @@ DECLARE_HEAP_OBJECT(CallContext, ExecutionContext) { } void setArg(uint index, Value v); }; -V4_ASSERT_IS_TRIVIAL(CallContext) +Q_STATIC_ASSERT(std::is_trivial< CallContext >::value); Q_STATIC_ASSERT(std::is_standard_layout<CallContextData>::value); Q_STATIC_ASSERT(offsetof(CallContextData, function) == 0); //### The following size check fails on Win8. With the ValueArray at the end of the @@ -190,7 +190,7 @@ DECLARE_HEAP_OBJECT(CatchContext, ExecutionContext) { void init(ExecutionContext *outerContext, String *exceptionVarName, const Value &exceptionValue); }; -V4_ASSERT_IS_TRIVIAL(CatchContext) +Q_STATIC_ASSERT(std::is_trivial< CatchContext >::value); } diff --git a/src/qml/jsruntime/qv4dateobject.cpp b/src/qml/jsruntime/qv4dateobject.cpp index b8392d27e9..d56db80c3f 100644 --- a/src/qml/jsruntime/qv4dateobject.cpp +++ b/src/qml/jsruntime/qv4dateobject.cpp @@ -328,7 +328,7 @@ static inline double DaylightSavingTA(double t) // t is a UTC time static inline double DaylightSavingTA(double t) { struct tm tmtm; -#if defined(_MSC_VER) && _MSC_VER >= 1400 +#if defined(Q_CC_MSVC) __time64_t tt = (__time64_t)(t / msPerSecond); // _localtime_64_s returns non-zero on failure if (_localtime64_s(&tmtm, &tt) != 0) diff --git a/src/qml/jsruntime/qv4global_p.h b/src/qml/jsruntime/qv4global_p.h index 090a164ef6..07c88a2814 100644 --- a/src/qml/jsruntime/qv4global_p.h +++ b/src/qml/jsruntime/qv4global_p.h @@ -76,9 +76,6 @@ namespace std { inline bool isinf(double d) { return !_finite(d) && !_isnan(d); } inline bool isnan(double d) { return !!_isnan(d); } inline bool isfinite(double d) { return _finite(d); } -#if _MSC_VER < 1800 -inline bool signbit(double d) { return _copysign(1.0, d) < 0; } -#endif } // namespace std diff --git a/src/qml/jsruntime/qv4managed_p.h b/src/qml/jsruntime/qv4managed_p.h index f81dcf9479..092c61b81c 100644 --- a/src/qml/jsruntime/qv4managed_p.h +++ b/src/qml/jsruntime/qv4managed_p.h @@ -93,7 +93,7 @@ inline void qYouForgotTheQ_MANAGED_Macro(T1, T2) {} dptr->_checkIsInitialized(); \ return dptr; \ } \ - V4_ASSERT_IS_TRIVIAL(QV4::Heap::DataClass) + Q_STATIC_ASSERT(std::is_trivial< QV4::Heap::DataClass >::value); #define V4_MANAGED(DataClass, superClass) \ private: \ diff --git a/src/qml/jsruntime/qv4memberdata_p.h b/src/qml/jsruntime/qv4memberdata_p.h index 3e231d693b..7345790ac3 100644 --- a/src/qml/jsruntime/qv4memberdata_p.h +++ b/src/qml/jsruntime/qv4memberdata_p.h @@ -65,7 +65,7 @@ namespace Heap { DECLARE_HEAP_OBJECT(MemberData, Base) { DECLARE_MARKOBJECTS(MemberData); }; -V4_ASSERT_IS_TRIVIAL(MemberData) +Q_STATIC_ASSERT(std::is_trivial< MemberData >::value); } diff --git a/src/qml/jsruntime/qv4object_p.h b/src/qml/jsruntime/qv4object_p.h index 66177617f7..60012822d8 100644 --- a/src/qml/jsruntime/qv4object_p.h +++ b/src/qml/jsruntime/qv4object_p.h @@ -153,7 +153,7 @@ DECLARE_EXPORTED_HEAP_OBJECT(Object, Base) { dptr->_checkIsInitialized(); \ return dptr; \ } \ - V4_ASSERT_IS_TRIVIAL(QV4::Heap::DataClass); + Q_STATIC_ASSERT(std::is_trivial< QV4::Heap::DataClass >::value); #define V4_PROTOTYPE(p) \ static QV4::Object *defaultPrototype(QV4::ExecutionEngine *e) \ diff --git a/src/qml/jsruntime/qv4objectiterator_p.h b/src/qml/jsruntime/qv4objectiterator_p.h index 30a6ad3025..3e501f23ce 100644 --- a/src/qml/jsruntime/qv4objectiterator_p.h +++ b/src/qml/jsruntime/qv4objectiterator_p.h @@ -73,7 +73,7 @@ struct Q_QML_EXPORT ObjectIteratorData uint memberIndex; uint flags; }; -V4_ASSERT_IS_TRIVIAL(ObjectIteratorData) +Q_STATIC_ASSERT(std::is_trivial< ObjectIteratorData >::value); struct Q_QML_EXPORT ObjectIterator: ObjectIteratorData { diff --git a/src/qml/jsruntime/qv4regexp_p.h b/src/qml/jsruntime/qv4regexp_p.h index 498468e165..94bebbd931 100644 --- a/src/qml/jsruntime/qv4regexp_p.h +++ b/src/qml/jsruntime/qv4regexp_p.h @@ -100,7 +100,7 @@ struct RegExp : Base { int captureCount() const { return subPatternCount + 1; } }; -V4_ASSERT_IS_TRIVIAL(RegExp) +Q_STATIC_ASSERT(std::is_trivial< RegExp >::value); } diff --git a/src/qml/jsruntime/qv4runtime.cpp b/src/qml/jsruntime/qv4runtime.cpp index 240fba7905..93d538127b 100644 --- a/src/qml/jsruntime/qv4runtime.cpp +++ b/src/qml/jsruntime/qv4runtime.cpp @@ -604,6 +604,14 @@ static Q_NEVER_INLINE ReturnedValue getElementFallback(ExecutionEngine *engine, return o->get(name); } +/* load element: + + Managed *m = object.heapObject(); + if (m) + return m->internalClass->getIndexed(m, index); + return getIndexedFallback(object, index); +*/ + ReturnedValue Runtime::method_loadElement(ExecutionEngine *engine, const Value &object, const Value &index) { uint idx = 0; diff --git a/src/qml/jsruntime/qv4string_p.h b/src/qml/jsruntime/qv4string_p.h index 85345aca4d..9053d9d48f 100644 --- a/src/qml/jsruntime/qv4string_p.h +++ b/src/qml/jsruntime/qv4string_p.h @@ -131,7 +131,7 @@ private: static void append(const String *data, QChar *ch); #endif }; -V4_ASSERT_IS_TRIVIAL(String) +Q_STATIC_ASSERT(std::is_trivial< String >::value); } diff --git a/src/qml/jsruntime/qv4value_p.h b/src/qml/jsruntime/qv4value_p.h index 52d9f23afd..a0495cca61 100644 --- a/src/qml/jsruntime/qv4value_p.h +++ b/src/qml/jsruntime/qv4value_p.h @@ -483,7 +483,7 @@ public: template<typename T> Value &operator=(const Scoped<T> &t); }; -V4_ASSERT_IS_TRIVIAL(Value) +Q_STATIC_ASSERT(std::is_trivial< Value >::value); inline void Value::mark(MarkStack *markStack) { diff --git a/src/qml/jsruntime/qv4vme_moth.cpp b/src/qml/jsruntime/qv4vme_moth.cpp index 6956112718..91558ba103 100644 --- a/src/qml/jsruntime/qv4vme_moth.cpp +++ b/src/qml/jsruntime/qv4vme_moth.cpp @@ -1142,14 +1142,13 @@ QV4::ReturnedValue VME::exec(const FunctionObject *fo, const Value *thisObject, MOTH_BEGIN_INSTR(CmpInstanceOf) // 11.8.6, 5: rval must be an Object - const Object *rhs = Primitive::fromReturnedValue(acc).as<Object>(); - if (Q_UNLIKELY(!rhs)) { + if (Q_UNLIKELY(!Primitive::fromReturnedValue(acc).isObject())) { acc = engine->throwTypeError(); goto catchException; } // 11.8.6, 7: call "HasInstance", which we term instanceOf, and return the result. - acc = rhs->instanceOf(STACK_VALUE(lhs)); + acc = Primitive::fromReturnedValue(acc).objectValue()->instanceOf(STACK_VALUE(lhs)); CHECK_EXCEPTION; MOTH_END_INSTR(CmpInstanceOf) diff --git a/src/qml/memory/qv4heap_p.h b/src/qml/memory/qv4heap_p.h index 363e891d5c..7bc841b21d 100644 --- a/src/qml/memory/qv4heap_p.h +++ b/src/qml/memory/qv4heap_p.h @@ -60,12 +60,6 @@ // parent's init all up the inheritance chain), define QML_CHECK_INIT_DESTROY_CALLS below. #undef QML_CHECK_INIT_DESTROY_CALLS -#if defined(_MSC_VER) && (_MSC_VER < 1900) // broken compilers: -# define V4_ASSERT_IS_TRIVIAL(x) -#else // working compilers: -# define V4_ASSERT_IS_TRIVIAL(x) Q_STATIC_ASSERT(std::is_trivial< x >::value); -#endif - QT_BEGIN_NAMESPACE namespace QV4 { @@ -175,7 +169,7 @@ struct Q_QML_EXPORT Base { Q_ALWAYS_INLINE void _setDestroyed() {} #endif }; -V4_ASSERT_IS_TRIVIAL(Base) +Q_STATIC_ASSERT(std::is_trivial< Base >::value); // This class needs to consist only of pointer sized members to allow // for a size/offset translation when cross-compiling between 32- and // 64-bit. @@ -253,7 +247,7 @@ private: QtSharedPointer::ExternalRefCountData *d; QObject *qObject; }; -V4_ASSERT_IS_TRIVIAL(QQmlQPointer<QObject>) +Q_STATIC_ASSERT(std::is_trivial< QQmlQPointer<QObject> >::value); #endif } diff --git a/src/qml/memory/qv4mm_p.h b/src/qml/memory/qv4mm_p.h index 921fea3956..f7c50ff3cf 100644 --- a/src/qml/memory/qv4mm_p.h +++ b/src/qml/memory/qv4mm_p.h @@ -169,7 +169,7 @@ public: template<typename ManagedType> inline typename ManagedType::Data *allocManaged(std::size_t size) { - V4_ASSERT_IS_TRIVIAL(typename ManagedType::Data) + Q_STATIC_ASSERT(std::is_trivial< typename ManagedType::Data >::value); size = align(size); Heap::Base *o = allocData(size); InternalClass *ic = ManagedType::defaultInternalClass(engine); @@ -182,7 +182,7 @@ public: template<typename ManagedType> inline typename ManagedType::Data *allocManaged(std::size_t size, InternalClass *ic) { - V4_ASSERT_IS_TRIVIAL(typename ManagedType::Data) + Q_STATIC_ASSERT(std::is_trivial< typename ManagedType::Data >::value); size = align(size); Heap::Base *o = allocData(size); o->internalClass = ic; diff --git a/src/qml/memory/qv4writebarrier_p.h b/src/qml/memory/qv4writebarrier_p.h index c0f4b0b29a..39413a6f09 100644 --- a/src/qml/memory/qv4writebarrier_p.h +++ b/src/qml/memory/qv4writebarrier_p.h @@ -138,7 +138,7 @@ private: Heap::Base *ptr; }; typedef Pointer<char *, 0> V4PointerCheck; -V4_ASSERT_IS_TRIVIAL(V4PointerCheck) +Q_STATIC_ASSERT(std::is_trivial< V4PointerCheck >::value); } diff --git a/src/qml/qml/v8/qv8engine.cpp b/src/qml/qml/v8/qv8engine.cpp index dadff819cf..2947f7870a 100644 --- a/src/qml/qml/v8/qv8engine.cpp +++ b/src/qml/qml/v8/qv8engine.cpp @@ -127,7 +127,6 @@ QV8Engine::QV8Engine(QJSEngine* qq) : q(qq) , m_engine(0) , m_xmlHttpRequestData(0) - , m_listModelData(0) { #ifdef Q_PROCESSOR_X86_32 if (!qCpuHasFeature(SSE2)) { @@ -164,9 +163,6 @@ QV8Engine::~QV8Engine() m_xmlHttpRequestData = 0; #endif - delete m_listModelData; - m_listModelData = 0; - delete m_v4Engine; } diff --git a/src/qml/qml/v8/qv8engine_p.h b/src/qml/qml/v8/qv8engine_p.h index a430fba0e6..98b182147c 100644 --- a/src/qml/qml/v8/qv8engine_p.h +++ b/src/qml/qml/v8/qv8engine_p.h @@ -77,12 +77,6 @@ namespace QV4 { struct QObjectMethod; } -#define V4THROW_ERROR(string) \ - return ctx->engine()->throwError(QString::fromUtf8(string)); - -#define V4THROW_TYPE(string) \ - return ctx->engine()->throwTypeError(QStringLiteral(string)); - #define V4_DEFINE_EXTENSION(dataclass, datafunction) \ static inline dataclass *datafunction(QV4::ExecutionEngine *engine) \ { \ @@ -183,9 +177,6 @@ public: void *xmlHttpRequestData() const { return m_xmlHttpRequestData; } - Deletable *listModelData() const { return m_listModelData; } - void setListModelData(Deletable *d) { if (m_listModelData) delete m_listModelData; m_listModelData = d; } - void freezeObject(const QV4::Value &value); #if QT_CONFIG(qml_network) @@ -222,7 +213,6 @@ protected: void *m_xmlHttpRequestData; QVector<Deletable *> m_extensionData; - Deletable *m_listModelData; QSet<QString> m_illegalNames; diff --git a/src/qml/types/qqmllistmodel.cpp b/src/qml/types/qqmllistmodel.cpp index e32e0c75f3..0f04d48bf8 100644 --- a/src/qml/types/qqmllistmodel.cpp +++ b/src/qml/types/qqmllistmodel.cpp @@ -271,23 +271,24 @@ QObject *ListModel::getOrCreateModelObject(QQmlListModel *model, int elementInde return e->m_objectCache; } -void ListModel::sync(ListModel *src, ListModel *target, QHash<int, ListModel *> *targetModelHash) +bool ListModel::sync(ListModel *src, ListModel *target) { // Sanity check target->m_uid = src->m_uid; - if (targetModelHash) - targetModelHash->insert(target->m_uid, target); + + bool hasChanges = false; // Build hash of elements <-> uid for each of the lists QHash<int, ElementSync> elementHash; - for (int i=0 ; i < target->elements.count() ; ++i) { + for (int i = 0; i < target->elements.count(); ++i) { ListElement *e = target->elements.at(i); int uid = e->getUid(); ElementSync sync; sync.target = e; + sync.targetIndex = i; elementHash.insert(uid, sync); } - for (int i=0 ; i < src->elements.count() ; ++i) { + for (int i = 0; i < src->elements.count(); ++i) { ListElement *e = src->elements.at(i); int uid = e->getUid(); @@ -295,24 +296,39 @@ void ListModel::sync(ListModel *src, ListModel *target, QHash<int, ListModel *> if (it == elementHash.end()) { ElementSync sync; sync.src = e; + sync.srcIndex = i; elementHash.insert(uid, sync); } else { ElementSync &sync = it.value(); sync.src = e; + sync.srcIndex = i; } } + QQmlListModel *targetModel = target->m_modelCache; + // Get list of elements that are in the target but no longer in the source. These get deleted first. - QHash<int, ElementSync>::iterator it = elementHash.begin(); - QHash<int, ElementSync>::iterator end = elementHash.end(); - while (it != end) { - const ElementSync &s = it.value(); - if (s.src == 0) { + int rowsRemoved = 0; + for (int i = 0 ; i < target->elements.count() ; ++i) { + ListElement *element = target->elements.at(i); + ElementSync &s = elementHash.find(element->getUid()).value(); + Q_ASSERT(s.targetIndex >= 0); + // need to update the targetIndex, to keep it correct after removals + s.targetIndex -= rowsRemoved; + if (s.src == nullptr) { + Q_ASSERT(s.targetIndex == i); + hasChanges = true; + if (targetModel) + targetModel->beginRemoveRows(QModelIndex(), i, i); s.target->destroy(target->m_layout); target->elements.removeOne(s.target); delete s.target; + if (targetModel) + targetModel->endRemoveRows(); + ++rowsRemoved; + --i; + continue; } - ++it; } // Sync the layouts @@ -320,15 +336,15 @@ void ListModel::sync(ListModel *src, ListModel *target, QHash<int, ListModel *> // Clear the target list, and append in correct order from the source target->elements.clear(); - for (int i=0 ; i < src->elements.count() ; ++i) { + for (int i = 0; i < src->elements.count(); ++i) { ListElement *srcElement = src->elements.at(i); - it = elementHash.find(srcElement->getUid()); - const ElementSync &s = it.value(); + ElementSync &s = elementHash.find(srcElement->getUid()).value(); + Q_ASSERT(s.srcIndex >= 0); ListElement *targetElement = s.target; - if (targetElement == 0) { + if (targetElement == nullptr) { targetElement = new ListElement(srcElement->getUid()); } - ListElement::sync(srcElement, src->m_layout, targetElement, target->m_layout, targetModelHash); + s.changedRoles = ListElement::sync(srcElement, src->m_layout, targetElement, target->m_layout); target->elements.append(targetElement); } @@ -340,6 +356,39 @@ void ListModel::sync(ListModel *src, ListModel *target, QHash<int, ListModel *> if (ModelNodeMetaObject *mo = e->objectCache()) mo->updateValues(); } + + // now emit the change notifications required. This can be safely done, as we're only emitting changes, moves and inserts, + // so the model indices can't be out of bounds + // + // to ensure things are kept in the correct order, emit inserts and moves first. This shouls ensure all persistent + // model indices are updated correctly + int rowsInserted = 0; + for (int i = 0 ; i < target->elements.count() ; ++i) { + ListElement *element = target->elements.at(i); + ElementSync &s = elementHash.find(element->getUid()).value(); + Q_ASSERT(s.srcIndex >= 0); + s.srcIndex += rowsInserted; + if (s.srcIndex != s.targetIndex) { + if (targetModel) { + if (s.targetIndex == -1) { + targetModel->beginInsertRows(QModelIndex(), i, i); + targetModel->endInsertRows(); + } else { + targetModel->beginMoveRows(QModelIndex(), i, i, QModelIndex(), s.srcIndex); + targetModel->endMoveRows(); + } + } + hasChanges = true; + ++rowsInserted; + } + if (s.targetIndex != -1 && !s.changedRoles.isEmpty()) { + QModelIndex idx = targetModel->createIndex(i, 0); + if (targetModel) + targetModel->dataChanged(idx, idx, s.changedRoles); + hasChanges = true; + } + } + return hasChanges; } ListModel::ListModel(ListLayout *layout, QQmlListModel *modelCache, int uid) : m_layout(layout), m_modelCache(modelCache) @@ -949,7 +998,11 @@ int ListElement::setVariantMapProperty(const ListLayout::Role &role, QVariantMap char *mem = getPropertyMemory(role); if (isMemoryUsed<QVariantMap>(mem)) { QVariantMap *map = reinterpret_cast<QVariantMap *>(mem); + if (m && map->isSharedWith(*m)) + return roleIndex; map->~QMap(); + } else if (!m) { + return roleIndex; } if (m) new (mem) QVariantMap(*m); @@ -1101,12 +1154,14 @@ ListElement::~ListElement() delete next; } -void ListElement::sync(ListElement *src, ListLayout *srcLayout, ListElement *target, ListLayout *targetLayout, QHash<int, ListModel *> *targetModelHash) +QVector<int> ListElement::sync(ListElement *src, ListLayout *srcLayout, ListElement *target, ListLayout *targetLayout) { + QVector<int> changedRoles; for (int i=0 ; i < srcLayout->roleCount() ; ++i) { const ListLayout::Role &srcRole = srcLayout->getExistingRole(i); const ListLayout::Role &targetRole = targetLayout->getExistingRole(i); + int roleIndex = -1; switch (srcRole.type) { case ListLayout::Role::List: { @@ -1118,14 +1173,15 @@ void ListElement::sync(ListElement *src, ListLayout *srcLayout, ListElement *tar targetSubModel = new ListModel(targetRole.subLayout, 0, srcSubModel->getUid()); target->setListPropertyFast(targetRole, targetSubModel); } - ListModel::sync(srcSubModel, targetSubModel, targetModelHash); + if (ListModel::sync(srcSubModel, targetSubModel)) + roleIndex = targetRole.index; } } break; case ListLayout::Role::QObject: { QObject *object = src->getQObjectProperty(srcRole); - target->setQObjectProperty(targetRole, object); + roleIndex = target->setQObjectProperty(targetRole, object); } break; case ListLayout::Role::String: @@ -1135,20 +1191,23 @@ void ListElement::sync(ListElement *src, ListLayout *srcLayout, ListElement *tar case ListLayout::Role::Function: { QVariant v = src->getProperty(srcRole, 0, 0); - target->setVariantProperty(targetRole, v); + roleIndex = target->setVariantProperty(targetRole, v); } break; case ListLayout::Role::VariantMap: { QVariantMap *map = src->getVariantMapProperty(srcRole); - target->setVariantMapProperty(targetRole, map); + roleIndex = target->setVariantMapProperty(targetRole, map); } break; default: break; } + if (roleIndex >= 0) + changedRoles << roleIndex; } + return changedRoles; } void ListElement::destroy(ListLayout *layout) @@ -1493,20 +1552,22 @@ DynamicRoleModelNode *DynamicRoleModelNode::create(const QVariantMap &obj, QQmlL return object; } -void DynamicRoleModelNode::sync(DynamicRoleModelNode *src, DynamicRoleModelNode *target, QHash<int, QQmlListModel *> *targetModelHash) +QVector<int> DynamicRoleModelNode::sync(DynamicRoleModelNode *src, DynamicRoleModelNode *target) { - for (int i=0 ; i < src->m_meta->count() ; ++i) { + QVector<int> changedRoles; + for (int i = 0; i < src->m_meta->count(); ++i) { const QByteArray &name = src->m_meta->name(i); QVariant value = src->m_meta->value(i); QQmlListModel *srcModel = qobject_cast<QQmlListModel *>(value.value<QObject *>()); QQmlListModel *targetModel = qobject_cast<QQmlListModel *>(target->m_meta->value(i).value<QObject *>()); + bool modelHasChanges = false; if (srcModel) { if (targetModel == 0) targetModel = QQmlListModel::createWithOwner(target->m_owner); - QQmlListModel::sync(srcModel, targetModel, targetModelHash); + modelHasChanges = QQmlListModel::sync(srcModel, targetModel); QObject *targetModelObject = targetModel; value = QVariant::fromValue(targetModelObject); @@ -1514,8 +1575,10 @@ void DynamicRoleModelNode::sync(DynamicRoleModelNode *src, DynamicRoleModelNode delete targetModel; } - target->setValue(name, value); + if (target->setValue(name, value) || modelHasChanges) + changedRoles << target->m_owner->m_roles.indexOf(QString::fromUtf8(name)); } + return changedRoles; } void DynamicRoleModelNode::updateValues(const QVariantMap &object, QVector<int> &roles) @@ -1761,9 +1824,9 @@ QQmlListModel::QQmlListModel(QQmlListModel *orig, QQmlListModelWorkerAgent *agen m_listModel = new ListModel(m_layout, this, orig->m_listModel->getUid()); if (m_dynamicRoles) - sync(orig, this, 0); + sync(orig, this); else - ListModel::sync(orig->m_listModel, m_listModel, 0); + ListModel::sync(orig->m_listModel, m_listModel); m_engine = 0; } @@ -1814,25 +1877,26 @@ QV4::ExecutionEngine *QQmlListModel::engine() const return m_engine; } -void QQmlListModel::sync(QQmlListModel *src, QQmlListModel *target, QHash<int, QQmlListModel *> *targetModelHash) +bool QQmlListModel::sync(QQmlListModel *src, QQmlListModel *target) { Q_ASSERT(src->m_dynamicRoles && target->m_dynamicRoles); + bool hasChanges = false; + target->m_uid = src->m_uid; - if (targetModelHash) - targetModelHash->insert(target->m_uid, target); target->m_roles = src->m_roles; // Build hash of elements <-> uid for each of the lists QHash<int, ElementSync> elementHash; - for (int i=0 ; i < target->m_modelObjects.count() ; ++i) { + for (int i = 0 ; i < target->m_modelObjects.count(); ++i) { DynamicRoleModelNode *e = target->m_modelObjects.at(i); int uid = e->getUid(); ElementSync sync; sync.target = e; + sync.targetIndex = i; elementHash.insert(uid, sync); } - for (int i=0 ; i < src->m_modelObjects.count() ; ++i) { + for (int i = 0 ; i < src->m_modelObjects.count(); ++i) { DynamicRoleModelNode *e = src->m_modelObjects.at(i); int uid = e->getUid(); @@ -1840,118 +1904,102 @@ void QQmlListModel::sync(QQmlListModel *src, QQmlListModel *target, QHash<int, Q if (it == elementHash.end()) { ElementSync sync; sync.src = e; + sync.srcIndex = i; elementHash.insert(uid, sync); } else { ElementSync &sync = it.value(); sync.src = e; + sync.srcIndex = i; } } // Get list of elements that are in the target but no longer in the source. These get deleted first. - QHash<int, ElementSync>::iterator it = elementHash.begin(); - QHash<int, ElementSync>::iterator end = elementHash.end(); - while (it != end) { - const ElementSync &s = it.value(); - if (s.src == 0) { - int targetIndex = target->m_modelObjects.indexOf(s.target); - target->m_modelObjects.remove(targetIndex, 1); + int rowsRemoved = 0; + for (int i = 0 ; i < target->m_modelObjects.count() ; ++i) { + DynamicRoleModelNode *element = target->m_modelObjects.at(i); + ElementSync &s = elementHash.find(element->getUid()).value(); + Q_ASSERT(s.targetIndex >= 0); + // need to update the targetIndex, to keep it correct after removals + s.targetIndex -= rowsRemoved; + if (s.src == nullptr) { + Q_ASSERT(s.targetIndex == i); + hasChanges = true; + target->beginRemoveRows(QModelIndex(), i, i); + target->m_modelObjects.remove(i, 1); + target->endRemoveRows(); delete s.target; + ++rowsRemoved; + --i; + continue; } - ++it; } // Clear the target list, and append in correct order from the source target->m_modelObjects.clear(); - for (int i=0 ; i < src->m_modelObjects.count() ; ++i) { - DynamicRoleModelNode *srcElement = src->m_modelObjects.at(i); - it = elementHash.find(srcElement->getUid()); - const ElementSync &s = it.value(); + for (int i = 0 ; i < src->m_modelObjects.count() ; ++i) { + DynamicRoleModelNode *element = src->m_modelObjects.at(i); + ElementSync &s = elementHash.find(element->getUid()).value(); + Q_ASSERT(s.srcIndex >= 0); DynamicRoleModelNode *targetElement = s.target; if (targetElement == 0) { - targetElement = new DynamicRoleModelNode(target, srcElement->getUid()); + targetElement = new DynamicRoleModelNode(target, element->getUid()); } - DynamicRoleModelNode::sync(srcElement, targetElement, targetModelHash); + s.changedRoles = DynamicRoleModelNode::sync(element, targetElement); target->m_modelObjects.append(targetElement); } -} -void QQmlListModel::emitItemsChanged(int index, int count, const QVector<int> &roles) -{ - if (count <= 0) - return; - - if (m_mainThread) { - emit dataChanged(createIndex(index, 0), createIndex(index + count - 1, 0), roles);; - } else { - int uid = m_dynamicRoles ? getUid() : m_listModel->getUid(); - m_agent->data.changedChange(uid, index, count, roles); + // now emit the change notifications required. This can be safely done, as we're only emitting changes, moves and inserts, + // so the model indices can't be out of bounds + // + // to ensure things are kept in the correct order, emit inserts and moves first. This shouls ensure all persistent + // model indices are updated correctly + int rowsInserted = 0; + for (int i = 0 ; i < target->m_modelObjects.count() ; ++i) { + DynamicRoleModelNode *element = target->m_modelObjects.at(i); + ElementSync &s = elementHash.find(element->getUid()).value(); + Q_ASSERT(s.srcIndex >= 0); + s.srcIndex += rowsInserted; + if (s.srcIndex != s.targetIndex) { + if (s.targetIndex == -1) { + target->beginInsertRows(QModelIndex(), i, i); + target->endInsertRows(); + } else { + target->beginMoveRows(QModelIndex(), i, i, QModelIndex(), s.srcIndex); + target->endMoveRows(); + } + hasChanges = true; + ++rowsInserted; + } + if (s.targetIndex != -1 && !s.changedRoles.isEmpty()) { + QModelIndex idx = target->createIndex(i, 0); + emit target->dataChanged(idx, idx, s.changedRoles); + hasChanges = true; + } } + return hasChanges; } -void QQmlListModel::emitItemsAboutToBeRemoved(int index, int count) -{ - if (count <= 0 || !m_mainThread) - return; - - beginRemoveRows(QModelIndex(), index, index + count - 1); -} - -void QQmlListModel::emitItemsRemoved(int index, int count) +void QQmlListModel::emitItemsChanged(int index, int count, const QVector<int> &roles) { if (count <= 0) return; - if (m_mainThread) { - endRemoveRows(); - emit countChanged(); - } else { - int uid = m_dynamicRoles ? getUid() : m_listModel->getUid(); - if (index == 0 && count == this->count()) - m_agent->data.clearChange(uid); - m_agent->data.removeChange(uid, index, count); - } + if (m_mainThread) + emit dataChanged(createIndex(index, 0), createIndex(index + count - 1, 0), roles);; } void QQmlListModel::emitItemsAboutToBeInserted(int index, int count) { - if (count <= 0 || !m_mainThread) - return; - - beginInsertRows(QModelIndex(), index, index + count - 1); + Q_ASSERT(index >= 0 && count >= 0); + if (m_mainThread) + beginInsertRows(QModelIndex(), index, index + count - 1); } -void QQmlListModel::emitItemsInserted(int index, int count) +void QQmlListModel::emitItemsInserted() { - if (count <= 0) - return; - if (m_mainThread) { endInsertRows(); emit countChanged(); - } else { - int uid = m_dynamicRoles ? getUid() : m_listModel->getUid(); - m_agent->data.insertChange(uid, index, count); - } -} - -void QQmlListModel::emitItemsAboutToBeMoved(int from, int to, int n) -{ - if (n <= 0 || !m_mainThread) - return; - - beginMoveRows(QModelIndex(), from, from + n - 1, QModelIndex(), to > from ? to + n : to); -} - -void QQmlListModel::emitItemsMoved(int from, int to, int n) -{ - if (n <= 0) - return; - - if (m_mainThread) { - endMoveRows(); - } else { - int uid = m_dynamicRoles ? getUid() : m_listModel->getUid(); - m_agent->data.moveChange(uid, from, n, to); } } @@ -2133,7 +2181,13 @@ void QQmlListModel::remove(QQmlV4Function *args) void QQmlListModel::removeElements(int index, int removeCount) { - emitItemsAboutToBeRemoved(index, removeCount); + Q_ASSERT(index >= 0 && removeCount >= 0); + + if (!removeCount) + return; + + if (m_mainThread) + beginRemoveRows(QModelIndex(), index, index + removeCount - 1); QVector<std::function<void()>> toDestroy; if (m_dynamicRoles) { @@ -2148,7 +2202,10 @@ void QQmlListModel::removeElements(int index, int removeCount) toDestroy = m_listModel->remove(index, removeCount); } - emitItemsRemoved(index, removeCount); + if (m_mainThread) { + endRemoveRows(); + emit countChanged(); + } for (const auto &destroyer : toDestroy) destroyer(); } @@ -2197,7 +2254,7 @@ void QQmlListModel::insert(QQmlV4Function *args) m_listModel->insert(index+i, argObject); } } - emitItemsInserted(index, objectArrayLength); + emitItemsInserted(); } else if (argObject) { emitItemsAboutToBeInserted(index, 1); @@ -2207,7 +2264,7 @@ void QQmlListModel::insert(QQmlV4Function *args) m_listModel->insert(index, argObject); } - emitItemsInserted(index, 1); + emitItemsInserted(); } else { qmlWarning(this) << tr("insert: value is not an object"); } @@ -2232,14 +2289,15 @@ void QQmlListModel::insert(QQmlV4Function *args) */ void QQmlListModel::move(int from, int to, int n) { - if (n==0 || from==to) + if (n == 0 || from == to) return; if (!canMove(from, to, n)) { qmlWarning(this) << tr("move: out of range"); return; } - emitItemsAboutToBeMoved(from, to, n); + if (m_mainThread) + beginMoveRows(QModelIndex(), from, from + n - 1, QModelIndex(), to > from ? to + n : to); if (m_dynamicRoles) { @@ -2268,7 +2326,8 @@ void QQmlListModel::move(int from, int to, int n) m_listModel->move(from, to, n); } - emitItemsMoved(from, to, n); + if (m_mainThread) + endMoveRows(); } /*! @@ -2308,7 +2367,7 @@ void QQmlListModel::append(QQmlV4Function *args) } } - emitItemsInserted(index, objectArrayLength); + emitItemsInserted(); } else if (argObject) { int index; @@ -2322,7 +2381,7 @@ void QQmlListModel::append(QQmlV4Function *args) m_listModel->append(argObject); } - emitItemsInserted(index, 1); + emitItemsInserted(); } else { qmlWarning(this) << tr("append: value is not an object"); } @@ -2424,7 +2483,7 @@ void QQmlListModel::set(int index, const QQmlV4Handle &handle) m_listModel->insert(index, object); } - emitItemsInserted(index, 1); + emitItemsInserted(); } else { QVector<int> roles; diff --git a/src/qml/types/qqmllistmodel_p.h b/src/qml/types/qqmllistmodel_p.h index 499a113504..18b7b8bb22 100644 --- a/src/qml/types/qqmllistmodel_p.h +++ b/src/qml/types/qqmllistmodel_p.h @@ -147,24 +147,21 @@ private: struct ElementSync { - ElementSync() : src(0), target(0) {} - - DynamicRoleModelNode *src; - DynamicRoleModelNode *target; + DynamicRoleModelNode *src = nullptr; + DynamicRoleModelNode *target = nullptr; + int srcIndex = -1; + int targetIndex = -1; + QVector<int> changedRoles; }; int getUid() const { return m_uid; } - static void sync(QQmlListModel *src, QQmlListModel *target, QHash<int, QQmlListModel *> *targetModelHash); + static bool sync(QQmlListModel *src, QQmlListModel *target); static QQmlListModel *createWithOwner(QQmlListModel *newOwner); void emitItemsChanged(int index, int count, const QVector<int> &roles); - void emitItemsAboutToBeRemoved(int index, int count); - void emitItemsRemoved(int index, int count); void emitItemsAboutToBeInserted(int index, int count); - void emitItemsInserted(int index, int count); - void emitItemsAboutToBeMoved(int from, int to, int n); - void emitItemsMoved(int from, int to, int n); + void emitItemsInserted(); void removeElements(int index, int removeCount); }; diff --git a/src/qml/types/qqmllistmodel_p_p.h b/src/qml/types/qqmllistmodel_p_p.h index dea1ef2eb3..65567ab69a 100644 --- a/src/qml/types/qqmllistmodel_p_p.h +++ b/src/qml/types/qqmllistmodel_p_p.h @@ -108,7 +108,7 @@ public: return m_uid; } - static void sync(DynamicRoleModelNode *src, DynamicRoleModelNode *target, QHash<int, QQmlListModel *> *targetModelHash); + static QVector<int> sync(DynamicRoleModelNode *src, DynamicRoleModelNode *target); private: QQmlListModel *m_owner; @@ -261,7 +261,7 @@ public: ListElement(int existingUid); ~ListElement(); - static void sync(ListElement *src, ListLayout *srcLayout, ListElement *target, ListLayout *targetLayout, QHash<int, ListModel *> *targetModelHash); + static QVector<int> sync(ListElement *src, ListLayout *srcLayout, ListElement *target, ListLayout *targetLayout); enum { @@ -379,7 +379,7 @@ public: int getUid() const { return m_uid; } - static void sync(ListModel *src, ListModel *target, QHash<int, ListModel *> *srcModelHash); + static bool sync(ListModel *src, ListModel *target); QObject *getOrCreateModelObject(QQmlListModel *model, int elementIndex); @@ -392,10 +392,11 @@ private: struct ElementSync { - ElementSync() : src(0), target(0) {} - - ListElement *src; - ListElement *target; + ListElement *src = nullptr; + ListElement *target = nullptr; + int srcIndex = -1; + int targetIndex = -1; + QVector<int> changedRoles; }; void newElement(int index); diff --git a/src/qml/types/qqmllistmodelworkeragent.cpp b/src/qml/types/qqmllistmodelworkeragent.cpp index 0a5adbf292..a2750c926a 100644 --- a/src/qml/types/qqmllistmodelworkeragent.cpp +++ b/src/qml/types/qqmllistmodelworkeragent.cpp @@ -50,39 +50,8 @@ QT_BEGIN_NAMESPACE - -void QQmlListModelWorkerAgent::Data::clearChange(int uid) -{ - for (int i=0 ; i < changes.count() ; ++i) { - if (changes[i].modelUid == uid) { - changes.removeAt(i); - --i; - } - } -} - -void QQmlListModelWorkerAgent::Data::insertChange(int uid, int index, int count) +QQmlListModelWorkerAgent::Sync::~Sync() { - Change c = { uid, Change::Inserted, index, count, 0, QVector<int>() }; - changes << c; -} - -void QQmlListModelWorkerAgent::Data::removeChange(int uid, int index, int count) -{ - Change c = { uid, Change::Removed, index, count, 0, QVector<int>() }; - changes << c; -} - -void QQmlListModelWorkerAgent::Data::moveChange(int uid, int index, int count, int to) -{ - Change c = { uid, Change::Moved, index, count, to, QVector<int>() }; - changes << c; -} - -void QQmlListModelWorkerAgent::Data::changedChange(int uid, int index, int count, const QVector<int> &roles) -{ - Change c = { uid, Change::Changed, index, count, 0, roles }; - changes << c; } QQmlListModelWorkerAgent::QQmlListModelWorkerAgent(QQmlListModel *model) @@ -167,8 +136,7 @@ void QQmlListModelWorkerAgent::move(int from, int to, int count) void QQmlListModelWorkerAgent::sync() { - Sync *s = new Sync(data, m_copy); - data.changes.clear(); + Sync *s = new Sync(m_copy); mutex.lock(); QCoreApplication::postEvent(this, s); @@ -183,61 +151,14 @@ bool QQmlListModelWorkerAgent::event(QEvent *e) QMutexLocker locker(&mutex); if (m_orig) { Sync *s = static_cast<Sync *>(e); - const QList<Change> &changes = s->data.changes; - cc = m_orig->count() != s->list->count(); - - QHash<int, QQmlListModel *> targetModelDynamicHash; - QHash<int, ListModel *> targetModelStaticHash; + cc = (m_orig->count() != s->list->count()); Q_ASSERT(m_orig->m_dynamicRoles == s->list->m_dynamicRoles); if (m_orig->m_dynamicRoles) - QQmlListModel::sync(s->list, m_orig, &targetModelDynamicHash); + QQmlListModel::sync(s->list, m_orig); else - ListModel::sync(s->list->m_listModel, m_orig->m_listModel, &targetModelStaticHash); - - for (int ii = 0; ii < changes.count(); ++ii) { - const Change &change = changes.at(ii); - - QQmlListModel *model = 0; - if (m_orig->m_dynamicRoles) { - model = targetModelDynamicHash.value(change.modelUid); - } else { - ListModel *lm = targetModelStaticHash.value(change.modelUid); - if (lm) - model = lm->m_modelCache; - } - - if (model) { - switch (change.type) { - case Change::Inserted: - model->beginInsertRows( - QModelIndex(), change.index, change.index + change.count - 1); - model->endInsertRows(); - break; - case Change::Removed: - model->beginRemoveRows( - QModelIndex(), change.index, change.index + change.count - 1); - model->endRemoveRows(); - break; - case Change::Moved: - model->beginMoveRows( - QModelIndex(), - change.index, - change.index + change.count - 1, - QModelIndex(), - change.to > change.index ? change.to + change.count : change.to); - model->endMoveRows(); - break; - case Change::Changed: - emit model->dataChanged( - model->createIndex(change.index, 0), - model->createIndex(change.index + change.count - 1, 0), - change.roles); - break; - } - } - } + ListModel::sync(s->list->m_listModel, m_orig->m_listModel); } syncDone.wakeAll(); diff --git a/src/qml/types/qqmllistmodelworkeragent_p.h b/src/qml/types/qqmllistmodelworkeragent_p.h index 5a39651bf7..761a467e89 100644 --- a/src/qml/types/qqmllistmodelworkeragent_p.h +++ b/src/qml/types/qqmllistmodelworkeragent_p.h @@ -114,35 +114,12 @@ private: friend class QQuickWorkerScriptEnginePrivate; friend class QQmlListModel; - struct Change - { - int modelUid; - enum { Inserted, Removed, Moved, Changed } type; - int index; // Inserted/Removed/Moved/Changed - int count; // Inserted/Removed/Moved/Changed - int to; // Moved - QVector<int> roles; - }; - - struct Data - { - QList<Change> changes; - - void clearChange(int uid); - void insertChange(int uid, int index, int count); - void removeChange(int uid, int index, int count); - void moveChange(int uid, int index, int count, int to); - void changedChange(int uid, int index, int count, const QVector<int> &roles); - }; - Data data; - struct Sync : public QEvent { - Sync(const Data &d, QQmlListModel *l) + Sync(QQmlListModel *l) : QEvent(QEvent::User) - , data(d) , list(l) {} - Data data; + ~Sync(); QQmlListModel *list; }; diff --git a/src/quick/items/qquickview.cpp b/src/quick/items/qquickview.cpp index fca1805fc9..9a29d6c2ca 100644 --- a/src/quick/items/qquickview.cpp +++ b/src/quick/items/qquickview.cpp @@ -198,6 +198,16 @@ QQuickView::QQuickView(QQmlEngine* engine, QWindow *parent) } /*! + \internal +*/ +QQuickView::QQuickView(const QUrl &source, QQuickRenderControl *control) + : QQuickWindow(*(new QQuickViewPrivate), control) +{ + d_func()->init(); + setSource(source); +} + +/*! Destroys the QQuickView. */ QQuickView::~QQuickView() diff --git a/src/quick/items/qquickview.h b/src/quick/items/qquickview.h index 014d02e7f5..006a691387 100644 --- a/src/quick/items/qquickview.h +++ b/src/quick/items/qquickview.h @@ -62,6 +62,7 @@ public: explicit QQuickView(QWindow *parent = nullptr); QQuickView(QQmlEngine* engine, QWindow *parent); explicit QQuickView(const QUrl &source, QWindow *parent = nullptr); + QQuickView(const QUrl &source, QQuickRenderControl *renderControl); virtual ~QQuickView(); QUrl source() const; diff --git a/src/quick/items/qquickwindow.cpp b/src/quick/items/qquickwindow.cpp index db7a80ee9a..436adf8c49 100644 --- a/src/quick/items/qquickwindow.cpp +++ b/src/quick/items/qquickwindow.cpp @@ -1288,7 +1288,15 @@ QQuickWindow::QQuickWindow(QQuickRenderControl *control) d->init(this, control); } - +/*! + \internal +*/ +QQuickWindow::QQuickWindow(QQuickWindowPrivate &dd, QQuickRenderControl *control) + : QWindow(dd, 0) +{ + Q_D(QQuickWindow); + d->init(this, control); +} /*! Destroys the window. diff --git a/src/quick/items/qquickwindow.h b/src/quick/items/qquickwindow.h index e5b54c8fb9..06af7bbf02 100644 --- a/src/quick/items/qquickwindow.h +++ b/src/quick/items/qquickwindow.h @@ -204,6 +204,7 @@ public Q_SLOTS: protected: QQuickWindow(QQuickWindowPrivate &dd, QWindow *parent = nullptr); + QQuickWindow(QQuickWindowPrivate &dd, QQuickRenderControl *control); void exposeEvent(QExposeEvent *) override; void resizeEvent(QResizeEvent *) override; diff --git a/src/quick/util/qquickimageprovider.h b/src/quick/util/qquickimageprovider.h index 681de4b6c2..4451105782 100644 --- a/src/quick/util/qquickimageprovider.h +++ b/src/quick/util/qquickimageprovider.h @@ -56,6 +56,7 @@ class QQuickWindow; class Q_QUICK_EXPORT QQuickTextureFactory : public QObject { + Q_OBJECT public: QQuickTextureFactory(); virtual ~QQuickTextureFactory(); diff --git a/src/src.pro b/src/src.pro index 42bf90e092..33c47048b5 100644 --- a/src/src.pro +++ b/src/src.pro @@ -2,7 +2,7 @@ TEMPLATE = subdirs CONFIG += ordered include($$OUT_PWD/qml/qtqml-config.pri) include($$OUT_PWD/quick/qtquick-config.pri) -QT_FOR_CONFIG += network qml quick-private +QT_FOR_CONFIG += qml quick-private SUBDIRS += \ qml @@ -21,4 +21,7 @@ SUBDIRS += \ imports \ qmldevtools -qtConfig(localserver):qtConfig(qml-debug): SUBDIRS += qmldebug +qtConfig(qml-network) { + QT_FOR_CONFIG += network + qtConfig(localserver):qtConfig(qml-debug): SUBDIRS += qmldebug +} |