diff options
Diffstat (limited to 'src/qml')
48 files changed, 706 insertions, 522 deletions
diff --git a/src/qml/compiler/qv4compilationunitmapper_win.cpp b/src/qml/compiler/qv4compilationunitmapper_win.cpp index 457b702ac3..37cac846a0 100644 --- a/src/qml/compiler/qv4compilationunitmapper_win.cpp +++ b/src/qml/compiler/qv4compilationunitmapper_win.cpp @@ -75,7 +75,6 @@ CompiledData::Unit *CompilationUnitMapper::open(const QString &cacheFileName, co CloseHandle(handle); }); -#if !defined(Q_OS_WINRT) || _MSC_VER >= 1900 CompiledData::Unit header; DWORD bytesRead; if (!ReadFile(handle, reinterpret_cast<char *>(&header), sizeof(header), &bytesRead, nullptr)) { @@ -115,19 +114,12 @@ CompiledData::Unit *CompilationUnitMapper::open(const QString &cacheFileName, co } return reinterpret_cast<CompiledData::Unit*>(dataPtr); -#else - Q_UNUSED(sourcePath); - *errorString = QStringLiteral("Compilation unit mapping not supported on WinRT 8.1"); - return nullptr; -#endif } void CompilationUnitMapper::close() { -#if !defined(Q_OS_WINRT) || _MSC_VER >= 1900 if (dataPtr != nullptr) UnmapViewOfFile(dataPtr); -#endif dataPtr = nullptr; } diff --git a/src/qml/compiler/qv4compileddata.cpp b/src/qml/compiler/qv4compileddata.cpp index 8586c84c3d..6aac111897 100644 --- a/src/qml/compiler/qv4compileddata.cpp +++ b/src/qml/compiler/qv4compileddata.cpp @@ -407,6 +407,11 @@ bool CompilationUnit::loadFromDisk(const QUrl &url, EvalISelFactory *iselFactory const Unit * const oldDataPtr = (data && !(data->flags & QV4::CompiledData::Unit::StaticData)) ? data : nullptr; QScopedValueRollback<const Unit *> dataPtrChange(data, mappedUnit); + if (sourcePath != QQmlFile::urlToLocalFileOrQrc(stringAt(data->sourceFileIndex))) { + *errorString = QStringLiteral("QML source file has moved to a different location."); + return false; + } + { const QString foundArchitecture = stringAt(data->architectureIndex); const QString expectedArchitecture = QSysInfo::buildAbi(); diff --git a/src/qml/compiler/qv4isel_moth.cpp b/src/qml/compiler/qv4isel_moth.cpp index 1f5c22eb97..9dbebd1128 100644 --- a/src/qml/compiler/qv4isel_moth.cpp +++ b/src/qml/compiler/qv4isel_moth.cpp @@ -242,6 +242,11 @@ void InstructionSelection::run(int functionIndex) addInstruction(set); } exceptionHandler = _block->catchBlock; + } else if (_block->catchBlock == nullptr && _block->index() != 0 && _block->in.isEmpty()) { + exceptionHandler = nullptr; + Instruction::SetExceptionHandler set; + set.offset = 0; + addInstruction(set); } for (IR::Stmt *s : _block->statements()) { diff --git a/src/qml/compiler/qv4ssa.cpp b/src/qml/compiler/qv4ssa.cpp index 943700de44..1d512711b8 100644 --- a/src/qml/compiler/qv4ssa.cpp +++ b/src/qml/compiler/qv4ssa.cpp @@ -2758,7 +2758,7 @@ public: visit(s); } - foreach (const Conversion &conversion, _conversions) { + for (const Conversion &conversion : qAsConst(_conversions)) { IR::Move *move = conversion.stmt->asMove(); // Note: isel only supports move into member when source is a temp, so convert diff --git a/src/qml/debugger/qqmlprofiler_p.h b/src/qml/debugger/qqmlprofiler_p.h index 242f26ee0d..3a507bef74 100644 --- a/src/qml/debugger/qqmlprofiler_p.h +++ b/src/qml/debugger/qqmlprofiler_p.h @@ -149,40 +149,38 @@ class Q_QML_PRIVATE_EXPORT QQmlProfiler : public QObject, public QQmlProfilerDef Q_OBJECT public: - class BindingRefCount : public QQmlRefCount { + class FunctionRefCount : public QQmlRefCount { public: - BindingRefCount(QQmlBinding *binding): - m_binding(binding) + FunctionRefCount(QV4::Function *function): + m_function(function) { - m_binding->ref.ref(); + m_function->compilationUnit->addref(); } - BindingRefCount(const BindingRefCount &other) : - QQmlRefCount(other), m_binding(other.m_binding) + FunctionRefCount(const FunctionRefCount &other) : + QQmlRefCount(other), m_function(other.m_function) { - m_binding->ref.ref(); + m_function->compilationUnit->addref(); } - BindingRefCount &operator=(const BindingRefCount &other) + FunctionRefCount &operator=(const FunctionRefCount &other) { if (this != &other) { QQmlRefCount::operator=(other); - other.m_binding->ref.ref(); - if (!m_binding->ref.deref()) - delete m_binding; - m_binding = other.m_binding; + other.m_function->compilationUnit->addref(); + m_function->compilationUnit->release(); + m_function = other.m_function; } return *this; } - ~BindingRefCount() + ~FunctionRefCount() { - if (!m_binding->ref.deref()) - delete m_binding; + m_function->compilationUnit->release(); } private: - QQmlBinding *m_binding; + QV4::Function *m_function; }; struct Location { @@ -199,14 +197,10 @@ public: RefLocation() : Location(), locationType(MaximumRangeType), ref(nullptr), sent(false) {} - RefLocation(QQmlBinding *binding, QV4::FunctionObject *function) : + RefLocation(QV4::Function *function) : Location(function->sourceLocation()), locationType(Binding), - ref(new BindingRefCount(binding), QQmlRefPointer<QQmlRefCount>::Adopt), sent(false) - {} - - RefLocation(QQmlBinding *binding, QV4::Function *function) : - Location(function->sourceLocation()), locationType(Binding), - ref(new BindingRefCount(binding), QQmlRefPointer<QQmlRefCount>::Adopt), sent(false) + ref(new FunctionRefCount(function), + QQmlRefPointer<QQmlRefCount>::Adopt), sent(false) {} RefLocation(QV4::CompiledData::CompilationUnit *ref, const QUrl &url, const QV4::CompiledData::Object *obj, @@ -236,16 +230,21 @@ public: typedef QHash<quintptr, Location> LocationHash; - void startBinding(QQmlBinding *binding, QV4::Function *function) + void startBinding(QV4::Function *function) { - quintptr locationId(id(binding)); + // Use the QV4::Function as ID, as that is common among different instances of the same + // component. QQmlBinding is per instance. + // Add 1 to the ID, to make it different from the IDs the V4 profiler produces. The +1 makes + // the pointer point into the middle of the QV4::Function. Thus it still points to valid + // memory but we cannot accidentally create a duplicate key from another object. + quintptr locationId(id(function) + 1); m_data.append(QQmlProfilerData(m_timer.nsecsElapsed(), (1 << RangeStart | 1 << RangeLocation), Binding, locationId)); RefLocation &location = m_locations[locationId]; if (!location.isValid()) - location = RefLocation(binding, function); + location = RefLocation(function); } // Have toByteArrays() construct another RangeData event from the same QString later. @@ -281,7 +280,8 @@ public: Creating, id(obj))); } - void updateCreating(const QV4::CompiledData::Object *obj, QV4::CompiledData::CompilationUnit *ref, + void updateCreating(const QV4::CompiledData::Object *obj, + QV4::CompiledData::CompilationUnit *ref, const QUrl &url, const QString &type) { quintptr locationId(id(obj)); @@ -330,12 +330,11 @@ struct QQmlProfilerHelper : public QQmlProfilerDefinitions { }; struct QQmlBindingProfiler : public QQmlProfilerHelper { - QQmlBindingProfiler(QQmlProfiler *profiler, QQmlBinding *binding, - QV4::Function *function) : + QQmlBindingProfiler(QQmlProfiler *profiler, QV4::Function *function) : QQmlProfilerHelper(profiler) { Q_QML_PROFILE(QQmlProfilerDefinitions::ProfileBinding, profiler, - startBinding(binding, function)); + startBinding(function)); } ~QQmlBindingProfiler() diff --git a/src/qml/doc/src/examples.qdoc b/src/qml/doc/src/examples.qdoc index f3550ae199..4f12d42f48 100644 --- a/src/qml/doc/src/examples.qdoc +++ b/src/qml/doc/src/examples.qdoc @@ -32,4 +32,40 @@ The list of examples demonstrating how to extend C++ to QML or the other way around. + +\noautolist + +\table + \row + \li \l {Extending QML - Adding Types Example} + \li Exporting C++ Classes + \row + \li \l {Extending QML - Object and List Property Types Example} + \li Exporting C++ Properties + \row + \li \l {Extending QML - Extension Objects Example} + \li Extension Objects + \row + \li \l {Extending QML - Inheritance and Coercion Example} + \li C++ Inheritance and Coercion + \row + \li \l {Extending QML - Methods Example} + \li Methods Support + \row + \li \l {Extending QML - Attached Properties Example} + \li Attached Properties + \row + \li \l {Extending QML - Signal Support Example} + \li Signal Support + \row + \li \l {Extending QML - Property Value Source Example} + \li Property Value Source + \row + \li \l {Extending QML - Default Property Example} + \li Default Property + \row + \li \l {Extending QML - Grouped Properties Example} + \li Grouped Properties +\endtable + */ diff --git a/src/qml/doc/src/qmllanguageref/documents/networktransparency.qdoc b/src/qml/doc/src/qmllanguageref/documents/networktransparency.qdoc index 7fa271c2d9..5cfd80f8a0 100644 --- a/src/qml/doc/src/qmllanguageref/documents/networktransparency.qdoc +++ b/src/qml/doc/src/qmllanguageref/documents/networktransparency.qdoc @@ -48,12 +48,8 @@ Image { } \endqml -Network transparency is supported throughout QML, for example: - -\list -\li Fonts - the \c source property of FontLoader is a URL -\li WebViews - the \c url property of WebView (obviously!) -\endlist +Network transparency is supported throughout QML, for example, both the FontLoader +and Image elements support loading resources from a remote server. Even QML types themselves can be on the network - if the \l {Prototyping with qmlscene} is used to load \tt http://example.com/mystuff/Hello.qml and that content refers to a type "World", the engine diff --git a/src/qml/jit/qv4assembler.cpp b/src/qml/jit/qv4assembler.cpp index e1acc33f82..018396318e 100644 --- a/src/qml/jit/qv4assembler.cpp +++ b/src/qml/jit/qv4assembler.cpp @@ -52,6 +52,8 @@ #include <WTFStubs.h> #include <iostream> +#include <QBuffer> +#include <QCoreApplication> #if ENABLE(ASSEMBLER) @@ -146,11 +148,11 @@ bool CompilationUnit::memoryMapCode(QString *errorString) const Assembler::VoidType Assembler::Void; -Assembler::Assembler(InstructionSelection *isel, IR::Function* function, QV4::ExecutableAllocator *executableAllocator) +Assembler::Assembler(QV4::Compiler::JSUnitGenerator *jsGenerator, IR::Function* function, QV4::ExecutableAllocator *executableAllocator) : _function(function) , _nextBlock(0) , _executableAllocator(executableAllocator) - , _isel(isel) + , _jsGenerator(jsGenerator) { _addrs.resize(_function->basicBlockCount()); _patches.resize(_function->basicBlockCount()); @@ -301,7 +303,7 @@ Assembler::Pointer Assembler::loadStringAddress(RegisterID reg, const QString &s loadPtr(Address(Assembler::EngineRegister, qOffsetOf(QV4::ExecutionEngine, current)), Assembler::ScratchRegister); loadPtr(Address(Assembler::ScratchRegister, qOffsetOf(QV4::Heap::ExecutionContext, compilationUnit)), Assembler::ScratchRegister); loadPtr(Address(Assembler::ScratchRegister, qOffsetOf(QV4::CompiledData::CompilationUnit, runtimeStrings)), reg); - const int id = _isel->registerString(string); + const int id = _jsGenerator->registerString(string); return Pointer(reg, id * sizeof(QV4::String*)); } @@ -314,13 +316,13 @@ Assembler::Address Assembler::loadConstant(const Primitive &v, RegisterID baseRe { loadPtr(Address(Assembler::EngineRegister, qOffsetOf(QV4::ExecutionEngine, current)), baseReg); loadPtr(Address(baseReg, qOffsetOf(QV4::Heap::ExecutionContext, constantTable)), baseReg); - const int index = _isel->jsUnitGenerator()->registerConstant(v.asReturnedValue()); + const int index = _jsGenerator->registerConstant(v.asReturnedValue()); return Address(baseReg, index * sizeof(QV4::Value)); } void Assembler::loadStringRef(RegisterID reg, const QString &string) { - const int id = _isel->registerString(string); + const int id = _jsGenerator->registerString(string); move(TrustedImm32(id), reg); } @@ -496,4 +498,174 @@ void Assembler::setStackLayout(int maxArgCountForBuiltins, int regularRegistersT _stackLayout.reset(new StackLayout(_function, maxArgCountForBuiltins, regularRegistersToSave, fpRegistersToSave)); } + +namespace { +class QIODevicePrintStream: public FilePrintStream +{ + Q_DISABLE_COPY(QIODevicePrintStream) + +public: + explicit QIODevicePrintStream(QIODevice *dest) + : FilePrintStream(0) + , dest(dest) + , buf(4096, '0') + { + Q_ASSERT(dest); + } + + ~QIODevicePrintStream() + {} + + void vprintf(const char* format, va_list argList) WTF_ATTRIBUTE_PRINTF(2, 0) + { + const int written = qvsnprintf(buf.data(), buf.size(), format, argList); + if (written > 0) + dest->write(buf.constData(), written); + memset(buf.data(), 0, qMin(written, buf.size())); + } + + void flush() + {} + +private: + QIODevice *dest; + QByteArray buf; +}; +} // anonymous namespace + +static void printDisassembledOutputWithCalls(QByteArray processedOutput, const QHash<void*, const char*>& functions) +{ + for (QHash<void*, const char*>::ConstIterator it = functions.begin(), end = functions.end(); + it != end; ++it) { + const QByteArray ptrString = "0x" + QByteArray::number(quintptr(it.key()), 16); + int idx = processedOutput.indexOf(ptrString); + if (idx < 0) + continue; + idx = processedOutput.lastIndexOf('\n', idx); + if (idx < 0) + continue; + processedOutput = processedOutput.insert(idx, QByteArrayLiteral(" ; call ") + it.value()); + } + + qDebug("%s", processedOutput.constData()); +} + +#if defined(Q_OS_LINUX) +static FILE *pmap; + +static void qt_closePmap() +{ + if (pmap) { + fclose(pmap); + pmap = 0; + } +} + +#endif + +JSC::MacroAssemblerCodeRef Assembler::link(int *codeSize) +{ + Label endOfCode = label(); + + { + for (size_t i = 0, ei = _patches.size(); i != ei; ++i) { + Label target = _addrs.at(i); + Q_ASSERT(target.isSet()); + for (Jump jump : qAsConst(_patches.at(i))) + jump.linkTo(target, this); + } + } + + JSC::JSGlobalData dummy(_executableAllocator); + JSC::LinkBuffer linkBuffer(dummy, this, 0); + + for (const DataLabelPatch &p : qAsConst(_dataLabelPatches)) + linkBuffer.patch(p.dataLabel, linkBuffer.locationOf(p.target)); + + // link exception handlers + for (Jump jump : qAsConst(exceptionPropagationJumps)) + linkBuffer.link(jump, linkBuffer.locationOf(exceptionReturnLabel)); + + { + for (size_t i = 0, ei = _labelPatches.size(); i != ei; ++i) { + Label target = _addrs.at(i); + Q_ASSERT(target.isSet()); + for (DataLabelPtr label : _labelPatches.at(i)) + linkBuffer.patch(label, linkBuffer.locationOf(target)); + } + } + + *codeSize = linkBuffer.offsetOf(endOfCode); + + QByteArray name; + + JSC::MacroAssemblerCodeRef codeRef; + + static const bool showCode = qEnvironmentVariableIsSet("QV4_SHOW_ASM"); + if (showCode) { + QHash<void*, const char*> functions; +#ifndef QT_NO_DEBUG + for (CallInfo call : qAsConst(_callInfos)) + functions[linkBuffer.locationOf(call.label).dataLocation()] = call.functionName; +#endif + + QBuffer buf; + buf.open(QIODevice::WriteOnly); + WTF::setDataFile(new QIODevicePrintStream(&buf)); + + name = _function->name->toUtf8(); + if (name.isEmpty()) + name = "IR::Function(0x" + QByteArray::number(quintptr(_function), 16) + ')'; + codeRef = linkBuffer.finalizeCodeWithDisassembly("%s", name.data()); + + WTF::setDataFile(stderr); + printDisassembledOutputWithCalls(buf.data(), functions); + } else { + codeRef = linkBuffer.finalizeCodeWithoutDisassembly(); + } + +#if defined(Q_OS_LINUX) + // This implements writing of JIT'd addresses so that perf can find the + // symbol names. + // + // Perf expects the mapping to be in a certain place and have certain + // content, for more information, see: + // https://github.com/torvalds/linux/blob/master/tools/perf/Documentation/jit-interface.txt + static bool doProfile = !qEnvironmentVariableIsEmpty("QV4_PROFILE_WRITE_PERF_MAP"); + static bool profileInitialized = false; + if (doProfile && !profileInitialized) { + profileInitialized = true; + + char pname[PATH_MAX]; + snprintf(pname, PATH_MAX - 1, "/tmp/perf-%lu.map", + (unsigned long)QCoreApplication::applicationPid()); + + pmap = fopen(pname, "w"); + if (!pmap) + qWarning("QV4: Can't write %s, call stacks will not contain JavaScript function names", pname); + + // make sure we clean up nicely + std::atexit(qt_closePmap); + } + + if (pmap) { + // this may have been pre-populated, if QV4_SHOW_ASM was on + if (name.isEmpty()) { + name = _function->name->toUtf8(); + if (name.isEmpty()) + name = "IR::Function(0x" + QByteArray::number(quintptr(_function), 16) + ')'; + } + + fprintf(pmap, "%llx %x %.*s\n", + (long long unsigned int)codeRef.code().executableAddress(), + *codeSize, + name.length(), + name.constData()); + fflush(pmap); + } +#endif + + return codeRef; +} + #endif diff --git a/src/qml/jit/qv4assembler_p.h b/src/qml/jit/qv4assembler_p.h index 94478cd9cd..de9c246ed6 100644 --- a/src/qml/jit/qv4assembler_p.h +++ b/src/qml/jit/qv4assembler_p.h @@ -111,7 +111,7 @@ class Assembler : public JSC::MacroAssembler, public TargetPlatform Q_DISABLE_COPY(Assembler) public: - Assembler(InstructionSelection *isel, IR::Function* function, QV4::ExecutableAllocator *executableAllocator); + Assembler(QV4::Compiler::JSUnitGenerator *jsGenerator, IR::Function* function, QV4::ExecutableAllocator *executableAllocator); // Explicit type to allow distinguishing between // pushing an address itself or the value it points @@ -1092,7 +1092,7 @@ private: IR::BasicBlock *_nextBlock; QV4::ExecutableAllocator *_executableAllocator; - InstructionSelection *_isel; + QV4::Compiler::JSUnitGenerator *_jsGenerator; }; template <typename Result, typename Source> diff --git a/src/qml/jit/qv4binop.cpp b/src/qml/jit/qv4binop.cpp index 9c535bb0bb..d2758c4a47 100644 --- a/src/qml/jit/qv4binop.cpp +++ b/src/qml/jit/qv4binop.cpp @@ -112,7 +112,7 @@ void Binop::generate(IR::Expr *lhs, IR::Expr *rhs, IR::Expr *target) return; } - Assembler::Jump done; + Jump done; if (lhs->type != IR::StringType && rhs->type != IR::StringType) done = genInlineBinop(lhs, rhs, target); @@ -129,13 +129,13 @@ void Binop::generate(IR::Expr *lhs, IR::Expr *rhs, IR::Expr *target) RuntimeCall context(info.contextImplementation); if (fallBack.isValid()) { as->generateFunctionCallImp(info.needsExceptionCheck, target, info.name, fallBack, - Assembler::PointerToValue(lhs), - Assembler::PointerToValue(rhs)); + PointerToValue(lhs), + PointerToValue(rhs)); } else if (context.isValid()) { as->generateFunctionCallImp(info.needsExceptionCheck, target, info.name, context, Assembler::EngineRegister, - Assembler::PointerToValue(lhs), - Assembler::PointerToValue(rhs)); + PointerToValue(lhs), + PointerToValue(rhs)); } else { Q_ASSERT(!"unreachable"); } @@ -148,9 +148,9 @@ void Binop::generate(IR::Expr *lhs, IR::Expr *rhs, IR::Expr *target) void Binop::doubleBinop(IR::Expr *lhs, IR::Expr *rhs, IR::Expr *target) { IR::Temp *targetTemp = target->asTemp(); - Assembler::FPRegisterID targetReg; + FPRegisterID targetReg; if (targetTemp && targetTemp->kind == IR::Temp::PhysicalRegister) - targetReg = (Assembler::FPRegisterID) targetTemp->index; + targetReg = (FPRegisterID) targetTemp->index; else targetReg = Assembler::FPGpr0; @@ -162,7 +162,7 @@ void Binop::doubleBinop(IR::Expr *lhs, IR::Expr *rhs, IR::Expr *target) #if CPU(X86) if (IR::Const *c = rhs->asConst()) { // Y = X + constant -> Y = X; Y += [constant-address] as->moveDouble(as->toDoubleRegister(lhs, targetReg), targetReg); - Assembler::Address addr = as->loadConstant(c, Assembler::ScratchRegister); + Address addr = as->loadConstant(c, Assembler::ScratchRegister); as->addDouble(addr, targetReg); break; } @@ -184,7 +184,7 @@ void Binop::doubleBinop(IR::Expr *lhs, IR::Expr *rhs, IR::Expr *target) #if CPU(X86) if (IR::Const *c = rhs->asConst()) { // Y = X * constant -> Y = X; Y *= [constant-address] as->moveDouble(as->toDoubleRegister(lhs, targetReg), targetReg); - Assembler::Address addr = as->loadConstant(c, Assembler::ScratchRegister); + Address addr = as->loadConstant(c, Assembler::ScratchRegister); as->mulDouble(addr, targetReg); break; } @@ -203,7 +203,7 @@ void Binop::doubleBinop(IR::Expr *lhs, IR::Expr *rhs, IR::Expr *target) #if CPU(X86) if (IR::Const *c = rhs->asConst()) { // Y = X - constant -> Y = X; Y -= [constant-address] as->moveDouble(as->toDoubleRegister(lhs, targetReg), targetReg); - Assembler::Address addr = as->loadConstant(c, Assembler::ScratchRegister); + Address addr = as->loadConstant(c, Assembler::ScratchRegister); as->subDouble(addr, targetReg); break; } @@ -231,7 +231,7 @@ void Binop::doubleBinop(IR::Expr *lhs, IR::Expr *rhs, IR::Expr *target) #if CPU(X86) if (IR::Const *c = rhs->asConst()) { // Y = X / constant -> Y = X; Y /= [constant-address] as->moveDouble(as->toDoubleRegister(lhs, targetReg), targetReg); - Assembler::Address addr = as->loadConstant(c, Assembler::ScratchRegister); + Address addr = as->loadConstant(c, Assembler::ScratchRegister); as->divDouble(addr, targetReg); break; } @@ -258,9 +258,9 @@ void Binop::doubleBinop(IR::Expr *lhs, IR::Expr *rhs, IR::Expr *target) default: { Q_ASSERT(target->type == IR::BoolType); - Assembler::Jump trueCase = as->branchDouble(false, op, lhs, rhs); + Jump trueCase = as->branchDouble(false, op, lhs, rhs); as->storeBool(false, target); - Assembler::Jump done = as->jump(); + Jump done = as->jump(); trueCase.link(as); as->storeBool(true, target); done.link(as); @@ -305,13 +305,13 @@ bool Binop::int32Binop(IR::Expr *leftSource, IR::Expr *rightSource, IR::Expr *ta bool inplaceOpWithAddress = false; IR::Temp *targetTemp = target->asTemp(); - Assembler::RegisterID targetReg = Assembler::ReturnValueRegister; + RegisterID targetReg = Assembler::ReturnValueRegister; if (targetTemp && targetTemp->kind == IR::Temp::PhysicalRegister) { IR::Temp *rhs = rightSource->asTemp(); if (!rhs || rhs->kind != IR::Temp::PhysicalRegister || rhs->index != targetTemp->index) { // We try to load leftSource into the target's register, but we can't do that if // the target register is the same as rightSource. - targetReg = (Assembler::RegisterID) targetTemp->index; + targetReg = (RegisterID) targetTemp->index; } else if (rhs && rhs->kind == IR::Temp::PhysicalRegister && targetTemp->index == rhs->index) { // However, if the target register is the same as the rightSource register, we can flip // the operands for certain operations. @@ -323,7 +323,7 @@ bool Binop::int32Binop(IR::Expr *leftSource, IR::Expr *rightSource, IR::Expr *ta case IR::OpMul: // X = Y op X -> X = X op Y (or rephrased: X op= Y (so an in-place operation)) std::swap(leftSource, rightSource); - targetReg = (Assembler::RegisterID) targetTemp->index; + targetReg = (RegisterID) targetTemp->index; break; case IR::OpLShift: @@ -368,7 +368,7 @@ bool Binop::int32Binop(IR::Expr *leftSource, IR::Expr *rightSource, IR::Expr *ta && targetTemp->kind == IR::Temp::PhysicalRegister && targetTemp->index == rightSource->asTemp()->index) { // X = Y - X -> Tmp = X; X = Y; X -= Tmp - targetReg = (Assembler::RegisterID) targetTemp->index; + targetReg = (RegisterID) targetTemp->index; as->move(targetReg, Assembler::ScratchRegister); as->move(as->toInt32Register(leftSource, targetReg), targetReg); as->sub32(Assembler::ScratchRegister, targetReg); @@ -384,7 +384,7 @@ bool Binop::int32Binop(IR::Expr *leftSource, IR::Expr *rightSource, IR::Expr *ta case IR::OpURShift: if (IR::Const *c = rightSource->asConst()) { if ((QV4::Primitive::toUInt32(c->value) & 0x1f) == 0) { - Assembler::RegisterID r = as->toInt32Register(leftSource, targetReg); + RegisterID r = as->toInt32Register(leftSource, targetReg); as->storeInt32(r, target); return true; } @@ -395,10 +395,10 @@ bool Binop::int32Binop(IR::Expr *leftSource, IR::Expr *rightSource, IR::Expr *ta break; } - Assembler::RegisterID l = as->toInt32Register(leftSource, targetReg); + RegisterID l = as->toInt32Register(leftSource, targetReg); if (IR::Const *c = rightSource->asConst()) { // All cases of Y = X op Const - Assembler::TrustedImm32 r(int(c->value)); - Assembler::TrustedImm32 ur(QV4::Primitive::toUInt32(c->value) & 0x1f); + TrustedImm32 r(int(c->value)); + TrustedImm32 ur(QV4::Primitive::toUInt32(c->value) & 0x1f); switch (op) { case IR::OpBitAnd: as->and32(r, l, targetReg); break; @@ -419,7 +419,7 @@ bool Binop::int32Binop(IR::Expr *leftSource, IR::Expr *rightSource, IR::Expr *ta return false; } } else if (inplaceOpWithAddress) { // All cases of X = X op [address-of-Y] - Assembler::Pointer rhsAddr = as->loadAddress(Assembler::ScratchRegister, rightSource); + Pointer rhsAddr = as->loadAddress(Assembler::ScratchRegister, rightSource); switch (op) { case IR::OpBitAnd: as->and32(rhsAddr, targetReg); break; case IR::OpBitOr: as->or32 (rhsAddr, targetReg); break; @@ -433,7 +433,7 @@ bool Binop::int32Binop(IR::Expr *leftSource, IR::Expr *rightSource, IR::Expr *ta return false; } } else { // All cases of Z = X op Y - Assembler::RegisterID r = as->toInt32Register(rightSource, Assembler::ScratchRegister); + RegisterID r = as->toInt32Register(rightSource, Assembler::ScratchRegister); switch (op) { case IR::OpBitAnd: as->and32(l, r, targetReg); break; case IR::OpBitOr: as->or32 (l, r, targetReg); break; @@ -452,10 +452,10 @@ bool Binop::int32Binop(IR::Expr *leftSource, IR::Expr *rightSource, IR::Expr *ta // Not all CPUs accept shifts over more than 31 bits, and some CPUs (like ARM) will do // surprising stuff when shifting over 0 bits. #define CHECK_RHS(op) { \ - as->and32(Assembler::TrustedImm32(0x1f), r, Assembler::ScratchRegister); \ - Assembler::Jump notZero = as->branch32(Assembler::NotEqual, Assembler::ScratchRegister, Assembler::TrustedImm32(0)); \ + as->and32(TrustedImm32(0x1f), r, Assembler::ScratchRegister); \ + Jump notZero = as->branch32(RelationalCondition::NotEqual, Assembler::ScratchRegister, TrustedImm32(0)); \ as->move(l, targetReg); \ - Assembler::Jump done = as->jump(); \ + Jump done = as->jump(); \ notZero.link(as); \ op; \ done.link(as); \ @@ -493,7 +493,7 @@ static inline Assembler::FPRegisterID getFreeFPReg(IR::Expr *shouldNotOverlap, u Assembler::Jump Binop::genInlineBinop(IR::Expr *leftSource, IR::Expr *rightSource, IR::Expr *target) { - Assembler::Jump done; + Jump done; // Try preventing a call for a few common binary operations. This is used in two cases: // - no register allocation was performed (not available for the platform, or the IR was @@ -505,10 +505,10 @@ Assembler::Jump Binop::genInlineBinop(IR::Expr *leftSource, IR::Expr *rightSourc // register. switch (op) { case IR::OpAdd: { - Assembler::FPRegisterID lReg = getFreeFPReg(rightSource, 2); - Assembler::FPRegisterID rReg = getFreeFPReg(leftSource, 4); - Assembler::Jump leftIsNoDbl = as->genTryDoubleConversion(leftSource, lReg); - Assembler::Jump rightIsNoDbl = as->genTryDoubleConversion(rightSource, rReg); + FPRegisterID lReg = getFreeFPReg(rightSource, 2); + FPRegisterID rReg = getFreeFPReg(leftSource, 4); + Jump leftIsNoDbl = as->genTryDoubleConversion(leftSource, lReg); + Jump rightIsNoDbl = as->genTryDoubleConversion(rightSource, rReg); as->addDouble(rReg, lReg); as->storeDouble(lReg, target); @@ -520,10 +520,10 @@ Assembler::Jump Binop::genInlineBinop(IR::Expr *leftSource, IR::Expr *rightSourc rightIsNoDbl.link(as); } break; case IR::OpMul: { - Assembler::FPRegisterID lReg = getFreeFPReg(rightSource, 2); - Assembler::FPRegisterID rReg = getFreeFPReg(leftSource, 4); - Assembler::Jump leftIsNoDbl = as->genTryDoubleConversion(leftSource, lReg); - Assembler::Jump rightIsNoDbl = as->genTryDoubleConversion(rightSource, rReg); + FPRegisterID lReg = getFreeFPReg(rightSource, 2); + FPRegisterID rReg = getFreeFPReg(leftSource, 4); + Jump leftIsNoDbl = as->genTryDoubleConversion(leftSource, lReg); + Jump rightIsNoDbl = as->genTryDoubleConversion(rightSource, rReg); as->mulDouble(rReg, lReg); as->storeDouble(lReg, target); @@ -535,10 +535,10 @@ Assembler::Jump Binop::genInlineBinop(IR::Expr *leftSource, IR::Expr *rightSourc rightIsNoDbl.link(as); } break; case IR::OpSub: { - Assembler::FPRegisterID lReg = getFreeFPReg(rightSource, 2); - Assembler::FPRegisterID rReg = getFreeFPReg(leftSource, 4); - Assembler::Jump leftIsNoDbl = as->genTryDoubleConversion(leftSource, lReg); - Assembler::Jump rightIsNoDbl = as->genTryDoubleConversion(rightSource, rReg); + FPRegisterID lReg = getFreeFPReg(rightSource, 2); + FPRegisterID rReg = getFreeFPReg(leftSource, 4); + Jump leftIsNoDbl = as->genTryDoubleConversion(leftSource, lReg); + Jump rightIsNoDbl = as->genTryDoubleConversion(rightSource, rReg); as->subDouble(rReg, lReg); as->storeDouble(lReg, target); @@ -550,10 +550,10 @@ Assembler::Jump Binop::genInlineBinop(IR::Expr *leftSource, IR::Expr *rightSourc rightIsNoDbl.link(as); } break; case IR::OpDiv: { - Assembler::FPRegisterID lReg = getFreeFPReg(rightSource, 2); - Assembler::FPRegisterID rReg = getFreeFPReg(leftSource, 4); - Assembler::Jump leftIsNoDbl = as->genTryDoubleConversion(leftSource, lReg); - Assembler::Jump rightIsNoDbl = as->genTryDoubleConversion(rightSource, rReg); + FPRegisterID lReg = getFreeFPReg(rightSource, 2); + FPRegisterID rReg = getFreeFPReg(leftSource, 4); + Jump leftIsNoDbl = as->genTryDoubleConversion(leftSource, lReg); + Jump rightIsNoDbl = as->genTryDoubleConversion(rightSource, rReg); as->divDouble(rReg, lReg); as->storeDouble(lReg, target); diff --git a/src/qml/jit/qv4binop_p.h b/src/qml/jit/qv4binop_p.h index 37601f54ba..3742e99e5a 100644 --- a/src/qml/jit/qv4binop_p.h +++ b/src/qml/jit/qv4binop_p.h @@ -67,13 +67,23 @@ struct Binop { , op(operation) {} + using Jump = Assembler::Jump; + using Address = Assembler::Address; + using RegisterID = Assembler::RegisterID; + using FPRegisterID = Assembler::FPRegisterID; + using TrustedImm32 = Assembler::TrustedImm32; + using ResultCondition = Assembler::ResultCondition; + using RelationalCondition = Assembler::RelationalCondition; + using Pointer = Assembler::Pointer; + using PointerToValue = Assembler::PointerToValue; + void generate(IR::Expr *lhs, IR::Expr *rhs, IR::Expr *target); void doubleBinop(IR::Expr *lhs, IR::Expr *rhs, IR::Expr *target); bool int32Binop(IR::Expr *leftSource, IR::Expr *rightSource, IR::Expr *target); - Assembler::Jump genInlineBinop(IR::Expr *leftSource, IR::Expr *rightSource, IR::Expr *target); + Jump genInlineBinop(IR::Expr *leftSource, IR::Expr *rightSource, IR::Expr *target); - typedef Assembler::Jump (Binop::*MemRegOp)(Assembler::Address, Assembler::RegisterID); - typedef Assembler::Jump (Binop::*ImmRegOp)(Assembler::TrustedImm32, Assembler::RegisterID); + typedef Jump (Binop::*MemRegOp)(Address, RegisterID); + typedef Jump (Binop::*ImmRegOp)(TrustedImm32, RegisterID); struct OpInfo { const char *name; @@ -88,97 +98,97 @@ struct Binop { static const OpInfo &operation(IR::AluOp operation) { return operations[operation]; } - Assembler::Jump inline_add32(Assembler::Address addr, Assembler::RegisterID reg) + Jump inline_add32(Address addr, RegisterID reg) { #if HAVE(ALU_OPS_WITH_MEM_OPERAND) - return as->branchAdd32(Assembler::Overflow, addr, reg); + return as->branchAdd32(ResultCondition::Overflow, addr, reg); #else as->load32(addr, Assembler::ScratchRegister); - return as->branchAdd32(Assembler::Overflow, Assembler::ScratchRegister, reg); + return as->branchAdd32(ResultCondition::Overflow, Assembler::ScratchRegister, reg); #endif } - Assembler::Jump inline_add32(Assembler::TrustedImm32 imm, Assembler::RegisterID reg) + Jump inline_add32(TrustedImm32 imm, RegisterID reg) { - return as->branchAdd32(Assembler::Overflow, imm, reg); + return as->branchAdd32(ResultCondition::Overflow, imm, reg); } - Assembler::Jump inline_sub32(Assembler::Address addr, Assembler::RegisterID reg) + Jump inline_sub32(Address addr, RegisterID reg) { #if HAVE(ALU_OPS_WITH_MEM_OPERAND) - return as->branchSub32(Assembler::Overflow, addr, reg); + return as->branchSub32(ResultCondition::Overflow, addr, reg); #else as->load32(addr, Assembler::ScratchRegister); - return as->branchSub32(Assembler::Overflow, Assembler::ScratchRegister, reg); + return as->branchSub32(ResultCondition::Overflow, Assembler::ScratchRegister, reg); #endif } - Assembler::Jump inline_sub32(Assembler::TrustedImm32 imm, Assembler::RegisterID reg) + Jump inline_sub32(TrustedImm32 imm, RegisterID reg) { - return as->branchSub32(Assembler::Overflow, imm, reg); + return as->branchSub32(ResultCondition::Overflow, imm, reg); } - Assembler::Jump inline_mul32(Assembler::Address addr, Assembler::RegisterID reg) + Jump inline_mul32(Address addr, RegisterID reg) { #if HAVE(ALU_OPS_WITH_MEM_OPERAND) return as->branchMul32(Assembler::Overflow, addr, reg); #else as->load32(addr, Assembler::ScratchRegister); - return as->branchMul32(Assembler::Overflow, Assembler::ScratchRegister, reg); + return as->branchMul32(ResultCondition::Overflow, Assembler::ScratchRegister, reg); #endif } - Assembler::Jump inline_mul32(Assembler::TrustedImm32 imm, Assembler::RegisterID reg) + Jump inline_mul32(TrustedImm32 imm, RegisterID reg) { - return as->branchMul32(Assembler::Overflow, imm, reg, reg); + return as->branchMul32(ResultCondition::Overflow, imm, reg, reg); } - Assembler::Jump inline_shl32(Assembler::Address addr, Assembler::RegisterID reg) + Jump inline_shl32(Address addr, RegisterID reg) { as->load32(addr, Assembler::ScratchRegister); - as->and32(Assembler::TrustedImm32(0x1f), Assembler::ScratchRegister); + as->and32(TrustedImm32(0x1f), Assembler::ScratchRegister); as->lshift32(Assembler::ScratchRegister, reg); - return Assembler::Jump(); + return Jump(); } - Assembler::Jump inline_shl32(Assembler::TrustedImm32 imm, Assembler::RegisterID reg) + Jump inline_shl32(TrustedImm32 imm, RegisterID reg) { imm.m_value &= 0x1f; as->lshift32(imm, reg); - return Assembler::Jump(); + return Jump(); } - Assembler::Jump inline_shr32(Assembler::Address addr, Assembler::RegisterID reg) + Jump inline_shr32(Address addr, RegisterID reg) { as->load32(addr, Assembler::ScratchRegister); - as->and32(Assembler::TrustedImm32(0x1f), Assembler::ScratchRegister); + as->and32(TrustedImm32(0x1f), Assembler::ScratchRegister); as->rshift32(Assembler::ScratchRegister, reg); - return Assembler::Jump(); + return Jump(); } - Assembler::Jump inline_shr32(Assembler::TrustedImm32 imm, Assembler::RegisterID reg) + Jump inline_shr32(TrustedImm32 imm, RegisterID reg) { imm.m_value &= 0x1f; as->rshift32(imm, reg); - return Assembler::Jump(); + return Jump(); } - Assembler::Jump inline_ushr32(Assembler::Address addr, Assembler::RegisterID reg) + Jump inline_ushr32(Address addr, RegisterID reg) { as->load32(addr, Assembler::ScratchRegister); - as->and32(Assembler::TrustedImm32(0x1f), Assembler::ScratchRegister); + as->and32(TrustedImm32(0x1f), Assembler::ScratchRegister); as->urshift32(Assembler::ScratchRegister, reg); - return as->branchTest32(Assembler::Signed, reg, reg); + return as->branchTest32(ResultCondition::Signed, reg, reg); } - Assembler::Jump inline_ushr32(Assembler::TrustedImm32 imm, Assembler::RegisterID reg) + Jump inline_ushr32(TrustedImm32 imm, RegisterID reg) { imm.m_value &= 0x1f; as->urshift32(imm, reg); - return as->branchTest32(Assembler::Signed, reg, reg); + return as->branchTest32(ResultCondition::Signed, reg, reg); } - Assembler::Jump inline_and32(Assembler::Address addr, Assembler::RegisterID reg) + Jump inline_and32(Address addr, RegisterID reg) { #if HAVE(ALU_OPS_WITH_MEM_OPERAND) as->and32(addr, reg); @@ -186,16 +196,16 @@ struct Binop { as->load32(addr, Assembler::ScratchRegister); as->and32(Assembler::ScratchRegister, reg); #endif - return Assembler::Jump(); + return Jump(); } - Assembler::Jump inline_and32(Assembler::TrustedImm32 imm, Assembler::RegisterID reg) + Jump inline_and32(TrustedImm32 imm, RegisterID reg) { as->and32(imm, reg); - return Assembler::Jump(); + return Jump(); } - Assembler::Jump inline_or32(Assembler::Address addr, Assembler::RegisterID reg) + Jump inline_or32(Address addr, RegisterID reg) { #if HAVE(ALU_OPS_WITH_MEM_OPERAND) as->or32(addr, reg); @@ -203,16 +213,16 @@ struct Binop { as->load32(addr, Assembler::ScratchRegister); as->or32(Assembler::ScratchRegister, reg); #endif - return Assembler::Jump(); + return Jump(); } - Assembler::Jump inline_or32(Assembler::TrustedImm32 imm, Assembler::RegisterID reg) + Jump inline_or32(TrustedImm32 imm, RegisterID reg) { as->or32(imm, reg); - return Assembler::Jump(); + return Jump(); } - Assembler::Jump inline_xor32(Assembler::Address addr, Assembler::RegisterID reg) + Jump inline_xor32(Address addr, RegisterID reg) { #if HAVE(ALU_OPS_WITH_MEM_OPERAND) as->xor32(addr, reg); @@ -220,13 +230,13 @@ struct Binop { as->load32(addr, Assembler::ScratchRegister); as->xor32(Assembler::ScratchRegister, reg); #endif - return Assembler::Jump(); + return Jump(); } - Assembler::Jump inline_xor32(Assembler::TrustedImm32 imm, Assembler::RegisterID reg) + Jump inline_xor32(TrustedImm32 imm, RegisterID reg) { as->xor32(imm, reg); - return Assembler::Jump(); + return Jump(); } diff --git a/src/qml/jit/qv4isel_masm.cpp b/src/qml/jit/qv4isel_masm.cpp index c5d612ae65..20752b5c34 100644 --- a/src/qml/jit/qv4isel_masm.cpp +++ b/src/qml/jit/qv4isel_masm.cpp @@ -68,175 +68,6 @@ using namespace QV4; using namespace QV4::JIT; -namespace { -class QIODevicePrintStream: public FilePrintStream -{ - Q_DISABLE_COPY(QIODevicePrintStream) - -public: - explicit QIODevicePrintStream(QIODevice *dest) - : FilePrintStream(0) - , dest(dest) - , buf(4096, '0') - { - Q_ASSERT(dest); - } - - ~QIODevicePrintStream() - {} - - void vprintf(const char* format, va_list argList) WTF_ATTRIBUTE_PRINTF(2, 0) - { - const int written = qvsnprintf(buf.data(), buf.size(), format, argList); - if (written > 0) - dest->write(buf.constData(), written); - memset(buf.data(), 0, qMin(written, buf.size())); - } - - void flush() - {} - -private: - QIODevice *dest; - QByteArray buf; -}; -} // anonymous namespace - -static void printDisassembledOutputWithCalls(QByteArray processedOutput, const QHash<void*, const char*>& functions) -{ - for (QHash<void*, const char*>::ConstIterator it = functions.begin(), end = functions.end(); - it != end; ++it) { - const QByteArray ptrString = "0x" + QByteArray::number(quintptr(it.key()), 16); - int idx = processedOutput.indexOf(ptrString); - if (idx < 0) - continue; - idx = processedOutput.lastIndexOf('\n', idx); - if (idx < 0) - continue; - processedOutput = processedOutput.insert(idx, QByteArrayLiteral(" ; call ") + it.value()); - } - - qDebug("%s", processedOutput.constData()); -} - -#if defined(Q_OS_LINUX) -static FILE *pmap; - -static void qt_closePmap() -{ - if (pmap) { - fclose(pmap); - pmap = 0; - } -} - -#endif - -JSC::MacroAssemblerCodeRef Assembler::link(int *codeSize) -{ - Label endOfCode = label(); - - { - for (size_t i = 0, ei = _patches.size(); i != ei; ++i) { - Label target = _addrs.at(i); - Q_ASSERT(target.isSet()); - for (Jump jump : qAsConst(_patches.at(i))) - jump.linkTo(target, this); - } - } - - JSC::JSGlobalData dummy(_executableAllocator); - JSC::LinkBuffer linkBuffer(dummy, this, 0); - - for (const DataLabelPatch &p : qAsConst(_dataLabelPatches)) - linkBuffer.patch(p.dataLabel, linkBuffer.locationOf(p.target)); - - // link exception handlers - for (Jump jump : qAsConst(exceptionPropagationJumps)) - linkBuffer.link(jump, linkBuffer.locationOf(exceptionReturnLabel)); - - { - for (size_t i = 0, ei = _labelPatches.size(); i != ei; ++i) { - Label target = _addrs.at(i); - Q_ASSERT(target.isSet()); - for (DataLabelPtr label : _labelPatches.at(i)) - linkBuffer.patch(label, linkBuffer.locationOf(target)); - } - } - - *codeSize = linkBuffer.offsetOf(endOfCode); - - QByteArray name; - - JSC::MacroAssemblerCodeRef codeRef; - - static const bool showCode = qEnvironmentVariableIsSet("QV4_SHOW_ASM"); - if (showCode) { - QHash<void*, const char*> functions; -#ifndef QT_NO_DEBUG - for (CallInfo call : qAsConst(_callInfos)) - functions[linkBuffer.locationOf(call.label).dataLocation()] = call.functionName; -#endif - - QBuffer buf; - buf.open(QIODevice::WriteOnly); - WTF::setDataFile(new QIODevicePrintStream(&buf)); - - name = _function->name->toUtf8(); - if (name.isEmpty()) - name = "IR::Function(0x" + QByteArray::number(quintptr(_function), 16) + ')'; - codeRef = linkBuffer.finalizeCodeWithDisassembly("%s", name.data()); - - WTF::setDataFile(stderr); - printDisassembledOutputWithCalls(buf.data(), functions); - } else { - codeRef = linkBuffer.finalizeCodeWithoutDisassembly(); - } - -#if defined(Q_OS_LINUX) - // This implements writing of JIT'd addresses so that perf can find the - // symbol names. - // - // Perf expects the mapping to be in a certain place and have certain - // content, for more information, see: - // https://github.com/torvalds/linux/blob/master/tools/perf/Documentation/jit-interface.txt - static bool doProfile = !qEnvironmentVariableIsEmpty("QV4_PROFILE_WRITE_PERF_MAP"); - static bool profileInitialized = false; - if (doProfile && !profileInitialized) { - profileInitialized = true; - - char pname[PATH_MAX]; - snprintf(pname, PATH_MAX - 1, "/tmp/perf-%lu.map", - (unsigned long)QCoreApplication::applicationPid()); - - pmap = fopen(pname, "w"); - if (!pmap) - qWarning("QV4: Can't write %s, call stacks will not contain JavaScript function names", pname); - - // make sure we clean up nicely - std::atexit(qt_closePmap); - } - - if (pmap) { - // this may have been pre-populated, if QV4_SHOW_ASM was on - if (name.isEmpty()) { - name = _function->name->toUtf8(); - if (name.isEmpty()) - name = "IR::Function(0x" + QByteArray::number(quintptr(_function), 16) + ')'; - } - - fprintf(pmap, "%llx %x %.*s\n", - (long long unsigned int)codeRef.code().executableAddress(), - *codeSize, - name.length(), - name.constData()); - fflush(pmap); - } -#endif - - return codeRef; -} - InstructionSelection::InstructionSelection(QQmlEnginePrivate *qmlEngine, QV4::ExecutableAllocator *execAllocator, IR::Module *module, Compiler::JSUnitGenerator *jsGenerator, EvalISelFactory *iselFactory) : EvalInstructionSelection(execAllocator, module, jsGenerator, iselFactory) , _block(0) @@ -278,7 +109,7 @@ void InstructionSelection::run(int functionIndex) qSwap(_removableJumps, removableJumps); Assembler* oldAssembler = _as; - _as = new Assembler(this, _function, executableAllocator); + _as = new Assembler(jsGenerator, _function, executableAllocator); _as->setStackLayout(6, // 6 == max argc for calls to built-ins with an argument array regularRegistersToSave.size(), fpRegistersToSave.size()); diff --git a/src/qml/jit/qv4regalloc.cpp b/src/qml/jit/qv4regalloc.cpp index 63d542b5c8..3fb0815299 100644 --- a/src/qml/jit/qv4regalloc.cpp +++ b/src/qml/jit/qv4regalloc.cpp @@ -1087,12 +1087,12 @@ private: if (_info->def(it->temp()) != successorStart && !it->isSplitFromInterval()) { const int successorEnd = successor->terminator()->id(); const int idx = successor->in.indexOf(predecessor); - foreach (const Use &use, _info->uses(it->temp())) { + for (const Use &use : _info->uses(it->temp)) { if (use.pos == static_cast<unsigned>(successorStart)) { // only check the current edge, not all other possible ones. This is // important for phi nodes: they have uses that are only valid when // coming in over a specific edge. - foreach (Stmt *s, successor->statements()) { + for (Stmt *s : successor->statements()) { if (Phi *phi = s->asPhi()) { Q_ASSERT(it->temp().index != phi->targetTemp->index); Q_ASSERT(phi->d->incoming[idx]->asTemp() == 0 diff --git a/src/qml/jsapi/qjsvalue.cpp b/src/qml/jsapi/qjsvalue.cpp index b473e96286..bab2e633a7 100644 --- a/src/qml/jsapi/qjsvalue.cpp +++ b/src/qml/jsapi/qjsvalue.cpp @@ -73,7 +73,8 @@ For the object-based types (including Date and RegExp), use the newT() functions in QJSEngine (e.g. QJSEngine::newObject()) to create a QJSValue of the desired type. For the primitive types, - use one of the QJSValue constructor overloads. + use one of the QJSValue constructor overloads. For other types, e.g. + registered gadget types such as QPoint, you can use QJSEngine::toScriptValue. The methods named isT() (e.g. isBool(), isUndefined()) can be used to test if a value is of a certain type. The methods named diff --git a/src/qml/jsruntime/qv4engine.cpp b/src/qml/jsruntime/qv4engine.cpp index 8f2c5174da..a11f7f0875 100644 --- a/src/qml/jsruntime/qv4engine.cpp +++ b/src/qml/jsruntime/qv4engine.cpp @@ -158,8 +158,6 @@ ExecutionEngine::ExecutionEngine(EvalISelFactory *factory) } Q_ASSERT(maxCallDepth > 0); - MemoryManager::GCBlocker gcBlocker(memoryManager); - if (!factory) { #if QT_CONFIG(qml_interpreter) bool jitDisabled = true; diff --git a/src/qml/jsruntime/qv4global_p.h b/src/qml/jsruntime/qv4global_p.h index c37ad1668d..1dbc538be2 100644 --- a/src/qml/jsruntime/qv4global_p.h +++ b/src/qml/jsruntime/qv4global_p.h @@ -97,19 +97,19 @@ inline double trunc(double d) { return d > 0 ? floor(d) : ceil(d); } // // NOTE: This should match the logic in qv4targetplatform_p.h! -#if defined(Q_PROCESSOR_X86) && !defined(__ILP32__) \ +#if defined(Q_PROCESSOR_X86) && (QT_POINTER_SIZE == 4) \ && (defined(Q_OS_WIN) || defined(Q_OS_LINUX) || defined(Q_OS_QNX) || defined(Q_OS_FREEBSD)) # define V4_ENABLE_JIT -#elif defined(Q_PROCESSOR_X86_64) && !defined(__ILP32__) \ +#elif defined(Q_PROCESSOR_X86_64) && (QT_POINTER_SIZE == 8) \ && (defined(Q_OS_WIN) || defined(Q_OS_LINUX) || defined(Q_OS_MAC) || defined(Q_OS_FREEBSD)) # define V4_ENABLE_JIT -#elif defined(Q_PROCESSOR_ARM_32) +#elif defined(Q_PROCESSOR_ARM_32) && (QT_POINTER_SIZE == 4) # if defined(thumb2) || defined(__thumb2__) || ((defined(__thumb) || defined(__thumb__)) && __TARGET_ARCH_THUMB-0 == 4) # define V4_ENABLE_JIT # elif defined(__ARM_ARCH_ISA_THUMB) && __ARM_ARCH_ISA_THUMB == 2 // clang 3.5 and later will set this if the core supports the Thumb-2 ISA. # define V4_ENABLE_JIT # endif -#elif defined(Q_PROCESSOR_ARM_64) +#elif defined(Q_PROCESSOR_ARM_64) && (QT_POINTER_SIZE == 8) # if defined(Q_OS_LINUX) # define V4_ENABLE_JIT # endif diff --git a/src/qml/jsruntime/qv4profiling_p.h b/src/qml/jsruntime/qv4profiling_p.h index d27e853343..f75ac4d33a 100644 --- a/src/qml/jsruntime/qv4profiling_p.h +++ b/src/qml/jsruntime/qv4profiling_p.h @@ -158,12 +158,11 @@ public: FunctionCall &operator=(const FunctionCall &other) { if (&other != this) { - if (m_function) - m_function->compilationUnit->release(); + other.m_function->compilationUnit->addref(); + m_function->compilationUnit->release(); m_function = other.m_function; m_start = other.m_start; m_end = other.m_end; - m_function->compilationUnit->addref(); } return *this; } diff --git a/src/qml/jsruntime/qv4regexpobject.cpp b/src/qml/jsruntime/qv4regexpobject.cpp index 218695624b..41d8010fef 100644 --- a/src/qml/jsruntime/qv4regexpobject.cpp +++ b/src/qml/jsruntime/qv4regexpobject.cpp @@ -307,7 +307,8 @@ void RegExpCtor::markObjects(Heap::Base *that, ExecutionEngine *e) { RegExpCtor::Data *This = static_cast<RegExpCtor::Data *>(that); This->lastMatch.mark(e); - This->lastInput->mark(e); + if (This->lastInput) + This->lastInput->mark(e); FunctionObject::markObjects(that, e); } diff --git a/src/qml/jsruntime/qv4runtime.cpp b/src/qml/jsruntime/qv4runtime.cpp index d6c55926b1..023a739e33 100644 --- a/src/qml/jsruntime/qv4runtime.cpp +++ b/src/qml/jsruntime/qv4runtime.cpp @@ -499,6 +499,7 @@ Heap::String *RuntimeHelpers::convertToString(ExecutionEngine *engine, const Val { Scope scope(engine); ScopedValue prim(scope, RuntimeHelpers::toPrimitive(value, STRING_HINT)); + Q_ASSERT(!prim->isManaged() || prim->isString()); return RuntimeHelpers::convertToString(engine, prim); } case Value::Integer_Type: diff --git a/src/qml/jsruntime/qv4script.cpp b/src/qml/jsruntime/qv4script.cpp index b54177bee9..62145f36cc 100644 --- a/src/qml/jsruntime/qv4script.cpp +++ b/src/qml/jsruntime/qv4script.cpp @@ -88,8 +88,6 @@ void Script::parse() ExecutionEngine *v4 = scope->engine(); Scope valueScope(v4); - MemoryManager::GCBlocker gcBlocker(v4->memoryManager); - IR::Module module(v4->debugger() != 0); QQmlJS::Engine ee, *engine = ⅇ diff --git a/src/qml/jsruntime/qv4string.cpp b/src/qml/jsruntime/qv4string.cpp index 1efd8cb714..cde2131aab 100644 --- a/src/qml/jsruntime/qv4string.cpp +++ b/src/qml/jsruntime/qv4string.cpp @@ -102,6 +102,7 @@ void Heap::String::init(MemoryManager *mm, String *l, String *r) stringHash = UINT_MAX; largestSubLength = qMax(l->largestSubLength, r->largestSubLength); len = l->len + r->len; + Q_ASSERT(largestSubLength <= len); if (!l->largestSubLength && l->len > largestSubLength) largestSubLength = l->len; @@ -113,6 +114,15 @@ void Heap::String::init(MemoryManager *mm, String *l, String *r) simplifyString(); } +void Heap::String::destroy() { + if (!largestSubLength) { + mm->changeUnmanagedHeapSizeUsage(qptrdiff(-text->size) * (int)sizeof(QChar)); + if (!text->ref.deref()) + QStringData::deallocate(text); + } + Base::destroy(); +} + uint String::toUInt(bool *ok) const { *ok = true; @@ -151,7 +161,7 @@ void Heap::String::simplifyString() const text->ref.ref(); identifier = 0; largestSubLength = 0; - mm->growUnmanagedHeapSizeUsage(size_t(text->size) * sizeof(QChar)); + mm->changeUnmanagedHeapSizeUsage(qptrdiff(text->size) * (qptrdiff)sizeof(QChar)); } void Heap::String::append(const String *data, QChar *ch) diff --git a/src/qml/jsruntime/qv4string_p.h b/src/qml/jsruntime/qv4string_p.h index 4890a85724..5b0fd292d6 100644 --- a/src/qml/jsruntime/qv4string_p.h +++ b/src/qml/jsruntime/qv4string_p.h @@ -73,11 +73,7 @@ struct Q_QML_PRIVATE_EXPORT String : Base { #ifndef V4_BOOTSTRAP void init(MemoryManager *mm, const QString &text); void init(MemoryManager *mm, String *l, String *n); - void destroy() { - if (!largestSubLength && !text->ref.deref()) - QStringData::deallocate(text); - Base::destroy(); - } + void destroy(); void simplifyString() const; int length() const { Q_ASSERT((largestSubLength && diff --git a/src/qml/memory/qv4mm.cpp b/src/qml/memory/qv4mm.cpp index 606d3ec162..51eb82059a 100644 --- a/src/qml/memory/qv4mm.cpp +++ b/src/qml/memory/qv4mm.cpp @@ -194,10 +194,8 @@ struct MemoryManager::Data namespace { -bool sweepChunk(MemoryManager::Data::ChunkHeader *header, uint *itemsInUse, ExecutionEngine *engine, std::size_t *unmanagedHeapSize) +bool sweepChunk(MemoryManager::Data::ChunkHeader *header, uint *itemsInUse, ExecutionEngine *engine) { - Q_ASSERT(unmanagedHeapSize); - bool isEmpty = true; Heap::Base *tail = &header->freeItems; // qDebug("chunkStart @ %p, size=%x, pos=%x", header->itemStart, header->itemSize, header->itemSize>>4); @@ -222,13 +220,6 @@ bool sweepChunk(MemoryManager::Data::ChunkHeader *header, uint *itemsInUse, Exec #ifdef V4_USE_VALGRIND VALGRIND_ENABLE_ERROR_REPORTING; #endif - if (std::size_t(header->itemSize) == MemoryManager::align(sizeof(Heap::String)) && m->vtable()->isString) { - std::size_t heapBytes = static_cast<Heap::String *>(m)->retainedTextSize(); - Q_ASSERT(*unmanagedHeapSize >= heapBytes); -// qDebug() << "-- it's a string holding on to" << heapBytes << "bytes"; - *unmanagedHeapSize -= heapBytes; - } - if (m->vtable()->destroy) { m->vtable()->destroy(m); m->_checkIsDestroyed(); @@ -502,7 +493,7 @@ void MemoryManager::sweep(bool lastSweep) for (size_t i = 0; i < m_d->heapChunks.size(); ++i) { Data::ChunkHeader *header = reinterpret_cast<Data::ChunkHeader *>(m_d->heapChunks[i].base()); - chunkIsEmpty[i] = sweepChunk(header, &itemsInUse[header->itemSize >> 4], engine, &m_d->unmanagedHeapSize); + chunkIsEmpty[i] = sweepChunk(header, &itemsInUse[header->itemSize >> 4], engine); } std::vector<PageAllocation>::iterator chunkIter = m_d->heapChunks.begin(); @@ -565,16 +556,6 @@ void MemoryManager::sweep(bool lastSweep) } } -bool MemoryManager::isGCBlocked() const -{ - return m_d->gcBlocked; -} - -void MemoryManager::setGCBlocked(bool blockGC) -{ - m_d->gcBlocked = blockGC; -} - void MemoryManager::runGC() { if (m_d->gcBlocked) { @@ -652,7 +633,7 @@ size_t MemoryManager::getLargeItemsMem() const return total; } -void MemoryManager::growUnmanagedHeapSizeUsage(size_t delta) +void MemoryManager::changeUnmanagedHeapSizeUsage(qptrdiff delta) { m_d->unmanagedHeapSize += delta; } diff --git a/src/qml/memory/qv4mm_p.h b/src/qml/memory/qv4mm_p.h index dfa0d85dff..e6417cb2e0 100644 --- a/src/qml/memory/qv4mm_p.h +++ b/src/qml/memory/qv4mm_p.h @@ -76,26 +76,6 @@ class Q_QML_EXPORT MemoryManager public: struct Data; - class GCBlocker - { - public: - GCBlocker(MemoryManager *mm) - : mm(mm) - , wasBlocked(mm->isGCBlocked()) - { - mm->setGCBlocked(true); - } - - ~GCBlocker() - { - mm->setGCBlocked(wasBlocked); - } - - private: - MemoryManager *mm; - bool wasBlocked; - }; - public: MemoryManager(ExecutionEngine *engine); ~MemoryManager(); @@ -309,8 +289,6 @@ public: return t->d(); } - bool isGCBlocked() const; - void setGCBlocked(bool blockGC); void runGC(); void dumpStats() const; @@ -319,7 +297,7 @@ public: size_t getAllocatedMem() const; size_t getLargeItemsMem() const; - void growUnmanagedHeapSizeUsage(size_t delta); // called when a JS object grows itself. Specifically: Heap::String::append + void changeUnmanagedHeapSizeUsage(qptrdiff delta); // called when a JS object grows itself. Specifically: Heap::String::append protected: /// expects size to be aligned diff --git a/src/qml/qml.pro b/src/qml/qml.pro index 826a074701..8f9e4b7f83 100644 --- a/src/qml/qml.pro +++ b/src/qml/qml.pro @@ -14,6 +14,8 @@ solaris-cc*:QMAKE_CXXFLAGS_RELEASE -= -O2 # Ensure this gcc optimization is switched off for mips platforms to avoid trouble with JIT. gcc:isEqual(QT_ARCH, "mips"): QMAKE_CXXFLAGS += -fno-reorder-blocks +DEFINES += QT_NO_FOREACH + exists("qqml_enable_gcov") { QMAKE_CXXFLAGS = -fprofile-arcs -ftest-coverage -fno-elide-constructors LIBS_PRIVATE += -lgcov diff --git a/src/qml/qml/qqmlabstractbinding.cpp b/src/qml/qml/qqmlabstractbinding.cpp index 39d609454f..b1c320afd4 100644 --- a/src/qml/qml/qqmlabstractbinding.cpp +++ b/src/qml/qml/qqmlabstractbinding.cpp @@ -191,7 +191,7 @@ void QQmlAbstractBinding::removeFromObject() void QQmlAbstractBinding::printBindingLoopError(QQmlProperty &prop) { - qmlInfo(prop.object()) << QString(QLatin1String("Binding loop detected for property \"%1\"")).arg(prop.name()); + qmlWarning(prop.object()) << QString(QLatin1String("Binding loop detected for property \"%1\"")).arg(prop.name()); } QString QQmlAbstractBinding::expression() const diff --git a/src/qml/qml/qqmlabstracturlinterceptor.h b/src/qml/qml/qqmlabstracturlinterceptor.h index dfb8a46027..665b37fb3a 100644 --- a/src/qml/qml/qqmlabstracturlinterceptor.h +++ b/src/qml/qml/qqmlabstracturlinterceptor.h @@ -47,7 +47,6 @@ QT_BEGIN_NAMESPACE class Q_QML_EXPORT QQmlAbstractUrlInterceptor { - Q_FLAGS(InterceptionPoint) public: enum DataType { //Matches QQmlDataBlob::Type QmlFile = 0, diff --git a/src/qml/qml/qqmlapplicationengine.cpp b/src/qml/qml/qqmlapplicationengine.cpp index 8a97b7eba7..2a96d96302 100644 --- a/src/qml/qml/qqmlapplicationengine.cpp +++ b/src/qml/qml/qqmlapplicationengine.cpp @@ -190,9 +190,14 @@ void QQmlApplicationEnginePrivate::_q_finishLoad(QObject *o) /*! \fn QQmlApplicationEngine::objectCreated(QObject *object, const QUrl &url) - This signal is emitted when an object finishes loading. If loading was successful, \a object contains a pointer to the loaded object. - Otherwise the pointer is NULL. The \a url loaded is also provided, note that if a QString file path was initially passed to the - QQmlApplicationEngine, this url will be the equivalent of QUrl::fromLocalFile(filePath). + This signal is emitted when an object finishes loading. If loading was + successful, \a object contains a pointer to the loaded object, otherwise + the pointer is NULL. + + The \a url to the component the \a object came from is also provided. + + \note If the path to the component was provided as a QString containing a + relative path, the \a url will contain a fully resolved path to the file. */ /*! @@ -226,7 +231,7 @@ QQmlApplicationEngine::QQmlApplicationEngine(const QUrl &url, QObject *parent) This is provided as a convenience, and is the same as using the empty constructor and calling load afterwards. */ QQmlApplicationEngine::QQmlApplicationEngine(const QString &filePath, QObject *parent) - : QQmlApplicationEngine(QUrl::fromLocalFile(filePath), parent) + : QQmlApplicationEngine(QUrl::fromUserInput(filePath, QLatin1String("."), QUrl::AssumeLocalFile), parent) { } @@ -265,7 +270,7 @@ void QQmlApplicationEngine::load(const QUrl &url) void QQmlApplicationEngine::load(const QString &filePath) { Q_D(QQmlApplicationEngine); - d->startLoad(QUrl::fromLocalFile(filePath)); + d->startLoad(QUrl::fromUserInput(filePath, QLatin1String("."), QUrl::AssumeLocalFile)); } /*! diff --git a/src/qml/qml/qqmlbinding.cpp b/src/qml/qml/qqmlbinding.cpp index 284ae1f36f..62288a5845 100644 --- a/src/qml/qml/qqmlbinding.cpp +++ b/src/qml/qml/qqmlbinding.cpp @@ -163,7 +163,7 @@ void QQmlBinding::update(QQmlPropertyData::WriteFlags flags) if (canUseAccessor()) flags.setFlag(QQmlPropertyData::BypassInterceptor); - QQmlBindingProfiler prof(ep->profiler, this, function()); + QQmlBindingProfiler prof(ep->profiler, function()); doUpdate(watcher, flags, scope); if (!watcher.wasDeleted()) diff --git a/src/qml/qml/qqmlboundsignal.cpp b/src/qml/qml/qqmlboundsignal.cpp index 254d5e1907..4fbd828307 100644 --- a/src/qml/qml/qqmlboundsignal.cpp +++ b/src/qml/qml/qqmlboundsignal.cpp @@ -91,7 +91,7 @@ QQmlBoundSignalExpression::QQmlBoundSignalExpression(QObject *target, int index, function += QQmlPropertyCache::signalParameterStringForJS(v4, signal.parameterNames(), &error); if (!error.isEmpty()) { - qmlInfo(scopeObject()) << error; + qmlWarning(scopeObject()) << error; return; } } else @@ -129,7 +129,7 @@ QQmlBoundSignalExpression::QQmlBoundSignalExpression(QObject *target, int index, QString error; QQmlPropertyCache::signalParameterStringForJS(engine, signalParameters, &error); if (!error.isEmpty()) { - qmlInfo(scopeObject()) << error; + qmlWarning(scopeObject()) << error; return; } runtimeFunction->updateInternalClass(engine, signalParameters); @@ -199,7 +199,10 @@ void QQmlBoundSignalExpression::evaluate(void **a) // for several cases (such as QVariant type and QObject-derived types) //args[ii] = engine->metaTypeToJS(type, a[ii + 1]); if (type == qMetaTypeId<QJSValue>()) { - callData->args[ii] = *QJSValuePrivate::getValue(reinterpret_cast<QJSValue *>(a[ii + 1])); + if (QV4::Value *v4Value = QJSValuePrivate::getValue(reinterpret_cast<QJSValue *>(a[ii + 1]))) + callData->args[ii] = *v4Value; + else + callData->args[ii] = QV4::Encode::undefined(); } else if (type == QMetaType::QVariant) { callData->args[ii] = scope.engine->fromVariant(*((QVariant *)a[ii + 1])); } else if (type == QMetaType::Int) { diff --git a/src/qml/qml/qqmlcomponent.cpp b/src/qml/qml/qqmlcomponent.cpp index 6ebcd142fb..50ed58e63d 100644 --- a/src/qml/qml/qqmlcomponent.cpp +++ b/src/qml/qml/qqmlcomponent.cpp @@ -47,8 +47,6 @@ #include "qqml.h" #include "qqmlengine.h" #include "qqmlbinding_p.h" -#include <private/qqmldebugconnector_p.h> -#include <private/qqmldebugserviceinterfaces_p.h> #include "qqmlincubator.h" #include "qqmlincubator_p.h" #include <private/qqmljavascriptexpression_p.h> @@ -876,15 +874,6 @@ QQmlComponentPrivate::beginCreate(QQmlContextData *context) depthIncreased = false; } - if (rv) { - if (QQmlEngineDebugService *service = - QQmlDebugConnector::service<QQmlEngineDebugService>()) { - if (!context->isInternal) - context->asQQmlContextPrivate()->instances.append(rv); - service->objectCreated(engine, rv); - } - } - return rv; } @@ -1244,7 +1233,7 @@ void QQmlComponent::createObject(QQmlV4Function *args) if (args->length() >= 2) { QV4::ScopedValue v(scope, (*args)[1]); if (!v->as<QV4::Object>() || v->as<QV4::ArrayObject>()) { - qmlInfo(this) << tr("createObject: value is not an object"); + qmlWarning(this) << tr("createObject: value is not an object"); args->setReturnValue(QV4::Encode::null()); return; } @@ -1361,7 +1350,7 @@ void QQmlComponent::incubateObject(QQmlV4Function *args) QV4::ScopedValue v(scope, (*args)[1]); if (v->isNull()) { } else if (!v->as<QV4::Object>() || v->as<QV4::ArrayObject>()) { - qmlInfo(this) << tr("createObject: value is not an object"); + qmlWarning(this) << tr("createObject: value is not an object"); args->setReturnValue(QV4::Encode::null()); return; } else { diff --git a/src/qml/qml/qqmlcustomparser.cpp b/src/qml/qml/qqmlcustomparser.cpp index 85c91a592a..0b0bbef795 100644 --- a/src/qml/qml/qqmlcustomparser.cpp +++ b/src/qml/qml/qqmlcustomparser.cpp @@ -83,7 +83,7 @@ QT_BEGIN_NAMESPACE by \a data, which is a block of data previously returned by a call to compile(). - Errors should be reported using qmlInfo(object). + Errors should be reported using qmlWarning(object). The \a object will be an instance of the TypeClass specified by QML_REGISTER_CUSTOM_TYPE. */ diff --git a/src/qml/qml/qqmlengine.cpp b/src/qml/qml/qqmlengine.cpp index c2915c840b..e1fa97b52f 100644 --- a/src/qml/qml/qqmlengine.cpp +++ b/src/qml/qml/qqmlengine.cpp @@ -436,7 +436,6 @@ The following functions are also on the Qt object. \list \li \c "android" - Android - \li \c "blackberry" - BlackBerry OS \li \c "ios" - iOS \li \c "tvos" - tvOS \li \c "linux" - Linux @@ -444,7 +443,6 @@ The following functions are also on the Qt object. \li \c "unix" - Other Unix-based OS \li \c "windows" - Windows \li \c "winrt" - WinRT / UWP - \li \c "winphone" - Windows Phone \endlist \endtable */ @@ -1914,9 +1912,29 @@ void QQmlEnginePrivate::sendExit(int retCode) static void dumpwarning(const QQmlError &error) { - QMessageLogger(error.url().toString().toLatin1().constData(), - error.line(), 0).warning().nospace() - << qPrintable(error.toString()); + switch (error.messageType()) { + case QtDebugMsg: + QMessageLogger(error.url().toString().toLatin1().constData(), + error.line(), 0).debug().nospace() + << qPrintable(error.toString()); + break; + case QtInfoMsg: + QMessageLogger(error.url().toString().toLatin1().constData(), + error.line(), 0).info().nospace() + << qPrintable(error.toString()); + break; + case QtWarningMsg: + case QtFatalMsg: // fatal does not support streaming, and furthermore, is actually fatal. Probably not desirable for QML. + QMessageLogger(error.url().toString().toLatin1().constData(), + error.line(), 0).warning().nospace() + << qPrintable(error.toString()); + break; + case QtCriticalMsg: + QMessageLogger(error.url().toString().toLatin1().constData(), + error.line(), 0).critical().nospace() + << qPrintable(error.toString()); + break; + } } static void dumpwarning(const QList<QQmlError> &errors) @@ -2129,8 +2147,7 @@ bool QQmlEngine::importPlugin(const QString &filePath, const QString &uri, QList Returns the directory where SQL and other offline storage is placed. - QQuickWebView and the SQL databases created with openDatabase() - are stored here. + The SQL databases created with openDatabase() are stored here. The default is QML/OfflineStorage in the platform-standard user application data directory. diff --git a/src/qml/qml/qqmlerror.cpp b/src/qml/qml/qqmlerror.cpp index 0a6c7b4960..7a1e02eec6 100644 --- a/src/qml/qml/qqmlerror.cpp +++ b/src/qml/qml/qqmlerror.cpp @@ -85,11 +85,12 @@ public: QString description; quint16 line; quint16 column; + QtMsgType messageType; QObject *object; }; QQmlErrorPrivate::QQmlErrorPrivate() -: line(0), column(0), object() +: line(0), column(0), messageType(QtMsgType::QtWarningMsg), object() { } @@ -119,12 +120,14 @@ QQmlError &QQmlError::operator=(const QQmlError &other) delete d; d = 0; } else { - if (!d) d = new QQmlErrorPrivate; + if (!d) + d = new QQmlErrorPrivate; d->url = other.d->url; d->description = other.d->description; d->line = other.d->line; d->column = other.d->column; d->object = other.d->object; + d->messageType = other.d->messageType; } return *this; } @@ -150,8 +153,9 @@ bool QQmlError::isValid() const */ QUrl QQmlError::url() const { - if (d) return d->url; - else return QUrl(); + if (d) + return d->url; + return QUrl(); } /*! @@ -159,7 +163,8 @@ QUrl QQmlError::url() const */ void QQmlError::setUrl(const QUrl &url) { - if (!d) d = new QQmlErrorPrivate; + if (!d) + d = new QQmlErrorPrivate; d->url = url; } @@ -168,8 +173,9 @@ void QQmlError::setUrl(const QUrl &url) */ QString QQmlError::description() const { - if (d) return d->description; - else return QString(); + if (d) + return d->description; + return QString(); } /*! @@ -177,7 +183,8 @@ QString QQmlError::description() const */ void QQmlError::setDescription(const QString &description) { - if (!d) d = new QQmlErrorPrivate; + if (!d) + d = new QQmlErrorPrivate; d->description = description; } @@ -186,8 +193,9 @@ void QQmlError::setDescription(const QString &description) */ int QQmlError::line() const { - if (d) return qmlSourceCoordinate(d->line); - else return -1; + if (d) + return qmlSourceCoordinate(d->line); + return -1; } /*! @@ -195,7 +203,8 @@ int QQmlError::line() const */ void QQmlError::setLine(int line) { - if (!d) d = new QQmlErrorPrivate; + if (!d) + d = new QQmlErrorPrivate; d->line = qmlSourceCoordinate(line); } @@ -204,8 +213,9 @@ void QQmlError::setLine(int line) */ int QQmlError::column() const { - if (d) return qmlSourceCoordinate(d->column); - else return -1; + if (d) + return qmlSourceCoordinate(d->column); + return -1; } /*! @@ -213,7 +223,8 @@ int QQmlError::column() const */ void QQmlError::setColumn(int column) { - if (!d) d = new QQmlErrorPrivate; + if (!d) + d = new QQmlErrorPrivate; d->column = qmlSourceCoordinate(column); } @@ -225,8 +236,9 @@ void QQmlError::setColumn(int column) */ QObject *QQmlError::object() const { - if (d) return d->object; - else return 0; + if (d) + return d->object; + return 0; } /*! @@ -234,11 +246,37 @@ QObject *QQmlError::object() const */ void QQmlError::setObject(QObject *object) { - if (!d) d = new QQmlErrorPrivate; + if (!d) + d = new QQmlErrorPrivate; d->object = object; } /*! + \since 5.9 + + Returns the message type. + */ +QtMsgType QQmlError::messageType() const +{ + if (d) + return d->messageType; + return QtMsgType::QtWarningMsg; +} + +/*! + \since 5.9 + + Sets the \a messageType for this message. The message type determines which + QDebug handlers are responsible for recieving the message. + */ +void QQmlError::setMessageType(QtMsgType messageType) +{ + if (!d) + d = new QQmlErrorPrivate; + d->messageType = messageType; +} + +/*! Returns the error as a human readable string. */ QString QQmlError::toString() const diff --git a/src/qml/qml/qqmlerror.h b/src/qml/qml/qqmlerror.h index e4c42223cf..ef529e3828 100644 --- a/src/qml/qml/qqmlerror.h +++ b/src/qml/qml/qqmlerror.h @@ -47,6 +47,7 @@ QT_BEGIN_NAMESPACE +// ### Qt 6: should this be called QQmlMessage, since it can have a message type? class QDebug; class QQmlErrorPrivate; class Q_QML_EXPORT QQmlError @@ -69,6 +70,8 @@ public: void setColumn(int); QObject *object() const; void setObject(QObject *); + QtMsgType messageType() const; + void setMessageType(QtMsgType messageType); QString toString() const; private: diff --git a/src/qml/qml/qqmlextensionplugin.cpp b/src/qml/qml/qqmlextensionplugin.cpp index ca19691e93..097fa71200 100644 --- a/src/qml/qml/qqmlextensionplugin.cpp +++ b/src/qml/qml/qqmlextensionplugin.cpp @@ -117,4 +117,14 @@ void QQmlExtensionPlugin::initializeEngine(QQmlEngine *engine, const char *uri) Q_UNUSED(uri); } +/*! + \class QQmlExtensionInterface + \internal + \inmodule QtQml + + \class QQmlTypesExtensionInterface + \internal + \inmodule QtQml +*/ + QT_END_NAMESPACE diff --git a/src/qml/qml/qqmlinfo.cpp b/src/qml/qml/qqmlinfo.cpp index 5b6e02d5b1..dae15e2eca 100644 --- a/src/qml/qml/qqmlinfo.cpp +++ b/src/qml/qml/qqmlinfo.cpp @@ -50,13 +50,45 @@ QT_BEGIN_NAMESPACE /*! + \fn QQmlInfo QtQml::qmlDebug(const QObject *object) + \relates QQmlEngine + \since 5.9 + + Prints debug messages that include the file and line number for the + specified QML \a object. + + When QML types produce logging messages, it improves traceability + if they include the QML file and line number on which the + particular instance was instantiated. + + To include the file and line number, an object must be passed. If + the file and line number is not available for that instance + (either it was not instantiated by the QML engine or location + information is disabled), "unknown location" will be used instead. + + For example, + + \code + qmlDebug(object) << "Internal state: 42"; + \endcode + + prints + + \code + QML MyCustomType (unknown location): Internal state: 42 + \endcode + + \sa QtQml::qmlInfo, QtQml::qmlWarning +*/ + +/*! \fn QQmlInfo QtQml::qmlInfo(const QObject *object) \relates QQmlEngine - Prints warning messages that include the file and line number for the + Prints informational messages that include the file and line number for the specified QML \a object. - When QML types display warning messages, it improves traceability + When QML types produce logging messages, it improves traceability if they include the QML file and line number on which the particular instance was instantiated. @@ -76,14 +108,58 @@ QT_BEGIN_NAMESPACE \code QML MyCustomType (unknown location): component property is a write-once property \endcode + + \note In versions prior to Qt 5.9, qmlInfo reported messages using a warning + QtMsgType. For Qt 5.9 and above, qmlInfo uses an info QtMsgType. To send + warnings, use qmlWarning. + + \sa QtQml::qmlDebug, QtQml::qmlWarning +*/ + + +/*! + \fn QQmlInfo QtQml::qmlWarning(const QObject *object) + \relates QQmlEngine + \since 5.9 + + Prints warning messages that include the file and line number for the + specified QML \a object. + + When QML types produce logging messages, it improves traceability + if they include the QML file and line number on which the + particular instance was instantiated. + + To include the file and line number, an object must be passed. If + the file and line number is not available for that instance + (either it was not instantiated by the QML engine or location + information is disabled), "unknown location" will be used instead. + + For example, + + \code + qmlInfo(object) << tr("property cannot be set to 0"); + \endcode + + prints + + \code + QML MyCustomType (unknown location): property cannot be set to 0 + \endcode + + \sa QtQml::qmlDebug, QtQml::qmlInfo */ class QQmlInfoPrivate { public: - QQmlInfoPrivate() : ref (1), object(0) {} + QQmlInfoPrivate(QtMsgType type) + : ref (1) + , msgType(type) + , object(nullptr) + {} int ref; + QtMsgType msgType; const QObject *object; QString buffer; QList<QQmlError> errors; @@ -110,6 +186,7 @@ QQmlInfo::~QQmlInfo() if (!d->buffer.isEmpty()) { QQmlError error; + error.setMessageType(d->msgType); QObject *object = const_cast<QObject *>(d->object); @@ -139,28 +216,32 @@ QQmlInfo::~QQmlInfo() namespace QtQml { -QQmlInfo qmlInfo(const QObject *me) -{ - QQmlInfoPrivate *d = new QQmlInfoPrivate; - d->object = me; - return QQmlInfo(d); -} +#define MESSAGE_FUNCS(FuncName, MessageLevel) \ + QQmlInfo FuncName(const QObject *me) \ + { \ + QQmlInfoPrivate *d = new QQmlInfoPrivate(MessageLevel); \ + d->object = me; \ + return QQmlInfo(d); \ + } \ + QQmlInfo FuncName(const QObject *me, const QQmlError &error) \ + { \ + QQmlInfoPrivate *d = new QQmlInfoPrivate(MessageLevel); \ + d->object = me; \ + d->errors << error; \ + return QQmlInfo(d); \ + } \ + QQmlInfo FuncName(const QObject *me, const QList<QQmlError> &errors) \ + { \ + QQmlInfoPrivate *d = new QQmlInfoPrivate(MessageLevel); \ + d->object = me; \ + d->errors = errors; \ + return QQmlInfo(d); \ + } -QQmlInfo qmlInfo(const QObject *me, const QQmlError &error) -{ - QQmlInfoPrivate *d = new QQmlInfoPrivate; - d->object = me; - d->errors << error; - return QQmlInfo(d); -} +MESSAGE_FUNCS(qmlDebug, QtMsgType::QtDebugMsg) +MESSAGE_FUNCS(qmlInfo, QtMsgType::QtInfoMsg) +MESSAGE_FUNCS(qmlWarning, QtMsgType::QtWarningMsg) -QQmlInfo qmlInfo(const QObject *me, const QList<QQmlError> &errors) -{ - QQmlInfoPrivate *d = new QQmlInfoPrivate; - d->object = me; - d->errors = errors; - return QQmlInfo(d); -} } // namespace QtQml diff --git a/src/qml/qml/qqmlinfo.h b/src/qml/qml/qqmlinfo.h index ab0281a688..673125632e 100644 --- a/src/qml/qml/qqmlinfo.h +++ b/src/qml/qml/qqmlinfo.h @@ -48,11 +48,19 @@ QT_BEGIN_NAMESPACE class QQmlInfo; +// declared in namespace to avoid symbol conflicts with QtDeclarative namespace QtQml { - // declared in namespace to avoid symbol conflicts with QtDeclarative + Q_QML_EXPORT QQmlInfo qmlDebug(const QObject *me); + Q_QML_EXPORT QQmlInfo qmlDebug(const QObject *me, const QQmlError &error); + Q_QML_EXPORT QQmlInfo qmlDebug(const QObject *me, const QList<QQmlError> &errors); + Q_QML_EXPORT QQmlInfo qmlInfo(const QObject *me); Q_QML_EXPORT QQmlInfo qmlInfo(const QObject *me, const QQmlError &error); Q_QML_EXPORT QQmlInfo qmlInfo(const QObject *me, const QList<QQmlError> &errors); + + Q_QML_EXPORT QQmlInfo qmlWarning(const QObject *me); + Q_QML_EXPORT QQmlInfo qmlWarning(const QObject *me, const QQmlError &error); + Q_QML_EXPORT QQmlInfo qmlWarning(const QObject *me, const QList<QQmlError> &errors); } QT_WARNING_PUSH QT_WARNING_DISABLE_CLANG("-Wheader-hygiene") @@ -93,9 +101,15 @@ public: #endif private: + friend Q_QML_EXPORT QQmlInfo QtQml::qmlDebug(const QObject *me); + friend Q_QML_EXPORT QQmlInfo QtQml::qmlDebug(const QObject *me, const QQmlError &error); + friend Q_QML_EXPORT QQmlInfo QtQml::qmlDebug(const QObject *me, const QList<QQmlError> &errors); friend Q_QML_EXPORT QQmlInfo QtQml::qmlInfo(const QObject *me); friend Q_QML_EXPORT QQmlInfo QtQml::qmlInfo(const QObject *me, const QQmlError &error); friend Q_QML_EXPORT QQmlInfo QtQml::qmlInfo(const QObject *me, const QList<QQmlError> &errors); + friend Q_QML_EXPORT QQmlInfo QtQml::qmlWarning(const QObject *me); + friend Q_QML_EXPORT QQmlInfo QtQml::qmlWarning(const QObject *me, const QQmlError &error); + friend Q_QML_EXPORT QQmlInfo QtQml::qmlWarning(const QObject *me, const QList<QQmlError> &errors); QQmlInfo(QQmlInfoPrivate *); QQmlInfoPrivate *d; diff --git a/src/qml/qml/qqmllist.cpp b/src/qml/qml/qqmllist.cpp index a719956483..edd93ef03d 100644 --- a/src/qml/qml/qqmllist.cpp +++ b/src/qml/qml/qqmllist.cpp @@ -335,7 +335,7 @@ int QQmlListReference::count() const \since 5.0 \inmodule QtQml \brief The QQmlListProperty class allows applications to expose list-like -properties to QML. +properties of QObject-derived classes to QML. QML has many list properties, where more than one object value can be assigned. The use of a list property from QML looks like this: @@ -369,7 +369,8 @@ QML list properties are type-safe - in this case \c {Fruit} is a QObject type th The \l {Qt Quick 1} version of this class is named QDeclarativeListProperty. -\note QQmlListProperty can only be used for lists of QObject-derived object pointers. +\sa {Extending QML - Object and List Property Types Example} + */ /*! diff --git a/src/qml/qml/qqmlloggingcategory.cpp b/src/qml/qml/qqmlloggingcategory.cpp index 70e59db07b..764b874131 100644 --- a/src/qml/qml/qqmlloggingcategory.cpp +++ b/src/qml/qml/qqmlloggingcategory.cpp @@ -112,13 +112,13 @@ void QQmlLoggingCategory::componentComplete() { m_initialized = true; if (m_name.isNull()) - qmlInfo(this) << QLatin1String("Declaring the name of the LoggingCategory is mandatory and cannot be changed later !"); + qmlWarning(this) << QLatin1String("Declaring the name of the LoggingCategory is mandatory and cannot be changed later !"); } void QQmlLoggingCategory::setName(const QString &name) { if (m_initialized) { - qmlInfo(this) << QLatin1String("The name of a LoggingCategory cannot be changed after the Item is created"); + qmlWarning(this) << QLatin1String("The name of a LoggingCategory cannot be changed after the Item is created"); return; } diff --git a/src/qml/qml/qqmlobjectcreator.cpp b/src/qml/qml/qqmlobjectcreator.cpp index 2e2a3fb303..09936f6e7a 100644 --- a/src/qml/qml/qqmlobjectcreator.cpp +++ b/src/qml/qml/qqmlobjectcreator.cpp @@ -53,6 +53,8 @@ #include <private/qqmlscriptstring_p.h> #include <private/qqmlpropertyvalueinterceptor_p.h> #include <private/qqmlvaluetypeproxybinding_p.h> +#include <private/qqmldebugconnector_p.h> +#include <private/qqmldebugserviceinterfaces_p.h> QT_USE_NAMESPACE @@ -216,6 +218,17 @@ QObject *QQmlObjectCreator::create(int subComponentIndex, QObject *parent, QQmlI phase = ObjectsCreated; + if (instance) { + if (QQmlEngineDebugService *service + = QQmlDebugConnector::service<QQmlEngineDebugService>()) { + if (!parentContext->isInternal) + parentContext->asQQmlContextPrivate()->instances.append(instance); + service->objectCreated(engine, instance); + } else if (!parentContext->isInternal && QQmlDebugConnector::service<QV4DebugService>()) { + parentContext->asQQmlContextPrivate()->instances.append(instance); + } + } + return instance; } diff --git a/src/qml/qml/qqmlplatform.cpp b/src/qml/qml/qqmlplatform.cpp index a47a0ab4a4..64ca208f1b 100644 --- a/src/qml/qml/qqmlplatform.cpp +++ b/src/qml/qml/qqmlplatform.cpp @@ -59,16 +59,12 @@ QString QQmlPlatform::os() { #if defined(Q_OS_ANDROID) return QStringLiteral("android"); -#elif defined(Q_OS_BLACKBERRY) - return QStringLiteral("blackberry"); #elif defined(Q_OS_IOS) return QStringLiteral("ios"); #elif defined(Q_OS_TVOS) return QStringLiteral("tvos"); #elif defined(Q_OS_MAC) return QStringLiteral("osx"); -#elif defined(Q_OS_WINPHONE) - return QStringLiteral("winphone"); #elif defined(Q_OS_WINRT) return QStringLiteral("winrt"); #elif defined(Q_OS_WIN) diff --git a/src/qml/qml/qqmltypeloader.cpp b/src/qml/qml/qqmltypeloader.cpp index 76ac15e2f1..ac993a1037 100644 --- a/src/qml/qml/qqmltypeloader.cpp +++ b/src/qml/qml/qqmltypeloader.cpp @@ -2428,7 +2428,7 @@ void QQmlTypeData::continueLoadFromIR() QList<QQmlError> errors; - foreach (const QV4::CompiledData::Import *import, m_document->imports) { + for (const QV4::CompiledData::Import *import : qAsConst(m_document->imports)) { if (!addImport(import, &errors)) { Q_ASSERT(errors.size()); QQmlError error(errors.takeFirst()); diff --git a/src/qml/types/qqmlbind.cpp b/src/qml/types/qqmlbind.cpp index a545fe57ca..2ded9c13c8 100644 --- a/src/qml/types/qqmlbind.cpp +++ b/src/qml/types/qqmlbind.cpp @@ -82,12 +82,12 @@ void QQmlBindPrivate::validate(QObject *binding) const return; if (!prop.isValid()) { - qmlInfo(binding) << "Property '" << propName << "' does not exist on " << QQmlMetaType::prettyTypeName(obj) << "."; + qmlWarning(binding) << "Property '" << propName << "' does not exist on " << QQmlMetaType::prettyTypeName(obj) << "."; return; } if (!prop.isWritable()) { - qmlInfo(binding) << "Property '" << propName << "' on " << QQmlMetaType::prettyTypeName(obj) << " is read-only."; + qmlWarning(binding) << "Property '" << propName << "' on " << QQmlMetaType::prettyTypeName(obj) << " is read-only."; return; } } diff --git a/src/qml/types/qqmlconnections.cpp b/src/qml/types/qqmlconnections.cpp index 2aed4d9972..870aeaa6e2 100644 --- a/src/qml/types/qqmlconnections.cpp +++ b/src/qml/types/qqmlconnections.cpp @@ -168,7 +168,7 @@ void QQmlConnections::setTarget(QObject *obj) if (d->targetSet && d->target == obj) return; d->targetSet = true; // even if setting to 0, it is *set* - foreach (QQmlBoundSignal *s, d->boundsignals) { + for (QQmlBoundSignal *s : qAsConst(d->boundsignals)) { // It is possible that target is being changed due to one of our signal // handlers -> use deleteLater(). if (s->isNotifying()) @@ -278,7 +278,7 @@ void QQmlConnections::connectSignals() QQmlContextData *ctxtdata = ddata ? ddata->outerContext : 0; const QV4::CompiledData::Unit *qmlUnit = d->compilationUnit->data; - foreach (const QV4::CompiledData::Binding *binding, d->bindings) { + for (const QV4::CompiledData::Binding *binding : qAsConst(d->bindings)) { Q_ASSERT(binding->type == QV4::CompiledData::Binding::Type_Script); QString propName = qmlUnit->stringAt(binding->propertyNameIndex); @@ -295,7 +295,7 @@ void QQmlConnections::connectSignals() d->boundsignals += signal; } else { if (!d->ignoreUnknownSignals) - qmlInfo(this) << tr("Cannot assign to non-existent property \"%1\"").arg(propName); + qmlWarning(this) << tr("Cannot assign to non-existent property \"%1\"").arg(propName); } } } diff --git a/src/qml/types/qqmldelegatemodel.cpp b/src/qml/types/qqmldelegatemodel.cpp index be10b270ae..c0d75cae33 100644 --- a/src/qml/types/qqmldelegatemodel.cpp +++ b/src/qml/types/qqmldelegatemodel.cpp @@ -264,7 +264,7 @@ QQmlDelegateModel::~QQmlDelegateModel() { Q_D(QQmlDelegateModel); - foreach (QQmlDelegateModelItem *cacheItem, d->m_cache) { + for (QQmlDelegateModelItem *cacheItem : qAsConst(d->m_cache)) { if (cacheItem->object) { delete cacheItem->object; @@ -310,7 +310,7 @@ void QQmlDelegateModel::componentComplete() --d->m_groupCount; --i; } else if (name.at(0).isUpper()) { - qmlInfo(d->m_groups[i]) << QQmlDelegateModelGroup::tr("Group names must start with a lower case letter"); + qmlWarning(d->m_groups[i]) << QQmlDelegateModelGroup::tr("Group names must start with a lower case letter"); d->m_groups[i] = d->m_groups[d->m_groupCount - 1]; --d->m_groupCount; --i; @@ -404,7 +404,7 @@ void QQmlDelegateModel::setDelegate(QQmlComponent *delegate) { Q_D(QQmlDelegateModel); if (d->m_transaction) { - qmlInfo(this) << tr("The delegate of a DelegateModel cannot be changed within onUpdated."); + qmlWarning(this) << tr("The delegate of a DelegateModel cannot be changed within onUpdated."); return; } bool wasValid = d->m_delegate != 0; @@ -610,7 +610,7 @@ void QQmlDelegateModelPrivate::group_append( if (d->m_complete) return; if (d->m_groupCount == Compositor::MaximumGroupCount) { - qmlInfo(d->q_func()) << QQmlDelegateModel::tr("The maximum number of supported DelegateModelGroups is 8"); + qmlWarning(d->q_func()) << QQmlDelegateModel::tr("The maximum number of supported DelegateModelGroups is 8"); return; } d->m_groups[d->m_groupCount] = group; @@ -719,7 +719,7 @@ void QQmlDelegateModel::setFilterGroup(const QString &group) Q_D(QQmlDelegateModel); if (d->m_transaction) { - qmlInfo(this) << tr("The group of a DelegateModel cannot be changed within onChanged"); + qmlWarning(this) << tr("The group of a DelegateModel cannot be changed within onChanged"); return; } @@ -764,7 +764,8 @@ void QQmlDelegateModelPrivate::updateFilterGroup() emit q->countChanged(); if (m_parts) { - foreach (QQmlPartsModel *model, m_parts->models) + auto partsCopy = m_parts->models; // deliberate; this may alter m_parts + for (QQmlPartsModel *model : qAsConst(partsCopy)) model->updateFilterGroup(m_compositorGroup, changeSet); } } @@ -889,7 +890,7 @@ void QQmlDelegateModelPrivate::incubatorStatusChanged(QQDMIncubationTask *incuba emitCreatedItem(incubationTask, cacheItem->object); cacheItem->releaseObject(); } else if (status == QQmlIncubator::Error) { - qmlInfo(q, m_delegate->errors()) << "Error creating delegate"; + qmlWarning(q, m_delegate->errors()) << "Error creating delegate"; } if (!cacheItem->isObjectReferenced()) { @@ -1472,7 +1473,8 @@ void QQmlDelegateModelPrivate::emitChanges() for (int i = 1; i < m_groupCount; ++i) QQmlDelegateModelGroupPrivate::get(m_groups[i])->emitModelUpdated(reset); - foreach (QQmlDelegateModelItem *cacheItem, m_cache) { + auto cacheCopy = m_cache; // deliberate; emitChanges may alter m_cache + for (QQmlDelegateModelItem *cacheItem : qAsConst(cacheCopy)) { if (cacheItem->attached) cacheItem->attached->emitChanges(); } @@ -2459,7 +2461,7 @@ QQmlV4Handle QQmlDelegateModelGroup::get(int index) if (!model->m_context || !model->m_context->isValid()) { return QQmlV4Handle(QV4::Encode::undefined()); } else if (index < 0 || index >= model->m_compositor.count(d->group)) { - qmlInfo(this) << tr("get: index out of range"); + qmlWarning(this) << tr("get: index out of range"); return QQmlV4Handle(QV4::Encode::undefined()); } @@ -2552,7 +2554,7 @@ void QQmlDelegateModelGroup::insert(QQmlV4Function *args) QV4::ScopedValue v(scope, (*args)[i]); if (d->parseIndex(v, &index, &group)) { if (index < 0 || index > model->m_compositor.count(group)) { - qmlInfo(this) << tr("insert: index out of range"); + qmlWarning(this) << tr("insert: index out of range"); return; } if (++i == args->length()) @@ -2637,7 +2639,7 @@ void QQmlDelegateModelGroup::create(QQmlV4Function *args) } } if (index < 0 || index >= model->m_compositor.count(group)) { - qmlInfo(this) << tr("create: index out of range"); + qmlWarning(this) << tr("create: index out of range"); return; } @@ -2690,22 +2692,22 @@ void QQmlDelegateModelGroup::resolve(QQmlV4Function *args) QV4::ScopedValue v(scope, (*args)[0]); if (d->parseIndex(v, &from, &fromGroup)) { if (from < 0 || from >= model->m_compositor.count(fromGroup)) { - qmlInfo(this) << tr("resolve: from index out of range"); + qmlWarning(this) << tr("resolve: from index out of range"); return; } } else { - qmlInfo(this) << tr("resolve: from index invalid"); + qmlWarning(this) << tr("resolve: from index invalid"); return; } v = (*args)[1]; if (d->parseIndex(v, &to, &toGroup)) { if (to < 0 || to >= model->m_compositor.count(toGroup)) { - qmlInfo(this) << tr("resolve: to index out of range"); + qmlWarning(this) << tr("resolve: to index out of range"); return; } } else { - qmlInfo(this) << tr("resolve: to index invalid"); + qmlWarning(this) << tr("resolve: to index invalid"); return; } @@ -2713,11 +2715,11 @@ void QQmlDelegateModelGroup::resolve(QQmlV4Function *args) Compositor::iterator toIt = model->m_compositor.find(toGroup, to); if (!fromIt->isUnresolved()) { - qmlInfo(this) << tr("resolve: from is not an unresolved item"); + qmlWarning(this) << tr("resolve: from is not an unresolved item"); return; } if (!toIt->list) { - qmlInfo(this) << tr("resolve: to is not a model item"); + qmlWarning(this) << tr("resolve: to is not a model item"); return; } @@ -2787,7 +2789,7 @@ void QQmlDelegateModelGroup::remove(QQmlV4Function *args) QV4::Scope scope(args->v4engine()); QV4::ScopedValue v(scope, (*args)[0]); if (!d->parseIndex(v, &index, &group)) { - qmlInfo(this) << tr("remove: invalid index"); + qmlWarning(this) << tr("remove: invalid index"); return; } @@ -2799,11 +2801,11 @@ void QQmlDelegateModelGroup::remove(QQmlV4Function *args) QQmlDelegateModelPrivate *model = QQmlDelegateModelPrivate::get(d->model); if (index < 0 || index >= model->m_compositor.count(group)) { - qmlInfo(this) << tr("remove: index out of range"); + qmlWarning(this) << tr("remove: index out of range"); } else if (count != 0) { Compositor::iterator it = model->m_compositor.find(group, index); if (count < 0 || count > model->m_compositor.count(d->group) - it.index[d->group]) { - qmlInfo(this) << tr("remove: invalid count"); + qmlWarning(this) << tr("remove: invalid count"); } else { model->removeGroups(it, count, d->group, 1 << d->group); } @@ -2858,11 +2860,11 @@ void QQmlDelegateModelGroup::addGroups(QQmlV4Function *args) QQmlDelegateModelPrivate *model = QQmlDelegateModelPrivate::get(d->model); if (index < 0 || index >= model->m_compositor.count(group)) { - qmlInfo(this) << tr("addGroups: index out of range"); + qmlWarning(this) << tr("addGroups: index out of range"); } else if (count != 0) { Compositor::iterator it = model->m_compositor.find(group, index); if (count < 0 || count > model->m_compositor.count(d->group) - it.index[d->group]) { - qmlInfo(this) << tr("addGroups: invalid count"); + qmlWarning(this) << tr("addGroups: invalid count"); } else { model->addGroups(it, count, d->group, groups); } @@ -2888,11 +2890,11 @@ void QQmlDelegateModelGroup::removeGroups(QQmlV4Function *args) QQmlDelegateModelPrivate *model = QQmlDelegateModelPrivate::get(d->model); if (index < 0 || index >= model->m_compositor.count(group)) { - qmlInfo(this) << tr("removeGroups: index out of range"); + qmlWarning(this) << tr("removeGroups: index out of range"); } else if (count != 0) { Compositor::iterator it = model->m_compositor.find(group, index); if (count < 0 || count > model->m_compositor.count(d->group) - it.index[d->group]) { - qmlInfo(this) << tr("removeGroups: invalid count"); + qmlWarning(this) << tr("removeGroups: invalid count"); } else { model->removeGroups(it, count, d->group, groups); } @@ -2918,11 +2920,11 @@ void QQmlDelegateModelGroup::setGroups(QQmlV4Function *args) QQmlDelegateModelPrivate *model = QQmlDelegateModelPrivate::get(d->model); if (index < 0 || index >= model->m_compositor.count(group)) { - qmlInfo(this) << tr("setGroups: index out of range"); + qmlWarning(this) << tr("setGroups: index out of range"); } else if (count != 0) { Compositor::iterator it = model->m_compositor.find(group, index); if (count < 0 || count > model->m_compositor.count(d->group) - it.index[d->group]) { - qmlInfo(this) << tr("setGroups: invalid count"); + qmlWarning(this) << tr("setGroups: invalid count"); } else { model->setGroups(it, count, d->group, groups); } @@ -2957,13 +2959,13 @@ void QQmlDelegateModelGroup::move(QQmlV4Function *args) QV4::Scope scope(args->v4engine()); QV4::ScopedValue v(scope, (*args)[0]); if (!d->parseIndex(v, &from, &fromGroup)) { - qmlInfo(this) << tr("move: invalid from index"); + qmlWarning(this) << tr("move: invalid from index"); return; } v = (*args)[1]; if (!d->parseIndex(v, &to, &toGroup)) { - qmlInfo(this) << tr("move: invalid to index"); + qmlWarning(this) << tr("move: invalid to index"); return; } @@ -2976,11 +2978,11 @@ void QQmlDelegateModelGroup::move(QQmlV4Function *args) QQmlDelegateModelPrivate *model = QQmlDelegateModelPrivate::get(d->model); if (count < 0) { - qmlInfo(this) << tr("move: invalid count"); + qmlWarning(this) << tr("move: invalid count"); } else if (from < 0 || from + count > model->m_compositor.count(fromGroup)) { - qmlInfo(this) << tr("move: from index out of range"); + qmlWarning(this) << tr("move: from index out of range"); } else if (!model->m_compositor.verifyMoveTo(fromGroup, from, toGroup, to, count, d->group)) { - qmlInfo(this) << tr("move: to index out of range"); + qmlWarning(this) << tr("move: to index out of range"); } else if (count > 0) { QVector<Compositor::Remove> removes; QVector<Compositor::Insert> inserts; @@ -3038,7 +3040,7 @@ QString QQmlPartsModel::filterGroup() const void QQmlPartsModel::setFilterGroup(const QString &group) { if (QQmlDelegateModelPrivate::get(m_model)->m_transaction) { - qmlInfo(this) << tr("The group of a DelegateModel cannot be changed within onChanged"); + qmlWarning(this) << tr("The group of a DelegateModel cannot be changed within onChanged"); return; } @@ -3151,7 +3153,7 @@ QObject *QQmlPartsModel::object(int index, bool asynchronous) model->release(object); if (!model->m_delegateValidated) { if (object) - qmlInfo(model->m_delegate) << tr("Delegate component must be Package type."); + qmlWarning(model->m_delegate) << tr("Delegate component must be Package type."); model->m_delegateValidated = true; } diff --git a/src/qml/types/qqmllistmodel.cpp b/src/qml/types/qqmllistmodel.cpp index 1a2e4c7f6f..cc4ccbaeb1 100644 --- a/src/qml/types/qqmllistmodel.cpp +++ b/src/qml/types/qqmllistmodel.cpp @@ -99,7 +99,7 @@ const ListLayout::Role &ListLayout::getRoleOrCreate(const QString &key, Role::Da if (node) { const Role &r = *node->value; if (type != r.type) - qmlInfo(0) << QStringLiteral("Can't assign to existing role '%1' of different type [%2 -> %3]").arg(r.name).arg(roleTypeName(type)).arg(roleTypeName(r.type)); + qmlWarning(0) << QStringLiteral("Can't assign to existing role '%1' of different type [%2 -> %3]").arg(r.name).arg(roleTypeName(type)).arg(roleTypeName(r.type)); return r; } @@ -112,7 +112,7 @@ const ListLayout::Role &ListLayout::getRoleOrCreate(QV4::String *key, Role::Data if (node) { const Role &r = *node->value; if (type != r.type) - qmlInfo(0) << QStringLiteral("Can't assign to existing role '%1' of different type [%2 -> %3]").arg(r.name).arg(roleTypeName(type)).arg(roleTypeName(r.type)); + qmlWarning(0) << QStringLiteral("Can't assign to existing role '%1' of different type [%2 -> %3]").arg(r.name).arg(roleTypeName(type)).arg(roleTypeName(r.type)); return r; } @@ -226,7 +226,7 @@ const ListLayout::Role *ListLayout::getRoleOrCreate(const QString &key, const QV } if (type == Role::Invalid) { - qmlInfo(0) << "Can't create role for unsupported data type"; + qmlWarning(0) << "Can't create role for unsupported data type"; return 0; } @@ -1201,7 +1201,7 @@ int ListElement::setJsProperty(const ListLayout::Role &role, const QV4::Value &d } roleIndex = setListProperty(role, subModel); } else { - qmlInfo(0) << QStringLiteral("Can't assign to existing role '%1' of different type [%2 -> %3]").arg(role.name).arg(roleTypeName(role.type)).arg(roleTypeName(ListLayout::Role::List)); + qmlWarning(0) << QStringLiteral("Can't assign to existing role '%1' of different type [%2 -> %3]").arg(role.name).arg(roleTypeName(role.type)).arg(roleTypeName(ListLayout::Role::List)); } } else if (d.isBoolean()) { roleIndex = setBoolProperty(role, d.booleanValue()); @@ -1267,10 +1267,12 @@ void ModelNodeMetaObject::updateValues() { const int roleCount = m_model->m_listModel->roleCount(); if (!m_initialized) { - int *changedRoles = reinterpret_cast<int *>(alloca(roleCount * sizeof(int))); - for (int i = 0; i < roleCount; ++i) - changedRoles[i] = i; - emitDirectNotifies(changedRoles, roleCount); + if (roleCount) { + int *changedRoles = reinterpret_cast<int *>(alloca(roleCount * sizeof(int))); + for (int i = 0; i < roleCount; ++i) + changedRoles[i] = i; + emitDirectNotifies(changedRoles, roleCount); + } return; } for (int i=0 ; i < roleCount ; ++i) { @@ -1984,18 +1986,18 @@ void QQmlListModel::setDynamicRoles(bool enableDynamicRoles) if (m_mainThread && m_agent == 0) { if (enableDynamicRoles) { if (m_layout->roleCount()) - qmlInfo(this) << tr("unable to enable dynamic roles as this model is not empty!"); + qmlWarning(this) << tr("unable to enable dynamic roles as this model is not empty!"); else m_dynamicRoles = true; } else { if (m_roles.count()) { - qmlInfo(this) << tr("unable to enable static roles as this model is not empty!"); + qmlWarning(this) << tr("unable to enable static roles as this model is not empty!"); } else { m_dynamicRoles = false; } } } else { - qmlInfo(this) << tr("dynamic role setting must be made from the main thread, before any worker scripts are created"); + qmlWarning(this) << tr("dynamic role setting must be made from the main thread, before any worker scripts are created"); } } @@ -2048,7 +2050,7 @@ void QQmlListModel::remove(QQmlV4Function *args) int removeCount = (argLength == 2 ? QV4::ScopedValue(scope, (*args)[1])->toInt32() : 1); if (index < 0 || index+removeCount > count() || removeCount <= 0) { - qmlInfo(this) << tr("remove: indices [%1 - %2] out of range [0 - %3]").arg(index).arg(index+removeCount).arg(count()); + qmlWarning(this) << tr("remove: indices [%1 - %2] out of range [0 - %3]").arg(index).arg(index+removeCount).arg(count()); return; } @@ -2064,7 +2066,7 @@ void QQmlListModel::remove(QQmlV4Function *args) emitItemsRemoved(index, removeCount); } else { - qmlInfo(this) << tr("remove: incorrect number of arguments"); + qmlWarning(this) << tr("remove: incorrect number of arguments"); } } @@ -2092,7 +2094,7 @@ void QQmlListModel::insert(QQmlV4Function *args) int index = arg0->toInt32(); if (index < 0 || index > count()) { - qmlInfo(this) << tr("insert: index %1 out of range").arg(index); + qmlWarning(this) << tr("insert: index %1 out of range").arg(index); return; } @@ -2124,10 +2126,10 @@ void QQmlListModel::insert(QQmlV4Function *args) emitItemsInserted(index, 1); } else { - qmlInfo(this) << tr("insert: value is not an object"); + qmlWarning(this) << tr("insert: value is not an object"); } } else { - qmlInfo(this) << tr("insert: value is not an object"); + qmlWarning(this) << tr("insert: value is not an object"); } } @@ -2150,7 +2152,7 @@ void QQmlListModel::move(int from, int to, int n) if (n==0 || from==to) return; if (!canMove(from, to, n)) { - qmlInfo(this) << tr("move: out of range"); + qmlWarning(this) << tr("move: out of range"); return; } @@ -2239,10 +2241,10 @@ void QQmlListModel::append(QQmlV4Function *args) emitItemsInserted(index, 1); } else { - qmlInfo(this) << tr("append: value is not an object"); + qmlWarning(this) << tr("append: value is not an object"); } } else { - qmlInfo(this) << tr("append: value is not an object"); + qmlWarning(this) << tr("append: value is not an object"); } } @@ -2321,11 +2323,11 @@ void QQmlListModel::set(int index, const QQmlV4Handle &handle) QV4::ScopedObject object(scope, handle); if (!object) { - qmlInfo(this) << tr("set: value is not an object"); + qmlWarning(this) << tr("set: value is not an object"); return; } if (index > count() || index < 0) { - qmlInfo(this) << tr("set: index %1 out of range").arg(index); + qmlWarning(this) << tr("set: index %1 out of range").arg(index); return; } @@ -2371,7 +2373,7 @@ void QQmlListModel::set(int index, const QQmlV4Handle &handle) void QQmlListModel::setProperty(int index, const QString& property, const QVariant& value) { if (count() == 0 || index >= count() || index < 0) { - qmlInfo(this) << tr("set: index %1 out of range").arg(index); + qmlWarning(this) << tr("set: index %1 out of range").arg(index); return; } @@ -2401,7 +2403,7 @@ void QQmlListModel::sync() // This is just a dummy method to make it look like sync() exists in // ListModel (and not just QQmlListModelWorkerAgent) and to let // us document sync(). - qmlInfo(this) << "List sync() can only be called from a WorkerScript"; + qmlWarning(this) << "List sync() can only be called from a WorkerScript"; } bool QQmlListModelParser::verifyProperty(const QV4::CompiledData::Unit *qmlUnit, const QV4::CompiledData::Binding *binding) @@ -2543,7 +2545,7 @@ void QQmlListModelParser::applyBindings(QObject *obj, QV4::CompiledData::Compila } if (setRoles == false) - qmlInfo(obj) << "All ListElement declarations are empty, no roles can be created unless dynamicRoles is set."; + qmlWarning(obj) << "All ListElement declarations are empty, no roles can be created unless dynamicRoles is set."; } bool QQmlListModelParser::definesEmptyList(const QString &s) diff --git a/src/qml/types/qqmlobjectmodel.cpp b/src/qml/types/qqmlobjectmodel.cpp index 695043b592..21205f4490 100644 --- a/src/qml/types/qqmlobjectmodel.cpp +++ b/src/qml/types/qqmlobjectmodel.cpp @@ -373,7 +373,7 @@ void QQmlObjectModel::insert(int index, QObject *object) { Q_D(QQmlObjectModel); if (index < 0 || index > count()) { - qmlInfo(this) << tr("insert: index %1 out of range").arg(index); + qmlWarning(this) << tr("insert: index %1 out of range").arg(index); return; } d->insert(index, object); @@ -400,7 +400,7 @@ void QQmlObjectModel::move(int from, int to, int n) if (n <= 0 || from == to) return; if (from < 0 || to < 0 || from + n > count() || to + n > count()) { - qmlInfo(this) << tr("move: out of range"); + qmlWarning(this) << tr("move: out of range"); return; } d->move(from, to, n); @@ -418,7 +418,7 @@ void QQmlObjectModel::remove(int index, int n) { Q_D(QQmlObjectModel); if (index < 0 || n <= 0 || index + n > count()) { - qmlInfo(this) << tr("remove: indices [%1 - %2] out of range [0 - %3]").arg(index).arg(index+n).arg(count()); + qmlWarning(this) << tr("remove: indices [%1 - %2] out of range [0 - %3]").arg(index).arg(index+n).arg(count()); return; } d->remove(index, n); |