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

Reply via email to