Merge lp:~ricmm/kubuntu-packaging/qtdeclarative-opensource-src_532-implement-jit-cache into lp:~kubuntu-packagers/kubuntu-packaging/qtdeclarative-opensource-src_532
- qtdeclarative-opensource-src_532-implement-jit-cache
- Merge into qtdeclarative-opensource-s...
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 |
Related bugs: |
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_
Description of the change
To post a comment you must log in.
Revision history for this message
Timo Jyrinki (timo-jyrinki) wrote : | # |
Revision history for this message
Timo Jyrinki (timo-jyrinki) : | # |
review:
Approve
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Autolanding.
More details in the following jenkins job:
http://
Executed test runs:
FAILURE: http://
FAILURE: http://
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 |
Published to archives after testing.