Uploaded image for project: 'Qt'
  1. Qt
  2. QTBUG-136806

QtQml restores QmlIR from CompilationUnits when loading AOT-compiled artefacts

    XMLWordPrintable

Details

    • b9a085b26 (dev)

    Description

      This is rather wasteful since it duplicates the complete CU just to add some flags here and there. In particular, this is slower than loading a run time generated .qmlc file for the same QML document.

      The following pieces of data are produced by QQmlTypeCompiler and are not present in AOT-compiled units:

      1. Object::HasCustomParserBindings and Binding::IsCustomParserBinding
      2. Object::HasDeferredBindings and Binding::IsDeferredBinding
      3. Alias::AliasPointsToPointerObject, Alias::targetObjectId, Alias::isAliasToLocalAlias, Alias::localAliasIndex
      4. synthetic bindings for implicit components
      5. script strings, either as QQmlScriptString properties or for custom parsers
      6. Binding::IsBindingToAlias
      7. enum bindings as number values (which is faster than looking them up at run time)
      8. Binding::IsSignalHandlerObject, Binding::IsPropertyObserver, Binding::IsSignalHandlerExpression

      See qqmltypecompiler.cpp about that.

      The workflow for AOT-compiled units is:

      1. mmap() a .qmlc file or cast the byte array in the generated C++ as QV4::CompiledData::Unit, part of which is a QmlUnit containing all the QML objects, properties, bindings, etc
      2. build a QmlIR::Document, duplicating most of the QmlUnit into a QQmlJS::MemoryPool
      3. Run QQmlTypeCompiler on the QmlIR::Document, adjust all the bits and pieces as needed
      4. Produce yet another QmlUnit in a malloc'd piece of memory and transfer the contents of the QmlIR::Document into that one
      5. Drop the QmlIR::Document, freeing the memory pool
      6. construct a QV4::CompiledData::CompilationUnit consisting of the new QmlUnit and the original QV4::CompiledData::Unit (which still contains the now-useless old QmlUnit)

      Compilation units created at run time and stored in .qmlc files do not have this problem. They simply contain the result of the type compilation and can be used as-is the next time around.

      If we could store all the bits and pieces produced by QQmlTypeCompiler in a way that doesn't involve the compilation unit, we

      1. wouldn't need to copy any of the data around when loading AOT-compiled code.
      2. would need to run an additional QQmlTypeCompiler pass when loading .qmlc files created at run time.

      This is a tough trade-off.

      Another thing to note is that qmlcachegen could figure out all the extra data when considering the type information we also use for AOT-compilation of functions and bindings to C++. Since most of the time qmlcachegen is called with all the type information present, we could shift the QQmlTypeCompiler code to compile time and generate units with the PendingTypeCompilation flag off. The type loader could then honor this and conditionally skip the type compilation. This is probably less controversial.

      Furthermore, qmlcachegen then needs to calculate the dependency checksum ahead of time. When the checksum doesn't match, we not only need to reject the QmlUnit data, but also the AOT-compiled functions and bindings. Those rely on the same type information, after all.

      Attachments

        For Gerrit Dashboard: QTBUG-136806
        # Subject Branch Project Status CR V

        Activity

          People

            ulherman Ulf Hermann
            ulherman Ulf Hermann
            Votes:
            0 Vote for this issue
            Watchers:
            2 Start watching this issue

            Dates

              Created:
              Updated:

              Gerrit Reviews

                There are no open Gerrit changes