aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/qml/compiler/qqmlirbuilder.cpp409
-rw-r--r--src/qml/compiler/qqmlirbuilder_p.h34
-rw-r--r--src/qml/compiler/qqmltypecompiler.cpp34
-rw-r--r--src/qml/compiler/qv4codegen.cpp106
-rw-r--r--src/qml/compiler/qv4codegen_p.h63
-rw-r--r--src/qml/compiler/qv4compileddata.cpp22
-rw-r--r--src/qml/compiler/qv4compileddata_p.h39
-rw-r--r--src/qml/compiler/qv4compiler.cpp57
-rw-r--r--src/qml/compiler/qv4compiler_p.h2
-rw-r--r--src/qml/compiler/qv4compilercontext.cpp7
-rw-r--r--src/qml/compiler/qv4compilercontext_p.h6
-rw-r--r--src/qml/compiler/qv4instr_moth.cpp44
-rw-r--r--src/qml/compiler/qv4instr_moth_p.h20
-rw-r--r--src/qml/doc/src/cppintegration/definetypes.qdoc7
-rw-r--r--src/qml/doc/src/javascript/functionlist.qdoc61
-rw-r--r--src/qml/doc/src/javascript/hostenvironment.qdoc5
-rw-r--r--src/qml/jit/qv4baselineassembler.cpp32
-rw-r--r--src/qml/jit/qv4baselinejit.cpp114
-rw-r--r--src/qml/jit/qv4baselinejit_p.h15
-rw-r--r--src/qml/jit/qv4jithelpers.cpp6
-rw-r--r--src/qml/jit/qv4jithelpers_p.h1
-rw-r--r--src/qml/jsruntime/qv4engine.cpp8
-rw-r--r--src/qml/jsruntime/qv4engine_p.h1
-rw-r--r--src/qml/jsruntime/qv4function.cpp1
-rw-r--r--src/qml/jsruntime/qv4function_p.h1
-rw-r--r--src/qml/jsruntime/qv4internalclass.cpp12
-rw-r--r--src/qml/jsruntime/qv4lookup_p.h35
-rw-r--r--src/qml/jsruntime/qv4qmlcontext.cpp283
-rw-r--r--src/qml/jsruntime/qv4qmlcontext_p.h10
-rw-r--r--src/qml/jsruntime/qv4qobjectwrapper.cpp187
-rw-r--r--src/qml/jsruntime/qv4qobjectwrapper_p.h55
-rw-r--r--src/qml/jsruntime/qv4runtime.cpp135
-rw-r--r--src/qml/jsruntime/qv4runtimeapi_p.h15
-rw-r--r--src/qml/jsruntime/qv4value_p.h16
-rw-r--r--src/qml/jsruntime/qv4vme_moth.cpp60
-rw-r--r--src/qml/qml/qqmlbinding.cpp32
-rw-r--r--src/qml/qml/qqmlimport.cpp2
-rw-r--r--src/qml/qml/qqmljavascriptexpression.cpp82
-rw-r--r--src/qml/qml/qqmljavascriptexpression_p.h21
-rw-r--r--src/qml/qml/qqmltypewrapper.cpp61
-rw-r--r--src/qml/qml/qqmltypewrapper_p.h3
-rw-r--r--src/qml/qml/qqmlvaluetypewrapper.cpp151
-rw-r--r--src/qml/qml/qqmlvaluetypewrapper_p.h3
-rw-r--r--src/qml/types/qqmllistmodel.cpp10
-rw-r--r--src/qml/types/qqmllistmodel_p_p.h2
-rw-r--r--tests/auto/qml/debugger/qqmlpreview/tst_qqmlpreview.cpp2
-rw-r--r--tests/auto/qml/qqmlecmascript/data/signalHandlers.qml2
-rw-r--r--tests/auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp22
-rw-r--r--tests/auto/qml/qqmlimport/data/interceptQmldir.qml7
-rw-r--r--tests/auto/qml/qqmlimport/data/intercepted/View.qml5
-rw-r--r--tests/auto/qml/qqmlimport/data/intercepted/qmldir2
-rw-r--r--tests/auto/qml/qqmlimport/tst_qqmlimport.cpp28
-rw-r--r--tests/auto/qml/qqmllanguage/data/EdgeObject.qml20
-rw-r--r--tests/auto/qml/qqmllanguage/data/anchorsToParentInPropertyChagnes.qml10
-rw-r--r--tests/auto/qml/qqmllanguage/data/thisInQmlScope.qml13
-rw-r--r--tests/auto/qml/qqmllanguage/tst_qqmllanguage.cpp13
-rw-r--r--tests/auto/qml/qqmlnotifier/tst_qqmlnotifier.cpp2
-rw-r--r--tests/auto/qml/qv4mm/tst_qv4mm.cpp26
-rw-r--r--tests/auto/qmltest/animatedimage/BLACKLIST2
-rw-r--r--tests/auto/quick/qquickgridview/tst_qquickgridview.cpp2
-rw-r--r--tests/auto/quick/qquicklistview/BLACKLIST2
-rw-r--r--tests/auto/quick/touchmouse/BLACKLIST4
-rw-r--r--tools/qmlcachegen/qmlcachegen.cpp9
63 files changed, 1142 insertions, 1299 deletions
diff --git a/src/qml/compiler/qqmlirbuilder.cpp b/src/qml/compiler/qqmlirbuilder.cpp
index 7bd5aeb188..a22dd7aa32 100644
--- a/src/qml/compiler/qqmlirbuilder.cpp
+++ b/src/qml/compiler/qqmlirbuilder.cpp
@@ -974,7 +974,6 @@ bool IRBuilder::visit(QQmlJS::AST::UiSourceElement *node)
foe->node = funDecl;
foe->parentNode = funDecl;
foe->nameIndex = registerString(funDecl->name.toString());
- foe->disableAcceleratedLookups = false;
const int index = _object->functionsAndExpressions->append(foe);
Function *f = New<Function>();
@@ -1098,7 +1097,6 @@ void IRBuilder::setBindingValue(QV4::CompiledData::Binding *binding, QQmlJS::AST
expr->parentNode = parentNode;
expr->nameIndex = registerString(QLatin1String("expression for ")
+ stringAt(binding->propertyNameIndex));
- expr->disableAcceleratedLookups = false;
const int index = bindingsTarget()->functionsAndExpressions->append(expr);
binding->value.compiledScriptIndex = index;
// We don't need to store the binding script as string, except for script strings
@@ -1825,19 +1823,13 @@ char *QmlUnitGenerator::writeBindings(char *bindingPtr, const Object *o, Binding
JSCodeGen::JSCodeGen(const QString &sourceCode, QV4::Compiler::JSUnitGenerator *jsUnitGenerator,
QV4::Compiler::Module *jsModule, QQmlJS::Engine *jsEngine,
- QQmlJS::AST::UiProgram *qmlRoot, QQmlTypeNameCache *imports,
+ QQmlJS::AST::UiProgram *qmlRoot,
const QV4::Compiler::StringTableGenerator *stringPool, const QSet<QString> &globalNames)
: QV4::Compiler::Codegen(jsUnitGenerator, /*strict mode*/false)
, sourceCode(sourceCode)
, jsEngine(jsEngine)
, qmlRoot(qmlRoot)
- , imports(imports)
, stringPool(stringPool)
- , _disableAcceleratedLookups(false)
- , _contextObject(nullptr)
- , _scopeObject(nullptr)
- , _qmlContextSlot(-1)
- , _importedScriptsSlot(-1)
{
m_globalNames = globalNames;
@@ -1845,18 +1837,6 @@ JSCodeGen::JSCodeGen(const QString &sourceCode, QV4::Compiler::JSUnitGenerator *
_fileNameIsUrl = true;
}
-void JSCodeGen::beginContextScope(const JSCodeGen::ObjectIdMapping &objectIds, QQmlPropertyCache *contextObject)
-{
- _idObjects = objectIds;
- _contextObject = contextObject;
- _scopeObject = nullptr;
-}
-
-void JSCodeGen::beginObjectScope(QQmlPropertyCache *scopeObject)
-{
- _scopeObject = scopeObject;
-}
-
QVector<int> JSCodeGen::generateJSCodeForFunctionsAndBindings(const QList<CompiledFunctionOrExpression> &functions)
{
auto qmlName = [&](const CompiledFunctionOrExpression &c) {
@@ -1921,7 +1901,6 @@ QVector<int> JSCodeGen::generateJSCodeForFunctionsAndBindings(const QList<Compil
body = body->finish();
}
- _disableAcceleratedLookups = qmlFunction.disableAcceleratedLookups;
int idx = defineFunction(name, function ? function : qmlFunction.parentNode,
function ? function->formals : nullptr,
body);
@@ -1931,391 +1910,6 @@ QVector<int> JSCodeGen::generateJSCodeForFunctionsAndBindings(const QList<Compil
return runtimeFunctionIndices;
}
-int JSCodeGen::defineFunction(const QString &name, AST::Node *ast, AST::FormalParameterList *formals, AST::StatementList *body)
-{
- int qmlContextTemp = -1;
- int importedScriptsTemp = -1;
- qSwap(_qmlContextSlot, qmlContextTemp);
- qSwap(_importedScriptsSlot, importedScriptsTemp);
-
- int result = Codegen::defineFunction(name, ast, formals, body);
-
- qSwap(_importedScriptsSlot, importedScriptsTemp);
- qSwap(_qmlContextSlot, qmlContextTemp);
-
- return result;
-}
-
-#ifndef V4_BOOTSTRAP
-QQmlPropertyData *JSCodeGen::lookupQmlCompliantProperty(QQmlPropertyCache *cache, const QString &name)
-{
- QQmlPropertyData *pd = cache->property(name, /*object*/nullptr, /*context*/nullptr);
-
- if (pd && !cache->isAllowedInRevision(pd))
- return nullptr;
-
- return pd;
-}
-
-enum MetaObjectResolverFlags {
- AllPropertiesAreFinal = 0x1,
- LookupsIncludeEnums = 0x2,
- LookupsExcludeProperties = 0x4,
- ResolveTypeInformationOnly = 0x8
-};
-
-#if 0
-static void initMetaObjectResolver(QV4::IR::MemberExpressionResolver *resolver, QQmlPropertyCache *metaObject);
-
-static void initScopedEnumResolver(QV4::IR::MemberExpressionResolver *resolver, const QQmlType &qmlType, int index);
-
-static QV4::IR::DiscoveredType resolveQmlType(QQmlEnginePrivate *qmlEngine,
- const QV4::IR::MemberExpressionResolver *resolver,
- QV4::IR::Member *member)
-{
- QV4::IR::Type result = QV4::IR::VarType;
-
- QQmlType type = resolver->qmlType;
-
- if (member->name->constData()->isUpper()) {
- bool ok = false;
- int value = type.enumValue(qmlEngine, *member->name, &ok);
- if (ok) {
- member->setEnumValue(value);
- return QV4::IR::SInt32Type;
- } else {
- int index = type.scopedEnumIndex(qmlEngine, *member->name, &ok);
- if (ok) {
- auto newResolver = resolver->owner->New<QV4::IR::MemberExpressionResolver>();
- newResolver->owner = resolver->owner;
- initScopedEnumResolver(newResolver, type, index);
- return QV4::IR::DiscoveredType(newResolver);
- }
- }
- }
-
- if (type.isCompositeSingleton()) {
- QQmlRefPointer<QQmlTypeData> tdata = qmlEngine->typeLoader.getType(type.singletonInstanceInfo()->url);
- Q_ASSERT(tdata);
- tdata->release(); // Decrease the reference count added from QQmlTypeLoader::getType()
- // When a singleton tries to reference itself, it may not be complete yet.
- if (tdata->isComplete()) {
- auto newResolver = resolver->owner->New<QV4::IR::MemberExpressionResolver>();
- newResolver->owner = resolver->owner;
- initMetaObjectResolver(newResolver, qmlEngine->propertyCacheForType(tdata->compilationUnit()->metaTypeId));
- newResolver->flags |= AllPropertiesAreFinal;
- return newResolver->resolveMember(qmlEngine, newResolver, member);
- }
- } else if (type.isSingleton()) {
- const QMetaObject *singletonMeta = type.singletonInstanceInfo()->instanceMetaObject;
- if (singletonMeta) { // QJSValue-based singletons cannot be accelerated
- auto newResolver = resolver->owner->New<QV4::IR::MemberExpressionResolver>();
- newResolver->owner = resolver->owner;
- initMetaObjectResolver(newResolver, qmlEngine->cache(singletonMeta));
- member->kind = QV4::IR::Member::MemberOfSingletonObject;
- return newResolver->resolveMember(qmlEngine, newResolver, member);
- }
- }
-#if 0
- else if (const QMetaObject *attachedMeta = type->attachedPropertiesType(qmlEngine)) {
- // Right now the attached property IDs are not stable and cannot be embedded in the
- // code that is cached on disk.
- QQmlPropertyCache *cache = qmlEngine->cache(attachedMeta);
- auto newResolver = resolver->owner->New<QV4::IR::MemberExpressionResolver>();
- newResolver->owner = resolver->owner;
- initMetaObjectResolver(newResolver, cache);
- member->setAttachedPropertiesId(type->attachedPropertiesId(qmlEngine));
- return newResolver->resolveMember(qmlEngine, newResolver, member);
- }
-#endif
-
- return result;
-}
-
-static void initQmlTypeResolver(QV4::IR::MemberExpressionResolver *resolver, const QQmlType &qmlType)
-{
- Q_ASSERT(resolver);
-
- resolver->resolveMember = &resolveQmlType;
- resolver->qmlType = qmlType;
- resolver->typenameCache = 0;
- resolver->flags = 0;
-}
-
-static QV4::IR::DiscoveredType resolveImportNamespace(
- QQmlEnginePrivate *, const QV4::IR::MemberExpressionResolver *resolver,
- QV4::IR::Member *member)
-{
- QV4::IR::Type result = QV4::IR::VarType;
- QQmlTypeNameCache *typeNamespace = resolver->typenameCache;
- const QQmlImportRef *importNamespace = resolver->import;
-
- QQmlTypeNameCache::Result r = typeNamespace->query(*member->name, importNamespace);
- if (r.isValid()) {
- member->freeOfSideEffects = true;
- if (r.scriptIndex != -1) {
- // TODO: remember the index and replace with subscript later.
- result = QV4::IR::VarType;
- } else if (r.type.isValid()) {
- // TODO: Propagate singleton information, so that it is loaded
- // through the singleton getter in the run-time. Until then we
- // can't accelerate access :(
- if (!r.type.isSingleton()) {
- auto newResolver = resolver->owner->New<QV4::IR::MemberExpressionResolver>();
- newResolver->owner = resolver->owner;
- initQmlTypeResolver(newResolver, r.type);
- return QV4::IR::DiscoveredType(newResolver);
- }
- } else {
- Q_ASSERT(false); // How can this happen?
- }
- }
-
- return result;
-}
-
-static void initImportNamespaceResolver(QV4::IR::MemberExpressionResolver *resolver,
- QQmlTypeNameCache *imports, const QQmlImportRef *importNamespace)
-{
- resolver->resolveMember = &resolveImportNamespace;
- resolver->import = importNamespace;
- resolver->typenameCache = imports;
- resolver->flags = 0;
-}
-
-static QV4::IR::DiscoveredType resolveMetaObjectProperty(
- QQmlEnginePrivate *qmlEngine, const QV4::IR::MemberExpressionResolver *resolver,
- QV4::IR::Member *member)
-{
- QV4::IR::Type result = QV4::IR::VarType;
- QQmlPropertyCache *metaObject = resolver->propertyCache;
-
- if (member->name->constData()->isUpper() && (resolver->flags & LookupsIncludeEnums)) {
- const QMetaObject *mo = metaObject->createMetaObject();
- QByteArray enumName = member->name->toUtf8();
- for (int ii = mo->enumeratorCount() - 1; ii >= 0; --ii) {
- QMetaEnum metaEnum = mo->enumerator(ii);
- bool ok;
- int value = metaEnum.keyToValue(enumName.constData(), &ok);
- if (ok) {
- member->setEnumValue(value);
- return QV4::IR::SInt32Type;
- }
- }
- }
-
- if (member->kind != QV4::IR::Member::MemberOfIdObjectsArray && member->kind != QV4::IR::Member::MemberOfSingletonObject &&
- qmlEngine && !(resolver->flags & LookupsExcludeProperties)) {
- QQmlPropertyData *property = member->property;
- if (!property && metaObject) {
- if (QQmlPropertyData *candidate = metaObject->property(*member->name, /*object*/0, /*context*/0)) {
- const bool isFinalProperty = (candidate->isFinal() || (resolver->flags & AllPropertiesAreFinal))
- && !candidate->isFunction();
-
- if (lookupHints()
- && !(resolver->flags & AllPropertiesAreFinal)
- && !candidate->isFinal()
- && !candidate->isFunction()
- && candidate->isDirect()) {
- qWarning() << "Hint: Access to property" << *member->name << "of" << metaObject->className() << "could be accelerated if it was marked as FINAL";
- }
-
- if (isFinalProperty && metaObject->isAllowedInRevision(candidate)) {
- property = candidate;
- member->inhibitTypeConversionOnWrite = true;
- if (!(resolver->flags & ResolveTypeInformationOnly))
- member->property = candidate; // Cache for next iteration and isel needs it.
- }
- }
- }
-
- if (property) {
- // Enums cannot be mapped to IR types, they need to go through the run-time handling
- // of accepting strings that will then be converted to the right values.
- if (property->isEnum())
- return QV4::IR::VarType;
-
- switch (property->propType()) {
- case QMetaType::Bool: result = QV4::IR::BoolType; break;
- case QMetaType::Int: result = QV4::IR::SInt32Type; break;
- case QMetaType::Double: result = QV4::IR::DoubleType; break;
- case QMetaType::QString: result = QV4::IR::StringType; break;
- default:
- if (property->isQObject()) {
- if (QQmlPropertyCache *cache = qmlEngine->propertyCacheForType(property->propType())) {
- auto newResolver = resolver->owner->New<QV4::IR::MemberExpressionResolver>();
- newResolver->owner = resolver->owner;
- initMetaObjectResolver(newResolver, cache);
- return QV4::IR::DiscoveredType(newResolver);
- }
- } else if (const QMetaObject *valueTypeMetaObject = QQmlValueTypeFactory::metaObjectForMetaType(property->propType())) {
- if (QQmlPropertyCache *cache = qmlEngine->cache(valueTypeMetaObject)) {
- auto newResolver = resolver->owner->New<QV4::IR::MemberExpressionResolver>();
- newResolver->owner = resolver->owner;
- initMetaObjectResolver(newResolver, cache);
- newResolver->flags |= ResolveTypeInformationOnly;
- return QV4::IR::DiscoveredType(newResolver);
- }
- }
- break;
- }
- }
- }
-
- return result;
-}
-
-static void initMetaObjectResolver(QV4::IR::MemberExpressionResolver *resolver, QQmlPropertyCache *metaObject)
-{
- Q_ASSERT(resolver);
-
- resolver->resolveMember = &resolveMetaObjectProperty;
- resolver->propertyCache = metaObject;
- resolver->flags = 0;
-}
-
-static QV4::IR::DiscoveredType resolveScopedEnum(QQmlEnginePrivate *qmlEngine,
- const QV4::IR::MemberExpressionResolver *resolver,
- QV4::IR::Member *member)
-{
- if (!member->name->constData()->isUpper())
- return QV4::IR::VarType;
-
- QQmlType type = resolver->qmlType;
- int index = resolver->flags;
-
- bool ok = false;
- int value = type.scopedEnumValue(qmlEngine, index, *member->name, &ok);
- if (!ok)
- return QV4::IR::VarType;
- member->setEnumValue(value);
- return QV4::IR::SInt32Type;
-}
-
-static void initScopedEnumResolver(QV4::IR::MemberExpressionResolver *resolver, const QQmlType &qmlType, int index)
-{
- Q_ASSERT(resolver);
-
- resolver->resolveMember = &resolveScopedEnum;
- resolver->qmlType = qmlType;
- resolver->flags = index;
-}
-#endif
-
-#endif // V4_BOOTSTRAP
-
-void JSCodeGen::beginFunctionBodyHook()
-{
- _qmlContextSlot = bytecodeGenerator->newRegister();
- _importedScriptsSlot = bytecodeGenerator->newRegister();
-
-#ifndef V4_BOOTSTRAP
- Instruction::LoadQmlContext load;
- load.result = Reference::fromStackSlot(this, _qmlContextSlot).stackSlot();
- bytecodeGenerator->addInstruction(load);
-
-#if 0
- temp->type = QV4::IR::QObjectType;
- temp->memberResolver = _function->New<QV4::IR::MemberExpressionResolver>();
- initMetaObjectResolver(temp->memberResolver, _scopeObject);
- auto name = _block->NAME(QV4::IR::Name::builtin_qml_context, 0, 0);
- name->type = temp->type;
-#endif
-
- Instruction::LoadQmlImportedScripts loadScripts;
- loadScripts.result = Reference::fromStackSlot(this, _importedScriptsSlot).stackSlot();
- bytecodeGenerator->addInstruction(loadScripts);
-#endif
-}
-
-QV4::Compiler::Codegen::Reference JSCodeGen::fallbackNameLookup(const QString &name)
-{
-#ifndef V4_BOOTSTRAP
- if (_disableAcceleratedLookups)
- return Reference();
-
- // Implement QML lookup semantics in the current file context.
- //
- // Note: We do not check if properties of the qml scope object or context object
- // are final. That's because QML tries to get as close as possible to lexical scoping,
- // which means in terms of properties that only those visible at compile time are chosen.
- // I.e. access to a "foo" property declared within the same QML component as "property int foo"
- // will always access that instance and as integer. If a sub-type implements its own property string foo,
- // then that one is not chosen for accesses from within this file, because it wasn't visible at compile
- // time. This corresponds to the logic in QQmlPropertyCache::findProperty to find the property associated
- // with the correct QML context.
-
- // Look for IDs first.
- for (const IdMapping &mapping : qAsConst(_idObjects)) {
- if (name == mapping.name) {
- if (_context->contextType == QV4::Compiler::ContextType::Binding)
- _context->idObjectDependencies.insert(mapping.idIndex);
-
- Instruction::LoadIdObject load;
- load.base = Reference::fromStackSlot(this, _qmlContextSlot).stackSlot();
- load.index = mapping.idIndex;
-
- Reference result = Reference::fromAccumulator(this);
- bytecodeGenerator->addInstruction(load);
- result.isReadonly = true;
- return result;
- }
- }
-
- if (name.at(0).isUpper()) {
- QQmlTypeNameCache::Result r = imports->query(name);
- if (r.isValid()) {
- if (r.scriptIndex != -1) {
- Reference imports = Reference::fromStackSlot(this, _importedScriptsSlot);
- return Reference::fromSubscript(imports, Reference::fromConst(this, QV4::Encode(r.scriptIndex)));
- } else if (r.type.isValid()) {
- return Reference::fromName(this, name);
- } else {
- Q_ASSERT(r.importNamespace);
- return Reference::fromName(this, name);
- }
- }
- }
-
- if (_scopeObject) {
- QQmlPropertyData *data = lookupQmlCompliantProperty(_scopeObject, name);
- if (data) {
- // Q_INVOKABLEs can't be FINAL, so we have to look them up at run-time
- if (data->isFunction())
- return Reference::fromName(this, name);
-
- Reference base = Reference::fromStackSlot(this, _qmlContextSlot);
- Reference::PropertyCapturePolicy capturePolicy;
- if (!data->isConstant() && !data->isQmlBinding())
- capturePolicy = Reference::CaptureAtRuntime;
- else
- capturePolicy = data->isConstant() ? Reference::DontCapture : Reference::CaptureAheadOfTime;
- return Reference::fromQmlScopeObject(base, data->coreIndex(), data->notifyIndex(), capturePolicy);
- }
- }
-
- if (_contextObject) {
- QQmlPropertyData *data = lookupQmlCompliantProperty(_contextObject, name);
- if (data) {
- // Q_INVOKABLEs can't be FINAL, so we have to look them up at run-time
- if (data->isFunction())
- return Reference::fromName(this, name);
-
- Reference base = Reference::fromStackSlot(this, _qmlContextSlot);
- Reference::PropertyCapturePolicy capturePolicy;
- if (!data->isConstant() && !data->isQmlBinding())
- capturePolicy = Reference::CaptureAtRuntime;
- else
- capturePolicy = data->isConstant() ? Reference::DontCapture : Reference::CaptureAheadOfTime;
- return Reference::fromQmlContextObject(base, data->coreIndex(), data->notifyIndex(), capturePolicy);
- }
- }
-#else
- Q_UNUSED(name)
-#endif // V4_BOOTSTRAP
- return Reference();
-}
-
#ifndef V4_BOOTSTRAP
QQmlPropertyData *PropertyResolver::property(const QString &name, bool *notInRevision, RevisionCheck check) const
@@ -2435,7 +2029,6 @@ QmlIR::Object *IRLoader::loadObject(const QV4::CompiledData::Object *serializedO
b->value.compiledScriptIndex = functionIndices.count() - 1;
QmlIR::CompiledFunctionOrExpression *foe = pool->New<QmlIR::CompiledFunctionOrExpression>();
- foe->disableAcceleratedLookups = true;
foe->nameIndex = 0;
QQmlJS::AST::ExpressionNode *expr;
diff --git a/src/qml/compiler/qqmlirbuilder_p.h b/src/qml/compiler/qqmlirbuilder_p.h
index 7c5944931e..22bc2d2953 100644
--- a/src/qml/compiler/qqmlirbuilder_p.h
+++ b/src/qml/compiler/qqmlirbuilder_p.h
@@ -282,7 +282,6 @@ struct Q_QML_PRIVATE_EXPORT CompiledFunctionOrExpression
QQmlJS::AST::Node *parentNode = nullptr; // FunctionDeclaration, Statement or Expression
QQmlJS::AST::Node *node = nullptr; // FunctionDeclaration, Statement or Expression
quint32 nameIndex = 0;
- bool disableAcceleratedLookups = false;
CompiledFunctionOrExpression *next = nullptr;
};
@@ -543,47 +542,16 @@ struct Q_QML_PRIVATE_EXPORT JSCodeGen : public QV4::Compiler::Codegen
{
JSCodeGen(const QString &sourceCode, QV4::Compiler::JSUnitGenerator *jsUnitGenerator, QV4::Compiler::Module *jsModule,
QQmlJS::Engine *jsEngine, QQmlJS::AST::UiProgram *qmlRoot,
- QQmlTypeNameCache *imports, const QV4::Compiler::StringTableGenerator *stringPool, const QSet<QString> &globalNames);
-
- struct IdMapping
- {
- QString name;
- int idIndex;
- QQmlPropertyCache *type;
- };
- typedef QVector<IdMapping> ObjectIdMapping;
-
- void beginContextScope(const ObjectIdMapping &objectIds, QQmlPropertyCache *contextObject);
- void beginObjectScope(QQmlPropertyCache *scopeObject);
+ const QV4::Compiler::StringTableGenerator *stringPool, const QSet<QString> &globalNames);
// Returns mapping from input functions to index in IR::Module::functions / compiledData->runtimeFunctions
QVector<int> generateJSCodeForFunctionsAndBindings(const QList<CompiledFunctionOrExpression> &functions);
- int defineFunction(const QString &name, AST::Node *ast,
- AST::FormalParameterList *formals,
- AST::StatementList *body) override;
-
-protected:
- void beginFunctionBodyHook() override;
- bool canAccelerateGlobalLookups() const override { return !_disableAcceleratedLookups; }
- Reference fallbackNameLookup(const QString &name) override;
-
private:
- // returns nullptr if lookup needs to happen by name
- QQmlPropertyData *lookupQmlCompliantProperty(QQmlPropertyCache *cache, const QString &name);
-
QString sourceCode;
QQmlJS::Engine *jsEngine; // needed for memory pool
QQmlJS::AST::UiProgram *qmlRoot;
- QQmlTypeNameCache *imports;
const QV4::Compiler::StringTableGenerator *stringPool;
-
- bool _disableAcceleratedLookups;
- ObjectIdMapping _idObjects;
- QQmlPropertyCache *_contextObject;
- QQmlPropertyCache *_scopeObject;
- int _qmlContextSlot;
- int _importedScriptsSlot;
};
struct Q_QML_PRIVATE_EXPORT IRLoader {
diff --git a/src/qml/compiler/qqmltypecompiler.cpp b/src/qml/compiler/qqmltypecompiler.cpp
index 70b048d737..66d3afc7a0 100644
--- a/src/qml/compiler/qqmltypecompiler.cpp
+++ b/src/qml/compiler/qqmltypecompiler.cpp
@@ -146,8 +146,7 @@ QQmlRefPointer<QV4::CompiledData::CompilationUnit> QQmlTypeCompiler::compile()
document->jsModule.fileName = typeData->urlString();
document->jsModule.finalUrl = typeData->finalUrlString();
QmlIR::JSCodeGen v4CodeGenerator(document->code, &document->jsGenerator, &document->jsModule, &document->jsParserEngine,
- document->program, typeNameCache.data(), &document->jsGenerator.stringTable, engine->v8engine()->illegalNames());
- v4CodeGenerator.setUseFastLookups(false);
+ document->program, &document->jsGenerator.stringTable, engine->v8engine()->illegalNames());
QQmlJSCodeGenerator jsCodeGen(this, &v4CodeGenerator);
if (!jsCodeGen.generateCodeForComponents())
return nullptr;
@@ -767,10 +766,6 @@ void QQmlScriptStringScanner::scan()
if (!pd || pd->propType() != scriptStringMetaType)
continue;
- QmlIR::CompiledFunctionOrExpression *foe = obj->functionsAndExpressions->slowAt(binding->value.compiledScriptIndex);
- if (foe)
- foe->disableAcceleratedLookups = true;
-
QString script = compiler->bindingAsString(obj, binding->value.compiledScriptIndex);
binding->stringIndex = compiler->registerString(script);
}
@@ -1324,24 +1319,6 @@ bool QQmlJSCodeGenerator::compileComponent(int contextObject)
contextObject = componentBinding->value.objectIndex;
}
- QmlIR::JSCodeGen::ObjectIdMapping idMapping;
- idMapping.reserve(obj->namedObjectsInComponent.size());
- for (int i = 0; i < obj->namedObjectsInComponent.size(); ++i) {
- const int objectIndex = obj->namedObjectsInComponent.at(i);
- QmlIR::JSCodeGen::IdMapping m;
- const QmlIR::Object *obj = qmlObjects.at(objectIndex);
- m.name = stringAt(obj->idNameIndex);
- m.idIndex = obj->id;
- m.type = propertyCaches->at(objectIndex);
-
- auto *tref = resolvedType(obj->inheritedTypeNameIndex);
- if (tref && tref->isFullyDynamicType)
- m.type = nullptr;
-
- idMapping << m;
- }
- v4CodeGen->beginContextScope(idMapping, propertyCaches->at(contextObject));
-
if (!compileJavaScriptCodeInObjectsRecursively(contextObject, contextObject))
return false;
@@ -1355,16 +1332,9 @@ bool QQmlJSCodeGenerator::compileJavaScriptCodeInObjectsRecursively(int objectIn
return true;
if (object->functionsAndExpressions->count > 0) {
- QQmlPropertyCache *scopeObject = propertyCaches->at(scopeObjectIndex);
- v4CodeGen->beginObjectScope(scopeObject);
-
QList<QmlIR::CompiledFunctionOrExpression> functionsToCompile;
- for (QmlIR::CompiledFunctionOrExpression *foe = object->functionsAndExpressions->first; foe; foe = foe->next) {
- const bool haveCustomParser = customParsers.contains(object->inheritedTypeNameIndex);
- if (haveCustomParser)
- foe->disableAcceleratedLookups = true;
+ for (QmlIR::CompiledFunctionOrExpression *foe = object->functionsAndExpressions->first; foe; foe = foe->next)
functionsToCompile << *foe;
- }
const QVector<int> runtimeFunctionIndices = v4CodeGen->generateJSCodeForFunctionsAndBindings(functionsToCompile);
const QList<QQmlError> jsErrors = v4CodeGen->qmlErrors();
if (!jsErrors.isEmpty()) {
diff --git a/src/qml/compiler/qv4codegen.cpp b/src/qml/compiler/qv4codegen.cpp
index 009545eceb..f497184ab5 100644
--- a/src/qml/compiler/qv4codegen.cpp
+++ b/src/qml/compiler/qv4codegen.cpp
@@ -1875,8 +1875,6 @@ bool Codegen::visit(CallExpression *ast)
switch (base.type) {
case Reference::Member:
case Reference::Subscript:
- case Reference::QmlScopeObject:
- case Reference::QmlContextObject:
base = base.asLValue();
break;
case Reference::Name:
@@ -1938,21 +1936,7 @@ bool Codegen::visit(CallExpression *ast)
void Codegen::handleCall(Reference &base, Arguments calldata, int slotForFunction, int slotForThisObject)
{
//### Do we really need all these call instructions? can's we load the callee in a temp?
- if (base.type == Reference::QmlScopeObject) {
- Instruction::CallScopeObjectProperty call;
- call.base = base.qmlBase.stackSlot();
- call.name = base.qmlCoreIndex;
- call.argc = calldata.argc;
- call.argv = calldata.argv;
- bytecodeGenerator->addTracingInstruction(call);
- } else if (base.type == Reference::QmlContextObject) {
- Instruction::CallContextObjectProperty call;
- call.base = base.qmlBase.stackSlot();
- call.name = base.qmlCoreIndex;
- call.argc = calldata.argc;
- call.argv = calldata.argv;
- bytecodeGenerator->addTracingInstruction(call);
- } else if (base.type == Reference::Member) {
+ if (base.type == Reference::Member) {
if (!disable_lookups && useFastLookups) {
Instruction::CallPropertyLookup call;
call.base = base.propertyBase.stackSlot();
@@ -1982,11 +1966,19 @@ void Codegen::handleCall(Reference &base, Arguments calldata, int slotForFunctio
call.argv = calldata.argv;
bytecodeGenerator->addTracingInstruction(call);
} else if (!disable_lookups && useFastLookups && base.global) {
- Instruction::CallGlobalLookup call;
- call.index = registerGlobalGetterLookup(base.nameAsIndex());
- call.argc = calldata.argc;
- call.argv = calldata.argv;
- bytecodeGenerator->addTracingInstruction(call);
+ if (base.qmlGlobal) {
+ Instruction::CallQmlContextPropertyLookup call;
+ call.index = registerQmlContextPropertyGetterLookup(base.nameAsIndex());
+ call.argc = calldata.argc;
+ call.argv = calldata.argv;
+ bytecodeGenerator->addTracingInstruction(call);
+ } else {
+ Instruction::CallGlobalLookup call;
+ call.index = registerGlobalGetterLookup(base.nameAsIndex());
+ call.argc = calldata.argc;
+ call.argv = calldata.argv;
+ bytecodeGenerator->addTracingInstruction(call);
+ }
} else {
Instruction::CallName call;
call.name = base.nameAsIndex();
@@ -2355,14 +2347,10 @@ Codegen::Reference Codegen::referenceForName(const QString &name, bool isLhs, co
return r;
}
- // This hook allows implementing QML lookup semantics
- Reference fallback = fallbackNameLookup(name);
- if (fallback.type != Reference::Invalid)
- return fallback;
-
Reference r = Reference::fromName(this, name);
- r.global = useFastLookups && (resolved.type == Context::ResolvedName::Global);
- if (!r.global && canAccelerateGlobalLookups() && m_globalNames.contains(name))
+ r.global = useFastLookups && (resolved.type == Context::ResolvedName::Global || resolved.type == Context::ResolvedName::QmlGlobal);
+ r.qmlGlobal = resolved.type == Context::ResolvedName::QmlGlobal;
+ if (!r.global && !r.qmlGlobal && m_globalNames.contains(name))
r.global = true;
return r;
}
@@ -2378,12 +2366,6 @@ void Codegen::loadClosure(int closureId)
}
}
-Codegen::Reference Codegen::fallbackNameLookup(const QString &name)
-{
- Q_UNUSED(name)
- return Reference();
-}
-
bool Codegen::visit(IdentifierExpression *ast)
{
if (hasError)
@@ -3090,8 +3072,6 @@ int Codegen::defineFunction(const QString &name, AST::Node *ast,
bytecodeGenerator->addInstruction(yield);
}
- beginFunctionBodyHook();
-
statementList(body);
if (!hasError) {
@@ -4034,10 +4014,6 @@ bool Codegen::Reference::operator==(const Codegen::Reference &other) const
return index == other.index;
case Const:
return constant == other.constant;
- case QmlScopeObject:
- case QmlContextObject:
- return qmlCoreIndex == other.qmlCoreIndex && qmlNotifyIndex == other.qmlNotifyIndex
- && capturePolicy == other.capturePolicy;
}
return true;
}
@@ -4095,9 +4071,7 @@ Codegen::Reference Codegen::Reference::storeConsumeAccumulator() const
Codegen::Reference Codegen::Reference::baseObject() const
{
- if (type == Reference::QmlScopeObject || type == Reference::QmlContextObject) {
- return Reference::fromStackSlot(codegen, qmlBase.stackSlot());
- } else if (type == Reference::Member) {
+ if (type == Reference::Member) {
RValue rval = propertyBase;
if (!rval.isValid())
return Reference::fromConst(codegen, Encode::undefined());
@@ -4182,8 +4156,6 @@ bool Codegen::Reference::storeWipesAccumulator() const
case Name:
case Member:
case Subscript:
- case QmlScopeObject:
- case QmlContextObject:
return true;
}
}
@@ -4263,18 +4235,6 @@ void Codegen::Reference::storeAccumulator() const
store.index = elementSubscript.stackSlot();
codegen->bytecodeGenerator->addTracingInstruction(store);
} return;
- case QmlScopeObject: {
- Instruction::StoreScopeObjectProperty store;
- store.base = qmlBase;
- store.propertyIndex = qmlCoreIndex;
- codegen->bytecodeGenerator->addInstruction(store);
- } return;
- case QmlContextObject: {
- Instruction::StoreContextObjectProperty store;
- store.base = qmlBase;
- store.propertyIndex = qmlCoreIndex;
- codegen->bytecodeGenerator->addInstruction(store);
- } return;
case Invalid:
case Accumulator:
case Const:
@@ -4389,9 +4349,15 @@ QT_WARNING_POP
}
}
if (!disable_lookups && global) {
- Instruction::LoadGlobalLookup load;
- load.index = codegen->registerGlobalGetterLookup(nameAsIndex());
- codegen->bytecodeGenerator->addTracingInstruction(load);
+ if (qmlGlobal) {
+ Instruction::LoadQmlContextPropertyLookup load;
+ load.index = codegen->registerQmlContextPropertyGetterLookup(nameAsIndex());
+ codegen->bytecodeGenerator->addTracingInstruction(load);
+ } else {
+ Instruction::LoadGlobalLookup load;
+ load.index = codegen->registerGlobalGetterLookup(nameAsIndex());
+ codegen->bytecodeGenerator->addTracingInstruction(load);
+ }
} else {
Instruction::LoadName load;
load.name = nameAsIndex();
@@ -4425,24 +4391,6 @@ QT_WARNING_POP
load.base = elementBase;
codegen->bytecodeGenerator->addTracingInstruction(load);
} return;
- case QmlScopeObject: {
- Instruction::LoadScopeObjectProperty load;
- load.base = qmlBase;
- load.propertyIndex = qmlCoreIndex;
- load.captureRequired = capturePolicy == CaptureAtRuntime;
- codegen->bytecodeGenerator->addInstruction(load);
- if (capturePolicy == CaptureAheadOfTime)
- codegen->_context->scopeObjectPropertyDependencies.insert(qmlCoreIndex, qmlNotifyIndex);
- } return;
- case QmlContextObject: {
- Instruction::LoadContextObjectProperty load;
- load.base = qmlBase;
- load.propertyIndex = qmlCoreIndex;
- load.captureRequired = capturePolicy == CaptureAtRuntime;
- codegen->bytecodeGenerator->addInstruction(load);
- if (capturePolicy == CaptureAheadOfTime)
- codegen->_context->contextObjectPropertyDependencies.insert(qmlCoreIndex, qmlNotifyIndex);
- } return;
case Invalid:
break;
}
diff --git a/src/qml/compiler/qv4codegen_p.h b/src/qml/compiler/qv4codegen_p.h
index 0b25d9c53d..ad86483132 100644
--- a/src/qml/compiler/qv4codegen_p.h
+++ b/src/qml/compiler/qv4codegen_p.h
@@ -184,9 +184,7 @@ public:
Member,
Subscript,
Import,
- QmlScopeObject,
- QmlContextObject,
- LastLValue = QmlContextObject,
+ LastLValue = Import,
Const
} type = Invalid;
@@ -207,7 +205,8 @@ public:
subscriptRequiresTDZCheck(false),
stackSlotIsLocalOrArgument(false),
isVolatile(false),
- global(false)
+ global(false),
+ qmlGlobal(false)
{}
Reference(const Reference &) = default;
@@ -222,10 +221,6 @@ public:
bool isValid() const { return type != Invalid; }
bool loadTriggersSideEffect() const {
switch (type) {
- case QmlScopeObject:
- return capturePolicy != DontCapture;
- case QmlContextObject:
- return capturePolicy != DontCapture;
case Name:
case Member:
case Subscript:
@@ -244,28 +239,6 @@ public:
return isStackSlot();
}
- enum PropertyCapturePolicy {
- /*
- We're reading a property from the scope or context object, but it's a CONSTANT property,
- so we don't need to register a dependency at all.
- */
- DontCapture,
- /*
- We're reading the property of a QObject, and we know that it's the
- scope object or context object, which we know very well. Instead of registering a
- property capture every time, we can do that ahead of time and then register all those
- captures in one shot in registerQmlDependencies().
- */
- CaptureAheadOfTime,
- /*
- We're reading the property of a QObject, and we're not quite sure where
- the QObject comes from or what it is. So, when reading that property at run-time,
- make sure that we capture where we read that property so that if it changes we can
- re-evaluate the entire expression.
- */
- CaptureAtRuntime
- };
-
static Reference fromAccumulator(Codegen *cg) {
return Reference(cg, Accumulator);
}
@@ -332,22 +305,6 @@ public:
r.isReadonly = true;
return r;
}
- static Reference fromQmlScopeObject(const Reference &base, qint16 coreIndex, qint16 notifyIndex, PropertyCapturePolicy capturePolicy) {
- Reference r(base.codegen, QmlScopeObject);
- r.qmlBase = base.storeOnStack().stackSlot();
- r.qmlCoreIndex = coreIndex;
- r.qmlNotifyIndex = notifyIndex;
- r.capturePolicy = capturePolicy;
- return r;
- }
- static Reference fromQmlContextObject(const Reference &base, qint16 coreIndex, qint16 notifyIndex, PropertyCapturePolicy capturePolicy) {
- Reference r(base.codegen, QmlContextObject);
- r.qmlBase = base.storeOnStack().stackSlot();
- r.qmlCoreIndex = coreIndex;
- r.qmlNotifyIndex = notifyIndex;
- r.capturePolicy = capturePolicy;
- return r;
- }
static Reference fromThis(Codegen *cg) {
Reference r = fromStackSlot(cg, CallData::This);
r.isReadonly = true;
@@ -402,12 +359,6 @@ public:
Moth::StackSlot elementBase;
RValue elementSubscript;
};
- struct { // QML scope/context object case
- Moth::StackSlot qmlBase;
- qint16 qmlCoreIndex;
- qint16 qmlNotifyIndex;
- PropertyCapturePolicy capturePolicy;
- };
Moth::StackSlot property; // super property
};
QString name;
@@ -421,6 +372,7 @@ public:
quint32 stackSlotIsLocalOrArgument:1;
quint32 isVolatile:1;
quint32 global:1;
+ quint32 qmlGlobal:1;
private:
void storeAccumulator() const;
@@ -553,6 +505,7 @@ public:
int registerGetterLookup(int nameIndex) { return jsUnitGenerator->registerGetterLookup(nameIndex); }
int registerSetterLookup(int nameIndex) { return jsUnitGenerator->registerSetterLookup(nameIndex); }
int registerGlobalGetterLookup(int nameIndex) { return jsUnitGenerator->registerGlobalGetterLookup(nameIndex); }
+ int registerQmlContextPropertyGetterLookup(int nameIndex) { return jsUnitGenerator->registerQmlContextPropertyGetterLookup(nameIndex); }
// Returns index in _module->functions
virtual int defineFunction(const QString &name, AST::Node *ast,
@@ -595,12 +548,6 @@ protected:
Reference referenceForPropertyName(const Codegen::Reference &object, AST::PropertyName *name);
- // Hooks provided to implement QML lookup semantics
- virtual bool canAccelerateGlobalLookups() const { return true; }
- virtual Reference fallbackNameLookup(const QString &name);
-
- virtual void beginFunctionBodyHook() {}
-
void emitReturn(const Reference &expr);
// nodes
diff --git a/src/qml/compiler/qv4compileddata.cpp b/src/qml/compiler/qv4compileddata.cpp
index cb614f7d40..b110fafaac 100644
--- a/src/qml/compiler/qv4compileddata.cpp
+++ b/src/qml/compiler/qv4compileddata.cpp
@@ -51,6 +51,8 @@
#include <private/qqmlengine_p.h>
#include <private/qv4vme_moth_p.h>
#include <private/qv4module_p.h>
+#include <private/qv4qobjectwrapper_p.h>
+#include <private/qqmlvaluetypewrapper_p.h>
#include "qv4compilationunitmapper_p.h"
#include <QQmlPropertyMap>
#include <QDateTime>
@@ -168,6 +170,8 @@ QV4::Function *CompilationUnit::linkToEngine(ExecutionEngine *engine)
l->setter = QV4::Lookup::setterGeneric;
else if (type == CompiledData::Lookup::Type_GlobalGetter)
l->globalGetter = QV4::Lookup::globalGetterGeneric;
+ else if (type == CompiledData::Lookup::Type_QmlContextPropertyGetter)
+ l->qmlContextPropertyGetter = QQmlContextWrapper::resolveQmlContextPropertyLookupGetter;
l->nameIndex = compiledLookups[i].nameIndex;
}
}
@@ -270,6 +274,24 @@ void CompilationUnit::unlink()
propertyCaches.clear();
+ if (runtimeLookups) {
+ for (uint i = 0; i < data->lookupTableSize; ++i) {
+ QV4::Lookup &l = runtimeLookups[i];
+ if (l.getter == QV4::QObjectWrapper::lookupGetter) {
+ if (QQmlPropertyCache *pc = l.qobjectLookup.propertyCache)
+ pc->release();
+ } else if (l.getter == QQmlValueTypeWrapper::lookupGetter) {
+ if (QQmlPropertyCache *pc = l.qgadgetLookup.propertyCache)
+ pc->release();
+ }
+
+ if (l.qmlContextPropertyGetter == QQmlContextWrapper::lookupScopeObjectProperty) {
+ if (QQmlPropertyCache *pc = l.qobjectLookup.propertyCache)
+ pc->release();
+ }
+ }
+ }
+
dependentScripts.clear();
typeNameCache = nullptr;
diff --git a/src/qml/compiler/qv4compileddata_p.h b/src/qml/compiler/qv4compileddata_p.h
index 2dccc8db04..2d7a027b37 100644
--- a/src/qml/compiler/qv4compileddata_p.h
+++ b/src/qml/compiler/qv4compileddata_p.h
@@ -73,7 +73,7 @@
QT_BEGIN_NAMESPACE
// Bump this whenever the compiler data structures change in an incompatible way.
-#define QV4_DATA_STRUCTURE_VERSION 0x1b
+#define QV4_DATA_STRUCTURE_VERSION 0x21
class QIODevice;
class QQmlPropertyCache;
@@ -160,9 +160,10 @@ static_assert(sizeof(RegExp) == 4, "RegExp structure needs to have the expected
struct Lookup
{
enum Type : unsigned int {
- Type_Getter = 0x0,
- Type_Setter = 0x1,
- Type_GlobalGetter = 2
+ Type_Getter = 0,
+ Type_Setter = 1,
+ Type_GlobalGetter = 2,
+ Type_QmlContextPropertyGetter = 3
};
union {
@@ -287,29 +288,16 @@ struct Function
quint16_le nRegisters;
Location location;
- // Qml Extensions Begin
- // Array of resolved ID objects
- size_t dependingIdObjectsOffset() const { return lineNumberOffset() + nLineNumbers * sizeof(CodeOffsetToLine); }
- quint16_le nDependingIdObjects;
- quint16_le nDependingContextProperties;
- // Array of int pairs (property index and notify index)
- size_t dependingContextPropertiesOffset() const { return dependingIdObjectsOffset() + nDependingIdObjects * sizeof(quint32); }
- quint16_le nDependingScopeProperties;
- // Array of int pairs (property index and notify index)
- size_t dependingScopePropertiesOffset() const { return dependingContextPropertiesOffset() + nDependingContextProperties * sizeof(quint32); }
- // Qml Extensions End
+ quint32_le nLabelInfos;
+ size_t labelInfosOffset() const { return lineNumberOffset() + nLineNumbers * sizeof(CodeOffsetToLine); }
typedef quint16_le TraceInfoCount;
TraceInfoCount nTraceInfos;
static constexpr TraceInfoCount NoTracing() { return TraceInfoCount::max(); }
- quint32_le nLabelInfos;
- size_t labelInfosOffset() const { return dependingScopePropertiesOffset() + nDependingScopeProperties; }
-
// Keep all unaligned data at the end
quint8 flags;
quint8 padding1;
- quint16 padding2;
// quint32 formalsIndex[nFormals]
// quint32 localsIndex[nLocals]
@@ -317,9 +305,6 @@ struct Function
const quint32_le *formalsTable() const { return reinterpret_cast<const quint32_le *>(reinterpret_cast<const char *>(this) + formalsOffset); }
const quint32_le *localsTable() const { return reinterpret_cast<const quint32_le *>(reinterpret_cast<const char *>(this) + localsOffset); }
const CodeOffsetToLine *lineNumberTable() const { return reinterpret_cast<const CodeOffsetToLine *>(reinterpret_cast<const char *>(this) + lineNumberOffset()); }
- const quint32_le *qmlIdObjectDependencyTable() const { return reinterpret_cast<const quint32_le *>(reinterpret_cast<const char *>(this) + dependingIdObjectsOffset()); }
- const quint32_le *qmlContextPropertiesDependencyTable() const { return reinterpret_cast<const quint32_le *>(reinterpret_cast<const char *>(this) + dependingContextPropertiesOffset()); }
- const quint32_le *qmlScopePropertiesDependencyTable() const { return reinterpret_cast<const quint32_le *>(reinterpret_cast<const char *>(this) + dependingScopePropertiesOffset()); }
// --- QQmlPropertyCacheCreator interface
const quint32_le *formalsBegin() const { return formalsTable(); }
@@ -330,11 +315,9 @@ struct Function
const char *code() const { return reinterpret_cast<const char *>(this) + codeOffset; }
- inline bool hasQmlDependencies() const { return nDependingIdObjects > 0 || nDependingContextProperties > 0 || nDependingScopeProperties > 0; }
-
- static int calculateSize(int nFormals, int nLocals, int nLines, int nInnerfunctions, int nIdObjectDependencies, int nPropertyDependencies, int labelInfoSize, int codeSize) {
- int trailingData = (nFormals + nLocals + nInnerfunctions + nIdObjectDependencies + labelInfoSize +
- 2 * nPropertyDependencies)*sizeof (quint32) + nLines*sizeof(CodeOffsetToLine);
+ static int calculateSize(int nFormals, int nLocals, int nLines, int nInnerfunctions, int labelInfoSize, int codeSize) {
+ int trailingData = (nFormals + nLocals + nInnerfunctions + labelInfoSize)*sizeof (quint32)
+ + nLines*sizeof(CodeOffsetToLine);
size_t size = align(align(sizeof(Function)) + size_t(trailingData)) + align(codeSize);
Q_ASSERT(size < INT_MAX);
return int(size);
@@ -344,7 +327,7 @@ struct Function
return (a + 7) & ~size_t(7);
}
};
-static_assert(sizeof(Function) == 60, "Function structure needs to have the expected size to be binary compatible on disk when generated by host compiler and loaded by target");
+static_assert(sizeof(Function) == 52, "Function structure needs to have the expected size to be binary compatible on disk when generated by host compiler and loaded by target");
struct Method {
enum Type {
diff --git a/src/qml/compiler/qv4compiler.cpp b/src/qml/compiler/qv4compiler.cpp
index 0833f552e6..01c033cb2a 100644
--- a/src/qml/compiler/qv4compiler.cpp
+++ b/src/qml/compiler/qv4compiler.cpp
@@ -154,15 +154,19 @@ int QV4::Compiler::JSUnitGenerator::registerSetterLookup(int nameIndex)
return lookups.size() - 1;
}
-int QV4::Compiler::JSUnitGenerator::registerGlobalGetterLookup(const QString &name)
+int QV4::Compiler::JSUnitGenerator::registerGlobalGetterLookup(int nameIndex)
{
- return registerGlobalGetterLookup(registerString(name));
+ CompiledData::Lookup l;
+ l.type_and_flags = CompiledData::Lookup::Type_GlobalGetter;
+ l.nameIndex = nameIndex;
+ lookups << l;
+ return lookups.size() - 1;
}
-int QV4::Compiler::JSUnitGenerator::registerGlobalGetterLookup(int nameIndex)
+int QV4::Compiler::JSUnitGenerator::registerQmlContextPropertyGetterLookup(int nameIndex)
{
CompiledData::Lookup l;
- l.type_and_flags = CompiledData::Lookup::Type_GlobalGetter;
+ l.type_and_flags = CompiledData::Lookup::Type_QmlContextPropertyGetter;
l.nameIndex = nameIndex;
lookups << l;
return lookups.size() - 1;
@@ -423,28 +427,6 @@ void QV4::Compiler::JSUnitGenerator::writeFunction(char *f, QV4::Compiler::Conte
function->nTraceInfos = irFunction->nTraceInfos;
function->nRegisters = irFunction->registerCountInFunction;
- function->nDependingIdObjects = 0;
- function->nDependingContextProperties = 0;
- function->nDependingScopeProperties = 0;
-
- if (!irFunction->idObjectDependencies.isEmpty()) {
- function->nDependingIdObjects = irFunction->idObjectDependencies.count();
- Q_ASSERT(function->dependingIdObjectsOffset() == currentOffset);
- currentOffset += function->nDependingIdObjects * sizeof(quint32);
- }
-
- if (!irFunction->contextObjectPropertyDependencies.isEmpty()) {
- function->nDependingContextProperties = irFunction->contextObjectPropertyDependencies.count();
- Q_ASSERT(function->dependingContextPropertiesOffset() == currentOffset);
- currentOffset += function->nDependingContextProperties * sizeof(quint32) * 2;
- }
-
- if (!irFunction->scopeObjectPropertyDependencies.isEmpty()) {
- function->nDependingScopeProperties = irFunction->scopeObjectPropertyDependencies.count();
- Q_ASSERT(function->dependingScopePropertiesOffset() == currentOffset);
- currentOffset += function->nDependingScopeProperties * sizeof(quint32) * 2;
- }
-
if (!irFunction->labelInfo.empty()) {
function->nLabelInfos = quint32(irFunction->labelInfo.size());
Q_ASSERT(function->labelInfosOffset() == currentOffset);
@@ -470,25 +452,6 @@ void QV4::Compiler::JSUnitGenerator::writeFunction(char *f, QV4::Compiler::Conte
// write line numbers
memcpy(f + function->lineNumberOffset(), irFunction->lineNumberMapping.constData(), irFunction->lineNumberMapping.size()*sizeof(CompiledData::CodeOffsetToLine));
- // write QML dependencies
- quint32_le *writtenDeps = (quint32_le *)(f + function->dependingIdObjectsOffset());
- for (int id : irFunction->idObjectDependencies) {
- Q_ASSERT(id >= 0);
- *writtenDeps++ = static_cast<quint32>(id);
- }
-
- writtenDeps = (quint32_le *)(f + function->dependingContextPropertiesOffset());
- for (auto property : irFunction->contextObjectPropertyDependencies) {
- *writtenDeps++ = property.key(); // property index
- *writtenDeps++ = property.value(); // notify index
- }
-
- writtenDeps = (quint32_le *)(f + function->dependingScopePropertiesOffset());
- for (auto property : irFunction->scopeObjectPropertyDependencies) {
- *writtenDeps++ = property.key(); // property index
- *writtenDeps++ = property.value(); // notify index
- }
-
quint32_le *labels = (quint32_le *)(f + function->labelInfosOffset());
for (unsigned u : irFunction->labelInfo) {
*labels++ = u;
@@ -690,10 +653,8 @@ QV4::CompiledData::Unit QV4::Compiler::JSUnitGenerator::generateHeader(QV4::Comp
Context *f = module->functions.at(i);
blockAndFunctionOffsets[i] = nextOffset;
- const int qmlIdDepsCount = f->idObjectDependencies.count();
- const int qmlPropertyDepsCount = f->scopeObjectPropertyDependencies.count() + f->contextObjectPropertyDependencies.count();
quint32 size = QV4::CompiledData::Function::calculateSize(f->arguments.size(), f->locals.size(), f->lineNumberMapping.size(), f->nestedContexts.size(),
- qmlIdDepsCount, qmlPropertyDepsCount, int(f->labelInfo.size()), f->code.size());
+ int(f->labelInfo.size()), f->code.size());
functionSize += size - f->code.size();
nextOffset += size;
}
diff --git a/src/qml/compiler/qv4compiler_p.h b/src/qml/compiler/qv4compiler_p.h
index 2f5889ab53..49e334bb81 100644
--- a/src/qml/compiler/qv4compiler_p.h
+++ b/src/qml/compiler/qv4compiler_p.h
@@ -118,8 +118,8 @@ struct Q_QML_PRIVATE_EXPORT JSUnitGenerator {
int registerGetterLookup(int nameIndex);
int registerSetterLookup(const QString &name);
int registerSetterLookup(int nameIndex);
- int registerGlobalGetterLookup(const QString &name);
int registerGlobalGetterLookup(int nameIndex);
+ int registerQmlContextPropertyGetterLookup(int nameIndex);
int registerRegExp(QQmlJS::AST::RegExpLiteral *regexp);
diff --git a/src/qml/compiler/qv4compilercontext.cpp b/src/qml/compiler/qv4compilercontext.cpp
index 419c77fc03..afac8d0b4d 100644
--- a/src/qml/compiler/qv4compilercontext.cpp
+++ b/src/qml/compiler/qv4compilercontext.cpp
@@ -187,10 +187,13 @@ Context::ResolvedName Context::resolveName(const QString &name, const QQmlJS::AS
}
// ### can we relax the restrictions here?
- if (c->contextType == ContextType::Eval || c->contextType == ContextType::Binding)
+ if (c->contextType == ContextType::Eval)
return result;
- result.type = ResolvedName::Global;
+ if (c->contextType == ContextType::Binding)
+ result.type = ResolvedName::QmlGlobal;
+ else
+ result.type = ResolvedName::Global;
return result;
}
diff --git a/src/qml/compiler/qv4compilercontext_p.h b/src/qml/compiler/qv4compilercontext_p.h
index 5b91b93346..cb20ea9d57 100644
--- a/src/qml/compiler/qv4compilercontext_p.h
+++ b/src/qml/compiler/qv4compilercontext_p.h
@@ -278,11 +278,6 @@ struct Context {
}
};
- // Qml extension:
- SmallSet<int> idObjectDependencies;
- PropertyDependencyMap contextObjectPropertyDependencies;
- PropertyDependencyMap scopeObjectPropertyDependencies;
-
Context(Context *parent, ContextType type)
: parent(parent)
, contextType(type)
@@ -338,6 +333,7 @@ struct Context {
struct ResolvedName {
enum Type {
Unresolved,
+ QmlGlobal,
Global,
Local,
Stack,
diff --git a/src/qml/compiler/qv4instr_moth.cpp b/src/qml/compiler/qv4instr_moth.cpp
index c0b1be1492..345f03ae8a 100644
--- a/src/qml/compiler/qv4instr_moth.cpp
+++ b/src/qml/compiler/qv4instr_moth.cpp
@@ -287,6 +287,10 @@ void dumpBytecode(const char *code, int len, int nLocals, int nFormals, int /*st
d << index << TRACE_SLOT;
MOTH_END_INSTR(LoadGlobalLookup)
+ MOTH_BEGIN_INSTR(LoadQmlContextPropertyLookup)
+ d << index << TRACE_SLOT;
+ MOTH_END_INSTR(LoadQmlContextPropertyLookup)
+
MOTH_BEGIN_INSTR(StoreNameSloppy)
d << name;
MOTH_END_INSTR(StoreNameSloppy)
@@ -328,26 +332,6 @@ void dumpBytecode(const char *code, int len, int nLocals, int nFormals, int /*st
d << dumpRegister(property, nFormals);
MOTH_END_INSTR(StoreSuperProperty)
- MOTH_BEGIN_INSTR(StoreScopeObjectProperty)
- d << dumpRegister(base, nFormals) << "[" << propertyIndex << "]";
- MOTH_END_INSTR(StoreScopeObjectProperty)
-
- MOTH_BEGIN_INSTR(LoadScopeObjectProperty)
- d << dumpRegister(base, nFormals) << "[" << propertyIndex << "]" << (captureRequired ? " (capture)" : " (no capture)");
- MOTH_END_INSTR(LoadScopeObjectProperty)
-
- MOTH_BEGIN_INSTR(StoreContextObjectProperty)
- d << dumpRegister(base, nFormals) << "[" << propertyIndex << "]";
- MOTH_END_INSTR(StoreContextObjectProperty)
-
- MOTH_BEGIN_INSTR(LoadContextObjectProperty)
- d << dumpRegister(base, nFormals) << "[" << propertyIndex << "]" << (captureRequired ? " (capture)" : " (no capture)");
- MOTH_END_INSTR(LoadContextObjectProperty)
-
- MOTH_BEGIN_INSTR(LoadIdObject)
- d << dumpRegister(base, nFormals) << "[" << index << "]";
- MOTH_END_INSTR(LoadIdObject)
-
MOTH_BEGIN_INSTR(Yield)
MOTH_END_INSTR(Yield)
@@ -394,15 +378,9 @@ void dumpBytecode(const char *code, int len, int nLocals, int nFormals, int /*st
d << index << dumpArguments(argc, argv, nFormals) << TRACE_SLOT;
MOTH_END_INSTR(CallGlobalLookup)
- MOTH_BEGIN_INSTR(CallScopeObjectProperty)
- d << dumpRegister(base, nFormals) << "." << name << dumpArguments(argc, argv, nFormals)
- << TRACE_SLOT;
- MOTH_END_INSTR(CallScopeObjectProperty)
-
- MOTH_BEGIN_INSTR(CallContextObjectProperty)
- d << dumpRegister(base, nFormals) << "." << name << dumpArguments(argc, argv, nFormals)
- << TRACE_SLOT;
- MOTH_END_INSTR(CallContextObjectProperty)
+ MOTH_BEGIN_INSTR(CallQmlContextPropertyLookup)
+ d << index << dumpArguments(argc, argv, nFormals) << TRACE_SLOT;
+ MOTH_END_INSTR(CallQmlContextPropertyLookup)
MOTH_BEGIN_INSTR(CallWithSpread)
d << "new " << dumpRegister(func, nFormals) << dumpRegister(thisObject, nFormals)
@@ -729,14 +707,6 @@ void dumpBytecode(const char *code, int len, int nLocals, int nFormals, int /*st
d << index;
MOTH_END_INSTR(GetTemplateObject)
- MOTH_BEGIN_INSTR(LoadQmlContext)
- d << dumpRegister(result, nFormals);
- MOTH_END_INSTR(LoadQmlContext)
-
- MOTH_BEGIN_INSTR(LoadQmlImportedScripts)
- d << dumpRegister(result, nFormals);
- MOTH_END_INSTR(LoadQmlImportedScripts)
-
MOTH_BEGIN_INSTR(TailCall)
d << dumpRegister(func, nFormals) << dumpRegister(thisObject, nFormals) << dumpArguments(argc, argv, nFormals);
MOTH_END_INSTR(TailCall)
diff --git a/src/qml/compiler/qv4instr_moth_p.h b/src/qml/compiler/qv4instr_moth_p.h
index 3996143843..26901c297c 100644
--- a/src/qml/compiler/qv4instr_moth_p.h
+++ b/src/qml/compiler/qv4instr_moth_p.h
@@ -86,12 +86,11 @@ QT_BEGIN_NAMESPACE
#define INSTR_LoadClosure(op) INSTRUCTION(op, LoadClosure, 1, value)
#define INSTR_LoadName(op) INSTRUCTION(op, LoadName, 2, name, traceSlot)
#define INSTR_LoadGlobalLookup(op) INSTRUCTION(op, LoadGlobalLookup, 2, index, traceSlot)
+#define INSTR_LoadQmlContextPropertyLookup(op) INSTRUCTION(op, LoadQmlContextPropertyLookup, 2, index, traceSlot)
#define INSTR_StoreNameSloppy(op) INSTRUCTION(op, StoreNameSloppy, 1, name)
#define INSTR_StoreNameStrict(op) INSTRUCTION(op, StoreNameStrict, 1, name)
#define INSTR_LoadProperty(op) INSTRUCTION(op, LoadProperty, 2, name, traceSlot)
#define INSTR_GetLookup(op) INSTRUCTION(op, GetLookup, 2, index, traceSlot)
-#define INSTR_LoadScopeObjectProperty(op) INSTRUCTION(op, LoadScopeObjectProperty, 3, propertyIndex, base, captureRequired)
-#define INSTR_LoadContextObjectProperty(op) INSTRUCTION(op, LoadContextObjectProperty, 3, propertyIndex, base, captureRequired)
#define INSTR_LoadIdObject(op) INSTRUCTION(op, LoadIdObject, 2, index, base)
#define INSTR_Yield(op) INSTRUCTION(op, Yield, 0)
#define INSTR_YieldStar(op) INSTRUCTION(op, YieldStar, 0)
@@ -101,8 +100,6 @@ QT_BEGIN_NAMESPACE
#define INSTR_SetLookup(op) INSTRUCTION(op, SetLookup, 2, index, base)
#define INSTR_LoadSuperProperty(op) INSTRUCTION(op, LoadSuperProperty, 1, property)
#define INSTR_StoreSuperProperty(op) INSTRUCTION(op, StoreSuperProperty, 1, property)
-#define INSTR_StoreScopeObjectProperty(op) INSTRUCTION(op, StoreScopeObjectProperty, 2, base, propertyIndex)
-#define INSTR_StoreContextObjectProperty(op) INSTRUCTION(op, StoreContextObjectProperty, 2, base, propertyIndex)
#define INSTR_LoadElement(op) INSTRUCTION(op, LoadElement, 2, base, traceSlot)
#define INSTR_StoreElement(op) INSTRUCTION(op, StoreElement, 3, base, index, traceSlot)
#define INSTR_CallValue(op) INSTRUCTION(op, CallValue, 4, name, argc, argv, traceSlot)
@@ -113,8 +110,7 @@ QT_BEGIN_NAMESPACE
#define INSTR_CallName(op) INSTRUCTION(op, CallName, 4, name, argc, argv, traceSlot)
#define INSTR_CallPossiblyDirectEval(op) INSTRUCTION(op, CallPossiblyDirectEval, 3, argc, argv, traceSlot)
#define INSTR_CallGlobalLookup(op) INSTRUCTION(op, CallGlobalLookup, 4, index, argc, argv, traceSlot)
-#define INSTR_CallScopeObjectProperty(op) INSTRUCTION(op, CallScopeObjectProperty, 5, name, base, argc, argv, traceSlot)
-#define INSTR_CallContextObjectProperty(op) INSTRUCTION(op, CallContextObjectProperty, 5, name, base, argc, argv, traceSlot)
+#define INSTR_CallQmlContextPropertyLookup(op) INSTRUCTION(op, CallQmlContextPropertyLookup, 4, index, argc, argv, traceSlot)
#define INSTR_CallWithSpread(op) INSTRUCTION(op, CallWithSpread, 5, func, thisObject, argc, argv, traceSlot)
#define INSTR_Construct(op) INSTRUCTION(op, Construct, 3, func, argc, argv)
#define INSTR_ConstructWithSpread(op) INSTRUCTION(op, ConstructWithSpread, 3, func, argc, argv)
@@ -194,7 +190,6 @@ QT_BEGIN_NAMESPACE
#define INSTR_Div(op) INSTRUCTION(op, Div, 1, lhs)
#define INSTR_Mod(op) INSTRUCTION(op, Mod, 2, lhs, traceSlot)
#define INSTR_Sub(op) INSTRUCTION(op, Sub, 2, lhs, traceSlot)
-#define INSTR_LoadQmlContext(op) INSTRUCTION(op, LoadQmlContext, 1, result)
#define INSTR_LoadQmlImportedScripts(op) INSTRUCTION(op, LoadQmlImportedScripts, 1, result)
#define INSTR_InitializeBlockDeadTemporalZone(op) INSTRUCTION(op, InitializeBlockDeadTemporalZone, 2, firstReg, count)
#define INSTR_ThrowOnNullOrUndefined(op) INSTRUCTION(op, ThrowOnNullOrUndefined, 0)
@@ -228,6 +223,7 @@ QT_BEGIN_NAMESPACE
F(LoadClosure) \
F(LoadName) \
F(LoadGlobalLookup) \
+ F(LoadQmlContextPropertyLookup) \
F(StoreNameSloppy) \
F(StoreNameStrict) \
F(LoadElement) \
@@ -238,11 +234,6 @@ QT_BEGIN_NAMESPACE
F(SetLookup) \
F(LoadSuperProperty) \
F(StoreSuperProperty) \
- F(StoreScopeObjectProperty) \
- F(StoreContextObjectProperty) \
- F(LoadScopeObjectProperty) \
- F(LoadContextObjectProperty) \
- F(LoadIdObject) \
F(ConvertThisToObject) \
F(ToObject) \
F(Jump) \
@@ -296,8 +287,7 @@ QT_BEGIN_NAMESPACE
F(CallName) \
F(CallPossiblyDirectEval) \
F(CallGlobalLookup) \
- F(CallScopeObjectProperty) \
- F(CallContextObjectProperty) \
+ F(CallQmlContextPropertyLookup) \
F(CallWithSpread) \
F(Construct) \
F(ConstructWithSpread) \
@@ -328,8 +318,6 @@ QT_BEGIN_NAMESPACE
F(CreateMappedArgumentsObject) \
F(CreateUnmappedArgumentsObject) \
F(CreateRestParameter) \
- F(LoadQmlContext) \
- F(LoadQmlImportedScripts) \
F(Yield) \
F(YieldStar) \
F(Resume) \
diff --git a/src/qml/doc/src/cppintegration/definetypes.qdoc b/src/qml/doc/src/cppintegration/definetypes.qdoc
index f6f630c749..41bc9fd140 100644
--- a/src/qml/doc/src/cppintegration/definetypes.qdoc
+++ b/src/qml/doc/src/cppintegration/definetypes.qdoc
@@ -142,9 +142,10 @@ types:
\li qmlRegisterType() (with no parameters) registers a C++ type that is not
instantiable and cannot be referred to from QML. This enables the engine to
coerce any inherited types that are instantiable from QML.
-\li qmlRegisterInterface() registers a Qt interface type with a specific QML
-type name. The type is not instantiable from QML but can be referred to by its
-type name.
+\li qmlRegisterInterface() registers an existing Qt interface type. The type is
+not instantiable from QML, and you cannot declare QML properties with it. Using
+C++ properties of this type from QML will do the expected interface casts,
+though.
\li qmlRegisterUncreatableType() registers a named C++ type that is not
instantiable but should be identifiable as a type to the QML type system. This
is useful if a type's enums or attached properties should be accessible from QML
diff --git a/src/qml/doc/src/javascript/functionlist.qdoc b/src/qml/doc/src/javascript/functionlist.qdoc
index 24ff640284..7a6a922480 100644
--- a/src/qml/doc/src/javascript/functionlist.qdoc
+++ b/src/qml/doc/src/javascript/functionlist.qdoc
@@ -55,6 +55,8 @@
\li decodeURIComponent(encodedURIComponent)
\li encodeURI(uri)
\li encodeURIComponent(uriComponent)
+ \li escape(string)
+ \li unescape(string)
\endlist
\section2 Constructor Properties
@@ -63,11 +65,20 @@
\li Object
\li Function
\li Array
+ \li ArrayBuffer
\li String
\li Boolean
\li Number
+ \li DataView
\li Date
+ \li Promise
\li RegExp
+ \li Map
+ \li WeakMap
+ \li Set
+ \li WeakSet
+ \li SharedArrayBuffer
+ \li Symbol
\li Error
\li EvalError
\li RangeError
@@ -80,8 +91,11 @@
\section2 Other Properties
\list
+ \li Atomics
\li Math
\li JSON
+ \li Reflect
+ \li Proxy
\endlist
\section1 The Object Object
@@ -92,12 +106,19 @@
\list
\li getPrototypeOf(O)
+ \li setPrototypeOf(O, P)
\li getOwnPropertyDescriptor(O, P)
+ \li getOwnPropertyDescriptors(O)
\li getOwnPropertyNames(O)
+ \li getOwnPropertySymbols(O)
+ \li assign(O [, Properties])
\li create(O [, Properties])
\li defineProperty(O, P, Attributes)
\li defineProperties(O, Properties)
+ \li entries(O)
+ \li is(V1, V2)
\li keys(O)
+ \li values(O)
\li seal(O)
\li isSealed(O)
\li freeze(O)
@@ -117,6 +138,8 @@
\li hasOwnProperty(V)
\li isPrototypeOf(V)
\li propertyIsEnumerable(V)
+ \li __defineGetter__(P, F)
+ \li __defineSetter__(P, F)
\endlist
\section1 Function Objects
@@ -130,6 +153,7 @@
\li apply(thisArg, argArray)
\li call(thisArg [, arg1 [, arg2, ...]])
\li bind((thisArg [, arg1 [, arg2, …]])
+ \li [Symbol.hasInstance](O)
\endlist
\section1 Array Objects
@@ -142,9 +166,14 @@
\li toString()
\li toLocaleString()
\li concat([item1 [, item2 [, ...]]])
+ \li copyWithin([item1 [, item2 [, ...]]])
+ \li entries()
+ \li fill(item [, index1 [, index2]])
\li join(separator)
\li find(callbackfn [, thisArg]) // ECMAScript 6: Added in Qt 5.9
\li findIndex(callbackfn [, thisArg]) // ECMAScript 6: Added in Qt 5.9
+ \li includes(item)
+ \li keys()
\li pop()
\li push([item1 [, item2 [, ...]]])
\li reverse()
@@ -162,6 +191,8 @@
\li filter(callbackfn [, thisArg])
\li reduce(callbackfn [, initialValue])
\li reduceRight(callbackfn [, initialValue])
+ \li values()
+ \li [Symbol.iterator]()
\endlist
\section1 String Objects
@@ -175,6 +206,7 @@
\li valueOf()
\li charAt(pos)
\li charCodeAt(pos)
+ \li codePointAt(pos)
\li concat([string1 [, string2 [, ...]]])
\li endsWith(searchString [, endPosition ]) // ECMAScript 6: Added in Qt 5.8
\li includes(searchString [, position ]) // ECMAScript 6: Added in 5.8
@@ -182,18 +214,23 @@
\li lastIndexOf(searchString, position)
\li localeCompare(that)
\li match(regexp)
+ \li normalize()
+ \li padEnd(length [, string])
+ \li padStart(length [, string])
\li repeat(count) // ECMAScript 6: Added in Qt 5.9
\li replace(searchValue, replaceValue)
\li search(regexp)
\li slice(start, end)
\li split(separator, limit)
\li startsWith(searchString [, position ]) // ECMAScript 6: Added in Qt 5.8
+ \li substr(start, length)
\li substring(start, end)
\li toLowerCase()
\li toLocaleLowerCase()
\li toUpperCase()
\li toLocaleUpperCase()
\li trim()
+ \li [Symbol.iterator]()
\endlist
Additionally, the QML engine adds the following functions to the \l String prototype:
@@ -222,6 +259,7 @@
\list
\li toString(radix)
\li toLocaleString()
+ \li valueOf()
\li toFixed(fractionDigits)
\li toExponential(fractionDigits)
\li toPrecision(precision)
@@ -245,12 +283,16 @@
\li MAX_VALUE
\li MIN_VALUE
\li EPSILON // ECMAScript 6: Added in Qt 5.8
+ \li MAX_SAFE_INTEGER
+ \li MIN_SAFE_INTEGER
\endlist
\section3 Function Properties
\list
\li isFinite(x) // ECMAScript 6: Added in Qt 5.8
+ \li isInteger(x)
+ \li isSafeInteger(x)
\li isNaN(x) // ECMAScript 6: Added in Qt 5.8
\endlist
@@ -274,14 +316,27 @@
\list
\li abs(x)
\li acos(x)
+ \li acosh(x)
\li asin(x)
+ \li asinh(x)
\li atan(x)
+ \li atanh(x)
\li atan2(y, x)
+ \li cbrt(x)
\li ceil(x)
+ \li clz32(x)
\li cos(x)
+ \li cosh(x)
\li exp(x)
+ \li expm1(x)
\li floor(x)
+ \li fround(x)
+ \li hypot(x, y)
+ \li imul(x, y)
\li log(x)
+ \li log10(x)
+ \li log1p(x)
+ \li log2(x)
\li max([value1 [, value2 [, ...]]])
\li min([value1 [, value2 [, ...]]])
\li pow(x, y)
@@ -289,8 +344,11 @@
\li round(x)
\li sign(x) // ECMAScript 6: Added in Qt 5.8
\li sin(x)
+ \li sinh(x)
\li sqrt(x)
\li tan(x)
+ \li tanh(x)
+ \li trunc(x)
\endlist
\section1 Date Objects
@@ -338,11 +396,14 @@
\li setUTCDate(date)
\li setMonth(month [, date])
\li setUTCMonth(month [, date])
+ \li setYear(year)
\li setFullYear(year [, month [, date]])
\li setUTCFullYear(year [, month [, date]])
\li toUTCString()
+ \li toGMTString()
\li toISOString()
\li toJSON()
+ \li [Symbol.toPrimitive](hint)
\endlist
Additionally, the QML engine adds the following functions to the \l Date prototype:
diff --git a/src/qml/doc/src/javascript/hostenvironment.qdoc b/src/qml/doc/src/javascript/hostenvironment.qdoc
index eb40f10065..c22c392b80 100644
--- a/src/qml/doc/src/javascript/hostenvironment.qdoc
+++ b/src/qml/doc/src/javascript/hostenvironment.qdoc
@@ -40,11 +40,10 @@ not provide a \c window object or \c{DOM API} as commonly found in a browser env
Like a browser or server-side JavaScript environment, the QML runtime implements the
\l{ECMA-262}{ECMAScript Language Specification} standard. This provides access to
all of the built-in types and functions defined by the standard, such as Object, Array, and Math.
-The QML runtime implements the 5th edition of the standard, which is the same edition commonly
-implemented by browsers.
+The QML runtime implements the 7th edition of the standard.
The standard ECMAScript built-ins are not explicitly documented in the QML documentation. For more
-information on their use, please refer to the ECMA-262 5th edition standard or one of the many online
+information on their use, please refer to the ECMA-262 7th edition standard or one of the many online
JavaScript reference and tutorial sites, such as the \l{W3Schools JavaScript Reference} (JavaScript Objects
Reference section). Many sites focus on JavaScript in the browser, so in some cases you may need to double
check the specification to determine whether a given function or object is part of standard ECMAScript or
diff --git a/src/qml/jit/qv4baselineassembler.cpp b/src/qml/jit/qv4baselineassembler.cpp
index 987f366256..25c74e74e8 100644
--- a/src/qml/jit/qv4baselineassembler.cpp
+++ b/src/qml/jit/qv4baselineassembler.cpp
@@ -208,17 +208,20 @@ public:
isNumber.link(this);
}
+ // this converts both the lhs and the accumulator to int32
void toInt32LhsAcc(Address lhs, RegisterID lhsTarget)
{
load64(lhs, lhsTarget);
urshift64(lhsTarget, TrustedImm32(Value::QuickType_Shift), ScratchRegister2);
auto lhsIsInt = branch32(Equal, TrustedImm32(Value::QT_Int), ScratchRegister2);
- pushAligned(AccumulatorRegister);
+ const Address accumulatorStackAddress(JSStackFrameRegister,
+ offsetof(CallData, accumulator));
+ storeAccumulator(accumulatorStackAddress);
move(lhsTarget, registerForArg(0));
callHelper(toInt32Helper);
move(ReturnValueRegister, lhsTarget);
- popAligned(AccumulatorRegister);
+ loadAccumulator(accumulatorStackAddress);
lhsIsInt.link(this);
urshift64(AccumulatorRegister, TrustedImm32(Value::QuickType_Shift), ScratchRegister2);
@@ -498,6 +501,7 @@ public:
isNumber.link(this);
}
+ // this converts both the lhs and the accumulator to int32
void toInt32LhsAcc(Address lhs, RegisterID lhsTarget)
{
bool accumulatorNeedsSaving = AccumulatorRegisterValue == ReturnValueRegisterValue
@@ -510,32 +514,28 @@ public:
auto lhsIsInt = jump();
lhsIsNotInt.link(this);
- if (accumulatorNeedsSaving) {
- push(AccumulatorRegisterTag);
- push(AccumulatorRegisterValue);
- }
+
+ // Save accumulator from being garbage collected, no matter if we will reuse the register.
+ const Address accumulatorStackAddress(JSStackFrameRegister,
+ offsetof(CallData, accumulator));
+ storeAccumulator(accumulatorStackAddress);
if (ArgInRegCount < 2) {
- if (!accumulatorNeedsSaving)
- subPtr(TrustedImm32(2 * PointerSize), StackPointerRegister);
+ subPtr(TrustedImm32(2 * PointerSize), StackPointerRegister);
push(lhsTarget);
load32(lhs, lhsTarget);
push(lhsTarget);
} else {
- if (accumulatorNeedsSaving)
- subPtr(TrustedImm32(2 * PointerSize), StackPointerRegister);
move(lhsTarget, registerForArg(1));
load32(lhs, registerForArg(0));
}
callHelper(toInt32Helper);
move(ReturnValueRegisterValue, lhsTarget);
- if (accumulatorNeedsSaving) {
- addPtr(TrustedImm32(2 * PointerSize), StackPointerRegister);
- pop(AccumulatorRegisterValue);
- pop(AccumulatorRegisterTag);
- } else if (ArgInRegCount < 2) {
+ if (ArgInRegCount < 2)
addPtr(TrustedImm32(4 * PointerSize), StackPointerRegister);
- }
+
+ if (accumulatorNeedsSaving) // otherwise it's still the same
+ loadAccumulator(accumulatorStackAddress);
lhsIsInt.link(this);
diff --git a/src/qml/jit/qv4baselinejit.cpp b/src/qml/jit/qv4baselinejit.cpp
index 8de0259509..e518fc5a0e 100644
--- a/src/qml/jit/qv4baselinejit.cpp
+++ b/src/qml/jit/qv4baselinejit.cpp
@@ -215,6 +215,16 @@ void BaselineJIT::generate_LoadGlobalLookup(int index, int /*traceSlot*/)
as->checkException();
}
+void BaselineJIT::generate_LoadQmlContextPropertyLookup(int index, int /*traceSlot*/)
+{
+ as->prepareCallWithArgCount(3);
+ as->passInt32AsArg(index, 2);
+ as->passEngineAsArg(1);
+ as->passFunctionAsArg(0);
+ BASELINEJIT_GENERATE_RUNTIME_CALL(Helpers::loadQmlContextPropertyLookup, CallResultDestination::InAccumulator);
+ as->checkException();
+}
+
void BaselineJIT::generate_StoreNameSloppy(int name)
{
STORE_IP();
@@ -339,66 +349,6 @@ void BaselineJIT::generate_StoreSuperProperty(int property)
as->checkException();
}
-
-void BaselineJIT::generate_StoreScopeObjectProperty(int base, int propertyIndex)
-{
- STORE_ACC();
- as->prepareCallWithArgCount(4);
- as->passAccumulatorAsArg(3);
- as->passInt32AsArg(propertyIndex, 2);
- as->passJSSlotAsArg(base, 1);
- as->passEngineAsArg(0);
- BASELINEJIT_GENERATE_RUNTIME_CALL(Runtime::method_storeQmlScopeObjectProperty, CallResultDestination::Ignore);
- as->checkException();
-}
-
-void BaselineJIT::generate_StoreContextObjectProperty(int base, int propertyIndex)
-{
- STORE_ACC();
- as->prepareCallWithArgCount(4);
- as->passAccumulatorAsArg(3);
- as->passInt32AsArg(propertyIndex, 2);
- as->passJSSlotAsArg(base, 1);
- as->passEngineAsArg(0);
- BASELINEJIT_GENERATE_RUNTIME_CALL(Runtime::method_storeQmlContextObjectProperty, CallResultDestination::Ignore);
- as->checkException();
-}
-
-void BaselineJIT::generate_LoadScopeObjectProperty(int propertyIndex, int base, int captureRequired)
-{
- STORE_IP();
- as->prepareCallWithArgCount(4);
- as->passInt32AsArg(captureRequired, 3);
- as->passInt32AsArg(propertyIndex, 2);
- as->passJSSlotAsArg(base, 1);
- as->passEngineAsArg(0);
- BASELINEJIT_GENERATE_RUNTIME_CALL(Runtime::method_loadQmlScopeObjectProperty, CallResultDestination::InAccumulator);
- as->checkException();
-}
-
-void BaselineJIT::generate_LoadContextObjectProperty(int propertyIndex, int base, int captureRequired)
-{
- STORE_IP();
- as->prepareCallWithArgCount(4);
- as->passInt32AsArg(captureRequired, 3);
- as->passInt32AsArg(propertyIndex, 2);
- as->passJSSlotAsArg(base, 1);
- as->passEngineAsArg(0);
- BASELINEJIT_GENERATE_RUNTIME_CALL(Runtime::method_loadQmlContextObjectProperty, CallResultDestination::InAccumulator);
- as->checkException();
-}
-
-void BaselineJIT::generate_LoadIdObject(int index, int base)
-{
- STORE_IP();
- as->prepareCallWithArgCount(3);
- as->passInt32AsArg(index, 2);
- as->passJSSlotAsArg(base, 1);
- as->passEngineAsArg(0);
- BASELINEJIT_GENERATE_RUNTIME_CALL(Runtime::method_loadQmlIdObject, CallResultDestination::InAccumulator);
- as->checkException();
-}
-
void BaselineJIT::generate_Yield()
{
// #####
@@ -516,33 +466,19 @@ void BaselineJIT::generate_CallGlobalLookup(int index, int argc, int argv, int /
as->checkException();
}
-void BaselineJIT::generate_CallScopeObjectProperty(int propIdx, int base, int argc, int argv, int /*traceSlot*/)
-{
- STORE_IP();
- as->prepareCallWithArgCount(5);
- as->passInt32AsArg(argc, 4);
- as->passJSSlotAsArg(argv, 3);
- as->passInt32AsArg(propIdx, 2);
- as->passJSSlotAsArg(base, 1);
- as->passEngineAsArg(0);
- BASELINEJIT_GENERATE_RUNTIME_CALL(Runtime::method_callQmlScopeObjectProperty, CallResultDestination::InAccumulator);
- as->checkException();
-}
-
-void BaselineJIT::generate_CallContextObjectProperty(int propIdx, int base, int argc, int argv, int /*traceSlot*/)
+void BaselineJIT::generate_CallQmlContextPropertyLookup(int index, int argc, int argv,
+ int /*traceSlot*/)
{
STORE_IP();
- as->prepareCallWithArgCount(5);
- as->passInt32AsArg(argc, 4);
- as->passJSSlotAsArg(argv, 3);
- as->passInt32AsArg(propIdx, 2);
- as->passJSSlotAsArg(base, 1);
+ as->prepareCallWithArgCount(4);
+ as->passInt32AsArg(argc, 3);
+ as->passJSSlotAsArg(argv, 2);
+ as->passInt32AsArg(index, 1);
as->passEngineAsArg(0);
- BASELINEJIT_GENERATE_RUNTIME_CALL(Runtime::method_callQmlContextObjectProperty, CallResultDestination::InAccumulator);
+ BASELINEJIT_GENERATE_RUNTIME_CALL(Runtime::method_callQmlContextPropertyLookup, CallResultDestination::InAccumulator);
as->checkException();
}
-
void BaselineJIT::generate_CallWithSpread(int func, int thisObject, int argc, int argv, int /*traceSlot*/)
{
STORE_IP();
@@ -980,22 +916,6 @@ void BaselineJIT::generate_Sub(int lhs, int /*traceSlot*/) { as->sub(lhs); }
// as->checkException();
//}
-void BaselineJIT::generate_LoadQmlContext(int result)
-{
- as->prepareCallWithArgCount(1);
- as->passEngineAsArg(0);
- BASELINEJIT_GENERATE_RUNTIME_CALL(Runtime::method_loadQmlContext, CallResultDestination::InAccumulator);
- as->storeReg(result);
-}
-
-void BaselineJIT::generate_LoadQmlImportedScripts(int result)
-{
- as->prepareCallWithArgCount(1);
- as->passEngineAsArg(0);
- BASELINEJIT_GENERATE_RUNTIME_CALL(Runtime::method_loadQmlImportedScripts, CallResultDestination::InAccumulator);
- as->storeReg(result);
-}
-
void BaselineJIT::generate_InitializeBlockDeadTemporalZone(int firstReg, int count)
{
as->loadValue(Value::emptyValue().rawValue());
diff --git a/src/qml/jit/qv4baselinejit_p.h b/src/qml/jit/qv4baselinejit_p.h
index 998f9f110b..10c89bc74b 100644
--- a/src/qml/jit/qv4baselinejit_p.h
+++ b/src/qml/jit/qv4baselinejit_p.h
@@ -97,6 +97,7 @@ public:
void generate_LoadClosure(int value) override;
void generate_LoadName(int name, int traceSlot) override;
void generate_LoadGlobalLookup(int index, int traceSlot) override;
+ void generate_LoadQmlContextPropertyLookup(int index, int traceSlot) override;
void generate_StoreNameSloppy(int name) override;
void generate_StoreNameStrict(int name) override;
void generate_LoadElement(int base, int traceSlot) override;
@@ -107,15 +108,6 @@ public:
void generate_SetLookup(int index, int base) override;
void generate_LoadSuperProperty(int property) override;
void generate_StoreSuperProperty(int property) override;
- void generate_StoreScopeObjectProperty(int base,
- int propertyIndex) override;
- void generate_StoreContextObjectProperty(int base,
- int propertyIndex) override;
- void generate_LoadScopeObjectProperty(int propertyIndex, int base,
- int captureRequired) override;
- void generate_LoadContextObjectProperty(int propertyIndex, int base,
- int captureRequired) override;
- void generate_LoadIdObject(int index, int base) override;
void generate_Yield() override;
void generate_YieldStar() override;
void generate_Resume(int) override;
@@ -128,8 +120,7 @@ public:
void generate_CallName(int name, int argc, int argv, int traceSlot) override;
void generate_CallPossiblyDirectEval(int argc, int argv, int traceSlot) override;
void generate_CallGlobalLookup(int index, int argc, int argv, int traceSlot) override;
- void generate_CallScopeObjectProperty(int propIdx, int base, int argc, int argv, int traceSlot) override;
- void generate_CallContextObjectProperty(int propIdx, int base, int argc, int argv, int traceSlot) override;
+ void generate_CallQmlContextPropertyLookup(int index, int argc, int argv, int traceSlot) override;
void generate_CallWithSpread(int func, int thisObject, int argc, int argv, int traceSlot) override;
void generate_TailCall(int func, int thisObject, int argc, int argv) override;
void generate_Construct(int func, int argc, int argv) override;
@@ -211,8 +202,6 @@ public:
void generate_Div(int lhs) override;
void generate_Mod(int lhs, int traceSlot) override;
void generate_Sub(int lhs, int traceSlot) override;
- void generate_LoadQmlContext(int result) override;
- void generate_LoadQmlImportedScripts(int result) override;
void generate_InitializeBlockDeadTemporalZone(int firstReg, int count) override;
void generate_ThrowOnNullOrUndefined() override;
void generate_GetTemplateObject(int index) override;
diff --git a/src/qml/jit/qv4jithelpers.cpp b/src/qml/jit/qv4jithelpers.cpp
index f43f37ad70..674fd8c8c8 100644
--- a/src/qml/jit/qv4jithelpers.cpp
+++ b/src/qml/jit/qv4jithelpers.cpp
@@ -70,6 +70,12 @@ ReturnedValue loadGlobalLookup(Function *f, ExecutionEngine *engine, int index)
return l->globalGetter(l, engine);
}
+ReturnedValue loadQmlContextPropertyLookup(Function *f, ExecutionEngine *engine, int index)
+{
+ Lookup *l = f->compilationUnit->runtimeLookups + index;
+ return l->qmlContextPropertyGetter(l, engine, nullptr);
+}
+
ReturnedValue toObject(ExecutionEngine *engine, const Value &obj)
{
if (obj.isObject())
diff --git a/src/qml/jit/qv4jithelpers_p.h b/src/qml/jit/qv4jithelpers_p.h
index bd5f65034d..d9abfc071e 100644
--- a/src/qml/jit/qv4jithelpers_p.h
+++ b/src/qml/jit/qv4jithelpers_p.h
@@ -66,6 +66,7 @@ namespace Helpers {
void convertThisToObject(ExecutionEngine *engine, Value *t);
ReturnedValue loadGlobalLookup(Function *f, ExecutionEngine *engine, int index);
+ReturnedValue loadQmlContextPropertyLookup(Function *f, ExecutionEngine *engine, int index);
ReturnedValue toObject(ExecutionEngine *engine, const Value &obj);
ReturnedValue exp(const Value &base, const Value &exp);
ReturnedValue getLookup(Function *f, ExecutionEngine *engine, const Value &base, int index);
diff --git a/src/qml/jsruntime/qv4engine.cpp b/src/qml/jsruntime/qv4engine.cpp
index 8adb84719f..0a41579a25 100644
--- a/src/qml/jsruntime/qv4engine.cpp
+++ b/src/qml/jsruntime/qv4engine.cpp
@@ -1179,6 +1179,14 @@ ReturnedValue ExecutionEngine::throwTypeError(const QString &message)
return throwError(error);
}
+ReturnedValue ExecutionEngine::throwReferenceError(const QString &name)
+{
+ Scope scope(this);
+ QString msg = name + QLatin1String(" is not defined");
+ ScopedObject error(scope, newReferenceErrorObject(msg));
+ return throwError(error);
+}
+
ReturnedValue ExecutionEngine::throwReferenceError(const Value &value)
{
Scope scope(this);
diff --git a/src/qml/jsruntime/qv4engine_p.h b/src/qml/jsruntime/qv4engine_p.h
index 64c7e2f32b..86367c0ece 100644
--- a/src/qml/jsruntime/qv4engine_p.h
+++ b/src/qml/jsruntime/qv4engine_p.h
@@ -569,6 +569,7 @@ public:
ReturnedValue throwTypeError();
ReturnedValue throwTypeError(const QString &message);
ReturnedValue throwReferenceError(const Value &value);
+ ReturnedValue throwReferenceError(const QString &name);
ReturnedValue throwReferenceError(const QString &value, const QString &fileName, int lineNumber, int column);
ReturnedValue throwRangeError(const Value &value);
ReturnedValue throwRangeError(const QString &message);
diff --git a/src/qml/jsruntime/qv4function.cpp b/src/qml/jsruntime/qv4function.cpp
index 7702939e23..1bd4329fe8 100644
--- a/src/qml/jsruntime/qv4function.cpp
+++ b/src/qml/jsruntime/qv4function.cpp
@@ -96,7 +96,6 @@ Function::Function(ExecutionEngine *engine, CompiledData::CompilationUnit *unit,
, codeData(function->code())
, jittedCode(nullptr)
, codeRef(nullptr)
- , hasQmlDependencies(function->hasQmlDependencies())
{
Scope scope(engine);
Scoped<InternalClass> ic(scope, engine->internalClasses(EngineBase::Class_CallContext));
diff --git a/src/qml/jsruntime/qv4function_p.h b/src/qml/jsruntime/qv4function_p.h
index 374e46b929..f8125a58f8 100644
--- a/src/qml/jsruntime/qv4function_p.h
+++ b/src/qml/jsruntime/qv4function_p.h
@@ -94,7 +94,6 @@ public:
Heap::InternalClass *internalClass;
uint nFormals;
int interpreterCallCount = 0;
- bool hasQmlDependencies;
bool isEval = false;
static Function *create(ExecutionEngine *engine, CompiledData::CompilationUnit *unit, const CompiledData::Function *function);
diff --git a/src/qml/jsruntime/qv4internalclass.cpp b/src/qml/jsruntime/qv4internalclass.cpp
index ddb8542e07..9906e2b1a0 100644
--- a/src/qml/jsruntime/qv4internalclass.cpp
+++ b/src/qml/jsruntime/qv4internalclass.cpp
@@ -257,11 +257,15 @@ void InternalClass::init(Heap::InternalClass *other)
void InternalClass::destroy()
{
-#ifndef QT_NO_DEBUG
for (const auto &t : transitions) {
- Q_ASSERT(!t.lookup || !t.lookup->isMarked());
- }
+ if (t.lookup) {
+#ifndef QT_NO_DEBUG
+ Q_ASSERT(t.lookup->parent == this);
#endif
+ t.lookup->parent = nullptr;
+ }
+ }
+
if (parent && parent->engine && parent->isMarked())
parent->removeChildEntry(this);
@@ -659,8 +663,6 @@ void InternalClass::markObjects(Heap::Base *b, MarkStack *stack)
Heap::InternalClass *ic = static_cast<Heap::InternalClass *>(b);
if (ic->prototype)
ic->prototype->mark(stack);
- if (ic->parent)
- ic->parent->mark(stack);
ic->nameMap.mark(stack);
}
diff --git a/src/qml/jsruntime/qv4lookup_p.h b/src/qml/jsruntime/qv4lookup_p.h
index 83e561863b..03dc5f6d3c 100644
--- a/src/qml/jsruntime/qv4lookup_p.h
+++ b/src/qml/jsruntime/qv4lookup_p.h
@@ -68,8 +68,10 @@ struct Lookup {
union {
ReturnedValue (*getter)(Lookup *l, ExecutionEngine *engine, const Value &object);
ReturnedValue (*globalGetter)(Lookup *l, ExecutionEngine *engine);
+ ReturnedValue (*qmlContextPropertyGetter)(Lookup *l, ExecutionEngine *engine, Value *thisObject);
bool (*setter)(Lookup *l, ExecutionEngine *engine, Value &object, const Value &v);
};
+ // NOTE: gc assumes the first two entries in the struct are pointers to heap objects or null
union {
struct {
Heap::Base *h1;
@@ -116,6 +118,39 @@ struct Lookup {
quintptr _unused2;
uint index;
} indexedLookup;
+ struct {
+ Heap::InternalClass *ic;
+ Heap::QObjectWrapper *staticQObject;
+ QQmlPropertyCache *propertyCache;
+ QQmlPropertyData *propertyData;
+ } qobjectLookup;
+ struct {
+ Heap::InternalClass *ic;
+ quintptr unused;
+ QQmlPropertyCache *propertyCache;
+ QQmlPropertyData *propertyData;
+ } qgadgetLookup;
+ struct {
+ quintptr unused1;
+ quintptr unused2;
+ int scriptIndex;
+ } qmlContextScriptLookup;
+ struct {
+ Heap::Object *singleton;
+ quintptr unused;
+ } qmlContextSingletonLookup;
+ struct {
+ quintptr unused1;
+ quintptr unused2;
+ int objectId;
+ } qmlContextIdObjectLookup;
+ struct {
+ // Same as protoLookup, as used for global lookups
+ quintptr reserved1;
+ quintptr reserved2;
+ quintptr reserved3;
+ ReturnedValue (*getterTrampoline)(Lookup *l, ExecutionEngine *engine);
+ } qmlContextGlobalLookup;
};
uint nameIndex;
diff --git a/src/qml/jsruntime/qv4qmlcontext.cpp b/src/qml/jsruntime/qv4qmlcontext.cpp
index 88b0822f42..97b955632d 100644
--- a/src/qml/jsruntime/qv4qmlcontext.cpp
+++ b/src/qml/jsruntime/qv4qmlcontext.cpp
@@ -55,6 +55,8 @@
#include <private/qjsvalue_p.h>
#include <private/qv4qobjectwrapper_p.h>
#include <private/qv4module_p.h>
+#include <private/qv4lookup_p.h>
+#include <private/qv4identifiertable_p.h>
QT_BEGIN_NAMESPACE
@@ -77,14 +79,11 @@ void Heap::QQmlContextWrapper::destroy()
Object::destroy();
}
-ReturnedValue QQmlContextWrapper::virtualGet(const Managed *m, PropertyKey id, const Value *receiver, bool *hasProperty)
+ReturnedValue QQmlContextWrapper::getPropertyAndBase(const QQmlContextWrapper *resource, PropertyKey id, const Value *receiver, bool *hasProperty, Value *base, Lookup *lookup)
{
- Q_ASSERT(m->as<QQmlContextWrapper>());
-
if (!id.isString())
- return Object::virtualGet(m, id, receiver, hasProperty);
+ return Object::virtualGet(resource, id, receiver, hasProperty);
- const QQmlContextWrapper *resource = static_cast<const QQmlContextWrapper *>(m);
QV4::ExecutionEngine *v4 = resource->engine();
QV4::Scope scope(v4);
@@ -100,11 +99,11 @@ ReturnedValue QQmlContextWrapper::virtualGet(const Managed *m, PropertyKey id, c
}
}
- return Object::virtualGet(m, id, receiver, hasProperty);
+ return Object::virtualGet(resource, id, receiver, hasProperty);
}
bool hasProp = false;
- ScopedValue result(scope, Object::virtualGet(m, id, receiver, &hasProp));
+ ScopedValue result(scope, Object::virtualGet(resource, id, receiver, &hasProp));
if (hasProp) {
if (hasProperty)
*hasProperty = hasProp;
@@ -160,6 +159,8 @@ ReturnedValue QQmlContextWrapper::virtualGet(const Managed *m, PropertyKey id, c
// Note: The scope object is only a QADMO for example when somebody registers a QQmlPropertyMap
// sub-class as QML type and then instantiates it in .qml.
if (scopeObject && QQmlPropertyCache::isDynamicMetaObject(scopeObject->metaObject())) {
+ // all bets are off, so don't try to optimize any lookups
+ lookup = nullptr;
if (performGobalLookUp())
return result->asReturnedValue();
}
@@ -172,11 +173,35 @@ ReturnedValue QQmlContextWrapper::virtualGet(const Managed *m, PropertyKey id, c
if (hasProperty)
*hasProperty = true;
if (r.scriptIndex != -1) {
+ if (lookup) {
+ lookup->qmlContextScriptLookup.scriptIndex = r.scriptIndex;
+ lookup->qmlContextPropertyGetter = QQmlContextWrapper::lookupScript;
+ return lookup->qmlContextPropertyGetter(lookup, v4, base);
+ }
QV4::ScopedObject scripts(scope, context->importedScripts.valueRef());
if (scripts)
return scripts->get(r.scriptIndex);
return QV4::Encode::null();
} else if (r.type.isValid()) {
+ if (lookup) {
+ if (r.type.isSingleton()) {
+ QQmlEngine *e = v4->qmlEngine();
+ QQmlType::SingletonInstanceInfo *siinfo = r.type.singletonInstanceInfo();
+ siinfo->init(e);
+ if (siinfo->qobjectApi(e)) {
+ lookup->qmlContextSingletonLookup.singleton =
+ static_cast<Heap::Object*>(
+ Value::fromReturnedValue(
+ QQmlTypeWrapper::create(v4, nullptr, r.type)
+ ).heapObject());
+ } else {
+ QV4::ScopedObject o(scope, QJSValuePrivate::convertedToValue(v4, siinfo->scriptApi(e)));
+ lookup->qmlContextSingletonLookup.singleton = o->d();
+ }
+ lookup->qmlContextPropertyGetter = QQmlContextWrapper::lookupSingleton;
+ return lookup->qmlContextPropertyGetter(lookup, v4, base);
+ }
+ }
return QQmlTypeWrapper::create(v4, scopeObject, r.type);
} else if (r.importNamespace) {
return QQmlTypeWrapper::create(v4, scopeObject, context->imports, r.importNamespace);
@@ -188,6 +213,15 @@ ReturnedValue QQmlContextWrapper::virtualGet(const Managed *m, PropertyKey id, c
}
QQmlEnginePrivate *ep = QQmlEnginePrivate::get(v4->qmlEngine());
+ Lookup * const originalLookup = lookup;
+
+ decltype(lookup->qmlContextPropertyGetter) contextGetterFunction = QQmlContextWrapper::lookupContextObjectProperty;
+
+ // minor optimization so we don't potentially try two property lookups on the same object
+ if (scopeObject == context->contextObject) {
+ scopeObject = nullptr;
+ contextGetterFunction = QQmlContextWrapper::lookupScopeObjectProperty;
+ }
while (context) {
// Search context properties
@@ -198,11 +232,17 @@ ReturnedValue QQmlContextWrapper::virtualGet(const Managed *m, PropertyKey id, c
if (propertyIdx != -1) {
if (propertyIdx < context->idValueCount) {
+ if (hasProperty)
+ *hasProperty = true;
+
+ if (lookup) {
+ lookup->qmlContextIdObjectLookup.objectId = propertyIdx;
+ lookup->qmlContextPropertyGetter = QQmlContextWrapper::lookupIdObject;
+ return lookup->qmlContextPropertyGetter(lookup, v4, base);
+ }
if (ep->propertyCapture)
ep->propertyCapture->captureProperty(&context->idValues[propertyIdx].bindings);
- if (hasProperty)
- *hasProperty = true;
return QV4::QObjectWrapper::wrap(v4, context->idValues[propertyIdx]);
} else {
@@ -229,11 +269,30 @@ ReturnedValue QQmlContextWrapper::virtualGet(const Managed *m, PropertyKey id, c
// Search scope object
if (scopeObject) {
bool hasProp = false;
+
+ QQmlPropertyData *propertyData = nullptr;
QV4::ScopedValue result(scope, QV4::QObjectWrapper::getQmlProperty(v4, context, scopeObject,
- name, QV4::QObjectWrapper::CheckRevision, &hasProp));
+ name, QV4::QObjectWrapper::CheckRevision, &hasProp, &propertyData));
if (hasProp) {
if (hasProperty)
*hasProperty = true;
+ if (base)
+ *base = QV4::QObjectWrapper::wrap(v4, scopeObject);
+
+ if (lookup && propertyData) {
+ QQmlData *ddata = QQmlData::get(scopeObject, false);
+ if (ddata && ddata->propertyCache) {
+ ScopedValue val(scope, base ? *base : Value::fromReturnedValue(QV4::QObjectWrapper::wrap(v4, scopeObject)));
+ const QObjectWrapper *That = static_cast<const QObjectWrapper *>(val->objectValue());
+ lookup->qobjectLookup.ic = That->internalClass();
+ lookup->qobjectLookup.staticQObject = nullptr;
+ lookup->qobjectLookup.propertyCache = ddata->propertyCache;
+ lookup->qobjectLookup.propertyCache->addref();
+ lookup->qobjectLookup.propertyData = propertyData;
+ lookup->qmlContextPropertyGetter = QQmlContextWrapper::lookupScopeObjectProperty;
+ }
+ }
+
return result->asReturnedValue();
}
}
@@ -243,27 +302,73 @@ ReturnedValue QQmlContextWrapper::virtualGet(const Managed *m, PropertyKey id, c
// Search context object
if (context->contextObject) {
bool hasProp = false;
- result = QV4::QObjectWrapper::getQmlProperty(v4, context, context->contextObject, name, QV4::QObjectWrapper::CheckRevision, &hasProp);
+ QQmlPropertyData *propertyData = nullptr;
+ result = QV4::QObjectWrapper::getQmlProperty(v4, context, context->contextObject,
+ name, QV4::QObjectWrapper::CheckRevision, &hasProp, &propertyData);
if (hasProp) {
if (hasProperty)
*hasProperty = true;
+ if (base)
+ *base = QV4::QObjectWrapper::wrap(v4, context->contextObject);
+
+ if (lookup && propertyData) {
+ QQmlData *ddata = QQmlData::get(context->contextObject, false);
+ if (ddata && ddata->propertyCache) {
+ ScopedValue val(scope, base ? *base : Value::fromReturnedValue(QV4::QObjectWrapper::wrap(v4, context->contextObject)));
+ const QObjectWrapper *That = static_cast<const QObjectWrapper *>(val->objectValue());
+ lookup->qobjectLookup.ic = That->internalClass();
+ lookup->qobjectLookup.staticQObject = nullptr;
+ lookup->qobjectLookup.propertyCache = ddata->propertyCache;
+ lookup->qobjectLookup.propertyCache->addref();
+ lookup->qobjectLookup.propertyData = propertyData;
+ lookup->qmlContextPropertyGetter = contextGetterFunction;
+ }
+ }
+
return result->asReturnedValue();
}
}
context = context->parent;
+
+ // As the hierarchy of contexts is not stable, we can't do accelerated lookups beyond
+ // the immediate QML context (of the .qml file).
+ lookup = nullptr;
}
// Do a lookup in the global object here to avoid expressionContext->unresolvedNames becoming
// true if we access properties of the global object.
- if (performGobalLookUp())
- return result->asReturnedValue();
+ if (originalLookup) {
+ // Try a lookup in the global object. It's theoretically possible to first find a property
+ // in the global object and then later a context property with the same name is added, but that
+ // never really worked as we used to detect access to global properties at type compile time anyway.
+ lookup = originalLookup;
+ result = lookup->resolveGlobalGetter(v4);
+ if (lookup->globalGetter != Lookup::globalGetterGeneric) {
+ if (hasProperty)
+ *hasProperty = true;
+ lookup->qmlContextGlobalLookup.getterTrampoline = lookup->globalGetter;
+ lookup->qmlContextPropertyGetter = QQmlContextWrapper::lookupInGlobalObject;
+ return result->asReturnedValue();
+ }
+ lookup->qmlContextPropertyGetter = QQmlContextWrapper::resolveQmlContextPropertyLookupGetter;
+ } else {
+ if (performGobalLookUp())
+ return result->asReturnedValue();
+ }
expressionContext->unresolvedNames = true;
return Encode::undefined();
}
+ReturnedValue QQmlContextWrapper::virtualGet(const Managed *m, PropertyKey id, const Value *receiver, bool *hasProperty)
+{
+ Q_ASSERT(m->as<QQmlContextWrapper>());
+ const QQmlContextWrapper *This = static_cast<const QQmlContextWrapper *>(m);
+ return getPropertyAndBase(This, id, receiver, hasProperty, /*base*/nullptr);
+}
+
bool QQmlContextWrapper::virtualPut(Managed *m, PropertyKey id, const Value &value, Value *receiver)
{
Q_ASSERT(m->as<QQmlContextWrapper>());
@@ -298,8 +403,16 @@ bool QQmlContextWrapper::virtualPut(Managed *m, PropertyKey id, const Value &val
while (context) {
const QV4::IdentifierHash &properties = context->propertyNames();
// Search context properties
- if (properties.count() && properties.value(name) != -1)
- return false;
+ if (properties.count()) {
+ const int propertyIndex = properties.value(name);
+ if (propertyIndex != -1) {
+ if (propertyIndex < context->idValueCount) {
+ v4->throwError(QLatin1String("left-hand side of assignment operator is not an lvalue"));
+ return false;
+ }
+ return false;
+ }
+ }
// Search scope object
if (scopeObject &&
@@ -323,6 +436,146 @@ bool QQmlContextWrapper::virtualPut(Managed *m, PropertyKey id, const Value &val
return false;
}
+ReturnedValue QQmlContextWrapper::resolveQmlContextPropertyLookupGetter(Lookup *l, ExecutionEngine *engine, Value *base)
+{
+ Scope scope(engine);
+ PropertyKey name =engine->identifierTable->asPropertyKey(engine->currentStackFrame->v4Function->compilationUnit->
+ runtimeStrings[l->nameIndex]);
+
+ // Special hack for bounded signal expressions, where the parameters of signals are injected
+ // into the handler expression through the locals of the call context. So for onClicked: { ... }
+ // the parameters of the clicked signal are injected and we must allow for them to be found here
+ // before any other property from the QML context.
+ ExecutionContext &ctx = static_cast<ExecutionContext &>(engine->currentStackFrame->jsFrame->context);
+ if (ctx.d()->type == Heap::ExecutionContext::Type_CallContext) {
+ uint index = ctx.d()->internalClass->indexOfValueOrGetter(name);
+ if (index < UINT_MAX)
+ return static_cast<Heap::CallContext*>(ctx.d())->locals[index].asReturnedValue();
+ }
+
+ Scoped<QQmlContextWrapper> qmlContext(scope, engine->qmlContext()->qml());
+ bool hasProperty = false;
+ ScopedValue result(scope, QQmlContextWrapper::getPropertyAndBase(qmlContext, name, /*receiver*/nullptr,
+ &hasProperty, base, l));
+ if (!hasProperty)
+ return engine->throwReferenceError(name.toQString());
+ return result->asReturnedValue();
+}
+
+ReturnedValue QQmlContextWrapper::lookupScript(Lookup *l, ExecutionEngine *engine, Value *base)
+{
+ Q_UNUSED(base)
+ Scope scope(engine);
+ Scoped<QmlContext> qmlContext(scope, engine->qmlContext());
+ if (!qmlContext)
+ return QV4::Encode::null();
+
+ QQmlContextData *context = qmlContext->qmlContext();
+ if (!context)
+ return QV4::Encode::null();
+
+ QV4::ScopedObject scripts(scope, context->importedScripts.valueRef());
+ if (!scripts)
+ return QV4::Encode::null();
+ return scripts->get(l->qmlContextScriptLookup.scriptIndex);
+}
+
+ReturnedValue QQmlContextWrapper::lookupSingleton(Lookup *l, ExecutionEngine *engine, Value *base)
+{
+ Q_UNUSED(engine)
+ Q_UNUSED(base)
+ return Value::fromHeapObject(l->qmlContextSingletonLookup.singleton).asReturnedValue();
+}
+
+ReturnedValue QQmlContextWrapper::lookupIdObject(Lookup *l, ExecutionEngine *engine, Value *base)
+{
+ Q_UNUSED(base)
+ Scope scope(engine);
+ Scoped<QmlContext> qmlContext(scope, engine->qmlContext());
+ if (!qmlContext)
+ return QV4::Encode::null();
+
+ QQmlContextData *context = qmlContext->qmlContext();
+ if (!context)
+ return QV4::Encode::null();
+
+ QQmlEnginePrivate *qmlEngine = QQmlEnginePrivate::get(engine->qmlEngine());
+ const int objectId = l->qmlContextIdObjectLookup.objectId;
+
+ if (qmlEngine->propertyCapture)
+ qmlEngine->propertyCapture->captureProperty(&context->idValues[objectId].bindings);
+
+ return QV4::QObjectWrapper::wrap(engine, context->idValues[objectId]);
+}
+
+ReturnedValue QQmlContextWrapper::lookupScopeObjectProperty(Lookup *l, ExecutionEngine *engine, Value *base)
+{
+ Q_UNUSED(base)
+ Scope scope(engine);
+ Scoped<QmlContext> qmlContext(scope, engine->qmlContext());
+ if (!qmlContext)
+ return QV4::Encode::undefined();
+
+ QObject *scopeObject = qmlContext->qmlScope();
+ if (!scopeObject)
+ return QV4::Encode::undefined();
+
+ if (QQmlData::wasDeleted(scopeObject))
+ return QV4::Encode::undefined();
+
+ const auto revertLookup = [l, engine, base]() {
+ l->qobjectLookup.propertyCache->release();
+ l->qobjectLookup.propertyCache = nullptr;
+ l->qmlContextPropertyGetter = QQmlContextWrapper::resolveQmlContextPropertyLookupGetter;
+ return QQmlContextWrapper::resolveQmlContextPropertyLookupGetter(l, engine, base);
+ };
+
+ ScopedValue obj(scope, QV4::QObjectWrapper::wrap(engine, scopeObject));
+ return QObjectWrapper::lookupGetterImpl(l, engine, obj, /*useOriginalProperty*/ true, revertLookup);
+}
+
+ReturnedValue QQmlContextWrapper::lookupContextObjectProperty(Lookup *l, ExecutionEngine *engine, Value *base)
+{
+ Q_UNUSED(base)
+ Scope scope(engine);
+ Scoped<QmlContext> qmlContext(scope, engine->qmlContext());
+ if (!qmlContext)
+ return QV4::Encode::undefined();
+
+ QQmlContextData *context = qmlContext->qmlContext();
+ if (!context)
+ return QV4::Encode::undefined();
+
+ QObject *contextObject = context->contextObject;
+ if (!contextObject)
+ return QV4::Encode::undefined();
+
+ if (QQmlData::wasDeleted(contextObject))
+ return QV4::Encode::undefined();
+
+ const auto revertLookup = [l, engine, base]() {
+ l->qobjectLookup.propertyCache->release();
+ l->qobjectLookup.propertyCache = nullptr;
+ l->qmlContextPropertyGetter = QQmlContextWrapper::resolveQmlContextPropertyLookupGetter;
+ return QQmlContextWrapper::resolveQmlContextPropertyLookupGetter(l, engine, base);
+ };
+
+ ScopedValue obj(scope, QV4::QObjectWrapper::wrap(engine, contextObject));
+ return QObjectWrapper::lookupGetterImpl(l, engine, obj, /*useOriginalProperty*/ true, revertLookup);
+}
+
+ReturnedValue QQmlContextWrapper::lookupInGlobalObject(Lookup *l, ExecutionEngine *engine, Value *base)
+{
+ Q_UNUSED(base);
+ ReturnedValue result = l->qmlContextGlobalLookup.getterTrampoline(l, engine);
+ // In the unlikely event of mutation of the global object, update the trampoline.
+ if (l->qmlContextPropertyGetter != lookupInGlobalObject) {
+ l->qmlContextGlobalLookup.getterTrampoline = l->globalGetter;
+ l->qmlContextPropertyGetter = QQmlContextWrapper::lookupInGlobalObject;
+ }
+ return result;
+}
+
void Heap::QmlContext::init(QV4::ExecutionContext *outerContext, QV4::QQmlContextWrapper *qml)
{
Heap::ExecutionContext::init(Heap::ExecutionContext::Type_QmlContext);
diff --git a/src/qml/jsruntime/qv4qmlcontext_p.h b/src/qml/jsruntime/qv4qmlcontext_p.h
index dd6de3323d..6375294375 100644
--- a/src/qml/jsruntime/qv4qmlcontext_p.h
+++ b/src/qml/jsruntime/qv4qmlcontext_p.h
@@ -99,8 +99,18 @@ struct Q_QML_EXPORT QQmlContextWrapper : Object
inline QObject *getScopeObject() const { return d()->scopeObject; }
inline QQmlContextData *getContext() const { return *d()->context; }
+ static ReturnedValue getPropertyAndBase(const QQmlContextWrapper *resource, PropertyKey id, const Value *receiver,
+ bool *hasProperty, Value *base, Lookup *lookup = nullptr);
static ReturnedValue virtualGet(const Managed *m, PropertyKey id, const Value *receiver, bool *hasProperty);
static bool virtualPut(Managed *m, PropertyKey id, const Value &value, Value *receiver);
+
+ static ReturnedValue resolveQmlContextPropertyLookupGetter(Lookup *l, ExecutionEngine *engine, Value *base);
+ static ReturnedValue lookupScript(Lookup *l, ExecutionEngine *engine, Value *base);
+ static ReturnedValue lookupSingleton(Lookup *l, ExecutionEngine *engine, Value *base);
+ static ReturnedValue lookupIdObject(Lookup *l, ExecutionEngine *engine, Value *base);
+ static ReturnedValue lookupScopeObjectProperty(Lookup *l, ExecutionEngine *engine, Value *base);
+ static ReturnedValue lookupContextObjectProperty(Lookup *l, ExecutionEngine *engine, Value *base);
+ static ReturnedValue lookupInGlobalObject(Lookup *l, ExecutionEngine *engine, Value *base);
};
struct Q_QML_EXPORT QmlContext : public ExecutionContext
diff --git a/src/qml/jsruntime/qv4qobjectwrapper.cpp b/src/qml/jsruntime/qv4qobjectwrapper.cpp
index 40be6f41c8..377c30617a 100644
--- a/src/qml/jsruntime/qv4qobjectwrapper.cpp
+++ b/src/qml/jsruntime/qv4qobjectwrapper.cpp
@@ -56,6 +56,8 @@
#include <private/qv4functionobject_p.h>
#include <private/qv4runtime_p.h>
#include <private/qv4variantobject_p.h>
+#include <private/qv4identifiertable_p.h>
+#include <private/qv4lookup_p.h>
#if QT_CONFIG(qml_sequence_object)
#include <private/qv4sequenceobject_p.h>
@@ -231,7 +233,7 @@ QQmlPropertyData *QObjectWrapper::findProperty(ExecutionEngine *engine, QObject
return result;
}
-ReturnedValue QObjectWrapper::getProperty(ExecutionEngine *engine, QObject *object, QQmlPropertyData *property, bool captureRequired)
+ReturnedValue QObjectWrapper::getProperty(ExecutionEngine *engine, QObject *object, QQmlPropertyData *property)
{
QQmlData::flushPendingBinding(object, QQmlPropertyIndex(property->coreIndex()));
@@ -257,7 +259,7 @@ ReturnedValue QObjectWrapper::getProperty(ExecutionEngine *engine, QObject *obje
QQmlEnginePrivate *ep = engine->qmlEngine() ? QQmlEnginePrivate::get(engine->qmlEngine()) : nullptr;
- if (captureRequired && ep && ep->propertyCapture && !property->isConstant())
+ if (ep && ep->propertyCapture && !property->isConstant())
ep->propertyCapture->captureProperty(object, property->coreIndex(), property->notifyIndex());
if (property->isVarProperty()) {
@@ -269,9 +271,53 @@ ReturnedValue QObjectWrapper::getProperty(ExecutionEngine *engine, QObject *obje
}
}
+static OptionalReturnedValue getDestroyOrToStringMethod(ExecutionEngine *v4, String *name, QObject *qobj, bool *hasProperty = nullptr)
+{
+ int index = 0;
+ if (name->equals(v4->id_destroy()))
+ index = QV4::QObjectMethod::DestroyMethod;
+ else if (name->equals(v4->id_toString()))
+ index = QV4::QObjectMethod::ToStringMethod;
+ else
+ return OptionalReturnedValue();
+
+ if (hasProperty)
+ *hasProperty = true;
+ ExecutionContext *global = v4->rootContext();
+ return OptionalReturnedValue(QV4::QObjectMethod::create(global, qobj, index));
+}
+
+static OptionalReturnedValue getPropertyFromImports(ExecutionEngine *v4, String *name, QQmlContextData *qmlContext, QObject *qobj,
+ bool *hasProperty = nullptr)
+{
+ if (!qmlContext || !qmlContext->imports)
+ return OptionalReturnedValue();
+
+ QQmlTypeNameCache::Result r = qmlContext->imports->query(name);
+
+ if (hasProperty)
+ *hasProperty = true;
+
+ if (!r.isValid())
+ return OptionalReturnedValue();
+
+ if (r.scriptIndex != -1) {
+ return OptionalReturnedValue(QV4::Encode::undefined());
+ } else if (r.type.isValid()) {
+ return OptionalReturnedValue(QQmlTypeWrapper::create(v4, qobj,r.type, Heap::QQmlTypeWrapper::ExcludeEnums));
+ } else if (r.importNamespace) {
+ return OptionalReturnedValue(QQmlTypeWrapper::create(v4, qobj, qmlContext->imports, r.importNamespace,
+ Heap::QQmlTypeWrapper::ExcludeEnums));
+ }
+ Q_UNREACHABLE();
+ return OptionalReturnedValue();
+}
+
ReturnedValue QObjectWrapper::getQmlProperty(QQmlContextData *qmlContext, String *name, QObjectWrapper::RevisionMode revisionMode,
bool *hasProperty, bool includeImports) const
{
+ // Keep this code in sync with ::virtualResolveLookupGetter
+
if (QQmlData::wasDeleted(d()->object())) {
if (hasProperty)
*hasProperty = false;
@@ -280,39 +326,17 @@ ReturnedValue QObjectWrapper::getQmlProperty(QQmlContextData *qmlContext, String
ExecutionEngine *v4 = engine();
- if (name->equals(v4->id_destroy()) || name->equals(v4->id_toString())) {
- int index = name->equals(v4->id_destroy()) ? QV4::QObjectMethod::DestroyMethod : QV4::QObjectMethod::ToStringMethod;
- if (hasProperty)
- *hasProperty = true;
- ExecutionContext *global = v4->rootContext();
- return QV4::QObjectMethod::create(global, d()->object(), index);
- }
+ if (auto methodValue = getDestroyOrToStringMethod(v4, name, d()->object(), hasProperty))
+ return *methodValue;
QQmlPropertyData local;
QQmlPropertyData *result = findProperty(v4, qmlContext, name, revisionMode, &local);
if (!result) {
+ // Check for attached properties
if (includeImports && name->startsWithUpper()) {
- // Check for attached properties
- if (qmlContext && qmlContext->imports) {
- QQmlTypeNameCache::Result r = qmlContext->imports->query(name);
-
- if (hasProperty)
- *hasProperty = true;
-
- if (r.isValid()) {
- if (r.scriptIndex != -1) {
- return QV4::Encode::undefined();
- } else if (r.type.isValid()) {
- return QQmlTypeWrapper::create(v4, d()->object(),
- r.type, Heap::QQmlTypeWrapper::ExcludeEnums);
- } else if (r.importNamespace) {
- return QQmlTypeWrapper::create(v4, d()->object(),
- qmlContext->imports, r.importNamespace, Heap::QQmlTypeWrapper::ExcludeEnums);
- }
- Q_ASSERT(!"Unreachable");
- }
- }
+ if (auto importProperty = getPropertyFromImports(v4, name, qmlContext, d()->object(), hasProperty))
+ return *importProperty;
}
return QV4::Object::virtualGet(this, name->propertyKey(), this, hasProperty);
}
@@ -333,27 +357,7 @@ ReturnedValue QObjectWrapper::getQmlProperty(QQmlContextData *qmlContext, String
return getProperty(v4, d()->object(), result);
}
-ReturnedValue QObjectWrapper::getProperty(ExecutionEngine *engine, QObject *object, int propertyIndex, bool captureRequired)
-{
- if (QQmlData::wasDeleted(object))
- return QV4::Encode::null();
- QQmlData *ddata = QQmlData::get(object, /*create*/false);
- if (!ddata)
- return QV4::Encode::undefined();
-
- if (Q_UNLIKELY(!ddata->propertyCache)) {
- ddata->propertyCache = QQmlEnginePrivate::get(engine)->cache(object->metaObject());
- ddata->propertyCache->addref();
- }
-
- QQmlPropertyCache *cache = ddata->propertyCache;
- Q_ASSERT(cache);
- QQmlPropertyData *property = cache->property(propertyIndex);
- Q_ASSERT(property); // We resolved this property earlier, so it better exist!
- return getProperty(engine, object, property, captureRequired);
-}
-
-ReturnedValue QObjectWrapper::getQmlProperty(QV4::ExecutionEngine *engine, QQmlContextData *qmlContext, QObject *object, String *name, QObjectWrapper::RevisionMode revisionMode, bool *hasProperty)
+ReturnedValue QObjectWrapper::getQmlProperty(QV4::ExecutionEngine *engine, QQmlContextData *qmlContext, QObject *object, String *name, QObjectWrapper::RevisionMode revisionMode, bool *hasProperty, QQmlPropertyData **property)
{
if (QQmlData::wasDeleted(object)) {
if (hasProperty)
@@ -361,13 +365,8 @@ ReturnedValue QObjectWrapper::getQmlProperty(QV4::ExecutionEngine *engine, QQmlC
return QV4::Encode::null();
}
- if (name->equals(engine->id_destroy()) || name->equals(engine->id_toString())) {
- int index = name->equals(engine->id_destroy()) ? QV4::QObjectMethod::DestroyMethod : QV4::QObjectMethod::ToStringMethod;
- if (hasProperty)
- *hasProperty = true;
- ExecutionContext *global = engine->rootContext();
- return QV4::QObjectMethod::create(global, object, index);
- }
+ if (auto methodValue = getDestroyOrToStringMethod(engine, name, object, hasProperty))
+ return *methodValue;
QQmlData *ddata = QQmlData::get(object, false);
QQmlPropertyData local;
@@ -385,6 +384,9 @@ ReturnedValue QObjectWrapper::getQmlProperty(QV4::ExecutionEngine *engine, QQmlC
if (hasProperty)
*hasProperty = true;
+ if (property)
+ *property = result;
+
return getProperty(engine, object, result);
} else {
// Check if this object is already wrapped.
@@ -829,6 +831,71 @@ OwnPropertyKeyIterator *QObjectWrapper::virtualOwnPropertyKeys(const Object *m,
return new QObjectWrapperOwnPropertyKeyIterator;
}
+ReturnedValue QObjectWrapper::virtualResolveLookupGetter(const Object *object, ExecutionEngine *engine, Lookup *lookup)
+{
+ // Keep this code in sync with ::getQmlProperty
+ PropertyKey id = engine->identifierTable->asPropertyKey(engine->currentStackFrame->v4Function->compilationUnit->
+ runtimeStrings[lookup->nameIndex]);
+ if (!id.isString())
+ return Object::virtualResolveLookupGetter(object, engine, lookup);
+ Scope scope(engine);
+
+ const QObjectWrapper *This = static_cast<const QObjectWrapper *>(object);
+ ScopedString name(scope, id.asStringOrSymbol());
+ QQmlContextData *qmlContext = engine->callingQmlContext();
+
+ QObject * const qobj = This->d()->object();
+
+ if (QQmlData::wasDeleted(qobj))
+ return QV4::Encode::undefined();
+
+ if (auto methodValue = getDestroyOrToStringMethod(engine, name, qobj))
+ return *methodValue;
+
+ QQmlData *ddata = QQmlData::get(qobj, false);
+ if (!ddata || !ddata->propertyCache) {
+ QQmlPropertyData local;
+ QQmlPropertyData *property = QQmlPropertyCache::property(engine->jsEngine(), qobj, name, qmlContext, local);
+ return getProperty(engine, qobj, property);
+ }
+ QQmlPropertyData *property = ddata->propertyCache->property(name.getPointer(), qobj, qmlContext);
+
+ if (!property) {
+ // Check for attached properties
+ if (name->startsWithUpper()) {
+ if (auto importProperty = getPropertyFromImports(engine, name, qmlContext, qobj))
+ return *importProperty;
+ }
+ return QV4::Object::virtualResolveLookupGetter(object, engine, lookup);
+ }
+
+ lookup->qobjectLookup.ic = This->internalClass();
+ lookup->qobjectLookup.staticQObject = nullptr;
+ lookup->qobjectLookup.propertyCache = ddata->propertyCache;
+ lookup->qobjectLookup.propertyCache->addref();
+ lookup->qobjectLookup.propertyData = property;
+ lookup->getter = QV4::QObjectWrapper::lookupGetter;
+ return lookup->getter(lookup, engine, *object);
+}
+
+ReturnedValue QObjectWrapper::lookupGetter(Lookup *lookup, ExecutionEngine *engine, const Value &object)
+{
+ const auto revertLookup = [lookup, engine, &object]() {
+ lookup->qobjectLookup.propertyCache->release();
+ lookup->qobjectLookup.propertyCache = nullptr;
+ lookup->getter = Lookup::getterGeneric;
+ return Lookup::getterGeneric(lookup, engine, object);
+ };
+
+ return lookupGetterImpl(lookup, engine, object, /*useOriginalProperty*/ false, revertLookup);
+}
+
+bool QObjectWrapper::virtualResolveLookupSetter(Object *object, ExecutionEngine *engine, Lookup *lookup,
+ const Value &value)
+{
+ return Object::virtualResolveLookupSetter(object, engine, lookup, value);
+}
+
namespace QV4 {
struct QObjectSlotDispatcher : public QtPrivate::QSlotObjectBase
@@ -1920,13 +1987,13 @@ ReturnedValue QObjectMethod::create(ExecutionContext *scope, QObject *object, in
return method.asReturnedValue();
}
-ReturnedValue QObjectMethod::create(ExecutionContext *scope, const QQmlValueTypeWrapper *valueType, int index)
+ReturnedValue QObjectMethod::create(ExecutionContext *scope, Heap::QQmlValueTypeWrapper *valueType, int index)
{
Scope valueScope(scope);
Scoped<QObjectMethod> method(valueScope, valueScope.engine->memoryManager->allocate<QObjectMethod>(scope));
- method->d()->setPropertyCache(valueType->d()->propertyCache());
+ method->d()->setPropertyCache(valueType->propertyCache());
method->d()->index = index;
- method->d()->valueTypeWrapper.set(valueScope.engine, valueType->d());
+ method->d()->valueTypeWrapper.set(valueScope.engine, valueType);
return method.asReturnedValue();
}
diff --git a/src/qml/jsruntime/qv4qobjectwrapper_p.h b/src/qml/jsruntime/qv4qobjectwrapper_p.h
index 6465ee0fa6..2558ede401 100644
--- a/src/qml/jsruntime/qv4qobjectwrapper_p.h
+++ b/src/qml/jsruntime/qv4qobjectwrapper_p.h
@@ -62,6 +62,7 @@
#include <private/qv4value_p.h>
#include <private/qv4functionobject_p.h>
+#include <private/qv4lookup_p.h>
QT_BEGIN_NAMESPACE
@@ -167,7 +168,7 @@ struct Q_QML_EXPORT QObjectWrapper : public Object
QObject *object() const { return d()->object(); }
ReturnedValue getQmlProperty(QQmlContextData *qmlContext, String *name, RevisionMode revisionMode, bool *hasProperty = nullptr, bool includeImports = false) const;
- static ReturnedValue getQmlProperty(ExecutionEngine *engine, QQmlContextData *qmlContext, QObject *object, String *name, RevisionMode revisionMode, bool *hasProperty = nullptr);
+ static ReturnedValue getQmlProperty(ExecutionEngine *engine, QQmlContextData *qmlContext, QObject *object, String *name, RevisionMode revisionMode, bool *hasProperty = nullptr, QQmlPropertyData **property = nullptr);
static bool setQmlProperty(ExecutionEngine *engine, QQmlContextData *qmlContext, QObject *object, String *name, RevisionMode revisionMode, const Value &value);
@@ -176,13 +177,18 @@ struct Q_QML_EXPORT QObjectWrapper : public Object
using Object::get;
- static ReturnedValue getProperty(ExecutionEngine *engine, QObject *object, int propertyIndex, bool captureRequired);
static void setProperty(ExecutionEngine *engine, QObject *object, int propertyIndex, const Value &value);
void setProperty(ExecutionEngine *engine, int propertyIndex, const Value &value);
void destroyObject(bool lastCall);
- static ReturnedValue getProperty(ExecutionEngine *engine, QObject *object, QQmlPropertyData *property, bool captureRequired = true);
+ static ReturnedValue getProperty(ExecutionEngine *engine, QObject *object, QQmlPropertyData *property);
+
+ static ReturnedValue virtualResolveLookupGetter(const Object *object, ExecutionEngine *engine, Lookup *lookup);
+ static ReturnedValue lookupGetter(Lookup *l, ExecutionEngine *engine, const Value &object);
+ template <typename ReversalFunctor> static ReturnedValue lookupGetterImpl(Lookup *l, ExecutionEngine *engine, const Value &object, bool useOriginalProperty, ReversalFunctor revert);
+ static bool virtualResolveLookupSetter(Object *object, ExecutionEngine *engine, Lookup *lookup, const Value &value);
+
protected:
static void setProperty(ExecutionEngine *engine, QObject *object, QQmlPropertyData *property, const Value &value);
@@ -218,6 +224,47 @@ inline ReturnedValue QObjectWrapper::wrap(ExecutionEngine *engine, QObject *obje
return wrap_slowPath(engine, object);
}
+template <typename ReversalFunctor>
+inline ReturnedValue QObjectWrapper::lookupGetterImpl(Lookup *lookup, ExecutionEngine *engine, const Value &object, bool useOriginalProperty, ReversalFunctor revertLookup)
+{
+ // we can safely cast to a QV4::Object here. If object is something else,
+ // the internal class won't match
+ Heap::Object *o = static_cast<Heap::Object *>(object.heapObject());
+ if (!o || o->internalClass != lookup->qobjectLookup.ic)
+ return revertLookup();
+
+ const Heap::QObjectWrapper *This = lookup->qobjectLookup.staticQObject ? lookup->qobjectLookup.staticQObject :
+ static_cast<const Heap::QObjectWrapper *>(o);
+ QObject *qobj = This->object();
+ if (QQmlData::wasDeleted(qobj))
+ return QV4::Encode::undefined();
+
+ QQmlData *ddata = QQmlData::get(qobj, /*create*/false);
+ if (!ddata)
+ return revertLookup();
+
+ QQmlPropertyData *property = lookup->qobjectLookup.propertyData;
+ if (ddata->propertyCache != lookup->qobjectLookup.propertyCache) {
+ if (property->isOverridden() && (!useOriginalProperty || property->isFunction() || property->isSignalHandler()))
+ return revertLookup();
+
+ QQmlPropertyCache *fromMo = ddata->propertyCache;
+ QQmlPropertyCache *toMo = lookup->qobjectLookup.propertyCache;
+ bool canConvert = false;
+ while (fromMo) {
+ if (fromMo == toMo) {
+ canConvert = true;
+ break;
+ }
+ fromMo = fromMo->parent();
+ }
+ if (!canConvert)
+ return revertLookup();
+ }
+
+ return getProperty(engine, qobj, property);
+}
+
struct QQmlValueTypeWrapper;
struct Q_QML_EXPORT QObjectMethod : public QV4::FunctionObject
@@ -228,7 +275,7 @@ struct Q_QML_EXPORT QObjectMethod : public QV4::FunctionObject
enum { DestroyMethod = -1, ToStringMethod = -2 };
static ReturnedValue create(QV4::ExecutionContext *scope, QObject *object, int index);
- static ReturnedValue create(QV4::ExecutionContext *scope, const QQmlValueTypeWrapper *valueType, int index);
+ static ReturnedValue create(QV4::ExecutionContext *scope, Heap::QQmlValueTypeWrapper *valueType, int index);
int methodIndex() const { return d()->index; }
QObject *object() const { return d()->object(); }
diff --git a/src/qml/jsruntime/qv4runtime.cpp b/src/qml/jsruntime/qv4runtime.cpp
index afa4632e07..bde7cc6798 100644
--- a/src/qml/jsruntime/qv4runtime.cpp
+++ b/src/qml/jsruntime/qv4runtime.cpp
@@ -1349,18 +1349,42 @@ uint Runtime::method_compareIn(ExecutionEngine *engine, const Value &left, const
return v->booleanValue();
}
+static ReturnedValue throwPropertyIsNotAFunctionTypeError(ExecutionEngine *engine, Value *thisObject, const QString &propertyName)
+{
+ QString objectAsString = QStringLiteral("[null]");
+ if (!thisObject->isUndefined())
+ objectAsString = thisObject->toQStringNoThrow();
+ QString msg = QStringLiteral("Property '%1' of object %2 is not a function")
+ .arg(propertyName, objectAsString);
+ return engine->throwTypeError(msg);
+}
ReturnedValue Runtime::method_callGlobalLookup(ExecutionEngine *engine, uint index, Value *argv, int argc)
{
+ Scope scope(engine);
Lookup *l = engine->currentStackFrame->v4Function->compilationUnit->runtimeLookups + index;
Value function = Value::fromReturnedValue(l->globalGetter(l, engine));
+ Value thisObject = Value::undefinedValue();
if (!function.isFunctionObject())
- return engine->throwTypeError();
+ return throwPropertyIsNotAFunctionTypeError(engine, &thisObject,
+ engine->currentStackFrame->v4Function->compilationUnit->runtimeStrings[l->nameIndex]->toQString());
- Value thisObject = Value::undefinedValue();
return static_cast<FunctionObject &>(function).call(&thisObject, argv, argc);
}
+ReturnedValue Runtime::method_callQmlContextPropertyLookup(ExecutionEngine *engine, uint index, Value *argv, int argc)
+{
+ Scope scope(engine);
+ ScopedValue thisObject(scope);
+ Lookup *l = engine->currentStackFrame->v4Function->compilationUnit->runtimeLookups + index;
+ Value function = Value::fromReturnedValue(l->qmlContextPropertyGetter(l, engine, thisObject));
+ if (!function.isFunctionObject())
+ return throwPropertyIsNotAFunctionTypeError(engine, thisObject,
+ engine->currentStackFrame->v4Function->compilationUnit->runtimeStrings[l->nameIndex]->toQString());
+
+ return static_cast<FunctionObject &>(function).call(thisObject, argv, argc);
+}
+
ReturnedValue Runtime::method_callPossiblyDirectEval(ExecutionEngine *engine, Value *argv, int argc)
{
Scope scope(engine);
@@ -1371,13 +1395,8 @@ ReturnedValue Runtime::method_callPossiblyDirectEval(ExecutionEngine *engine, Va
if (engine->hasException)
return Encode::undefined();
- if (!function) {
- QString objectAsString = QStringLiteral("[null]");
- if (!thisObject->isUndefined())
- objectAsString = thisObject->toQStringNoThrow();
- QString msg = QStringLiteral("Property 'eval' of object %2 is not a function").arg(objectAsString);
- return engine->throwTypeError(msg);
- }
+ if (!function)
+ return throwPropertyIsNotAFunctionTypeError(engine, thisObject, QLatin1String("eval"));
if (function->d() == engine->evalFunction()->d())
return static_cast<EvalFunction *>(function.getPointer())->evalCall(thisObject, argv, argc, true);
@@ -1396,15 +1415,9 @@ ReturnedValue Runtime::method_callName(ExecutionEngine *engine, int nameIndex, V
if (engine->hasException)
return Encode::undefined();
- if (!f) {
- QString objectAsString = QStringLiteral("[null]");
- if (!thisObject->isUndefined())
- objectAsString = thisObject->toQStringNoThrow();
- QString msg = QStringLiteral("Property '%1' of object %2 is not a function")
- .arg(engine->currentStackFrame->v4Function->compilationUnit->runtimeStrings[nameIndex]->toQString(),
- objectAsString);
- return engine->throwTypeError(msg);
- }
+ if (!f)
+ return throwPropertyIsNotAFunctionTypeError(engine, thisObject,
+ engine->currentStackFrame->v4Function->compilationUnit->runtimeStrings[nameIndex]->toQString());
return f->call(thisObject, argv, argc);
}
@@ -1492,38 +1505,6 @@ ReturnedValue Runtime::method_callWithReceiver(ExecutionEngine *engine, const Va
return static_cast<const FunctionObject &>(func).call(thisObject, argv, argc);
}
-ReturnedValue Runtime::method_callQmlScopeObjectProperty(ExecutionEngine *engine, Value *base,
- int propertyIndex, Value *argv, int argc)
-{
- Scope scope(engine);
- ScopedFunctionObject fo(scope, method_loadQmlScopeObjectProperty(engine, *base, propertyIndex,
- /*captureRequired*/true));
- if (!fo) {
- QString error = QStringLiteral("Property '%1' of scope object is not a function").arg(propertyIndex);
- return engine->throwTypeError(error);
- }
-
- QObject *qmlScopeObj = static_cast<QmlContext *>(base)->d()->qml()->scopeObject;
- ScopedValue qmlScopeValue(scope, QObjectWrapper::wrap(engine, qmlScopeObj));
- return fo->call(qmlScopeValue, argv, argc);
-}
-
-ReturnedValue Runtime::method_callQmlContextObjectProperty(ExecutionEngine *engine, Value *base,
- int propertyIndex, Value *argv, int argc)
-{
- Scope scope(engine);
- ScopedFunctionObject fo(scope, method_loadQmlContextObjectProperty(engine, *base, propertyIndex,
- /*captureRequired*/true));
- if (!fo) {
- QString error = QStringLiteral("Property '%1' of context object is not a function").arg(propertyIndex);
- return engine->throwTypeError(error);
- }
-
- QObject *qmlContextObj = static_cast<QmlContext *>(base)->d()->qml()->context->contextData()->contextObject;
- ScopedValue qmlContextValue(scope, QObjectWrapper::wrap(engine, qmlContextObj));
- return fo->call(qmlContextValue, argv, argc);
-}
-
struct CallArgs {
Value *argv;
int argc;
@@ -1939,65 +1920,11 @@ QV4::ReturnedValue Runtime::method_createRestParameter(ExecutionEngine *engine,
return engine->newArrayObject(values, nValues)->asReturnedValue();
}
-
-ReturnedValue Runtime::method_loadQmlContext(NoThrowEngine *engine)
-{
- Heap::QmlContext *ctx = engine->qmlContext();
- Q_ASSERT(ctx);
- return ctx->asReturnedValue();
-}
-
ReturnedValue Runtime::method_regexpLiteral(ExecutionEngine *engine, int id)
{
Heap::RegExpObject *ro = engine->newRegExpObject(engine->currentStackFrame->v4Function->compilationUnit->runtimeRegularExpressions[id].as<RegExp>());
return ro->asReturnedValue();
}
-
-ReturnedValue Runtime::method_loadQmlScopeObjectProperty(ExecutionEngine *engine, const Value &context, int propertyIndex, bool captureRequired)
-{
- const QmlContext &c = static_cast<const QmlContext &>(context);
- return QV4::QObjectWrapper::getProperty(engine, c.d()->qml()->scopeObject, propertyIndex, captureRequired);
-}
-
-ReturnedValue Runtime::method_loadQmlContextObjectProperty(ExecutionEngine *engine, const Value &context, int propertyIndex, bool captureRequired)
-{
- const QmlContext &c = static_cast<const QmlContext &>(context);
- return QV4::QObjectWrapper::getProperty(engine, (*c.d()->qml()->context)->contextObject, propertyIndex, captureRequired);
-}
-
-ReturnedValue Runtime::method_loadQmlIdObject(ExecutionEngine *engine, const Value &c, uint index)
-{
- const QmlContext &qmlContext = static_cast<const QmlContext &>(c);
- QQmlContextData *context = *qmlContext.d()->qml()->context;
- if (!context || index >= (uint)context->idValueCount)
- return Encode::undefined();
-
- QQmlEnginePrivate *ep = engine->qmlEngine() ? QQmlEnginePrivate::get(engine->qmlEngine()) : nullptr;
- if (ep && ep->propertyCapture)
- ep->propertyCapture->captureProperty(&context->idValues[index].bindings);
-
- return QObjectWrapper::wrap(engine, context->idValues[index].data());
-}
-
-void Runtime::method_storeQmlScopeObjectProperty(ExecutionEngine *engine, const Value &context, int propertyIndex, const Value &value)
-{
- const QmlContext &c = static_cast<const QmlContext &>(context);
- return QV4::QObjectWrapper::setProperty(engine, c.d()->qml()->scopeObject, propertyIndex, value);
-}
-
-void Runtime::method_storeQmlContextObjectProperty(ExecutionEngine *engine, const Value &context, int propertyIndex, const Value &value)
-{
- const QmlContext &c = static_cast<const QmlContext &>(context);
- return QV4::QObjectWrapper::setProperty(engine, (*c.d()->qml()->context)->contextObject, propertyIndex, value);
-}
-
-ReturnedValue Runtime::method_loadQmlImportedScripts(NoThrowEngine *engine)
-{
- QQmlContextData *context = engine->callingQmlContext();
- if (!context)
- return Encode::undefined();
- return context->importedScripts.value();
-}
#endif // V4_BOOTSTRAP
ReturnedValue Runtime::method_uMinus(const Value &value)
diff --git a/src/qml/jsruntime/qv4runtimeapi_p.h b/src/qml/jsruntime/qv4runtimeapi_p.h
index dc4dbb11b1..ceec13a3bb 100644
--- a/src/qml/jsruntime/qv4runtimeapi_p.h
+++ b/src/qml/jsruntime/qv4runtimeapi_p.h
@@ -93,6 +93,7 @@ struct ExceptionCheck<void (*)(QV4::NoThrowEngine *, A, B, C)> {
#define FOR_EACH_RUNTIME_METHOD(F) \
/* call */ \
F(ReturnedValue, callGlobalLookup, (ExecutionEngine *engine, uint index, Value *argv, int argc)) \
+ F(ReturnedValue, callQmlContextPropertyLookup, (ExecutionEngine *engine, uint index, Value *argv, int argc)) \
F(ReturnedValue, callName, (ExecutionEngine *engine, int nameIndex, Value *argv, int argc)) \
F(ReturnedValue, callProperty, (ExecutionEngine *engine, Value *base, int nameIndex, Value *argv, int argc)) \
F(ReturnedValue, callPropertyLookup, (ExecutionEngine *engine, Value *base, uint index, Value *argv, int argc)) \
@@ -196,19 +197,7 @@ struct ExceptionCheck<void (*)(QV4::NoThrowEngine *, A, B, C)> {
F(Bool, compareInstanceof, (ExecutionEngine *engine, const Value &left, const Value &right)) \
F(Bool, compareIn, (ExecutionEngine *engine, const Value &left, const Value &right)) \
\
- F(ReturnedValue, regexpLiteral, (ExecutionEngine *engine, int id)) \
- \
- /* qml */ \
- F(ReturnedValue, loadQmlContext, (NoThrowEngine *engine)) \
- F(ReturnedValue, loadQmlImportedScripts, (NoThrowEngine *engine)) \
- F(ReturnedValue, loadQmlScopeObjectProperty, (ExecutionEngine *engine, const Value &context, int propertyIndex, bool captureRequired)) \
- F(ReturnedValue, loadQmlContextObjectProperty, (ExecutionEngine *engine, const Value &context, int propertyIndex, bool captureRequired)) \
- F(ReturnedValue, loadQmlIdObject, (ExecutionEngine *engine, const Value &context, uint index)) \
- F(ReturnedValue, callQmlScopeObjectProperty, (ExecutionEngine *engine, Value *base, int propertyIndex, Value *argv, int argc)) \
- F(ReturnedValue, callQmlContextObjectProperty, (ExecutionEngine *engine, Value *base, int propertyIndex, Value *argv, int argc)) \
- \
- F(void, storeQmlScopeObjectProperty, (ExecutionEngine *engine, const Value &context, int propertyIndex, const Value &value)) \
- F(void, storeQmlContextObjectProperty, (ExecutionEngine *engine, const Value &context, int propertyIndex, const Value &value)) \
+ F(ReturnedValue, regexpLiteral, (ExecutionEngine *engine, int id))
struct Q_QML_PRIVATE_EXPORT Runtime {
Runtime();
diff --git a/src/qml/jsruntime/qv4value_p.h b/src/qml/jsruntime/qv4value_p.h
index 20a84beccd..b4a045edfb 100644
--- a/src/qml/jsruntime/qv4value_p.h
+++ b/src/qml/jsruntime/qv4value_p.h
@@ -863,6 +863,22 @@ struct ValueArray {
// have wrong offsets between host and target.
Q_STATIC_ASSERT(offsetof(ValueArray<0>, values) == 8);
+class OptionalReturnedValue {
+ ReturnedValue value;
+public:
+
+ OptionalReturnedValue() : value(Value::emptyValue().asReturnedValue()) {}
+ explicit OptionalReturnedValue(ReturnedValue v)
+ : value(v)
+ {
+ Q_ASSERT(!Value::fromReturnedValue(v).isEmpty());
+ }
+
+ ReturnedValue operator->() const { return value; }
+ ReturnedValue operator*() const { return value; }
+ explicit operator bool() const { return !Value::fromReturnedValue(value).isEmpty(); }
+};
+
}
QT_END_NAMESPACE
diff --git a/src/qml/jsruntime/qv4vme_moth.cpp b/src/qml/jsruntime/qv4vme_moth.cpp
index b7d2902b1d..dd712a15d6 100644
--- a/src/qml/jsruntime/qv4vme_moth.cpp
+++ b/src/qml/jsruntime/qv4vme_moth.cpp
@@ -629,6 +629,14 @@ QV4::ReturnedValue VME::interpret(CppStackFrame *frame, ExecutionEngine *engine,
traceValue(acc, function, traceSlot);
MOTH_END_INSTR(LoadGlobalLookup)
+ MOTH_BEGIN_INSTR(LoadQmlContextPropertyLookup)
+ STORE_IP();
+ QV4::Lookup *l = function->compilationUnit->runtimeLookups + index;
+ acc = l->qmlContextPropertyGetter(l, engine, nullptr);
+ CHECK_EXCEPTION;
+ traceValue(acc, function, traceSlot);
+ MOTH_END_INSTR(LoadQmlContextPropertyLookup)
+
MOTH_BEGIN_INSTR(StoreNameStrict)
STORE_IP();
STORE_ACC();
@@ -725,37 +733,6 @@ QV4::ReturnedValue VME::interpret(CppStackFrame *frame, ExecutionEngine *engine,
CHECK_EXCEPTION;
MOTH_END_INSTR(StoreSuperProperty)
- MOTH_BEGIN_INSTR(StoreScopeObjectProperty)
- STORE_ACC();
- Runtime::method_storeQmlScopeObjectProperty(engine, STACK_VALUE(base), propertyIndex, accumulator);
- CHECK_EXCEPTION;
- MOTH_END_INSTR(StoreScopeObjectProperty)
-
- MOTH_BEGIN_INSTR(LoadScopeObjectProperty)
- STORE_IP();
- acc = Runtime::method_loadQmlScopeObjectProperty(engine, STACK_VALUE(base), propertyIndex, captureRequired);
- CHECK_EXCEPTION;
- MOTH_END_INSTR(LoadScopeObjectProperty)
-
- MOTH_BEGIN_INSTR(StoreContextObjectProperty)
- STORE_IP();
- STORE_ACC();
- Runtime::method_storeQmlContextObjectProperty(engine, STACK_VALUE(base), propertyIndex, accumulator);
- CHECK_EXCEPTION;
- MOTH_END_INSTR(StoreContextObjectProperty)
-
- MOTH_BEGIN_INSTR(LoadContextObjectProperty)
- STORE_IP();
- acc = Runtime::method_loadQmlContextObjectProperty(engine, STACK_VALUE(base), propertyIndex, captureRequired);
- CHECK_EXCEPTION;
- MOTH_END_INSTR(LoadContextObjectProperty)
-
- MOTH_BEGIN_INSTR(LoadIdObject)
- STORE_IP();
- acc = Runtime::method_loadQmlIdObject(engine, STACK_VALUE(base), index);
- CHECK_EXCEPTION;
- MOTH_END_INSTR(LoadIdObject)
-
MOTH_BEGIN_INSTR(Yield)
frame->yield = code;
frame->yieldIsIterator = false;
@@ -875,19 +852,12 @@ QV4::ReturnedValue VME::interpret(CppStackFrame *frame, ExecutionEngine *engine,
traceValue(acc, function, traceSlot);
MOTH_END_INSTR(CallGlobalLookup)
- MOTH_BEGIN_INSTR(CallScopeObjectProperty)
+ MOTH_BEGIN_INSTR(CallQmlContextPropertyLookup)
STORE_IP();
- acc = Runtime::method_callQmlScopeObjectProperty(engine, stack + base, name, stack + argv, argc);
+ acc = Runtime::method_callQmlContextPropertyLookup(engine, index, stack + argv, argc);
CHECK_EXCEPTION;
traceValue(acc, function, traceSlot);
- MOTH_END_INSTR(CallScopeObjectProperty)
-
- MOTH_BEGIN_INSTR(CallContextObjectProperty)
- STORE_IP();
- acc = Runtime::method_callQmlContextObjectProperty(engine, stack + base, name, stack + argv, argc);
- CHECK_EXCEPTION;
- traceValue(acc, function, traceSlot);
- MOTH_END_INSTR(CallContextObjectProperty)
+ MOTH_END_INSTR(CallQmlContextPropertyLookup)
MOTH_BEGIN_INSTR(CallWithSpread)
STORE_IP();
@@ -1525,14 +1495,6 @@ QV4::ReturnedValue VME::interpret(CppStackFrame *frame, ExecutionEngine *engine,
#endif // QT_CONFIG(qml_debug)
MOTH_END_INSTR(Debug)
- MOTH_BEGIN_INSTR(LoadQmlContext)
- STACK_VALUE(result) = Runtime::method_loadQmlContext(static_cast<QV4::NoThrowEngine*>(engine));
- MOTH_END_INSTR(LoadQmlContext)
-
- MOTH_BEGIN_INSTR(LoadQmlImportedScripts)
- STACK_VALUE(result) = Runtime::method_loadQmlImportedScripts(static_cast<QV4::NoThrowEngine*>(engine));
- MOTH_END_INSTR(LoadQmlImportedScripts)
-
handleUnwind:
Q_ASSERT(engine->hasException || frame->unwindLevel);
if (!frame->unwindHandler) {
diff --git a/src/qml/qml/qqmlbinding.cpp b/src/qml/qml/qqmlbinding.cpp
index a949df4968..b164517011 100644
--- a/src/qml/qml/qqmlbinding.cpp
+++ b/src/qml/qml/qqmlbinding.cpp
@@ -260,8 +260,6 @@ protected:
} else {
clearError();
}
-
- cancelPermanentGuards();
}
ep->dereferenceScarceResources();
@@ -643,24 +641,22 @@ QVector<QQmlProperty> QQmlBinding::dependencies() const
if (!m_target.data())
return dependencies;
- for (const auto &guardList : { permanentGuards, activeGuards }) {
- for (QQmlJavaScriptExpressionGuard *guard = guardList.first(); guard; guard = guardList.next(guard)) {
- if (guard->signalIndex() == -1) // guard's sender is a QQmlNotifier, not a QObject*.
- continue;
+ for (QQmlJavaScriptExpressionGuard *guard = activeGuards.first(); guard; guard = activeGuards.next(guard)) {
+ if (guard->signalIndex() == -1) // guard's sender is a QQmlNotifier, not a QObject*.
+ continue;
- QObject *senderObject = guard->senderAsObject();
- if (!senderObject)
- continue;
+ QObject *senderObject = guard->senderAsObject();
+ if (!senderObject)
+ continue;
- const QMetaObject *senderMeta = senderObject->metaObject();
- if (!senderMeta)
- continue;
+ const QMetaObject *senderMeta = senderObject->metaObject();
+ if (!senderMeta)
+ continue;
- for (int i = 0; i < senderMeta->propertyCount(); i++) {
- QMetaProperty property = senderMeta->property(i);
- if (property.notifySignalIndex() == QMetaObjectPrivate::signal(senderMeta, guard->signalIndex()).methodIndex()) {
- dependencies.push_back(QQmlProperty(senderObject, QString::fromUtf8(senderObject->metaObject()->property(i).name())));
- }
+ for (int i = 0; i < senderMeta->propertyCount(); i++) {
+ QMetaProperty property = senderMeta->property(i);
+ if (property.notifySignalIndex() == QMetaObjectPrivate::signal(senderMeta, guard->signalIndex()).methodIndex()) {
+ dependencies.push_back(QQmlProperty(senderObject, QString::fromUtf8(senderObject->metaObject()->property(i).name())));
}
}
}
@@ -670,7 +666,7 @@ QVector<QQmlProperty> QQmlBinding::dependencies() const
bool QQmlBinding::hasDependencies() const
{
- return !permanentGuards.isEmpty() || !activeGuards.isEmpty() || translationsCaptured();
+ return !activeGuards.isEmpty() || translationsCaptured();
}
class QObjectPointerBinding: public QQmlNonbindingBinding
diff --git a/src/qml/qml/qqmlimport.cpp b/src/qml/qml/qqmlimport.cpp
index e379d416fd..a31dbd1e08 100644
--- a/src/qml/qml/qqmlimport.cpp
+++ b/src/qml/qml/qqmlimport.cpp
@@ -1546,7 +1546,7 @@ bool QQmlImportsPrivate::addFileImport(const QString& uri, const QString &prefix
QString localFileOrQrc = QQmlFile::urlToLocalFileOrQrc(qmldirUrl);
Q_ASSERT(!localFileOrQrc.isEmpty());
- QString dir = QQmlFile::urlToLocalFileOrQrc(resolveLocalUrl(base, importUri));
+ const QString dir = localFileOrQrc.left(localFileOrQrc.lastIndexOf(Slash) + 1);
if (!typeLoader->directoryExists(dir)) {
if (!isImplicitImport) {
QQmlError error;
diff --git a/src/qml/qml/qqmljavascriptexpression.cpp b/src/qml/qml/qqmljavascriptexpression.cpp
index 380163202a..9a3a5218e0 100644
--- a/src/qml/qml/qqmljavascriptexpression.cpp
+++ b/src/qml/qml/qqmljavascriptexpression.cpp
@@ -109,7 +109,6 @@ QQmlJavaScriptExpression::~QQmlJavaScriptExpression()
}
clearActiveGuards();
- clearPermanentGuards();
clearError();
if (m_scopeObject.isT2()) // notify DeleteWatcher of our deletion.
m_scopeObject.asT2()->_s = nullptr;
@@ -118,12 +117,8 @@ QQmlJavaScriptExpression::~QQmlJavaScriptExpression()
void QQmlJavaScriptExpression::setNotifyOnValueChanged(bool v)
{
activeGuards.setFlagValue(v);
- permanentGuards.setFlagValue(v);
- if (!v) {
+ if (!v)
clearActiveGuards();
- clearPermanentGuards();
- m_permanentDependenciesRegistered = false;
- }
}
void QQmlJavaScriptExpression::resetNotifyOnValueChanged()
@@ -216,10 +211,6 @@ QV4::ReturnedValue QQmlJavaScriptExpression::evaluate(QV4::CallData *callData, b
QV4::ReturnedValue res = v4Function->call(&callData->thisObject, callData->args, callData->argc(), static_cast<QV4::ExecutionContext *>(m_qmlScope.valueRef()));
QV4::Scope scope(v4);
QV4::ScopedValue result(scope, res);
- if (v4Function->hasQmlDependencies) {
- QV4::Heap::QmlContext *qc = m_qmlScope.as<QV4::QmlContext>()->d();
- QQmlPropertyCapture::registerQmlDependencies(qc, v4, v4Function->compiledFunction);
- }
if (scope.hasException()) {
if (watcher.wasDeleted())
@@ -254,7 +245,7 @@ QV4::ReturnedValue QQmlJavaScriptExpression::evaluate(QV4::CallData *callData, b
return result->asReturnedValue();
}
-void QQmlPropertyCapture::captureProperty(QQmlNotifier *n, Duration duration)
+void QQmlPropertyCapture::captureProperty(QQmlNotifier *n)
{
if (watcher->wasDeleted())
return;
@@ -274,17 +265,14 @@ void QQmlPropertyCapture::captureProperty(QQmlNotifier *n, Duration duration)
g->connect(n);
}
- if (duration == Permanently)
- expression->permanentGuards.prepend(g);
- else
- expression->activeGuards.prepend(g);
+ expression->activeGuards.prepend(g);
}
/*! \internal
\a n is in the signal index range (see QObjectPrivate::signalIndex()).
*/
-void QQmlPropertyCapture::captureProperty(QObject *o, int c, int n, Duration duration, bool doNotify)
+void QQmlPropertyCapture::captureProperty(QObject *o, int c, int n, bool doNotify)
{
if (watcher->wasDeleted())
return;
@@ -323,61 +311,8 @@ void QQmlPropertyCapture::captureProperty(QObject *o, int c, int n, Duration dur
g->connect(o, n, engine, doNotify);
}
- if (duration == Permanently)
- expression->permanentGuards.prepend(g);
- else
- expression->activeGuards.prepend(g);
- }
-}
-
-void QQmlPropertyCapture::registerQmlDependencies(QV4::Heap::QmlContext *context, const QV4::ExecutionEngine *engine, const QV4::CompiledData::Function *compiledFunction)
-{
- // Let the caller check and avoid the function call :)
- Q_ASSERT(compiledFunction->hasQmlDependencies());
-
- QQmlEnginePrivate *ep = QQmlEnginePrivate::get(engine->qmlEngine());
- if (!ep)
- return;
- QQmlPropertyCapture *capture = ep->propertyCapture;
- if (!capture || capture->watcher->wasDeleted())
- return;
-
- if (capture->expression->m_permanentDependenciesRegistered)
- return;
-
- capture->expression->m_permanentDependenciesRegistered = true;
-
- QV4::Heap::QQmlContextWrapper *wrapper = context->qml();
- QQmlContextData *qmlContext = wrapper->context->contextData();
-
- const quint32_le *idObjectDependency = compiledFunction->qmlIdObjectDependencyTable();
- const int idObjectDependencyCount = compiledFunction->nDependingIdObjects;
- for (int i = 0; i < idObjectDependencyCount; ++i, ++idObjectDependency) {
- Q_ASSERT(int(*idObjectDependency) < qmlContext->idValueCount);
- capture->captureProperty(&qmlContext->idValues[*idObjectDependency].bindings,
- QQmlPropertyCapture::Permanently);
- }
-
- Q_ASSERT(qmlContext->contextObject);
- const quint32_le *contextPropertyDependency = compiledFunction->qmlContextPropertiesDependencyTable();
- const int contextPropertyDependencyCount = compiledFunction->nDependingContextProperties;
- for (int i = 0; i < contextPropertyDependencyCount; ++i) {
- const int propertyIndex = *contextPropertyDependency++;
- const int notifyIndex = *contextPropertyDependency++;
- capture->captureProperty(qmlContext->contextObject, propertyIndex, notifyIndex,
- QQmlPropertyCapture::Permanently);
- }
-
- QObject *scopeObject = wrapper->scopeObject;
- const quint32_le *scopePropertyDependency = compiledFunction->qmlScopePropertiesDependencyTable();
- const int scopePropertyDependencyCount = compiledFunction->nDependingScopeProperties;
- for (int i = 0; i < scopePropertyDependencyCount; ++i) {
- const int propertyIndex = *scopePropertyDependency++;
- const int notifyIndex = *scopePropertyDependency++;
- capture->captureProperty(scopeObject, propertyIndex, notifyIndex,
- QQmlPropertyCapture::Permanently);
+ expression->activeGuards.prepend(g);
}
-
}
QQmlError QQmlJavaScriptExpression::error(QQmlEngine *engine) const
@@ -471,13 +406,6 @@ void QQmlJavaScriptExpression::clearActiveGuards()
g->Delete();
}
-void QQmlJavaScriptExpression::clearPermanentGuards()
-{
- m_permanentDependenciesRegistered = false;
- while (QQmlJavaScriptExpressionGuard *g = permanentGuards.takeFirst())
- g->Delete();
-}
-
void QQmlJavaScriptExpressionGuard_callback(QQmlNotifierEndpoint *e, void **)
{
QQmlJavaScriptExpression *expression =
diff --git a/src/qml/qml/qqmljavascriptexpression_p.h b/src/qml/qml/qqmljavascriptexpression_p.h
index de3fba0774..453c8ab8a8 100644
--- a/src/qml/qml/qqmljavascriptexpression_p.h
+++ b/src/qml/qml/qqmljavascriptexpression_p.h
@@ -144,7 +144,6 @@ public:
QQmlError error(QQmlEngine *) const;
void clearError();
void clearActiveGuards();
- void clearPermanentGuards();
QQmlDelayedError *delayedError();
static QV4::ReturnedValue evalFunction(QQmlContextData *ctxt, QObject *scope,
@@ -153,14 +152,6 @@ public:
protected:
void createQmlBinding(QQmlContextData *ctxt, QObject *scope, const QString &code, const QString &filename, quint16 line);
- void cancelPermanentGuards() const
- {
- if (m_permanentDependenciesRegistered) {
- for (QQmlJavaScriptExpressionGuard *it = permanentGuards.first(); it; it = permanentGuards.next(it))
- it->cancelNotify();
- }
- }
-
void setupFunction(QV4::ExecutionContext *qmlContext, QV4::Function *f);
void setCompilationUnit(const QQmlRefPointer<QV4::CompiledData::CompilationUnit> &compilationUnit);
@@ -169,7 +160,6 @@ protected:
// activeGuards:flag2 - useSharedContext
QBiPointer<QObject, DeleteWatcher> m_scopeObject;
QForwardFieldList<QQmlJavaScriptExpressionGuard, &QQmlJavaScriptExpressionGuard::next> activeGuards;
- QForwardFieldList<QQmlJavaScriptExpressionGuard, &QQmlJavaScriptExpressionGuard::next> permanentGuards;
void setTranslationsCaptured(bool captured) { m_error.setFlagValue(captured); }
bool translationsCaptured() const { return m_error.flag(); }
@@ -186,7 +176,6 @@ private:
QQmlContextData *m_context;
QQmlJavaScriptExpression **m_prevExpression;
QQmlJavaScriptExpression *m_nextExpression;
- bool m_permanentDependenciesRegistered = false;
QV4::PersistentValue m_qmlScope;
QQmlRefPointer<QV4::CompiledData::CompilationUnit> m_compilationUnit;
@@ -204,14 +193,8 @@ public:
Q_ASSERT(errorString == nullptr);
}
- enum Duration {
- OnlyOnce,
- Permanently
- };
-
- static void registerQmlDependencies(QV4::Heap::QmlContext *context, const QV4::ExecutionEngine *engine, const QV4::CompiledData::Function *compiledFunction);
- void captureProperty(QQmlNotifier *, Duration duration = OnlyOnce);
- void captureProperty(QObject *, int, int, Duration duration = OnlyOnce, bool doNotify = true);
+ void captureProperty(QQmlNotifier *);
+ void captureProperty(QObject *, int, int, bool doNotify = true);
void captureTranslation() { translationCaptured = true; }
QQmlEngine *engine;
diff --git a/src/qml/qml/qqmltypewrapper.cpp b/src/qml/qml/qqmltypewrapper.cpp
index 4089a7f030..d30c225741 100644
--- a/src/qml/qml/qqmltypewrapper.cpp
+++ b/src/qml/qml/qqmltypewrapper.cpp
@@ -47,6 +47,8 @@
#include <private/qv4functionobject_p.h>
#include <private/qv4objectproto_p.h>
#include <private/qv4qobjectwrapper_p.h>
+#include <private/qv4identifiertable_p.h>
+#include <private/qv4lookup_p.h>
QT_BEGIN_NAMESPACE
@@ -169,6 +171,7 @@ static ReturnedValue throwLowercaseEnumError(QV4::ExecutionEngine *v4, String *n
ReturnedValue QQmlTypeWrapper::virtualGet(const Managed *m, PropertyKey id, const Value *receiver, bool *hasProperty)
{
+ // Keep this code in sync with ::virtualResolveLookupGetter
Q_ASSERT(m->as<QQmlTypeWrapper>());
if (!id.isString())
@@ -425,6 +428,64 @@ ReturnedValue QQmlTypeWrapper::virtualInstanceOf(const Object *typeObject, const
return QV4::Encode(QQmlMetaObject::canConvert(theirType, myQmlType));
}
+ReturnedValue QQmlTypeWrapper::virtualResolveLookupGetter(const Object *object, ExecutionEngine *engine, Lookup *lookup)
+{
+ // Keep this code in sync with ::virtualGet
+ PropertyKey id = engine->identifierTable->asPropertyKey(engine->currentStackFrame->v4Function->compilationUnit->runtimeStrings[lookup->nameIndex]);
+ if (!id.isString())
+ return Object::virtualResolveLookupGetter(object, engine, lookup);
+ Scope scope(engine);
+
+ const QQmlTypeWrapper *This = static_cast<const QQmlTypeWrapper *>(object);
+ ScopedString name(scope, id.asStringOrSymbol());
+ QQmlContextData *qmlContext = engine->callingQmlContext();
+
+ Scoped<QQmlTypeWrapper> w(scope, static_cast<const QQmlTypeWrapper *>(This));
+ QQmlType type = w->d()->type();
+
+ if (type.isValid()) {
+
+ if (type.isSingleton()) {
+ QQmlEngine *e = engine->qmlEngine();
+ QQmlType::SingletonInstanceInfo *siinfo = type.singletonInstanceInfo();
+ siinfo->init(e);
+
+ QObject *qobjectSingleton = siinfo->qobjectApi(e);
+ if (qobjectSingleton) {
+
+ const bool includeEnums = w->d()->mode == Heap::QQmlTypeWrapper::IncludeEnums;
+ if (!includeEnums || !name->startsWithUpper()) {
+ QQmlData *ddata = QQmlData::get(qobjectSingleton, false);
+ if (ddata && ddata->propertyCache) {
+ ScopedValue val(scope, Value::fromReturnedValue(QV4::QObjectWrapper::wrap(engine, qobjectSingleton)));
+ QQmlPropertyData *property = ddata->propertyCache->property(name.getPointer(), qobjectSingleton, qmlContext);
+ if (property) {
+ lookup->qobjectLookup.ic = This->internalClass();
+ lookup->qobjectLookup.staticQObject = static_cast<Heap::QObjectWrapper *>(val->heapObject());
+ lookup->qobjectLookup.propertyCache = ddata->propertyCache;
+ lookup->qobjectLookup.propertyCache->addref();
+ lookup->qobjectLookup.propertyData = property;
+ lookup->getter = QV4::QObjectWrapper::lookupGetter;
+ return lookup->getter(lookup, engine, *This);
+ }
+ // Fall through to base implementation
+ }
+ // Fall through to base implementation
+ }
+ // Fall through to base implementation
+ }
+ // Fall through to base implementation
+ }
+ // Fall through to base implementation
+ }
+ return QV4::Object::virtualResolveLookupGetter(object, engine, lookup);
+}
+
+bool QQmlTypeWrapper::virtualResolveLookupSetter(Object *object, ExecutionEngine *engine, Lookup *lookup, const Value &value)
+{
+ return Object::virtualResolveLookupSetter(object, engine, lookup, value);
+}
+
void Heap::QQmlScopedEnumWrapper::destroy()
{
QQmlType::derefHandle(typePrivate);
diff --git a/src/qml/qml/qqmltypewrapper_p.h b/src/qml/qml/qqmltypewrapper_p.h
index fa1ad56902..44e82dec2b 100644
--- a/src/qml/qml/qqmltypewrapper_p.h
+++ b/src/qml/qml/qqmltypewrapper_p.h
@@ -111,6 +111,9 @@ struct Q_QML_EXPORT QQmlTypeWrapper : Object
static ReturnedValue create(ExecutionEngine *, QObject *, const QQmlRefPointer<QQmlTypeNameCache> &, const QQmlImportRef *,
Heap::QQmlTypeWrapper::TypeNameMode = Heap::QQmlTypeWrapper::IncludeEnums);
+ static ReturnedValue virtualResolveLookupGetter(const Object *object, ExecutionEngine *engine, Lookup *lookup);
+ static bool virtualResolveLookupSetter(Object *object, ExecutionEngine *engine, Lookup *lookup, const Value &value);
+
protected:
static ReturnedValue virtualGet(const Managed *m, PropertyKey id, const Value *receiver, bool *hasProperty);
static bool virtualPut(Managed *m, PropertyKey id, const Value &value, Value *receiver);
diff --git a/src/qml/qml/qqmlvaluetypewrapper.cpp b/src/qml/qml/qqmlvaluetypewrapper.cpp
index 9ce1c82f09..7df5757b95 100644
--- a/src/qml/qml/qqmlvaluetypewrapper.cpp
+++ b/src/qml/qml/qqmlvaluetypewrapper.cpp
@@ -51,6 +51,8 @@
#include <private/qv4stackframe_p.h>
#include <private/qv4objectiterator_p.h>
#include <private/qv4qobjectwrapper_p.h>
+#include <private/qv4identifiertable_p.h>
+#include <private/qv4lookup_p.h>
#include <QtCore/qloggingcategory.h>
QT_BEGIN_NAMESPACE
@@ -372,6 +374,117 @@ ReturnedValue QQmlValueTypeWrapper::method_toString(const FunctionObject *b, con
return Encode(b->engine()->newString(result));
}
+Q_ALWAYS_INLINE static ReturnedValue getGadgetProperty(ExecutionEngine *engine,
+ Heap::QQmlValueTypeWrapper *valueTypeWrapper,
+ QQmlPropertyData *property)
+{
+ if (property->isFunction()) {
+ // calling a Q_INVOKABLE function of a value type
+ return QV4::QObjectMethod::create(engine->rootContext(), valueTypeWrapper, property->coreIndex());
+ }
+
+#define VALUE_TYPE_LOAD(metatype, cpptype, constructor) \
+ if (property->propType() == metatype) { \
+ cpptype v; \
+ void *args[] = { &v, nullptr }; \
+ metaObject->d.static_metacall(reinterpret_cast<QObject*>(valueTypeWrapper->gadgetPtr), \
+ QMetaObject::ReadProperty, index, args); \
+ return QV4::Encode(constructor(v)); \
+ }
+
+ const QMetaObject *metaObject = valueTypeWrapper->propertyCache()->metaObject();
+
+ int index = property->coreIndex();
+ QQmlMetaObject::resolveGadgetMethodOrPropertyIndex(QMetaObject::ReadProperty, &metaObject, &index);
+
+ // These four types are the most common used by the value type wrappers
+ VALUE_TYPE_LOAD(QMetaType::QReal, qreal, qreal);
+ VALUE_TYPE_LOAD(QMetaType::Int || property->isEnum(), int, int);
+ VALUE_TYPE_LOAD(QMetaType::Int, int, int);
+ VALUE_TYPE_LOAD(QMetaType::QString, QString, engine->newString);
+ VALUE_TYPE_LOAD(QMetaType::Bool, bool, bool);
+
+ QVariant v;
+ void *args[] = { nullptr, nullptr };
+ if (property->propType() == QMetaType::QVariant) {
+ args[0] = &v;
+ } else {
+ v = QVariant(property->propType(), static_cast<void *>(nullptr));
+ args[0] = v.data();
+ }
+ metaObject->d.static_metacall(reinterpret_cast<QObject*>(valueTypeWrapper->gadgetPtr), QMetaObject::ReadProperty,
+ index, args);
+ return engine->fromVariant(v);
+#undef VALUE_TYPE_LOAD
+}
+
+ReturnedValue QQmlValueTypeWrapper::virtualResolveLookupGetter(const Object *object, ExecutionEngine *engine,
+ Lookup *lookup)
+{
+ PropertyKey id = engine->identifierTable->asPropertyKey(engine->currentStackFrame->v4Function->compilationUnit->
+ runtimeStrings[lookup->nameIndex]);
+ if (!id.isString())
+ return Object::virtualResolveLookupGetter(object, engine, lookup);
+
+ const QQmlValueTypeWrapper *r = static_cast<const QQmlValueTypeWrapper *>(object);
+ QV4::ExecutionEngine *v4 = r->engine();
+ Scope scope(v4);
+ ScopedString name(scope, id.asStringOrSymbol());
+
+ // Note: readReferenceValue() can change the reference->type.
+ if (const QQmlValueTypeReference *reference = r->as<QQmlValueTypeReference>()) {
+ if (!reference->readReferenceValue())
+ return Value::undefinedValue().asReturnedValue();
+ }
+
+ QQmlPropertyData *result = r->d()->propertyCache()->property(name.getPointer(), nullptr, nullptr);
+ if (!result)
+ return QV4::Object::virtualResolveLookupGetter(object, engine, lookup);
+
+ lookup->qgadgetLookup.ic = r->internalClass();
+ lookup->qgadgetLookup.propertyCache = r->d()->propertyCache();
+ lookup->qgadgetLookup.propertyCache->addref();
+ lookup->qgadgetLookup.propertyData = result;
+ lookup->getter = QQmlValueTypeWrapper::lookupGetter;
+ return lookup->getter(lookup, engine, *object);
+}
+
+ReturnedValue QQmlValueTypeWrapper::lookupGetter(Lookup *lookup, ExecutionEngine *engine, const Value &object)
+{
+ const auto revertLookup = [lookup, engine, &object]() {
+ lookup->qgadgetLookup.propertyCache->release();
+ lookup->qgadgetLookup.propertyCache = nullptr;
+ lookup->getter = Lookup::getterGeneric;
+ return Lookup::getterGeneric(lookup, engine, object);
+ };
+
+ // we can safely cast to a QV4::Object here. If object is something else,
+ // the internal class won't match
+ Heap::Object *o = static_cast<Heap::Object *>(object.heapObject());
+ if (!o || o->internalClass != lookup->qgadgetLookup.ic)
+ return revertLookup();
+
+ Heap::QQmlValueTypeWrapper *valueTypeWrapper =
+ const_cast<Heap::QQmlValueTypeWrapper*>(static_cast<const Heap::QQmlValueTypeWrapper *>(o));
+ if (valueTypeWrapper->propertyCache() != lookup->qgadgetLookup.propertyCache)
+ return revertLookup();
+
+ if (lookup->qgadgetLookup.ic->vtable == QQmlValueTypeReference::staticVTable()) {
+ Scope scope(engine);
+ Scoped<QQmlValueTypeReference> referenceWrapper(scope, valueTypeWrapper);
+ referenceWrapper->readReferenceValue();
+ }
+
+ QQmlPropertyData *property = lookup->qgadgetLookup.propertyData;
+ return getGadgetProperty(engine, valueTypeWrapper, property);
+}
+
+bool QQmlValueTypeWrapper::virtualResolveLookupSetter(Object *object, ExecutionEngine *engine, Lookup *lookup,
+ const Value &value)
+{
+ return Object::virtualResolveLookupSetter(object, engine, lookup, value);
+}
+
ReturnedValue QQmlValueTypeWrapper::virtualGet(const Managed *m, PropertyKey id, const Value *receiver, bool *hasProperty)
{
Q_ASSERT(m->as<QQmlValueTypeWrapper>());
@@ -397,43 +510,7 @@ ReturnedValue QQmlValueTypeWrapper::virtualGet(const Managed *m, PropertyKey id,
if (hasProperty)
*hasProperty = true;
- if (result->isFunction())
- // calling a Q_INVOKABLE function of a value type
- return QV4::QObjectMethod::create(v4->rootContext(), r, result->coreIndex());
-
-#define VALUE_TYPE_LOAD(metatype, cpptype, constructor) \
- if (result->propType() == metatype) { \
- cpptype v; \
- void *args[] = { &v, 0 }; \
- metaObject->d.static_metacall(reinterpret_cast<QObject*>(gadget), QMetaObject::ReadProperty, index, args); \
- return QV4::Encode(constructor(v)); \
- }
-
- const QMetaObject *metaObject = r->d()->propertyCache()->metaObject();
-
- int index = result->coreIndex();
- QQmlMetaObject::resolveGadgetMethodOrPropertyIndex(QMetaObject::ReadProperty, &metaObject, &index);
-
- void *gadget = r->d()->gadgetPtr;
-
- // These four types are the most common used by the value type wrappers
- VALUE_TYPE_LOAD(QMetaType::QReal, qreal, qreal);
- VALUE_TYPE_LOAD(QMetaType::Int || result->isEnum(), int, int);
- VALUE_TYPE_LOAD(QMetaType::Int, int, int);
- VALUE_TYPE_LOAD(QMetaType::QString, QString, v4->newString);
- VALUE_TYPE_LOAD(QMetaType::Bool, bool, bool);
-
- QVariant v;
- void *args[] = { nullptr, nullptr };
- if (result->propType() == QMetaType::QVariant) {
- args[0] = &v;
- } else {
- v = QVariant(result->propType(), static_cast<void *>(nullptr));
- args[0] = v.data();
- }
- metaObject->d.static_metacall(reinterpret_cast<QObject*>(gadget), QMetaObject::ReadProperty, index, args);
- return v4->fromVariant(v);
-#undef VALUE_TYPE_ACCESSOR
+ return getGadgetProperty(v4, r->d(), result);
}
bool QQmlValueTypeWrapper::virtualPut(Managed *m, PropertyKey id, const Value &value, Value *receiver)
diff --git a/src/qml/qml/qqmlvaluetypewrapper_p.h b/src/qml/qml/qqmlvaluetypewrapper_p.h
index 8db9474132..baac129afa 100644
--- a/src/qml/qml/qqmlvaluetypewrapper_p.h
+++ b/src/qml/qml/qqmlvaluetypewrapper_p.h
@@ -112,6 +112,9 @@ public:
static PropertyAttributes virtualGetOwnProperty(const Managed *m, PropertyKey id, Property *p);
static OwnPropertyKeyIterator *virtualOwnPropertyKeys(const Object *m, Value *target);
static ReturnedValue method_toString(const FunctionObject *b, const Value *thisObject, const Value *argv, int argc);
+ static ReturnedValue virtualResolveLookupGetter(const Object *object, ExecutionEngine *engine, Lookup *lookup);
+ static bool virtualResolveLookupSetter(Object *object, ExecutionEngine *engine, Lookup *lookup, const Value &value);
+ static ReturnedValue lookupGetter(Lookup *lookup, ExecutionEngine *engine, const Value &object);
static void initProto(ExecutionEngine *v4);
};
diff --git a/src/qml/types/qqmllistmodel.cpp b/src/qml/types/qqmllistmodel.cpp
index 27171b9bd4..565e60b3c1 100644
--- a/src/qml/types/qqmllistmodel.cpp
+++ b/src/qml/types/qqmllistmodel.cpp
@@ -52,6 +52,7 @@
#include <private/qv4dateobject_p.h>
#include <private/qv4objectiterator_p.h>
#include <private/qv4alloca_p.h>
+#include <private/qv4lookup_p.h>
#include <qqmlcontext.h>
#include <qqmlinfo.h>
@@ -1604,8 +1605,7 @@ ReturnedValue ModelObject::virtualGet(const Managed *m, PropertyKey id, const Va
if (QQmlEngine *qmlEngine = that->engine()->qmlEngine()) {
QQmlEnginePrivate *ep = QQmlEnginePrivate::get(qmlEngine);
if (ep && ep->propertyCapture)
- ep->propertyCapture->captureProperty(that->object(), -1, role->index,
- QQmlPropertyCapture::OnlyOnce, false);
+ ep->propertyCapture->captureProperty(that->object(), -1, role->index, /*doNotify=*/ false);
}
const int elementIndex = that->d()->elementIndex();
@@ -1613,6 +1613,12 @@ ReturnedValue ModelObject::virtualGet(const Managed *m, PropertyKey id, const Va
return that->engine()->fromVariant(value);
}
+ReturnedValue ModelObject::virtualResolveLookupGetter(const Object *object, ExecutionEngine *engine, Lookup *lookup)
+{
+ lookup->getter = Lookup::getterFallback;
+ return lookup->getter(lookup, engine, *object);
+}
+
struct ModelObjectOwnPropertyKeyIterator : ObjectOwnPropertyKeyIterator
{
int roleNameIndex = 0;
diff --git a/src/qml/types/qqmllistmodel_p_p.h b/src/qml/types/qqmllistmodel_p_p.h
index ff52ee049f..2876c71de6 100644
--- a/src/qml/types/qqmllistmodel_p_p.h
+++ b/src/qml/types/qqmllistmodel_p_p.h
@@ -181,6 +181,8 @@ struct ModelObject : public QObjectWrapper
protected:
static bool virtualPut(Managed *m, PropertyKey id, const Value& value, Value *receiver);
static ReturnedValue virtualGet(const Managed *m, PropertyKey id, const Value *receiver, bool *hasProperty);
+ static ReturnedValue virtualResolveLookupGetter(const Object *object, ExecutionEngine *engine, Lookup *lookup);
+ static ReturnedValue lookupGetter(Lookup *l, ExecutionEngine *engine, const Value &object);
static OwnPropertyKeyIterator *virtualOwnPropertyKeys(const Object *m, Value *target);
};
diff --git a/tests/auto/qml/debugger/qqmlpreview/tst_qqmlpreview.cpp b/tests/auto/qml/debugger/qqmlpreview/tst_qqmlpreview.cpp
index 4c4c514832..f713aa76c3 100644
--- a/tests/auto/qml/debugger/qqmlpreview/tst_qqmlpreview.cpp
+++ b/tests/auto/qml/debugger/qqmlpreview/tst_qqmlpreview.cpp
@@ -338,7 +338,7 @@ void tst_QQmlPreview::fps()
QVERIFY(m_client);
m_client->triggerLoad(testFileUrl(file));
if (QGuiApplication::platformName() != "offscreen") {
- QTRY_VERIFY(m_frameStats.numSyncs > 10);
+ QTRY_VERIFY_WITH_TIMEOUT(m_frameStats.numSyncs > 10, 10000);
QVERIFY(m_frameStats.minSync <= m_frameStats.maxSync);
QVERIFY(m_frameStats.totalSync / m_frameStats.numSyncs >= m_frameStats.minSync - 1);
QVERIFY(m_frameStats.totalSync / m_frameStats.numSyncs <= m_frameStats.maxSync);
diff --git a/tests/auto/qml/qqmlecmascript/data/signalHandlers.qml b/tests/auto/qml/qqmlecmascript/data/signalHandlers.qml
index 14326bb9e6..a924519f0f 100644
--- a/tests/auto/qml/qqmlecmascript/data/signalHandlers.qml
+++ b/tests/auto/qml/qqmlecmascript/data/signalHandlers.qml
@@ -8,6 +8,8 @@ QtObject {
signal testSignal
onTestSignal: count++
+ readonly property string scopeObjectAsString: this.toString()
+
property int funcCount: 0
function testFunction() {
funcCount++;
diff --git a/tests/auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp b/tests/auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp
index e6603a1a19..3cd70a0d1b 100644
--- a/tests/auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp
+++ b/tests/auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp
@@ -365,6 +365,7 @@ private slots:
void numberToStringWithRadix();
void tailCallWithArguments();
void deleteSparseInIteration();
+ void saveAccumulatorBeforeToInt32();
private:
// static void propertyVarWeakRefCallback(v8::Persistent<v8::Value> object, void* parameter);
@@ -1608,7 +1609,7 @@ void tst_qqmlecmascript::aliasPropertyReset()
// test that a manual write (of undefined) to a non-resettable property fails properly
QUrl url = testFileUrl("aliasreset/aliasPropertyReset.error.1.qml");
- QString warning1 = url.toString() + QLatin1String(": Error: Cannot assign [undefined] to int");
+ QString warning1 = url.toString() + QLatin1String(":15: Error: Cannot assign [undefined] to int");
QQmlComponent e1(&engine, url);
object = e1.create();
QVERIFY(object != nullptr);
@@ -6474,7 +6475,8 @@ void tst_qqmlecmascript::signalHandlers()
QMetaObject::invokeMethod(o.data(), "testSignalHandlerCall");
QCOMPARE(o->property("count").toInt(), 1);
- QCOMPARE(o->property("errorString").toString(), QLatin1String("TypeError: Property 'onTestSignal' of object [object Object] is not a function"));
+ QString scopeObjectAsString = o->property("scopeObjectAsString").toString();
+ QCOMPARE(o->property("errorString").toString(), QString("TypeError: Property 'onTestSignal' of object %1 is not a function").arg(scopeObjectAsString));
QCOMPARE(o->property("funcCount").toInt(), 0);
QMetaObject::invokeMethod(o.data(), "testSignalConnection");
@@ -8169,12 +8171,11 @@ void tst_qqmlecmascript::stackLimits()
void tst_qqmlecmascript::idsAsLValues()
{
QQmlEngine engine;
- QString err = QString(QLatin1String("%1:5 left-hand side of assignment operator is not an lvalue\n")).arg(testFileUrl("idAsLValue.qml").toString());
+ QString err = QString(QLatin1String("%1:5: Error: left-hand side of assignment operator is not an lvalue")).arg(testFileUrl("idAsLValue.qml").toString());
QQmlComponent component(&engine, testFileUrl("idAsLValue.qml"));
- QTest::ignoreMessage(QtWarningMsg, "QQmlComponent: Component is not ready");
+ QTest::ignoreMessage(QtWarningMsg, qPrintable(err));
MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create());
QVERIFY(!object);
- QCOMPARE(component.errorString(), err);
}
void tst_qqmlecmascript::qtbug_34792()
@@ -8936,6 +8937,17 @@ void tst_qqmlecmascript::deleteSparseInIteration()
QCOMPARE(value.property("2").toInt(), 4096);
}
+void tst_qqmlecmascript::saveAccumulatorBeforeToInt32()
+{
+ QJSEngine engine;
+
+ // Infinite recursion produces a range error, but should not crash.
+ // Also, any GC runs in between should not trash the temporary results of "a+a".
+ const QJSValue value = engine.evaluate("function a(){a(a&a+a)}a()");
+ QVERIFY(value.isError());
+ QCOMPARE(value.toString(), QLatin1String("RangeError: Maximum call stack size exceeded."));
+}
+
QTEST_MAIN(tst_qqmlecmascript)
#include "tst_qqmlecmascript.moc"
diff --git a/tests/auto/qml/qqmlimport/data/interceptQmldir.qml b/tests/auto/qml/qqmlimport/data/interceptQmldir.qml
new file mode 100644
index 0000000000..bf485b2282
--- /dev/null
+++ b/tests/auto/qml/qqmlimport/data/interceptQmldir.qml
@@ -0,0 +1,7 @@
+import QtQml 2.2
+
+import "$(INTERCEPT)" as Intercepted
+
+QtObject {
+ property QtObject view: Intercepted.View {}
+}
diff --git a/tests/auto/qml/qqmlimport/data/intercepted/View.qml b/tests/auto/qml/qqmlimport/data/intercepted/View.qml
new file mode 100644
index 0000000000..92aa3af95a
--- /dev/null
+++ b/tests/auto/qml/qqmlimport/data/intercepted/View.qml
@@ -0,0 +1,5 @@
+import QtQml 2.2
+
+QtObject {
+ property int foo: 12
+}
diff --git a/tests/auto/qml/qqmlimport/data/intercepted/qmldir b/tests/auto/qml/qqmlimport/data/intercepted/qmldir
new file mode 100644
index 0000000000..ab31de73d8
--- /dev/null
+++ b/tests/auto/qml/qqmlimport/data/intercepted/qmldir
@@ -0,0 +1,2 @@
+module SomeModule
+View 1.0 View.qml
diff --git a/tests/auto/qml/qqmlimport/tst_qqmlimport.cpp b/tests/auto/qml/qqmlimport/tst_qqmlimport.cpp
index 70aaa9678e..a3cb68fdcb 100644
--- a/tests/auto/qml/qqmlimport/tst_qqmlimport.cpp
+++ b/tests/auto/qml/qqmlimport/tst_qqmlimport.cpp
@@ -28,6 +28,7 @@
#include <QtTest/QtTest>
#include <QQmlApplicationEngine>
+#include <QQmlAbstractUrlInterceptor>
#include <QtQuick/qquickview.h>
#include <QtQuick/qquickitem.h>
#include <private/qqmlimport_p.h>
@@ -43,6 +44,7 @@ private slots:
void uiFormatLoading();
void completeQmldirPaths_data();
void completeQmldirPaths();
+ void interceptQmldir();
void cleanup();
};
@@ -185,6 +187,32 @@ void tst_QQmlImport::completeQmldirPaths()
QCOMPARE(QQmlImports::completeQmldirPaths(uri, basePaths, majorVersion, minorVersion), expectedPaths);
}
+class QmldirUrlInterceptor : public QQmlAbstractUrlInterceptor {
+public:
+ QUrl intercept(const QUrl &url, DataType type) override
+ {
+ if (type != UrlString && !url.isEmpty() && url.isValid()) {
+ QString str = url.toString(QUrl::None);
+ return str.replace(QStringLiteral("$(INTERCEPT)"), QStringLiteral("intercepted"));
+ }
+ return url;
+ }
+};
+
+void tst_QQmlImport::interceptQmldir()
+{
+ QQmlEngine engine;
+ QmldirUrlInterceptor interceptor;
+ engine.setUrlInterceptor(&interceptor);
+
+ QQmlComponent component(&engine);
+ component.loadUrl(testFileUrl("interceptQmldir.qml"));
+ QVERIFY(component.isReady());
+ QScopedPointer<QObject> obj(component.create());
+ QVERIFY(!obj.isNull());
+}
+
+
QTEST_MAIN(tst_QQmlImport)
#include "tst_qqmlimport.moc"
diff --git a/tests/auto/qml/qqmllanguage/data/EdgeObject.qml b/tests/auto/qml/qqmllanguage/data/EdgeObject.qml
new file mode 100644
index 0000000000..b25dc29c49
--- /dev/null
+++ b/tests/auto/qml/qqmllanguage/data/EdgeObject.qml
@@ -0,0 +1,20 @@
+import QtQuick 2.0
+
+Item {
+ property int edgeWidth: bg.width
+
+ Rectangle {
+ id: bg
+ }
+
+ states: [
+ State {
+ when: 1 === 1
+ PropertyChanges {
+ target: bg
+ anchors.left: parent.left
+ anchors.right: parent.right
+ }
+ }
+ ]
+}
diff --git a/tests/auto/qml/qqmllanguage/data/anchorsToParentInPropertyChagnes.qml b/tests/auto/qml/qqmllanguage/data/anchorsToParentInPropertyChagnes.qml
new file mode 100644
index 0000000000..8b1682da92
--- /dev/null
+++ b/tests/auto/qml/qqmllanguage/data/anchorsToParentInPropertyChagnes.qml
@@ -0,0 +1,10 @@
+import QtQuick 2.9
+
+Item {
+ width: 200
+ property int edgeWidth: edge.edgeWidth
+ EdgeObject {
+ id: edge
+ anchors.fill: parent
+ }
+}
diff --git a/tests/auto/qml/qqmllanguage/data/thisInQmlScope.qml b/tests/auto/qml/qqmllanguage/data/thisInQmlScope.qml
index e3c99e70e1..9ff758c33f 100644
--- a/tests/auto/qml/qqmllanguage/data/thisInQmlScope.qml
+++ b/tests/auto/qml/qqmllanguage/data/thisInQmlScope.qml
@@ -6,5 +6,18 @@ QtObject {
y = this.x;
}
property var f: g
+
Component.onCompleted: f()
+
+ property int a: 42
+ property int b: 0
+ function g_subobj(){
+ b = this.a;
+ }
+ property var f_subobj: g_subobj
+
+ property QtObject subObject: QtObject {
+ property int a: 100
+ Component.onCompleted: f_subobj()
+ }
}
diff --git a/tests/auto/qml/qqmllanguage/tst_qqmllanguage.cpp b/tests/auto/qml/qqmllanguage/tst_qqmllanguage.cpp
index 764a67a295..22ea3a89c3 100644
--- a/tests/auto/qml/qqmllanguage/tst_qqmllanguage.cpp
+++ b/tests/auto/qml/qqmllanguage/tst_qqmllanguage.cpp
@@ -299,6 +299,7 @@ private slots:
void retrieveQmlTypeId();
void polymorphicFunctionLookup();
+ void anchorsToParentInPropertyChanges();
private:
QQmlEngine engine;
@@ -5022,6 +5023,8 @@ void tst_qqmllanguage::thisInQmlScope()
QVERIFY(!o.isNull());
QCOMPARE(o->property("x"), QVariant(42));
QCOMPARE(o->property("y"), QVariant(42));
+ QCOMPARE(o->property("a"), QVariant(42));
+ QCOMPARE(o->property("b"), QVariant(42));
}
void tst_qqmllanguage::valueTypeGroupPropertiesInBehavior()
@@ -5069,6 +5072,16 @@ void tst_qqmllanguage::polymorphicFunctionLookup()
QVERIFY(o->property("ok").toBool());
}
+void tst_qqmllanguage::anchorsToParentInPropertyChanges()
+{
+ QQmlEngine engine;
+ QQmlComponent component(&engine, testFileUrl("anchorsToParentInPropertyChagnes.qml"));
+ VERIFY_ERRORS(0);
+ QScopedPointer<QObject> o(component.create());
+ QVERIFY(!o.isNull());
+ QTRY_COMPARE(o->property("edgeWidth").toInt(), 200);
+}
+
QTEST_MAIN(tst_qqmllanguage)
#include "tst_qqmllanguage.moc"
diff --git a/tests/auto/qml/qqmlnotifier/tst_qqmlnotifier.cpp b/tests/auto/qml/qqmlnotifier/tst_qqmlnotifier.cpp
index 6e831eacc1..a5332c8860 100644
--- a/tests/auto/qml/qqmlnotifier/tst_qqmlnotifier.cpp
+++ b/tests/auto/qml/qqmlnotifier/tst_qqmlnotifier.cpp
@@ -349,7 +349,7 @@ void tst_qqmlnotifier::deleteFromHandler()
QQmlEngine engine;
QQmlComponent component(&engine, testFileUrl("objectRenamer.qml"));
QPointer<QObject> mess = component.create();
- QObject::connect(mess, &QObject::objectNameChanged, [&]() { delete mess; });
+ QObject::connect(mess.data(), &QObject::objectNameChanged, [&]() { delete mess; });
QTRY_VERIFY(mess.isNull()); // BANG!
} else {
QProcess process;
diff --git a/tests/auto/qml/qv4mm/tst_qv4mm.cpp b/tests/auto/qml/qv4mm/tst_qv4mm.cpp
index 578a47d5fa..b57b716ed6 100644
--- a/tests/auto/qml/qv4mm/tst_qv4mm.cpp
+++ b/tests/auto/qml/qv4mm/tst_qv4mm.cpp
@@ -33,6 +33,7 @@
#include <private/qv4mm_p.h>
#include <private/qv4qobjectwrapper_p.h>
+#include <private/qjsvalue_p.h>
#include "../../shared/util.h"
@@ -46,6 +47,7 @@ private slots:
void gcStats();
void multiWrappedQObjects();
void accessParentOnDestruction();
+ void clearICParent();
};
void tst_qv4mm::gcStats()
@@ -108,6 +110,30 @@ void tst_qv4mm::accessParentOnDestruction()
QCOMPARE(obj->property("destructions").toInt(), 100);
}
+void tst_qv4mm::clearICParent()
+{
+ QJSEngine engine;
+ QJSValue value = engine.evaluate(
+ "(function() {\n"
+ " var test = Object.create(null);\n"
+ " for (var i = 0; i < 100; i++)\n"
+ " test[(\"key_\"+i)] = true;\n"
+ " for (var i = 0; i < 100; i++)\n"
+ " delete test[\"key_\" + i];\n"
+ " return test;\n"
+ "})();"
+ );
+ engine.collectGarbage();
+ QV4::Value *v4Value = QJSValuePrivate::getValue(&value);
+ QVERIFY(v4Value);
+ QV4::Heap::Object *v4Object = v4Value->toObject(engine.handle());
+ QVERIFY(v4Object);
+
+ // It should garbage collect the parents of the internalClass,
+ // as those aren't used anywhere else.
+ QCOMPARE(v4Object->internalClass->parent, nullptr);
+}
+
QTEST_MAIN(tst_qv4mm)
#include "tst_qv4mm.moc"
diff --git a/tests/auto/qmltest/animatedimage/BLACKLIST b/tests/auto/qmltest/animatedimage/BLACKLIST
new file mode 100644
index 0000000000..3a5ed393ea
--- /dev/null
+++ b/tests/auto/qmltest/animatedimage/BLACKLIST
@@ -0,0 +1,2 @@
+[AnimatedImage::test_crashRaceCondition_replyFinished]
+osx-10.13
diff --git a/tests/auto/quick/qquickgridview/tst_qquickgridview.cpp b/tests/auto/quick/qquickgridview/tst_qquickgridview.cpp
index 3b704d7fa4..448096720c 100644
--- a/tests/auto/quick/qquickgridview/tst_qquickgridview.cpp
+++ b/tests/auto/quick/qquickgridview/tst_qquickgridview.cpp
@@ -6637,7 +6637,7 @@ void tst_QQuickGridView::contentHeightWithDelayRemove()
QCOMPARE(qRound(gridview->contentHeight()), qRound(initialContentHeight));
QTRY_COMPARE(qRound(gridview->contentHeight()), eventualContentHeight);
} else {
- QCOMPARE(qRound(gridview->contentHeight()), eventualContentHeight);
+ QTRY_COMPARE(qRound(gridview->contentHeight()), eventualContentHeight);
}
delete window;
diff --git a/tests/auto/quick/qquicklistview/BLACKLIST b/tests/auto/quick/qquicklistview/BLACKLIST
index e22d52294f..ecdf8f558e 100644
--- a/tests/auto/quick/qquicklistview/BLACKLIST
+++ b/tests/auto/quick/qquicklistview/BLACKLIST
@@ -1,5 +1,7 @@
[enforceRange_withoutHighlight]
osx
+opensuse-42.3
+opensuse-leap
#QTBUG-53863
[populateTransitions]
opensuse-42.1
diff --git a/tests/auto/quick/touchmouse/BLACKLIST b/tests/auto/quick/touchmouse/BLACKLIST
index b2ba52eca9..0dfe28087a 100644
--- a/tests/auto/quick/touchmouse/BLACKLIST
+++ b/tests/auto/quick/touchmouse/BLACKLIST
@@ -1,2 +1,6 @@
[buttonOnDelayedPressFlickable]
windows gcc developer-build
+
+# QTBUG-74517
+[buttonOnFlickable]
+windows gcc developer-build
diff --git a/tools/qmlcachegen/qmlcachegen.cpp b/tools/qmlcachegen/qmlcachegen.cpp
index cf32eb1aaa..f6f1d99526 100644
--- a/tools/qmlcachegen/qmlcachegen.cpp
+++ b/tools/qmlcachegen/qmlcachegen.cpp
@@ -203,16 +203,14 @@ static bool compileQmlFile(const QString &inputFileName, SaveFunction saveFuncti
QmlIR::JSCodeGen v4CodeGen(irDocument.code,
&irDocument.jsGenerator, &irDocument.jsModule,
&irDocument.jsParserEngine, irDocument.program,
- /*import cache*/nullptr, &irDocument.jsGenerator.stringTable, illegalNames);
+ &irDocument.jsGenerator.stringTable, illegalNames);
v4CodeGen.setUseFastLookups(false); // Disable lookups in non-standalone (aka QML) mode
for (QmlIR::Object *object: qAsConst(irDocument.objects)) {
if (object->functionsAndExpressions->count == 0)
continue;
QList<QmlIR::CompiledFunctionOrExpression> functionsToCompile;
- for (QmlIR::CompiledFunctionOrExpression *foe = object->functionsAndExpressions->first; foe; foe = foe->next) {
- foe->disableAcceleratedLookups = true;
+ for (QmlIR::CompiledFunctionOrExpression *foe = object->functionsAndExpressions->first; foe; foe = foe->next)
functionsToCompile << *foe;
- }
const QVector<int> runtimeFunctionIndices = v4CodeGen.generateJSCodeForFunctionsAndBindings(functionsToCompile);
QList<QQmlJS::DiagnosticMessage> jsErrors = v4CodeGen.errors();
if (!jsErrors.isEmpty()) {
@@ -310,8 +308,7 @@ static bool compileJSFile(const QString &inputFileName, const QString &inputFile
{
QmlIR::JSCodeGen v4CodeGen(irDocument.code, &irDocument.jsGenerator,
&irDocument.jsModule, &irDocument.jsParserEngine,
- irDocument.program, /*import cache*/nullptr,
- &irDocument.jsGenerator.stringTable, illegalNames);
+ irDocument.program, &irDocument.jsGenerator.stringTable, illegalNames);
v4CodeGen.setUseFastLookups(false); // Disable lookups in non-standalone (aka QML) mode
v4CodeGen.generateFromProgram(inputFileName, inputFileUrl, sourceCode, program,
&irDocument.jsModule, QV4::Compiler::ContextType::ScriptImportedByQML);