aboutsummaryrefslogtreecommitdiffstats
path: root/src/qml/qml/qqmlengine.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/qml/qml/qqmlengine.cpp')
-rw-r--r--src/qml/qml/qqmlengine.cpp353
1 files changed, 220 insertions, 133 deletions
diff --git a/src/qml/qml/qqmlengine.cpp b/src/qml/qml/qqmlengine.cpp
index 7c218276c2..62b7675e1d 100644
--- a/src/qml/qml/qqmlengine.cpp
+++ b/src/qml/qml/qqmlengine.cpp
@@ -62,6 +62,8 @@
QT_BEGIN_NAMESPACE
+void qml_register_types_QML();
+
/*!
\qmltype QtObject
\instantiates QObject
@@ -215,23 +217,16 @@ void QQmlPrivate::qdeclarativeelement_destructor(QObject *o)
{
QObjectPrivate *p = QObjectPrivate::get(o);
if (QQmlData *d = QQmlData::get(p)) {
+ const auto invalidate = [](QQmlContextData *c) {c->invalidate();};
if (d->ownContext) {
- for (QQmlRefPointer<QQmlContextData> lc = d->ownContext->linkedContext(); lc;
- lc = lc->linkedContext()) {
- lc->invalidate();
- if (lc->contextObject() == o)
- lc->setContextObject(nullptr);
- }
- d->ownContext->invalidate();
- if (d->ownContext->contextObject() == o)
- d->ownContext->setContextObject(nullptr);
+ d->ownContext->deepClearContextObject(o, invalidate, invalidate);
d->ownContext.reset();
d->context = nullptr;
+ Q_ASSERT(!d->outerContext || d->outerContext->contextObject() != o);
+ } else if (d->outerContext && d->outerContext->contextObject() == o) {
+ d->outerContext->deepClearContextObject(o, invalidate, invalidate);
}
- if (d->outerContext && d->outerContext->contextObject() == o)
- d->outerContext->setContextObject(nullptr);
-
if (d->hasVMEMetaObject || d->hasInterceptorMetaObject) {
// This is somewhat dangerous because another thread might concurrently
// try to resolve the dynamic metaobject. In practice this will then
@@ -255,14 +250,11 @@ void QQmlPrivate::qdeclarativeelement_destructor(QObject *o)
}
}
-QQmlData::QQmlData()
- : ownMemory(true), indestructible(true), explicitIndestructibleSet(false),
+QQmlData::QQmlData(Ownership ownership)
+ : ownMemory(ownership == OwnsMemory), indestructible(true), explicitIndestructibleSet(false),
hasTaintedV4Object(false), isQueuedForDeletion(false), rootObjectInCreation(false),
- hasInterceptorMetaObject(false), hasVMEMetaObject(false), hasConstWrapper(false),
- bindingBitsArraySize(InlineBindingArraySize), notifyList(nullptr),
- bindings(nullptr), signalHandlers(nullptr), nextContextObject(nullptr), prevContextObject(nullptr),
- lineNumber(0), columnNumber(0), jsEngineId(0),
- guards(nullptr), extendedData(nullptr)
+ hasInterceptorMetaObject(false), hasVMEMetaObject(false), hasConstWrapper(false), dummy(0),
+ bindingBitsArraySize(InlineBindingArraySize)
{
memset(bindingBitsValue, 0, sizeof(bindingBitsValue));
init();
@@ -312,7 +304,10 @@ void QQmlData::signalEmitted(QAbstractDeclarativeData *, QObject *object, int in
// QQmlEngine to emit signals from a different thread. These signals are then automatically
// marshalled back onto the QObject's thread and handled by QML from there. This is tested
// by the qqmlecmascript::threadSignal() autotest.
- if (!ddata->notifyList)
+
+ // Relaxed semantics here. If we're on a different thread we might schedule a useless event,
+ // but that should be rare.
+ if (!ddata->notifyList.loadRelaxed())
return;
auto objectThreadData = QObjectPrivate::get(object)->threadData.loadRelaxed();
@@ -386,11 +381,15 @@ int QQmlData::endpointCount(int index)
void QQmlData::markAsDeleted(QObject *o)
{
- QQmlData::setQueuedForDeletion(o);
-
- QObjectPrivate *p = QObjectPrivate::get(o);
- for (QList<QObject *>::const_iterator it = p->children.constBegin(), end = p->children.constEnd(); it != end; ++it) {
- QQmlData::markAsDeleted(*it);
+ QVarLengthArray<QObject *> workStack;
+ workStack.push_back(o);
+ while (!workStack.isEmpty()) {
+ auto currentObject = workStack.last();
+ workStack.pop_back();
+ QQmlData::setQueuedForDeletion(currentObject);
+ auto currentObjectPriv = QObjectPrivate::get(currentObject);
+ for (QObject *child: std::as_const(currentObjectPriv->children))
+ workStack.push_back(child);
}
}
@@ -400,9 +399,7 @@ void QQmlData::setQueuedForDeletion(QObject *object)
if (QQmlData *ddata = QQmlData::get(object)) {
if (ddata->ownContext) {
Q_ASSERT(ddata->ownContext.data() == ddata->context);
- ddata->context->emitDestruction();
- if (ddata->ownContext->contextObject() == object)
- ddata->ownContext->setContextObject(nullptr);
+ ddata->ownContext->deepClearContextObject(object);
ddata->ownContext.reset();
ddata->context = nullptr;
}
@@ -413,7 +410,7 @@ void QQmlData::setQueuedForDeletion(QObject *object)
// possible to get the metaobject anymore.
// Also, there is no point in evaluating bindings in order to set properties on
// half-deleted objects.
- ddata->disconnectNotifiers();
+ ddata->disconnectNotifiers(DeleteNotifyList::No);
}
}
}
@@ -437,38 +434,57 @@ void QQmlData::flushPendingBinding(int coreIndex)
QQmlData::DeferredData::DeferredData() = default;
QQmlData::DeferredData::~DeferredData() = default;
+template<>
+int qmlRegisterType<void>(const char *uri, int versionMajor, int versionMinor, const char *qmlName)
+{
+ QQmlPrivate::RegisterType type = {
+ QQmlPrivate::RegisterType::CurrentVersion,
+ QMetaType(),
+ QMetaType(),
+ 0, nullptr, nullptr,
+ QString(),
+ nullptr,
+ uri,
+ QTypeRevision::fromVersion(versionMajor, versionMinor),
+ qmlName,
+ nullptr,
+ nullptr,
+ nullptr,
+ -1,
+ -1,
+ -1,
+ nullptr,
+ nullptr,
+ nullptr,
+ QTypeRevision::zero(),
+ -1,
+ QQmlPrivate::ValueTypeCreationMethod::None,
+ };
+
+ return QQmlPrivate::qmlregister(QQmlPrivate::TypeRegistration, &type);
+}
+
bool QQmlEnginePrivate::baseModulesUninitialized = true;
void QQmlEnginePrivate::init()
{
Q_Q(QQmlEngine);
if (baseModulesUninitialized) {
-
- // required for the Compiler.
- qmlRegisterType<QObject>("QML", 1, 0, "QtObject");
- qmlRegisterType<QQmlComponent>("QML", 1, 0, "Component");
- qmlRegisterAnonymousSequentialContainer<QList<QVariant>>("QML", 1);
- qmlRegisterAnonymousSequentialContainer<QList<bool>>("QML", 1);
- qmlRegisterAnonymousSequentialContainer<QList<int>>("QML", 1);
- qmlRegisterAnonymousSequentialContainer<QList<float>>("QML", 1);
- qmlRegisterAnonymousSequentialContainer<QList<double>>("QML", 1);
- qmlRegisterAnonymousSequentialContainer<QList<QString>>("QML", 1);
- qmlRegisterAnonymousSequentialContainer<QList<QUrl>>("QML", 1);
- qmlRegisterAnonymousSequentialContainer<QList<QDateTime>>("QML", 1);
- qmlRegisterAnonymousSequentialContainer<QList<QRegularExpression>>("QML", 1);
- qmlRegisterAnonymousSequentialContainer<QList<QByteArray>>("QML", 1);
+ // Register builtins
+ qml_register_types_QML();
// No need to specifically register those.
static_assert(std::is_same_v<QStringList, QList<QString>>);
static_assert(std::is_same_v<QVariantList, QList<QVariant>>);
- qRegisterMetaType<QVariant>();
qRegisterMetaType<QQmlScriptString>();
- qRegisterMetaType<QJSValue>();
qRegisterMetaType<QQmlComponent::Status>();
qRegisterMetaType<QList<QObject*> >();
qRegisterMetaType<QQmlBinding*>();
+ // Protect the module: We don't want any URL interceptor to mess with the builtins.
+ qmlProtectModule("QML", 1);
+
QQmlData::init();
baseModulesUninitialized = false;
}
@@ -484,29 +500,16 @@ void QQmlEnginePrivate::init()
\inmodule QtQml
\brief The QQmlEngine class provides an environment for instantiating QML components.
- Each QML component is instantiated in a QQmlContext.
- QQmlContext's are essential for passing data to QML
- components. In QML, contexts are arranged hierarchically and this
- hierarchy is managed by the QQmlEngine.
-
- Prior to creating any QML components, an application must have
- created a QQmlEngine to gain access to a QML context. The
- following example shows how to create a simple Text item.
-
- \code
- QQmlEngine engine;
- QQmlComponent component(&engine);
- component.setData("import QtQuick 2.0\nText { text: \"Hello world!\" }", QUrl());
- QQuickItem *item = qobject_cast<QQuickItem *>(component.create());
-
- //add item to view, etc
- ...
- \endcode
+ A QQmlEngine is used to manage \l{QQmlComponent}{components} and objects created from
+ them and execute their bindings and functions. QQmlEngine also inherits from
+ \l{QJSEngine} which allows seamless integration between your QML components and
+ JavaScript code.
- In this case, the Text item will be created in the engine's
- \l {QQmlEngine::rootContext()}{root context}.
+ Each QML component is instantiated in a QQmlContext. In QML, contexts are arranged
+ hierarchically and this hierarchy is managed by the QQmlEngine. By default,
+ components are instantiated in the \l {QQmlEngine::rootContext()}{root context}.
- \sa QQmlComponent, QQmlContext, {QML Global Object}
+ \sa QQmlComponent, QQmlContext, {QML Global Object}, QQmlApplicationEngine
*/
/*!
@@ -537,11 +540,12 @@ QQmlEngine::QQmlEngine(QQmlEnginePrivate &dd, QObject *parent)
invalidated, but not destroyed (unless they are parented to the
QQmlEngine object).
- See QJSEngine docs for details on cleaning up the JS engine.
+ See ~QJSEngine() for details on cleaning up the JS engine.
*/
QQmlEngine::~QQmlEngine()
{
Q_D(QQmlEngine);
+ handle()->inShutdown = true;
QJSEnginePrivate::removeFromDebugServer(this);
// Emit onDestruction signals for the root context before
@@ -610,9 +614,20 @@ QQmlEngine::~QQmlEngine()
void QQmlEngine::clearComponentCache()
{
Q_D(QQmlEngine);
+
+ // Contexts can hold on to CUs but live on the JS heap.
+ // Use a non-incremental GC run to get rid of those.
+ QV4::MemoryManager *mm = handle()->memoryManager;
+ auto oldLimit = mm->gcStateMachine->timeLimit;
+ mm->setGCTimeLimit(-1);
+ mm->runGC();
+ mm->gcStateMachine->timeLimit = std::move(oldLimit);
+
+ handle()->clearCompilationUnits();
d->typeLoader.lock();
d->typeLoader.clearCache();
d->typeLoader.unlock();
+ QQmlMetaType::freeUnusedTypesAndCaches();
}
/*!
@@ -630,6 +645,7 @@ void QQmlEngine::clearComponentCache()
void QQmlEngine::trimComponentCache()
{
Q_D(QQmlEngine);
+ handle()->trimCompilationUnits();
d->typeLoader.trimCache();
}
@@ -927,6 +943,45 @@ void QQmlEngine::setOutputWarningsToStandardError(bool enabled)
d->outputWarningsToMsgLog = enabled;
}
+
+/*!
+ \since 6.6
+ If this method is called inside of a function that is part of
+ a binding in QML, the binding will be treated as a translation binding.
+
+ \code
+ class I18nAwareClass : public QObject {
+
+ //...
+
+ QString text() const
+ {
+ if (auto engine = qmlEngine(this))
+ engine->markCurrentFunctionAsTranslationBinding();
+ return tr("Hello, world!");
+ }
+ };
+ \endcode
+
+ \note This function is mostly useful if you wish to provide your
+ own alternative to the qsTr function. To ensure that properties
+ exposed from C++ classes are updated on language changes, it is
+ instead recommended to react to \c LanguageChange events. That
+ is a more general mechanism which also works when the class is
+ used in a non-QML context, and has slightly less overhead. However,
+ using \c markCurrentFunctionAsTranslationBinding can be acceptable
+ when the class is already closely tied to the QML engine.
+ For more details, see \l {Prepare for Dynamic Language Changes}
+
+ \sa QQmlEngine::retranslate
+*/
+void QQmlEngine::markCurrentFunctionAsTranslationBinding()
+{
+ Q_D(QQmlEngine);
+ if (auto propertyCapture = d->propertyCapture)
+ propertyCapture->captureTranslation();
+}
+
/*!
\internal
@@ -1194,11 +1249,12 @@ void QQmlData::deferData(
deferData->context = context;
const QV4::CompiledData::Object *compiledObject = compilationUnit->objectAt(objectIndex);
- const QV4::BindingPropertyData &propertyData = compilationUnit->bindingPropertyDataPerObject.at(objectIndex);
+ const QV4::CompiledData::BindingPropertyData *propertyData
+ = compilationUnit->bindingPropertyDataPerObjectAt(objectIndex);
const QV4::CompiledData::Binding *binding = compiledObject->bindingTable();
for (quint32 i = 0; i < compiledObject->nBindings; ++i, ++binding) {
- const QQmlPropertyData *property = propertyData.at(i);
+ const QQmlPropertyData *property = propertyData->at(i);
if (binding->hasFlag(QV4::CompiledData::Binding::IsDeferredBinding))
deferData->bindings.insert(property ? property->coreIndex() : -1, binding);
}
@@ -1222,49 +1278,73 @@ void QQmlData::releaseDeferredData()
void QQmlData::addNotify(int index, QQmlNotifierEndpoint *endpoint)
{
- if (!notifyList) {
- notifyList = (NotifyList *)malloc(sizeof(NotifyList));
- notifyList->connectionMask = 0;
- notifyList->maximumTodoIndex = 0;
- notifyList->notifiesSize = 0;
- notifyList->todo = nullptr;
- notifyList->notifies = nullptr;
+ // Can only happen on "home" thread. We apply relaxed semantics when loading the atomics.
+
+ NotifyList *list = notifyList.loadRelaxed();
+
+ if (!list) {
+ list = new NotifyList;
+ // We don't really care when this change takes effect on other threads. The notifyList can
+ // only become non-null once in the life time of a QQmlData. It becomes null again when the
+ // underlying QObject is deleted. At that point any interaction with the QQmlData is UB
+ // anyway. So, for all intents and purposese, the list becomes non-null once and then stays
+ // non-null "forever". We can apply relaxed semantics.
+ notifyList.storeRelaxed(list);
}
Q_ASSERT(!endpoint->isConnected());
index = qMin(index, 0xFFFF - 1);
- notifyList->connectionMask |= (1ULL << quint64(index % 64));
- if (index < notifyList->notifiesSize) {
+ // Likewise, we don't really care _when_ the change in the connectionMask is propagated to other
+ // threads. Cross-thread event ordering is inherently nondeterministic. Therefore, when querying
+ // the conenctionMask in the presence of concurrent modification, any result is correct.
+ list->connectionMask.storeRelaxed(
+ list->connectionMask.loadRelaxed() | (1ULL << quint64(index % 64)));
- endpoint->next = notifyList->notifies[index];
+ if (index < list->notifiesSize) {
+ endpoint->next = list->notifies[index];
if (endpoint->next) endpoint->next->prev = &endpoint->next;
- endpoint->prev = &notifyList->notifies[index];
- notifyList->notifies[index] = endpoint;
-
+ endpoint->prev = &list->notifies[index];
+ list->notifies[index] = endpoint;
} else {
- notifyList->maximumTodoIndex = qMax(int(notifyList->maximumTodoIndex), index);
+ list->maximumTodoIndex = qMax(int(list->maximumTodoIndex), index);
- endpoint->next = notifyList->todo;
+ endpoint->next = list->todo;
if (endpoint->next) endpoint->next->prev = &endpoint->next;
- endpoint->prev = &notifyList->todo;
- notifyList->todo = endpoint;
+ endpoint->prev = &list->todo;
+ list->todo = endpoint;
}
}
-void QQmlData::disconnectNotifiers()
+void QQmlData::disconnectNotifiers(QQmlData::DeleteNotifyList doDelete)
{
- if (notifyList) {
- while (notifyList->todo)
- notifyList->todo->disconnect();
- for (int ii = 0; ii < notifyList->notifiesSize; ++ii) {
- while (QQmlNotifierEndpoint *ep = notifyList->notifies[ii])
+ // Can only happen on "home" thread. We apply relaxed semantics when loading the atomics.
+ if (NotifyList *list = notifyList.loadRelaxed()) {
+ while (QQmlNotifierEndpoint *todo = list->todo)
+ todo->disconnect();
+ for (int ii = 0; ii < list->notifiesSize; ++ii) {
+ while (QQmlNotifierEndpoint *ep = list->notifies[ii])
ep->disconnect();
}
- free(notifyList->notifies);
- free(notifyList);
- notifyList = nullptr;
+ free(list->notifies);
+
+ if (doDelete == DeleteNotifyList::Yes) {
+ // We can only get here from QQmlData::destroyed(), and that can only come from the
+ // the QObject dtor. If you're still sending signals at that point you have UB already
+ // without any threads. Therefore, it's enough to apply relaxed semantics.
+ notifyList.storeRelaxed(nullptr);
+ delete list;
+ } else {
+ // We can use relaxed semantics here. The worst thing that can happen is that some
+ // signal is falsely reported as connected. Signal connectedness across threads
+ // is not quite deterministic anyway.
+ list->connectionMask.storeRelaxed(0);
+ list->maximumTodoIndex = 0;
+ list->notifiesSize = 0;
+ list->notifies = nullptr;
+
+ }
}
}
@@ -1349,7 +1429,7 @@ void QQmlData::destroyed(QObject *object)
guard->objectDestroyed(guard);
}
- disconnectNotifiers();
+ disconnectNotifiers(DeleteNotifyList::Yes);
if (extendedData)
delete extendedData;
@@ -1390,7 +1470,7 @@ QQmlData *QQmlData::createQQmlData(QObjectPrivate *priv)
{
Q_ASSERT(priv);
Q_ASSERT(!priv->isDeletingChildren);
- priv->declarativeData = new QQmlData;
+ priv->declarativeData = new QQmlData(OwnsMemory);
return static_cast<QQmlData *>(priv->declarativeData);
}
@@ -1545,7 +1625,8 @@ void QQmlEnginePrivate::cleanupScarceResources()
The newly added \a path will be first in the importPathList().
- \sa setImportPathList(), {QML Modules}
+ \b {See also} \l setImportPathList(), \l {QML Modules},
+ and \l [QtQml] {QML Import Path}
*/
void QQmlEngine::addImportPath(const QString& path)
{
@@ -1563,9 +1644,8 @@ void QQmlEngine::addImportPath(const QString& path)
provided by that module. A \c qmldir file is required for defining the
type version mapping and possibly QML extensions plugins.
- By default, the list contains the directory of the application executable,
- paths specified in the \c QML_IMPORT_PATH environment variable,
- and the builtin \c QmlImportsPath from QLibraryInfo.
+ By default, this list contains the paths mentioned in
+ \l {QML Import Path}.
\sa addImportPath(), setImportPathList()
*/
@@ -1579,9 +1659,11 @@ QStringList QQmlEngine::importPathList() const
Sets \a paths as the list of directories where the engine searches for
installed modules in a URL-based directory structure.
- By default, the list contains the directory of the application executable,
- paths specified in the \c QML_IMPORT_PATH environment variable,
- and the builtin \c QmlImportsPath from QLibraryInfo.
+ By default, this list contains the paths mentioned in
+ \l {QML Import Path}.
+
+ \warning Calling setImportPathList does not preserve the default
+ import paths.
\sa importPathList(), addImportPath()
*/
@@ -1745,14 +1827,13 @@ QJSValue QQmlEnginePrivate::singletonInstance<QJSValue>(const QQmlType &type)
{
Q_Q(QQmlEngine);
- QJSValue value = singletonInstances.value(type);
- if (!value.isUndefined()) {
- return value;
- }
-
- QQmlType::SingletonInstanceInfo *siinfo = type.singletonInstanceInfo();
+ QQmlType::SingletonInstanceInfo::ConstPtr siinfo = type.singletonInstanceInfo();
Q_ASSERT(siinfo != nullptr);
+ QJSValue value = singletonInstances.value(siinfo);
+ if (!value.isUndefined())
+ return value;
+
if (siinfo->scriptCallback) {
value = siinfo->scriptCallback(q, q);
if (value.isQObject()) {
@@ -1761,7 +1842,7 @@ QJSValue QQmlEnginePrivate::singletonInstance<QJSValue>(const QQmlType &type)
// should behave identically to QML singleton types.
q->setContextForObject(o, new QQmlContext(q->rootContext(), q));
}
- singletonInstances.convertAndInsert(v4engine(), type, &value);
+ singletonInstances.convertAndInsert(v4engine(), siinfo, &value);
} else if (siinfo->qobjectCallback) {
QObject *o = siinfo->qobjectCallback(q, q);
@@ -1790,7 +1871,7 @@ QJSValue QQmlEnginePrivate::singletonInstance<QJSValue>(const QQmlType &type)
}
value = q->newQObject(o);
- singletonInstances.convertAndInsert(v4engine(), type, &value);
+ singletonInstances.convertAndInsert(v4engine(), siinfo, &value);
} else if (!siinfo->url.isEmpty()) {
QQmlComponent component(q, siinfo->url, QQmlComponent::PreferSynchronous);
if (component.isError()) {
@@ -1801,7 +1882,7 @@ QJSValue QQmlEnginePrivate::singletonInstance<QJSValue>(const QQmlType &type)
}
QObject *o = component.beginCreate(q->rootContext());
value = q->newQObject(o);
- singletonInstances.convertAndInsert(v4engine(), type, &value);
+ singletonInstances.convertAndInsert(v4engine(), siinfo, &value);
component.completeCreate();
}
@@ -1864,7 +1945,7 @@ void QQmlEnginePrivate::executeRuntimeFunction(const QV4::ExecutableCompilationU
// different version of ExecutionEngine::callInContext() that returns a
// QV4::ReturnedValue with no arguments since they are not needed by the
// outer function anyhow
- QV4::ScopedFunctionObject result(scope,
+ QV4::Scoped<QV4::JavaScriptFunctionObject> result(scope,
v4->callInContext(function, thisObject, callContext, 0, nullptr));
Q_ASSERT(result->function());
Q_ASSERT(result->function()->compilationUnit == function->compilationUnit);
@@ -1879,12 +1960,20 @@ void QQmlEnginePrivate::executeRuntimeFunction(const QV4::ExecutableCompilationU
QV4::ExecutableCompilationUnit *QQmlEnginePrivate::compilationUnitFromUrl(const QUrl &url)
{
+ QV4::ExecutionEngine *v4 = v4engine();
+ if (auto unit = v4->compilationUnitForUrl(url)) {
+ if (!unit->runtimeStrings)
+ unit->populate();
+ return unit.data();
+ }
+
auto unit = typeLoader.getType(url)->compilationUnit();
if (!unit)
return nullptr;
- if (!unit->engine)
- unit->linkToEngine(v4engine());
- return unit;
+
+ auto executable = v4->executableCompilationUnit(std::move(unit));
+ executable->populate();
+ return executable.data();
}
QQmlRefPointer<QQmlContextData>
@@ -1897,21 +1986,21 @@ QQmlEnginePrivate::createInternalContext(const QQmlRefPointer<QV4::ExecutableCom
QQmlRefPointer<QQmlContextData> context;
context = QQmlContextData::createRefCounted(parentContext);
context->setInternal(true);
- context->setImports(unit->typeNameCache);
+ context->setImports(unit->typeNameCache());
context->initFromTypeCompilationUnit(unit, subComponentIndex);
- if (isComponentRoot && unit->dependentScripts.size()) {
+ const auto *dependentScripts = unit->dependentScriptsPtr();
+ const qsizetype dependentScriptsSize = dependentScripts->size();
+ if (isComponentRoot && dependentScriptsSize) {
QV4::ExecutionEngine *v4 = v4engine();
Q_ASSERT(v4);
QV4::Scope scope(v4);
- QV4::ScopedObject scripts(scope, v4->newArrayObject(unit->dependentScripts.size()));
+ QV4::ScopedObject scripts(scope, v4->newArrayObject(dependentScriptsSize));
context->setImportedScripts(QV4::PersistentValue(v4, scripts.asReturnedValue()));
QV4::ScopedValue v(scope);
- for (int i = 0; i < unit->dependentScripts.size(); ++i) {
- QQmlRefPointer<QQmlScriptData> s = unit->dependentScripts.at(i);
- scripts->put(i, (v = s->scriptValueForContext(context)));
- }
+ for (qsizetype i = 0; i < dependentScriptsSize; ++i)
+ scripts->put(i, (v = dependentScripts->at(i)->scriptValueForContext(context)));
}
return context;
@@ -2032,10 +2121,12 @@ LoadHelper::LoadHelper(QQmlTypeLoader *loader, QAnyStringView uri)
{
auto import = std::make_shared<PendingImport>();
- import->uri = uri.toString();
+ import->uri = m_uri;
QList<QQmlError> errorList;
- if (!Blob::addImport(import, &errorList))
- m_uri = QString(); // reset m_uri to remember the failure
+ if (!Blob::addImport(import, &errorList)) {
+ qCDebug(lcQmlImport) << "LoadHelper: Errors loading " << m_uri << errorList;
+ m_uri.clear(); // reset m_uri to remember the failure
+ }
}
LoadHelper::ResolveTypeResult LoadHelper::resolveType(QAnyStringView typeName)
@@ -2054,9 +2145,8 @@ LoadHelper::ResolveTypeResult LoadHelper::resolveType(QAnyStringView typeName)
QTypeRevision versionReturn;
QList<QQmlError> errors;
QQmlImportNamespace *ns_return = nullptr;
- m_importCache->resolveType(typeName.toString(), &type, &versionReturn,
- &ns_return,
- &errors);
+ m_importCache->resolveType(
+ typeLoader(), typeName.toString(), &type, &versionReturn, &ns_return, &errors);
return {ResolveTypeResult::ModuleFound, type};
}
@@ -2072,7 +2162,4 @@ bool LoadHelper::couldFindModule() const
QT_END_NAMESPACE
-#include "moc_qqmlengine_p.cpp"
-
#include "moc_qqmlengine.cpp"
-