diff options
author | Simon Hausmann <simon.hausmann@qt.io> | 2017-04-07 14:48:56 +0200 |
---|---|---|
committer | Simon Hausmann <simon.hausmann@qt.io> | 2017-04-07 12:53:23 +0000 |
commit | 017350a8a9b4ac866c9b79186bf5a1dd6f6f06ec (patch) | |
tree | f98070d9bf0bd5659d34355b5eb9647637874187 /src | |
parent | b361a59c699fca02379c149cf0b9c59490a1ba62 (diff) | |
parent | 67d1d7843ab5e1c904c8f0f76eadb9fc3f1bbb17 (diff) |
Merge remote-tracking branch 'origin/5.9' into dev
Conflicts:
src/qml/jit/qv4assembler.cpp
src/qml/jit/qv4assembler_p.h
src/qml/jit/qv4isel_masm.cpp
src/qml/jsruntime/qv4vme_moth.cpp
Change-Id: I865d794e550a263387a39ca8d051ebf48b70cbc0
Diffstat (limited to 'src')
42 files changed, 916 insertions, 681 deletions
diff --git a/src/3rdparty/masm/wtf/Assertions.h b/src/3rdparty/masm/wtf/Assertions.h index 6263e50ed9..af65f5325c 100644 --- a/src/3rdparty/masm/wtf/Assertions.h +++ b/src/3rdparty/masm/wtf/Assertions.h @@ -233,7 +233,7 @@ WTF_EXPORT_PRIVATE void WTFInstallReportBacktraceOnCrashHook(); #define ASSERT_NOT_REACHED() ((void)0) #define NO_RETURN_DUE_TO_ASSERT -#if COMPILER(INTEL) && !OS(WINDOWS) || COMPILER(RVCT) +#if COMPILER(RVCT) template<typename T> inline void assertUnused(T& x) { (void)x; } #define ASSERT_UNUSED(variable, assertion) (assertUnused(variable)) diff --git a/src/imports/imports.pro b/src/imports/imports.pro index d16ac05669..c03224958c 100644 --- a/src/imports/imports.pro +++ b/src/imports/imports.pro @@ -6,9 +6,9 @@ SUBDIRS += \ builtins \ qtqml \ folderlistmodel \ - localstorage \ models +qtHaveModule(sql): SUBDIRS += localstorage qtConfig(settings): SUBDIRS += settings qtConfig(statemachine): SUBDIRS += statemachine @@ -17,9 +17,9 @@ qtHaveModule(quick) { layouts \ qtquick2 \ window \ - sharedimage \ testlib + qtConfig(systemsemaphore): SUBDIRS += sharedimage qtConfig(quick-particles): \ SUBDIRS += particles } diff --git a/src/imports/localstorage/plugin.cpp b/src/imports/localstorage/plugin.cpp index 8679750842..40682dd6a8 100644 --- a/src/imports/localstorage/plugin.cpp +++ b/src/imports/localstorage/plugin.cpp @@ -770,6 +770,8 @@ void QQuickLocalStorage::openDatabaseSync(QQmlV4Function *args) } args->setReturnValue(db.asReturnedValue()); +#else + Q_UNUSED(args) #endif // settings } diff --git a/src/particles/qquickparticlesystem.cpp b/src/particles/qquickparticlesystem.cpp index 99e278238b..6f134f08df 100644 --- a/src/particles/qquickparticlesystem.cpp +++ b/src/particles/qquickparticlesystem.cpp @@ -668,8 +668,11 @@ void QQuickParticleSystem::setPaused(bool arg) { if (m_animation && m_animation->state() != QAbstractAnimation::Stopped) m_paused ? m_animation->pause() : m_animation->resume(); if (!m_paused) { - foreach (QQuickParticlePainter *p, m_painters) - p->update(); + foreach (QQuickParticlePainter *p, m_painters) { + if (p) { + p->update(); + } + } } emit pausedChanged(arg); } @@ -873,8 +876,11 @@ void QQuickParticleSystem::emittersChanged() if (particleCount > bySysIdx.size())//New datum requests haven't updated it bySysIdx.resize(particleCount); - foreach (QQuickParticleAffector *a, m_affectors)//Groups may have changed - a->m_updateIntSet = true; + foreach (QQuickParticleAffector *a, m_affectors) {//Groups may have changed + if (a) { + a->m_updateIntSet = true; + } + } foreach (QQuickParticlePainter *p, m_painters) loadPainter(p); diff --git a/src/plugins/qmltooling/qmldbg_debugger/qqmlenginedebugservice.cpp b/src/plugins/qmltooling/qmldbg_debugger/qqmlenginedebugservice.cpp index 151e44c4d4..3fb0522cd1 100644 --- a/src/plugins/qmltooling/qmldbg_debugger/qqmlenginedebugservice.cpp +++ b/src/plugins/qmltooling/qmldbg_debugger/qqmlenginedebugservice.cpp @@ -409,18 +409,7 @@ QQmlEngineDebugServiceImpl::objectData(QObject *object) rv.objectId = QQmlDebugService::idForObject(object); rv.contextId = QQmlDebugService::idForObject(qmlContext(object)); rv.parentId = QQmlDebugService::idForObject(object->parent()); - QQmlType *type = QQmlMetaType::qmlType(object->metaObject()); - if (type) { - QString typeName = type->qmlTypeName(); - int lastSlash = typeName.lastIndexOf(QLatin1Char('/')); - rv.objectType = lastSlash < 0 ? typeName : typeName.mid(lastSlash+1); - } else { - rv.objectType = QString::fromUtf8(object->metaObject()->className()); - int marker = rv.objectType.indexOf(QLatin1String("_QMLTYPE_")); - if (marker != -1) - rv.objectType = rv.objectType.left(marker); - } - + rv.objectType = QQmlMetaType::prettyTypeName(object); return rv; } diff --git a/src/qml/compiler/compiler.pri b/src/qml/compiler/compiler.pri index fa66d3a6e3..871f28f2d0 100644 --- a/src/qml/compiler/compiler.pri +++ b/src/qml/compiler/compiler.pri @@ -10,7 +10,8 @@ HEADERS += \ $$PWD/qv4isel_util_p.h \ $$PWD/qv4ssa_p.h \ $$PWD/qqmlirbuilder_p.h \ - $$PWD/qqmltypecompiler_p.h + $$PWD/qqmltypecompiler_p.h \ + $$PWD/qv4jssimplifier_p.h SOURCES += \ $$PWD/qv4compileddata.cpp \ @@ -19,7 +20,8 @@ SOURCES += \ $$PWD/qv4isel_p.cpp \ $$PWD/qv4jsir.cpp \ $$PWD/qv4ssa.cpp \ - $$PWD/qqmlirbuilder.cpp + $$PWD/qqmlirbuilder.cpp \ + $$PWD/qv4jssimplifier.cpp !qmldevtools_build { diff --git a/src/qml/compiler/qqmltypecompiler.cpp b/src/qml/compiler/qqmltypecompiler.cpp index a3b8784fc8..d1d22be0ac 100644 --- a/src/qml/compiler/qqmltypecompiler.cpp +++ b/src/qml/compiler/qqmltypecompiler.cpp @@ -47,6 +47,7 @@ #include <private/qv4ssa_p.h> #include "qqmlpropertycachecreator_p.h" +#include "qv4jssimplifier_p.h" #define COMPILE_EXCEPTION(token, desc) \ { \ @@ -144,7 +145,7 @@ QV4::CompiledData::CompilationUnit *QQmlTypeCompiler::compile() if (!jsCodeGen.generateCodeForComponents()) return nullptr; - QQmlJavaScriptBindingExpressionSimplificationPass pass(this); + QQmlJavaScriptBindingExpressionSimplificationPass pass(document->objects, &document->jsModule, &document->jsGenerator); pass.reduceTranslationBindings(); QV4::ExecutionEngine *v4 = engine->v4engine(); @@ -1429,344 +1430,4 @@ void QQmlDefaultPropertyMerger::mergeDefaultProperties(int objectIndex) } } -QQmlJavaScriptBindingExpressionSimplificationPass::QQmlJavaScriptBindingExpressionSimplificationPass(QQmlTypeCompiler *typeCompiler) - : QQmlCompilePass(typeCompiler) - , qmlObjects(*typeCompiler->qmlObjects()) - , jsModule(typeCompiler->jsIRModule()) -{ - -} - -void QQmlJavaScriptBindingExpressionSimplificationPass::reduceTranslationBindings() -{ - for (int i = 0; i < qmlObjects.count(); ++i) - reduceTranslationBindings(i); - if (!irFunctionsToRemove.isEmpty()) { - QQmlIRFunctionCleanser cleanser(compiler, irFunctionsToRemove); - cleanser.clean(); - } -} - -void QQmlJavaScriptBindingExpressionSimplificationPass::reduceTranslationBindings(int objectIndex) -{ - const QmlIR::Object *obj = qmlObjects.at(objectIndex); - - for (QmlIR::Binding *binding = obj->firstBinding(); binding; binding = binding->next) { - if (binding->type != QV4::CompiledData::Binding::Type_Script) - continue; - - const int irFunctionIndex = obj->runtimeFunctionIndices.at(binding->value.compiledScriptIndex); - QV4::IR::Function *irFunction = jsModule->functions.at(irFunctionIndex); - if (simplifyBinding(irFunction, binding)) { - irFunctionsToRemove.append(irFunctionIndex); - jsModule->functions[irFunctionIndex] = 0; - delete irFunction; - } - } -} - -void QQmlJavaScriptBindingExpressionSimplificationPass::visitMove(QV4::IR::Move *move) -{ - QV4::IR::Temp *target = move->target->asTemp(); - if (!target || target->kind != QV4::IR::Temp::VirtualRegister) { - discard(); - return; - } - - if (QV4::IR::Call *call = move->source->asCall()) { - if (QV4::IR::Name *n = call->base->asName()) { - if (n->builtin == QV4::IR::Name::builtin_invalid) { - visitFunctionCall(n->id, call->args, target); - return; - } - } - discard(); - return; - } - - if (QV4::IR::Name *n = move->source->asName()) { - if (n->builtin == QV4::IR::Name::builtin_qml_context - || n->builtin == QV4::IR::Name::builtin_qml_imported_scripts_object) { - // these are free of side-effects - return; - } - discard(); - return; - } - - if (!move->source->asTemp() && !move->source->asString() && !move->source->asConst()) { - discard(); - return; - } - - _temps[target->index] = move->source; -} - -void QQmlJavaScriptBindingExpressionSimplificationPass::visitFunctionCall(const QString *name, QV4::IR::ExprList *args, QV4::IR::Temp *target) -{ - // more than one function call? - if (_nameOfFunctionCalled) { - discard(); - return; - } - - _nameOfFunctionCalled = name; - - _functionParameters.clear(); - while (args) { - int slot; - if (QV4::IR::Temp *param = args->expr->asTemp()) { - if (param->kind != QV4::IR::Temp::VirtualRegister) { - discard(); - return; - } - slot = param->index; - _functionParameters.append(slot); - } else if (QV4::IR::Const *param = args->expr->asConst()) { - slot = --_synthesizedConsts; - Q_ASSERT(!_temps.contains(slot)); - _temps[slot] = param; - _functionParameters.append(slot); - } - args = args->next; - } - - _functionCallReturnValue = target->index; -} - -void QQmlJavaScriptBindingExpressionSimplificationPass::visitRet(QV4::IR::Ret *ret) -{ - // nothing initialized earlier? - if (_returnValueOfBindingExpression != -1) { - discard(); - return; - } - QV4::IR::Temp *target = ret->expr->asTemp(); - if (!target || target->kind != QV4::IR::Temp::VirtualRegister) { - discard(); - return; - } - _returnValueOfBindingExpression = target->index; -} - -bool QQmlJavaScriptBindingExpressionSimplificationPass::simplifyBinding(QV4::IR::Function *function, QmlIR::Binding *binding) -{ - _canSimplify = true; - _nameOfFunctionCalled = 0; - _functionParameters.clear(); - _functionCallReturnValue = -1; - _temps.clear(); - _returnValueOfBindingExpression = -1; - _synthesizedConsts = 0; - - // It would seem unlikely that function with some many basic blocks (after optimization) - // consists merely of a qsTr call or a constant value return ;-) - if (function->basicBlockCount() > 10) - return false; - - for (QV4::IR::BasicBlock *bb : function->basicBlocks()) { - for (QV4::IR::Stmt *s : bb->statements()) { - visit(s); - if (!_canSimplify) - return false; - } - } - - if (_returnValueOfBindingExpression == -1) - return false; - - if (_nameOfFunctionCalled) { - if (_functionCallReturnValue != _returnValueOfBindingExpression) - return false; - return detectTranslationCallAndConvertBinding(binding); - } - - return false; -} - -bool QQmlJavaScriptBindingExpressionSimplificationPass::detectTranslationCallAndConvertBinding(QmlIR::Binding *binding) -{ - if (*_nameOfFunctionCalled == QLatin1String("qsTr")) { - QString translation; - QV4::CompiledData::TranslationData translationData; - translationData.number = -1; - translationData.commentIndex = 0; // empty string - - QVector<int>::ConstIterator param = _functionParameters.constBegin(); - QVector<int>::ConstIterator end = _functionParameters.constEnd(); - if (param == end) - return false; - - QV4::IR::String *stringParam = _temps[*param]->asString(); - if (!stringParam) - return false; - - translation = *stringParam->value; - - ++param; - if (param != end) { - stringParam = _temps[*param]->asString(); - if (!stringParam) - return false; - translationData.commentIndex = compiler->registerString(*stringParam->value); - ++param; - - if (param != end) { - QV4::IR::Const *constParam = _temps[*param]->asConst(); - if (!constParam || constParam->type != QV4::IR::SInt32Type) - return false; - - translationData.number = int(constParam->value); - ++param; - } - } - - if (param != end) - return false; - - binding->type = QV4::CompiledData::Binding::Type_Translation; - binding->stringIndex = compiler->registerString(translation); - binding->value.translationData = translationData; - return true; - } else if (*_nameOfFunctionCalled == QLatin1String("qsTrId")) { - QString id; - QV4::CompiledData::TranslationData translationData; - translationData.number = -1; - translationData.commentIndex = 0; // empty string, but unused - - QVector<int>::ConstIterator param = _functionParameters.constBegin(); - QVector<int>::ConstIterator end = _functionParameters.constEnd(); - if (param == end) - return false; - - QV4::IR::String *stringParam = _temps[*param]->asString(); - if (!stringParam) - return false; - - id = *stringParam->value; - - ++param; - if (param != end) { - QV4::IR::Const *constParam = _temps[*param]->asConst(); - if (!constParam || constParam->type != QV4::IR::SInt32Type) - return false; - - translationData.number = int(constParam->value); - ++param; - } - - if (param != end) - return false; - - binding->type = QV4::CompiledData::Binding::Type_TranslationById; - binding->stringIndex = compiler->registerString(id); - binding->value.translationData = translationData; - return true; - } else if (*_nameOfFunctionCalled == QLatin1String("QT_TR_NOOP") || *_nameOfFunctionCalled == QLatin1String("QT_TRID_NOOP")) { - QVector<int>::ConstIterator param = _functionParameters.constBegin(); - QVector<int>::ConstIterator end = _functionParameters.constEnd(); - if (param == end) - return false; - - QV4::IR::String *stringParam = _temps[*param]->asString(); - if (!stringParam) - return false; - - ++param; - if (param != end) - return false; - - binding->type = QV4::CompiledData::Binding::Type_String; - binding->stringIndex = compiler->registerString(*stringParam->value); - return true; - } else if (*_nameOfFunctionCalled == QLatin1String("QT_TRANSLATE_NOOP")) { - QVector<int>::ConstIterator param = _functionParameters.constBegin(); - QVector<int>::ConstIterator end = _functionParameters.constEnd(); - if (param == end) - return false; - - ++param; - if (param == end) - return false; - - QV4::IR::String *stringParam = _temps[*param]->asString(); - if (!stringParam) - return false; - - ++param; - if (param != end) - return false; - - binding->type = QV4::CompiledData::Binding::Type_String; - binding->stringIndex = compiler->registerString(*stringParam->value); - return true; - } - return false; -} - -QQmlIRFunctionCleanser::QQmlIRFunctionCleanser(QQmlTypeCompiler *typeCompiler, const QVector<int> &functionsToRemove) - : QQmlCompilePass(typeCompiler) - , module(typeCompiler->jsIRModule()) - , functionsToRemove(functionsToRemove) -{ -} - -void QQmlIRFunctionCleanser::clean() -{ - QVector<QV4::IR::Function*> newFunctions; - newFunctions.reserve(module->functions.count() - functionsToRemove.count()); - - newFunctionIndices.resize(module->functions.count()); - - for (int i = 0; i < module->functions.count(); ++i) { - QV4::IR::Function *f = module->functions.at(i); - Q_ASSERT(f || functionsToRemove.contains(i)); - if (f) { - newFunctionIndices[i] = newFunctions.count(); - newFunctions << f; - } - } - - module->functions = newFunctions; - - for (QV4::IR::Function *function : qAsConst(module->functions)) { - for (QV4::IR::BasicBlock *block : function->basicBlocks()) { - for (QV4::IR::Stmt *s : block->statements()) { - visit(s); - } - } - } - - for (QmlIR::Object *obj : qAsConst(*compiler->qmlObjects())) { - for (int i = 0; i < obj->runtimeFunctionIndices.count; ++i) - obj->runtimeFunctionIndices[i] = newFunctionIndices[obj->runtimeFunctionIndices.at(i)]; - } -} - -void QQmlIRFunctionCleanser::visit(QV4::IR::Stmt *s) -{ - - switch (s->stmtKind) { - case QV4::IR::Stmt::PhiStmt: - // nothing to do - break; - default: - STMT_VISIT_ALL_KINDS(s); - break; - } -} - -void QQmlIRFunctionCleanser::visit(QV4::IR::Expr *e) -{ - switch (e->exprKind) { - case QV4::IR::Expr::ClosureExpr: { - auto closure = e->asClosure(); - closure->value = newFunctionIndices.at(closure->value); - } break; - default: - EXPR_VISIT_ALL_KINDS(e); - break; - } -} - QT_END_NAMESPACE diff --git a/src/qml/compiler/qqmltypecompiler_p.h b/src/qml/compiler/qqmltypecompiler_p.h index 11261e3099..79fc073d8b 100644 --- a/src/qml/compiler/qqmltypecompiler_p.h +++ b/src/qml/compiler/qqmltypecompiler_p.h @@ -345,86 +345,6 @@ private: const QQmlPropertyCacheVector * const propertyCaches; }; -class QQmlJavaScriptBindingExpressionSimplificationPass : public QQmlCompilePass -{ -public: - QQmlJavaScriptBindingExpressionSimplificationPass(QQmlTypeCompiler *typeCompiler); - - void reduceTranslationBindings(); - -private: - void reduceTranslationBindings(int objectIndex); - - void visit(QV4::IR::Stmt *s) - { - switch (s->stmtKind) { - case QV4::IR::Stmt::MoveStmt: - visitMove(s->asMove()); - break; - case QV4::IR::Stmt::RetStmt: - visitRet(s->asRet()); - break; - case QV4::IR::Stmt::CJumpStmt: - discard(); - break; - case QV4::IR::Stmt::ExpStmt: - discard(); - break; - case QV4::IR::Stmt::JumpStmt: - break; - case QV4::IR::Stmt::PhiStmt: - break; - } - } - - void visitMove(QV4::IR::Move *move); - void visitRet(QV4::IR::Ret *ret); - - void visitFunctionCall(const QString *name, QV4::IR::ExprList *args, QV4::IR::Temp *target); - - void discard() { _canSimplify = false; } - - bool simplifyBinding(QV4::IR::Function *function, QmlIR::Binding *binding); - bool detectTranslationCallAndConvertBinding(QmlIR::Binding *binding); - - const QVector<QmlIR::Object*> &qmlObjects; - QV4::IR::Module *jsModule; - - bool _canSimplify; - const QString *_nameOfFunctionCalled; - QVector<int> _functionParameters; - int _functionCallReturnValue; - - QHash<int, QV4::IR::Expr*> _temps; - int _returnValueOfBindingExpression; - int _synthesizedConsts; - - QVector<int> irFunctionsToRemove; -}; - -class QQmlIRFunctionCleanser : public QQmlCompilePass -{ -public: - QQmlIRFunctionCleanser(QQmlTypeCompiler *typeCompiler, const QVector<int> &functionsToRemove); - - void clean(); - -private: - virtual void visitMove(QV4::IR::Move *s) { - visit(s->source); - visit(s->target); - } - - void visit(QV4::IR::Stmt *s); - void visit(QV4::IR::Expr *e); - -private: - QV4::IR::Module *module; - const QVector<int> &functionsToRemove; - - QVector<int> newFunctionIndices; -}; - QT_END_NAMESPACE #endif // QQMLTYPECOMPILER_P_H diff --git a/src/qml/compiler/qv4codegen.cpp b/src/qml/compiler/qv4codegen.cpp index 3234e7ee63..693a4230ba 100644 --- a/src/qml/compiler/qv4codegen.cpp +++ b/src/qml/compiler/qv4codegen.cpp @@ -92,6 +92,27 @@ static bool cjumpCanHandle(IR::AluOp op) } } +static inline void setJumpOutLocation(IR::Stmt *s, const Statement *body, + const SourceLocation &fallback) +{ + switch (body->kind) { + // Statements where we might never execute the last line. + // Use the fallback. + case Statement::Kind_ConditionalExpression: + case Statement::Kind_ForEachStatement: + case Statement::Kind_ForStatement: + case Statement::Kind_IfStatement: + case Statement::Kind_LocalForEachStatement: + case Statement::Kind_LocalForStatement: + case Statement::Kind_WhileStatement: + setLocation(s, fallback); + break; + default: + setLocation(s, body->lastSourceLocation()); + break; + } +} + Codegen::ScanFunctions::ScanFunctions(Codegen *cg, const QString &sourceCode, CompilationMode defaultProgramMode) : _cg(cg) , _sourceCode(sourceCode) @@ -2269,7 +2290,7 @@ bool Codegen::visit(DoWhileStatement *ast) _block = loopbody; statement(ast->statement); - setLocation(_block->JUMP(loopcond), ast->statement->lastSourceLocation()); + setJumpOutLocation(_block->JUMP(loopcond), ast->statement, ast->semicolonToken); _block = loopcond; condition(ast->expression, loopbody, loopend); @@ -2334,7 +2355,7 @@ bool Codegen::visit(ForEachStatement *ast) return false; move(*init, _block->TEMP(temp)); statement(ast->statement); - setLocation(_block->JUMP(foreachin), ast->lastSourceLocation()); + setJumpOutLocation(_block->JUMP(foreachin), ast->statement, ast->forToken); _block = foreachin; @@ -2373,7 +2394,7 @@ bool Codegen::visit(ForStatement *ast) _block = forbody; statement(ast->statement); - setLocation(_block->JUMP(forstep), ast->lastSourceLocation()); + setJumpOutLocation(_block->JUMP(forstep), ast->statement, ast->forToken); _block = forstep; statement(ast->expression); @@ -2399,12 +2420,12 @@ bool Codegen::visit(IfStatement *ast) _block = iftrue; statement(ast->ok); - _block->JUMP(endif); + setJumpOutLocation(_block->JUMP(endif), ast->ok, ast->ifToken); if (ast->ko) { _block = iffalse; statement(ast->ko); - _block->JUMP(endif); + setJumpOutLocation(_block->JUMP(endif), ast->ko, ast->elseToken); } _block = endif; @@ -2473,7 +2494,7 @@ bool Codegen::visit(LocalForEachStatement *ast) int temp = _block->newTemp(); move(identifier(ast->declaration->name.toString()), _block->TEMP(temp)); statement(ast->statement); - setLocation(_block->JUMP(foreachin), ast->lastSourceLocation()); + setJumpOutLocation(_block->JUMP(foreachin), ast->statement, ast->forToken); _block = foreachin; @@ -2512,7 +2533,7 @@ bool Codegen::visit(LocalForStatement *ast) _block = forbody; statement(ast->statement); - setLocation(_block->JUMP(forstep), ast->lastSourceLocation()); + setJumpOutLocation(_block->JUMP(forstep), ast->statement, ast->forToken); _block = forstep; statement(ast->expression); @@ -2813,7 +2834,7 @@ bool Codegen::visit(WhileStatement *ast) _block = whilebody; statement(ast->statement); - setLocation(_block->JUMP(whilecond), ast->lastSourceLocation()); + setJumpOutLocation(_block->JUMP(whilecond), ast->statement, ast->whileToken); _block = whileend; leaveLoop(); diff --git a/src/qml/compiler/qv4compileddata.cpp b/src/qml/compiler/qv4compileddata.cpp index 7940e5715e..d5e91a1bc6 100644 --- a/src/qml/compiler/qv4compileddata.cpp +++ b/src/qml/compiler/qv4compileddata.cpp @@ -461,6 +461,7 @@ bool CompilationUnit::saveToDisk(const QUrl &unitUrl, QString *errorString) return true; #else + Q_UNUSED(outputFileName) *errorString = QStringLiteral("features.temporaryfile is disabled."); return false; #endif // QT_CONFIG(temporaryfile) @@ -745,7 +746,7 @@ static QByteArray ownLibraryChecksum() if (dladdr(reinterpret_cast<const void *>(&ownLibraryChecksum), &libInfo) != 0) { QFile library(QFile::decodeName(libInfo.dli_fname)); if (library.open(QIODevice::ReadOnly)) { - QCryptographicHash hash(QCryptographicHash::Sha1); + QCryptographicHash hash(QCryptographicHash::Md5); hash.addData(&library); libraryChecksum = hash.result(); } diff --git a/src/qml/compiler/qv4compiler.cpp b/src/qml/compiler/qv4compiler.cpp index b81d724fe7..f7e63437e1 100644 --- a/src/qml/compiler/qv4compiler.cpp +++ b/src/qml/compiler/qv4compiler.cpp @@ -376,7 +376,7 @@ QV4::CompiledData::Unit QV4::Compiler::JSUnitGenerator::generateHeader(QV4::Comp unit.version = QV4_DATA_STRUCTURE_VERSION; unit.qtVersion = QT_VERSION; memset(unit.md5Checksum, 0, sizeof(unit.md5Checksum)); - unit.architectureIndex = registerString(QSysInfo::buildAbi()); + unit.architectureIndex = registerString(irModule->targetABI.isEmpty() ? QSysInfo::buildAbi() : irModule->targetABI); unit.codeGeneratorIndex = registerString(codeGeneratorName); memset(unit.dependencyMD5Checksum, 0, sizeof(unit.dependencyMD5Checksum)); diff --git a/src/qml/compiler/qv4isel_util_p.h b/src/qml/compiler/qv4isel_util_p.h index 1755193d32..e949e6f0ad 100644 --- a/src/qml/compiler/qv4isel_util_p.h +++ b/src/qml/compiler/qv4isel_util_p.h @@ -58,6 +58,59 @@ QT_BEGIN_NAMESPACE namespace QV4 { +struct TargetPrimitive32 { + static TargetPrimitive32 emptyValue() { TargetPrimitive32 p; p._val = quint64(Value::ValueTypeInternal_32::Empty) << 32; return p; } + static TargetPrimitive32 nullValue() { TargetPrimitive32 p; p._val = quint64(Value::ValueTypeInternal_32::Null) << 32; return p; } + static TargetPrimitive32 undefinedValue() { TargetPrimitive32 p; p._val = quint64(Value::Managed_Type_Internal_32) << 32; return p; } + static TargetPrimitive32 fromBoolean(bool b) { TargetPrimitive32 p; p._val = quint64(Value::ValueTypeInternal_32::Boolean) << 32 | quint64(b); return p; } + static TargetPrimitive32 fromInt32(int v) { TargetPrimitive32 p; p._val = quint64(Value::ValueTypeInternal_32::Integer) << 32 | quint32(v); return p; } + static TargetPrimitive32 fromDouble(double v) { + TargetPrimitive32 p; + memcpy(&p._val, &v, 8); + return p; + } + static TargetPrimitive32 fromUInt32(uint v) { + if (v < INT_MAX) + return fromInt32(qint32(v)); + return fromDouble(double(v)); + } + + quint32 value() const { return _val & quint64(~quint32(0)); } + quint32 tag() const { return _val >> 32; } + + quint64 rawValue() const { return _val; } + +private: + quint64 _val; +}; + +struct TargetPrimitive64 { + static TargetPrimitive64 emptyValue() { TargetPrimitive64 p; p._val = quint64(Value::ValueTypeInternal_64::Empty) << 32; return p; } + static TargetPrimitive64 nullValue() { TargetPrimitive64 p; p._val = quint64(Value::ValueTypeInternal_64::Null) << 32; return p; } + static TargetPrimitive64 undefinedValue() { TargetPrimitive64 p; p._val = 0; return p; } + static TargetPrimitive64 fromBoolean(bool b) { TargetPrimitive64 p; p._val = quint64(Value::ValueTypeInternal_64::Boolean) << 32 | quint64(b); return p; } + static TargetPrimitive64 fromInt32(int v) { TargetPrimitive64 p; p._val = quint64(Value::ValueTypeInternal_64::Integer) << 32 | quint32(v); return p; } + static TargetPrimitive64 fromDouble(double v) { + TargetPrimitive64 p; + memcpy(&p._val, &v, 8); + p._val ^= Value::NaNEncodeMask; + return p; + } + static TargetPrimitive64 fromUInt32(uint v) { + if (v < INT_MAX) + return fromInt32(qint32(v)); + return fromDouble(double(v)); + } + + quint32 value() const { return _val & quint64(~quint32(0)); } + quint32 tag() const { return _val >> 32; } + + quint64 rawValue() const { return _val; } + +private: + quint64 _val; +}; + inline bool canConvertToSignedInteger(double value) { int ival = (int) value; @@ -72,36 +125,37 @@ inline bool canConvertToUnsignedInteger(double value) return uval == value && !(value == 0 && isNegative(value)); } -inline Primitive convertToValue(IR::Const *c) +template <typename PrimitiveType = Primitive> +inline PrimitiveType convertToValue(IR::Const *c) { switch (c->type) { case IR::MissingType: - return Primitive::emptyValue(); + return PrimitiveType::emptyValue(); case IR::NullType: - return Primitive::nullValue(); + return PrimitiveType::nullValue(); case IR::UndefinedType: - return Primitive::undefinedValue(); + return PrimitiveType::undefinedValue(); case IR::BoolType: - return Primitive::fromBoolean(c->value != 0); + return PrimitiveType::fromBoolean(c->value != 0); case IR::SInt32Type: - return Primitive::fromInt32(int(c->value)); + return PrimitiveType::fromInt32(int(c->value)); case IR::UInt32Type: - return Primitive::fromUInt32(unsigned(c->value)); + return PrimitiveType::fromUInt32(unsigned(c->value)); case IR::DoubleType: - return Primitive::fromDouble(c->value); + return PrimitiveType::fromDouble(c->value); case IR::NumberType: { int ival = (int)c->value; if (canConvertToSignedInteger(c->value)) { - return Primitive::fromInt32(ival); + return PrimitiveType::fromInt32(ival); } else { - return Primitive::fromDouble(c->value); + return PrimitiveType::fromDouble(c->value); } } default: Q_UNREACHABLE(); } // unreachable, but the function must return something - return Primitive::undefinedValue(); + return PrimitiveType::undefinedValue(); } class ConvertTemps diff --git a/src/qml/compiler/qv4jsir_p.h b/src/qml/compiler/qv4jsir_p.h index f7c7b76ea8..35cf0fc174 100644 --- a/src/qml/compiler/qv4jsir_p.h +++ b/src/qml/compiler/qv4jsir_p.h @@ -946,6 +946,7 @@ struct Q_QML_PRIVATE_EXPORT Module { QDateTime sourceTimeStamp; bool isQmlModule; // implies rootFunction is always 0 uint unitFlags; // flags merged into CompiledData::Unit::flags + QString targetABI; // fallback to QSysInfo::buildAbi() if empty #ifdef QT_NO_QML_DEBUGGER static const bool debugMode = false; #else diff --git a/src/qml/compiler/qv4jssimplifier.cpp b/src/qml/compiler/qv4jssimplifier.cpp new file mode 100644 index 0000000000..7d09218fe6 --- /dev/null +++ b/src/qml/compiler/qv4jssimplifier.cpp @@ -0,0 +1,384 @@ +/**************************************************************************** +** +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the tools applications of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qv4jssimplifier_p.h" + +QT_BEGIN_NAMESPACE + +QQmlJavaScriptBindingExpressionSimplificationPass::QQmlJavaScriptBindingExpressionSimplificationPass(const QVector<QmlIR::Object*> &qmlObjects, QV4::IR::Module *jsModule, QV4::Compiler::JSUnitGenerator *unitGenerator) + : qmlObjects(qmlObjects) + , jsModule(jsModule) + , unitGenerator(unitGenerator) +{ + +} + +void QQmlJavaScriptBindingExpressionSimplificationPass::reduceTranslationBindings() +{ + for (int i = 0; i < qmlObjects.count(); ++i) + reduceTranslationBindings(i); + if (!irFunctionsToRemove.isEmpty()) { + QQmlIRFunctionCleanser cleanser(jsModule, qmlObjects, irFunctionsToRemove); + cleanser.clean(); + } +} + +void QQmlJavaScriptBindingExpressionSimplificationPass::reduceTranslationBindings(int objectIndex) +{ + const QmlIR::Object *obj = qmlObjects.at(objectIndex); + + for (QmlIR::Binding *binding = obj->firstBinding(); binding; binding = binding->next) { + if (binding->type != QV4::CompiledData::Binding::Type_Script) + continue; + + const int irFunctionIndex = obj->runtimeFunctionIndices.at(binding->value.compiledScriptIndex); + QV4::IR::Function *irFunction = jsModule->functions.at(irFunctionIndex); + if (simplifyBinding(irFunction, binding)) { + irFunctionsToRemove.append(irFunctionIndex); + jsModule->functions[irFunctionIndex] = 0; + delete irFunction; + } + } +} + +void QQmlJavaScriptBindingExpressionSimplificationPass::visitMove(QV4::IR::Move *move) +{ + QV4::IR::Temp *target = move->target->asTemp(); + if (!target || target->kind != QV4::IR::Temp::VirtualRegister) { + discard(); + return; + } + + if (QV4::IR::Call *call = move->source->asCall()) { + if (QV4::IR::Name *n = call->base->asName()) { + if (n->builtin == QV4::IR::Name::builtin_invalid) { + visitFunctionCall(n->id, call->args, target); + return; + } + } + discard(); + return; + } + + if (QV4::IR::Name *n = move->source->asName()) { + if (n->builtin == QV4::IR::Name::builtin_qml_context + || n->builtin == QV4::IR::Name::builtin_qml_imported_scripts_object) { + // these are free of side-effects + return; + } + discard(); + return; + } + + if (!move->source->asTemp() && !move->source->asString() && !move->source->asConst()) { + discard(); + return; + } + + _temps[target->index] = move->source; +} + +void QQmlJavaScriptBindingExpressionSimplificationPass::visitFunctionCall(const QString *name, QV4::IR::ExprList *args, QV4::IR::Temp *target) +{ + // more than one function call? + if (_nameOfFunctionCalled) { + discard(); + return; + } + + _nameOfFunctionCalled = name; + + _functionParameters.clear(); + while (args) { + int slot; + if (QV4::IR::Temp *param = args->expr->asTemp()) { + if (param->kind != QV4::IR::Temp::VirtualRegister) { + discard(); + return; + } + slot = param->index; + _functionParameters.append(slot); + } else if (QV4::IR::Const *param = args->expr->asConst()) { + slot = --_synthesizedConsts; + Q_ASSERT(!_temps.contains(slot)); + _temps[slot] = param; + _functionParameters.append(slot); + } + args = args->next; + } + + _functionCallReturnValue = target->index; +} + +void QQmlJavaScriptBindingExpressionSimplificationPass::visitRet(QV4::IR::Ret *ret) +{ + // nothing initialized earlier? + if (_returnValueOfBindingExpression != -1) { + discard(); + return; + } + QV4::IR::Temp *target = ret->expr->asTemp(); + if (!target || target->kind != QV4::IR::Temp::VirtualRegister) { + discard(); + return; + } + _returnValueOfBindingExpression = target->index; +} + +bool QQmlJavaScriptBindingExpressionSimplificationPass::simplifyBinding(QV4::IR::Function *function, QmlIR::Binding *binding) +{ + _canSimplify = true; + _nameOfFunctionCalled = 0; + _functionParameters.clear(); + _functionCallReturnValue = -1; + _temps.clear(); + _returnValueOfBindingExpression = -1; + _synthesizedConsts = 0; + + // It would seem unlikely that function with some many basic blocks (after optimization) + // consists merely of a qsTr call or a constant value return ;-) + if (function->basicBlockCount() > 10) + return false; + + for (QV4::IR::BasicBlock *bb : function->basicBlocks()) { + for (QV4::IR::Stmt *s : bb->statements()) { + visit(s); + if (!_canSimplify) + return false; + } + } + + if (_returnValueOfBindingExpression == -1) + return false; + + if (_nameOfFunctionCalled) { + if (_functionCallReturnValue != _returnValueOfBindingExpression) + return false; + return detectTranslationCallAndConvertBinding(binding); + } + + return false; +} + +bool QQmlJavaScriptBindingExpressionSimplificationPass::detectTranslationCallAndConvertBinding(QmlIR::Binding *binding) +{ + if (*_nameOfFunctionCalled == QLatin1String("qsTr")) { + QString translation; + QV4::CompiledData::TranslationData translationData; + translationData.number = -1; + translationData.commentIndex = 0; // empty string + + QVector<int>::ConstIterator param = _functionParameters.constBegin(); + QVector<int>::ConstIterator end = _functionParameters.constEnd(); + if (param == end) + return false; + + QV4::IR::String *stringParam = _temps[*param]->asString(); + if (!stringParam) + return false; + + translation = *stringParam->value; + + ++param; + if (param != end) { + stringParam = _temps[*param]->asString(); + if (!stringParam) + return false; + translationData.commentIndex = unitGenerator->registerString(*stringParam->value); + ++param; + + if (param != end) { + QV4::IR::Const *constParam = _temps[*param]->asConst(); + if (!constParam || constParam->type != QV4::IR::SInt32Type) + return false; + + translationData.number = int(constParam->value); + ++param; + } + } + + if (param != end) + return false; + + binding->type = QV4::CompiledData::Binding::Type_Translation; + binding->stringIndex = unitGenerator->registerString(translation); + binding->value.translationData = translationData; + return true; + } else if (*_nameOfFunctionCalled == QLatin1String("qsTrId")) { + QString id; + QV4::CompiledData::TranslationData translationData; + translationData.number = -1; + translationData.commentIndex = 0; // empty string, but unused + + QVector<int>::ConstIterator param = _functionParameters.constBegin(); + QVector<int>::ConstIterator end = _functionParameters.constEnd(); + if (param == end) + return false; + + QV4::IR::String *stringParam = _temps[*param]->asString(); + if (!stringParam) + return false; + + id = *stringParam->value; + + ++param; + if (param != end) { + QV4::IR::Const *constParam = _temps[*param]->asConst(); + if (!constParam || constParam->type != QV4::IR::SInt32Type) + return false; + + translationData.number = int(constParam->value); + ++param; + } + + if (param != end) + return false; + + binding->type = QV4::CompiledData::Binding::Type_TranslationById; + binding->stringIndex = unitGenerator->registerString(id); + binding->value.translationData = translationData; + return true; + } else if (*_nameOfFunctionCalled == QLatin1String("QT_TR_NOOP") || *_nameOfFunctionCalled == QLatin1String("QT_TRID_NOOP")) { + QVector<int>::ConstIterator param = _functionParameters.constBegin(); + QVector<int>::ConstIterator end = _functionParameters.constEnd(); + if (param == end) + return false; + + QV4::IR::String *stringParam = _temps[*param]->asString(); + if (!stringParam) + return false; + + ++param; + if (param != end) + return false; + + binding->type = QV4::CompiledData::Binding::Type_String; + binding->stringIndex = unitGenerator->registerString(*stringParam->value); + return true; + } else if (*_nameOfFunctionCalled == QLatin1String("QT_TRANSLATE_NOOP")) { + QVector<int>::ConstIterator param = _functionParameters.constBegin(); + QVector<int>::ConstIterator end = _functionParameters.constEnd(); + if (param == end) + return false; + + ++param; + if (param == end) + return false; + + QV4::IR::String *stringParam = _temps[*param]->asString(); + if (!stringParam) + return false; + + ++param; + if (param != end) + return false; + + binding->type = QV4::CompiledData::Binding::Type_String; + binding->stringIndex = unitGenerator->registerString(*stringParam->value); + return true; + } + return false; +} + +QQmlIRFunctionCleanser::QQmlIRFunctionCleanser(QV4::IR::Module *module, const QVector<QmlIR::Object *> &qmlObjects, const QVector<int> &functionsToRemove) + : module(module) + , qmlObjects(qmlObjects) + , functionsToRemove(functionsToRemove) +{ +} + +void QQmlIRFunctionCleanser::clean() +{ + QVector<QV4::IR::Function*> newFunctions; + newFunctions.reserve(module->functions.count() - functionsToRemove.count()); + + newFunctionIndices.resize(module->functions.count()); + + for (int i = 0; i < module->functions.count(); ++i) { + QV4::IR::Function *f = module->functions.at(i); + Q_ASSERT(f || functionsToRemove.contains(i)); + if (f) { + newFunctionIndices[i] = newFunctions.count(); + newFunctions << f; + } + } + + module->functions = newFunctions; + + for (QV4::IR::Function *function : qAsConst(module->functions)) { + for (QV4::IR::BasicBlock *block : function->basicBlocks()) { + for (QV4::IR::Stmt *s : block->statements()) { + visit(s); + } + } + } + + for (QmlIR::Object *obj : qmlObjects) { + for (int i = 0; i < obj->runtimeFunctionIndices.count; ++i) + obj->runtimeFunctionIndices[i] = newFunctionIndices[obj->runtimeFunctionIndices.at(i)]; + } +} + +void QQmlIRFunctionCleanser::visit(QV4::IR::Stmt *s) +{ + + switch (s->stmtKind) { + case QV4::IR::Stmt::PhiStmt: + // nothing to do + break; + default: + STMT_VISIT_ALL_KINDS(s); + break; + } +} + +void QQmlIRFunctionCleanser::visit(QV4::IR::Expr *e) +{ + switch (e->exprKind) { + case QV4::IR::Expr::ClosureExpr: { + auto closure = e->asClosure(); + closure->value = newFunctionIndices.at(closure->value); + } break; + default: + EXPR_VISIT_ALL_KINDS(e); + break; + } +} + +QT_END_NAMESPACE diff --git a/src/qml/compiler/qv4jssimplifier_p.h b/src/qml/compiler/qv4jssimplifier_p.h new file mode 100644 index 0000000000..ae8d74135c --- /dev/null +++ b/src/qml/compiler/qv4jssimplifier_p.h @@ -0,0 +1,154 @@ +/**************************************************************************** +** +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the tools applications of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ +#ifndef QV4JSSIMPLIFIER +#define QV4JSSIMPLIFIER + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include <private/qv4global_p.h> + +#include "qqmlirbuilder_p.h" + +QT_BEGIN_NAMESPACE + +namespace QmlIR { +struct Document; +} + +namespace QV4 { +namespace CompiledData { +struct QmlUnit; +struct Location; +} +} + +class QQmlJavaScriptBindingExpressionSimplificationPass +{ +public: + QQmlJavaScriptBindingExpressionSimplificationPass(const QVector<QmlIR::Object*> &qmlObjects, QV4::IR::Module *jsModule, QV4::Compiler::JSUnitGenerator *unitGenerator); + + void reduceTranslationBindings(); + +private: + void reduceTranslationBindings(int objectIndex); + + void visit(QV4::IR::Stmt *s) + { + switch (s->stmtKind) { + case QV4::IR::Stmt::MoveStmt: + visitMove(s->asMove()); + break; + case QV4::IR::Stmt::RetStmt: + visitRet(s->asRet()); + break; + case QV4::IR::Stmt::CJumpStmt: + discard(); + break; + case QV4::IR::Stmt::ExpStmt: + discard(); + break; + case QV4::IR::Stmt::JumpStmt: + break; + case QV4::IR::Stmt::PhiStmt: + break; + } + } + + void visitMove(QV4::IR::Move *move); + void visitRet(QV4::IR::Ret *ret); + + void visitFunctionCall(const QString *name, QV4::IR::ExprList *args, QV4::IR::Temp *target); + + void discard() { _canSimplify = false; } + + bool simplifyBinding(QV4::IR::Function *function, QmlIR::Binding *binding); + bool detectTranslationCallAndConvertBinding(QmlIR::Binding *binding); + + const QVector<QmlIR::Object*> &qmlObjects; + QV4::IR::Module *jsModule; + QV4::Compiler::JSUnitGenerator *unitGenerator; + + bool _canSimplify; + const QString *_nameOfFunctionCalled; + QVector<int> _functionParameters; + int _functionCallReturnValue; + + QHash<int, QV4::IR::Expr*> _temps; + int _returnValueOfBindingExpression; + int _synthesizedConsts; + + QVector<int> irFunctionsToRemove; +}; + +class QQmlIRFunctionCleanser +{ +public: + QQmlIRFunctionCleanser(QV4::IR::Module *module, const QVector<QmlIR::Object*> &qmlObjects, const QVector<int> &functionsToRemove); + + void clean(); + +private: + virtual void visitMove(QV4::IR::Move *s) { + visit(s->source); + visit(s->target); + } + + void visit(QV4::IR::Stmt *s); + void visit(QV4::IR::Expr *e); + +private: + QV4::IR::Module *module; + const QVector<QmlIR::Object*> &qmlObjects; + const QVector<int> &functionsToRemove; + + QVector<int> newFunctionIndices; +}; + +QT_END_NAMESPACE + +#endif // QV4JSSIMPLIFIER diff --git a/src/qml/doc/src/cppintegration/definetypes.qdoc b/src/qml/doc/src/cppintegration/definetypes.qdoc index 7d4a543089..32084bd308 100644 --- a/src/qml/doc/src/cppintegration/definetypes.qdoc +++ b/src/qml/doc/src/cppintegration/definetypes.qdoc @@ -687,7 +687,7 @@ class MessageBoard : public QObject Q_PROPERTY(QQmlListProperty<Message> messages READ messages) Q_CLASSINFO("DefaultProperty", "messages") public: - QQmlListProperty<Message> messages() const; + QQmlListProperty<Message> messages(); private: QList<Message *> messages; diff --git a/src/qml/doc/src/cppintegration/exposecppattributes.qdoc b/src/qml/doc/src/cppintegration/exposecppattributes.qdoc index 3bffd2eb6f..c4c58c2821 100644 --- a/src/qml/doc/src/cppintegration/exposecppattributes.qdoc +++ b/src/qml/doc/src/cppintegration/exposecppattributes.qdoc @@ -267,7 +267,7 @@ class MessageBoard : public QObject Q_OBJECT Q_PROPERTY(QQmlListProperty<Message> messages READ messages) public: - QQmlListProperty<Message> messages() const; + QQmlListProperty<Message> messages(); private: static void append_message(QQmlListProperty<Message> *list, Message *msg); diff --git a/src/qml/jit/qv4assembler.cpp b/src/qml/jit/qv4assembler.cpp index 583719a3c7..d062f3bbb2 100644 --- a/src/qml/jit/qv4assembler.cpp +++ b/src/qml/jit/qv4assembler.cpp @@ -156,9 +156,6 @@ bool CompilationUnit::saveCodeToDisk(QIODevice *device, const CompiledData::Unit } template <typename TargetConfiguration> -const typename Assembler<TargetConfiguration>::VoidType Assembler<TargetConfiguration>::Void; - -template <typename TargetConfiguration> Assembler<TargetConfiguration>::Assembler(QV4::Compiler::JSUnitGenerator *jsGenerator, IR::Function* function, QV4::ExecutableAllocator *executableAllocator) : _function(function) , _nextBlock(0) @@ -324,21 +321,21 @@ typename Assembler<TargetConfiguration>::Pointer Assembler<TargetConfiguration>: loadPtr(Address(Assembler::ScratchRegister, targetStructureOffset(Heap::ExecutionContextData::baseOffset + offsetof(Heap::ExecutionContextData, compilationUnit))), Assembler::ScratchRegister); loadPtr(Address(Assembler::ScratchRegister, offsetof(CompiledData::CompilationUnitBase, runtimeStrings)), reg); const int id = _jsGenerator->registerString(string); - return Pointer(reg, id * sizeof(QV4::String*)); + return Pointer(reg, id * RegisterSize); } template <typename TargetConfiguration> typename Assembler<TargetConfiguration>::Address Assembler<TargetConfiguration>::loadConstant(IR::Const *c, RegisterID baseReg) { - return loadConstant(convertToValue(c), baseReg); + return loadConstant(convertToValue<TargetPrimitive>(c), baseReg); } template <typename TargetConfiguration> -typename Assembler<TargetConfiguration>::Address Assembler<TargetConfiguration>::loadConstant(const Primitive &v, RegisterID baseReg) +typename Assembler<TargetConfiguration>::Address Assembler<TargetConfiguration>::loadConstant(const TargetPrimitive &v, RegisterID baseReg) { loadPtr(Address(Assembler::EngineRegister, targetStructureOffset(offsetof(QV4::EngineBase, current))), baseReg); loadPtr(Address(baseReg, targetStructureOffset(Heap::ExecutionContextData::baseOffset + offsetof(Heap::ExecutionContextData, constantTable))), baseReg); - const int index = _jsGenerator->registerConstant(v.asReturnedValue()); + const int index = _jsGenerator->registerConstant(v.rawValue()); return Address(baseReg, index * sizeof(QV4::Value)); } @@ -350,7 +347,7 @@ void Assembler<TargetConfiguration>::loadStringRef(RegisterID reg, const QString } template <typename TargetConfiguration> -void Assembler<TargetConfiguration>::storeValue(QV4::Primitive value, IR::Expr *destination) +void Assembler<TargetConfiguration>::storeValue(TargetPrimitive value, IR::Expr *destination) { WriteBarrier::Type barrier; Address addr = loadAddressForWriting(ScratchRegister, destination, &barrier); @@ -449,19 +446,13 @@ typename Assembler<TargetConfiguration>::Jump Assembler<TargetConfiguration>::ge // check if it's an int32: Assembler::Jump isNoInt = branch32(Assembler::NotEqual, Assembler::ScratchRegister, - Assembler::TrustedImm32(Value::Integer_Type_Internal)); + Assembler::TrustedImm32(quint32(ValueTypeInternal::Integer))); convertInt32ToDouble(toInt32Register(src, Assembler::ScratchRegister), dest); Assembler::Jump intDone = jump(); // not an int, check if it's a double: isNoInt.link(this); -#ifdef QV4_USE_64_BIT_VALUE_ENCODING - rshift32(TrustedImm32(Value::IsDoubleTag_Shift), ScratchRegister); - Assembler::Jump isNoDbl = branch32(RelationalCondition::Equal, JITTargetPlatform::ScratchRegister, TrustedImm32(0)); -#else - and32(Assembler::TrustedImm32(Value::NotDouble_Mask), Assembler::ScratchRegister); - Assembler::Jump isNoDbl = branch32(RelationalCondition::Equal, JITTargetPlatform::ScratchRegister, TrustedImm32(Value::NotDouble_Mask)); -#endif + Assembler::Jump isNoDbl = RegisterSizeDependentOps::checkIfTagRegisterIsDouble(this, ScratchRegister); toDoubleRegister(src, dest); intDone.link(this); @@ -530,7 +521,7 @@ void Assembler<TargetConfiguration>::returnFromFunction(IR::Ret *s, RegisterInfo } else if (IR::Temp *t = s->expr->asTemp()) { RegisterSizeDependentOps::setFunctionReturnValueFromTemp(this, t); } else if (IR::Const *c = s->expr->asConst()) { - QV4::Primitive retVal = convertToValue(c); + auto retVal = convertToValue<TargetPrimitive>(c); RegisterSizeDependentOps::setFunctionReturnValueFromConst(this, retVal); } else { Q_UNREACHABLE(); @@ -547,7 +538,7 @@ void Assembler<TargetConfiguration>::returnFromFunction(IR::Ret *s, RegisterInfo ret(); exceptionReturnLabel = label(); - QV4::Primitive retVal = Primitive::undefinedValue(); + auto retVal = TargetPrimitive::undefinedValue(); RegisterSizeDependentOps::setFunctionReturnValueFromConst(this, retVal); jump(leaveStackFrame); } diff --git a/src/qml/jit/qv4assembler_p.h b/src/qml/jit/qv4assembler_p.h index d4a18ae886..7598a5ac18 100644 --- a/src/qml/jit/qv4assembler_p.h +++ b/src/qml/jit/qv4assembler_p.h @@ -153,6 +153,8 @@ struct RegisterSizeDependentAssembler<JITAssembler, MacroAssembler, TargetPlatfo using TrustedImm64 = typename JITAssembler::TrustedImm64; using Jump = typename JITAssembler::Jump; using Label = typename JITAssembler::Label; + using ValueTypeInternal = Value::ValueTypeInternal_32; + using TargetPrimitive = TargetPrimitive32; static void emitSetGrayBit(JITAssembler *as, RegisterID base) { @@ -223,9 +225,9 @@ struct RegisterSizeDependentAssembler<JITAssembler, MacroAssembler, TargetPlatfo as->storeDouble(source, ptr, barrier); } - static void storeValue(JITAssembler *as, QV4::Primitive value, Address destination, WriteBarrier::Type barrier) + static void storeValue(JITAssembler *as, TargetPrimitive value, Address destination, WriteBarrier::Type barrier) { - as->store32(TrustedImm32(value.int_32()), destination); + as->store32(TrustedImm32(value.value()), destination); destination.offset += 4; as->store32(TrustedImm32(value.tag()), destination); if (WriteBarrier::isRequired<WriteBarrier::Primitive>() && barrier == WriteBarrier::Barrier) @@ -282,16 +284,16 @@ struct RegisterSizeDependentAssembler<JITAssembler, MacroAssembler, TargetPlatfo Jump done = as->jump(); intRange.link(as); as->move(srcReg, lowReg); - as->move(TrustedImm32(QV4::Value::Integer_Type_Internal), highReg); + as->move(TrustedImm32(quint32(QV4::Value::ValueTypeInternal_32::Integer)), highReg); done.link(as); } break; case IR::SInt32Type: as->move((RegisterID) t->index, lowReg); - as->move(TrustedImm32(QV4::Value::Integer_Type_Internal), highReg); + as->move(TrustedImm32(quint32(QV4::Value::ValueTypeInternal_32::Integer)), highReg); break; case IR::BoolType: as->move((RegisterID) t->index, lowReg); - as->move(TrustedImm32(QV4::Value::Boolean_Type_Internal), highReg); + as->move(TrustedImm32(quint32(QV4::Value::ValueTypeInternal_32::Boolean)), highReg); break; default: Q_UNREACHABLE(); @@ -304,9 +306,9 @@ struct RegisterSizeDependentAssembler<JITAssembler, MacroAssembler, TargetPlatfo } } - static void setFunctionReturnValueFromConst(JITAssembler *as, QV4::Primitive retVal) + static void setFunctionReturnValueFromConst(JITAssembler *as, TargetPrimitive retVal) { - as->move(TrustedImm32(retVal.int_32()), TargetPlatform::LowReturnValueRegister); + as->move(TrustedImm32(retVal.value()), TargetPlatform::LowReturnValueRegister); as->move(TrustedImm32(retVal.tag()), TargetPlatform::HighReturnValueRegister); } @@ -382,7 +384,7 @@ struct RegisterSizeDependentAssembler<JITAssembler, MacroAssembler, TargetPlatfo // check if it's an int32: Jump fallback = as->branch32(RelationalCondition::NotEqual, TargetPlatform::ReturnValueRegister, - TrustedImm32(Value::Integer_Type_Internal)); + TrustedImm32(quint32(Value::ValueTypeInternal_32::Integer))); IR::Temp *targetTemp = target->asTemp(); if (!targetTemp || targetTemp->kind == IR::Temp::StackSlot) { as->load32(addr, TargetPlatform::ReturnValueRegister); @@ -390,7 +392,7 @@ struct RegisterSizeDependentAssembler<JITAssembler, MacroAssembler, TargetPlatfo Pointer targetAddr = as->loadAddressForWriting(TargetPlatform::ScratchRegister, target, &barrier); as->store32(TargetPlatform::ReturnValueRegister, targetAddr); targetAddr.offset += 4; - as->store32(TrustedImm32(Value::Integer_Type_Internal), targetAddr); + as->store32(TrustedImm32(quint32(Value::ValueTypeInternal_32::Integer)), targetAddr); if (WriteBarrier::isRequired<WriteBarrier::Primitive>() && barrier == WriteBarrier::Barrier) emitWriteBarrier(as, targetAddr); } else { @@ -435,6 +437,13 @@ struct RegisterSizeDependentAssembler<JITAssembler, MacroAssembler, TargetPlatfo Jump jump = as->branchSub32(ResultCondition::NonZero, TrustedImm32(1), TargetPlatform::ScratchRegister); jump.linkTo(loop, as); } + + static Jump checkIfTagRegisterIsDouble(JITAssembler *as, RegisterID tagRegister) + { + as->and32(TrustedImm32(Value::NotDouble_Mask), tagRegister); + Jump isNoDbl = as->branch32(RelationalCondition::Equal, tagRegister, TrustedImm32(Value::NotDouble_Mask)); + return isNoDbl; + } }; template <typename JITAssembler, typename MacroAssembler, typename TargetPlatform> @@ -451,6 +460,8 @@ struct RegisterSizeDependentAssembler<JITAssembler, MacroAssembler, TargetPlatfo using BranchTruncateType = typename JITAssembler::BranchTruncateType; using Jump = typename JITAssembler::Jump; using Label = typename JITAssembler::Label; + using ValueTypeInternal = Value::ValueTypeInternal_64; + using TargetPrimitive = TargetPrimitive64; static void emitSetGrayBit(JITAssembler *as, RegisterID base) { @@ -558,7 +569,7 @@ struct RegisterSizeDependentAssembler<JITAssembler, MacroAssembler, TargetPlatfo Jump done = as->jump(); intRange.link(as); as->zeroExtend32ToPtr(srcReg, TargetPlatform::ReturnValueRegister); - quint64 tag = QV4::Value::Integer_Type_Internal; + quint64 tag = quint64(QV4::Value::ValueTypeInternal_64::Integer); as->or64(TrustedImm64(tag << 32), TargetPlatform::ReturnValueRegister); done.link(as); @@ -567,10 +578,10 @@ struct RegisterSizeDependentAssembler<JITAssembler, MacroAssembler, TargetPlatfo quint64 tag; switch (t->type) { case IR::SInt32Type: - tag = QV4::Value::Integer_Type_Internal; + tag = quint64(QV4::Value::ValueTypeInternal_64::Integer); break; case IR::BoolType: - tag = QV4::Value::Boolean_Type_Internal; + tag = quint64(QV4::Value::ValueTypeInternal_64::Boolean); break; default: tag = 31337; // bogus value @@ -584,12 +595,12 @@ struct RegisterSizeDependentAssembler<JITAssembler, MacroAssembler, TargetPlatfo } } - static void setFunctionReturnValueFromConst(JITAssembler *as, QV4::Primitive retVal) + static void setFunctionReturnValueFromConst(JITAssembler *as, TargetPrimitive retVal) { as->move(TrustedImm64(retVal.rawValue()), TargetPlatform::ReturnValueRegister); } - static void storeValue(JITAssembler *as, QV4::Primitive value, Address destination, WriteBarrier::Type barrier) + static void storeValue(JITAssembler *as, TargetPrimitive value, Address destination, WriteBarrier::Type barrier) { as->store64(TrustedImm64(value.rawValue()), destination); if (WriteBarrier::isRequired<WriteBarrier::Unknown>() && barrier == WriteBarrier::Barrier) @@ -628,7 +639,7 @@ struct RegisterSizeDependentAssembler<JITAssembler, MacroAssembler, TargetPlatfo Pointer addr = as->loadTempAddress(temp); as->load64(addr, dest); } else { - QV4::Value undefined = QV4::Primitive::undefinedValue(); + auto undefined = TargetPrimitive::undefinedValue(); as->move(TrustedImm64(undefined.rawValue()), dest); } } @@ -641,7 +652,7 @@ struct RegisterSizeDependentAssembler<JITAssembler, MacroAssembler, TargetPlatfo Pointer addr = as->loadArgLocalAddressForReading(dest, al); as->load64(addr, dest); } else { - QV4::Value undefined = QV4::Primitive::undefinedValue(); + auto undefined = TargetPrimitive::undefinedValue(); as->move(TrustedImm64(undefined.rawValue()), dest); } } @@ -650,7 +661,7 @@ struct RegisterSizeDependentAssembler<JITAssembler, MacroAssembler, TargetPlatfo { Q_UNUSED(argumentNumber); - QV4::Value v = convertToValue(c); + auto v = convertToValue<TargetPrimitive64>(c); as->move(TrustedImm64(v.rawValue()), dest); } @@ -659,7 +670,7 @@ struct RegisterSizeDependentAssembler<JITAssembler, MacroAssembler, TargetPlatfo Q_UNUSED(argumentNumber); if (!expr) { - QV4::Value undefined = QV4::Primitive::undefinedValue(); + auto undefined = TargetPrimitive::undefinedValue(); as->move(TrustedImm64(undefined.rawValue()), dest); } else if (IR::Temp *t = expr->asTemp()){ loadArgumentInRegister(as, t, dest, argumentNumber); @@ -751,7 +762,7 @@ struct RegisterSizeDependentAssembler<JITAssembler, MacroAssembler, TargetPlatfo Pointer targetAddr = as->loadAddressForWriting(TargetPlatform::ScratchRegister, target, &barrier); as->store32(TargetPlatform::ReturnValueRegister, targetAddr); targetAddr.offset += 4; - as->store32(TrustedImm32(Value::Integer_Type_Internal), targetAddr); + as->store32(TrustedImm32(quint32(Value::ValueTypeInternal_64::Integer)), targetAddr); if (WriteBarrier::isRequired<WriteBarrier::Primitive>() && barrier == WriteBarrier::Barrier) emitWriteBarrier(as, targetAddr); } else { @@ -783,6 +794,13 @@ struct RegisterSizeDependentAssembler<JITAssembler, MacroAssembler, TargetPlatfo Jump jump = as->branchSub32(ResultCondition::NonZero, TrustedImm32(1), TargetPlatform::ScratchRegister); jump.linkTo(loop, as); } + + static Jump checkIfTagRegisterIsDouble(JITAssembler *as, RegisterID tagRegister) + { + as->rshift32(TrustedImm32(Value::IsDoubleTag_Shift), tagRegister); + Jump isNoDbl = as->branch32(RelationalCondition::Equal, tagRegister, TrustedImm32(0)); + return isNoDbl; + } }; template <typename TargetConfiguration> @@ -851,8 +869,6 @@ public: return (hostOffset * RegisterSize) / QT_POINTER_SIZE; } - using RegisterSizeDependentOps = RegisterSizeDependentAssembler<Assembler<TargetConfiguration>, MacroAssembler, JITTargetPlatform, RegisterSize>; - struct LookupCall { Address addr; uint getterSetterOffset; @@ -883,6 +899,10 @@ public: {} }; + using RegisterSizeDependentOps = RegisterSizeDependentAssembler<Assembler<TargetConfiguration>, MacroAssembler, JITTargetPlatform, RegisterSize>; + using ValueTypeInternal = typename RegisterSizeDependentOps::ValueTypeInternal; + using TargetPrimitive = typename RegisterSizeDependentOps::TargetPrimitive; + // V4 uses two stacks: one stack with QV4::Value items, which is checked by the garbage // collector, and one stack used by the native C/C++/ABI code. This C++ stack is not scanned // by the garbage collector, so if any JS object needs to be retained, it should be put on the @@ -1112,7 +1132,7 @@ public: } Pointer loadStringAddress(RegisterID reg, const QString &string); Address loadConstant(IR::Const *c, RegisterID baseReg); - Address loadConstant(const Primitive &v, RegisterID baseReg); + Address loadConstant(const TargetPrimitive &v, RegisterID baseReg); void loadStringRef(RegisterID reg, const QString &string); Pointer stackSlotPointer(IR::Temp *t) const { @@ -1387,12 +1407,12 @@ public: RegisterSizeDependentOps::emitWriteBarrier(this, dest); } - void storeValue(QV4::Primitive value, Address destination, WriteBarrier::Type barrier) + void storeValue(TargetPrimitive value, Address destination, WriteBarrier::Type barrier) { RegisterSizeDependentOps::storeValue(this, value, destination, barrier); } - void storeValue(QV4::Primitive value, IR::Expr* temp); + void storeValue(TargetPrimitive value, IR::Expr* temp); void emitWriteBarrier(Address addr, WriteBarrier::Type barrier) { if (WriteBarrier::isRequired<WriteBarrier::Primitive>() && barrier == WriteBarrier::Barrier) @@ -1426,13 +1446,7 @@ public: if (argumentNumber < RegisterArgumentCount) loadArgumentInRegister(value, registerForArgument(argumentNumber), argumentNumber); else -#if OS(WINDOWS) && CPU(X86_64) - loadArgumentOnStack<argumentNumber>(value, argumentNumber); -#elif CPU(MIPS) // Stack space for 4 arguments needs to be allocated for MIPS platforms. - loadArgumentOnStack<argumentNumber>(value, argumentNumber + 4); -#else // Sanity: - loadArgumentOnStack<argumentNumber - RegisterArgumentCount>(value, argumentNumber); -#endif + loadArgumentOnStack<argumentNumber - RegisterArgumentCount + (StackShadowSpace / RegisterSize)>(value, argumentNumber); } template <int argumentNumber> @@ -1576,8 +1590,8 @@ public: Address tagAddr = addr; tagAddr.offset += 4; - QV4::Primitive v = convertToValue(c); - store32(TrustedImm32(v.int_32()), addr); + auto v = convertToValue<TargetPrimitive>(c); + store32(TrustedImm32(v.value()), addr); store32(TrustedImm32(v.tag()), tagAddr); return Pointer(addr); } @@ -1593,7 +1607,7 @@ public: { store32(reg, addr); addr.offset += 4; - store32(TrustedImm32(QV4::Primitive::fromBoolean(0).tag()), addr); + store32(TrustedImm32(TargetPrimitive::fromBoolean(0).tag()), addr); if (WriteBarrier::isRequired<WriteBarrier::Primitive>() && barrier == WriteBarrier::Barrier) RegisterSizeDependentOps::emitWriteBarrier(this, addr); } @@ -1640,7 +1654,7 @@ public: { store32(reg, addr); addr.offset += 4; - store32(TrustedImm32(QV4::Primitive::fromInt32(0).tag()), addr); + store32(TrustedImm32(TargetPrimitive::fromInt32(0).tag()), addr); if (WriteBarrier::isRequired<WriteBarrier::Primitive>() && barrier == WriteBarrier::Barrier) RegisterSizeDependentOps::emitWriteBarrier(this, addr); } @@ -1709,7 +1723,7 @@ public: RegisterID toInt32Register(IR::Expr *e, RegisterID scratchReg) { if (IR::Const *c = e->asConst()) { - move(TrustedImm32(convertToValue(c).int_32()), scratchReg); + move(TrustedImm32(convertToValue<Primitive>(c).int_32()), scratchReg); return scratchReg; } @@ -1748,11 +1762,11 @@ public: Pointer tagAddr = addr; tagAddr.offset += 4; load32(tagAddr, scratchReg); - Jump inIntRange = branch32(RelationalCondition::Equal, scratchReg, TrustedImm32(QV4::Value::Integer_Type_Internal)); + Jump inIntRange = branch32(RelationalCondition::Equal, scratchReg, TrustedImm32(quint32(ValueTypeInternal::Integer))); // it's not in signed int range, so load it as a double, and truncate it down loadDouble(addr, FPGpr0); - Address inversionAddress = loadConstant(QV4::Primitive::fromDouble(double(INT_MAX) + 1), scratchReg); + Address inversionAddress = loadConstant(TargetPrimitive::fromDouble(double(INT_MAX) + 1), scratchReg); subDouble(inversionAddress, FPGpr0); Jump canNeverHappen = branchTruncateDoubleToUint32(FPGpr0, scratchReg); canNeverHappen.link(this); @@ -1808,6 +1822,9 @@ private: }; template <typename TargetConfiguration> +const typename Assembler<TargetConfiguration>::VoidType Assembler<TargetConfiguration>::Void; + +template <typename TargetConfiguration> template <typename Result, typename Source> void Assembler<TargetConfiguration>::copyValue(Result result, Source source, WriteBarrier::Type barrier) { @@ -1832,7 +1849,7 @@ void Assembler<TargetConfiguration>::copyValue(Result result, IR::Expr* source, } else if (source->asTemp() || source->asArgLocal()) { RegisterSizeDependentOps::copyValueViaRegisters(this, source, result, barrier); } else if (IR::Const *c = source->asConst()) { - QV4::Primitive v = convertToValue(c); + auto v = convertToValue<TargetPrimitive>(c); storeValue(v, result, barrier); } else { Q_UNREACHABLE(); diff --git a/src/qml/jit/qv4isel_masm.cpp b/src/qml/jit/qv4isel_masm.cpp index 9841620481..599370f73d 100644 --- a/src/qml/jit/qv4isel_masm.cpp +++ b/src/qml/jit/qv4isel_masm.cpp @@ -256,7 +256,7 @@ void InstructionSelection<JITAssembler>::callBuiltinDeleteName(const QString &na template <typename JITAssembler> void InstructionSelection<JITAssembler>::callBuiltinDeleteValue(IR::Expr *result) { - _as->storeValue(Primitive::fromBoolean(false), result); + _as->storeValue(JITAssembler::TargetPrimitive::fromBoolean(false), result); } template <typename JITAssembler> @@ -376,7 +376,7 @@ void InstructionSelection<JITAssembler>::callBuiltinDefineObjectLiteral(IR::Expr ++arrayValueCount; // Index - _as->storeValue(QV4::Primitive::fromUInt32(index), _as->stackLayout().argumentAddressForCall(argc++), WriteBarrier::NoBarrier); + _as->storeValue(JITAssembler::TargetPrimitive::fromUInt32(index), _as->stackLayout().argumentAddressForCall(argc++), WriteBarrier::NoBarrier); // Value _as->copyValue(_as->stackLayout().argumentAddressForCall(argc++), it->expr, WriteBarrier::NoBarrier); @@ -400,7 +400,7 @@ void InstructionSelection<JITAssembler>::callBuiltinDefineObjectLiteral(IR::Expr ++arrayGetterSetterCount; // Index - _as->storeValue(QV4::Primitive::fromUInt32(index), _as->stackLayout().argumentAddressForCall(argc++), WriteBarrier::NoBarrier); + _as->storeValue(JITAssembler::TargetPrimitive::fromUInt32(index), _as->stackLayout().argumentAddressForCall(argc++), WriteBarrier::NoBarrier); // Getter _as->copyValue(_as->stackLayout().argumentAddressForCall(argc++), it->expr, WriteBarrier::NoBarrier); @@ -488,7 +488,7 @@ void InstructionSelection<JITAssembler>::loadConst(IR::Const *sourceConst, IR::E _as->toUInt32Register(sourceConst, (RegisterID) targetTemp->index); } else if (targetTemp->type == IR::BoolType) { Q_ASSERT(sourceConst->type == IR::BoolType); - _as->move(TrustedImm32(convertToValue(sourceConst).int_32()), + _as->move(TrustedImm32(convertToValue<Primitive>(sourceConst).int_32()), (RegisterID) targetTemp->index); } else { Q_UNREACHABLE(); @@ -497,7 +497,7 @@ void InstructionSelection<JITAssembler>::loadConst(IR::Const *sourceConst, IR::E } } - _as->storeValue(convertToValue(sourceConst), target); + _as->storeValue(convertToValue<typename JITAssembler::TargetPrimitive>(sourceConst), target); } template <typename JITAssembler> @@ -781,10 +781,10 @@ void InstructionSelection<JITAssembler>::swapValues(IR::Expr *source, IR::Expr * quint32 tag; switch (regTemp->type) { case IR::BoolType: - tag = QV4::Value::Boolean_Type_Internal; + tag = quint32(JITAssembler::ValueTypeInternal::Boolean); break; case IR::SInt32Type: - tag = QV4::Value::Integer_Type_Internal; + tag = quint32(JITAssembler::ValueTypeInternal::Integer); break; default: tag = 31337; // bogus value @@ -933,7 +933,7 @@ void InstructionSelection<JITAssembler>::convertTypeToDouble(IR::Expr *source, I // check if it's an int32: Jump isNoInt = _as->branch32(RelationalCondition::NotEqual, JITTargetPlatform::ScratchRegister, - TrustedImm32(Value::Integer_Type_Internal)); + TrustedImm32(quint32(JITAssembler::ValueTypeInternal::Integer))); convertIntToDouble(source, target); Jump intDone = _as->jump(); @@ -1011,13 +1011,13 @@ void InstructionSelection<JITAssembler>::convertTypeToBool(IR::Expr *source, IR: // checkif it's a bool: Jump notBool = _as->branch32(RelationalCondition::NotEqual, JITTargetPlatform::ReturnValueRegister, - TrustedImm32(Value::Boolean_Type_Internal)); + TrustedImm32(quint32(JITAssembler::ValueTypeInternal::Boolean))); _as->load32(addr, JITTargetPlatform::ReturnValueRegister); Jump boolDone = _as->jump(); // check if it's an int32: notBool.link(_as); Jump fallback = _as->branch32(RelationalCondition::NotEqual, JITTargetPlatform::ReturnValueRegister, - TrustedImm32(Value::Integer_Type_Internal)); + TrustedImm32(quint32(JITAssembler::ValueTypeInternal::Integer))); _as->load32(addr, JITTargetPlatform::ReturnValueRegister); Jump isZero = _as->branch32(RelationalCondition::Equal, JITTargetPlatform::ReturnValueRegister, TrustedImm32(0)); @@ -1087,7 +1087,7 @@ void InstructionSelection<JITAssembler>::convertTypeToUInt32(IR::Expr *source, I // check if it's an int32: Jump isNoInt = _as->branch32(RelationalCondition::NotEqual, JITTargetPlatform::ScratchRegister, - TrustedImm32(Value::Integer_Type_Internal)); + TrustedImm32(quint32(JITAssembler::ValueTypeInternal::Integer))); Pointer addr = _as->loadAddressForReading(JITTargetPlatform::ScratchRegister, source); _as->storeUInt32(_as->toInt32Register(addr, JITTargetPlatform::ScratchRegister), target); Jump intDone = _as->jump(); @@ -1203,7 +1203,8 @@ void InstructionSelection<JITAssembler>::visitCJump(IR::CJump *s) Address temp = _as->loadAddressForReading(JITTargetPlatform::ScratchRegister, s->cond); Address tag = temp; tag.offset += QV4::Value::tagOffset(); - Jump booleanConversion = _as->branch32(RelationalCondition::NotEqual, tag, TrustedImm32(QV4::Value::Boolean_Type_Internal)); + Jump booleanConversion = _as->branch32(RelationalCondition::NotEqual, tag, + TrustedImm32(quint32(JITAssembler::ValueTypeInternal::Boolean))); Address data = temp; data.offset += QV4::Value::valueOffset(); @@ -1322,12 +1323,12 @@ int InstructionSelection<JITAssembler>::prepareCallData(IR::ExprList* args, IR:: } Pointer p = _as->stackLayout().callDataAddress(offsetof(CallData, tag)); - _as->store32(TrustedImm32(QV4::Value::Integer_Type_Internal), p); + _as->store32(TrustedImm32(quint32(JITAssembler::ValueTypeInternal::Integer)), p); p = _as->stackLayout().callDataAddress(offsetof(CallData, argc)); _as->store32(TrustedImm32(argc), p); p = _as->stackLayout().callDataAddress(offsetof(CallData, thisObject)); if (!thisObject) - _as->storeValue(QV4::Primitive::undefinedValue(), p, WriteBarrier::NoBarrier); + _as->storeValue(JITAssembler::TargetPrimitive::undefinedValue(), p, WriteBarrier::NoBarrier); else _as->copyValue(p, thisObject, WriteBarrier::NoBarrier); @@ -1464,7 +1465,7 @@ bool InstructionSelection<JITAssembler>::visitCJumpStrictNull(IR::Binop *binop, RelationalCondition cond = binop->op == IR::OpStrictEqual ? RelationalCondition::Equal : RelationalCondition::NotEqual; - const TrustedImm32 tag(QV4::Value::Null_Type_Internal); + const TrustedImm32 tag{quint32(JITAssembler::ValueTypeInternal::Null)}; _as->generateCJumpOnCompare(cond, tagReg, tag, _block, trueBlock, falseBlock); return true; } @@ -1546,7 +1547,7 @@ bool InstructionSelection<JITAssembler>::visitCJumpStrictBool(IR::Binop *binop, // check if the tag of the var operand is indicates 'boolean' _as->load32(otherAddr, JITTargetPlatform::ScratchRegister); Jump noBool = _as->branch32(RelationalCondition::NotEqual, JITTargetPlatform::ScratchRegister, - TrustedImm32(QV4::Value::Boolean_Type_Internal)); + TrustedImm32(quint32(JITAssembler::ValueTypeInternal::Boolean))); if (binop->op == IR::OpStrictEqual) _as->addPatch(falseBlock, noBool); else @@ -1596,7 +1597,7 @@ bool InstructionSelection<JITAssembler>::visitCJumpNullUndefined(IR::Type nullOr if (binop->op == IR::OpNotEqual) qSwap(trueBlock, falseBlock); - Jump isNull = _as->branch32(RelationalCondition::Equal, tagReg, TrustedImm32(int(QV4::Value::Null_Type_Internal))); + Jump isNull = _as->branch32(RelationalCondition::Equal, tagReg, TrustedImm32(quint32(JITAssembler::ValueTypeInternal::Null))); Jump isNotUndefinedTag = _as->branch32(RelationalCondition::NotEqual, tagReg, TrustedImm32(int(QV4::Value::Managed_Type_Internal))); tagAddr.offset -= 4; _as->load32(tagAddr, tagReg); @@ -1648,18 +1649,18 @@ Q_QML_EXPORT QV4::EvalISelFactory *createISelForArchitecture(const QString &arch using ARMv7CrossAssembler = QV4::JIT::Assembler<AssemblerTargetConfiguration<JSC::MacroAssemblerARMv7, NoOperatingSystemSpecialization>>; using ARM64CrossAssembler = QV4::JIT::Assembler<AssemblerTargetConfiguration<JSC::MacroAssemblerARM64, NoOperatingSystemSpecialization>>; - if (architecture == QLatin1String("armv7")) + if (architecture == QLatin1String("arm")) return new ISelFactory<ARMv7CrossAssembler>; - else if (architecture == QLatin1String("armv8")) + else if (architecture == QLatin1String("arm64")) return new ISelFactory<ARM64CrossAssembler>; QString hostArch; #if CPU(ARM_THUMB2) - hostArch = QStringLiteral("armv7"); + hostArch = QStringLiteral("arm"); #elif CPU(MIPS) hostArch = QStringLiteral("mips"); #elif CPU(X86) - hostArch = QStringLiteral("x86"); + hostArch = QStringLiteral("i386"); #elif CPU(X86_64) hostArch = QStringLiteral("x86_64"); #endif diff --git a/src/qml/jit/qv4isel_masm_p.h b/src/qml/jit/qv4isel_masm_p.h index 0d02284539..7019a117a2 100644 --- a/src/qml/jit/qv4isel_masm_p.h +++ b/src/qml/jit/qv4isel_masm_p.h @@ -160,7 +160,7 @@ protected: // FramePointerRegister points to its old value on the stack, and above // it we have the return address, hence the need to step over two // values before reaching the first argument. - return Address(JITTargetPlatform::FramePointerRegister, (index + 2) * sizeof(void*)); + return Address(JITTargetPlatform::FramePointerRegister, (index + 2) * JITTargetPlatform::RegisterSize); } Pointer baseAddressForCallArguments() diff --git a/src/qml/jit/qv4targetplatform_p.h b/src/qml/jit/qv4targetplatform_p.h index ce6156802d..6d788f4a93 100644 --- a/src/qml/jit/qv4targetplatform_p.h +++ b/src/qml/jit/qv4targetplatform_p.h @@ -405,7 +405,7 @@ public: << RI(JSC::ARMRegisters::r9, QStringLiteral("r9"), RI::RegularRegister, RI::CalleeSaved, RI::RegAlloc) #endif << RI(JSC::ARMRegisters::r10, QStringLiteral("r10"), RI::RegularRegister, RI::CalleeSaved, RI::Predefined) -#if CPU(ARM_THUMB2) && !defined(V4_BOOTSTRAP) +#if CPU(ARM_THUMB2) || defined(V4_BOOTSTRAP) << RI(JSC::ARMRegisters::r11, QStringLiteral("r11"), RI::RegularRegister, RI::CalleeSaved, RI::Predefined) #endif << RI(JSC::ARMRegisters::d2, QStringLiteral("d2"), RI::FloatingPointRegister, RI::CallerSaved, RI::RegAlloc) diff --git a/src/qml/jsruntime/qv4engine.cpp b/src/qml/jsruntime/qv4engine.cpp index dd8cb177b4..806a614e95 100644 --- a/src/qml/jsruntime/qv4engine.cpp +++ b/src/qml/jsruntime/qv4engine.cpp @@ -524,7 +524,7 @@ void ExecutionEngine::initRootContext() sizeof(GlobalContext::Data) + sizeof(CallData))); r->d_unchecked()->init(this); r->d()->callData = reinterpret_cast<CallData *>(r->d() + 1); - r->d()->callData->tag = QV4::Value::Integer_Type_Internal; + r->d()->callData->tag = quint32(Value::ValueTypeInternal::Integer); r->d()->callData->argc = 0; r->d()->callData->thisObject = globalObject; r->d()->callData->args[0] = Encode::undefined(); diff --git a/src/qml/jsruntime/qv4globalobject.cpp b/src/qml/jsruntime/qv4globalobject.cpp index 1bc91f832b..f0630660d4 100644 --- a/src/qml/jsruntime/qv4globalobject.cpp +++ b/src/qml/jsruntime/qv4globalobject.cpp @@ -394,6 +394,7 @@ void EvalFunction::evalCall(Scope &scope, CallData *callData, bool directCall) c // set the correct strict mode flag on the context ctx->d()->strictMode = false; ctx->d()->compilationUnit = function->compilationUnit; + ctx->d()->constantTable = function->compilationUnit->constants; scope.result = Q_V4_PROFILE(ctx->engine(), function); } diff --git a/src/qml/jsruntime/qv4scopedvalue_p.h b/src/qml/jsruntime/qv4scopedvalue_p.h index 894434be16..e9dcc9172f 100644 --- a/src/qml/jsruntime/qv4scopedvalue_p.h +++ b/src/qml/jsruntime/qv4scopedvalue_p.h @@ -368,7 +368,7 @@ struct ScopedCallData { { int size = qMax(argc, QV4::Global::ReservedArgumentCount + int(offsetof(QV4::CallData, args)/sizeof(QV4::Value))); ptr = reinterpret_cast<CallData *>(scope.alloc(size)); - ptr->tag = QV4::Value::Integer_Type_Internal; + ptr->tag = quint32(QV4::Value::ValueTypeInternal::Integer); ptr->argc = argc; } diff --git a/src/qml/jsruntime/qv4value_p.h b/src/qml/jsruntime/qv4value_p.h index 56b4ec44a2..50cecb6598 100644 --- a/src/qml/jsruntime/qv4value_p.h +++ b/src/qml/jsruntime/qv4value_p.h @@ -207,23 +207,23 @@ public: } QML_NEARLY_ALWAYS_INLINE void setInt_32(int i) { - setTagValue(Integer_Type_Internal, quint32(i)); + setTagValue(quint32(ValueTypeInternal::Integer), quint32(i)); } QML_NEARLY_ALWAYS_INLINE uint uint_32() const { return value(); } QML_NEARLY_ALWAYS_INLINE void setEmpty() { - setTagValue(Empty_Type_Internal, value()); + setTagValue(quint32(ValueTypeInternal::Empty), value()); } QML_NEARLY_ALWAYS_INLINE void setEmpty(int i) { - setTagValue(Empty_Type_Internal, quint32(i)); + setTagValue(quint32(ValueTypeInternal::Empty), quint32(i)); } QML_NEARLY_ALWAYS_INLINE void setEmpty(quint32 i) { - setTagValue(Empty_Type_Internal, i); + setTagValue(quint32(ValueTypeInternal::Empty), i); } QML_NEARLY_ALWAYS_INLINE quint32 emptyValue() @@ -266,8 +266,17 @@ public: IsDoubleTag_Shift = IsDouble_Shift - Tag_Shift, Managed_Type_Internal_64 = 0 }; + static const quint64 Immediate_Mask_64 = 0x00020000u; // bit 49 + enum class ValueTypeInternal_64 { + Empty = Immediate_Mask_64| 0, + ConvertibleToInt = Immediate_Mask_64| 0x10000u, // bit 48 + Null = ConvertibleToInt | 0x08000u, + Boolean = ConvertibleToInt | 0x04000u, + Integer = ConvertibleToInt | 0x02000u + }; + // Used only by 32-bit encoding enum Masks { SilentNaNBit = 0x00040000, @@ -275,6 +284,14 @@ public: }; static const quint64 Immediate_Mask_32 = NotDouble_Mask | 0x00020000u | SilentNaNBit; + enum class ValueTypeInternal_32 { + Empty = Immediate_Mask_32| 0, + ConvertibleToInt = Immediate_Mask_32| 0x10000u, // bit 48 + Null = ConvertibleToInt | 0x08000u, + Boolean = ConvertibleToInt | 0x04000u, + Integer = ConvertibleToInt | 0x02000u + }; + enum { Managed_Type_Internal_32 = NotDouble_Mask }; @@ -284,28 +301,23 @@ public: Managed_Type_Internal = Managed_Type_Internal_64 }; static const quint64 Immediate_Mask = Immediate_Mask_64; + using ValueTypeInternal = ValueTypeInternal_64; #else enum { Managed_Type_Internal = Managed_Type_Internal_32 }; static const quint64 Immediate_Mask = Immediate_Mask_32; + using ValueTypeInternal = ValueTypeInternal_32; #endif enum { NaN_Mask = 0x7ff80000, }; - enum ValueTypeInternal { - Empty_Type_Internal = Immediate_Mask | 0, - ConvertibleToInt = Immediate_Mask | 0x10000u, // bit 48 - Null_Type_Internal = ConvertibleToInt | 0x08000u, - Boolean_Type_Internal = ConvertibleToInt | 0x04000u, - Integer_Type_Internal = ConvertibleToInt | 0x02000u - }; // used internally in property - inline bool isEmpty() const { return tag() == Empty_Type_Internal; } - inline bool isNull() const { return tag() == Null_Type_Internal; } - inline bool isBoolean() const { return tag() == Boolean_Type_Internal; } - inline bool isInteger() const { return tag() == Integer_Type_Internal; } + inline bool isEmpty() const { return tag() == quint32(ValueTypeInternal::Empty); } + inline bool isNull() const { return tag() == quint32(ValueTypeInternal::Null); } + inline bool isBoolean() const { return tag() == quint32(ValueTypeInternal::Boolean); } + inline bool isInteger() const { return tag() == quint32(ValueTypeInternal::Integer); } inline bool isNullOrUndefined() const { return isNull() || isUndefined(); } inline bool isNumber() const { return isDouble() || isInteger(); } @@ -330,9 +342,9 @@ public: inline bool isDouble() const { return (tag() & NotDouble_Mask) != NotDouble_Mask; } inline bool isManaged() const { return tag() == Managed_Type_Internal && !isUndefined(); } inline bool isManagedOrUndefined() const { return tag() == Managed_Type_Internal; } - inline bool integerCompatible() const { return (tag() & ConvertibleToInt) == ConvertibleToInt; } + inline bool integerCompatible() const { return (tag() & quint32(ValueTypeInternal::ConvertibleToInt)) == quint32(ValueTypeInternal::ConvertibleToInt); } static inline bool integerCompatible(Value a, Value b) { - return ((a.tag() & b.tag()) & ConvertibleToInt) == ConvertibleToInt; + return ((a.tag() & b.tag()) & quint32(ValueTypeInternal::ConvertibleToInt)) == quint32(ValueTypeInternal::ConvertibleToInt); } static inline bool bothDouble(Value a, Value b) { return ((a.tag() | b.tag()) & NotDouble_Mask) != NotDouble_Mask; @@ -359,7 +371,7 @@ public: inline bool isString() const; inline bool isObject() const; inline bool isInt32() { - if (tag() == Integer_Type_Internal) + if (tag() == quint32(ValueTypeInternal::Integer)) return true; if (isDouble()) { double d = doubleValue(); @@ -372,7 +384,7 @@ public: return false; } double asDouble() const { - if (tag() == Integer_Type_Internal) + if (tag() == quint32(ValueTypeInternal::Integer)) return int_32(); return doubleValue(); } @@ -427,7 +439,7 @@ public: inline bool tryIntegerConversion() { bool b = integerCompatible(); if (b) - setTagValue(Integer_Type_Internal, value()); + setTagValue(quint32(ValueTypeInternal::Integer), value()); return b; } @@ -610,14 +622,14 @@ inline Primitive Primitive::emptyValue(uint e) inline Primitive Primitive::nullValue() { Primitive v; - v.setTagValue(Null_Type_Internal, 0); + v.setTagValue(quint32(ValueTypeInternal::Null), 0); return v; } inline Primitive Primitive::fromBoolean(bool b) { Primitive v; - v.setTagValue(Boolean_Type_Internal, b); + v.setTagValue(quint32(ValueTypeInternal::Boolean), b); return v; } @@ -639,7 +651,7 @@ inline Primitive Primitive::fromUInt32(uint i) { Primitive v; if (i < INT_MAX) { - v.setTagValue(Integer_Type_Internal, i); + v.setTagValue(quint32(ValueTypeInternal::Integer), i); } else { v.setDouble(i); } diff --git a/src/qml/jsruntime/qv4vme_moth.cpp b/src/qml/jsruntime/qv4vme_moth.cpp index 8d523f17e9..e16df8dc60 100644 --- a/src/qml/jsruntime/qv4vme_moth.cpp +++ b/src/qml/jsruntime/qv4vme_moth.cpp @@ -251,6 +251,9 @@ int qt_v4DebuggerHook(const char *json) static void qt_v4CheckForBreak(QV4::ExecutionContext *context) { + if (!qt_v4IsStepping && !qt_v4Breakpoints.size()) + return; + const int lineNumber = context->d()->lineNumber; QV4::Function *function = qt_v4ExtractFunction(context); QString engineName = function->sourceFile(); @@ -585,7 +588,7 @@ QV4::ReturnedValue VME::run(ExecutionEngine *engine, const uchar *code #endif // DO_TRACE_INSTR Q_ASSERT(instr.callData + instr.argc + offsetof(QV4::CallData, args)/sizeof(QV4::Value) <= stackSize); QV4::CallData *callData = reinterpret_cast<QV4::CallData *>(stack + instr.callData); - callData->tag = QV4::Value::Integer_Type_Internal; + callData->tag = quint32(Value::ValueTypeInternal::Integer); callData->argc = instr.argc; callData->thisObject = QV4::Primitive::undefinedValue(); STOREVALUE(instr.result, Runtime::method_callValue(engine, VALUE(instr.dest), callData)); @@ -595,7 +598,7 @@ QV4::ReturnedValue VME::run(ExecutionEngine *engine, const uchar *code TRACE(property name, "%s, args=%u, argc=%u, this=%s", qPrintable(runtimeStrings[instr.name]->toQString()), instr.callData, instr.argc, (VALUE(instr.base)).toString(context)->toQString().toUtf8().constData()); Q_ASSERT(instr.callData + instr.argc + offsetof(QV4::CallData, args)/sizeof(QV4::Value) <= stackSize); QV4::CallData *callData = reinterpret_cast<QV4::CallData *>(stack + instr.callData); - callData->tag = QV4::Value::Integer_Type_Internal; + callData->tag = quint32(Value::ValueTypeInternal::Integer); callData->argc = instr.argc; callData->thisObject = VALUE(instr.base); STOREVALUE(instr.result, Runtime::method_callProperty(engine, instr.name, callData)); @@ -604,7 +607,7 @@ QV4::ReturnedValue VME::run(ExecutionEngine *engine, const uchar *code MOTH_BEGIN_INSTR(CallPropertyLookup) Q_ASSERT(instr.callData + instr.argc + offsetof(QV4::CallData, args)/sizeof(QV4::Value) <= stackSize); QV4::CallData *callData = reinterpret_cast<QV4::CallData *>(stack + instr.callData); - callData->tag = QV4::Value::Integer_Type_Internal; + callData->tag = quint32(Value::ValueTypeInternal::Integer); callData->argc = instr.argc; callData->thisObject = VALUE(instr.base); STOREVALUE(instr.result, Runtime::method_callPropertyLookup(engine, instr.lookupIndex, callData)); @@ -614,7 +617,7 @@ QV4::ReturnedValue VME::run(ExecutionEngine *engine, const uchar *code TRACE(property name, "%s, args=%u, argc=%u, this=%s", qPrintable(runtimeStrings[instr.name]->toQString()), instr.callData, instr.argc, (VALUE(instr.base)).toString(context)->toQString().toUtf8().constData()); Q_ASSERT(instr.callData + instr.argc + offsetof(QV4::CallData, args)/sizeof(QV4::Value) <= stackSize); QV4::CallData *callData = reinterpret_cast<QV4::CallData *>(stack + instr.callData); - callData->tag = QV4::Value::Integer_Type_Internal; + callData->tag = quint32(Value::ValueTypeInternal::Integer); callData->argc = instr.argc; callData->thisObject = VALUE(instr.base); STOREVALUE(instr.result, Runtime::method_callQmlScopeObjectProperty(engine, instr.index, callData)); @@ -624,7 +627,7 @@ QV4::ReturnedValue VME::run(ExecutionEngine *engine, const uchar *code TRACE(property name, "%s, args=%u, argc=%u, this=%s", qPrintable(runtimeStrings[instr.name]->toQString()), instr.callData, instr.argc, (VALUE(instr.base)).toString(context)->toQString().toUtf8().constData()); Q_ASSERT(instr.callData + instr.argc + offsetof(QV4::CallData, args)/sizeof(QV4::Value) <= stackSize); QV4::CallData *callData = reinterpret_cast<QV4::CallData *>(stack + instr.callData); - callData->tag = QV4::Value::Integer_Type_Internal; + callData->tag = quint32(Value::ValueTypeInternal::Integer); callData->argc = instr.argc; callData->thisObject = VALUE(instr.base); STOREVALUE(instr.result, Runtime::method_callQmlContextObjectProperty(engine, instr.index, callData)); @@ -633,7 +636,7 @@ QV4::ReturnedValue VME::run(ExecutionEngine *engine, const uchar *code MOTH_BEGIN_INSTR(CallElement) Q_ASSERT(instr.callData + instr.argc + offsetof(QV4::CallData, args)/sizeof(QV4::Value) <= stackSize); QV4::CallData *callData = reinterpret_cast<QV4::CallData *>(stack + instr.callData); - callData->tag = QV4::Value::Integer_Type_Internal; + callData->tag = quint32(Value::ValueTypeInternal::Integer); callData->argc = instr.argc; callData->thisObject = VALUE(instr.base); STOREVALUE(instr.result, Runtime::method_callElement(engine, VALUE(instr.index), callData)); @@ -642,7 +645,7 @@ QV4::ReturnedValue VME::run(ExecutionEngine *engine, const uchar *code MOTH_BEGIN_INSTR(CallActivationProperty) Q_ASSERT(instr.callData + instr.argc + offsetof(QV4::CallData, args)/sizeof(QV4::Value) <= stackSize); QV4::CallData *callData = reinterpret_cast<QV4::CallData *>(stack + instr.callData); - callData->tag = QV4::Value::Integer_Type_Internal; + callData->tag = quint32(Value::ValueTypeInternal::Integer); callData->argc = instr.argc; callData->thisObject = QV4::Primitive::undefinedValue(); STOREVALUE(instr.result, Runtime::method_callActivationProperty(engine, instr.name, callData)); @@ -651,7 +654,7 @@ QV4::ReturnedValue VME::run(ExecutionEngine *engine, const uchar *code MOTH_BEGIN_INSTR(CallGlobalLookup) Q_ASSERT(instr.callData + instr.argc + offsetof(QV4::CallData, args)/sizeof(QV4::Value) <= stackSize); QV4::CallData *callData = reinterpret_cast<QV4::CallData *>(stack + instr.callData); - callData->tag = QV4::Value::Integer_Type_Internal; + callData->tag = quint32(Value::ValueTypeInternal::Integer); callData->argc = instr.argc; callData->thisObject = QV4::Primitive::undefinedValue(); STOREVALUE(instr.result, Runtime::method_callGlobalLookup(engine, instr.index, callData)); @@ -757,7 +760,7 @@ QV4::ReturnedValue VME::run(ExecutionEngine *engine, const uchar *code MOTH_BEGIN_INSTR(CreateValue) Q_ASSERT(instr.callData + instr.argc + offsetof(QV4::CallData, args)/sizeof(QV4::Value) <= stackSize); QV4::CallData *callData = reinterpret_cast<QV4::CallData *>(stack + instr.callData); - callData->tag = QV4::Value::Integer_Type_Internal; + callData->tag = quint32(Value::ValueTypeInternal::Integer); callData->argc = instr.argc; callData->thisObject = QV4::Primitive::undefinedValue(); STOREVALUE(instr.result, Runtime::method_constructValue(engine, VALUE(instr.func), callData)); @@ -766,7 +769,7 @@ QV4::ReturnedValue VME::run(ExecutionEngine *engine, const uchar *code MOTH_BEGIN_INSTR(CreateProperty) Q_ASSERT(instr.callData + instr.argc + offsetof(QV4::CallData, args)/sizeof(QV4::Value) <= stackSize); QV4::CallData *callData = reinterpret_cast<QV4::CallData *>(stack + instr.callData); - callData->tag = QV4::Value::Integer_Type_Internal; + callData->tag = quint32(Value::ValueTypeInternal::Integer); callData->argc = instr.argc; callData->thisObject = VALUE(instr.base); STOREVALUE(instr.result, Runtime::method_constructProperty(engine, instr.name, callData)); @@ -775,7 +778,7 @@ QV4::ReturnedValue VME::run(ExecutionEngine *engine, const uchar *code MOTH_BEGIN_INSTR(ConstructPropertyLookup) Q_ASSERT(instr.callData + instr.argc + offsetof(QV4::CallData, args)/sizeof(QV4::Value) <= stackSize); QV4::CallData *callData = reinterpret_cast<QV4::CallData *>(stack + instr.callData); - callData->tag = QV4::Value::Integer_Type_Internal; + callData->tag = quint32(Value::ValueTypeInternal::Integer); callData->argc = instr.argc; callData->thisObject = VALUE(instr.base); STOREVALUE(instr.result, Runtime::method_constructPropertyLookup(engine, instr.index, callData)); @@ -784,7 +787,7 @@ QV4::ReturnedValue VME::run(ExecutionEngine *engine, const uchar *code MOTH_BEGIN_INSTR(CreateActivationProperty) Q_ASSERT(instr.callData + instr.argc + offsetof(QV4::CallData, args)/sizeof(QV4::Value) <= stackSize); QV4::CallData *callData = reinterpret_cast<QV4::CallData *>(stack + instr.callData); - callData->tag = QV4::Value::Integer_Type_Internal; + callData->tag = quint32(Value::ValueTypeInternal::Integer); callData->argc = instr.argc; callData->thisObject = QV4::Primitive::undefinedValue(); STOREVALUE(instr.result, Runtime::method_constructActivationProperty(engine, instr.name, callData)); @@ -793,7 +796,7 @@ QV4::ReturnedValue VME::run(ExecutionEngine *engine, const uchar *code MOTH_BEGIN_INSTR(ConstructGlobalLookup) Q_ASSERT(instr.callData + instr.argc + offsetof(QV4::CallData, args)/sizeof(QV4::Value) <= stackSize); QV4::CallData *callData = reinterpret_cast<QV4::CallData *>(stack + instr.callData); - callData->tag = QV4::Value::Integer_Type_Internal; + callData->tag = quint32(Value::ValueTypeInternal::Integer); callData->argc = instr.argc; callData->thisObject = QV4::Primitive::undefinedValue(); STOREVALUE(instr.result, Runtime::method_constructGlobalLookup(engine, instr.index, callData)); diff --git a/src/qml/qml.pro b/src/qml/qml.pro index 8f9e4b7f83..be3956bb61 100644 --- a/src/qml/qml.pro +++ b/src/qml/qml.pro @@ -48,7 +48,9 @@ include(jit/jit.pri) include(jsruntime/jsruntime.pri) include(qml/qml.pri) include(debugger/debugger.pri) -include(animations/animations.pri) +qtConfig(animation) { + include(animations/animations.pri) +} include(types/types.pri) MODULE_PLUGIN_TYPES = \ diff --git a/src/qml/qml/qqmlengine.cpp b/src/qml/qml/qqmlengine.cpp index d4d21583ba..c9c9ef363a 100644 --- a/src/qml/qml/qqmlengine.cpp +++ b/src/qml/qml/qqmlengine.cpp @@ -82,7 +82,9 @@ #include <private/qqmllocale_p.h> #include <private/qqmlbind_p.h> #include <private/qqmlconnections_p.h> +#if QT_CONFIG(animation) #include <private/qqmltimer_p.h> +#endif #include <private/qqmllistmodel_p.h> #include <private/qqmlplatform_p.h> #include <private/qquickpackage_p.h> @@ -218,7 +220,9 @@ void QQmlEnginePrivate::registerBaseTypes(const char *uri, int versionMajor, int qmlRegisterType<QQmlBind,8>(uri, versionMajor, (versionMinor < 8 ? 8 : versionMinor), "Binding"); //Only available in >=2.8 qmlRegisterType<QQmlConnections,1>(uri, versionMajor, (versionMinor < 3 ? 3 : versionMinor), "Connections"); //Only available in >=2.3 qmlRegisterType<QQmlConnections>(uri, versionMajor, versionMinor,"Connections"); +#if QT_CONFIG(animation) qmlRegisterType<QQmlTimer>(uri, versionMajor, versionMinor,"Timer"); +#endif qmlRegisterType<QQmlInstantiator>(uri, versionMajor, (versionMinor < 1 ? 1 : versionMinor), "Instantiator"); //Only available in >=2.1 qmlRegisterCustomType<QQmlConnections>(uri, versionMajor, versionMinor,"Connections", new QQmlConnectionsParser); qmlRegisterType<QQmlInstanceModel>(); diff --git a/src/qml/types/types.pri b/src/qml/types/types.pri index d2e5020738..e85ab5982b 100644 --- a/src/qml/types/types.pri +++ b/src/qml/types/types.pri @@ -7,7 +7,6 @@ SOURCES += \ $$PWD/qqmlmodelsmodule.cpp \ $$PWD/qqmlmodelindexvaluetype.cpp \ $$PWD/qqmlobjectmodel.cpp \ - $$PWD/qqmltimer.cpp \ $$PWD/qquickpackage.cpp \ $$PWD/qquickworkerscript.cpp \ $$PWD/qqmlinstantiator.cpp @@ -23,8 +22,15 @@ HEADERS += \ $$PWD/qqmlmodelsmodule_p.h \ $$PWD/qqmlmodelindexvaluetype_p.h \ $$PWD/qqmlobjectmodel_p.h \ - $$PWD/qqmltimer_p.h \ $$PWD/qquickpackage_p.h \ $$PWD/qquickworkerscript_p.h \ $$PWD/qqmlinstantiator_p.h \ $$PWD/qqmlinstantiator_p_p.h + +qtConfig(animation) { + SOURCES += \ + $$PWD/qqmltimer.cpp + + HEADERS += \ + $$PWD/qqmltimer_p.h +} diff --git a/src/quick/items/context2d/qquickcanvasitem.cpp b/src/quick/items/context2d/qquickcanvasitem.cpp index da9379e7af..dab35f2a54 100644 --- a/src/quick/items/context2d/qquickcanvasitem.cpp +++ b/src/quick/items/context2d/qquickcanvasitem.cpp @@ -1104,14 +1104,17 @@ bool QQuickCanvasItem::isImageLoaded(const QUrl& url) const QImage QQuickCanvasItem::toImage(const QRectF& rect) const { Q_D(const QQuickCanvasItem); - if (d->context) { - if (rect.isEmpty()) - return d->context->toImage(canvasWindow()); - else - return d->context->toImage(rect); - } - return QImage(); + if (!d->context) + return QImage(); + + const QRectF &rectSource = rect.isEmpty() ? canvasWindow() : rect; + const qreal dpr = window() ? window()->effectiveDevicePixelRatio() : qreal(1); + const QRectF rectScaled(rectSource.topLeft() * dpr, rectSource.size() * dpr); + + QImage image = d->context->toImage(rectScaled); + image.setDevicePixelRatio(dpr); + return image; } static const char* mimeToType(const QString &mime) diff --git a/src/quick/items/context2d/qquickcontext2d.cpp b/src/quick/items/context2d/qquickcontext2d.cpp index a32b065318..1a6f530bfa 100644 --- a/src/quick/items/context2d/qquickcontext2d.cpp +++ b/src/quick/items/context2d/qquickcontext2d.cpp @@ -960,7 +960,7 @@ static QV4::ReturnedValue qt_create_image_data(qreal w, qreal h, QV4::ExecutionE *pixelData->d()->image = QImage(w, h, QImage::Format_ARGB32); pixelData->d()->image->fill(0x00000000); } else { - Q_ASSERT(image.width() == qRound(w) && image.height() == qRound(h)); + Q_ASSERT(image.width()== qRound(w * image.devicePixelRatio()) && image.height() == qRound(h * image.devicePixelRatio())); *pixelData->d()->image = image.format() == QImage::Format_ARGB32 ? image : image.convertToFormat(QImage::Format_ARGB32); } diff --git a/src/quick/items/qquickdrag_p.h b/src/quick/items/qquickdrag_p.h index 357f72b3e7..17e9d8c690 100644 --- a/src/quick/items/qquickdrag_p.h +++ b/src/quick/items/qquickdrag_p.h @@ -248,7 +248,7 @@ class QQuickDragAttached : public QObject Q_PROPERTY(QObject *source READ source WRITE setSource NOTIFY sourceChanged RESET resetSource) Q_PROPERTY(QObject *target READ target NOTIFY targetChanged) Q_PROPERTY(QPointF hotSpot READ hotSpot WRITE setHotSpot NOTIFY hotSpotChanged) - Q_PROPERTY(QUrl imageSource READ imageSource WRITE setImageSource NOTIFY imageSourceChanged REVISION 8) + Q_PROPERTY(QUrl imageSource READ imageSource WRITE setImageSource NOTIFY imageSourceChanged) Q_PROPERTY(QStringList keys READ keys WRITE setKeys NOTIFY keysChanged) Q_PROPERTY(QVariantMap mimeData READ mimeData WRITE setMimeData NOTIFY mimeDataChanged) Q_PROPERTY(Qt::DropActions supportedActions READ supportedActions WRITE setSupportedActions NOTIFY supportedActionsChanged) diff --git a/src/quick/items/qquicktextcontrol.cpp b/src/quick/items/qquicktextcontrol.cpp index 555fd233b3..2dce3e9ec8 100644 --- a/src/quick/items/qquicktextcontrol.cpp +++ b/src/quick/items/qquicktextcontrol.cpp @@ -769,52 +769,8 @@ void QQuickTextControl::processEvent(QEvent *e, const QMatrix &matrix) case QEvent::ShortcutOverride: if (d->interactionFlags & Qt::TextEditable) { QKeyEvent* ke = static_cast<QKeyEvent *>(e); - if (ke->modifiers() == Qt::NoModifier - || ke->modifiers() == Qt::ShiftModifier - || ke->modifiers() == Qt::KeypadModifier) { - if (ke->key() < Qt::Key_Escape) { - ke->accept(); - } else { - switch (ke->key()) { - case Qt::Key_Return: - case Qt::Key_Enter: - case Qt::Key_Delete: - case Qt::Key_Home: - case Qt::Key_End: - case Qt::Key_Backspace: - case Qt::Key_Left: - case Qt::Key_Right: - case Qt::Key_Up: - case Qt::Key_Down: - case Qt::Key_Tab: - ke->accept(); - default: - break; - } - } -#if QT_CONFIG(shortcut) - } else if (ke == QKeySequence::Copy - || ke == QKeySequence::Paste - || ke == QKeySequence::Cut - || ke == QKeySequence::Redo - || ke == QKeySequence::Undo - || ke == QKeySequence::MoveToNextWord - || ke == QKeySequence::MoveToPreviousWord - || ke == QKeySequence::MoveToStartOfDocument - || ke == QKeySequence::MoveToEndOfDocument - || ke == QKeySequence::SelectNextWord - || ke == QKeySequence::SelectPreviousWord - || ke == QKeySequence::SelectStartOfLine - || ke == QKeySequence::SelectEndOfLine - || ke == QKeySequence::SelectStartOfBlock - || ke == QKeySequence::SelectEndOfBlock - || ke == QKeySequence::SelectStartOfDocument - || ke == QKeySequence::SelectEndOfDocument - || ke == QKeySequence::SelectAll - ) { + if (isCommonTextEditShortcut(ke)) ke->accept(); -#endif - } } break; default: diff --git a/src/quick/scenegraph/coreapi/qsgmaterial.cpp b/src/quick/scenegraph/coreapi/qsgmaterial.cpp index 8d666d3d0b..07dc87a643 100644 --- a/src/quick/scenegraph/coreapi/qsgmaterial.cpp +++ b/src/quick/scenegraph/coreapi/qsgmaterial.cpp @@ -419,6 +419,10 @@ void QSGMaterialShader::compile() \value DirtyMatrix Used to indicate that the matrix has changed and must be updated. \value DirtyOpacity Used to indicate that the opacity has changed and must be updated. + + \value DirtyCachedMaterialData Used to indicate that the cached material data have changed and must be updated. + + \value DirtyAll Used to indicate that everything needs to be updated. */ diff --git a/src/quick/scenegraph/coreapi/qsgnode.cpp b/src/quick/scenegraph/coreapi/qsgnode.cpp index 7ef75d4b4c..7ac3914023 100644 --- a/src/quick/scenegraph/coreapi/qsgnode.cpp +++ b/src/quick/scenegraph/coreapi/qsgnode.cpp @@ -112,6 +112,7 @@ static void qt_print_node_count() \value DirtyGeometry The geometry of a QSGGeometryNode has changed. \value DirtyMaterial The material of a QSGGeometryNode has changed. \value DirtyOpacity The opacity of a QSGOpacityNode has changed. + \value DirtySubtreeBlocked The subtree has been blocked. \sa QSGNode::markDirty() */ @@ -146,6 +147,7 @@ static void qt_print_node_count() \value TransformNodeType The type of QSGTransformNode \value ClipNodeType The type of QSGClipNode \value OpacityNodeType The type of QSGOpacityNode + \value RenderNodeType The type of QSGRenderNode \sa type() */ diff --git a/src/quick/scenegraph/util/qsgengine.cpp b/src/quick/scenegraph/util/qsgengine.cpp index 09e4cdf5a7..259e45c978 100644 --- a/src/quick/scenegraph/util/qsgengine.cpp +++ b/src/quick/scenegraph/util/qsgengine.cpp @@ -84,6 +84,8 @@ QT_BEGIN_NAMESPACE will delete the GL texture when the texture object is deleted. \value TextureCanUseAtlas The image can be uploaded into a texture atlas. + + \value TextureIsOpaque The texture object is opaque. */ QSGEnginePrivate::QSGEnginePrivate() diff --git a/src/quick/util/qquickimageprovider.cpp b/src/quick/util/qquickimageprovider.cpp index 0ceed7f681..c4a98c69f9 100644 --- a/src/quick/util/qquickimageprovider.cpp +++ b/src/quick/util/qquickimageprovider.cpp @@ -613,7 +613,6 @@ void QQuickImageProviderOptions::setPreserveAspectRatioFit(bool preserveAspectRa d->preserveAspectRatioFit = preserveAspectRatioFit; } - QQuickImageProviderWithOptions::QQuickImageProviderWithOptions(ImageType type, Flags flags) : QQuickAsyncImageProvider() { @@ -670,5 +669,49 @@ QQuickImageResponse *QQuickImageProviderWithOptions::requestImageResponse(const return requestImageResponse(id, requestedSize); } +/*! + Returns the recommended scaled image size for loading and storage. This is + calculated according to the native pixel size of the image \a originalSize, + the requested sourceSize \a requestedSize, the image file format \a format, + and \a options. If the calculation otherwise concludes that scaled loading + is not recommended, an invalid size is returned. +*/ +QSize QQuickImageProviderWithOptions::loadSize(const QSize &originalSize, const QSize &requestedSize, const QByteArray &format, const QQuickImageProviderOptions &options) +{ + QSize res; + if ((requestedSize.width() <= 0 && requestedSize.height() <= 0) || originalSize.isEmpty()) + return res; + + const bool preserveAspectCropOrFit = options.preserveAspectRatioCrop() || options.preserveAspectRatioFit(); + const bool force_scale = (format == "svg" || format == "svgz"); + + qreal ratio = 0.0; + if (requestedSize.width() && (preserveAspectCropOrFit || force_scale || requestedSize.width() < originalSize.width())) { + ratio = qreal(requestedSize.width()) / originalSize.width(); + } + if (requestedSize.height() && (preserveAspectCropOrFit || force_scale || requestedSize.height() < originalSize.height())) { + qreal hr = qreal(requestedSize.height()) / originalSize.height(); + if (ratio == 0.0) + ratio = hr; + else if (!preserveAspectCropOrFit && (hr < ratio)) + ratio = hr; + else if (preserveAspectCropOrFit && (hr > ratio)) + ratio = hr; + } + if (ratio > 0.0) { + res.setHeight(qRound(originalSize.height() * ratio)); + res.setWidth(qRound(originalSize.width() * ratio)); + } + return res; +} + +QQuickImageProviderWithOptions *QQuickImageProviderWithOptions::checkedCast(QQuickImageProvider *provider) +{ + if (provider && provider->d && provider->d->isProviderWithOptions) + return static_cast<QQuickImageProviderWithOptions *>(provider); + + return nullptr; +} + QT_END_NAMESPACE diff --git a/src/quick/util/qquickimageprovider.h b/src/quick/util/qquickimageprovider.h index c77ff95f32..681de4b6c2 100644 --- a/src/quick/util/qquickimageprovider.h +++ b/src/quick/util/qquickimageprovider.h @@ -88,7 +88,6 @@ Q_SIGNALS: class Q_QUICK_EXPORT QQuickImageProvider : public QQmlImageProviderBase { friend class QQuickImageProviderWithOptions; // ### Qt 6 Remove - friend class QQuickPixmapReader; // ### Qt 6 Remove public: QQuickImageProvider(ImageType type, Flags flags = Flags()); virtual ~QQuickImageProvider(); diff --git a/src/quick/util/qquickpixmapcache.cpp b/src/quick/util/qquickpixmapcache.cpp index 395b89c784..7d88935402 100644 --- a/src/quick/util/qquickpixmapcache.cpp +++ b/src/quick/util/qquickpixmapcache.cpp @@ -141,6 +141,7 @@ public: QUrl url; bool loading; + QQuickImageProviderOptions providerOptions; int redirectCount; class Event : public QEvent { @@ -204,7 +205,7 @@ protected: private: friend class QQuickPixmapReaderThreadObject; void processJobs(); - void processJob(QQuickPixmapReply *, const QUrl &, const QString &, const QQuickImageProviderOptions &, QQuickImageProvider::ImageType, QQuickImageProvider *); + void processJob(QQuickPixmapReply *, const QUrl &, const QString &, QQuickImageProvider::ImageType, QQuickImageProvider *); #if QT_CONFIG(qml_network) void networkRequestDone(QNetworkReply *); #endif @@ -386,37 +387,15 @@ static bool readImage(const QUrl& url, QIODevice *dev, QImage *image, QString *e const QSize &requestSize, const QQuickImageProviderOptions &providerOptions, QQuickImageProviderOptions::AutoTransform *appliedTransform = nullptr) { - const bool preserveAspectCropOrFit = providerOptions.preserveAspectRatioCrop() || providerOptions.preserveAspectRatioFit(); - QImageReader imgio(dev); if (providerOptions.autoTransform() != QQuickImageProviderOptions::UsePluginDefaultTransform) imgio.setAutoTransform(providerOptions.autoTransform() == QQuickImageProviderOptions::ApplyTransform); else if (appliedTransform) *appliedTransform = imgio.autoTransform() ? QQuickImageProviderOptions::ApplyTransform : QQuickImageProviderOptions::DoNotApplyTransform; - const bool force_scale = imgio.format() == "svg" || imgio.format() == "svgz"; - - if (requestSize.width() > 0 || requestSize.height() > 0) { - QSize s = imgio.size(); - qreal ratio = 0.0; - if (requestSize.width() && (preserveAspectCropOrFit || force_scale || requestSize.width() < s.width())) { - ratio = qreal(requestSize.width())/s.width(); - } - if (requestSize.height() && (preserveAspectCropOrFit || force_scale || requestSize.height() < s.height())) { - qreal hr = qreal(requestSize.height())/s.height(); - if (ratio == 0.0) - ratio = hr; - else if (!preserveAspectCropOrFit && (hr < ratio)) - ratio = hr; - else if (preserveAspectCropOrFit && (hr > ratio)) - ratio = hr; - } - if (ratio > 0.0) { - s.setHeight(qRound(s.height() * ratio)); - s.setWidth(qRound(s.width() * ratio)); - imgio.setScaledSize(s); - } - } + QSize scSize = QQuickImageProviderWithOptions::loadSize(imgio.size(), requestSize, imgio.format(), providerOptions); + if (scSize.isValid()) + imgio.setScaledSize(scSize); if (impsize) *impsize = imgio.size(); @@ -664,7 +643,7 @@ void QQuickPixmapReader::processJobs() PIXMAP_PROFILE(pixmapStateChanged<QQuickProfiler::PixmapLoadingStarted>(url)); locker.unlock(); - processJob(job, url, localFile, job->data->providerOptions, imageType, provider); + processJob(job, url, localFile, imageType, provider); locker.relock(); } } @@ -676,7 +655,6 @@ void QQuickPixmapReader::processJobs() } void QQuickPixmapReader::processJob(QQuickPixmapReply *runningJob, const QUrl &url, const QString &localFile, - const QQuickImageProviderOptions &providerOptions, QQuickImageProvider::ImageType imageType, QQuickImageProvider *provider) { // fetch @@ -693,8 +671,7 @@ void QQuickPixmapReader::processJob(QQuickPixmapReply *runningJob, const QUrl &u return; } - QQuickImageProviderWithOptions *providerV2 = provider->d->isProviderWithOptions ? static_cast<QQuickImageProviderWithOptions *>(provider) - : nullptr; + QQuickImageProviderWithOptions *providerV2 = QQuickImageProviderWithOptions::checkedCast(provider); switch (imageType) { case QQuickImageProvider::Invalid: @@ -707,7 +684,7 @@ void QQuickPixmapReader::processJob(QQuickPixmapReply *runningJob, const QUrl &u { QImage image; if (providerV2) { - image = providerV2->requestImage(imageId(url), &readSize, runningJob->requestSize, providerOptions); + image = providerV2->requestImage(imageId(url), &readSize, runningJob->requestSize, runningJob->providerOptions); } else { image = provider->requestImage(imageId(url), &readSize, runningJob->requestSize); } @@ -728,7 +705,7 @@ void QQuickPixmapReader::processJob(QQuickPixmapReply *runningJob, const QUrl &u { QPixmap pixmap; if (providerV2) { - pixmap = providerV2->requestPixmap(imageId(url), &readSize, runningJob->requestSize, providerOptions); + pixmap = providerV2->requestPixmap(imageId(url), &readSize, runningJob->requestSize, runningJob->providerOptions); } else { pixmap = provider->requestPixmap(imageId(url), &readSize, runningJob->requestSize); } @@ -749,7 +726,7 @@ void QQuickPixmapReader::processJob(QQuickPixmapReply *runningJob, const QUrl &u { QQuickTextureFactory *t; if (providerV2) { - t = providerV2->requestTexture(imageId(url), &readSize, runningJob->requestSize, providerOptions); + t = providerV2->requestTexture(imageId(url), &readSize, runningJob->requestSize, runningJob->providerOptions); } else { t = provider->requestTexture(imageId(url), &readSize, runningJob->requestSize); } @@ -772,7 +749,7 @@ void QQuickPixmapReader::processJob(QQuickPixmapReply *runningJob, const QUrl &u { QQuickImageResponse *response; if (providerV2) { - response = providerV2->requestImageResponse(imageId(url), runningJob->requestSize, providerOptions); + response = providerV2->requestImageResponse(imageId(url), runningJob->requestSize, runningJob->providerOptions); } else { QQuickAsyncImageProvider *asyncProvider = static_cast<QQuickAsyncImageProvider*>(provider); response = asyncProvider->requestImageResponse(imageId(url), runningJob->requestSize); @@ -794,7 +771,7 @@ void QQuickPixmapReader::processJob(QQuickPixmapReply *runningJob, const QUrl &u QFile f(localFile); QSize readSize; if (f.open(QIODevice::ReadOnly)) { - if (!readImage(url, &f, &image, &errorStr, &readSize, runningJob->requestSize, providerOptions)) + if (!readImage(url, &f, &image, &errorStr, &readSize, runningJob->requestSize, runningJob->providerOptions)) errorCode = QQuickPixmapReply::Loading; } else { errorStr = QQuickPixmap::tr("Cannot open: %1").arg(url.toString()); @@ -1075,7 +1052,7 @@ void QQuickPixmap::purgeCache() } QQuickPixmapReply::QQuickPixmapReply(QQuickPixmapData *d) -: data(d), engineForReader(0), requestSize(d->requestSize), url(d->url), loading(false), redirectCount(0) +: data(d), engineForReader(0), requestSize(d->requestSize), url(d->url), loading(false), providerOptions(d->providerOptions), redirectCount(0) { if (finishedIndex == -1) { finishedIndex = QMetaMethod::fromSignal(&QQuickPixmapReply::finished).methodIndex(); @@ -1196,6 +1173,7 @@ static QQuickPixmapData* createPixmapDataSync(QQuickPixmap *declarativePixmap, Q QQuickImageProvider::ImageType imageType = QQuickImageProvider::Invalid; QQuickImageProvider *provider = static_cast<QQuickImageProvider *>(engine->imageProvider(imageProviderId(url))); + QQuickImageProviderWithOptions *providerV2 = QQuickImageProviderWithOptions::checkedCast(provider); if (provider) imageType = provider->imageType(); @@ -1205,7 +1183,8 @@ static QQuickPixmapData* createPixmapDataSync(QQuickPixmap *declarativePixmap, Q QQuickPixmap::tr("Invalid image provider: %1").arg(url.toString())); case QQuickImageProvider::Texture: { - QQuickTextureFactory *texture = provider->requestTexture(imageId(url), &readSize, requestSize); + QQuickTextureFactory *texture = providerV2 ? providerV2->requestTexture(imageId(url), &readSize, requestSize, providerOptions) + : provider->requestTexture(imageId(url), &readSize, requestSize); if (texture) { *ok = true; return new QQuickPixmapData(declarativePixmap, url, texture, readSize, requestSize, providerOptions, QQuickImageProviderOptions::UsePluginDefaultTransform); @@ -1215,7 +1194,8 @@ static QQuickPixmapData* createPixmapDataSync(QQuickPixmap *declarativePixmap, Q case QQuickImageProvider::Image: { - QImage image = provider->requestImage(imageId(url), &readSize, requestSize); + QImage image = providerV2 ? providerV2->requestImage(imageId(url), &readSize, requestSize, providerOptions) + : provider->requestImage(imageId(url), &readSize, requestSize); if (!image.isNull()) { *ok = true; return new QQuickPixmapData(declarativePixmap, url, QQuickTextureFactory::textureFactoryForImage(image), readSize, requestSize, providerOptions, QQuickImageProviderOptions::UsePluginDefaultTransform); @@ -1224,7 +1204,8 @@ static QQuickPixmapData* createPixmapDataSync(QQuickPixmap *declarativePixmap, Q } case QQuickImageProvider::Pixmap: { - QPixmap pixmap = provider->requestPixmap(imageId(url), &readSize, requestSize); + QPixmap pixmap = providerV2 ? providerV2->requestPixmap(imageId(url), &readSize, requestSize, providerOptions) + : provider->requestPixmap(imageId(url), &readSize, requestSize); if (!pixmap.isNull()) { *ok = true; return new QQuickPixmapData(declarativePixmap, url, QQuickTextureFactory::textureFactoryForImage(pixmap.toImage()), readSize, requestSize, providerOptions, QQuickImageProviderOptions::UsePluginDefaultTransform); diff --git a/src/quick/util/qquickpixmapcache_p.h b/src/quick/util/qquickpixmapcache_p.h index 93d5a1cf56..91fb1ed3bb 100644 --- a/src/quick/util/qquickpixmapcache_p.h +++ b/src/quick/util/qquickpixmapcache_p.h @@ -204,6 +204,9 @@ public: virtual QPixmap requestPixmap(const QString &id, QSize *size, const QSize& requestedSize, const QQuickImageProviderOptions &options); virtual QQuickTextureFactory *requestTexture(const QString &id, QSize *size, const QSize &requestedSize, const QQuickImageProviderOptions &options); virtual QQuickImageResponse *requestImageResponse(const QString &id, const QSize &requestedSize, const QQuickImageProviderOptions &options); + + static QSize loadSize(const QSize &originalSize, const QSize &requestedSize, const QByteArray &format, const QQuickImageProviderOptions &options); + static QQuickImageProviderWithOptions *checkedCast(QQuickImageProvider *provider); }; QT_END_NAMESPACE diff --git a/src/quickwidgets/qquickwidget.cpp b/src/quickwidgets/qquickwidget.cpp index 5d7fb04b9f..be5837723a 100644 --- a/src/quickwidgets/qquickwidget.cpp +++ b/src/quickwidgets/qquickwidget.cpp @@ -157,6 +157,16 @@ void QQuickWidgetPrivate::invalidateRenderControl() #endif renderControl->invalidate(); + + // Many things can happen inside the above invalidate() call, including a + // change of current context. Restore if needed since some code will rely + // on the fact that this function makes and leaves the context current. +#if QT_CONFIG(opengl) + if (!useSoftwareRenderer && context) { + if (QOpenGLContext::currentContext() != context) + context->makeCurrent(offscreenSurface); + } +#endif } void QQuickWidgetPrivate::handleWindowChange() |