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

Subscribers

People subscribed via source and target branches