// Copyright (C) 2019 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only

/*!
\page qmldiskcache.html
\title The QML Disk Cache
\brief QML documents are pre-compiled ahead of time or cached after compilation
    at runtime.

To achieve optimal performance, QML documents are either pre-compiled ahead of
time during the build process or cached after compilation at runtime. This page
describes both strategies and how to configure the caching behavior.

\section1 Ahead-of-Time Compilation

You should define your QML modules using \l{qt_add_qml_module} that makes sure
the \l{Qt Quick Compiler} processes your QML and JavaScript files ahead of time.
This guarantees optimum performance at run time.

The \l{Qt Quick Compiler} generates byte code for each function and binding.
This byte code can be used by the QML interpreter and the Just-in-Time (JIT)
compiler in the QML engine. In addition, the \l{Qt Quick Compiler} generates
native code for suitable functions and bindings. The native code is executed
directly, which results in better performance than interpreting or just-in-time
compiling byte code. Both byte code and native code are then compiled into your
application binary.

One benefit of ahead-of-time compilation is that syntax errors in your QML
documents are detected at application compile-time instead of at run-time when
the file is loaded.

\section2 With CMake

When using CMake with \l{qt_add_qml_module}, QML files are automatically
compiled ahead of time. You should load your QML documents from the resource
file system where possible. This ensures the QML engine can find the code
compiled ahead of time.

\section2 With qmake

When using \l{qmake}, you can enable ahead-of-time compilation by specifying
\c{CONFIG += qtquickcompiler} in your project file. \l{\QC Documentation}{\QC}
has a setting that allows passing this directive to the qmake command line.
By default, it is enabled for release and profile builds.

When using qmake, you must organize your project in a specific way:

\list
    \li All QML documents (including JavaScript files) must be included as
        resources via \l{The Qt Resource System}{Qt's Resource system}.
    \li Your application must load the QML documents via the \c qrc:/// URL
        scheme.
\endlist

Note that qmake cannot pass as much information to the \l{Qt Quick Compiler}
as CMake. Therefore, the compilation will contain less native code.

\section1 Runtime Disk Caching

If no pre-compiled code is found at run time, or if the code cannot be used, the
QML engine compiles QML documents into a byte code representation on the fly.
Instead of re-compiling the same document each time it is loaded, the QML engine
caches the compiled byte code. The caching process is automatic: each time you
load a changed QML document, the cache is automatically re-created.

\section2 Cache File Format and Location

Cache files use the following extensions:

\list
    \li \c .qmlc for compiled QML documents
    \li \c .jsc for imported JavaScript files
    \li \c .mjsc for ECMAScript modules
\endlist

Cache files are located in a subdirectory named \c{qmlcache} of the system's
cache directory, as denoted by QStandardPaths::CacheLocation.

\section2 Memory Efficiency

Cache files are loaded via the \c mmap() system call on POSIX-compliant
operating systems or \c CreateFileMapping() on Windows. This memory-mapping
approach results in significant memory savings. In addition, when multiple
applications use the same QML document, the memory needed for the code is shared
between application processes, further reducing memory overhead.

\section1 Cache Validation

Cache files and ahead-of-time compiled code are only loaded if all of the
following conditions are met:

\list
    \li The Qt version has not changed
    \li The source code in the original file has not changed
    \li The QML debugger is not running
    \li The \l{Validation of ahead of time generated native code}{validation of AOT code}
        succeeds
\endlist

Note that \c{QML_FORCE_DISK_CACHE} (see below) can override the QML debugger
condition. The other environment variables do not influence these validation
conditions.

\section2 Validation of ahead of time generated native code

The native code generated by the \l{Qt Quick Compiler} has some assumptions
built in. If the conditions in which the code is executed differ from those in
which it was compiled, the code may be unsafe to use. Therefore, the native code
is validated at runtime using metadata stored alongside it. If this validation
passes, the code is executed as normal. If it fails, the execution silently
falls back to interpreting the bytecode instead. This validation happens once
per file, the first time the code is loaded, and either approves or rejects all
functions and bindings in that QML file as a whole.

You can customize the validation of AOT code:

\list
    \li To disable the validation at runtime, set the
        \c{QV4_SKIP_AOT_VALIDATION} environment variable. This allows you to
        avoid paying the small overhead of performing the validation.

        \code
        QV4_SKIP_AOT_VALIDATION=1 ./myQmlApp
        \endcode
    \li To ensure that validation succeeds at runtime, set the
        \c{QV4_FAIL_ON_INVALID_AOT} environment variable. If validation fails,
        the program is terminated. This allows you to make sure compiled
        functions are indeed executed as native code, for example.

        \code
        QV4_FAIL_ON_INVALID_AOT=1 ./myQmlApp
        \endcode
    \li To disable the feature completely and prevent the \l{Qt Quick Compiler}
        from generating the metadata and validation logic, pass
        \c{NO_GENERATE_AOT_VALIDATION} to \l{qt_add_qml_module}.

        \code
        qt_add_qml_module(... NO_GENERATE_AOT_VALIDATION)
        \endcode
\endlist


\section1 Configuration

You can fine-tune caching behavior using the environment variable
\c{QML_DISK_CACHE}, which takes a comma-separated list of options. For example:

\badcode
QML_DISK_CACHE=aot,qmlc-read
\endcode

The available options are as follows:

\table
    \header
        \li Option
        \li Description
    \row
        \li aot-native
        \li Load the compilation units compiled ahead of time and allow
            execution of any native code found in them.
    \row
        \li aot-bytecode
        \li Load the compilation units compiled ahead of time and allow
            interpretation and just-in-time compilation of byte code found
            in them.
    \row
        \li aot
        \li Shorthand for \c{aot-native,aot-bytecode}.
    \row
        \li qmlc-read
        \li Load any cached compilation units for QML and JavaScript files from
            the host file system and allow interpretation and just-in-time
            compilation of byte code found in them.
    \row
        \li qmlc-write
        \li When compiling a QML or JavaScript file on the fly, create a cache
            file afterward. The cache file can be loaded when the same
            document is requested again.
    \row
        \li qmlc
        \li Shorthand for \c{qmlc-read,qmlc-write}.
\endtable

Furthermore, you can use the following environment variables:

\table
    \header
        \li Environment Variable
        \li Description
    \row
        \li \c{QML_DISABLE_DISK_CACHE}
        \li Disables the disk cache and forces re-compilation from source for
            all QML and JavaScript files. \c{QML_DISABLE_DISK_CACHE} overrides
            \c{QML_DISK_CACHE}.
    \row
        \li \c{QML_FORCE_DISK_CACHE}
        \li Enables the disk cache even when debugging QML. You cannot use the
            JavaScript debugger this way. It may fail to stop at breakpoints,
            for example. You can still use the QML inspector to explore the
            object hierarchy, though. \c{QML_FORCE_DISK_CACHE} overrides
            \c{QML_DISABLE_DISK_CACHE} and \c{QML_DISK_CACHE}.
    \row
        \li \c{QML_DISK_CACHE_PATH}
        \li Specifies a custom location where the cache files shall be stored
            instead of using the default location.
\endtable

*/
