Ricardo Mendoza has proposed merging lp:~ricmm/kubuntu-packaging/qtdeclarative-opensource-src_532-implement-jit-cache into lp:~kubuntu-packagers/kubuntu-packaging/qtdeclarative-opensource-src_532.
Commit message: Implement QV4 JIT cache, make it opt-in by default by means of the QV4_ENABLE_JIT_CACHE env var. Requested reviews: Kubuntu Packagers (kubuntu-packagers) For more details, see: https://code.launchpad.net/~ricmm/kubuntu-packaging/qtdeclarative-opensource-src_532-implement-jit-cache/+merge/248381 -- Your team Kubuntu Packagers is requested to review the proposed merge of lp:~ricmm/kubuntu-packaging/qtdeclarative-opensource-src_532-implement-jit-cache into lp:~kubuntu-packagers/kubuntu-packaging/qtdeclarative-opensource-src_532.
=== modified file 'debian/changelog' --- debian/changelog 2014-12-08 10:58:09 +0000 +++ debian/changelog 2015-02-03 13:57:48 +0000 @@ -1,3 +1,12 @@ +qtdeclarative-opensource-src (5.3.2-3ubuntu3) UNRELEASED; urgency=medium + + * debian/patches/QML-Compilation-unit-caching-and-JIT-changes.patch + - Implement QV4 JIT cache to reduce application startup speed by + removing unnecessary compiler/assembler runs. This can be enabled + by exporting QV4_ENABLE_JIT_CACHE=1. + + -- Ricardo Mendoza <[email protected]> Tue, 03 Feb 2015 14:51:20 +0100 + qtdeclarative-opensource-src (5.3.2-3ubuntu2) vivid; urgency=medium * debian/patches/Avoid-race-condition-in-QQmlEngine-on-shutdown.patch === added file 'debian/patches/QML-Compilation-unit-caching-and-JIT-changes.patch' --- debian/patches/QML-Compilation-unit-caching-and-JIT-changes.patch 1970-01-01 00:00:00 +0000 +++ debian/patches/QML-Compilation-unit-caching-and-JIT-changes.patch 2015-02-03 13:57:48 +0000 @@ -0,0 +1,1079 @@ +Index: qtdeclarative-opensource-src-5.3.2/src/3rdparty/masm/assembler/ARMv7Assembler.h +=================================================================== +--- qtdeclarative-opensource-src-5.3.2.orig/src/3rdparty/masm/assembler/ARMv7Assembler.h ++++ qtdeclarative-opensource-src-5.3.2/src/3rdparty/masm/assembler/ARMv7Assembler.h +@@ -445,6 +445,12 @@ public: + ConditionInvalid + } Condition; + ++ // Code inherited from the QMLC project ++ void appendData(char *data, int len) ++ { ++ return m_formatter.appendData(data, len); ++ } ++ + #define JUMP_ENUM_WITH_SIZE(index, value) (((value) << 3) | (index)) + #define JUMP_ENUM_SIZE(jump) ((jump) >> 3) + enum JumpType { JumpFixed = JUMP_ENUM_WITH_SIZE(0, 0), +@@ -2782,6 +2788,7 @@ private: + AssemblerLabel label() const { return m_buffer.label(); } + bool isAligned(int alignment) const { return m_buffer.isAligned(alignment); } + void* data() const { return m_buffer.data(); } ++ void appendData(char *data, int len) { return m_buffer.appendData(data, len); } + + unsigned debugOffset() { return m_buffer.debugOffset(); } + +Index: qtdeclarative-opensource-src-5.3.2/src/3rdparty/masm/assembler/AbstractMacroAssembler.h +=================================================================== +--- qtdeclarative-opensource-src-5.3.2.orig/src/3rdparty/masm/assembler/AbstractMacroAssembler.h ++++ qtdeclarative-opensource-src-5.3.2/src/3rdparty/masm/assembler/AbstractMacroAssembler.h +@@ -486,6 +486,11 @@ public: + return Call(jump.m_label, Linkable); + } + ++ unsigned int getFlags(void) ++ { ++ return m_flags; ++ } ++ + AssemblerLabel m_label; + private: + Flags m_flags; +@@ -746,6 +751,12 @@ public: + { + AssemblerType::cacheFlush(code, size); + } ++ ++ void appendData(char *data, int len) ++ { ++ return m_assembler.appendData(data, len); ++ } ++ + protected: + AbstractMacroAssembler() + : m_randomSource(cryptographicallyRandomNumber()) +Index: qtdeclarative-opensource-src-5.3.2/src/3rdparty/masm/assembler/AssemblerBuffer.h +=================================================================== +--- qtdeclarative-opensource-src-5.3.2.orig/src/3rdparty/masm/assembler/AssemblerBuffer.h ++++ qtdeclarative-opensource-src-5.3.2/src/3rdparty/masm/assembler/AssemblerBuffer.h +@@ -86,6 +86,14 @@ namespace JSC { + grow(); + } + ++ void appendData(char *data, int len) ++ { ++ if (!isAvailable(len)) ++ grow(len); ++ memcpy(m_buffer + m_index, data, len); ++ m_index += len; ++ } ++ + bool isAligned(int alignment) const + { + return !(m_index & (alignment - 1)); +Index: qtdeclarative-opensource-src-5.3.2/src/3rdparty/masm/assembler/LinkBuffer.h +=================================================================== +--- qtdeclarative-opensource-src-5.3.2.orig/src/3rdparty/masm/assembler/LinkBuffer.h ++++ qtdeclarative-opensource-src-5.3.2/src/3rdparty/masm/assembler/LinkBuffer.h +@@ -109,11 +109,13 @@ public: + + // These methods are used to link or set values at code generation time. + +- void link(Call call, FunctionPtr function) ++ unsigned int link(Call call, FunctionPtr function) + { + ASSERT(call.isFlagSet(Call::Linkable)); + call.m_label = applyOffset(call.m_label); + MacroAssembler::linkCall(code(), call, function); ++ ++ return call.m_label.m_offset; + } + + void link(Jump jump, CodeLocationLabel label) +Index: qtdeclarative-opensource-src-5.3.2/src/3rdparty/masm/assembler/X86Assembler.h +=================================================================== +--- qtdeclarative-opensource-src-5.3.2.orig/src/3rdparty/masm/assembler/X86Assembler.h ++++ qtdeclarative-opensource-src-5.3.2/src/3rdparty/masm/assembler/X86Assembler.h +@@ -101,6 +101,11 @@ public: + ConditionNC = ConditionAE, + } Condition; + ++ void appendData(char *data, int len) ++ { ++ return m_formatter.appendData(data, len); ++ } ++ + private: + typedef enum { + OP_ADD_EvGv = 0x01, +@@ -2380,6 +2385,7 @@ private: + AssemblerLabel label() const { return m_buffer.label(); } + bool isAligned(int alignment) const { return m_buffer.isAligned(alignment); } + void* data() const { return m_buffer.data(); } ++ void appendData(char *data, int len) { return m_buffer.appendData(data, len); } + + PassRefPtr<ExecutableMemoryHandle> executableCopy(JSGlobalData& globalData, void* ownerUID, JITCompilationEffort effort) + { +Index: qtdeclarative-opensource-src-5.3.2/src/qml/compiler/compiler.pri +=================================================================== +--- qtdeclarative-opensource-src-5.3.2.orig/src/qml/compiler/compiler.pri ++++ qtdeclarative-opensource-src-5.3.2/src/qml/compiler/compiler.pri +@@ -28,10 +28,10 @@ HEADERS += \ + $$PWD/qv4isel_moth_p.h \ + $$PWD/qv4instr_moth_p.h + +- + SOURCES += \ + $$PWD/qqmltypecompiler.cpp \ + $$PWD/qv4instr_moth.cpp \ + $$PWD/qv4isel_moth.cpp + ++DEFINES += V4_UNIT_CACHE + } +Index: qtdeclarative-opensource-src-5.3.2/src/qml/compiler/qqmlirbuilder.cpp +=================================================================== +--- qtdeclarative-opensource-src-5.3.2.orig/src/qml/compiler/qqmlirbuilder.cpp ++++ qtdeclarative-opensource-src-5.3.2/src/qml/compiler/qqmlirbuilder.cpp +@@ -1512,7 +1512,12 @@ bool IRBuilder::isStatementNodeScript(QQ + QV4::CompiledData::QmlUnit *QmlUnitGenerator::generate(Document &output) + { + QV4::CompiledData::CompilationUnit *compilationUnit = output.javaScriptCompilationUnit; +- QV4::CompiledData::Unit *jsUnit = compilationUnit->createUnitData(&output); ++ QV4::CompiledData::Unit *jsUnit; ++ if (!compilationUnit->data) ++ jsUnit = compilationUnit->createUnitData(&output); ++ else ++ jsUnit = compilationUnit->data; ++ + const uint unitSize = jsUnit->unitSize; + + const int importSize = sizeof(QV4::CompiledData::Import) * output.imports.count(); +Index: qtdeclarative-opensource-src-5.3.2/src/qml/compiler/qqmltypecompiler.cpp +=================================================================== +--- qtdeclarative-opensource-src-5.3.2.orig/src/qml/compiler/qqmltypecompiler.cpp ++++ qtdeclarative-opensource-src-5.3.2/src/qml/compiler/qqmltypecompiler.cpp +@@ -226,6 +226,7 @@ bool QQmlTypeCompiler::compile() + QV4::ExecutionEngine *v4 = engine->v4engine(); + QScopedPointer<QV4::EvalInstructionSelection> isel(v4->iselFactory->create(engine, v4->executableAllocator, &document->jsModule, &document->jsGenerator)); + isel->setUseFastLookups(false); ++ isel->setEngine(engine); + document->javaScriptCompilationUnit = isel->compile(/*generated unit data*/false); + } + +@@ -435,6 +436,7 @@ QQmlPropertyCacheCreator::QQmlPropertyCa + , qmlObjects(*typeCompiler->qmlObjects()) + , imports(typeCompiler->imports()) + , resolvedTypes(typeCompiler->resolvedTypes()) ++ , m_url(typeCompiler->url()) + { + } + +Index: qtdeclarative-opensource-src-5.3.2/src/qml/compiler/qqmltypecompiler_p.h +=================================================================== +--- qtdeclarative-opensource-src-5.3.2.orig/src/qml/compiler/qqmltypecompiler_p.h ++++ qtdeclarative-opensource-src-5.3.2/src/qml/compiler/qqmltypecompiler_p.h +@@ -149,6 +149,7 @@ protected: + QHash<int, QQmlCompiledData::TypeReference*> *resolvedTypes; + QVector<QByteArray> vmeMetaObjects; + QVector<QQmlPropertyCache*> propertyCaches; ++ QUrl m_url; + }; + + // "Converts" signal expressions to full-fleged function declarations with +Index: qtdeclarative-opensource-src-5.3.2/src/qml/compiler/qv4compileddata_p.h +=================================================================== +--- qtdeclarative-opensource-src-5.3.2.orig/src/qml/compiler/qv4compileddata_p.h ++++ qtdeclarative-opensource-src-5.3.2/src/qml/compiler/qv4compileddata_p.h +@@ -607,6 +607,9 @@ struct Q_QML_PRIVATE_EXPORT CompilationU + QV4::InternalClass **runtimeClasses; + QVector<QV4::Function *> runtimeFunctions; + ++ QVector<int> lookupTable; ++ bool isRestored; ++ + QV4::Function *linkToEngine(QV4::ExecutionEngine *engine); + void unlink(); + +Index: qtdeclarative-opensource-src-5.3.2/src/qml/compiler/qv4isel_moth_p.h +=================================================================== +--- qtdeclarative-opensource-src-5.3.2.orig/src/qml/compiler/qv4isel_moth_p.h ++++ qtdeclarative-opensource-src-5.3.2/src/qml/compiler/qv4isel_moth_p.h +@@ -72,6 +72,7 @@ public: + ~InstructionSelection(); + + virtual void run(int functionIndex); ++ virtual QV4::JIT::InstructionSelection* impl() { return NULL; };; + + protected: + virtual QV4::CompiledData::CompilationUnit *backendCompileStep(); +Index: qtdeclarative-opensource-src-5.3.2/src/qml/compiler/qv4isel_p.cpp +=================================================================== +--- qtdeclarative-opensource-src-5.3.2.orig/src/qml/compiler/qv4isel_p.cpp ++++ qtdeclarative-opensource-src-5.3.2/src/qml/compiler/qv4isel_p.cpp +@@ -1,8 +1,14 @@ +-/**************************************************************************** ++/*************************************************************************** + ** + ** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). + ** Contact: http://www.qt-project.org/legal + ** ++** Copyright (C) 2014 Nomovok Ltd. All rights reserved. ++** Contact: [email protected] ++** ++** Copyright (C) 2014 Canonical Limited and/or its subsidiary(-ies). ++** Contact: [email protected] ++** + ** This file is part of the QtQml module of the Qt Toolkit. + ** + ** $QT_BEGIN_LICENSE:LGPL$ +@@ -49,6 +55,50 @@ + + #include <QString> + ++#ifdef V4_UNIT_CACHE ++#include <private/qqmltypenamecache_p.h> ++#include <private/qqmlcompiler_p.h> ++#include <private/qqmltypeloader_p.h> ++#include <private/qv4compileddata_p.h> ++#include <private/qv4assembler_p.h> ++#include "../jit/qv4cachedlinkdata_p.h" ++#include "../jit/qv4assembler_p.h" ++#include <sys/stat.h> ++#include <QCryptographicHash> ++#include <QStandardPaths> ++#include <QDir> ++#include <QFile> ++#include <QDataStream> ++#include <QBuffer> ++#endif ++ ++bool writeData(QDataStream& stream, const char* data, int len) ++{ ++ if (stream.writeRawData(data, len) != len) ++ return false; ++ else ++ return true; ++} ++ ++bool writeDataWithLen(QDataStream& stream, const char* data, int len) ++{ ++ quint32 l = len; ++ if (!writeData(stream, (const char *)&l, sizeof(quint32))) ++ return false; ++ if (!writeData(stream, data, len)) ++ return false; ++ return true; ++} ++ ++bool readData(char *data, int len, QDataStream &stream) ++{ ++ if (stream.readRawData(data, len) != len) { ++ return false; ++ } else { ++ return true; ++ } ++} ++ + namespace { + Q_GLOBAL_STATIC_WITH_ARGS(QTextStream, qout, (stderr, QIODevice::WriteOnly)); + #define qout *qout() +@@ -57,6 +107,14 @@ Q_GLOBAL_STATIC_WITH_ARGS(QTextStream, q + using namespace QV4; + using namespace QV4::IR; + ++static bool do_cache = false; ++ ++enum CacheState { ++ UNTESTED = 0, ++ VALID = 1, ++ INVALID = 2 ++}; ++ + EvalInstructionSelection::EvalInstructionSelection(QV4::ExecutableAllocator *execAllocator, Module *module, QV4::Compiler::JSUnitGenerator *jsGenerator) + : useFastLookups(true) + , executableAllocator(execAllocator) +@@ -71,6 +129,9 @@ EvalInstructionSelection::EvalInstructio + Q_ASSERT(execAllocator); + #endif + Q_ASSERT(module); ++ ++ // Enable JIT cache only when explicitly requested and only cache files-on-disk (no qrc or inlines) ++ do_cache = !qgetenv("QV4_ENABLE_JIT_CACHE").isEmpty() && irModule->fileName.startsWith(QStringLiteral("file://")); + } + + EvalInstructionSelection::~EvalInstructionSelection() +@@ -79,17 +140,306 @@ EvalInstructionSelection::~EvalInstructi + EvalISelFactory::~EvalISelFactory() + {} + +-QV4::CompiledData::CompilationUnit *EvalInstructionSelection::compile(bool generateUnitData) ++QV4::CompiledData::CompilationUnit *EvalInstructionSelection::runAll(bool generateUnitData) + { +- for (int i = 0; i < irModule->functions.size(); ++i) +- run(i); ++ QV4::CompiledData::CompilationUnit *unit; ++ ++ for (int i = 0; i < irModule->functions.size(); ++i) { ++ run(i); // Performs the actual compilation ++ } ++ ++ unit = backendCompileStep(); ++ ++#ifdef V4_UNIT_CACHE ++ unit->isRestored = false; ++#endif + +- QV4::CompiledData::CompilationUnit *unit = backendCompileStep(); + if (generateUnitData) + unit->data = jsGenerator->generateUnit(); ++ + return unit; + } + ++QV4::CompiledData::CompilationUnit *EvalInstructionSelection::compile(bool generateUnitData) ++{ ++#ifndef V4_UNIT_CACHE ++ return runAll(generateUnitData); ++#else ++ // Check if running JIT mode and if cache is enabled ++ if (!do_cache || !this->impl()) ++ return runAll(generateUnitData); ++ ++ QV4::CompiledData::CompilationUnit *unit; ++ ++ bool loaded = false; ++ bool do_save = true; ++ ++ QByteArray path(qgetenv("HOME") + QByteArray("/.cache/QML/Apps/") + (qgetenv("APP_ID").isEmpty() ? QCoreApplication::applicationName().toLatin1() : qgetenv("APP_ID"))); ++ ++ if (m_engine && m_engine->qmlCacheValid == CacheState::UNTESTED) { ++ bool valid = true; ++ QDir cacheDir; ++ cacheDir.setPath(QLatin1String(path)); ++ QStringList files = cacheDir.entryList(); ++ for (int i = 0; i < files.size(); i++) { ++ if (valid == false) ++ break; ++ ++ QFile cacheFile(path + QDir::separator() + files.at(i)); ++ if (cacheFile.open(QIODevice::ReadOnly)) { ++ QDataStream stream(&cacheFile); ++ quint32 strLen = 0; ++ readData((char *)&strLen, sizeof(quint32), stream); ++ if (strLen == 0) { ++ cacheFile.close(); ++ continue; ++ } ++ ++ char *tmpStr = (char *) malloc(strLen); ++ readData((char *)tmpStr, strLen, stream); ++ quint32 mtime = 0; ++ readData((char *)&mtime, sizeof(quint32), stream); ++ ++ struct stat sb; ++ stat(tmpStr, &sb); ++ if (QFile::exists(QLatin1String(tmpStr))) { ++ QByteArray time(ctime(&sb.st_mtime)); ++ if (mtime != (quint32) sb.st_mtime) { ++ if (m_engine) m_engine->qmlCacheValid = CacheState::INVALID; ++ valid = false; ++ } ++ } else { ++ // Compilation unit of unresolvable type (inline), remove ++ cacheFile.remove(); ++ } ++ ++ free(tmpStr); ++ cacheFile.close(); ++ } ++ } ++ if (valid) { ++ m_engine->qmlCacheValid = CacheState::VALID; ++ } else { ++ for (int i = 0; i < files.size(); i++) ++ cacheDir.remove(files.at(i)); ++ } ++ } ++ ++ // Search for cache blob by mtime/app_id/file hash ++ struct stat sb; ++ stat(irModule->fileName.toLatin1().remove(0, 7).constData(), &sb); ++ QByteArray time(ctime(&sb.st_mtime)); ++ QByteArray urlHash(QCryptographicHash::hash((irModule->fileName.toLatin1() + qgetenv("APP_ID") + time), QCryptographicHash::Md5).toHex()); ++ QDir dir; ++ dir.mkpath(QLatin1String(path)); ++ QFile cacheFile(path + QDir::separator() + urlHash); ++ ++ QByteArray fileData; ++ ++ // TODO: Support inline compilation units ++ if (cacheFile.exists() && cacheFile.open(QIODevice::ReadOnly)) { ++ if (!irModule->fileName.isEmpty() && !irModule->fileName.contains(QStringLiteral("inline")) && m_engine) { ++ loaded = true; ++ fileData.append(cacheFile.readAll()); ++ } else { ++ loaded = false; ++ cacheFile.close(); ++ return runAll(generateUnitData); ++ } ++ } ++ ++ // Check file integrity ++ QString fileHash(QLatin1String(QCryptographicHash::hash(fileData.left(fileData.size()-32), QCryptographicHash::Md5).toHex())); ++ if (!fileHash.contains(QLatin1String(fileData.right(32)))) { ++ cacheFile.close(); ++ cacheFile.remove(); ++ loaded = false; ++ } ++ ++ // This code has been inspired and influenced by Nomovok's QMLC compiler available at ++ // https://github.com/qmlc/qmlc. All original Copyrights are maintained for the ++ // basic code snippets. ++ ++ if (loaded) { ++ // Retrieve unit skeleton from isel implementation ++ unit = backendCompileStep(); ++ QV4::JIT::CompilationUnit *tmpUnit = (QV4::JIT::CompilationUnit *) unit; ++ tmpUnit->codeRefs.resize(irModule->functions.size()); ++ ++ QDataStream stream(fileData); ++ ++ quint32 strLen = 0; ++ readData((char *)&strLen, sizeof(quint32), stream); ++ char *tmpStr = (char *) malloc(strLen); ++ readData((char *)tmpStr, strLen, stream); ++ quint32 mtime = 0; ++ readData((char *)&mtime, sizeof(quint32), stream); ++ ++ unit->lookupTable.reserve(tmpUnit->codeRefs.size()); ++ quint32 len; ++ for (int i = 0; i < tmpUnit->codeRefs.size(); i++) { ++ quint32 strLen; ++ readData((char *)&strLen, sizeof(quint32), stream); ++ ++ char *fStr = (char *) malloc(strLen); ++ readData(fStr, strLen, stream); ++ ++ QString hashString(QLatin1String(irModule->functions.at(i)->name->toLatin1().constData())); ++ hashString.append(QString::number(irModule->functions.at(i)->line)); ++ hashString.append(QString::number(irModule->functions.at(i)->column)); ++ ++ if (!hashString.contains(QLatin1String(fStr))) ++ return runAll(generateUnitData); ++ ++ unit->lookupTable.append(i); ++ ++ len = 0; ++ readData((char *)&len, sizeof(quint32), stream); ++ ++ // Temporary unlinked code buffer ++ executableAllocator->allocate(len); ++ char *data = (char *) malloc(len); ++ readData(data, len, stream); ++ ++ quint32 linkCallCount = 0; ++ readData((char *)&linkCallCount, sizeof(quint32), stream); ++ ++ QVector<QV4::JIT::CachedLinkData> linkCalls; ++ linkCalls.resize(linkCallCount); ++ readData((char *)linkCalls.data(), linkCallCount * sizeof(QV4::JIT::CachedLinkData), stream); ++ ++ quint32 constVectorLen = 0; ++ readData((char *)&constVectorLen, sizeof(quint32), stream); ++ ++ QVector<QV4::Primitive > constantVector; ++ if (constVectorLen > 0) { ++ constantVector.resize(constVectorLen); ++ readData((char *)constantVector.data(), constVectorLen * sizeof(QV4::Primitive), stream); ++ } ++ ++ // Pre-allocate link buffer to append code ++ QV4::ExecutableAllocator* executableAllocator = m_engine->v4engine()->executableAllocator; ++ ++ QV4::IR::Function nullFunction(0, 0, QLatin1String("")); ++ ++ QV4::JIT::Assembler* as = new QV4::JIT::Assembler(this->impl(), &nullFunction, executableAllocator, 6); ++ ++ QList<QV4::JIT::Assembler::CallToLink>& callsToLink = as->callsToLink(); ++ for (int i = 0; i < linkCalls.size(); i++) { ++ QV4::JIT::CachedLinkData& call = linkCalls[i]; ++ void *functionPtr = CACHED_LINK_TABLE[call.index].addr; ++ QV4::JIT::Assembler::CallToLink c; ++ JSC::AssemblerLabel label(call.offset); ++ c.call = QV4::JIT::Assembler::Call(label, QV4::JIT::Assembler::Call::Linkable); ++ c.externalFunction = JSC::FunctionPtr((quint32(*)(void))functionPtr); ++ c.functionName = CACHED_LINK_TABLE[call.index].name; ++ callsToLink.append(c); ++ } ++ ++ QV4::JIT::Assembler::ConstantTable& constTable = as->constantTable(); ++ foreach (const QV4::Primitive &p, constantVector) ++ constTable.add(p); ++ ++ as->appendData(data, len); ++ ++ int dummySize = -1; // Pass known value to trigger use of code buffer ++ tmpUnit->codeRefs[i] = as->link(&dummySize); ++ Q_ASSERT(dummySize == (int)codeRefLen); ++ ++ delete as; ++ } ++ ++ quint32 size = 0; ++ readData((char *)&size, sizeof(quint32), stream); ++ ++ void *dataPtr = malloc(size); ++ QV4::CompiledData::Unit *finalUnit = reinterpret_cast<QV4::CompiledData::Unit*>(dataPtr); ++ if (size > 0) ++ readData((char *)dataPtr, size, stream); ++ ++ unit->data = nullptr; ++ if (irModule->functions.size() > 0) ++ unit->data = finalUnit; ++ ++ unit->isRestored = true; ++ } else { ++ // Not loading from cache, run all instructions ++ unit = runAll(false); ++ } ++ ++ if ((unit->data == nullptr) && (do_save || generateUnitData)) ++ unit->data = jsGenerator->generateUnit(); ++ ++ // Save compilation unit ++ QV4::JIT::CompilationUnit *jitUnit = (QV4::JIT::CompilationUnit *) unit; ++ if (!loaded) { ++ if (cacheFile.open(QIODevice::WriteOnly)) { ++ // TODO: Support inline compilation units ++ if (!irModule->fileName.isEmpty() && !irModule->fileName.contains(QLatin1String("inline")) && m_engine) { ++ QBuffer fillBuff; ++ fillBuff.open(QIODevice::WriteOnly); ++ QDataStream stream(&fillBuff); ++ ++ quint32 fileNameSize = irModule->fileName.size(); ++ writeData(stream, (const char *)&fileNameSize, sizeof(quint32)); ++ writeData(stream, (const char *)irModule->fileName.toLatin1().remove(0, 7).constData(), irModule->fileName.size()); ++ ++ struct stat sb; ++ stat(irModule->fileName.toLatin1().remove(0, 7).constData(), &sb); ++ writeData(stream, (const char *)&sb.st_mtime, sizeof(quint32)); ++ ++ for (int i = 0; i < jitUnit->codeRefs.size(); i++) { ++ const JSC::MacroAssemblerCodeRef &codeRef = jitUnit->codeRefs[i]; ++ const QVector<QV4::Primitive> &constantValue = jitUnit->constantValues[i]; ++ quint32 len = codeRef.size(); ++ ++ QString hashString(QLatin1String(irModule->functions.at(i)->name->toLatin1())); ++ hashString.append(QString::number(irModule->functions.at(i)->line)); ++ hashString.append(QString::number(irModule->functions.at(i)->column)); ++ ++ quint32 strLen = hashString.size(); ++ strLen += 1; // /0 char ++ writeData(stream, (const char *)&strLen, sizeof(quint32)); ++ writeData(stream, (const char *)hashString.toLatin1().constData(), strLen); ++ writeData(stream, (const char *)&len, sizeof(quint32)); ++ writeData(stream, (const char *)(((unsigned long)codeRef.code().executableAddress())&~1), len); ++ ++ const QVector<QV4::JIT::CachedLinkData> &linkCalls = jitUnit->linkData[i]; ++ quint32 linkCallCount = linkCalls.size(); ++ ++ writeData(stream, (const char *)&linkCallCount, sizeof(quint32)); ++ if (linkCallCount > 0) ++ writeData(stream, (const char *)linkCalls.data(), linkCalls.size() * sizeof (QV4::JIT::CachedLinkData)); ++ ++ quint32 constTableCount = constantValue.size(); ++ writeData(stream, (const char *)&constTableCount, sizeof(quint32)); ++ ++ if (constTableCount > 0) ++ writeData(stream, (const char*)constantValue.data(), sizeof(QV4::Primitive) * constantValue.size()); ++ } ++ ++ QV4::CompiledData::Unit *retUnit = unit->data; ++ quint32 size = retUnit->unitSize; ++ ++ if (size > 0) { ++ writeData(stream, (const char*)&size, sizeof(quint32)); ++ writeData(stream, (const char*)retUnit, size); ++ } ++ ++ // Write MD5 hash of stored data for consistency check ++ QByteArray fileHash(QCryptographicHash::hash(fillBuff.data(), QCryptographicHash::Md5).toHex()); ++ fillBuff.write(fileHash); ++ cacheFile.write(fillBuff.data()); ++ } ++ cacheFile.close(); ++ } else { ++ cacheFile.close(); ++ } ++ } ++ return unit; ++#endif ++} ++ + void IRDecoder::visitMove(IR::Move *s) + { + if (IR::Name *n = s->target->asName()) { +Index: qtdeclarative-opensource-src-5.3.2/src/qml/compiler/qv4isel_p.h +=================================================================== +--- qtdeclarative-opensource-src-5.3.2.orig/src/qml/compiler/qv4isel_p.h ++++ qtdeclarative-opensource-src-5.3.2/src/qml/compiler/qv4isel_p.h +@@ -56,6 +56,10 @@ class QQmlEnginePrivate; + + namespace QV4 { + ++namespace JIT { ++ class InstructionSelection; ++} ++ + class ExecutableAllocator; + struct Function; + +@@ -65,6 +69,7 @@ public: + EvalInstructionSelection(QV4::ExecutableAllocator *execAllocator, IR::Module *module, QV4::Compiler::JSUnitGenerator *jsGenerator); + virtual ~EvalInstructionSelection() = 0; + ++ QV4::CompiledData::CompilationUnit *runAll(bool generateUnitData); + QV4::CompiledData::CompilationUnit *compile(bool generateUnitData = true); + + void setUseFastLookups(bool b) { useFastLookups = b; } +@@ -78,9 +83,11 @@ public: + int registerRegExp(IR::RegExp *regexp) { return jsGenerator->registerRegExp(regexp); } + int registerJSClass(int count, IR::ExprList *args) { return jsGenerator->registerJSClass(count, args); } + QV4::Compiler::JSUnitGenerator *jsUnitGenerator() const { return jsGenerator; } ++ void setEngine(QQmlEnginePrivate *qmlEngine) { m_engine = qmlEngine; } + + protected: + virtual void run(int functionIndex) = 0; ++ virtual QV4::JIT::InstructionSelection* impl() = 0; + virtual QV4::CompiledData::CompilationUnit *backendCompileStep() = 0; + + bool useFastLookups; +@@ -88,6 +95,7 @@ protected: + QV4::Compiler::JSUnitGenerator *jsGenerator; + QScopedPointer<QV4::Compiler::JSUnitGenerator> ownJSGenerator; + IR::Module *irModule; ++ QQmlEnginePrivate *m_engine; + }; + + class Q_QML_PRIVATE_EXPORT EvalISelFactory +Index: qtdeclarative-opensource-src-5.3.2/src/qml/jit/qv4assembler.cpp +=================================================================== +--- qtdeclarative-opensource-src-5.3.2.orig/src/qml/jit/qv4assembler.cpp ++++ qtdeclarative-opensource-src-5.3.2/src/qml/jit/qv4assembler.cpp +@@ -77,7 +77,10 @@ void CompilationUnit::linkBackendToEngin + + QV4::Function *runtimeFunction = new QV4::Function(engine, this, compiledFunction, + (ReturnedValue (*)(QV4::ExecutionContext *, const uchar *)) codeRefs[i].code().executableAddress()); +- runtimeFunctions[i] = runtimeFunction; ++ if (isRestored) ++ runtimeFunctions[lookupTable.at(i)] = runtimeFunction; ++ else ++ runtimeFunctions[i] = runtimeFunction; + } + } + +Index: qtdeclarative-opensource-src-5.3.2/src/qml/jit/qv4assembler_p.h +=================================================================== +--- qtdeclarative-opensource-src-5.3.2.orig/src/qml/jit/qv4assembler_p.h ++++ qtdeclarative-opensource-src-5.3.2/src/qml/jit/qv4assembler_p.h +@@ -70,6 +70,16 @@ namespace JIT { + + class InstructionSelection; + ++struct CachedLinkData { ++ quint32 index; // Link table index ++ quint32 offset; // Offset inside the codeRef code ++}; ++ ++struct LinkableCode { ++ int len; ++ void* code; ++}; ++ + struct CompilationUnit : public QV4::CompiledData::CompilationUnit + { + virtual ~CompilationUnit(); +@@ -82,6 +92,8 @@ struct CompilationUnit : public QV4::Com + + QVector<JSC::MacroAssemblerCodeRef> codeRefs; + QList<QVector<QV4::Primitive> > constantValues; ++ QList<QVector<CachedLinkData>> linkData; ++ QList<LinkableCode> linkableCode; + }; + + struct RelativeCall { +@@ -1151,7 +1163,12 @@ public: + move(TrustedImm64(u.i), ReturnValueRegister); + move64ToDouble(ReturnValueRegister, target); + #else +- JSC::MacroAssembler::loadDouble(constantTable().loadValueAddress(c, ScratchRegister), target); ++ QV4::Primitive vv = convertToValue(c); ++ FPRegisterID scratchFp; ++ scratchFp = target; ++ move(TrustedImm32(vv.int_32), ReturnValueRegister); ++ move(TrustedImm32(vv.tag), ScratchRegister); ++ moveIntsToDouble(ReturnValueRegister, ScratchRegister, target, scratchFp); + #endif + return target; + } +@@ -1241,6 +1258,12 @@ public: + Label exceptionReturnLabel; + IR::BasicBlock * catchBlock; + QVector<Jump> exceptionPropagationJumps; ++ ++ LinkableCode tmpBuffer; ++ ++ LinkableCode& codeToLink() { return tmpBuffer; } ++ QList<CallToLink>& callsToLink() { return _callsToLink; } ++ + private: + const StackLayout _stackLayout; + ConstantTable _constTable; +Index: qtdeclarative-opensource-src-5.3.2/src/qml/jit/qv4cachedlinkdata_p.h +=================================================================== +--- /dev/null ++++ qtdeclarative-opensource-src-5.3.2/src/qml/jit/qv4cachedlinkdata_p.h +@@ -0,0 +1,188 @@ ++/*************************************************************************** ++** ++** Copyright (C) 2014 Nomovok Ltd. All rights reserved. ++** Contact: [email protected] ++** ++** Copyright (C) 2014 Canonical Limited and/or its subsidiary(-ies). ++** Contact: [email protected] ++** ++** 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 as published by the Free Software ++** Foundation and appearing in the file LICENSE.LGPL included in the ++** packaging of this file. Please review the following information to ++** ensure the GNU Lesser General Public License version 2.1 requirements ++** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. ++** ++** In addition, as a special exception, Digia gives you certain additional ++** rights. These rights are described in the Digia Qt LGPL Exception ++** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. ++** ++** GNU General Public License Usage ++** Alternatively, this file may be used under the terms of the GNU ++** General Public License version 3.0 as published by the Free Software ++** Foundation and appearing in the file LICENSE.GPL included in the ++** packaging of this file. Please review the following information to ++** ensure the GNU General Public License version 3.0 requirements will be ++** met: http://www.gnu.org/copyleft/gpl.html. ++** ++****************************************************************************/ ++ ++#ifndef QV4CACHEDLINKDATA_P_H ++#define QV4CACHEDLINKDATA_P_H ++ ++#include <qv4jsir_p.h> ++#include <qv4isel_masm_p.h> ++#include <qv4runtime_p.h> ++ ++QT_BEGIN_NAMESPACE ++ ++struct CachedLinkEntry { ++ const char *name; ++ void *addr; ++}; ++ ++#define CACHED_LINK_TABLE_ADD_NS(x) QV4::Runtime::x ++#define CACHED_LINK_TABLE_STR(x) "Runtime::" #x ++#define CACHED_LINK_TABLE_ENTRY_RUNTIME(x) { (const char *)CACHED_LINK_TABLE_STR(x), (void *)CACHED_LINK_TABLE_ADD_NS(x) } ++ ++// table to link objects ++// this table can be used to resolve functions, it is id -> object mapping to maximize performance in linking phase ++// when adding new calls, add to end of the list to maintain compatibility ++const CachedLinkEntry CACHED_LINK_TABLE[] = { ++ // call ++ CACHED_LINK_TABLE_ENTRY_RUNTIME(callGlobalLookup), ++ CACHED_LINK_TABLE_ENTRY_RUNTIME(callActivationProperty), ++ CACHED_LINK_TABLE_ENTRY_RUNTIME(callProperty), ++ CACHED_LINK_TABLE_ENTRY_RUNTIME(callPropertyLookup), ++ CACHED_LINK_TABLE_ENTRY_RUNTIME(callElement), ++ CACHED_LINK_TABLE_ENTRY_RUNTIME(callValue), ++ ++ // construct ++ CACHED_LINK_TABLE_ENTRY_RUNTIME(constructGlobalLookup), ++ CACHED_LINK_TABLE_ENTRY_RUNTIME(constructActivationProperty), ++ CACHED_LINK_TABLE_ENTRY_RUNTIME(constructProperty), ++ CACHED_LINK_TABLE_ENTRY_RUNTIME(constructPropertyLookup), ++ CACHED_LINK_TABLE_ENTRY_RUNTIME(constructValue), ++ ++ // set & get ++ CACHED_LINK_TABLE_ENTRY_RUNTIME(setActivationProperty), ++ CACHED_LINK_TABLE_ENTRY_RUNTIME(setProperty), ++ CACHED_LINK_TABLE_ENTRY_RUNTIME(setElement), ++ CACHED_LINK_TABLE_ENTRY_RUNTIME(getProperty), ++ CACHED_LINK_TABLE_ENTRY_RUNTIME(getActivationProperty), ++ CACHED_LINK_TABLE_ENTRY_RUNTIME(getElement), ++ ++ // typeof ++ CACHED_LINK_TABLE_ENTRY_RUNTIME(typeofValue), ++ CACHED_LINK_TABLE_ENTRY_RUNTIME(typeofName), ++ CACHED_LINK_TABLE_ENTRY_RUNTIME(typeofMember), ++ CACHED_LINK_TABLE_ENTRY_RUNTIME(typeofElement), ++ ++ // delete ++ CACHED_LINK_TABLE_ENTRY_RUNTIME(deleteElement), ++ CACHED_LINK_TABLE_ENTRY_RUNTIME(deleteMember), ++ CACHED_LINK_TABLE_ENTRY_RUNTIME(deleteName), ++ ++ // exceptions & scopes ++ CACHED_LINK_TABLE_ENTRY_RUNTIME(throwException), ++ CACHED_LINK_TABLE_ENTRY_RUNTIME(unwindException), ++ CACHED_LINK_TABLE_ENTRY_RUNTIME(pushWithScope), ++ CACHED_LINK_TABLE_ENTRY_RUNTIME(pushCatchScope), ++ CACHED_LINK_TABLE_ENTRY_RUNTIME(popScope), ++ ++ // closures ++ CACHED_LINK_TABLE_ENTRY_RUNTIME(closure), ++ ++ // function header ++ CACHED_LINK_TABLE_ENTRY_RUNTIME(declareVar), ++ CACHED_LINK_TABLE_ENTRY_RUNTIME(setupArgumentsObject), ++ CACHED_LINK_TABLE_ENTRY_RUNTIME(convertThisToObject), ++ ++ // literals ++ CACHED_LINK_TABLE_ENTRY_RUNTIME(arrayLiteral), ++ CACHED_LINK_TABLE_ENTRY_RUNTIME(objectLiteral), ++ CACHED_LINK_TABLE_ENTRY_RUNTIME(regexpLiteral), ++ ++ // foreach ++ CACHED_LINK_TABLE_ENTRY_RUNTIME(foreachIterator), ++ CACHED_LINK_TABLE_ENTRY_RUNTIME(foreachNextPropertyName), ++ ++ // unary operators ++ //typedef ReturnedValue (*UnaryOperation)(const ValueRef); ++ {"NOOP", (void *)qt_noop}, ++ CACHED_LINK_TABLE_ENTRY_RUNTIME(uPlus), ++ CACHED_LINK_TABLE_ENTRY_RUNTIME(uMinus), ++ CACHED_LINK_TABLE_ENTRY_RUNTIME(uNot), ++ CACHED_LINK_TABLE_ENTRY_RUNTIME(complement), ++ CACHED_LINK_TABLE_ENTRY_RUNTIME(increment), ++ CACHED_LINK_TABLE_ENTRY_RUNTIME(decrement), ++ ++ // binary operators ++ //typedef ReturnedValue (*BinaryOperation)(const ValueRef left, const ValueRef right); ++ {"NOOP", (void *)qt_noop}, ++ //typedef ReturnedValue (*BinaryOperationContext)(ExecutionContext *ctx, const ValueRef left, const ValueRef right); ++ {"NOOP", (void *)qt_noop}, ++ ++ CACHED_LINK_TABLE_ENTRY_RUNTIME(instanceof), ++ CACHED_LINK_TABLE_ENTRY_RUNTIME(in), ++ CACHED_LINK_TABLE_ENTRY_RUNTIME(add), ++ CACHED_LINK_TABLE_ENTRY_RUNTIME(addString), ++ CACHED_LINK_TABLE_ENTRY_RUNTIME(bitOr), ++ CACHED_LINK_TABLE_ENTRY_RUNTIME(bitXor), ++ CACHED_LINK_TABLE_ENTRY_RUNTIME(bitAnd), ++ CACHED_LINK_TABLE_ENTRY_RUNTIME(sub), ++ CACHED_LINK_TABLE_ENTRY_RUNTIME(mul), ++ CACHED_LINK_TABLE_ENTRY_RUNTIME(div), ++ CACHED_LINK_TABLE_ENTRY_RUNTIME(mod), ++ CACHED_LINK_TABLE_ENTRY_RUNTIME(shl), ++ CACHED_LINK_TABLE_ENTRY_RUNTIME(shr), ++ CACHED_LINK_TABLE_ENTRY_RUNTIME(ushr), ++ CACHED_LINK_TABLE_ENTRY_RUNTIME(greaterThan), ++ CACHED_LINK_TABLE_ENTRY_RUNTIME(lessThan), ++ CACHED_LINK_TABLE_ENTRY_RUNTIME(greaterEqual), ++ CACHED_LINK_TABLE_ENTRY_RUNTIME(lessEqual), ++ CACHED_LINK_TABLE_ENTRY_RUNTIME(equal), ++ CACHED_LINK_TABLE_ENTRY_RUNTIME(notEqual), ++ CACHED_LINK_TABLE_ENTRY_RUNTIME(strictEqual), ++ CACHED_LINK_TABLE_ENTRY_RUNTIME(strictNotEqual), ++ ++ // comparisons ++ //typedef Bool (*CompareOperation)(const ValueRef left, const ValueRef right);} ++ {"NOOP", (void *)qt_noop}, ++ CACHED_LINK_TABLE_ENTRY_RUNTIME(compareGreaterThan), ++ CACHED_LINK_TABLE_ENTRY_RUNTIME(compareLessThan), ++ CACHED_LINK_TABLE_ENTRY_RUNTIME(compareGreaterEqual), ++ CACHED_LINK_TABLE_ENTRY_RUNTIME(compareLessEqual), ++ CACHED_LINK_TABLE_ENTRY_RUNTIME(compareEqual), ++ CACHED_LINK_TABLE_ENTRY_RUNTIME(compareNotEqual), ++ CACHED_LINK_TABLE_ENTRY_RUNTIME(compareStrictEqual), ++ CACHED_LINK_TABLE_ENTRY_RUNTIME(compareStrictNotEqual), ++ ++ //typedef Bool (*CompareOperationContext)(ExecutionContext *ctx, const ValueRef left, const ValueRef right); ++ {"NOOP", (void *)qt_noop}, ++ CACHED_LINK_TABLE_ENTRY_RUNTIME(compareInstanceof), ++ CACHED_LINK_TABLE_ENTRY_RUNTIME(compareIn), ++ ++ // conversions ++ CACHED_LINK_TABLE_ENTRY_RUNTIME(toBoolean), ++ CACHED_LINK_TABLE_ENTRY_RUNTIME(toDouble), ++ CACHED_LINK_TABLE_ENTRY_RUNTIME(toInt), ++ CACHED_LINK_TABLE_ENTRY_RUNTIME(doubleToInt), ++ CACHED_LINK_TABLE_ENTRY_RUNTIME(toUInt), ++ CACHED_LINK_TABLE_ENTRY_RUNTIME(doubleToUInt), ++ ++ // qml ++ CACHED_LINK_TABLE_ENTRY_RUNTIME(getQmlIdArray), ++ CACHED_LINK_TABLE_ENTRY_RUNTIME(getQmlImportedScripts), ++ CACHED_LINK_TABLE_ENTRY_RUNTIME(getQmlContextObject), ++ CACHED_LINK_TABLE_ENTRY_RUNTIME(getQmlScopeObject), ++ CACHED_LINK_TABLE_ENTRY_RUNTIME(getQmlSingleton), ++ CACHED_LINK_TABLE_ENTRY_RUNTIME(getQmlAttachedProperty), ++ CACHED_LINK_TABLE_ENTRY_RUNTIME(getQmlQObjectProperty), ++ CACHED_LINK_TABLE_ENTRY_RUNTIME(setQmlQObjectProperty) ++}; ++ ++QT_END_NAMESPACE ++ ++#endif +Index: qtdeclarative-opensource-src-5.3.2/src/qml/jit/qv4isel_masm.cpp +=================================================================== +--- qtdeclarative-opensource-src-5.3.2.orig/src/qml/jit/qv4isel_masm.cpp ++++ qtdeclarative-opensource-src-5.3.2/src/qml/jit/qv4isel_masm.cpp +@@ -51,6 +51,7 @@ + #include "qv4assembler_p.h" + #include "qv4unop_p.h" + #include "qv4binop_p.h" ++#include "qv4cachedlinkdata_p.h" + + #include <QtCore/QBuffer> + +@@ -147,9 +148,13 @@ JSC::MacroAssemblerCodeRef Assembler::li + JSC::LinkBuffer linkBuffer(dummy, this, 0); + + QHash<void*, const char*> functions; ++ int i = 0; + foreach (CallToLink ctl, _callsToLink) { +- linkBuffer.link(ctl.call, ctl.externalFunction); ++ unsigned int offset = linkBuffer.link(ctl.call, ctl.externalFunction); ++ ctl.call.m_label.m_offset = offset; + functions[linkBuffer.locationOf(ctl.label).dataLocation()] = ctl.functionName; ++ _callsToLink.replace(i, ctl); ++ i++; + } + + foreach (const DataLabelPatch &p, _dataLabelPatches) +@@ -367,6 +372,25 @@ void InstructionSelection::run(int funct + JSC::MacroAssemblerCodeRef codeRef =_as->link(&dummySize); + compilationUnit->codeRefs[functionIndex] = codeRef; + ++ QVector<CachedLinkData> calls; ++ QList<Assembler::CallToLink>& callsToLink = _as->callsToLink(); ++ for (int i = 0; i < callsToLink.size(); i++) { ++ Assembler::CallToLink& ctl = callsToLink[i]; ++ int index = -1; ++ for (uint i = 0; i < sizeof(CACHED_LINK_TABLE) / sizeof (CachedLinkEntry); i++) { ++ if (CACHED_LINK_TABLE[i].addr == ctl.externalFunction.value()) { ++ index = i; ++ break; ++ } ++ } ++ CachedLinkData link; ++ link.index = index; ++ link.offset = ctl.call.m_label.m_offset; ++ calls.append(link); ++ } ++ compilationUnit->linkData.insert(functionIndex, calls); // link data; ++ compilationUnit->linkableCode.insert(functionIndex, _as->codeToLink()); // code to link ++ + qSwap(_function, function); + delete _as; + _as = oldAssembler; +@@ -1828,5 +1852,4 @@ void InstructionSelection::visitCJumpEqu + _block, trueBlock, falseBlock); + } + +- + #endif // ENABLE(ASSEMBLER) +Index: qtdeclarative-opensource-src-5.3.2/src/qml/jit/qv4isel_masm_p.h +=================================================================== +--- qtdeclarative-opensource-src-5.3.2.orig/src/qml/jit/qv4isel_masm_p.h ++++ qtdeclarative-opensource-src-5.3.2/src/qml/jit/qv4isel_masm_p.h +@@ -73,6 +73,8 @@ public: + virtual void run(int functionIndex); + + const void *addConstantTable(QVector<QV4::Primitive> *values); ++ ++ virtual InstructionSelection* impl() { return this; }; + protected: + virtual QV4::CompiledData::CompilationUnit *backendCompileStep(); + +Index: qtdeclarative-opensource-src-5.3.2/src/qml/jsruntime/qv4functionobject.cpp +=================================================================== +--- qtdeclarative-opensource-src-5.3.2.orig/src/qml/jsruntime/qv4functionobject.cpp ++++ qtdeclarative-opensource-src-5.3.2/src/qml/jsruntime/qv4functionobject.cpp +@@ -234,6 +234,7 @@ ReturnedValue FunctionCtor::construct(Ma + + QV4::Compiler::JSUnitGenerator jsGenerator(&module); + QScopedPointer<EvalInstructionSelection> isel(v4->iselFactory->create(QQmlEnginePrivate::get(v4), v4->executableAllocator, &module, &jsGenerator)); ++ isel->setEngine(QQmlEnginePrivate::get(v4)); + QV4::CompiledData::CompilationUnit *compilationUnit = isel->compile(); + QV4::Function *vmf = compilationUnit->linkToEngine(v4); + +Index: qtdeclarative-opensource-src-5.3.2/src/qml/jsruntime/qv4qobjectwrapper.cpp +=================================================================== +--- qtdeclarative-opensource-src-5.3.2.orig/src/qml/jsruntime/qv4qobjectwrapper.cpp ++++ qtdeclarative-opensource-src-5.3.2/src/qml/jsruntime/qv4qobjectwrapper.cpp +@@ -628,6 +628,7 @@ ReturnedValue QObjectWrapper::getPropert + QQmlPropertyCache *cache = ddata->propertyCache; + Q_ASSERT(cache); + QQmlPropertyData *property = cache->property(propertyIndex); ++ + Q_ASSERT(property); // We resolved this property earlier, so it better exist! + return getProperty(object, ctx, property, captureRequired); + } +Index: qtdeclarative-opensource-src-5.3.2/src/qml/jsruntime/qv4script.cpp +=================================================================== +--- qtdeclarative-opensource-src-5.3.2.orig/src/qml/jsruntime/qv4script.cpp ++++ qtdeclarative-opensource-src-5.3.2/src/qml/jsruntime/qv4script.cpp +@@ -272,6 +272,7 @@ void Script::parse() + QScopedPointer<EvalInstructionSelection> isel(v4->iselFactory->create(QQmlEnginePrivate::get(v4), v4->executableAllocator, &module, &jsGenerator)); + if (inheritContext) + isel->setUseFastLookups(false); ++ isel->setEngine(QQmlEnginePrivate::get(v4)); + QV4::CompiledData::CompilationUnit *compilationUnit = isel->compile(); + vmFunction = compilationUnit->linkToEngine(v4); + ScopedValue holder(valueScope, new (v4->memoryManager) CompilationUnitHolder(v4, compilationUnit)); +@@ -394,6 +395,7 @@ QV4::CompiledData::CompilationUnit *Scri + + QScopedPointer<EvalInstructionSelection> isel(engine->iselFactory->create(QQmlEnginePrivate::get(engine), engine->executableAllocator, module, unitGenerator)); + isel->setUseFastLookups(false); ++ isel->setEngine(QQmlEnginePrivate::get(engine)); + return isel->compile(/*generate unit data*/false); + } + +Index: qtdeclarative-opensource-src-5.3.2/src/qml/qml/qqmlengine.cpp +=================================================================== +--- qtdeclarative-opensource-src-5.3.2.orig/src/qml/qml/qqmlengine.cpp ++++ qtdeclarative-opensource-src-5.3.2/src/qml/qml/qqmlengine.cpp +@@ -561,7 +561,8 @@ QQmlEnginePrivate::QQmlEnginePrivate(QQm + activeObjectCreator(0), + networkAccessManager(0), networkAccessManagerFactory(0), urlInterceptor(0), + scarceResourcesRefCount(0), typeLoader(e), importDatabase(e), uniqueId(1), +- incubatorCount(0), incubationController(0), mutex(QMutex::Recursive) ++ incubatorCount(0), incubationController(0), mutex(QMutex::Recursive), ++ qmlCacheValid(0) + { + useNewCompiler = true; + } +Index: qtdeclarative-opensource-src-5.3.2/src/qml/qml/qqmlengine_p.h +=================================================================== +--- qtdeclarative-opensource-src-5.3.2.orig/src/qml/qml/qqmlengine_p.h ++++ qtdeclarative-opensource-src-5.3.2/src/qml/qml/qqmlengine_p.h +@@ -270,6 +270,8 @@ public: + + mutable QMutex mutex; + ++ int qmlCacheValid; ++ + private: + // Locker locks the QQmlEnginePrivate data structures for read and write, if necessary. + // Currently, locking is only necessary if the threaded loader is running concurrently. If it is +Index: qtdeclarative-opensource-src-5.3.2/src/qml/qml/qqmljavascriptexpression.cpp +=================================================================== +--- qtdeclarative-opensource-src-5.3.2.orig/src/qml/qml/qqmljavascriptexpression.cpp ++++ qtdeclarative-opensource-src-5.3.2/src/qml/qml/qqmljavascriptexpression.cpp +@@ -335,6 +335,7 @@ QV4::ReturnedValue QQmlJavaScriptExpress + + QV4::ScopedObject qmlScopeObject(scope, QV4::QmlContextWrapper::qmlScope(ep->v8engine(), ctxt, qmlScope)); + QV4::Script script(v4, qmlScopeObject, code, filename, line); ++ + QV4::ScopedValue result(scope); + script.parse(); + if (!v4->hasException) === modified file 'debian/patches/series' --- debian/patches/series 2014-12-08 10:58:09 +0000 +++ debian/patches/series 2015-02-03 13:57:48 +0000 @@ -6,3 +6,4 @@ Support-RFC2822Date-date-format-similar-to-V8.patch Avoid-race-condition-in-QQmlEngine-on-shutdown.patch Fix-crashes-when-calling-Array.sort-with-imperfect-s.patch +QML-Compilation-unit-caching-and-JIT-changes.patch
-- kubuntu-devel mailing list [email protected] Modify settings or unsubscribe at: https://lists.ubuntu.com/mailman/listinfo/kubuntu-devel
