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
This commit is contained in:
Simon Hausmann 2017-04-07 14:48:56 +02:00
commit 017350a8a9
60 changed files with 1287 additions and 732 deletions

View File

@ -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))

View File

@ -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
}

View File

@ -770,6 +770,8 @@ void QQuickLocalStorage::openDatabaseSync(QQmlV4Function *args)
}
args->setReturnValue(db.asReturnedValue());
#else
Q_UNUSED(args)
#endif // settings
}

View File

@ -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);

View File

@ -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;
}

View File

@ -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 {

View File

@ -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

View File

@ -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

View File

@ -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();

View File

@ -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();
}

View File

@ -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));

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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;

View File

@ -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);

View File

@ -155,9 +155,6 @@ bool CompilationUnit::saveCodeToDisk(QIODevice *device, const CompiledData::Unit
return true;
}
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)
@ -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);
}

View File

@ -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);
@ -1807,6 +1821,9 @@ private:
QV4::Compiler::JSUnitGenerator *_jsGenerator;
};
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();

View File

@ -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

View File

@ -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()

View File

@ -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)

View File

@ -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();

View File

@ -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);
}

View File

@ -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;
}

View File

@ -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);
}

View File

@ -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));

View File

@ -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 = \

View File

@ -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>();

View File

@ -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
}

View File

@ -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)

View File

@ -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);
}

View File

@ -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)

View File

@ -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:

View File

@ -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.
*/

View File

@ -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()
*/

View File

@ -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()

View File

@ -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

View File

@ -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();

View File

@ -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);

View File

@ -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

View File

@ -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()

View File

@ -0,0 +1,43 @@
/****************************************************************************
**
** Copyright (C) 2017 reMarkable A/S
** Contact: http://www.qt.io/licensing/
**
** This file is part of the test suite of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL21$
** 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 http://www.qt.io/terms-conditions. For further
** information use the contact form at http://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 2.1 or version 3 as published by the Free
** Software Foundation and appearing in the file LICENSE.LGPLv21 and
** LICENSE.LGPLv3 included in the packaging of this file. Please review the
** following information to ensure the GNU Lesser General Public License
** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** As a special exception, The Qt Company gives you certain additional
** rights. These rights are described in The Qt Company LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** $QT_END_LICENSE$
**
****************************************************************************/
import QtQuick 2.6
import QtQuick.Particles 2.0
ParticleSystem {
running: false
Affector { Component.onCompleted: destroy() }
Emitter {
Timer { interval: 1; running: true; onTriggered: parent.lifeSpan = 1 }
}
}

View File

@ -42,6 +42,7 @@ public:
private slots:
void initTestCase();
void test_basic();
void test_affectorscrash();
};
void tst_qquickparticlesystem::initTestCase()
@ -78,6 +79,12 @@ void tst_qquickparticlesystem::test_basic()
delete view;
QVERIFY(extremelyFuzzyCompare(stillAlive, 500, 5));//Small simulation variance is permissible.
}
void tst_qquickparticlesystem::test_affectorscrash()
{
QScopedPointer<QQuickView> view (createView(testFileUrl("crashaffectors.qml"), 600));
// This should have crashed by now
}
QTEST_MAIN(tst_qquickparticlesystem);

View File

@ -180,14 +180,9 @@ void tst_QQmlEngineDebugService::recursiveObjectTest(
{
const QMetaObject *meta = o->metaObject();
QQmlType *type = QQmlMetaType::qmlType(meta);
QString className = type ? QString(type->qmlTypeName())
: QString(meta->className());
className = className.mid(className.lastIndexOf(QLatin1Char('/'))+1);
QCOMPARE(oref.debugId, QQmlDebugService::idForObject(o));
QCOMPARE(oref.name, o->objectName());
QCOMPARE(oref.className, className);
QCOMPARE(oref.className, QQmlMetaType::prettyTypeName(o));
QCOMPARE(oref.contextDebugId, QQmlDebugService::idForObject(
qmlContext(o)));
@ -201,6 +196,7 @@ void tst_QQmlEngineDebugService::recursiveObjectTest(
QmlDebugObjectReference cref;
foreach (const QmlDebugObjectReference &ref, oref.children) {
QVERIFY(!ref.className.isEmpty());
if (ref.debugId == debugId) {
cref = ref;
break;
@ -369,6 +365,7 @@ void tst_QQmlEngineDebugService::setMethodBody()
{
bool success;
QmlDebugObjectReference obj = findRootObject(2);
QVERIFY(!obj.className.isEmpty());
QObject *root = m_components.at(2);
// Without args
@ -410,6 +407,7 @@ void tst_QQmlEngineDebugService::setMethodBody()
void tst_QQmlEngineDebugService::watch_property()
{
QmlDebugObjectReference obj = findRootObject();
QVERIFY(!obj.className.isEmpty());
QmlDebugPropertyReference prop = findProperty(obj.properties, "width");
bool success;
@ -454,6 +452,7 @@ void tst_QQmlEngineDebugService::watch_property()
void tst_QQmlEngineDebugService::watch_object()
{
QmlDebugObjectReference obj = findRootObject();
QVERIFY(!obj.className.isEmpty());
bool success;
@ -519,6 +518,7 @@ void tst_QQmlEngineDebugService::watch_expression()
int origWidth = m_rootItem->property("width").toInt();
QmlDebugObjectReference obj = findRootObject();
QVERIFY(!obj.className.isEmpty());
bool success;
@ -654,6 +654,7 @@ void tst_QQmlEngineDebugService::queryObject()
bool success;
QmlDebugObjectReference rootObject = findRootObject();
QVERIFY(!rootObject.className.isEmpty());
QQmlEngineDebugClient *unconnected = new QQmlEngineDebugClient(0);
recursive ? unconnected->queryObjectRecursive(rootObject, &success) : unconnected->queryObject(rootObject, &success);
@ -665,6 +666,7 @@ void tst_QQmlEngineDebugService::queryObject()
QVERIFY(QQmlDebugTest::waitForSignal(m_dbg, SIGNAL(result())));
QmlDebugObjectReference obj = m_dbg->object();
QVERIFY(!obj.className.isEmpty());
// check source as defined in main()
QmlDebugFileReference source = obj.source;
@ -676,12 +678,15 @@ void tst_QQmlEngineDebugService::queryObject()
recursiveObjectTest(m_rootItem, obj, recursive);
if (recursive) {
foreach (const QmlDebugObjectReference &child, obj.children)
foreach (const QmlDebugObjectReference &child, obj.children) {
QVERIFY(!child.className.isEmpty());
QVERIFY(child.properties.count() > 0);
}
QmlDebugObjectReference rect;
QmlDebugObjectReference text;
foreach (const QmlDebugObjectReference &child, obj.children) {
QVERIFY(!child.className.isEmpty());
if (child.className == "Rectangle")
rect = child;
else if (child.className == "Text")
@ -695,8 +700,10 @@ void tst_QQmlEngineDebugService::queryObject()
QCOMPARE(findProperty(text.properties, "color").value, qVariantFromValue(QColor("blue")));
} else {
foreach (const QmlDebugObjectReference &child, obj.children)
foreach (const QmlDebugObjectReference &child, obj.children) {
QVERIFY(!child.className.isEmpty());
QCOMPARE(child.properties.count(), 0);
}
}
}
@ -715,6 +722,7 @@ void tst_QQmlEngineDebugService::queryObjectsForLocation()
bool success;
QmlDebugObjectReference rootObject = findRootObject();
QVERIFY(!rootObject.className.isEmpty());
const QString fileName = QFileInfo(rootObject.source.url.toString()).fileName();
int lineNumber = rootObject.source.lineNumber;
@ -737,6 +745,7 @@ void tst_QQmlEngineDebugService::queryObjectsForLocation()
QCOMPARE(m_dbg->objects().count(), 1);
QmlDebugObjectReference obj = m_dbg->objects().first();
QVERIFY(!obj.className.isEmpty());
// check source as defined in main()
QmlDebugFileReference source = obj.source;
@ -748,12 +757,15 @@ void tst_QQmlEngineDebugService::queryObjectsForLocation()
recursiveObjectTest(m_rootItem, obj, recursive);
if (recursive) {
foreach (const QmlDebugObjectReference &child, obj.children)
foreach (const QmlDebugObjectReference &child, obj.children) {
QVERIFY(!child.className.isEmpty());
QVERIFY(child.properties.count() > 0);
}
QmlDebugObjectReference rect;
QmlDebugObjectReference text;
foreach (const QmlDebugObjectReference &child, obj.children) {
QVERIFY(!child.className.isEmpty());
if (child.className == "Rectangle")
rect = child;
else if (child.className == "Text")
@ -767,8 +779,10 @@ void tst_QQmlEngineDebugService::queryObjectsForLocation()
QCOMPARE(findProperty(text.properties, "color").value, qVariantFromValue(QColor("blue")));
} else {
foreach (const QmlDebugObjectReference &child, obj.children)
foreach (const QmlDebugObjectReference &child, obj.children) {
QVERIFY(!child.className.isEmpty());
QCOMPARE(child.properties.count(), 0);
}
}
}
@ -783,6 +797,7 @@ void tst_QQmlEngineDebugService::queryObjectsForLocation_data()
void tst_QQmlEngineDebugService::regression_QTCREATORBUG_7451()
{
QmlDebugObjectReference rootObject = findRootObject();
QVERIFY(!rootObject.className.isEmpty());
int contextId = rootObject.contextDebugId;
QQmlContext *context = qobject_cast<QQmlContext *>(QQmlDebugService::objectForId(contextId));
QQmlComponent component(context->engine());
@ -809,6 +824,7 @@ void tst_QQmlEngineDebugService::regression_QTCREATORBUG_7451()
QVERIFY(QQmlDebugTest::waitForSignal(m_dbg, SIGNAL(result())));
foreach (QmlDebugObjectReference child, rootObject.children) {
QVERIFY(!child.className.isEmpty());
success = false;
lineNumber = child.source.lineNumber;
columnNumber = child.source.columnNumber;
@ -831,6 +847,7 @@ void tst_QQmlEngineDebugService::regression_QTCREATORBUG_7451()
QVERIFY(QQmlDebugTest::waitForSignal(m_dbg, SIGNAL(result())));
foreach (QmlDebugObjectReference child, rootObject.children) {
QVERIFY(!child.className.isEmpty());
success = false;
lineNumber = child.source.lineNumber;
columnNumber = child.source.columnNumber;
@ -846,6 +863,7 @@ void tst_QQmlEngineDebugService::queryObjectWithNonStreamableTypes()
bool success;
QmlDebugObjectReference rootObject = findRootObject(4, true);
QVERIFY(!rootObject.className.isEmpty());
QQmlEngineDebugClient *unconnected = new QQmlEngineDebugClient(0);
unconnected->queryObject(rootObject, &success);
@ -857,6 +875,7 @@ void tst_QQmlEngineDebugService::queryObjectWithNonStreamableTypes()
QVERIFY(QQmlDebugTest::waitForSignal(m_dbg, SIGNAL(result())));
QmlDebugObjectReference obj = m_dbg->object();
QVERIFY(!obj.className.isEmpty());
QCOMPARE(findProperty(obj.properties, "modelIndex").value, QVariant());
}
@ -950,6 +969,7 @@ void tst_QQmlEngineDebugService::queryExpressionResultBC_data()
void tst_QQmlEngineDebugService::setBindingForObject()
{
QmlDebugObjectReference rootObject = findRootObject();
QVERIFY(!rootObject.className.isEmpty());
QVERIFY(rootObject.debugId != -1);
QmlDebugPropertyReference widthPropertyRef = findProperty(rootObject.properties, "width");
@ -967,6 +987,7 @@ void tst_QQmlEngineDebugService::setBindingForObject()
QCOMPARE(m_dbg->valid(), true);
rootObject = findRootObject();
QVERIFY(!rootObject.className.isEmpty());
widthPropertyRef = findProperty(rootObject.properties, "width");
QCOMPARE(widthPropertyRef.value, QVariant(15));
@ -982,6 +1003,7 @@ void tst_QQmlEngineDebugService::setBindingForObject()
QCOMPARE(m_dbg->valid(), true);
rootObject = findRootObject();
QVERIFY(!rootObject.className.isEmpty());
widthPropertyRef = findProperty(rootObject.properties, "width");
QCOMPARE(widthPropertyRef.value, QVariant(20));
@ -992,13 +1014,14 @@ void tst_QQmlEngineDebugService::setBindingForObject()
// set handler
//
rootObject = findRootObject();
QVERIFY(!rootObject.className.isEmpty());
QCOMPARE(rootObject.children.size(), 5); // Rectangle, Text, MouseArea, Component.onCompleted, NonScriptPropertyElement
QmlDebugObjectReference mouseAreaObject = rootObject.children.at(2);
QVERIFY(!mouseAreaObject.className.isEmpty());
m_dbg->queryObjectRecursive(mouseAreaObject, &success);
QVERIFY(success);
QVERIFY(QQmlDebugTest::waitForSignal(m_dbg, SIGNAL(result())));
mouseAreaObject = m_dbg->object();
QCOMPARE(mouseAreaObject.className, QString("MouseArea"));
QmlDebugPropertyReference onEnteredRef = findProperty(mouseAreaObject.properties, "onEntered");
@ -1015,11 +1038,14 @@ void tst_QQmlEngineDebugService::setBindingForObject()
QCOMPARE(m_dbg->valid(), true);
rootObject = findRootObject();
QVERIFY(!rootObject.className.isEmpty());
mouseAreaObject = rootObject.children.at(2);
QVERIFY(!mouseAreaObject.className.isEmpty());
m_dbg->queryObjectRecursive(mouseAreaObject, &success);
QVERIFY(success);
QVERIFY(QQmlDebugTest::waitForSignal(m_dbg, SIGNAL(result())));
mouseAreaObject = m_dbg->object();
QVERIFY(!mouseAreaObject.className.isEmpty());
onEnteredRef = findProperty(mouseAreaObject.properties, "onEntered");
QCOMPARE(onEnteredRef.name, QString("onEntered"));
QCOMPARE(onEnteredRef.value, QVariant("function() { [code] }"));
@ -1028,6 +1054,7 @@ void tst_QQmlEngineDebugService::setBindingForObject()
void tst_QQmlEngineDebugService::resetBindingForObject()
{
QmlDebugObjectReference rootObject = findRootObject();
QVERIFY(!rootObject.className.isEmpty());
QVERIFY(rootObject.debugId != -1);
QmlDebugPropertyReference widthPropertyRef = findProperty(rootObject.properties, "width");
@ -1048,6 +1075,7 @@ void tst_QQmlEngineDebugService::resetBindingForObject()
QCOMPARE(m_dbg->valid(), true);
rootObject = findRootObject();
QVERIFY(!rootObject.className.isEmpty());
widthPropertyRef = findProperty(rootObject.properties, "width");
QCOMPARE(widthPropertyRef.value, QVariant(0));
@ -1063,6 +1091,7 @@ void tst_QQmlEngineDebugService::resetBindingForObject()
QCOMPARE(m_dbg->valid(), true);
rootObject = findRootObject();
QVERIFY(!rootObject.className.isEmpty());
QmlDebugPropertyReference boldPropertyRef = findProperty(rootObject.properties, "font.bold");
QCOMPARE(boldPropertyRef.value.toBool(), false);
@ -1076,7 +1105,7 @@ void tst_QQmlEngineDebugService::setBindingInStates()
const int sourceIndex = 3;
QmlDebugObjectReference obj = findRootObject(sourceIndex);
QVERIFY(!obj.className.isEmpty());
QVERIFY(obj.debugId != -1);
QVERIFY(obj.children.count() >= 2);
bool success;
@ -1092,6 +1121,7 @@ void tst_QQmlEngineDebugService::setBindingInStates()
QVERIFY(QQmlDebugTest::waitForSignal(m_dbg, SIGNAL(result())));
obj = findRootObject(sourceIndex);
QVERIFY(!obj.className.isEmpty());
QCOMPARE(findProperty(obj.properties,"width").value.toInt(),200);
@ -1102,6 +1132,7 @@ void tst_QQmlEngineDebugService::setBindingInStates()
obj = findRootObject(sourceIndex, true);
QVERIFY(!obj.className.isEmpty());
QCOMPARE(findProperty(obj.properties,"width").value.toInt(),100);
@ -1111,6 +1142,7 @@ void tst_QQmlEngineDebugService::setBindingInStates()
QVERIFY(state.children.count() > 0);
QmlDebugObjectReference propertyChange = state.children[0];
QVERIFY(!propertyChange.className.isEmpty());
QVERIFY(propertyChange.debugId != -1);
m_dbg->setBindingForObject(propertyChange.debugId, "width",QVariant(300),true,
@ -1120,6 +1152,7 @@ void tst_QQmlEngineDebugService::setBindingInStates()
// check properties changed in state
obj = findRootObject(sourceIndex);
QVERIFY(!obj.className.isEmpty());
QCOMPARE(findProperty(obj.properties,"width").value.toInt(),100);
@ -1128,6 +1161,7 @@ void tst_QQmlEngineDebugService::setBindingInStates()
QVERIFY(QQmlDebugTest::waitForSignal(m_dbg, SIGNAL(result())));
obj = findRootObject(sourceIndex);
QVERIFY(!obj.className.isEmpty());
QCOMPARE(findProperty(obj.properties,"width").value.toInt(),300);
// check changing properties of base state from within a state
@ -1141,6 +1175,7 @@ void tst_QQmlEngineDebugService::setBindingInStates()
QVERIFY(QQmlDebugTest::waitForSignal(m_dbg, SIGNAL(result())));
obj = findRootObject(sourceIndex);
QVERIFY(!obj.className.isEmpty());
QCOMPARE(findProperty(obj.properties,"width").value.toInt(),300);
m_dbg->queryExpressionResult(obj.debugId,QString("state=\"\""), &success);
@ -1148,6 +1183,7 @@ void tst_QQmlEngineDebugService::setBindingInStates()
QVERIFY(QQmlDebugTest::waitForSignal(m_dbg, SIGNAL(result())));
obj = findRootObject(sourceIndex);
QVERIFY(!obj.className.isEmpty());
QCOMPARE(findProperty(obj.properties,"width").value.toInt(), 400);
// reset binding while in a state
@ -1156,6 +1192,7 @@ void tst_QQmlEngineDebugService::setBindingInStates()
QVERIFY(QQmlDebugTest::waitForSignal(m_dbg, SIGNAL(result())));
obj = findRootObject(sourceIndex);
QVERIFY(!obj.className.isEmpty());
QCOMPARE(findProperty(obj.properties,"width").value.toInt(), 300);
m_dbg->resetBindingForObject(propertyChange.debugId, "width", &success);
@ -1164,6 +1201,7 @@ void tst_QQmlEngineDebugService::setBindingInStates()
QCOMPARE(m_dbg->valid(), true);
obj = findRootObject(sourceIndex);
QVERIFY(!obj.className.isEmpty());
QCOMPARE(findProperty(obj.properties,"width").value.toInt(), 400);
// re-add binding
@ -1174,6 +1212,7 @@ void tst_QQmlEngineDebugService::setBindingInStates()
QCOMPARE(m_dbg->valid(), true);
obj = findRootObject(sourceIndex);
QVERIFY(!obj.className.isEmpty());
QCOMPARE(findProperty(obj.properties,"width").value.toInt(), 300);
}
@ -1182,7 +1221,7 @@ void tst_QQmlEngineDebugService::queryObjectTree()
const int sourceIndex = 3;
QmlDebugObjectReference obj = findRootObject(sourceIndex, true);
QVERIFY(!obj.className.isEmpty());
QVERIFY(obj.debugId != -1);
QVERIFY(obj.children.count() >= 2);
@ -1192,16 +1231,16 @@ void tst_QQmlEngineDebugService::queryObjectTree()
QVERIFY(state.children.count() > 0);
QmlDebugObjectReference propertyChange = state.children[0];
QVERIFY(!propertyChange.className.isEmpty());
QVERIFY(propertyChange.debugId != -1);
QmlDebugPropertyReference propertyChangeTarget = findProperty(propertyChange.properties,"target");
QCOMPARE(propertyChangeTarget.objectDebugId, propertyChange.debugId);
QmlDebugObjectReference targetReference = qvariant_cast<QmlDebugObjectReference>(propertyChangeTarget.value);
QVERIFY(!targetReference.className.isEmpty());
QVERIFY(targetReference.debugId != -1);
// check transition
QmlDebugObjectReference transition = obj.children[0];
QCOMPARE(transition.className, QString("Transition"));
@ -1210,12 +1249,14 @@ void tst_QQmlEngineDebugService::queryObjectTree()
QVERIFY(transition.children.count() > 0);
QmlDebugObjectReference animation = transition.children[0];
QVERIFY(!animation.className.isEmpty());
QVERIFY(animation.debugId != -1);
QmlDebugPropertyReference animationTarget = findProperty(animation.properties,"target");
QCOMPARE(animationTarget.objectDebugId, animation.debugId);
targetReference = qvariant_cast<QmlDebugObjectReference>(animationTarget.value);
QVERIFY(!targetReference.className.isEmpty());
QVERIFY(targetReference.debugId != -1);
QCOMPARE(findProperty(animation.properties,"property").value.toString(), QString("width"));

View File

@ -315,8 +315,8 @@ private slots:
void stepToEndOfScript_data() { redundancy_data(); }
void stepToEndOfScript();
void lastLineOfLoop_data();
void lastLineOfLoop();
void lastLineOfConditional_data();
void lastLineOfConditional();
private:
QV4Debugger *debugger() const
{
@ -801,32 +801,60 @@ void tst_qv4debugger::stepToEndOfScript()
QCOMPARE(state.lineNumber, -4); // A return instruction without proper line number.
}
void tst_qv4debugger::lastLineOfLoop_data()
void tst_qv4debugger::lastLineOfConditional_data()
{
QTest::addColumn<QString>("loopHead");
QTest::addColumn<QString>("loopTail");
QTest::addColumn<QString>("head");
QTest::addColumn<QString>("tail");
QTest::addColumn<int>("breakPoint");
QTest::addColumn<int>("lastLine");
QTest::newRow("for") << "for (var i = 0; i < 10; ++i) {\n" << "}\n";
QTest::newRow("for..in") << "for (var i in [0, 1, 2, 3, 4]) {\n" << "}\n";
QTest::newRow("while") << "while (ret < 10) {\n" << "}\n";
QTest::newRow("do..while") << "do {\n" << "} while (ret < 10);\n";
QTest::newRow("for {block}") << "for (var i = 0; i < 10; ++i) {\n" << "}" << 4 << 7;
QTest::newRow("for..in {block}") << "for (var i in [0, 1, 2, 3, 4]) {\n" << "}" << 4 << 7;
QTest::newRow("while {block}") << "while (ret < 10) {\n" << "}" << 4 << 7;
QTest::newRow("do..while {block}") << "do {\n" << "} while (ret < 10);" << 4 << 7;
QTest::newRow("if true {block}") << "if (true) {\n" << "}"
<< 4 << 7;
QTest::newRow("if false {block}") << "if (false) {\n" << "}"
<< 2 << 8;
QTest::newRow("if true else {block}") << "if (true) {\n" << "} else {\n ret += 8;\n}"
<< 4 << 7;
QTest::newRow("if false else {block}") << "if (false) {\n" << "} else {\n ret += 8;\n}"
<< 8 << 9;
QTest::newRow("for statement") << "for (var i = 0; i < 10; ++i)\n" << "" << 4 << 2;
QTest::newRow("for..in statement") << "for (var i in [0, 1, 2, 3, 4])\n" << "" << 4 << 2;
QTest::newRow("while statement") << "while (ret < 10)\n" << "" << 4 << 2;
QTest::newRow("do..while statement") << "do\n" << "while (ret < 10);" << 4 << 7;
// For two nested if statements without blocks, we need to map the jump from the inner to the
// outer one on the outer "if". There is just no better place.
QTest::newRow("if true statement") << "if (true)\n" << "" << 4 << 2;
QTest::newRow("if false statement") << "if (false)\n" << "" << 2 << 8;
// Also two nested ifs without blocks.
QTest::newRow("if true else statement") << "if (true)\n" << "else\n ret += 8;" << 4 << 2;
QTest::newRow("if false else statement") << "if (false)\n" << "else\n ret += 8;" << 8 << 9;
}
void tst_qv4debugger::lastLineOfLoop()
void tst_qv4debugger::lastLineOfConditional()
{
QFETCH(QString, loopHead);
QFETCH(QString, loopTail);
QFETCH(QString, head);
QFETCH(QString, tail);
QFETCH(int, breakPoint);
QFETCH(int, lastLine);
QString script =
"var ret = 0;\n"
+ loopHead +
"var ret = 2;\n"
+ head +
" if (ret == 2)\n"
" ret += 4;\n" // breakpoint, then step over
" else \n"
" else\n"
" ret += 1;\n"
+ loopTail;
+ tail + "\n" +
"ret -= 5;";
debugger()->addBreakPoint("trueBranch", 4);
debugger()->addBreakPoint("trueBranch", breakPoint);
m_debuggerAgent->m_resumeSpeed = QV4Debugger::StepOver;
evaluateJavaScript(script, "trueBranch");
QVERIFY(m_debuggerAgent->m_wasPaused);
@ -834,10 +862,10 @@ void tst_qv4debugger::lastLineOfLoop()
QVERIFY(m_debuggerAgent->m_statesWhenPaused.count() > 1);
QV4Debugger::ExecutionState firstState = m_debuggerAgent->m_statesWhenPaused.first();
QCOMPARE(firstState.fileName, QString("trueBranch"));
QCOMPARE(firstState.lineNumber, 4);
QCOMPARE(firstState.lineNumber, breakPoint);
QV4Debugger::ExecutionState secondState = m_debuggerAgent->m_statesWhenPaused.at(1);
QCOMPARE(secondState.fileName, QString("trueBranch"));
QCOMPARE(secondState.lineNumber, 7);
QCOMPARE(secondState.lineNumber, lastLine);
}
void tst_qv4debugger::redundancy_data()

View File

@ -386,6 +386,7 @@ void QQmlEngineDebugClient::decode(QPacket &ds,
{
QmlDebugObjectReference obj;
obj.debugId = prop.value.toInt();
obj.className = prop.valueTypeName;
prop.value = qVariantFromValue(obj);
break;
}

View File

@ -36,6 +36,7 @@ PRIVATETESTS += \
qqmlcpputils \
qqmldirparser \
v4misc \
qmlcachegen
!boot2qt {
PRIVATETESTS += \

View File

@ -0,0 +1,7 @@
CONFIG += testcase
TARGET = tst_qmlcachegen
macos:CONFIG -= app_bundle
SOURCES += tst_qmlcachegen.cpp
QT += core-private qml-private testlib

View File

@ -0,0 +1,163 @@
/****************************************************************************
**
** Copyright (C) 2016 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the test suite of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:GPL-EXCEPT$
** 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 General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3 as published by the Free Software
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
** 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-3.0.html.
**
** $QT_END_LICENSE$
**
****************************************************************************/
#include <qtest.h>
#include <QQmlComponent>
#include <QQmlEngine>
#include <QProcess>
#include <QLibraryInfo>
#include <QSysInfo>
class tst_qmlcachegen: public QObject
{
Q_OBJECT
private slots:
void initTestCase();
void loadGeneratedFile();
void translationExpressionSupport();
};
// A wrapper around QQmlComponent to ensure the temporary reference counts
// on the type data as a result of the main thread <> loader thread communication
// are dropped. Regular Synchronous loading will leave us with an event posted
// to the gui thread and an extra refcount that will only be dropped after the
// event delivery. A plain sendPostedEvents() however is insufficient because
// we can't be sure that the event is posted after the constructor finished.
class CleanlyLoadingComponent : public QQmlComponent
{
public:
CleanlyLoadingComponent(QQmlEngine *engine, const QUrl &url)
: QQmlComponent(engine, url, QQmlComponent::Asynchronous)
{ waitForLoad(); }
CleanlyLoadingComponent(QQmlEngine *engine, const QString &fileName)
: QQmlComponent(engine, fileName, QQmlComponent::Asynchronous)
{ waitForLoad(); }
void waitForLoad()
{
QTRY_VERIFY(status() == QQmlComponent::Ready || status() == QQmlComponent::Error);
}
};
static bool generateCache(const QString &qmlFileName)
{
QProcess proc;
proc.setProcessChannelMode(QProcess::ForwardedChannels);
proc.setProgram(QLibraryInfo::location(QLibraryInfo::BinariesPath) + QDir::separator() + QLatin1String("qmlcachegen"));
proc.setArguments(QStringList() << (QLatin1String("--target-architecture=") + QSysInfo::buildCpuArchitecture()) << (QLatin1String("--target-abi=") + QSysInfo::buildAbi()) << qmlFileName);
proc.start();
if (!proc.waitForFinished())
return false;
if (proc.exitStatus() != QProcess::NormalExit)
return false;
return proc.exitCode() == 0;
}
void tst_qmlcachegen::initTestCase()
{
qputenv("QML_FORCE_DISK_CACHE", "1");
}
void tst_qmlcachegen::loadGeneratedFile()
{
QTemporaryDir tempDir;
QVERIFY(tempDir.isValid());
const auto writeTempFile = [&tempDir](const QString &fileName, const char *contents) {
QFile f(tempDir.path() + '/' + fileName);
const bool ok = f.open(QIODevice::WriteOnly | QIODevice::Truncate);
Q_ASSERT(ok);
f.write(contents);
return f.fileName();
};
const QString testFilePath = writeTempFile("test.qml", "import QtQml 2.0\n"
"QtObject {\n"
" property int value: Math.min(100, 42);\n"
"}");
QVERIFY(generateCache(testFilePath));
const QString cacheFilePath = testFilePath + QLatin1Char('c');
QVERIFY(QFile::exists(cacheFilePath));
QVERIFY(QFile::remove(testFilePath));
QQmlEngine engine;
CleanlyLoadingComponent component(&engine, QUrl::fromLocalFile(testFilePath));
QScopedPointer<QObject> obj(component.create());
QVERIFY(!obj.isNull());
QCOMPARE(obj->property("value").toInt(), 42);
}
void tst_qmlcachegen::translationExpressionSupport()
{
QTemporaryDir tempDir;
QVERIFY(tempDir.isValid());
const auto writeTempFile = [&tempDir](const QString &fileName, const char *contents) {
QFile f(tempDir.path() + '/' + fileName);
const bool ok = f.open(QIODevice::WriteOnly | QIODevice::Truncate);
Q_ASSERT(ok);
f.write(contents);
return f.fileName();
};
const QString testFilePath = writeTempFile("test.qml", "import QtQml.Models 2.2\n"
"import QtQml 2.2\n"
"QtObject {\n"
" property ListModel model: ListModel {\n"
" ListElement {\n"
" text: qsTr(\"All\")\n"
" }\n"
" ListElement {\n"
" text: QT_TR_NOOP(\"Ok\")\n"
" }\n"
" }\n"
" property string text: model.get(0).text + \" \" + model.get(1).text\n"
"}");
QVERIFY(generateCache(testFilePath));
const QString cacheFilePath = testFilePath + QLatin1Char('c');
QVERIFY(QFile::exists(cacheFilePath));
QVERIFY(QFile::remove(testFilePath));
QQmlEngine engine;
CleanlyLoadingComponent component(&engine, QUrl::fromLocalFile(testFilePath));
QScopedPointer<QObject> obj(component.create());
QVERIFY(!obj.isNull());
QCOMPARE(obj->property("text").toString(), QString("All Ok"));
}
QTEST_GUILESS_MAIN(tst_qmlcachegen)
#include "tst_qmlcachegen.moc"

View File

@ -10,3 +10,7 @@ linux
[ListView::test_listInteractiveCurrentIndexEnforce]
linux
macos-10.12
[TextEdit::test_textentry]
macos-10.12
[TextEdit::test_textentry_char]
macos-10.12

View File

@ -0,0 +1,2 @@
[active]
osx-10.11

View File

@ -17,3 +17,5 @@ osx
osx-10.10
[flickVelocity]
osx-10.10
[nestedSliderUsingTouch:keepNeither]
ubuntu-16.04

View File

@ -63,9 +63,7 @@ public:
, touchReleases(0)
, ungrabs(0)
, m_active(false)
{
setFlags(ItemAcceptsDrops);
}
{ }
QPointF pos() const { return m_pos; }
@ -2044,10 +2042,10 @@ void tst_qquickflickable::nestedSliderUsingTouch()
QCOMPARE(tda->active(), !ungrabs);
QTest::touchEvent(window, touchDevice).release(0, p0, window);
QQuickTouchUtils::flush(window);
QCOMPARE(tda->touchPointStates.first(), Qt::TouchPointPressed);
QCOMPARE(tda->touchUpdates, updates);
QCOMPARE(tda->touchReleases, releases);
QCOMPARE(tda->ungrabs, ungrabs);
QTRY_COMPARE(tda->touchPointStates.first(), Qt::TouchPointPressed);
QTRY_COMPARE(tda->touchUpdates, updates);
QTRY_COMPARE(tda->touchReleases, releases);
QTRY_COMPARE(tda->ungrabs, ungrabs);
}
// QTBUG-31328

View File

@ -0,0 +1,4 @@
[nonOverlapping]
ubuntu-16.04
[nested]
ubuntu-16.04

View File

@ -0,0 +1,2 @@
[requestActivate]
osx-10.11

View File

@ -55,7 +55,9 @@
#include <QLibraryInfo>
#include <qqml.h>
#include <qqmldebug.h>
#if QT_CONFIG(animation)
#include <private/qabstractanimation_p.h>
#endif
#include <cstdio>
#include <cstring>
@ -476,10 +478,12 @@ int main(int argc, char *argv[])
break;
else if (arg == QLatin1String("-verbose"))
verboseMode = true;
#if QT_CONFIG(animation)
else if (arg == QLatin1String("-slow-animations"))
QUnifiedTimer::instance()->setSlowModeEnabled(true);
else if (arg == QLatin1String("-fixed-animations"))
QUnifiedTimer::instance()->setConsistentTiming(true);
#endif
else if (arg == QLatin1String("-I")) {
if (i+1 == argList.count())
continue;//Invalid usage, but just ignore it

View File

@ -10,7 +10,10 @@ isEmpty(TARGETPATH): error("Must set TARGETPATH (QML import name) for ahead-of-t
!isEmpty(QT_TARGET_ARCH):QML_CACHEGEN_ARCH=$$QT_TARGET_ARCH
else:QML_CACHEGEN_ARCH=$$QT_ARCH
QML_CACHEGEN_ARGS=--target-architecture=$$QML_CACHEGEN_ARCH
!isEmpty(QT_TARGET_BUILDABI):QML_CACHEGEN_ABI=$$QT_TARGET_BUILDABI
else:QML_CACHEGEN_ABI=$$QT_BUILDABI
QML_CACHEGEN_ARGS=--target-architecture=$$QML_CACHEGEN_ARCH --target-abi=$$QML_CACHEGEN_ABI
!system($$QML_CACHEGEN_ARCH_CHECK $$QML_CACHEGEN_ARGS --check-if-supported) {
message("QML cache generation requested but target architecture $$QML_CACHEGEN_ARCH is not supported.")

View File

@ -37,6 +37,7 @@
#include <private/qqmlirbuilder_p.h>
#include <private/qv4isel_moth_p.h>
#include <private/qqmljsparser_p.h>
#include <private/qv4jssimplifier_p.h>
QT_BEGIN_NAMESPACE
@ -113,9 +114,10 @@ static void annotateListElements(QmlIR::Document *document)
}
}
static bool compileQmlFile(const QString &inputFileName, const QString &outputFileName, QV4::EvalISelFactory *iselFactory, Error *error)
static bool compileQmlFile(const QString &inputFileName, const QString &outputFileName, QV4::EvalISelFactory *iselFactory, const QString &targetABI, Error *error)
{
QmlIR::Document irDocument(/*debugMode*/false);
irDocument.jsModule.targetABI = targetABI;
QString sourceCode;
{
@ -173,7 +175,10 @@ static bool compileQmlFile(const QString &inputFileName, const QString &outputFi
QmlIR::QmlUnitGenerator generator;
// ### translation binding simplification
{
QQmlJavaScriptBindingExpressionSimplificationPass pass(irDocument.objects, &irDocument.jsModule, &irDocument.jsGenerator);
pass.reduceTranslationBindings();
}
QV4::ExecutableAllocator allocator;
QScopedPointer<QV4::EvalInstructionSelection> isel(iselFactory->create(/*engine*/nullptr, &allocator, &irDocument.jsModule, &irDocument.jsGenerator));
@ -193,9 +198,10 @@ static bool compileQmlFile(const QString &inputFileName, const QString &outputFi
return true;
}
static bool compileJSFile(const QString &inputFileName, const QString &outputFileName, QV4::EvalISelFactory *iselFactory, Error *error)
static bool compileJSFile(const QString &inputFileName, const QString &outputFileName, QV4::EvalISelFactory *iselFactory, const QString &targetABI, Error *error)
{
QmlIR::Document irDocument(/*debugMode*/false);
irDocument.jsModule.targetABI = targetABI;
QString sourceCode;
{
@ -262,8 +268,6 @@ static bool compileJSFile(const QString &inputFileName, const QString &outputFil
QmlIR::QmlUnitGenerator generator;
// ### translation binding simplification
QV4::ExecutableAllocator allocator;
QScopedPointer<QV4::EvalInstructionSelection> isel(iselFactory->create(/*engine*/nullptr, &allocator, &irDocument.jsModule, &irDocument.jsGenerator));
// Disable lookups in non-standalone (aka QML) mode
@ -300,6 +304,9 @@ int main(int argc, char **argv)
QCommandLineOption targetArchitectureOption(QStringLiteral("target-architecture"), QCoreApplication::translate("main", "Target architecture"), QCoreApplication::translate("main", "architecture"));
parser.addOption(targetArchitectureOption);
QCommandLineOption targetABIOption(QStringLiteral("target-abi"), QCoreApplication::translate("main", "Target architecture binary interface"), QCoreApplication::translate("main", "abi"));
parser.addOption(targetABIOption);
QCommandLineOption outputFileOption(QStringLiteral("o"), QCoreApplication::translate("main", "Output file name"), QCoreApplication::translate("main", "file name"));
parser.addOption(outputFileOption);
@ -347,13 +354,15 @@ int main(int argc, char **argv)
if (parser.isSet(outputFileOption))
outputFileName = parser.value(outputFileOption);
const QString targetABI = parser.value(targetABIOption);
if (inputFile.endsWith(QLatin1String(".qml"))) {
if (!compileQmlFile(inputFile, outputFileName, isel.data(), &error)) {
if (!compileQmlFile(inputFile, outputFileName, isel.data(), targetABI, &error)) {
error.augment(QLatin1String("Error compiling qml file: ")).print();
return EXIT_FAILURE;
}
} else if (inputFile.endsWith(QLatin1String(".js"))) {
if (!compileJSFile(inputFile, outputFileName, isel.data(), &error)) {
if (!compileJSFile(inputFile, outputFileName, isel.data(), targetABI, &error)) {
error.augment(QLatin1String("Error compiling qml file: ")).print();
return EXIT_FAILURE;
}

View File

@ -2,8 +2,9 @@ TEMPLATE = subdirs
QT_FOR_CONFIG += qml-private
SUBDIRS += \
qmlmin \
qmlimportscanner \
qmlcachegen
qmlimportscanner
qtConfig(commandlineparser): SUBDIRS += qmlcachegen
!android|android_app {
SUBDIRS += \