aboutsummaryrefslogtreecommitdiffstats
path: root/src/qml/compiler/qv4compileddata.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/qml/compiler/qv4compileddata.cpp')
-rw-r--r--src/qml/compiler/qv4compileddata.cpp236
1 files changed, 167 insertions, 69 deletions
diff --git a/src/qml/compiler/qv4compileddata.cpp b/src/qml/compiler/qv4compileddata.cpp
index 6aac111897..8f8d374e24 100644
--- a/src/qml/compiler/qv4compileddata.cpp
+++ b/src/qml/compiler/qv4compileddata.cpp
@@ -52,7 +52,6 @@
#include "qv4compilationunitmapper_p.h"
#include <QQmlPropertyMap>
#include <QDateTime>
-#include <QSaveFile>
#include <QFile>
#include <QFileInfo>
#include <QScopedValueRollback>
@@ -62,6 +61,7 @@
#include <private/qqmlirbuilder_p.h>
#include <QCoreApplication>
#include <QCryptographicHash>
+#include <QSaveFile>
#include <algorithm>
@@ -77,6 +77,27 @@ namespace QV4 {
namespace CompiledData {
+#ifdef V4_BOOTSTRAP
+static QString cacheFilePath(const QString &localSourcePath)
+{
+ const QString localCachePath = localSourcePath + QLatin1Char('c');
+ return localCachePath;
+}
+#else
+static QString cacheFilePath(const QUrl &url)
+{
+ const QString localSourcePath = QQmlFile::urlToLocalFileOrQrc(url);
+ const QString localCachePath = localSourcePath + QLatin1Char('c');
+ if (QFileInfo(QFileInfo(localSourcePath).dir().absolutePath()).isWritable())
+ return localCachePath;
+ QCryptographicHash fileNameHash(QCryptographicHash::Sha1);
+ fileNameHash.addData(localSourcePath.toUtf8());
+ QString directory = QStandardPaths::writableLocation(QStandardPaths::CacheLocation) + QLatin1String("/qmlcache/");
+ QDir::root().mkpath(directory);
+ return directory + QString::fromUtf8(fileNameHash.result().toHex()) + QLatin1Char('.') + QFileInfo(localCachePath).completeSuffix();
+}
+#endif
+
#ifndef V4_BOOTSTRAP
CompilationUnit::CompilationUnit()
: data(0)
@@ -207,7 +228,7 @@ void CompilationUnit::unlink()
dependentScripts.at(ii)->release();
dependentScripts.clear();
- importCache = nullptr;
+ typeNameCache = nullptr;
qDeleteAll(resolvedTypes);
resolvedTypes.clear();
@@ -329,20 +350,68 @@ bool CompilationUnit::verifyChecksum(QQmlEngine *engine,
sizeof(data->dependencyMD5Checksum)) == 0;
}
-static QString cacheFilePath(const QUrl &url)
+bool CompilationUnit::loadFromDisk(const QUrl &url, EvalISelFactory *iselFactory, QString *errorString)
{
- const QString localSourcePath = QQmlFile::urlToLocalFileOrQrc(url);
- const QString localCachePath = localSourcePath + QLatin1Char('c');
- if (QFileInfo(QFileInfo(localSourcePath).dir().absolutePath()).isWritable())
- return localCachePath;
- QCryptographicHash fileNameHash(QCryptographicHash::Sha1);
- fileNameHash.addData(localSourcePath.toUtf8());
- QString directory = QStandardPaths::writableLocation(QStandardPaths::CacheLocation) + QLatin1String("/qmlcache/");
- QDir::root().mkpath(directory);
- return directory + QString::fromUtf8(fileNameHash.result().toHex()) + QLatin1Char('.') + QFileInfo(localCachePath).completeSuffix();
+ if (!QQmlFile::isLocalFile(url)) {
+ *errorString = QStringLiteral("File has to be a local file.");
+ return false;
+ }
+
+ const QString sourcePath = QQmlFile::urlToLocalFileOrQrc(url);
+ QScopedPointer<CompilationUnitMapper> cacheFile(new CompilationUnitMapper());
+
+ CompiledData::Unit *mappedUnit = cacheFile->open(cacheFilePath(url), sourcePath, errorString);
+ if (!mappedUnit)
+ return false;
+
+ const Unit * const oldDataPtr = (data && !(data->flags & QV4::CompiledData::Unit::StaticData)) ? data : nullptr;
+ QScopedValueRollback<const Unit *> dataPtrChange(data, mappedUnit);
+
+ if (sourcePath != QQmlFile::urlToLocalFileOrQrc(stringAt(data->sourceFileIndex))) {
+ *errorString = QStringLiteral("QML source file has moved to a different location.");
+ return false;
+ }
+
+ {
+ const QString foundArchitecture = stringAt(data->architectureIndex);
+ const QString expectedArchitecture = QSysInfo::buildAbi();
+ if (foundArchitecture != expectedArchitecture) {
+ *errorString = QString::fromUtf8("Architecture mismatch. Found %1 expected %2").arg(foundArchitecture).arg(expectedArchitecture);
+ return false;
+ }
+ }
+
+ {
+ const QString foundCodeGenerator = stringAt(data->codeGeneratorIndex);
+ const QString expectedCodeGenerator = iselFactory->codeGeneratorName;
+ if (foundCodeGenerator != expectedCodeGenerator) {
+ *errorString = QString::fromUtf8("Code generator mismatch. Found code generated by %1 but expected %2").arg(foundCodeGenerator).arg(expectedCodeGenerator);
+ return false;
+ }
+ }
+
+ if (!memoryMapCode(errorString))
+ return false;
+
+ dataPtrChange.commit();
+ free(const_cast<Unit*>(oldDataPtr));
+ backingFile.reset(cacheFile.take());
+ return true;
+}
+
+bool CompilationUnit::memoryMapCode(QString *errorString)
+{
+ *errorString = QStringLiteral("Missing code mapping backend");
+ return false;
}
+#endif // V4_BOOTSTRAP
+
+#if defined(V4_BOOTSTRAP)
+bool CompilationUnit::saveToDisk(const QString &unitUrl, QString *errorString)
+#else
bool CompilationUnit::saveToDisk(const QUrl &unitUrl, QString *errorString)
+#endif
{
errorString->clear();
@@ -351,10 +420,12 @@ bool CompilationUnit::saveToDisk(const QUrl &unitUrl, QString *errorString)
return false;
}
+#if !defined(V4_BOOTSTRAP)
if (!QQmlFile::isLocalFile(unitUrl)) {
*errorString = QStringLiteral("File has to be a local file.");
return false;
}
+#endif
// Foo.qml -> Foo.qmlc
QSaveFile cacheFile(cacheFilePath(unitUrl));
@@ -390,78 +461,105 @@ bool CompilationUnit::saveToDisk(const QUrl &unitUrl, QString *errorString)
return true;
}
-bool CompilationUnit::loadFromDisk(const QUrl &url, EvalISelFactory *iselFactory, QString *errorString)
+void CompilationUnit::prepareCodeOffsetsForDiskStorage(Unit *unit)
{
- if (!QQmlFile::isLocalFile(url)) {
- *errorString = QStringLiteral("File has to be a local file.");
- return false;
- }
+ Q_UNUSED(unit);
+}
- const QString sourcePath = QQmlFile::urlToLocalFileOrQrc(url);
- QScopedPointer<CompilationUnitMapper> cacheFile(new CompilationUnitMapper());
+bool CompilationUnit::saveCodeToDisk(QIODevice *device, const Unit *unit, QString *errorString)
+{
+ Q_UNUSED(device);
+ Q_UNUSED(unit);
+ *errorString = QStringLiteral("Saving code to disk is not supported in this configuration");
+ return false;
+}
- CompiledData::Unit *mappedUnit = cacheFile->open(cacheFilePath(url), sourcePath, errorString);
- if (!mappedUnit)
- return false;
+Unit *CompilationUnit::createUnitData(QmlIR::Document *irDocument)
+{
+ if (!irDocument->javaScriptCompilationUnit->data)
+ return irDocument->jsGenerator.generateUnit(QV4::Compiler::JSUnitGenerator::GenerateWithoutStringTable);
- const Unit * const oldDataPtr = (data && !(data->flags & QV4::CompiledData::Unit::StaticData)) ? data : nullptr;
- QScopedValueRollback<const Unit *> dataPtrChange(data, mappedUnit);
+ QQmlRefPointer<QV4::CompiledData::CompilationUnit> compilationUnit = irDocument->javaScriptCompilationUnit;
+ QV4::CompiledData::Unit *jsUnit = const_cast<QV4::CompiledData::Unit*>(irDocument->javaScriptCompilationUnit->data);
- if (sourcePath != QQmlFile::urlToLocalFileOrQrc(stringAt(data->sourceFileIndex))) {
- *errorString = QStringLiteral("QML source file has moved to a different location.");
- return false;
- }
+ QV4::Compiler::StringTableGenerator &stringTable = irDocument->jsGenerator.stringTable;
- {
- const QString foundArchitecture = stringAt(data->architectureIndex);
- const QString expectedArchitecture = QSysInfo::buildAbi();
- if (foundArchitecture != expectedArchitecture) {
- *errorString = QString::fromUtf8("Architecture mismatch. Found %1 expected %2").arg(foundArchitecture).arg(expectedArchitecture);
- return false;
+ // Collect signals that have had a change in signature (from onClicked to onClicked(mouse) for example)
+ // and now need fixing in the QV4::CompiledData. Also register strings at the same time, to finalize
+ // the string table.
+ QVector<quint32> changedSignals;
+ QVector<QQmlJS::AST::FormalParameterList*> changedSignalParameters;
+ for (QmlIR::Object *o: qAsConst(irDocument->objects)) {
+ for (QmlIR::Binding *binding = o->firstBinding(); binding; binding = binding->next) {
+ if (!(binding->flags & QV4::CompiledData::Binding::IsSignalHandlerExpression))
+ continue;
+
+ quint32 functionIndex = binding->value.compiledScriptIndex;
+ QmlIR::CompiledFunctionOrExpression *foe = o->functionsAndExpressions->slowAt(functionIndex);
+ if (!foe)
+ continue;
+
+ // save absolute index
+ changedSignals << o->runtimeFunctionIndices.at(functionIndex);
+
+ Q_ASSERT(foe->node);
+ Q_ASSERT(QQmlJS::AST::cast<QQmlJS::AST::FunctionDeclaration*>(foe->node));
+
+ QQmlJS::AST::FormalParameterList *parameters = QQmlJS::AST::cast<QQmlJS::AST::FunctionDeclaration*>(foe->node)->formals;
+ changedSignalParameters << parameters;
+
+ for (; parameters; parameters = parameters->next)
+ stringTable.registerString(parameters->name.toString());
}
}
- {
- const QString foundCodeGenerator = stringAt(data->codeGeneratorIndex);
- const QString expectedCodeGenerator = iselFactory->codeGeneratorName;
- if (foundCodeGenerator != expectedCodeGenerator) {
- *errorString = QString::fromUtf8("Code generator mismatch. Found code generated by %1 but expected %2").arg(foundCodeGenerator).arg(expectedCodeGenerator);
- return false;
+ QVector<quint32> signalParameterNameTable;
+ quint32 signalParameterNameTableOffset = jsUnit->unitSize;
+
+ // Update signal signatures
+ if (!changedSignals.isEmpty()) {
+ if (jsUnit == compilationUnit->data) {
+ char *unitCopy = (char*)malloc(jsUnit->unitSize);
+ memcpy(unitCopy, jsUnit, jsUnit->unitSize);
+ jsUnit = reinterpret_cast<QV4::CompiledData::Unit*>(unitCopy);
}
- }
- if (!memoryMapCode(errorString))
- return false;
+ for (int i = 0; i < changedSignals.count(); ++i) {
+ const uint functionIndex = changedSignals.at(i);
+ // The data is now read-write due to the copy above, so the const_cast is ok.
+ QV4::CompiledData::Function *function = const_cast<QV4::CompiledData::Function *>(jsUnit->functionAt(functionIndex));
+ Q_ASSERT(function->nFormals == quint32(0));
- dataPtrChange.commit();
- free(const_cast<Unit*>(oldDataPtr));
- backingFile.reset(cacheFile.take());
- return true;
-}
+ function->formalsOffset = signalParameterNameTableOffset - jsUnit->functionOffsetTable()[functionIndex];
-void CompilationUnit::prepareCodeOffsetsForDiskStorage(Unit *unit)
-{
- Q_UNUSED(unit);
-}
+ for (QQmlJS::AST::FormalParameterList *parameters = changedSignalParameters.at(i);
+ parameters; parameters = parameters->next) {
+ signalParameterNameTable.append(stringTable.getStringId(parameters->name.toString()));
+ function->nFormals = function->nFormals + 1;
+ }
-bool CompilationUnit::saveCodeToDisk(QIODevice *device, const Unit *unit, QString *errorString)
-{
- Q_UNUSED(device);
- Q_UNUSED(unit);
- *errorString = QStringLiteral("Saving code to disk is not supported in this configuration");
- return false;
-}
+ // Hack to ensure an activation is created.
+ function->flags |= QV4::CompiledData::Function::HasCatchOrWith | QV4::CompiledData::Function::HasDirectEval;
-bool CompilationUnit::memoryMapCode(QString *errorString)
-{
- *errorString = QStringLiteral("Missing code mapping backend");
- return false;
-}
-#endif // V4_BOOTSTRAP
+ signalParameterNameTableOffset += function->nFormals * sizeof(quint32);
+ }
+ }
-Unit *CompilationUnit::createUnitData(QmlIR::Document *irDocument)
-{
- return irDocument->jsGenerator.generateUnit(QV4::Compiler::JSUnitGenerator::GenerateWithoutStringTable);
+ if (!signalParameterNameTable.isEmpty()) {
+ Q_ASSERT(jsUnit != compilationUnit->data);
+ const uint signalParameterTableSize = signalParameterNameTable.count() * sizeof(quint32);
+ uint newSize = jsUnit->unitSize + signalParameterTableSize;
+ const uint oldSize = jsUnit->unitSize;
+ char *unitWithSignalParameters = (char*)realloc(jsUnit, newSize);
+ memcpy(unitWithSignalParameters + oldSize, signalParameterNameTable.constData(), signalParameterTableSize);
+ jsUnit = reinterpret_cast<QV4::CompiledData::Unit*>(unitWithSignalParameters);
+ jsUnit->unitSize = newSize;
+ }
+
+ if (jsUnit != compilationUnit->data)
+ jsUnit->flags &= ~QV4::CompiledData::Unit::StaticData;
+
+ return jsUnit;
}
QString Binding::valueAsString(const Unit *unit) const
@@ -624,7 +722,7 @@ static QByteArray ownLibraryChecksum()
if (checksumInitialized)
return libraryChecksum;
checksumInitialized = true;
-#if defined(Q_OS_UNIX) && !defined(QT_NO_DYNAMIC_CAST)
+#if defined(Q_OS_UNIX) && !defined(QT_NO_DYNAMIC_CAST) && !defined(Q_OS_INTEGRITY)
Dl_info libInfo;
if (dladdr(reinterpret_cast<const void *>(&ownLibraryChecksum), &libInfo) != 0) {
QFile library(QFile::decodeName(libInfo.dli_fname));