Merge lp:~ricmm/kubuntu-packaging/qtdeclarative-opensource-src_532-implement-jit-cache into lp:~kubuntu-packagers/kubuntu-packaging/qtdeclarative-opensource-src_532

Proposed by Ricardo Mendoza
Status: Merged
Merged at revision: 174
Proposed branch: lp:~ricmm/kubuntu-packaging/qtdeclarative-opensource-src_532-implement-jit-cache
Merge into: lp:~kubuntu-packagers/kubuntu-packaging/qtdeclarative-opensource-src_532
Diff against target: 1113 lines (+1093/-0)
3 files modified
debian/changelog (+9/-0)
debian/patches/QML-Compilation-unit-caching-and-JIT-changes.patch (+1083/-0)
debian/patches/series (+1/-0)
To merge this branch: bzr merge lp:~ricmm/kubuntu-packaging/qtdeclarative-opensource-src_532-implement-jit-cache
Reviewer Review Type Date Requested Status
PS Jenkins bot continuous-integration Needs Fixing
Timo Jyrinki Approve
Review via email: mp+248381@code.launchpad.net

Commit message

Implement QV4 JIT cache, make it opt-in by default by means of the QV4_ENABLE_JIT_CACHE env var.

To post a comment you must log in.
Revision history for this message
Timo Jyrinki (timo-jyrinki) wrote :

Published to archives after testing.

Revision history for this message
Timo Jyrinki (timo-jyrinki) :
review: Approve
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'debian/changelog'
2--- debian/changelog 2014-12-08 10:58:09 +0000
3+++ debian/changelog 2015-02-04 10:51:00 +0000
4@@ -1,3 +1,12 @@
5+qtdeclarative-opensource-src (5.3.2-3ubuntu3) UNRELEASED; urgency=medium
6+
7+ * debian/patches/QML-Compilation-unit-caching-and-JIT-changes.patch
8+ - Implement QV4 JIT cache to reduce application startup speed by
9+ removing unnecessary compiler/assembler runs. This can be enabled
10+ by exporting QV4_ENABLE_JIT_CACHE=1.
11+
12+ -- Ricardo Mendoza <ricardo.mendoza@canonical.com> Tue, 03 Feb 2015 14:51:20 +0100
13+
14 qtdeclarative-opensource-src (5.3.2-3ubuntu2) vivid; urgency=medium
15
16 * debian/patches/Avoid-race-condition-in-QQmlEngine-on-shutdown.patch
17
18=== added file 'debian/patches/QML-Compilation-unit-caching-and-JIT-changes.patch'
19--- debian/patches/QML-Compilation-unit-caching-and-JIT-changes.patch 1970-01-01 00:00:00 +0000
20+++ debian/patches/QML-Compilation-unit-caching-and-JIT-changes.patch 2015-02-04 10:51:00 +0000
21@@ -0,0 +1,1083 @@
22+Index: qtdeclarative-opensource-src-5.3.2/src/3rdparty/masm/assembler/ARMv7Assembler.h
23+===================================================================
24+--- qtdeclarative-opensource-src-5.3.2.orig/src/3rdparty/masm/assembler/ARMv7Assembler.h
25++++ qtdeclarative-opensource-src-5.3.2/src/3rdparty/masm/assembler/ARMv7Assembler.h
26+@@ -445,6 +445,12 @@ public:
27+ ConditionInvalid
28+ } Condition;
29+
30++ // Code inherited from the QMLC project
31++ void appendData(char *data, int len)
32++ {
33++ return m_formatter.appendData(data, len);
34++ }
35++
36+ #define JUMP_ENUM_WITH_SIZE(index, value) (((value) << 3) | (index))
37+ #define JUMP_ENUM_SIZE(jump) ((jump) >> 3)
38+ enum JumpType { JumpFixed = JUMP_ENUM_WITH_SIZE(0, 0),
39+@@ -2782,6 +2788,7 @@ private:
40+ AssemblerLabel label() const { return m_buffer.label(); }
41+ bool isAligned(int alignment) const { return m_buffer.isAligned(alignment); }
42+ void* data() const { return m_buffer.data(); }
43++ void appendData(char *data, int len) { return m_buffer.appendData(data, len); }
44+
45+ unsigned debugOffset() { return m_buffer.debugOffset(); }
46+
47+Index: qtdeclarative-opensource-src-5.3.2/src/3rdparty/masm/assembler/AbstractMacroAssembler.h
48+===================================================================
49+--- qtdeclarative-opensource-src-5.3.2.orig/src/3rdparty/masm/assembler/AbstractMacroAssembler.h
50++++ qtdeclarative-opensource-src-5.3.2/src/3rdparty/masm/assembler/AbstractMacroAssembler.h
51+@@ -486,6 +486,11 @@ public:
52+ return Call(jump.m_label, Linkable);
53+ }
54+
55++ unsigned int getFlags(void)
56++ {
57++ return m_flags;
58++ }
59++
60+ AssemblerLabel m_label;
61+ private:
62+ Flags m_flags;
63+@@ -746,6 +751,12 @@ public:
64+ {
65+ AssemblerType::cacheFlush(code, size);
66+ }
67++
68++ void appendData(char *data, int len)
69++ {
70++ return m_assembler.appendData(data, len);
71++ }
72++
73+ protected:
74+ AbstractMacroAssembler()
75+ : m_randomSource(cryptographicallyRandomNumber())
76+Index: qtdeclarative-opensource-src-5.3.2/src/3rdparty/masm/assembler/AssemblerBuffer.h
77+===================================================================
78+--- qtdeclarative-opensource-src-5.3.2.orig/src/3rdparty/masm/assembler/AssemblerBuffer.h
79++++ qtdeclarative-opensource-src-5.3.2/src/3rdparty/masm/assembler/AssemblerBuffer.h
80+@@ -86,6 +86,14 @@ namespace JSC {
81+ grow();
82+ }
83+
84++ void appendData(char *data, int len)
85++ {
86++ if (!isAvailable(len))
87++ grow(len);
88++ memcpy(m_buffer + m_index, data, len);
89++ m_index += len;
90++ }
91++
92+ bool isAligned(int alignment) const
93+ {
94+ return !(m_index & (alignment - 1));
95+Index: qtdeclarative-opensource-src-5.3.2/src/3rdparty/masm/assembler/LinkBuffer.h
96+===================================================================
97+--- qtdeclarative-opensource-src-5.3.2.orig/src/3rdparty/masm/assembler/LinkBuffer.h
98++++ qtdeclarative-opensource-src-5.3.2/src/3rdparty/masm/assembler/LinkBuffer.h
99+@@ -109,11 +109,13 @@ public:
100+
101+ // These methods are used to link or set values at code generation time.
102+
103+- void link(Call call, FunctionPtr function)
104++ unsigned int link(Call call, FunctionPtr function)
105+ {
106+ ASSERT(call.isFlagSet(Call::Linkable));
107+ call.m_label = applyOffset(call.m_label);
108+ MacroAssembler::linkCall(code(), call, function);
109++
110++ return call.m_label.m_offset;
111+ }
112+
113+ void link(Jump jump, CodeLocationLabel label)
114+Index: qtdeclarative-opensource-src-5.3.2/src/3rdparty/masm/assembler/X86Assembler.h
115+===================================================================
116+--- qtdeclarative-opensource-src-5.3.2.orig/src/3rdparty/masm/assembler/X86Assembler.h
117++++ qtdeclarative-opensource-src-5.3.2/src/3rdparty/masm/assembler/X86Assembler.h
118+@@ -101,6 +101,11 @@ public:
119+ ConditionNC = ConditionAE,
120+ } Condition;
121+
122++ void appendData(char *data, int len)
123++ {
124++ return m_formatter.appendData(data, len);
125++ }
126++
127+ private:
128+ typedef enum {
129+ OP_ADD_EvGv = 0x01,
130+@@ -2380,6 +2385,7 @@ private:
131+ AssemblerLabel label() const { return m_buffer.label(); }
132+ bool isAligned(int alignment) const { return m_buffer.isAligned(alignment); }
133+ void* data() const { return m_buffer.data(); }
134++ void appendData(char *data, int len) { return m_buffer.appendData(data, len); }
135+
136+ PassRefPtr<ExecutableMemoryHandle> executableCopy(JSGlobalData& globalData, void* ownerUID, JITCompilationEffort effort)
137+ {
138+Index: qtdeclarative-opensource-src-5.3.2/src/qml/compiler/compiler.pri
139+===================================================================
140+--- qtdeclarative-opensource-src-5.3.2.orig/src/qml/compiler/compiler.pri
141++++ qtdeclarative-opensource-src-5.3.2/src/qml/compiler/compiler.pri
142+@@ -28,10 +28,10 @@ HEADERS += \
143+ $$PWD/qv4isel_moth_p.h \
144+ $$PWD/qv4instr_moth_p.h
145+
146+-
147+ SOURCES += \
148+ $$PWD/qqmltypecompiler.cpp \
149+ $$PWD/qv4instr_moth.cpp \
150+ $$PWD/qv4isel_moth.cpp
151+
152++DEFINES += V4_UNIT_CACHE
153+ }
154+Index: qtdeclarative-opensource-src-5.3.2/src/qml/compiler/qqmlirbuilder.cpp
155+===================================================================
156+--- qtdeclarative-opensource-src-5.3.2.orig/src/qml/compiler/qqmlirbuilder.cpp
157++++ qtdeclarative-opensource-src-5.3.2/src/qml/compiler/qqmlirbuilder.cpp
158+@@ -1512,7 +1512,12 @@ bool IRBuilder::isStatementNodeScript(QQ
159+ QV4::CompiledData::QmlUnit *QmlUnitGenerator::generate(Document &output)
160+ {
161+ QV4::CompiledData::CompilationUnit *compilationUnit = output.javaScriptCompilationUnit;
162+- QV4::CompiledData::Unit *jsUnit = compilationUnit->createUnitData(&output);
163++ QV4::CompiledData::Unit *jsUnit;
164++ if (!compilationUnit->data)
165++ jsUnit = compilationUnit->createUnitData(&output);
166++ else
167++ jsUnit = compilationUnit->data;
168++
169+ const uint unitSize = jsUnit->unitSize;
170+
171+ const int importSize = sizeof(QV4::CompiledData::Import) * output.imports.count();
172+Index: qtdeclarative-opensource-src-5.3.2/src/qml/compiler/qqmltypecompiler.cpp
173+===================================================================
174+--- qtdeclarative-opensource-src-5.3.2.orig/src/qml/compiler/qqmltypecompiler.cpp
175++++ qtdeclarative-opensource-src-5.3.2/src/qml/compiler/qqmltypecompiler.cpp
176+@@ -226,6 +226,7 @@ bool QQmlTypeCompiler::compile()
177+ QV4::ExecutionEngine *v4 = engine->v4engine();
178+ QScopedPointer<QV4::EvalInstructionSelection> isel(v4->iselFactory->create(engine, v4->executableAllocator, &document->jsModule, &document->jsGenerator));
179+ isel->setUseFastLookups(false);
180++ isel->setEngine(engine);
181+ document->javaScriptCompilationUnit = isel->compile(/*generated unit data*/false);
182+ }
183+
184+@@ -435,6 +436,7 @@ QQmlPropertyCacheCreator::QQmlPropertyCa
185+ , qmlObjects(*typeCompiler->qmlObjects())
186+ , imports(typeCompiler->imports())
187+ , resolvedTypes(typeCompiler->resolvedTypes())
188++ , m_url(typeCompiler->url())
189+ {
190+ }
191+
192+Index: qtdeclarative-opensource-src-5.3.2/src/qml/compiler/qqmltypecompiler_p.h
193+===================================================================
194+--- qtdeclarative-opensource-src-5.3.2.orig/src/qml/compiler/qqmltypecompiler_p.h
195++++ qtdeclarative-opensource-src-5.3.2/src/qml/compiler/qqmltypecompiler_p.h
196+@@ -149,6 +149,7 @@ protected:
197+ QHash<int, QQmlCompiledData::TypeReference*> *resolvedTypes;
198+ QVector<QByteArray> vmeMetaObjects;
199+ QVector<QQmlPropertyCache*> propertyCaches;
200++ QUrl m_url;
201+ };
202+
203+ // "Converts" signal expressions to full-fleged function declarations with
204+Index: qtdeclarative-opensource-src-5.3.2/src/qml/compiler/qv4compileddata_p.h
205+===================================================================
206+--- qtdeclarative-opensource-src-5.3.2.orig/src/qml/compiler/qv4compileddata_p.h
207++++ qtdeclarative-opensource-src-5.3.2/src/qml/compiler/qv4compileddata_p.h
208+@@ -607,6 +607,9 @@ struct Q_QML_PRIVATE_EXPORT CompilationU
209+ QV4::InternalClass **runtimeClasses;
210+ QVector<QV4::Function *> runtimeFunctions;
211+
212++ QVector<int> lookupTable;
213++ bool isRestored;
214++
215+ QV4::Function *linkToEngine(QV4::ExecutionEngine *engine);
216+ void unlink();
217+
218+Index: qtdeclarative-opensource-src-5.3.2/src/qml/compiler/qv4isel_moth_p.h
219+===================================================================
220+--- qtdeclarative-opensource-src-5.3.2.orig/src/qml/compiler/qv4isel_moth_p.h
221++++ qtdeclarative-opensource-src-5.3.2/src/qml/compiler/qv4isel_moth_p.h
222+@@ -72,6 +72,7 @@ public:
223+ ~InstructionSelection();
224+
225+ virtual void run(int functionIndex);
226++ virtual QV4::JIT::InstructionSelection* impl() { return NULL; };;
227+
228+ protected:
229+ virtual QV4::CompiledData::CompilationUnit *backendCompileStep();
230+Index: qtdeclarative-opensource-src-5.3.2/src/qml/compiler/qv4isel_p.cpp
231+===================================================================
232+--- qtdeclarative-opensource-src-5.3.2.orig/src/qml/compiler/qv4isel_p.cpp
233++++ qtdeclarative-opensource-src-5.3.2/src/qml/compiler/qv4isel_p.cpp
234+@@ -1,8 +1,14 @@
235+-/****************************************************************************
236++/***************************************************************************
237+ **
238+ ** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
239+ ** Contact: http://www.qt-project.org/legal
240+ **
241++** Copyright (C) 2014 Nomovok Ltd. All rights reserved.
242++** Contact: info@nomovok.com
243++**
244++** Copyright (C) 2014 Canonical Limited and/or its subsidiary(-ies).
245++** Contact: ricardo.mendoza@canonical.com
246++**
247+ ** This file is part of the QtQml module of the Qt Toolkit.
248+ **
249+ ** $QT_BEGIN_LICENSE:LGPL$
250+@@ -49,6 +55,54 @@
251+
252+ #include <QString>
253+
254++#ifndef V4_ENABLE_JIT
255++#undef V4_UNIT_CACHE
256++#endif
257++
258++#ifdef V4_UNIT_CACHE
259++#include <private/qqmltypenamecache_p.h>
260++#include <private/qqmlcompiler_p.h>
261++#include <private/qqmltypeloader_p.h>
262++#include <private/qv4compileddata_p.h>
263++#include <private/qv4assembler_p.h>
264++#include "../jit/qv4cachedlinkdata_p.h"
265++#include "../jit/qv4assembler_p.h"
266++#include <sys/stat.h>
267++#include <QCryptographicHash>
268++#include <QStandardPaths>
269++#include <QDir>
270++#include <QFile>
271++#include <QDataStream>
272++#include <QBuffer>
273++#endif
274++
275++bool writeData(QDataStream& stream, const char* data, int len)
276++{
277++ if (stream.writeRawData(data, len) != len)
278++ return false;
279++ else
280++ return true;
281++}
282++
283++bool writeDataWithLen(QDataStream& stream, const char* data, int len)
284++{
285++ quint32 l = len;
286++ if (!writeData(stream, (const char *)&l, sizeof(quint32)))
287++ return false;
288++ if (!writeData(stream, data, len))
289++ return false;
290++ return true;
291++}
292++
293++bool readData(char *data, int len, QDataStream &stream)
294++{
295++ if (stream.readRawData(data, len) != len) {
296++ return false;
297++ } else {
298++ return true;
299++ }
300++}
301++
302+ namespace {
303+ Q_GLOBAL_STATIC_WITH_ARGS(QTextStream, qout, (stderr, QIODevice::WriteOnly));
304+ #define qout *qout()
305+@@ -57,6 +111,14 @@ Q_GLOBAL_STATIC_WITH_ARGS(QTextStream, q
306+ using namespace QV4;
307+ using namespace QV4::IR;
308+
309++static bool do_cache = false;
310++
311++enum CacheState {
312++ UNTESTED = 0,
313++ VALID = 1,
314++ INVALID = 2
315++};
316++
317+ EvalInstructionSelection::EvalInstructionSelection(QV4::ExecutableAllocator *execAllocator, Module *module, QV4::Compiler::JSUnitGenerator *jsGenerator)
318+ : useFastLookups(true)
319+ , executableAllocator(execAllocator)
320+@@ -71,6 +133,9 @@ EvalInstructionSelection::EvalInstructio
321+ Q_ASSERT(execAllocator);
322+ #endif
323+ Q_ASSERT(module);
324++
325++ // Enable JIT cache only when explicitly requested and only cache files-on-disk (no qrc or inlines)
326++ do_cache = !qgetenv("QV4_ENABLE_JIT_CACHE").isEmpty() && irModule->fileName.startsWith(QStringLiteral("file://"));
327+ }
328+
329+ EvalInstructionSelection::~EvalInstructionSelection()
330+@@ -79,17 +144,306 @@ EvalInstructionSelection::~EvalInstructi
331+ EvalISelFactory::~EvalISelFactory()
332+ {}
333+
334+-QV4::CompiledData::CompilationUnit *EvalInstructionSelection::compile(bool generateUnitData)
335++QV4::CompiledData::CompilationUnit *EvalInstructionSelection::runAll(bool generateUnitData)
336+ {
337+- for (int i = 0; i < irModule->functions.size(); ++i)
338+- run(i);
339++ QV4::CompiledData::CompilationUnit *unit;
340++
341++ for (int i = 0; i < irModule->functions.size(); ++i) {
342++ run(i); // Performs the actual compilation
343++ }
344++
345++ unit = backendCompileStep();
346++
347++#ifdef V4_UNIT_CACHE
348++ unit->isRestored = false;
349++#endif
350+
351+- QV4::CompiledData::CompilationUnit *unit = backendCompileStep();
352+ if (generateUnitData)
353+ unit->data = jsGenerator->generateUnit();
354++
355+ return unit;
356+ }
357+
358++QV4::CompiledData::CompilationUnit *EvalInstructionSelection::compile(bool generateUnitData)
359++{
360++#ifndef V4_UNIT_CACHE
361++ return runAll(generateUnitData);
362++#else
363++ // Check if running JIT mode and if cache is enabled
364++ if (!do_cache || !this->impl())
365++ return runAll(generateUnitData);
366++
367++ QV4::CompiledData::CompilationUnit *unit;
368++
369++ bool loaded = false;
370++ bool do_save = true;
371++
372++ QByteArray path(qgetenv("HOME") + QByteArray("/.cache/QML/Apps/") + (qgetenv("APP_ID").isEmpty() ? QCoreApplication::applicationName().toLatin1() : qgetenv("APP_ID")));
373++
374++ if (m_engine && m_engine->qmlCacheValid == CacheState::UNTESTED) {
375++ bool valid = true;
376++ QDir cacheDir;
377++ cacheDir.setPath(QLatin1String(path));
378++ QStringList files = cacheDir.entryList();
379++ for (int i = 0; i < files.size(); i++) {
380++ if (valid == false)
381++ break;
382++
383++ QFile cacheFile(path + QDir::separator() + files.at(i));
384++ if (cacheFile.open(QIODevice::ReadOnly)) {
385++ QDataStream stream(&cacheFile);
386++ quint32 strLen = 0;
387++ readData((char *)&strLen, sizeof(quint32), stream);
388++ if (strLen == 0) {
389++ cacheFile.close();
390++ continue;
391++ }
392++
393++ char *tmpStr = (char *) malloc(strLen);
394++ readData((char *)tmpStr, strLen, stream);
395++ quint32 mtime = 0;
396++ readData((char *)&mtime, sizeof(quint32), stream);
397++
398++ struct stat sb;
399++ stat(tmpStr, &sb);
400++ if (QFile::exists(QLatin1String(tmpStr))) {
401++ QByteArray time(ctime(&sb.st_mtime));
402++ if (mtime != (quint32) sb.st_mtime) {
403++ if (m_engine) m_engine->qmlCacheValid = CacheState::INVALID;
404++ valid = false;
405++ }
406++ } else {
407++ // Compilation unit of unresolvable type (inline), remove
408++ cacheFile.remove();
409++ }
410++
411++ free(tmpStr);
412++ cacheFile.close();
413++ }
414++ }
415++ if (valid) {
416++ m_engine->qmlCacheValid = CacheState::VALID;
417++ } else {
418++ for (int i = 0; i < files.size(); i++)
419++ cacheDir.remove(files.at(i));
420++ }
421++ }
422++
423++ // Search for cache blob by mtime/app_id/file hash
424++ struct stat sb;
425++ stat(irModule->fileName.toLatin1().remove(0, 7).constData(), &sb);
426++ QByteArray time(ctime(&sb.st_mtime));
427++ QByteArray urlHash(QCryptographicHash::hash((irModule->fileName.toLatin1() + qgetenv("APP_ID") + time), QCryptographicHash::Md5).toHex());
428++ QDir dir;
429++ dir.mkpath(QLatin1String(path));
430++ QFile cacheFile(path + QDir::separator() + urlHash);
431++
432++ QByteArray fileData;
433++
434++ // TODO: Support inline compilation units
435++ if (cacheFile.exists() && cacheFile.open(QIODevice::ReadOnly)) {
436++ if (!irModule->fileName.isEmpty() && !irModule->fileName.contains(QStringLiteral("inline")) && m_engine) {
437++ loaded = true;
438++ fileData.append(cacheFile.readAll());
439++ } else {
440++ loaded = false;
441++ cacheFile.close();
442++ return runAll(generateUnitData);
443++ }
444++ }
445++
446++ // Check file integrity
447++ QString fileHash(QLatin1String(QCryptographicHash::hash(fileData.left(fileData.size()-32), QCryptographicHash::Md5).toHex()));
448++ if (!fileHash.contains(QLatin1String(fileData.right(32)))) {
449++ cacheFile.close();
450++ cacheFile.remove();
451++ loaded = false;
452++ }
453++
454++ // This code has been inspired and influenced by Nomovok's QMLC compiler available at
455++ // https://github.com/qmlc/qmlc. All original Copyrights are maintained for the
456++ // basic code snippets.
457++
458++ if (loaded) {
459++ // Retrieve unit skeleton from isel implementation
460++ unit = backendCompileStep();
461++ QV4::JIT::CompilationUnit *tmpUnit = (QV4::JIT::CompilationUnit *) unit;
462++ tmpUnit->codeRefs.resize(irModule->functions.size());
463++
464++ QDataStream stream(fileData);
465++
466++ quint32 strLen = 0;
467++ readData((char *)&strLen, sizeof(quint32), stream);
468++ char *tmpStr = (char *) malloc(strLen);
469++ readData((char *)tmpStr, strLen, stream);
470++ quint32 mtime = 0;
471++ readData((char *)&mtime, sizeof(quint32), stream);
472++
473++ unit->lookupTable.reserve(tmpUnit->codeRefs.size());
474++ quint32 len;
475++ for (int i = 0; i < tmpUnit->codeRefs.size(); i++) {
476++ quint32 strLen;
477++ readData((char *)&strLen, sizeof(quint32), stream);
478++
479++ char *fStr = (char *) malloc(strLen);
480++ readData(fStr, strLen, stream);
481++
482++ QString hashString(QLatin1String(irModule->functions.at(i)->name->toLatin1().constData()));
483++ hashString.append(QString::number(irModule->functions.at(i)->line));
484++ hashString.append(QString::number(irModule->functions.at(i)->column));
485++
486++ if (!hashString.contains(QLatin1String(fStr)))
487++ return runAll(generateUnitData);
488++
489++ unit->lookupTable.append(i);
490++
491++ len = 0;
492++ readData((char *)&len, sizeof(quint32), stream);
493++
494++ // Temporary unlinked code buffer
495++ executableAllocator->allocate(len);
496++ char *data = (char *) malloc(len);
497++ readData(data, len, stream);
498++
499++ quint32 linkCallCount = 0;
500++ readData((char *)&linkCallCount, sizeof(quint32), stream);
501++
502++ QVector<QV4::JIT::CachedLinkData> linkCalls;
503++ linkCalls.resize(linkCallCount);
504++ readData((char *)linkCalls.data(), linkCallCount * sizeof(QV4::JIT::CachedLinkData), stream);
505++
506++ quint32 constVectorLen = 0;
507++ readData((char *)&constVectorLen, sizeof(quint32), stream);
508++
509++ QVector<QV4::Primitive > constantVector;
510++ if (constVectorLen > 0) {
511++ constantVector.resize(constVectorLen);
512++ readData((char *)constantVector.data(), constVectorLen * sizeof(QV4::Primitive), stream);
513++ }
514++
515++ // Pre-allocate link buffer to append code
516++ QV4::ExecutableAllocator* executableAllocator = m_engine->v4engine()->executableAllocator;
517++
518++ QV4::IR::Function nullFunction(0, 0, QLatin1String(""));
519++
520++ QV4::JIT::Assembler* as = new QV4::JIT::Assembler(this->impl(), &nullFunction, executableAllocator, 6);
521++
522++ QList<QV4::JIT::Assembler::CallToLink>& callsToLink = as->callsToLink();
523++ for (int i = 0; i < linkCalls.size(); i++) {
524++ QV4::JIT::CachedLinkData& call = linkCalls[i];
525++ void *functionPtr = CACHED_LINK_TABLE[call.index].addr;
526++ QV4::JIT::Assembler::CallToLink c;
527++ JSC::AssemblerLabel label(call.offset);
528++ c.call = QV4::JIT::Assembler::Call(label, QV4::JIT::Assembler::Call::Linkable);
529++ c.externalFunction = JSC::FunctionPtr((quint32(*)(void))functionPtr);
530++ c.functionName = CACHED_LINK_TABLE[call.index].name;
531++ callsToLink.append(c);
532++ }
533++
534++ QV4::JIT::Assembler::ConstantTable& constTable = as->constantTable();
535++ foreach (const QV4::Primitive &p, constantVector)
536++ constTable.add(p);
537++
538++ as->appendData(data, len);
539++
540++ int dummySize = -1; // Pass known value to trigger use of code buffer
541++ tmpUnit->codeRefs[i] = as->link(&dummySize);
542++ Q_ASSERT(dummySize == (int)codeRefLen);
543++
544++ delete as;
545++ }
546++
547++ quint32 size = 0;
548++ readData((char *)&size, sizeof(quint32), stream);
549++
550++ void *dataPtr = malloc(size);
551++ QV4::CompiledData::Unit *finalUnit = reinterpret_cast<QV4::CompiledData::Unit*>(dataPtr);
552++ if (size > 0)
553++ readData((char *)dataPtr, size, stream);
554++
555++ unit->data = nullptr;
556++ if (irModule->functions.size() > 0)
557++ unit->data = finalUnit;
558++
559++ unit->isRestored = true;
560++ } else {
561++ // Not loading from cache, run all instructions
562++ unit = runAll(false);
563++ }
564++
565++ if ((unit->data == nullptr) && (do_save || generateUnitData))
566++ unit->data = jsGenerator->generateUnit();
567++
568++ // Save compilation unit
569++ QV4::JIT::CompilationUnit *jitUnit = (QV4::JIT::CompilationUnit *) unit;
570++ if (!loaded) {
571++ if (cacheFile.open(QIODevice::WriteOnly)) {
572++ // TODO: Support inline compilation units
573++ if (!irModule->fileName.isEmpty() && !irModule->fileName.contains(QLatin1String("inline")) && m_engine) {
574++ QBuffer fillBuff;
575++ fillBuff.open(QIODevice::WriteOnly);
576++ QDataStream stream(&fillBuff);
577++
578++ quint32 fileNameSize = irModule->fileName.size();
579++ writeData(stream, (const char *)&fileNameSize, sizeof(quint32));
580++ writeData(stream, (const char *)irModule->fileName.toLatin1().remove(0, 7).constData(), irModule->fileName.size());
581++
582++ struct stat sb;
583++ stat(irModule->fileName.toLatin1().remove(0, 7).constData(), &sb);
584++ writeData(stream, (const char *)&sb.st_mtime, sizeof(quint32));
585++
586++ for (int i = 0; i < jitUnit->codeRefs.size(); i++) {
587++ const JSC::MacroAssemblerCodeRef &codeRef = jitUnit->codeRefs[i];
588++ const QVector<QV4::Primitive> &constantValue = jitUnit->constantValues[i];
589++ quint32 len = codeRef.size();
590++
591++ QString hashString(QLatin1String(irModule->functions.at(i)->name->toLatin1()));
592++ hashString.append(QString::number(irModule->functions.at(i)->line));
593++ hashString.append(QString::number(irModule->functions.at(i)->column));
594++
595++ quint32 strLen = hashString.size();
596++ strLen += 1; // /0 char
597++ writeData(stream, (const char *)&strLen, sizeof(quint32));
598++ writeData(stream, (const char *)hashString.toLatin1().constData(), strLen);
599++ writeData(stream, (const char *)&len, sizeof(quint32));
600++ writeData(stream, (const char *)(((unsigned long)codeRef.code().executableAddress())&~1), len);
601++
602++ const QVector<QV4::JIT::CachedLinkData> &linkCalls = jitUnit->linkData[i];
603++ quint32 linkCallCount = linkCalls.size();
604++
605++ writeData(stream, (const char *)&linkCallCount, sizeof(quint32));
606++ if (linkCallCount > 0)
607++ writeData(stream, (const char *)linkCalls.data(), linkCalls.size() * sizeof (QV4::JIT::CachedLinkData));
608++
609++ quint32 constTableCount = constantValue.size();
610++ writeData(stream, (const char *)&constTableCount, sizeof(quint32));
611++
612++ if (constTableCount > 0)
613++ writeData(stream, (const char*)constantValue.data(), sizeof(QV4::Primitive) * constantValue.size());
614++ }
615++
616++ QV4::CompiledData::Unit *retUnit = unit->data;
617++ quint32 size = retUnit->unitSize;
618++
619++ if (size > 0) {
620++ writeData(stream, (const char*)&size, sizeof(quint32));
621++ writeData(stream, (const char*)retUnit, size);
622++ }
623++
624++ // Write MD5 hash of stored data for consistency check
625++ QByteArray fileHash(QCryptographicHash::hash(fillBuff.data(), QCryptographicHash::Md5).toHex());
626++ fillBuff.write(fileHash);
627++ cacheFile.write(fillBuff.data());
628++ }
629++ cacheFile.close();
630++ } else {
631++ cacheFile.close();
632++ }
633++ }
634++ return unit;
635++#endif
636++}
637++
638+ void IRDecoder::visitMove(IR::Move *s)
639+ {
640+ if (IR::Name *n = s->target->asName()) {
641+Index: qtdeclarative-opensource-src-5.3.2/src/qml/compiler/qv4isel_p.h
642+===================================================================
643+--- qtdeclarative-opensource-src-5.3.2.orig/src/qml/compiler/qv4isel_p.h
644++++ qtdeclarative-opensource-src-5.3.2/src/qml/compiler/qv4isel_p.h
645+@@ -56,6 +56,10 @@ class QQmlEnginePrivate;
646+
647+ namespace QV4 {
648+
649++namespace JIT {
650++ class InstructionSelection;
651++}
652++
653+ class ExecutableAllocator;
654+ struct Function;
655+
656+@@ -65,6 +69,7 @@ public:
657+ EvalInstructionSelection(QV4::ExecutableAllocator *execAllocator, IR::Module *module, QV4::Compiler::JSUnitGenerator *jsGenerator);
658+ virtual ~EvalInstructionSelection() = 0;
659+
660++ QV4::CompiledData::CompilationUnit *runAll(bool generateUnitData);
661+ QV4::CompiledData::CompilationUnit *compile(bool generateUnitData = true);
662+
663+ void setUseFastLookups(bool b) { useFastLookups = b; }
664+@@ -78,9 +83,11 @@ public:
665+ int registerRegExp(IR::RegExp *regexp) { return jsGenerator->registerRegExp(regexp); }
666+ int registerJSClass(int count, IR::ExprList *args) { return jsGenerator->registerJSClass(count, args); }
667+ QV4::Compiler::JSUnitGenerator *jsUnitGenerator() const { return jsGenerator; }
668++ void setEngine(QQmlEnginePrivate *qmlEngine) { m_engine = qmlEngine; }
669+
670+ protected:
671+ virtual void run(int functionIndex) = 0;
672++ virtual QV4::JIT::InstructionSelection* impl() = 0;
673+ virtual QV4::CompiledData::CompilationUnit *backendCompileStep() = 0;
674+
675+ bool useFastLookups;
676+@@ -88,6 +95,7 @@ protected:
677+ QV4::Compiler::JSUnitGenerator *jsGenerator;
678+ QScopedPointer<QV4::Compiler::JSUnitGenerator> ownJSGenerator;
679+ IR::Module *irModule;
680++ QQmlEnginePrivate *m_engine;
681+ };
682+
683+ class Q_QML_PRIVATE_EXPORT EvalISelFactory
684+Index: qtdeclarative-opensource-src-5.3.2/src/qml/jit/qv4assembler.cpp
685+===================================================================
686+--- qtdeclarative-opensource-src-5.3.2.orig/src/qml/jit/qv4assembler.cpp
687++++ qtdeclarative-opensource-src-5.3.2/src/qml/jit/qv4assembler.cpp
688+@@ -77,7 +77,10 @@ void CompilationUnit::linkBackendToEngin
689+
690+ QV4::Function *runtimeFunction = new QV4::Function(engine, this, compiledFunction,
691+ (ReturnedValue (*)(QV4::ExecutionContext *, const uchar *)) codeRefs[i].code().executableAddress());
692+- runtimeFunctions[i] = runtimeFunction;
693++ if (isRestored)
694++ runtimeFunctions[lookupTable.at(i)] = runtimeFunction;
695++ else
696++ runtimeFunctions[i] = runtimeFunction;
697+ }
698+ }
699+
700+Index: qtdeclarative-opensource-src-5.3.2/src/qml/jit/qv4assembler_p.h
701+===================================================================
702+--- qtdeclarative-opensource-src-5.3.2.orig/src/qml/jit/qv4assembler_p.h
703++++ qtdeclarative-opensource-src-5.3.2/src/qml/jit/qv4assembler_p.h
704+@@ -70,6 +70,16 @@ namespace JIT {
705+
706+ class InstructionSelection;
707+
708++struct CachedLinkData {
709++ quint32 index; // Link table index
710++ quint32 offset; // Offset inside the codeRef code
711++};
712++
713++struct LinkableCode {
714++ int len;
715++ void* code;
716++};
717++
718+ struct CompilationUnit : public QV4::CompiledData::CompilationUnit
719+ {
720+ virtual ~CompilationUnit();
721+@@ -82,6 +92,8 @@ struct CompilationUnit : public QV4::Com
722+
723+ QVector<JSC::MacroAssemblerCodeRef> codeRefs;
724+ QList<QVector<QV4::Primitive> > constantValues;
725++ QList<QVector<CachedLinkData>> linkData;
726++ QList<LinkableCode> linkableCode;
727+ };
728+
729+ struct RelativeCall {
730+@@ -1151,7 +1163,12 @@ public:
731+ move(TrustedImm64(u.i), ReturnValueRegister);
732+ move64ToDouble(ReturnValueRegister, target);
733+ #else
734+- JSC::MacroAssembler::loadDouble(constantTable().loadValueAddress(c, ScratchRegister), target);
735++ QV4::Primitive vv = convertToValue(c);
736++ FPRegisterID scratchFp;
737++ scratchFp = target;
738++ move(TrustedImm32(vv.int_32), ReturnValueRegister);
739++ move(TrustedImm32(vv.tag), ScratchRegister);
740++ moveIntsToDouble(ReturnValueRegister, ScratchRegister, target, scratchFp);
741+ #endif
742+ return target;
743+ }
744+@@ -1241,6 +1258,12 @@ public:
745+ Label exceptionReturnLabel;
746+ IR::BasicBlock * catchBlock;
747+ QVector<Jump> exceptionPropagationJumps;
748++
749++ LinkableCode tmpBuffer;
750++
751++ LinkableCode& codeToLink() { return tmpBuffer; }
752++ QList<CallToLink>& callsToLink() { return _callsToLink; }
753++
754+ private:
755+ const StackLayout _stackLayout;
756+ ConstantTable _constTable;
757+Index: qtdeclarative-opensource-src-5.3.2/src/qml/jit/qv4cachedlinkdata_p.h
758+===================================================================
759+--- /dev/null
760++++ qtdeclarative-opensource-src-5.3.2/src/qml/jit/qv4cachedlinkdata_p.h
761+@@ -0,0 +1,188 @@
762++/***************************************************************************
763++**
764++** Copyright (C) 2014 Nomovok Ltd. All rights reserved.
765++** Contact: info@nomovok.com
766++**
767++** Copyright (C) 2014 Canonical Limited and/or its subsidiary(-ies).
768++** Contact: ricardo.mendoza@canonical.com
769++**
770++** GNU Lesser General Public License Usage
771++** Alternatively, this file may be used under the terms of the GNU Lesser
772++** General Public License version 2.1 as published by the Free Software
773++** Foundation and appearing in the file LICENSE.LGPL included in the
774++** packaging of this file. Please review the following information to
775++** ensure the GNU Lesser General Public License version 2.1 requirements
776++** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
777++**
778++** In addition, as a special exception, Digia gives you certain additional
779++** rights. These rights are described in the Digia Qt LGPL Exception
780++** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
781++**
782++** GNU General Public License Usage
783++** Alternatively, this file may be used under the terms of the GNU
784++** General Public License version 3.0 as published by the Free Software
785++** Foundation and appearing in the file LICENSE.GPL included in the
786++** packaging of this file. Please review the following information to
787++** ensure the GNU General Public License version 3.0 requirements will be
788++** met: http://www.gnu.org/copyleft/gpl.html.
789++**
790++****************************************************************************/
791++
792++#ifndef QV4CACHEDLINKDATA_P_H
793++#define QV4CACHEDLINKDATA_P_H
794++
795++#include <qv4jsir_p.h>
796++#include <qv4isel_masm_p.h>
797++#include <qv4runtime_p.h>
798++
799++QT_BEGIN_NAMESPACE
800++
801++struct CachedLinkEntry {
802++ const char *name;
803++ void *addr;
804++};
805++
806++#define CACHED_LINK_TABLE_ADD_NS(x) QV4::Runtime::x
807++#define CACHED_LINK_TABLE_STR(x) "Runtime::" #x
808++#define CACHED_LINK_TABLE_ENTRY_RUNTIME(x) { (const char *)CACHED_LINK_TABLE_STR(x), (void *)CACHED_LINK_TABLE_ADD_NS(x) }
809++
810++// table to link objects
811++// this table can be used to resolve functions, it is id -> object mapping to maximize performance in linking phase
812++// when adding new calls, add to end of the list to maintain compatibility
813++const CachedLinkEntry CACHED_LINK_TABLE[] = {
814++ // call
815++ CACHED_LINK_TABLE_ENTRY_RUNTIME(callGlobalLookup),
816++ CACHED_LINK_TABLE_ENTRY_RUNTIME(callActivationProperty),
817++ CACHED_LINK_TABLE_ENTRY_RUNTIME(callProperty),
818++ CACHED_LINK_TABLE_ENTRY_RUNTIME(callPropertyLookup),
819++ CACHED_LINK_TABLE_ENTRY_RUNTIME(callElement),
820++ CACHED_LINK_TABLE_ENTRY_RUNTIME(callValue),
821++
822++ // construct
823++ CACHED_LINK_TABLE_ENTRY_RUNTIME(constructGlobalLookup),
824++ CACHED_LINK_TABLE_ENTRY_RUNTIME(constructActivationProperty),
825++ CACHED_LINK_TABLE_ENTRY_RUNTIME(constructProperty),
826++ CACHED_LINK_TABLE_ENTRY_RUNTIME(constructPropertyLookup),
827++ CACHED_LINK_TABLE_ENTRY_RUNTIME(constructValue),
828++
829++ // set & get
830++ CACHED_LINK_TABLE_ENTRY_RUNTIME(setActivationProperty),
831++ CACHED_LINK_TABLE_ENTRY_RUNTIME(setProperty),
832++ CACHED_LINK_TABLE_ENTRY_RUNTIME(setElement),
833++ CACHED_LINK_TABLE_ENTRY_RUNTIME(getProperty),
834++ CACHED_LINK_TABLE_ENTRY_RUNTIME(getActivationProperty),
835++ CACHED_LINK_TABLE_ENTRY_RUNTIME(getElement),
836++
837++ // typeof
838++ CACHED_LINK_TABLE_ENTRY_RUNTIME(typeofValue),
839++ CACHED_LINK_TABLE_ENTRY_RUNTIME(typeofName),
840++ CACHED_LINK_TABLE_ENTRY_RUNTIME(typeofMember),
841++ CACHED_LINK_TABLE_ENTRY_RUNTIME(typeofElement),
842++
843++ // delete
844++ CACHED_LINK_TABLE_ENTRY_RUNTIME(deleteElement),
845++ CACHED_LINK_TABLE_ENTRY_RUNTIME(deleteMember),
846++ CACHED_LINK_TABLE_ENTRY_RUNTIME(deleteName),
847++
848++ // exceptions & scopes
849++ CACHED_LINK_TABLE_ENTRY_RUNTIME(throwException),
850++ CACHED_LINK_TABLE_ENTRY_RUNTIME(unwindException),
851++ CACHED_LINK_TABLE_ENTRY_RUNTIME(pushWithScope),
852++ CACHED_LINK_TABLE_ENTRY_RUNTIME(pushCatchScope),
853++ CACHED_LINK_TABLE_ENTRY_RUNTIME(popScope),
854++
855++ // closures
856++ CACHED_LINK_TABLE_ENTRY_RUNTIME(closure),
857++
858++ // function header
859++ CACHED_LINK_TABLE_ENTRY_RUNTIME(declareVar),
860++ CACHED_LINK_TABLE_ENTRY_RUNTIME(setupArgumentsObject),
861++ CACHED_LINK_TABLE_ENTRY_RUNTIME(convertThisToObject),
862++
863++ // literals
864++ CACHED_LINK_TABLE_ENTRY_RUNTIME(arrayLiteral),
865++ CACHED_LINK_TABLE_ENTRY_RUNTIME(objectLiteral),
866++ CACHED_LINK_TABLE_ENTRY_RUNTIME(regexpLiteral),
867++
868++ // foreach
869++ CACHED_LINK_TABLE_ENTRY_RUNTIME(foreachIterator),
870++ CACHED_LINK_TABLE_ENTRY_RUNTIME(foreachNextPropertyName),
871++
872++ // unary operators
873++ //typedef ReturnedValue (*UnaryOperation)(const ValueRef);
874++ {"NOOP", (void *)qt_noop},
875++ CACHED_LINK_TABLE_ENTRY_RUNTIME(uPlus),
876++ CACHED_LINK_TABLE_ENTRY_RUNTIME(uMinus),
877++ CACHED_LINK_TABLE_ENTRY_RUNTIME(uNot),
878++ CACHED_LINK_TABLE_ENTRY_RUNTIME(complement),
879++ CACHED_LINK_TABLE_ENTRY_RUNTIME(increment),
880++ CACHED_LINK_TABLE_ENTRY_RUNTIME(decrement),
881++
882++ // binary operators
883++ //typedef ReturnedValue (*BinaryOperation)(const ValueRef left, const ValueRef right);
884++ {"NOOP", (void *)qt_noop},
885++ //typedef ReturnedValue (*BinaryOperationContext)(ExecutionContext *ctx, const ValueRef left, const ValueRef right);
886++ {"NOOP", (void *)qt_noop},
887++
888++ CACHED_LINK_TABLE_ENTRY_RUNTIME(instanceof),
889++ CACHED_LINK_TABLE_ENTRY_RUNTIME(in),
890++ CACHED_LINK_TABLE_ENTRY_RUNTIME(add),
891++ CACHED_LINK_TABLE_ENTRY_RUNTIME(addString),
892++ CACHED_LINK_TABLE_ENTRY_RUNTIME(bitOr),
893++ CACHED_LINK_TABLE_ENTRY_RUNTIME(bitXor),
894++ CACHED_LINK_TABLE_ENTRY_RUNTIME(bitAnd),
895++ CACHED_LINK_TABLE_ENTRY_RUNTIME(sub),
896++ CACHED_LINK_TABLE_ENTRY_RUNTIME(mul),
897++ CACHED_LINK_TABLE_ENTRY_RUNTIME(div),
898++ CACHED_LINK_TABLE_ENTRY_RUNTIME(mod),
899++ CACHED_LINK_TABLE_ENTRY_RUNTIME(shl),
900++ CACHED_LINK_TABLE_ENTRY_RUNTIME(shr),
901++ CACHED_LINK_TABLE_ENTRY_RUNTIME(ushr),
902++ CACHED_LINK_TABLE_ENTRY_RUNTIME(greaterThan),
903++ CACHED_LINK_TABLE_ENTRY_RUNTIME(lessThan),
904++ CACHED_LINK_TABLE_ENTRY_RUNTIME(greaterEqual),
905++ CACHED_LINK_TABLE_ENTRY_RUNTIME(lessEqual),
906++ CACHED_LINK_TABLE_ENTRY_RUNTIME(equal),
907++ CACHED_LINK_TABLE_ENTRY_RUNTIME(notEqual),
908++ CACHED_LINK_TABLE_ENTRY_RUNTIME(strictEqual),
909++ CACHED_LINK_TABLE_ENTRY_RUNTIME(strictNotEqual),
910++
911++ // comparisons
912++ //typedef Bool (*CompareOperation)(const ValueRef left, const ValueRef right);}
913++ {"NOOP", (void *)qt_noop},
914++ CACHED_LINK_TABLE_ENTRY_RUNTIME(compareGreaterThan),
915++ CACHED_LINK_TABLE_ENTRY_RUNTIME(compareLessThan),
916++ CACHED_LINK_TABLE_ENTRY_RUNTIME(compareGreaterEqual),
917++ CACHED_LINK_TABLE_ENTRY_RUNTIME(compareLessEqual),
918++ CACHED_LINK_TABLE_ENTRY_RUNTIME(compareEqual),
919++ CACHED_LINK_TABLE_ENTRY_RUNTIME(compareNotEqual),
920++ CACHED_LINK_TABLE_ENTRY_RUNTIME(compareStrictEqual),
921++ CACHED_LINK_TABLE_ENTRY_RUNTIME(compareStrictNotEqual),
922++
923++ //typedef Bool (*CompareOperationContext)(ExecutionContext *ctx, const ValueRef left, const ValueRef right);
924++ {"NOOP", (void *)qt_noop},
925++ CACHED_LINK_TABLE_ENTRY_RUNTIME(compareInstanceof),
926++ CACHED_LINK_TABLE_ENTRY_RUNTIME(compareIn),
927++
928++ // conversions
929++ CACHED_LINK_TABLE_ENTRY_RUNTIME(toBoolean),
930++ CACHED_LINK_TABLE_ENTRY_RUNTIME(toDouble),
931++ CACHED_LINK_TABLE_ENTRY_RUNTIME(toInt),
932++ CACHED_LINK_TABLE_ENTRY_RUNTIME(doubleToInt),
933++ CACHED_LINK_TABLE_ENTRY_RUNTIME(toUInt),
934++ CACHED_LINK_TABLE_ENTRY_RUNTIME(doubleToUInt),
935++
936++ // qml
937++ CACHED_LINK_TABLE_ENTRY_RUNTIME(getQmlIdArray),
938++ CACHED_LINK_TABLE_ENTRY_RUNTIME(getQmlImportedScripts),
939++ CACHED_LINK_TABLE_ENTRY_RUNTIME(getQmlContextObject),
940++ CACHED_LINK_TABLE_ENTRY_RUNTIME(getQmlScopeObject),
941++ CACHED_LINK_TABLE_ENTRY_RUNTIME(getQmlSingleton),
942++ CACHED_LINK_TABLE_ENTRY_RUNTIME(getQmlAttachedProperty),
943++ CACHED_LINK_TABLE_ENTRY_RUNTIME(getQmlQObjectProperty),
944++ CACHED_LINK_TABLE_ENTRY_RUNTIME(setQmlQObjectProperty)
945++};
946++
947++QT_END_NAMESPACE
948++
949++#endif
950+Index: qtdeclarative-opensource-src-5.3.2/src/qml/jit/qv4isel_masm.cpp
951+===================================================================
952+--- qtdeclarative-opensource-src-5.3.2.orig/src/qml/jit/qv4isel_masm.cpp
953++++ qtdeclarative-opensource-src-5.3.2/src/qml/jit/qv4isel_masm.cpp
954+@@ -51,6 +51,7 @@
955+ #include "qv4assembler_p.h"
956+ #include "qv4unop_p.h"
957+ #include "qv4binop_p.h"
958++#include "qv4cachedlinkdata_p.h"
959+
960+ #include <QtCore/QBuffer>
961+
962+@@ -147,9 +148,13 @@ JSC::MacroAssemblerCodeRef Assembler::li
963+ JSC::LinkBuffer linkBuffer(dummy, this, 0);
964+
965+ QHash<void*, const char*> functions;
966++ int i = 0;
967+ foreach (CallToLink ctl, _callsToLink) {
968+- linkBuffer.link(ctl.call, ctl.externalFunction);
969++ unsigned int offset = linkBuffer.link(ctl.call, ctl.externalFunction);
970++ ctl.call.m_label.m_offset = offset;
971+ functions[linkBuffer.locationOf(ctl.label).dataLocation()] = ctl.functionName;
972++ _callsToLink.replace(i, ctl);
973++ i++;
974+ }
975+
976+ foreach (const DataLabelPatch &p, _dataLabelPatches)
977+@@ -367,6 +372,25 @@ void InstructionSelection::run(int funct
978+ JSC::MacroAssemblerCodeRef codeRef =_as->link(&dummySize);
979+ compilationUnit->codeRefs[functionIndex] = codeRef;
980+
981++ QVector<CachedLinkData> calls;
982++ QList<Assembler::CallToLink>& callsToLink = _as->callsToLink();
983++ for (int i = 0; i < callsToLink.size(); i++) {
984++ Assembler::CallToLink& ctl = callsToLink[i];
985++ int index = -1;
986++ for (uint i = 0; i < sizeof(CACHED_LINK_TABLE) / sizeof (CachedLinkEntry); i++) {
987++ if (CACHED_LINK_TABLE[i].addr == ctl.externalFunction.value()) {
988++ index = i;
989++ break;
990++ }
991++ }
992++ CachedLinkData link;
993++ link.index = index;
994++ link.offset = ctl.call.m_label.m_offset;
995++ calls.append(link);
996++ }
997++ compilationUnit->linkData.insert(functionIndex, calls); // link data;
998++ compilationUnit->linkableCode.insert(functionIndex, _as->codeToLink()); // code to link
999++
1000+ qSwap(_function, function);
1001+ delete _as;
1002+ _as = oldAssembler;
1003+@@ -1828,5 +1852,4 @@ void InstructionSelection::visitCJumpEqu
1004+ _block, trueBlock, falseBlock);
1005+ }
1006+
1007+-
1008+ #endif // ENABLE(ASSEMBLER)
1009+Index: qtdeclarative-opensource-src-5.3.2/src/qml/jit/qv4isel_masm_p.h
1010+===================================================================
1011+--- qtdeclarative-opensource-src-5.3.2.orig/src/qml/jit/qv4isel_masm_p.h
1012++++ qtdeclarative-opensource-src-5.3.2/src/qml/jit/qv4isel_masm_p.h
1013+@@ -73,6 +73,8 @@ public:
1014+ virtual void run(int functionIndex);
1015+
1016+ const void *addConstantTable(QVector<QV4::Primitive> *values);
1017++
1018++ virtual InstructionSelection* impl() { return this; };
1019+ protected:
1020+ virtual QV4::CompiledData::CompilationUnit *backendCompileStep();
1021+
1022+Index: qtdeclarative-opensource-src-5.3.2/src/qml/jsruntime/qv4functionobject.cpp
1023+===================================================================
1024+--- qtdeclarative-opensource-src-5.3.2.orig/src/qml/jsruntime/qv4functionobject.cpp
1025++++ qtdeclarative-opensource-src-5.3.2/src/qml/jsruntime/qv4functionobject.cpp
1026+@@ -234,6 +234,7 @@ ReturnedValue FunctionCtor::construct(Ma
1027+
1028+ QV4::Compiler::JSUnitGenerator jsGenerator(&module);
1029+ QScopedPointer<EvalInstructionSelection> isel(v4->iselFactory->create(QQmlEnginePrivate::get(v4), v4->executableAllocator, &module, &jsGenerator));
1030++ isel->setEngine(QQmlEnginePrivate::get(v4));
1031+ QV4::CompiledData::CompilationUnit *compilationUnit = isel->compile();
1032+ QV4::Function *vmf = compilationUnit->linkToEngine(v4);
1033+
1034+Index: qtdeclarative-opensource-src-5.3.2/src/qml/jsruntime/qv4qobjectwrapper.cpp
1035+===================================================================
1036+--- qtdeclarative-opensource-src-5.3.2.orig/src/qml/jsruntime/qv4qobjectwrapper.cpp
1037++++ qtdeclarative-opensource-src-5.3.2/src/qml/jsruntime/qv4qobjectwrapper.cpp
1038+@@ -628,6 +628,7 @@ ReturnedValue QObjectWrapper::getPropert
1039+ QQmlPropertyCache *cache = ddata->propertyCache;
1040+ Q_ASSERT(cache);
1041+ QQmlPropertyData *property = cache->property(propertyIndex);
1042++
1043+ Q_ASSERT(property); // We resolved this property earlier, so it better exist!
1044+ return getProperty(object, ctx, property, captureRequired);
1045+ }
1046+Index: qtdeclarative-opensource-src-5.3.2/src/qml/jsruntime/qv4script.cpp
1047+===================================================================
1048+--- qtdeclarative-opensource-src-5.3.2.orig/src/qml/jsruntime/qv4script.cpp
1049++++ qtdeclarative-opensource-src-5.3.2/src/qml/jsruntime/qv4script.cpp
1050+@@ -272,6 +272,7 @@ void Script::parse()
1051+ QScopedPointer<EvalInstructionSelection> isel(v4->iselFactory->create(QQmlEnginePrivate::get(v4), v4->executableAllocator, &module, &jsGenerator));
1052+ if (inheritContext)
1053+ isel->setUseFastLookups(false);
1054++ isel->setEngine(QQmlEnginePrivate::get(v4));
1055+ QV4::CompiledData::CompilationUnit *compilationUnit = isel->compile();
1056+ vmFunction = compilationUnit->linkToEngine(v4);
1057+ ScopedValue holder(valueScope, new (v4->memoryManager) CompilationUnitHolder(v4, compilationUnit));
1058+@@ -394,6 +395,7 @@ QV4::CompiledData::CompilationUnit *Scri
1059+
1060+ QScopedPointer<EvalInstructionSelection> isel(engine->iselFactory->create(QQmlEnginePrivate::get(engine), engine->executableAllocator, module, unitGenerator));
1061+ isel->setUseFastLookups(false);
1062++ isel->setEngine(QQmlEnginePrivate::get(engine));
1063+ return isel->compile(/*generate unit data*/false);
1064+ }
1065+
1066+Index: qtdeclarative-opensource-src-5.3.2/src/qml/qml/qqmlengine.cpp
1067+===================================================================
1068+--- qtdeclarative-opensource-src-5.3.2.orig/src/qml/qml/qqmlengine.cpp
1069++++ qtdeclarative-opensource-src-5.3.2/src/qml/qml/qqmlengine.cpp
1070+@@ -561,7 +561,8 @@ QQmlEnginePrivate::QQmlEnginePrivate(QQm
1071+ activeObjectCreator(0),
1072+ networkAccessManager(0), networkAccessManagerFactory(0), urlInterceptor(0),
1073+ scarceResourcesRefCount(0), typeLoader(e), importDatabase(e), uniqueId(1),
1074+- incubatorCount(0), incubationController(0), mutex(QMutex::Recursive)
1075++ incubatorCount(0), incubationController(0), mutex(QMutex::Recursive),
1076++ qmlCacheValid(0)
1077+ {
1078+ useNewCompiler = true;
1079+ }
1080+Index: qtdeclarative-opensource-src-5.3.2/src/qml/qml/qqmlengine_p.h
1081+===================================================================
1082+--- qtdeclarative-opensource-src-5.3.2.orig/src/qml/qml/qqmlengine_p.h
1083++++ qtdeclarative-opensource-src-5.3.2/src/qml/qml/qqmlengine_p.h
1084+@@ -270,6 +270,8 @@ public:
1085+
1086+ mutable QMutex mutex;
1087+
1088++ int qmlCacheValid;
1089++
1090+ private:
1091+ // Locker locks the QQmlEnginePrivate data structures for read and write, if necessary.
1092+ // Currently, locking is only necessary if the threaded loader is running concurrently. If it is
1093+Index: qtdeclarative-opensource-src-5.3.2/src/qml/qml/qqmljavascriptexpression.cpp
1094+===================================================================
1095+--- qtdeclarative-opensource-src-5.3.2.orig/src/qml/qml/qqmljavascriptexpression.cpp
1096++++ qtdeclarative-opensource-src-5.3.2/src/qml/qml/qqmljavascriptexpression.cpp
1097+@@ -335,6 +335,7 @@ QV4::ReturnedValue QQmlJavaScriptExpress
1098+
1099+ QV4::ScopedObject qmlScopeObject(scope, QV4::QmlContextWrapper::qmlScope(ep->v8engine(), ctxt, qmlScope));
1100+ QV4::Script script(v4, qmlScopeObject, code, filename, line);
1101++
1102+ QV4::ScopedValue result(scope);
1103+ script.parse();
1104+ if (!v4->hasException)
1105
1106=== modified file 'debian/patches/series'
1107--- debian/patches/series 2014-12-08 10:58:09 +0000
1108+++ debian/patches/series 2015-02-04 10:51:00 +0000
1109@@ -6,3 +6,4 @@
1110 Support-RFC2822Date-date-format-similar-to-V8.patch
1111 Avoid-race-condition-in-QQmlEngine-on-shutdown.patch
1112 Fix-crashes-when-calling-Array.sort-with-imperfect-s.patch
1113+QML-Compilation-unit-caching-and-JIT-changes.patch

Subscribers

People subscribed via source and target branches