Use on-disk compilation unit if available
If we succeeded in saving the compilation unit to disk, then attempt to use it right away. This replaces the C++ heap usage for the compilation unit data as well as the anonymous allocated executable memory with file-backed mmap'ed memory. That means the memory can be discarded when overall availability is low and paged in on-demand. Change-Id: Ide1b1e11752d861eb049a99a26ca12cec5e2502e Reviewed-by: Ulf Hermann <ulf.hermann@qt.io>
This commit is contained in:
parent
01575a22ea
commit
234e762265
|
@ -424,6 +424,7 @@ bool CompilationUnit::loadFromDisk(const QUrl &url, EvalISelFactory *iselFactory
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const Unit * const oldDataPtr = (data && !(data->flags & QV4::CompiledData::Unit::StaticData)) ? data : nullptr;
|
||||||
QScopedValueRollback<const Unit *> dataPtrChange(data, reinterpret_cast<const Unit *>(cacheData));
|
QScopedValueRollback<const Unit *> dataPtrChange(data, reinterpret_cast<const Unit *>(cacheData));
|
||||||
|
|
||||||
{
|
{
|
||||||
|
@ -448,6 +449,7 @@ bool CompilationUnit::loadFromDisk(const QUrl &url, EvalISelFactory *iselFactory
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
dataPtrChange.commit();
|
dataPtrChange.commit();
|
||||||
|
free(const_cast<Unit*>(oldDataPtr));
|
||||||
backingFile.reset(cacheFile.take());
|
backingFile.reset(cacheFile.take());
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
|
@ -666,8 +666,10 @@ struct Unit
|
||||||
return QString();
|
return QString();
|
||||||
#if Q_BYTE_ORDER == Q_LITTLE_ENDIAN
|
#if Q_BYTE_ORDER == Q_LITTLE_ENDIAN
|
||||||
const QChar *characters = reinterpret_cast<const QChar *>(str + 1);
|
const QChar *characters = reinterpret_cast<const QChar *>(str + 1);
|
||||||
if (flags & StaticData)
|
// Too risky to do this while we unmap disk backed compilation but keep pointers to string
|
||||||
return QString::fromRawData(characters, str->size);
|
// data in the identifier tables.
|
||||||
|
// if (flags & StaticData)
|
||||||
|
// return QString::fromRawData(characters, str->size);
|
||||||
return QString(characters, str->size);
|
return QString(characters, str->size);
|
||||||
#else
|
#else
|
||||||
const LEUInt16 *characters = reinterpret_cast<const LEUInt16 *>(str + 1);
|
const LEUInt16 *characters = reinterpret_cast<const LEUInt16 *>(str + 1);
|
||||||
|
|
|
@ -1665,8 +1665,7 @@ bool CompilationUnit::saveCodeToDisk(QIODevice *device, const CompiledData::Unit
|
||||||
bool CompilationUnit::memoryMapCode(QString *errorString)
|
bool CompilationUnit::memoryMapCode(QString *errorString)
|
||||||
{
|
{
|
||||||
Q_UNUSED(errorString);
|
Q_UNUSED(errorString);
|
||||||
Q_ASSERT(codeRefs.isEmpty());
|
codeRefs.resize(data->functionTableSize);
|
||||||
codeRefs.reserve(data->functionTableSize);
|
|
||||||
|
|
||||||
const char *basePtr = reinterpret_cast<const char *>(data);
|
const char *basePtr = reinterpret_cast<const char *>(data);
|
||||||
|
|
||||||
|
@ -1680,7 +1679,7 @@ bool CompilationUnit::memoryMapCode(QString *errorString)
|
||||||
#else
|
#else
|
||||||
QByteArray code = QByteArray::fromRawData(codePtr, compiledFunction->codeSize);
|
QByteArray code = QByteArray::fromRawData(codePtr, compiledFunction->codeSize);
|
||||||
#endif
|
#endif
|
||||||
codeRefs.append(code);
|
codeRefs[i] = code;
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
|
|
@ -129,8 +129,7 @@ bool CompilationUnit::saveCodeToDisk(QIODevice *device, const CompiledData::Unit
|
||||||
bool CompilationUnit::memoryMapCode(QString *errorString)
|
bool CompilationUnit::memoryMapCode(QString *errorString)
|
||||||
{
|
{
|
||||||
Q_UNUSED(errorString);
|
Q_UNUSED(errorString);
|
||||||
Q_ASSERT(codeRefs.isEmpty());
|
codeRefs.resize(data->functionTableSize);
|
||||||
codeRefs.reserve(data->functionTableSize);
|
|
||||||
|
|
||||||
const char *basePtr = reinterpret_cast<const char *>(data);
|
const char *basePtr = reinterpret_cast<const char *>(data);
|
||||||
|
|
||||||
|
@ -139,7 +138,7 @@ bool CompilationUnit::memoryMapCode(QString *errorString)
|
||||||
void *codePtr = const_cast<void *>(reinterpret_cast<const void *>(basePtr + compiledFunction->codeOffset));
|
void *codePtr = const_cast<void *>(reinterpret_cast<const void *>(basePtr + compiledFunction->codeOffset));
|
||||||
JSC::MacroAssemblerCodeRef codeRef = JSC::MacroAssemblerCodeRef::createSelfManagedCodeRef(JSC::MacroAssemblerCodePtr(codePtr));
|
JSC::MacroAssemblerCodeRef codeRef = JSC::MacroAssemblerCodeRef::createSelfManagedCodeRef(JSC::MacroAssemblerCodePtr(codePtr));
|
||||||
JSC::ExecutableAllocator::makeExecutable(codePtr, compiledFunction->codeSize);
|
JSC::ExecutableAllocator::makeExecutable(codePtr, compiledFunction->codeSize);
|
||||||
codeRefs.append(codeRef);
|
codeRefs[i] = codeRef;
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
|
|
@ -2502,7 +2502,8 @@ void QQmlTypeData::compile(const QQmlRefPointer<QQmlTypeNameCache> &importCache,
|
||||||
{
|
{
|
||||||
Q_ASSERT(m_compiledData.isNull());
|
Q_ASSERT(m_compiledData.isNull());
|
||||||
|
|
||||||
QQmlTypeCompiler compiler(QQmlEnginePrivate::get(typeLoader()->engine()), this, m_document.data(), importCache, resolvedTypeCache);
|
QQmlEnginePrivate * const enginePrivate = QQmlEnginePrivate::get(typeLoader()->engine());
|
||||||
|
QQmlTypeCompiler compiler(enginePrivate, this, m_document.data(), importCache, resolvedTypeCache);
|
||||||
m_compiledData = compiler.compile();
|
m_compiledData = compiler.compile();
|
||||||
if (!m_compiledData) {
|
if (!m_compiledData) {
|
||||||
setError(compiler.compilationErrors());
|
setError(compiler.compilationErrors());
|
||||||
|
@ -2510,7 +2511,12 @@ void QQmlTypeData::compile(const QQmlRefPointer<QQmlTypeNameCache> &importCache,
|
||||||
}
|
}
|
||||||
if (diskCache() || forceDiskCacheRefresh()) {
|
if (diskCache() || forceDiskCacheRefresh()) {
|
||||||
QString errorString;
|
QString errorString;
|
||||||
if (!m_compiledData->saveToDisk(url(), &errorString)) {
|
if (m_compiledData->saveToDisk(url(), &errorString)) {
|
||||||
|
QString error;
|
||||||
|
if (!m_compiledData->loadFromDisk(url(), enginePrivate->v4engine()->iselFactory.data(), &error)) {
|
||||||
|
// ignore error, keep using the in-memory compilation unit.
|
||||||
|
}
|
||||||
|
} else {
|
||||||
qCDebug(DBG_DISK_CACHE) << "Error saving cached version of" << m_compiledData->url().toString() << "to disk:" << errorString;
|
qCDebug(DBG_DISK_CACHE) << "Error saving cached version of" << m_compiledData->url().toString() << "to disk:" << errorString;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2118,8 +2118,13 @@ void tst_qqmllanguage::scriptStringWithoutSourceCode()
|
||||||
QQmlTypeData *td = eng->typeLoader.getType(url);
|
QQmlTypeData *td = eng->typeLoader.getType(url);
|
||||||
Q_ASSERT(td);
|
Q_ASSERT(td);
|
||||||
|
|
||||||
const QV4::CompiledData::Unit *qmlUnit = td->compilationUnit()->data;
|
const QV4::CompiledData::Unit *readOnlyQmlUnit = td->compilationUnit()->data;
|
||||||
Q_ASSERT(qmlUnit);
|
Q_ASSERT(readOnlyQmlUnit);
|
||||||
|
QV4::CompiledData::Unit *qmlUnit = reinterpret_cast<QV4::CompiledData::Unit *>(malloc(readOnlyQmlUnit->unitSize));
|
||||||
|
memcpy(qmlUnit, readOnlyQmlUnit, readOnlyQmlUnit->unitSize);
|
||||||
|
qmlUnit->flags &= ~QV4::CompiledData::Unit::StaticData;
|
||||||
|
td->compilationUnit()->data = qmlUnit;
|
||||||
|
|
||||||
const QV4::CompiledData::Object *rootObject = qmlUnit->objectAt(qmlUnit->indexOfRootObject);
|
const QV4::CompiledData::Object *rootObject = qmlUnit->objectAt(qmlUnit->indexOfRootObject);
|
||||||
QCOMPARE(qmlUnit->stringAt(rootObject->inheritedTypeNameIndex), QString("MyTypeObject"));
|
QCOMPARE(qmlUnit->stringAt(rootObject->inheritedTypeNameIndex), QString("MyTypeObject"));
|
||||||
quint32 i;
|
quint32 i;
|
||||||
|
|
Loading…
Reference in New Issue