aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorSimon Hausmann <simon.hausmann@qt.io>2018-07-23 14:08:06 +0200
committerSimon Hausmann <simon.hausmann@qt.io>2018-07-31 17:08:08 +0000
commit8237f645a33199e0a8aded0a3f7e6077990707fd (patch)
tree2011793b9c3775f307cd5e2560143017ddb57719 /src
parent9337b1c339c34cd4fe10d236be2ee61ca76e17ba (diff)
Optimize memory consumption of ahead-of-time compile cache files
When loading a pre-compiled cache file, the strings contained therein will remain available in memory since commit 7dcada48d2435e8ceb0cc8a6771f79b76979e11f. While for aot built cache files we may have to add new strings (for example for signal handler parameters), we can re-use the existing strings by omitting them from the intermediately created string table. This saves ~283K RAM with qtquickcontrols1 gallery. Task-number: QTBUG-69588 Change-Id: I8ea807f6dea4cc35d8b7e5f7329809ed1cd12880 Reviewed-by: Lars Knoll <lars.knoll@qt.io>
Diffstat (limited to 'src')
-rw-r--r--src/qml/compiler/qqmlirbuilder.cpp4
-rw-r--r--src/qml/compiler/qqmltypecompiler.cpp8
-rw-r--r--src/qml/compiler/qv4compileddata.cpp11
-rw-r--r--src/qml/compiler/qv4compileddata_p.h17
-rw-r--r--src/qml/compiler/qv4compiler.cpp14
-rw-r--r--src/qml/compiler/qv4compiler_p.h7
6 files changed, 46 insertions, 15 deletions
diff --git a/src/qml/compiler/qqmlirbuilder.cpp b/src/qml/compiler/qqmlirbuilder.cpp
index 88527b0d94..511b953eaa 100644
--- a/src/qml/compiler/qqmlirbuilder.cpp
+++ b/src/qml/compiler/qqmlirbuilder.cpp
@@ -2352,9 +2352,7 @@ IRLoader::IRLoader(const QV4::CompiledData::Unit *qmlData, QmlIR::Document *outp
void IRLoader::load()
{
- output->jsGenerator.stringTable.clear();
- for (uint i = 0; i < unit->stringTableSize; ++i)
- output->jsGenerator.stringTable.registerString(unit->stringAtInternal(i));
+ output->jsGenerator.stringTable.initializeFromBackingUnit(unit);
for (quint32 i = 0; i < unit->nImports; ++i)
output->imports << unit->importAt(i);
diff --git a/src/qml/compiler/qqmltypecompiler.cpp b/src/qml/compiler/qqmltypecompiler.cpp
index a6bdf93e2e..15edc010fd 100644
--- a/src/qml/compiler/qqmltypecompiler.cpp
+++ b/src/qml/compiler/qqmltypecompiler.cpp
@@ -133,8 +133,12 @@ QQmlRefPointer<QV4::CompiledData::CompilationUnit> QQmlTypeCompiler::compile()
return nullptr;
}
- // Compile JS binding expressions and signal handlers
- if (!document->javaScriptCompilationUnit) {
+ if (document->javaScriptCompilationUnit) {
+ // If this file was loaded from an ahead-of-time built cache file, then set up the original
+ // unit data as backing unit and fetch strings from there to save memory.
+ document->javaScriptCompilationUnit->backingUnit = document->javaScriptCompilationUnit->unitData();
+ } else {
+ // Compile JS binding expressions and signal handlers if necessary
{
// We can compile script strings ahead of time, but they must be compiled
// without type optimizations as their scope is always entirely dynamic.
diff --git a/src/qml/compiler/qv4compileddata.cpp b/src/qml/compiler/qv4compileddata.cpp
index 84abd081cf..32d17a709d 100644
--- a/src/qml/compiler/qv4compileddata.cpp
+++ b/src/qml/compiler/qv4compileddata.cpp
@@ -126,10 +126,11 @@ QV4::Function *CompilationUnit::linkToEngine(ExecutionEngine *engine)
Q_ASSERT(!runtimeStrings);
Q_ASSERT(data);
- runtimeStrings = (QV4::Heap::String **)malloc(data->stringTableSize * sizeof(QV4::Heap::String*));
+ const quint32 stringCount = totalStringCount();
+ runtimeStrings = (QV4::Heap::String **)malloc(stringCount * sizeof(QV4::Heap::String*));
// memset the strings to 0 in case a GC run happens while we're within the loop below
- memset(runtimeStrings, 0, data->stringTableSize * sizeof(QV4::Heap::String*));
- for (uint i = 0; i < data->stringTableSize; ++i)
+ memset(runtimeStrings, 0, stringCount * sizeof(QV4::Heap::String*));
+ for (uint i = 0; i < stringCount; ++i)
runtimeStrings[i] = engine->newString(stringAt(i));
runtimeRegularExpressions = new QV4::Value[data->regexpTableSize];
@@ -187,7 +188,7 @@ QV4::Function *CompilationUnit::linkToEngine(ExecutionEngine *engine)
qDebug() << "=== Constant table";
Moth::dumpConstantTable(constants, data->constantTableSize);
qDebug() << "=== String table";
- for (uint i = 0; i < data->stringTableSize; ++i)
+ for (uint i = 0, end = totalStringCount(); i < end; ++i)
qDebug() << " " << i << ":" << runtimeStrings[i]->toQString();
qDebug() << "=== Closure table";
for (uint i = 0; i < data->functionTableSize; ++i)
@@ -240,7 +241,7 @@ void CompilationUnit::unlink()
void CompilationUnit::markObjects(QV4::MarkStack *markStack)
{
if (runtimeStrings) {
- for (uint i = 0; i < data->stringTableSize; ++i)
+ for (uint i = 0, end = totalStringCount(); i < end; ++i)
if (runtimeStrings[i])
runtimeStrings[i]->mark(markStack);
}
diff --git a/src/qml/compiler/qv4compileddata_p.h b/src/qml/compiler/qv4compileddata_p.h
index b3edf1c701..bf83c45384 100644
--- a/src/qml/compiler/qv4compileddata_p.h
+++ b/src/qml/compiler/qv4compileddata_p.h
@@ -831,6 +831,7 @@ struct Unit
/* end QML specific fields*/
QString stringAtInternal(int idx) const {
+ Q_ASSERT(idx < int(stringTableSize));
const quint32_le *offsetTable = reinterpret_cast<const quint32_le*>((reinterpret_cast<const char *>(this)) + offsetToStringTable);
const quint32_le offset = offsetTable[idx];
const String *str = reinterpret_cast<const String*>(reinterpret_cast<const char *>(this) + offset);
@@ -1083,12 +1084,22 @@ public:
bool isRegisteredWithEngine = false;
QScopedPointer<CompilationUnitMapper> backingFile;
+ const QV4::CompiledData::Unit *backingUnit = nullptr;
// --- interface for QQmlPropertyCacheCreator
typedef Object CompiledObject;
int objectCount() const { return data->nObjects; }
const Object *objectAt(int index) const { return data->objectAt(index); }
- QString stringAt(int index) const { return data->stringAtInternal(index); }
+ QString stringAt(int index) const
+ {
+ if (backingUnit) {
+ const qint32 backingUnitStringTableSize = backingUnit->stringTableSize;
+ if (index < backingUnitStringTableSize)
+ return backingUnit->stringAtInternal(index);
+ index -= backingUnitStringTableSize;
+ }
+ return data->stringAtInternal(index);
+ }
struct FunctionIterator
{
@@ -1117,6 +1128,10 @@ public:
protected:
void linkBackendToEngine(QV4::ExecutionEngine *engine);
+
+ quint32 totalStringCount() const
+ { return data->stringTableSize + (backingUnit ? backingUnit->stringTableSize : 0); }
+
#endif // V4_BOOTSTRAP
private:
diff --git a/src/qml/compiler/qv4compiler.cpp b/src/qml/compiler/qv4compiler.cpp
index 6dbd4a35fb..bc7265ab0c 100644
--- a/src/qml/compiler/qv4compiler.cpp
+++ b/src/qml/compiler/qv4compiler.cpp
@@ -77,13 +77,23 @@ void QV4::Compiler::StringTableGenerator::clear()
stringDataSize = 0;
}
+void QV4::Compiler::StringTableGenerator::initializeFromBackingUnit(const QV4::CompiledData::Unit *unit)
+{
+ clear();
+ for (uint i = 0; i < unit->stringTableSize; ++i)
+ registerString(unit->stringAtInternal(i));
+ backingUnitTableSize = unit->stringTableSize;
+ stringDataSize = 0;
+}
+
void QV4::Compiler::StringTableGenerator::serialize(CompiledData::Unit *unit)
{
char *dataStart = reinterpret_cast<char *>(unit);
quint32_le *stringTable = reinterpret_cast<quint32_le *>(dataStart + unit->offsetToStringTable);
char *stringData = dataStart + unit->offsetToStringTable + unit->stringTableSize * sizeof(uint);
- for (int i = 0; i < strings.size(); ++i) {
- stringTable[i] = stringData - dataStart;
+ for (int i = backingUnitTableSize ; i < strings.size(); ++i) {
+ const int index = i - backingUnitTableSize;
+ stringTable[index] = stringData - dataStart;
const QString &qstr = strings.at(i);
QV4::CompiledData::String *s = reinterpret_cast<QV4::CompiledData::String *>(stringData);
diff --git a/src/qml/compiler/qv4compiler_p.h b/src/qml/compiler/qv4compiler_p.h
index 381b6fad21..bb9794358b 100644
--- a/src/qml/compiler/qv4compiler_p.h
+++ b/src/qml/compiler/qv4compiler_p.h
@@ -80,18 +80,21 @@ struct Q_QML_PRIVATE_EXPORT StringTableGenerator {
int registerString(const QString &str);
int getStringId(const QString &string) const;
QString stringForIndex(int index) const { return strings.at(index); }
- uint stringCount() const { return strings.size(); }
+ uint stringCount() const { return strings.size() - backingUnitTableSize; }
- uint sizeOfTableAndData() const { return stringDataSize + strings.count() * sizeof(uint); }
+ uint sizeOfTableAndData() const { return stringDataSize + stringCount() * sizeof(uint); }
void clear();
+ void initializeFromBackingUnit(const CompiledData::Unit *unit);
+
void serialize(CompiledData::Unit *unit);
private:
QHash<QString, int> stringToId;
QStringList strings;
uint stringDataSize;
+ uint backingUnitTableSize = 0;
};
struct Q_QML_PRIVATE_EXPORT JSUnitGenerator {