Various cleanups
authorSimon Hausmann <simon.hausmann@digia.com>
Thu, 27 Mar 2014 16:07:06 +0000 (17:07 +0100)
committerThe Qt Project <gerrit-noreply@qt-project.org>
Fri, 28 Mar 2014 14:07:03 +0000 (15:07 +0100)
* Encapsulate the string pooling for the V4 data generation into a StringGenerator class.
* Move type reference collection into the IR::Document, where it belongs (as it writes
  into the typeReferences there)
* const fixes
* Remove unused methods and members
* Store unit and qml unit sizes right in the generated data structure. That makes copying
  easier (like we do when generating the QML data based on the JS fields)

Change-Id: I053146ab0b00cc90ac7f72f867415962d1be121b
Reviewed-by: Lars Knoll <lars.knoll@digia.com>
src/qml/compiler/qqmlirbuilder.cpp
src/qml/compiler/qqmlirbuilder_p.h
src/qml/compiler/qqmltypecompiler.cpp
src/qml/compiler/qqmltypecompiler_p.h
src/qml/compiler/qv4compileddata.cpp
src/qml/compiler/qv4compileddata_p.h
src/qml/compiler/qv4compiler.cpp
src/qml/compiler/qv4compiler_p.h
src/qml/qml/qqmltypeloader.cpp
src/qml/qml/qqmltypeloader_p.h

index bd0aedf089fdc82f64452b0337913cfe2bcabc68..e85703e9aa1ab8dec186b8e264d276989b4609b0 100644 (file)
@@ -188,12 +188,12 @@ void Object::insertSorted(Binding *b)
     bindings->insertAfter(insertionPoint, b);
 }
 
-QStringList Signal::parameterStringList(const QStringList &stringPool) const
+QStringList Signal::parameterStringList(const QV4::Compiler::StringTableGenerator *stringPool) const
 {
     QStringList result;
     result.reserve(parameters->count);
     for (SignalParameter *param = parameters->first; param; param = param->next)
-        result << stringPool.at(param->nameIndex);
+        result << stringPool->stringForIndex(param->nameIndex);
     return result;
 }
 
@@ -259,6 +259,32 @@ static inline bool isUriToken(int token)
     return false;
 }
 
+void Document::collectTypeReferences()
+{
+    foreach (Object *obj, objects) {
+        if (obj->inheritedTypeNameIndex != emptyStringIndex) {
+            QV4::CompiledData::TypeReference &r = typeReferences.add(obj->inheritedTypeNameIndex, obj->location);
+            r.needsCreation = true;
+            r.errorWhenNotFound = true;
+        }
+
+        for (const Property *prop = obj->firstProperty(); prop; prop = prop->next) {
+            if (prop->type >= QV4::CompiledData::Property::Custom) {
+                // ### FIXME: We could report the more accurate location here by using prop->location, but the old
+                // compiler can't and the tests expect it to be the object location right now.
+                QV4::CompiledData::TypeReference &r = typeReferences.add(prop->customTypeNameIndex, obj->location);
+                r.needsCreation = true;
+                r.errorWhenNotFound = true;
+            }
+        }
+
+        for (const Binding *binding = obj->firstBinding(); binding; binding = binding->next) {
+            if (binding->type == QV4::CompiledData::Binding::Type_AttachedProperty)
+                typeReferences.add(binding->propertyNameIndex, binding->location);
+        }
+    }
+}
+
 void Document::extractScriptMetaData(QString &script, QQmlError *error)
 {
     Q_ASSERT(error);
@@ -504,6 +530,15 @@ void Document::removeScriptPragmas(QString &script)
     }
 }
 
+Document::Document(bool debugMode)
+    : jsModule(debugMode)
+    , program(0)
+    , jsGenerator(&jsModule, sizeof(QV4::CompiledData::QmlUnit))
+    , unitFlags(0)
+    , javaScriptCompilationUnit(0)
+{
+}
+
 IRBuilder::IRBuilder(const QSet<QString> &illegalNames)
     : illegalNames(illegalNames)
     , _object(0)
@@ -546,7 +581,6 @@ bool IRBuilder::generateFromQml(const QString &code, const QUrl &url, const QStr
     qSwap(_imports, output->imports);
     qSwap(_pragmas, output->pragmas);
     qSwap(_objects, output->objects);
-    qSwap(_typeReferences, output->typeReferences);
     this->pool = output->jsParserEngine.pool();
     this->jsGenerator = &output->jsGenerator;
 
@@ -565,13 +599,11 @@ bool IRBuilder::generateFromQml(const QString &code, const QUrl &url, const QStr
 
     QQmlJS::AST::UiObjectDefinition *rootObject = QQmlJS::AST::cast<QQmlJS::AST::UiObjectDefinition*>(program->members->member);
     Q_ASSERT(rootObject);
-    if (defineQMLObject(&output->indexOfRootObject, rootObject))
-        collectTypeReferences();
+    defineQMLObject(&output->indexOfRootObject, rootObject);
 
     qSwap(_imports, output->imports);
     qSwap(_pragmas, output->pragmas);
     qSwap(_objects, output->objects);
-    qSwap(_typeReferences, output->typeReferences);
     return errors.isEmpty();
 }
 
@@ -789,10 +821,10 @@ bool IRBuilder::visit(QQmlJS::AST::UiImport *node)
         // Check for script qualifier clashes
         bool isScript = import->type == QV4::CompiledData::Import::ImportScript;
         for (int ii = 0; ii < _imports.count(); ++ii) {
-            QV4::CompiledData::Import *other = _imports.at(ii);
+            const QV4::CompiledData::Import *other = _imports.at(ii);
             bool otherIsScript = other->type == QV4::CompiledData::Import::ImportScript;
 
-            if ((isScript || otherIsScript) && qualifier == jsGenerator->strings.at(other->qualifierIndex)) {
+            if ((isScript || otherIsScript) && qualifier == jsGenerator->stringForIndex(other->qualifierIndex)) {
                 recordError(node->importIdToken, QCoreApplication::translate("QQmlParser","Script import qualifiers must be unique."));
                 return false;
             }
@@ -1372,7 +1404,7 @@ bool IRBuilder::resolveQualifiedId(QQmlJS::AST::UiQualifiedId **nameToResolve, O
     // If it's a namespace, prepend the qualifier and we'll resolve it later to the correct type.
     QString currentName = qualifiedIdElement->name.toString();
     if (qualifiedIdElement->next) {
-        foreach (QV4::CompiledData::Import* import, _imports)
+        foreach (const QV4::CompiledData::Import* import, _imports)
             if (import->qualifierIndex != emptyStringIndex
                 && stringAt(import->qualifierIndex) == currentName) {
                 qualifiedIdElement = qualifiedIdElement->next;
@@ -1451,32 +1483,6 @@ void IRBuilder::recordError(const QQmlJS::AST::SourceLocation &location, const Q
     errors << error;
 }
 
-void IRBuilder::collectTypeReferences()
-{
-    foreach (Object *obj, _objects) {
-        if (obj->inheritedTypeNameIndex != emptyStringIndex) {
-            QV4::CompiledData::TypeReference &r = _typeReferences.add(obj->inheritedTypeNameIndex, obj->location);
-            r.needsCreation = true;
-            r.errorWhenNotFound = true;
-        }
-
-        for (const Property *prop = obj->firstProperty(); prop; prop = prop->next) {
-            if (prop->type >= QV4::CompiledData::Property::Custom) {
-                // ### FIXME: We could report the more accurate location here by using prop->location, but the old
-                // compiler can't and the tests expect it to be the object location right now.
-                QV4::CompiledData::TypeReference &r = _typeReferences.add(prop->customTypeNameIndex, obj->location);
-                r.needsCreation = true;
-                r.errorWhenNotFound = true;
-            }
-        }
-
-        for (const Binding *binding = obj->firstBinding(); binding; binding = binding->next) {
-            if (binding->type == QV4::CompiledData::Binding::Type_AttachedProperty)
-                _typeReferences.add(binding->propertyNameIndex, binding->location);
-        }
-    }
-}
-
 bool IRBuilder::isStatementNodeScript(QQmlJS::AST::Statement *statement)
 {
     if (QQmlJS::AST::ExpressionStatement *stmt = QQmlJS::AST::cast<QQmlJS::AST::ExpressionStatement *>(statement)) {
@@ -1502,11 +1508,11 @@ bool IRBuilder::isStatementNodeScript(QQmlJS::AST::Statement *statement)
     return true;
 }
 
-QV4::CompiledData::QmlUnit *QmlUnitGenerator::generate(Document &output, int *totalUnitSizeInBytes)
+QV4::CompiledData::QmlUnit *QmlUnitGenerator::generate(Document &output)
 {
-    jsUnitGenerator = &output.jsGenerator;
-    int unitSize = 0;
-    QV4::CompiledData::Unit *jsUnit = jsUnitGenerator->generateUnit(&unitSize);
+    QV4::CompiledData::CompilationUnit *compilationUnit = output.javaScriptCompilationUnit;
+    QV4::CompiledData::Unit *jsUnit = compilationUnit->createUnitData(&output);
+    const uint unitSize = jsUnit->unitSize;
 
     const int importSize = sizeof(QV4::CompiledData::Import) * output.imports.count();
     const int objectOffsetTableSize = output.objects.count() * sizeof(quint32);
@@ -1526,14 +1532,14 @@ QV4::CompiledData::QmlUnit *QmlUnitGenerator::generate(Document &output, int *to
     }
 
     const int totalSize = unitSize + importSize + objectOffsetTableSize + objectsSize;
-    if (totalUnitSizeInBytes)
-        *totalUnitSizeInBytes = totalSize;
     char *data = (char*)malloc(totalSize);
     memcpy(data, jsUnit, unitSize);
-    free(jsUnit);
+    if (jsUnit != compilationUnit->data)
+        free(jsUnit);
     jsUnit = 0;
 
     QV4::CompiledData::QmlUnit *qmlUnit = reinterpret_cast<QV4::CompiledData::QmlUnit *>(data);
+    qmlUnit->qmlUnitSize = totalSize;
     qmlUnit->header.flags |= output.unitFlags;
     qmlUnit->header.flags |= QV4::CompiledData::Unit::IsQml;
     qmlUnit->offsetToImports = unitSize;
@@ -1544,7 +1550,7 @@ QV4::CompiledData::QmlUnit *QmlUnitGenerator::generate(Document &output, int *to
 
     // write imports
     char *importPtr = data + qmlUnit->offsetToImports;
-    foreach (QV4::CompiledData::Import *imp, output.imports) {
+    foreach (const QV4::CompiledData::Import *imp, output.imports) {
         QV4::CompiledData::Import *importToWrite = reinterpret_cast<QV4::CompiledData::Import*>(importPtr);
         *importToWrite = *imp;
         importPtr += sizeof(QV4::CompiledData::Import);
@@ -1649,13 +1655,8 @@ char *QmlUnitGenerator::writeBindings(char *bindingPtr, Object *o, BindingFilter
     return bindingPtr;
 }
 
-int QmlUnitGenerator::getStringId(const QString &str) const
-{
-    return jsUnitGenerator->getStringId(str);
-}
-
 JSCodeGen::JSCodeGen(const QString &fileName, const QString &sourceCode, QV4::IR::Module *jsModule, QQmlJS::Engine *jsEngine,
-                     QQmlJS::AST::UiProgram *qmlRoot, QQmlTypeNameCache *imports, const QStringList &stringPool)
+                     QQmlJS::AST::UiProgram *qmlRoot, QQmlTypeNameCache *imports, const QV4::Compiler::StringTableGenerator *stringPool)
     : QQmlJS::Codegen(/*strict mode*/false)
     , sourceCode(sourceCode)
     , jsEngine(jsEngine)
@@ -1723,7 +1724,7 @@ QVector<int> JSCodeGen::generateJSCodeForFunctionsAndBindings(const QList<Compil
         if (function)
             name = function->name.toString();
         else if (qmlFunction.nameIndex != 0)
-            name = stringPool.value(qmlFunction.nameIndex);
+            name = stringPool->stringForIndex(qmlFunction.nameIndex);
         else
             name = QStringLiteral("%qml-expression-entry");
 
index a34529067294ea94ce7f62f366b5d049de6fff14..cd67c52ed7448953fbbe20dc0ea99bcb6b11d2d4 100644 (file)
@@ -60,6 +60,9 @@ class QQmlTypeNameCache;
 
 namespace QmlIR {
 
+struct Document;
+struct IRLoader;
+
 template <typename T>
 struct PoolList
 {
@@ -199,7 +202,7 @@ struct Signal
     QV4::CompiledData::Location location;
     PoolList<SignalParameter> *parameters;
 
-    QStringList parameterStringList(const QStringList &stringPool) const;
+    QStringList parameterStringList(const QV4::Compiler::StringTableGenerator *stringPool) const;
 
     Signal *next;
 };
@@ -285,6 +288,8 @@ public:
     FixedPoolArray<int> *runtimeFunctionIndices;
 
 private:
+    friend struct IRLoader;
+
     PoolList<Property> *properties;
     PoolList<Signal> *qmlSignals;
     PoolList<Binding> *bindings;
@@ -303,15 +308,11 @@ struct Q_QML_EXPORT Pragma
 
 struct Q_QML_EXPORT Document
 {
-    Document(bool debugMode)
-        : jsModule(debugMode)
-        , jsGenerator(&jsModule, sizeof(QV4::CompiledData::QmlUnit))
-        , unitFlags(0)
-    {}
+    Document(bool debugMode);
     QString code;
     QQmlJS::Engine jsParserEngine;
     QV4::IR::Module jsModule;
-    QList<QV4::CompiledData::Import*> imports;
+    QList<const QV4::CompiledData::Import *> imports;
     QList<Pragma*> pragmas;
     QQmlJS::AST::UiProgram *program;
     int indexOfRootObject;
@@ -319,10 +320,14 @@ struct Q_QML_EXPORT Document
     QV4::Compiler::JSUnitGenerator jsGenerator;
     quint32 unitFlags;
 
+    QV4::CompiledData::CompilationUnit *javaScriptCompilationUnit;
+    QHash<int, QStringList> extraSignalParameters;
+
     QV4::CompiledData::TypeReferenceMap typeReferences;
+    void collectTypeReferences();
 
     int registerString(const QString &str) { return jsGenerator.registerString(str); }
-    QString stringAt(int index) const { return jsGenerator.strings.value(index); }
+    QString stringAt(int index) const { return jsGenerator.stringForIndex(index); }
 
     void extractScriptMetaData(QString &script, QQmlError *error);
     static void removeScriptPragmas(QString &script);
@@ -388,12 +393,10 @@ public:
 
     void recordError(const QQmlJS::AST::SourceLocation &location, const QString &description);
 
-    void collectTypeReferences();
-
     quint32 registerString(const QString &str) const { return jsGenerator->registerString(str); }
     template <typename _Tp> _Tp *New() { return pool->New<_Tp>(); }
 
-    QString stringAt(int index) const { return jsGenerator->strings.at(index); }
+    QString stringAt(int index) const { return jsGenerator->stringForIndex(index); }
 
     static bool isStatementNodeScript(QQmlJS::AST::Statement *statement);
 
@@ -401,7 +404,7 @@ public:
 
     QSet<QString> illegalNames;
 
-    QList<QV4::CompiledData::Import*> _imports;
+    QList<const QV4::CompiledData::Import *> _imports;
     QList<Pragma*> _pragmas;
     QList<Object*> _objects;
 
@@ -418,20 +421,11 @@ public:
 
 struct Q_QML_EXPORT QmlUnitGenerator
 {
-    QmlUnitGenerator()
-        : jsUnitGenerator(0)
-    {
-    }
-
-    QV4::CompiledData::QmlUnit *generate(Document &output, int *totalUnitSizeInBytes = 0);
+    QV4::CompiledData::QmlUnit *generate(Document &output);
 
 private:
     typedef bool (Binding::*BindingFilter)() const;
     char *writeBindings(char *bindingPtr, Object *o, BindingFilter filter) const;
-
-    int getStringId(const QString &str) const;
-
-    QV4::Compiler::JSUnitGenerator *jsUnitGenerator;
 };
 
 struct Q_QML_EXPORT PropertyResolver
@@ -457,7 +451,7 @@ struct Q_QML_EXPORT JSCodeGen : public QQmlJS::Codegen
 {
     JSCodeGen(const QString &fileName, const QString &sourceCode, QV4::IR::Module *jsModule,
               QQmlJS::Engine *jsEngine, QQmlJS::AST::UiProgram *qmlRoot, QQmlTypeNameCache *imports,
-              const QStringList &stringPool);
+              const QV4::Compiler::StringTableGenerator *stringPool);
 
     struct IdMapping
     {
@@ -484,7 +478,7 @@ private:
     QQmlJS::Engine *jsEngine; // needed for memory pool
     QQmlJS::AST::UiProgram *qmlRoot;
     QQmlTypeNameCache *imports;
-    const QStringList &stringPool;
+    const QV4::Compiler::StringTableGenerator *stringPool;
 
     bool _disableAcceleratedLookups;
     ObjectIdMapping _idObjects;
index 26f6e0b74f2d933e60a2c19cc10e50d5bd5aa54e..224bd23898e92c724d792d4393769140d9d6d00e 100644 (file)
@@ -202,37 +202,32 @@ bool QQmlTypeCompiler::compile()
     }
 
     // Compile JS binding expressions and signal handlers
-    {
-        QmlIR::JSCodeGen v4CodeGenerator(typeData->finalUrlString(), document->code, &document->jsModule, &document->jsParserEngine, document->program, compiledData->importCache, document->jsGenerator.strings);
+    if (!document->javaScriptCompilationUnit) {
+        QmlIR::JSCodeGen v4CodeGenerator(typeData->finalUrlString(), document->code, &document->jsModule, &document->jsParserEngine, document->program, compiledData->importCache, &document->jsGenerator.stringTable);
         QQmlJSCodeGenerator jsCodeGen(this, &v4CodeGenerator);
         if (!jsCodeGen.generateCodeForComponents())
             return false;
-    }
 
-    {
         QQmlJavaScriptBindingExpressionSimplificationPass pass(this);
         pass.reduceTranslationBindings();
-    }
 
-    QV4::ExecutionEngine *v4 = engine->v4engine();
-
-    QScopedPointer<QV4::EvalInstructionSelection> isel(v4->iselFactory->create(engine, v4->executableAllocator, &document->jsModule, &document->jsGenerator));
-    isel->setUseFastLookups(false);
-    QV4::CompiledData::CompilationUnit *jsUnit = isel->compile(/*generated unit data*/false);
+        QV4::ExecutionEngine *v4 = engine->v4engine();
+        QScopedPointer<QV4::EvalInstructionSelection> isel(v4->iselFactory->create(engine, v4->executableAllocator, &document->jsModule, &document->jsGenerator));
+        isel->setUseFastLookups(false);
+        document->javaScriptCompilationUnit = isel->compile(/*generated unit data*/false);
+    }
 
     // Generate QML compiled type data structures
 
     QmlIR::QmlUnitGenerator qmlGenerator;
     QV4::CompiledData::QmlUnit *qmlUnit = qmlGenerator.generate(*document);
 
-    if (jsUnit) {
-        Q_ASSERT(!jsUnit->data);
-        Q_ASSERT((void*)qmlUnit == (void*)&qmlUnit->header);
-        // The js unit owns the data and will free the qml unit.
-        jsUnit->data = &qmlUnit->header;
-    }
+    Q_ASSERT(document->javaScriptCompilationUnit);
+    Q_ASSERT((void*)qmlUnit == (void*)&qmlUnit->header);
+    // The js unit owns the data and will free the qml unit.
+    document->javaScriptCompilationUnit->data = &qmlUnit->header;
 
-    compiledData->compilationUnit = jsUnit;
+    compiledData->compilationUnit = document->javaScriptCompilationUnit;
     if (compiledData->compilationUnit)
         compiledData->compilationUnit->ref();
     compiledData->qmlUnit = qmlUnit; // ownership transferred to m_compiledData
@@ -383,9 +378,9 @@ QStringRef QQmlTypeCompiler::newStringRef(const QString &string)
     return document->jsParserEngine.newStringRef(string);
 }
 
-const QStringList &QQmlTypeCompiler::stringPool() const
+const QV4::Compiler::StringTableGenerator *QQmlTypeCompiler::stringPool() const
 {
-    return document->jsGenerator.strings;
+    return &document->jsGenerator.stringTable;
 }
 
 void QQmlTypeCompiler::setCustomParserBindings(const QVector<int> &bindings)
index e21c13c5df3de9e1fbd7eab4268212e27ce50e9d..ca84cee1f89729d47b187141be3f2332fb4db695 100644 (file)
@@ -99,7 +99,7 @@ public:
     QHash<int, QQmlCompiledData::CustomParserData> *customParserData();
     QQmlJS::MemoryPool *memoryPool();
     QStringRef newStringRef(const QString &string);
-    const QStringList &stringPool() const;
+    const QV4::Compiler::StringTableGenerator *stringPool() const;
     void setCustomParserBindings(const QVector<int> &bindings);
     void setDeferredBindingsPerObject(const QHash<int, QBitArray> &deferredBindingsPerObject);
 
index 2220fd5de5a12b93ffb32d063c1aa54c2d3ac241..56497ed8a35cd91977c3fdd41aaee5735cae80bf 100644 (file)
@@ -46,6 +46,7 @@
 #include <private/qv4objectproto_p.h>
 #include <private/qv4lookup_p.h>
 #include <private/qv4regexpobject_p.h>
+#include <private/qqmlirbuilder_p.h>
 #include <QCoreApplication>
 
 #include <algorithm>
@@ -180,6 +181,11 @@ void CompilationUnit::markObjects(QV4::ExecutionEngine *e)
     }
 }
 
+Unit *CompilationUnit::createUnitData(QmlIR::Document *irDocument)
+{
+    return irDocument->jsGenerator.generateUnit();
+}
+
 QString Binding::valueAsString(const Unit *unit) const
 {
     switch (type) {
index 474d4c88bc7f1490dacdb3ed8b1b67b1adf48152..d6d2419d74b590c1b29a37be26b449805a150e3f 100644 (file)
 
 QT_BEGIN_NAMESPACE
 
+namespace QmlIR {
+struct Document;
+}
+
 namespace QV4 {
 namespace IR {
 struct Function;
@@ -163,6 +167,7 @@ struct Unit
     char magic[8];
     qint16 architecture;
     qint16 version;
+    quint32 unitSize; // Size of the Unit and any depending data. Does _not_ include size of data needed by QmlUnit.
 
     enum {
         IsJavascript = 0x1,
@@ -198,8 +203,10 @@ struct Unit
         return QString(qstr.constData(), qstr.length());
     }
 
+    const uint *functionOffsetTable() const { return reinterpret_cast<const uint*>((reinterpret_cast<const char *>(this)) + offsetToFunctionTable); }
+
     const Function *functionAt(int idx) const {
-        const uint *offsetTable = reinterpret_cast<const uint*>((reinterpret_cast<const char *>(this)) + offsetToFunctionTable);
+        const uint *offsetTable = functionOffsetTable();
         const uint offset = offsetTable[idx];
         return reinterpret_cast<const Function*>(reinterpret_cast<const char *>(this) + offset);
     }
@@ -524,6 +531,7 @@ struct Import
 struct QmlUnit
 {
     Unit header;
+    quint32 qmlUnitSize; // size including header and all surrounding data.
     quint32 nImports;
     quint32 offsetToImports;
     quint32 nObjects;
@@ -578,16 +586,15 @@ struct Q_QML_EXPORT CompilationUnit
     QV4::Value *runtimeRegularExpressions;
     QV4::InternalClass **runtimeClasses;
     QVector<QV4::Function *> runtimeFunctions;
-//    QVector<QV4::Function *> runtimeFunctionsSortedByAddress;
+
+    // Called only when building QML, when we build the header for JS first and append QML data
+    virtual QV4::CompiledData::Unit *createUnitData(QmlIR::Document *irDocument);
 
     QV4::Function *linkToEngine(QV4::ExecutionEngine *engine);
     void unlink();
 
     virtual QV4::ExecutableAllocator::ChunkOfPages *chunkForFunction(int /*functionIndex*/) { return 0; }
 
-    // ### runtime data
-    // pointer to qml data for QML unit
-
     void markObjects(QV4::ExecutionEngine *e);
 
 protected:
index f25b1900cee9695f0a813c0544ec83770c4570bd..0338bf1840251cbf57452b65de521e5604b14235 100644 (file)
 #include <qv4engine_p.h>
 #include <private/qqmlpropertycache_p.h>
 
-QV4::Compiler::JSUnitGenerator::JSUnitGenerator(QV4::IR::Module *module, int headerSize)
-    : irModule(module)
-    , stringDataSize(0)
-    , jsClassDataSize(0)
+QV4::Compiler::StringTableGenerator::StringTableGenerator()
 {
-    if (headerSize == -1)
-        headerSize = sizeof(QV4::CompiledData::Unit);
-    this->headerSize = headerSize;
-    // Make sure the empty string always gets index 0
-    registerString(QString());
+    clear();
 }
 
-int QV4::Compiler::JSUnitGenerator::registerString(const QString &str)
+int QV4::Compiler::StringTableGenerator::registerString(const QString &str)
 {
     QHash<QString, int>::ConstIterator it = stringToId.find(str);
     if (it != stringToId.end())
@@ -68,12 +61,50 @@ int QV4::Compiler::JSUnitGenerator::registerString(const QString &str)
     return strings.size() - 1;
 }
 
-int QV4::Compiler::JSUnitGenerator::getStringId(const QString &string) const
+int QV4::Compiler::StringTableGenerator::getStringId(const QString &string) const
 {
     Q_ASSERT(stringToId.contains(string));
     return stringToId.value(string);
 }
 
+void QV4::Compiler::StringTableGenerator::clear()
+{
+    strings.clear();
+    stringToId.clear();
+    stringDataSize = 0;
+}
+
+void QV4::Compiler::StringTableGenerator::serialize(uint *stringTable, char *dataStart, char *stringData)
+{
+    for (int i = 0; i < strings.size(); ++i) {
+        stringTable[i] = stringData - dataStart;
+        const QString &qstr = strings.at(i);
+
+        QV4::CompiledData::String *s = (QV4::CompiledData::String*)(stringData);
+        s->hash = QV4::String::createHashValue(qstr.constData(), qstr.length());
+        s->flags = 0; // ###
+        s->str.ref.atomic.store(-1);
+        s->str.size = qstr.length();
+        s->str.alloc = 0;
+        s->str.capacityReserved = false;
+        s->str.offset = sizeof(QArrayData);
+        memcpy(s + 1, qstr.constData(), (qstr.length() + 1)*sizeof(ushort));
+
+        stringData += QV4::CompiledData::String::calculateSize(qstr);
+    }
+}
+
+QV4::Compiler::JSUnitGenerator::JSUnitGenerator(QV4::IR::Module *module, int headerSize)
+    : irModule(module)
+    , jsClassDataSize(0)
+{
+    if (headerSize == -1)
+        headerSize = sizeof(QV4::CompiledData::Unit);
+    this->headerSize = headerSize;
+    // Make sure the empty string always gets index 0
+    registerString(QString());
+}
+
 uint QV4::Compiler::JSUnitGenerator::registerIndexedGetterLookup()
 {
     CompiledData::Lookup l;
@@ -175,7 +206,7 @@ int QV4::Compiler::JSUnitGenerator::registerJSClass(int count, IR::ExprList *arg
     return jsClasses.size() - 1;
 }
 
-QV4::CompiledData::Unit *QV4::Compiler::JSUnitGenerator::generateUnit(int *totalUnitSize)
+QV4::CompiledData::Unit *QV4::Compiler::JSUnitGenerator::generateUnit()
 {
     registerString(irModule->fileName);
     foreach (QV4::IR::Function *f, irModule->functions) {
@@ -186,22 +217,20 @@ QV4::CompiledData::Unit *QV4::Compiler::JSUnitGenerator::generateUnit(int *total
             registerString(*f->locals.at(i));
     }
 
-    int unitSize = QV4::CompiledData::Unit::calculateSize(headerSize, strings.size(), irModule->functions.size(), regexps.size(),
+    int unitSize = QV4::CompiledData::Unit::calculateSize(headerSize, stringTable.stringCount(), irModule->functions.size(), regexps.size(),
                                                           constants.size(), lookups.size(), jsClasses.count());
 
     uint functionDataSize = 0;
     for (int i = 0; i < irModule->functions.size(); ++i) {
         QV4::IR::Function *f = irModule->functions.at(i);
-        functionOffsets.insert(f, functionDataSize + unitSize + stringDataSize);
+        functionOffsets.insert(f, functionDataSize + unitSize + stringTable.dataSize());
 
         const int qmlIdDepsCount = f->idObjectDependencies.count();
         const int qmlPropertyDepsCount = f->scopeObjectPropertyDependencies.count() + f->contextObjectPropertyDependencies.count();
         functionDataSize += QV4::CompiledData::Function::calculateSize(f->formals.size(), f->locals.size(), f->nestedFunctions.size(), qmlIdDepsCount, qmlPropertyDepsCount);
     }
 
-    const int totalSize = unitSize + functionDataSize + stringDataSize + jsClassDataSize;
-    if (totalUnitSize)
-        *totalUnitSize = totalSize;
+    const int totalSize = unitSize + functionDataSize + stringTable.dataSize() + jsClassDataSize;
     char *data = (char *)malloc(totalSize);
     memset(data, 0, totalSize);
     QV4::CompiledData::Unit *unit = (QV4::CompiledData::Unit*)data;
@@ -210,7 +239,8 @@ QV4::CompiledData::Unit *QV4::Compiler::JSUnitGenerator::generateUnit(int *total
     unit->architecture = 0; // ###
     unit->flags = QV4::CompiledData::Unit::IsJavascript;
     unit->version = 1;
-    unit->stringTableSize = strings.size();
+    unit->unitSize = totalSize;
+    unit->stringTableSize = stringTable.stringCount();
     unit->offsetToStringTable = headerSize;
     unit->functionTableSize = irModule->functions.size();
     unit->offsetToFunctionTable = unit->offsetToStringTable + unit->stringTableSize * sizeof(uint);
@@ -226,30 +256,17 @@ QV4::CompiledData::Unit *QV4::Compiler::JSUnitGenerator::generateUnit(int *total
     unit->sourceFileIndex = getStringId(irModule->fileName);
 
     // write strings and string table
-    uint *stringTable = (uint *)(data + unit->offsetToStringTable);
-    char *string = data + unitSize;
-    for (int i = 0; i < strings.size(); ++i) {
-        stringTable[i] = string - data;
-        const QString &qstr = strings.at(i);
-
-        QV4::CompiledData::String *s = (QV4::CompiledData::String*)(string);
-        s->hash = QV4::String::createHashValue(qstr.constData(), qstr.length());
-        s->flags = 0; // ###
-        s->str.ref.atomic.store(-1);
-        s->str.size = qstr.length();
-        s->str.alloc = 0;
-        s->str.capacityReserved = false;
-        s->str.offset = sizeof(QArrayData);
-        memcpy(s + 1, qstr.constData(), (qstr.length() + 1)*sizeof(ushort));
-
-        string += QV4::CompiledData::String::calculateSize(qstr);
+    {
+        uint *stringTablePtr = (uint *)(data + unit->offsetToStringTable);
+        char *string = data + unitSize;
+        stringTable.serialize(stringTablePtr, data, string);
     }
 
     uint *functionTable = (uint *)(data + unit->offsetToFunctionTable);
     for (int i = 0; i < irModule->functions.size(); ++i)
         functionTable[i] = functionOffsets.value(irModule->functions.at(i));
 
-    char *f = data + unitSize + stringDataSize;
+    char *f = data + unitSize + stringTable.dataSize();
     for (int i = 0; i < irModule->functions.size(); ++i) {
         QV4::IR::Function *function = irModule->functions.at(i);
         if (function == irModule->rootFunction)
@@ -271,7 +288,7 @@ QV4::CompiledData::Unit *QV4::Compiler::JSUnitGenerator::generateUnit(int *total
 
     // write js classes and js class lookup table
     uint *jsClassTable = (uint*)(data + unit->offsetToJSClassTable);
-    char *jsClass = data + unitSize + stringDataSize + functionDataSize;
+    char *jsClass = data + unitSize + stringTable.dataSize() + functionDataSize;
     for (int i = 0; i < jsClasses.count(); ++i) {
         jsClassTable[i] = jsClass - data;
 
@@ -383,5 +400,3 @@ int QV4::Compiler::JSUnitGenerator::writeFunction(char *f, int index, QV4::IR::F
     return CompiledData::Function::calculateSize(function->nFormals, function->nLocals, function->nInnerFunctions,
                                                  function->nDependingIdObjects, function->nDependingContextProperties + function->nDependingScopeProperties);
 }
-
-
index 6fd597a3b30677811e079aa275bb3b9bdb42545a..756e7cfd52f080f451f188b22ea340786f46e095 100644 (file)
@@ -59,13 +59,31 @@ struct JSClassMember;
 
 namespace Compiler {
 
-struct Q_QML_EXPORT JSUnitGenerator {
-    JSUnitGenerator(IR::Module *module, int headerSize = -1);
-
-    IR::Module *irModule;
+struct Q_QML_EXPORT StringTableGenerator {
+    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 dataSize() const { return stringDataSize; }
+
+    void clear();
+
+    void serialize(uint *stringTable, char *dataStart, char *stringData);
+
+private:
+    QHash<QString, int> stringToId;
+    QStringList strings;
+    uint stringDataSize;
+};
+
+struct Q_QML_EXPORT JSUnitGenerator {
+    JSUnitGenerator(IR::Module *module, int headerSize = -1);
+
+    int registerString(const QString &str) { return stringTable.registerString(str); }
+    int getStringId(const QString &string) const { return stringTable.getStringId(string); }
+    QString stringForIndex(int index) const { return stringTable.stringForIndex(index); }
 
     uint registerGetterLookup(const QString &name);
     uint registerSetterLookup(const QString &name);
@@ -79,13 +97,14 @@ struct Q_QML_EXPORT JSUnitGenerator {
 
     int registerJSClass(int count, IR::ExprList *args);
 
-    QV4::CompiledData::Unit *generateUnit(int *totalUnitSize = 0);
+    QV4::CompiledData::Unit *generateUnit();
     // Returns bytes written
     int writeFunction(char *f, int index, IR::Function *irFunction);
 
-    QHash<QString, int> stringToId;
-    QStringList strings;
-    uint stringDataSize;
+    StringTableGenerator stringTable;
+private:
+    IR::Module *irModule;
+
     QHash<IR::Function *, uint> functionOffsets;
     QList<CompiledData::Lookup> lookups;
     QVector<CompiledData::RegExp> regexps;
index a905519550db46e03f23b3f2de23e6cd44cf4d18..7f7ea1e5c1032e421a4acd84ca77f597ebbe3fa2 100644 (file)
@@ -1172,7 +1172,7 @@ void QQmlDataLoader::shutdownThread()
 }
 
 QQmlTypeLoader::Blob::Blob(const QUrl &url, QQmlDataBlob::Type type, QQmlTypeLoader *loader)
-  : QQmlDataBlob(url, type), m_typeLoader(loader), m_importCache(loader), m_stringPool(0), m_isSingleton(false)
+  : QQmlDataBlob(url, type), m_typeLoader(loader), m_importCache(loader), m_isSingleton(false)
 {
 }
 
@@ -2046,7 +2046,7 @@ void QQmlTypeData::done()
         const TypeReference &type = *it;
         Q_ASSERT(!type.typeData || type.typeData->isCompleteOrError());
         if (type.typeData && type.typeData->isError()) {
-            QString typeName = m_document->jsGenerator.strings.at(it.key());
+            QString typeName = m_document->stringAt(it.key());
 
             QList<QQmlError> errors = type.typeData->errors();
             QQmlError error;
@@ -2142,7 +2142,7 @@ void QQmlTypeData::dataReceived(const Data &data)
         return;
     }
 
-    m_stringPool = &m_document->jsGenerator.strings;
+    m_document->collectTypeReferences();
 
     m_importCache.setBaseUrl(finalUrl(), finalUrlString());
 
@@ -2172,7 +2172,7 @@ void QQmlTypeData::dataReceived(const Data &data)
 
     QList<QQmlError> errors;
 
-    foreach (QV4::CompiledData::Import *import, m_document->imports) {
+    foreach (const QV4::CompiledData::Import *import, m_document->imports) {
         if (!addImport(import, &errors)) {
             Q_ASSERT(errors.size());
             QQmlError error(errors.takeFirst());
@@ -2232,6 +2232,11 @@ void QQmlTypeData::downloadProgressChanged(qreal p)
     }
 }
 
+QString QQmlTypeData::stringAt(int index) const
+{
+    return m_document->jsGenerator.stringTable.stringForIndex(index);
+}
+
 void QQmlTypeData::compile()
 {
     Q_ASSERT(m_compiledData == 0);
@@ -2299,15 +2304,7 @@ void QQmlTypeData::resolveTypes()
         }
     }
 
-    QV4::CompiledData::TypeReferenceMap typeReferences;
-    QStringList names;
-    if (m_document) {
-        typeReferences = m_document->typeReferences;
-        names = m_document->jsGenerator.strings;
-    } else {
-        // ### collect from available QV4::CompiledData::QmlUnit
-    }
-    for (QV4::CompiledData::TypeReferenceMap::ConstIterator unresolvedRef = typeReferences.constBegin(), end = typeReferences.constEnd();
+    for (QV4::CompiledData::TypeReferenceMap::ConstIterator unresolvedRef = m_document->typeReferences.constBegin(), end = m_document->typeReferences.constEnd();
          unresolvedRef != end; ++unresolvedRef) {
 
         TypeReference ref; // resolved reference
@@ -2319,7 +2316,7 @@ void QQmlTypeData::resolveTypes()
         QQmlImportNamespace *typeNamespace = 0;
         QList<QQmlError> errors;
 
-        const QString name = names.at(unresolvedRef.key());
+        const QString name = stringAt(unresolvedRef.key());
         bool typeFound = m_importCache.resolveType(name, &ref.type,
                 &majorVersion, &minorVersion, &typeNamespace, &errors);
         if (!typeNamespace && !typeFound && !m_implicitImportLoaded) {
@@ -2606,8 +2603,6 @@ void QQmlScriptBlob::dataReceived(const Data &data)
         return;
     }
 
-    m_stringPool = &m_irUnit.jsGenerator.strings;
-
     QList<QQmlError> errors;
     QV4::ExecutionEngine *v4 = QV8Engine::getV4(m_typeLoader->engine());
     m_scriptData->m_precompiledScript = QV4::Script::precompile(&m_irUnit.jsModule, &m_irUnit.jsGenerator, v4, m_scriptData->url, source, &errors);
@@ -2619,6 +2614,7 @@ void QQmlScriptBlob::dataReceived(const Data &data)
         return;
     }
 
+    m_irUnit.javaScriptCompilationUnit = m_scriptData->m_precompiledScript;
     QmlIR::QmlUnitGenerator qmlGenerator;
     QV4::CompiledData::QmlUnit *qmlUnit = qmlGenerator.generate(m_irUnit);
     if (m_scriptData->m_precompiledScript) {
@@ -2687,6 +2683,11 @@ void QQmlScriptBlob::done()
     m_importCache.populateCache(m_scriptData->importCache);
 }
 
+QString QQmlScriptBlob::stringAt(int index) const
+{
+    return m_scriptData->m_precompiledScript->data->stringAt(index);
+}
+
 void QQmlScriptBlob::scriptImported(QQmlScriptBlob *blob, const QV4::CompiledData::Location &location, const QString &qualifier, const QString &nameSpace)
 {
     ScriptReference ref;
index 8335ffa7dbe6392acef56bdc1ca10981dc4d6a34..43828c572eb3f71ecadff526689d980e9d10d323 100644 (file)
@@ -293,11 +293,10 @@ public:
         virtual void dependencyComplete(QQmlDataBlob *);
 
     protected:
-        const QString &stringAt(int index) const { Q_ASSERT(m_stringPool); return m_stringPool->at(index); }
+        virtual QString stringAt(int) const { return QString(); }
 
         QQmlTypeLoader *m_typeLoader;
         QQmlImports m_importCache;
-        QStringList *m_stringPool; // used to resolve string indices in imports
         bool m_isSingleton;
         QHash<const QV4::CompiledData::Import*, int> m_unresolvedImports;
         QList<QQmlQmldirData *> m_qmldirs;
@@ -451,6 +450,8 @@ protected:
     virtual void allDependenciesDone();
     virtual void downloadProgressChanged(qreal);
 
+    virtual QString stringAt(int index) const;
+
 private:
     void resolveTypes();
     void compile();
@@ -542,6 +543,8 @@ protected:
     virtual void dataReceived(const Data &);
     virtual void done();
 
+    virtual QString stringAt(int index) const;
+
 private:
     virtual void scriptImported(QQmlScriptBlob *blob, const QV4::CompiledData::Location &location, const QString &qualifier, const QString &nameSpace);