Merge remote-tracking branch 'origin/5.13' into HEAD
Conflicts: src/qml/compiler/qv4compileddata_p.h src/qml/jit/qv4baselinejit.cpp src/qml/jit/qv4jithelpers.cpp src/qml/jsruntime/qv4lookup.cpp src/qml/jsruntime/qv4runtime.cpp src/qml/jsruntime/qv4runtimeapi_p.h src/qml/jsruntime/qv4vme_moth.cpp src/qml/qml/qqmltypemodule_p.h Change-Id: If28793e9e08418457a11fc2c5832f03cab2fcc76
This commit is contained in:
commit
a768780f36
|
@ -0,0 +1,101 @@
|
|||
Qt 5.12.2 is a bug-fix release. It maintains both forward and backward
|
||||
compatibility (source and binary) with Qt 5.12.0 through 5.12.1.
|
||||
|
||||
For more details, refer to the online documentation included in this
|
||||
distribution. The documentation is also available online:
|
||||
|
||||
https://doc.qt.io/qt-5/index.html
|
||||
|
||||
The Qt version 5.12 series is binary compatible with the 5.11.x series.
|
||||
Applications compiled for 5.11 will continue to run with 5.12.
|
||||
|
||||
Some of the changes listed in this file include issue tracking numbers
|
||||
corresponding to tasks in the Qt Bug Tracker:
|
||||
|
||||
https://bugreports.qt.io/
|
||||
|
||||
Each of these identifiers can be entered in the bug tracker to obtain more
|
||||
information about a particular change.
|
||||
|
||||
****************************************************************************
|
||||
* QtQml *
|
||||
****************************************************************************
|
||||
|
||||
- Important Behavior Changes:
|
||||
* The parameters passed to C++ functions from QML are now checked for
|
||||
compatibility with the expected arguments. If they cannot be
|
||||
converted, a warning is printed. In future versions of Qt a type error
|
||||
will be thrown in JavaScript and the function will not be invoked.
|
||||
|
||||
* [QTBUG-73239] Removed revisions from the new Qt.labs.settings methods
|
||||
and properties that were introduced in 5.12. Qt.labs plugins are
|
||||
intended to always have revision 1.0 until they graduate.
|
||||
|
||||
- QQmlApplicationEngine:
|
||||
* [QTBUG-73649] QQmlApplicationEngine connects quit() and exit() signals
|
||||
with queued connections to avoid problems with AutoConnection, when
|
||||
connecting to QCoreApplication slots.
|
||||
|
||||
- [QTBUG-69340] QML cache files are not unnecessarily re-generated.
|
||||
- [QTBUG-71325] Fixed a crash in V4 string to number conversion on 32-bit
|
||||
platforms.
|
||||
- [QTBUG-72137] Fixed a crash in QML garbage collector when accessing
|
||||
other items from Component.onDestruction.
|
||||
- [QTBUG-72352] QML can be built with -no-feature-translation.
|
||||
- [QTBUG-72407] We now annotate stack traces when frames are elided
|
||||
through tail calls.
|
||||
- [QTBUG-72734] Fixed a crash in the parser on certain kinds of bad input.
|
||||
- [QTBUG-72858] Exception handlers are correctly scoped for try blocks and
|
||||
for "for ... in" loops.
|
||||
- [QTBUG-72908] QML can be built with -c++std=c++11 again.
|
||||
- [QTBUG-72972] QQmlMetaType deletes attached properties in its destructor
|
||||
to avoid a crash.
|
||||
- [QTBUG-73009] Fixed a crash with qt.qml.binding.removal.info=true.
|
||||
- [QTBUG-73013] If a signal sender is deleted during the handling of the
|
||||
signal in QML, the QML engine won't crash anymore.
|
||||
- [QTBUG-73152] Brought behavior of String.replace() in line with other
|
||||
JS engines: "x".replace("x", "$1") gives "$1" in both JSC and V8, as there
|
||||
are no captures that could be used as a replacement for $1. Two-digit
|
||||
captures ($nm) get applied if $nm captures exist. If there are less than nm
|
||||
but more than n captures available $n is replaced by the n'th capture and m
|
||||
is copied over verbatim.
|
||||
- [QTBUG-73425] Fixed allocation of large arrays at startup.
|
||||
- [QTBUG-73733] Fixed an access-after-delete crash in DelegateModel.
|
||||
- [QTBUG-73734] When a Q_GADGET type, marked as a primitive type with
|
||||
Q_DECLARE_METATYPE, is emitted with a signal, it can now be accessed in QML.
|
||||
- [QTBUG-73750] Fixed undefined Q_ENUM value in QML Connections object.
|
||||
- [QTBUG-73821] Fixed a failing assert on 32bit platforms.
|
||||
- The JIT compiler is disabled for the IPL32 (or X32) ABI. It did not work
|
||||
before.
|
||||
- The tail call optimization correctly counts method arguments on 32bit
|
||||
platforms now.
|
||||
- The JavaScript engine now tolerates UINT_MAX as array index.
|
||||
|
||||
****************************************************************************
|
||||
* QtQuick *
|
||||
****************************************************************************
|
||||
|
||||
- TextInput/security:
|
||||
* When the TextInput is used for password input, preallocate a buffer
|
||||
for the string that stores the entered value and zero-out the string
|
||||
on TextInput destruction to avoid leaking sensitive data to process
|
||||
memory
|
||||
|
||||
- [QTBUG-63271] If a MouseArea sets itself invisible or disabled while
|
||||
handling a mouse press, it does not acquire the exclusive grab
|
||||
- [QTBUG-71887] TapHandler now consistently forgets touchpoints that occur
|
||||
outside its parent's bounds. This eliminates the warning "pointId is
|
||||
missing from current event, but was neither canceled nor released" when
|
||||
tapping quickly and having some of the taps fall out of bounds.
|
||||
(The warning still exists though, in case there are other scenarios where
|
||||
Handlers remember "wanting" certain touchpoints and then they go missing.)
|
||||
- [QTBUG-72822] PinchHandler now correctly holds its target in place when
|
||||
axes are disabled.
|
||||
- [QTBUG-71918] PointerHandlers are declared as direct children of
|
||||
Flickable (ListView, TableView etc.) now get the pointer events properly.
|
||||
- [QTBUG-42155] Canvas now handles switching between object and string
|
||||
based colors
|
||||
- [QTBUG-73113] Fixed a crash when reparenting QML Canvas items
|
||||
- [QTBUG-73013] Fixed a crash in QuickView on setSource while deleting
|
||||
the sender.
|
||||
- [QT3DS-1419] Improved quality of Qt 3D Studio text labels.
|
|
@ -97,6 +97,8 @@
|
|||
\sa StackView
|
||||
*/
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
|
||||
QQuickStackLayout::QQuickStackLayout(QQuickItem *parent) :
|
||||
QQuickLayout(*new QQuickStackLayoutPrivate, parent)
|
||||
{
|
||||
|
@ -345,4 +347,6 @@ bool QQuickStackLayout::shouldIgnoreItem(QQuickItem *item) const
|
|||
return ignored;
|
||||
}
|
||||
|
||||
QT_END_NAMESPACE
|
||||
|
||||
#include "moc_qquickstacklayout_p.cpp"
|
||||
|
|
|
@ -42,6 +42,8 @@
|
|||
|
||||
#include <qquicklayout_p.h>
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
|
||||
class QQuickStackLayoutPrivate;
|
||||
|
||||
class QQuickStackLayout : public QQuickLayout
|
||||
|
@ -105,4 +107,6 @@ private:
|
|||
bool explicitCurrentIndex;
|
||||
};
|
||||
|
||||
QT_END_NAMESPACE
|
||||
|
||||
#endif // QQUICKSTACKLAYOUT_H
|
||||
|
|
|
@ -566,7 +566,7 @@ bool IRBuilder::visit(QQmlJS::AST::UiQualifiedId *id)
|
|||
|
||||
void IRBuilder::accept(QQmlJS::AST::Node *node)
|
||||
{
|
||||
QQmlJS::AST::Node::acceptChild(node, this);
|
||||
QQmlJS::AST::Node::accept(node, this);
|
||||
}
|
||||
|
||||
bool IRBuilder::defineQMLObject(int *objectIndex, QQmlJS::AST::UiQualifiedId *qualifiedTypeNameId, const QQmlJS::AST::SourceLocation &location, QQmlJS::AST::UiObjectInitializer *initializer, Object *declarationsOverride)
|
||||
|
@ -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;
|
||||
|
|
|
@ -278,7 +278,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;
|
||||
};
|
||||
|
||||
|
@ -431,6 +430,12 @@ public:
|
|||
bool visit(QQmlJS::AST::UiScriptBinding *ast) override;
|
||||
bool visit(QQmlJS::AST::UiSourceElement *ast) override;
|
||||
|
||||
void throwRecursionDepthError() override
|
||||
{
|
||||
recordError(AST::SourceLocation(),
|
||||
QStringLiteral("Maximum statement or expression depth exceeded"));
|
||||
}
|
||||
|
||||
void accept(QQmlJS::AST::Node *node);
|
||||
|
||||
// returns index in _objects
|
||||
|
@ -533,47 +538,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 {
|
||||
|
|
|
@ -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()) {
|
||||
|
|
|
@ -100,9 +100,10 @@ Codegen::Codegen(QV4::Compiler::JSUnitGenerator *jsUnitGenerator, bool strict)
|
|||
, hasError(false)
|
||||
{
|
||||
jsUnitGenerator->codeGeneratorName = QStringLiteral("moth");
|
||||
pushExpr();
|
||||
}
|
||||
|
||||
const char *globalNames[] = {
|
||||
const char *Codegen::s_globalNames[] = {
|
||||
"isNaN",
|
||||
"parseFloat",
|
||||
"String",
|
||||
|
@ -182,7 +183,7 @@ void Codegen::generateFromProgram(const QString &fileName,
|
|||
//
|
||||
// Since this can be called from the loader thread we can't get the list
|
||||
// directly from the engine, so let's hardcode the most important ones here
|
||||
for (const char **g = globalNames; *g != nullptr; ++g)
|
||||
for (const char **g = s_globalNames; *g != nullptr; ++g)
|
||||
m_globalNames << QString::fromLatin1(*g);
|
||||
}
|
||||
|
||||
|
@ -264,7 +265,7 @@ Context *Codegen::enterBlock(Node *node)
|
|||
Codegen::Reference Codegen::unop(UnaryOperation op, const Reference &expr)
|
||||
{
|
||||
if (hasError)
|
||||
return _expr.result();
|
||||
return exprResult();
|
||||
|
||||
if (expr.isConstant()) {
|
||||
auto v = Value::fromReturnedValue(expr.constant);
|
||||
|
@ -310,7 +311,7 @@ Codegen::Reference Codegen::unop(UnaryOperation op, const Reference &expr)
|
|||
return Reference::fromAccumulator(this);
|
||||
}
|
||||
case PostIncrement:
|
||||
if (!_expr.accept(nx) || requiresReturnValue) {
|
||||
if (!exprAccept(nx) || requiresReturnValue) {
|
||||
Reference e = expr.asLValue();
|
||||
e.loadInAccumulator();
|
||||
Instruction::UPlus uplus = {};
|
||||
|
@ -330,13 +331,13 @@ Codegen::Reference Codegen::unop(UnaryOperation op, const Reference &expr)
|
|||
e.loadInAccumulator();
|
||||
Instruction::Increment inc = {};
|
||||
bytecodeGenerator->addTracingInstruction(inc);
|
||||
if (_expr.accept(nx))
|
||||
if (exprAccept(nx))
|
||||
return e.storeConsumeAccumulator();
|
||||
else
|
||||
return e.storeRetainAccumulator();
|
||||
}
|
||||
case PostDecrement:
|
||||
if (!_expr.accept(nx) || requiresReturnValue) {
|
||||
if (!exprAccept(nx) || requiresReturnValue) {
|
||||
Reference e = expr.asLValue();
|
||||
e.loadInAccumulator();
|
||||
Instruction::UPlus uplus = {};
|
||||
|
@ -356,7 +357,7 @@ Codegen::Reference Codegen::unop(UnaryOperation op, const Reference &expr)
|
|||
e.loadInAccumulator();
|
||||
Instruction::Decrement dec = {};
|
||||
bytecodeGenerator->addTracingInstruction(dec);
|
||||
if (_expr.accept(nx))
|
||||
if (exprAccept(nx))
|
||||
return e.storeConsumeAccumulator();
|
||||
else
|
||||
return e.storeRetainAccumulator();
|
||||
|
@ -368,22 +369,13 @@ Codegen::Reference Codegen::unop(UnaryOperation op, const Reference &expr)
|
|||
|
||||
void Codegen::addCJump()
|
||||
{
|
||||
bytecodeGenerator->addCJumpInstruction(_expr.trueBlockFollowsCondition(),
|
||||
_expr.iftrue(), _expr.iffalse());
|
||||
}
|
||||
|
||||
void Codegen::accept(Node *node)
|
||||
{
|
||||
if (hasError)
|
||||
return;
|
||||
|
||||
if (node)
|
||||
node->accept(this);
|
||||
const Result &expression = currentExpr();
|
||||
bytecodeGenerator->addCJumpInstruction(expression.trueBlockFollowsCondition(),
|
||||
expression.iftrue(), expression.iffalse());
|
||||
}
|
||||
|
||||
void Codegen::statement(Statement *ast)
|
||||
{
|
||||
RecursionDepthCheck depthCheck(this, ast->lastSourceLocation());
|
||||
RegisterScope scope(this);
|
||||
|
||||
bytecodeGenerator->setLocation(ast->firstSourceLocation());
|
||||
|
@ -399,23 +391,21 @@ void Codegen::statement(ExpressionNode *ast)
|
|||
if (! ast) {
|
||||
return;
|
||||
} else {
|
||||
RecursionDepthCheck depthCheck(this, ast->lastSourceLocation());
|
||||
RegisterScope scope(this);
|
||||
|
||||
Result r(nx);
|
||||
qSwap(_expr, r);
|
||||
pushExpr(Result(nx));
|
||||
VolatileMemoryLocations vLocs = scanVolatileMemoryLocations(ast);
|
||||
qSwap(_volatileMemoryLocations, vLocs);
|
||||
|
||||
accept(ast);
|
||||
|
||||
qSwap(_volatileMemoryLocations, vLocs);
|
||||
qSwap(_expr, r);
|
||||
Reference result = popResult();
|
||||
|
||||
if (hasError)
|
||||
return;
|
||||
if (r.result().loadTriggersSideEffect())
|
||||
r.result().loadInAccumulator(); // triggers side effects
|
||||
if (result.loadTriggersSideEffect())
|
||||
result.loadInAccumulator(); // triggers side effects
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -428,11 +418,9 @@ void Codegen::condition(ExpressionNode *ast, const BytecodeGenerator::Label *ift
|
|||
if (!ast)
|
||||
return;
|
||||
|
||||
RecursionDepthCheck depthCheck(this, ast->lastSourceLocation());
|
||||
Result r(iftrue, iffalse, trueBlockFollowsCondition);
|
||||
qSwap(_expr, r);
|
||||
pushExpr(Result(iftrue, iffalse, trueBlockFollowsCondition));
|
||||
accept(ast);
|
||||
qSwap(_expr, r);
|
||||
Result r = popExpr();
|
||||
|
||||
if (hasError)
|
||||
return;
|
||||
|
@ -450,18 +438,6 @@ void Codegen::condition(ExpressionNode *ast, const BytecodeGenerator::Label *ift
|
|||
}
|
||||
}
|
||||
|
||||
Codegen::Reference Codegen::expression(ExpressionNode *ast)
|
||||
{
|
||||
RecursionDepthCheck depthCheck(this, ast->lastSourceLocation());
|
||||
Result r;
|
||||
if (ast) {
|
||||
qSwap(_expr, r);
|
||||
accept(ast);
|
||||
qSwap(_expr, r);
|
||||
}
|
||||
return r.result();
|
||||
}
|
||||
|
||||
void Codegen::program(Program *ast)
|
||||
{
|
||||
if (ast) {
|
||||
|
@ -875,17 +851,13 @@ bool Codegen::visit(ExportDeclaration *ast)
|
|||
Reference exportedValue;
|
||||
|
||||
if (auto *fdecl = AST::cast<FunctionDeclaration*>(ast->variableStatementOrDeclaration)) {
|
||||
Result r;
|
||||
qSwap(_expr, r);
|
||||
pushExpr();
|
||||
visit(static_cast<FunctionExpression*>(fdecl));
|
||||
qSwap(_expr, r);
|
||||
exportedValue = r.result();
|
||||
exportedValue = popResult();
|
||||
} else if (auto *classDecl = AST::cast<ClassDeclaration*>(ast->variableStatementOrDeclaration)) {
|
||||
Result r;
|
||||
qSwap(_expr, r);
|
||||
pushExpr();
|
||||
visit(static_cast<ClassExpression*>(classDecl));
|
||||
qSwap(_expr, r);
|
||||
exportedValue = r.result();
|
||||
exportedValue = popResult();
|
||||
} else if (ExpressionNode *expr = ast->variableStatementOrDeclaration->expressionCast()) {
|
||||
exportedValue = expression(expr);
|
||||
}
|
||||
|
@ -1068,7 +1040,7 @@ bool Codegen::visit(ClassExpression *ast)
|
|||
(void) ctor.storeRetainAccumulator();
|
||||
}
|
||||
|
||||
_expr.setResult(Reference::fromAccumulator(this));
|
||||
setExprResult(Reference::fromAccumulator(this));
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -1151,7 +1123,7 @@ bool Codegen::visit(ArrayPattern *ast)
|
|||
}
|
||||
|
||||
if (!it) {
|
||||
_expr.setResult(Reference::fromAccumulator(this));
|
||||
setExprResult(Reference::fromAccumulator(this));
|
||||
return false;
|
||||
}
|
||||
Q_ASSERT(it->element && it->element->type == PatternElement::SpreadElement);
|
||||
|
@ -1246,7 +1218,7 @@ bool Codegen::visit(ArrayPattern *ast)
|
|||
}
|
||||
|
||||
array.loadInAccumulator();
|
||||
_expr.setResult(Reference::fromAccumulator(this));
|
||||
setExprResult(Reference::fromAccumulator(this));
|
||||
|
||||
return false;
|
||||
}
|
||||
|
@ -1262,7 +1234,7 @@ bool Codegen::visit(ArrayMemberExpression *ast)
|
|||
return false;
|
||||
if (base.isSuper()) {
|
||||
Reference index = expression(ast->expression).storeOnStack();
|
||||
_expr.setResult(Reference::fromSuperProperty(index));
|
||||
setExprResult(Reference::fromSuperProperty(index));
|
||||
return false;
|
||||
}
|
||||
base = base.storeOnStack();
|
||||
|
@ -1272,17 +1244,17 @@ bool Codegen::visit(ArrayMemberExpression *ast)
|
|||
QString s = str->value.toString();
|
||||
uint arrayIndex = QV4::String::toArrayIndex(s);
|
||||
if (arrayIndex == UINT_MAX) {
|
||||
_expr.setResult(Reference::fromMember(base, str->value.toString()));
|
||||
setExprResult(Reference::fromMember(base, str->value.toString()));
|
||||
return false;
|
||||
}
|
||||
Reference index = Reference::fromConst(this, QV4::Encode(arrayIndex));
|
||||
_expr.setResult(Reference::fromSubscript(base, index));
|
||||
setExprResult(Reference::fromSubscript(base, index));
|
||||
return false;
|
||||
}
|
||||
Reference index = expression(ast->expression);
|
||||
if (hasError)
|
||||
return false;
|
||||
_expr.setResult(Reference::fromSubscript(base, index));
|
||||
setExprResult(Reference::fromSubscript(base, index));
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -1313,12 +1285,13 @@ bool Codegen::visit(BinaryExpression *ast)
|
|||
TailCallBlocker blockTailCalls(this);
|
||||
|
||||
if (ast->op == QSOperator::And) {
|
||||
if (_expr.accept(cx)) {
|
||||
if (exprAccept(cx)) {
|
||||
auto iftrue = bytecodeGenerator->newLabel();
|
||||
condition(ast->left, &iftrue, _expr.iffalse(), true);
|
||||
condition(ast->left, &iftrue, currentExpr().iffalse(), true);
|
||||
iftrue.link();
|
||||
blockTailCalls.unblock();
|
||||
condition(ast->right, _expr.iftrue(), _expr.iffalse(), _expr.trueBlockFollowsCondition());
|
||||
const Result &expr = currentExpr();
|
||||
condition(ast->right, expr.iftrue(), expr.iffalse(), expr.trueBlockFollowsCondition());
|
||||
} else {
|
||||
auto iftrue = bytecodeGenerator->newLabel();
|
||||
auto endif = bytecodeGenerator->newLabel();
|
||||
|
@ -1340,15 +1313,16 @@ bool Codegen::visit(BinaryExpression *ast)
|
|||
|
||||
endif.link();
|
||||
|
||||
_expr.setResult(Reference::fromAccumulator(this));
|
||||
setExprResult(Reference::fromAccumulator(this));
|
||||
}
|
||||
return false;
|
||||
} else if (ast->op == QSOperator::Or) {
|
||||
if (_expr.accept(cx)) {
|
||||
if (exprAccept(cx)) {
|
||||
auto iffalse = bytecodeGenerator->newLabel();
|
||||
condition(ast->left, _expr.iftrue(), &iffalse, false);
|
||||
condition(ast->left, currentExpr().iftrue(), &iffalse, false);
|
||||
iffalse.link();
|
||||
condition(ast->right, _expr.iftrue(), _expr.iffalse(), _expr.trueBlockFollowsCondition());
|
||||
const Result &expr = currentExpr();
|
||||
condition(ast->right, expr.iftrue(), expr.iffalse(), expr.trueBlockFollowsCondition());
|
||||
} else {
|
||||
auto iffalse = bytecodeGenerator->newLabel();
|
||||
auto endif = bytecodeGenerator->newLabel();
|
||||
|
@ -1370,7 +1344,7 @@ bool Codegen::visit(BinaryExpression *ast)
|
|||
|
||||
endif.link();
|
||||
|
||||
_expr.setResult(Reference::fromAccumulator(this));
|
||||
setExprResult(Reference::fromAccumulator(this));
|
||||
}
|
||||
return false;
|
||||
} else if (ast->op == QSOperator::Assign) {
|
||||
|
@ -1381,9 +1355,9 @@ bool Codegen::visit(BinaryExpression *ast)
|
|||
return false;
|
||||
right = right.storeOnStack();
|
||||
destructurePattern(p, right);
|
||||
if (!_expr.accept(nx)) {
|
||||
if (!exprAccept(nx)) {
|
||||
right.loadInAccumulator();
|
||||
_expr.setResult(Reference::fromAccumulator(this));
|
||||
setExprResult(Reference::fromAccumulator(this));
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
@ -1403,10 +1377,10 @@ bool Codegen::visit(BinaryExpression *ast)
|
|||
if (hasError)
|
||||
return false;
|
||||
r.loadInAccumulator();
|
||||
if (_expr.accept(nx))
|
||||
_expr.setResult(left.storeConsumeAccumulator());
|
||||
if (exprAccept(nx))
|
||||
setExprResult(left.storeConsumeAccumulator());
|
||||
else
|
||||
_expr.setResult(left.storeRetainAccumulator());
|
||||
setExprResult(left.storeRetainAccumulator());
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -1449,7 +1423,7 @@ bool Codegen::visit(BinaryExpression *ast)
|
|||
return false;
|
||||
|
||||
binopHelper(baseOp(ast->op), tempLeft, right).loadInAccumulator();
|
||||
_expr.setResult(left.storeRetainAccumulator());
|
||||
setExprResult(left.storeRetainAccumulator());
|
||||
|
||||
break;
|
||||
}
|
||||
|
@ -1461,7 +1435,7 @@ bool Codegen::visit(BinaryExpression *ast)
|
|||
Reference right = expression(ast->right);
|
||||
if (hasError)
|
||||
return false;
|
||||
_expr.setResult(binopHelper(static_cast<QSOperator::Op>(ast->op), right, left));
|
||||
setExprResult(binopHelper(static_cast<QSOperator::Op>(ast->op), right, left));
|
||||
break;
|
||||
}
|
||||
// intentional fall-through!
|
||||
|
@ -1487,7 +1461,7 @@ bool Codegen::visit(BinaryExpression *ast)
|
|||
Reference right;
|
||||
if (AST::NumericLiteral *rhs = AST::cast<AST::NumericLiteral *>(ast->right)) {
|
||||
visit(rhs);
|
||||
right = _expr.result();
|
||||
right = exprResult();
|
||||
} else {
|
||||
left = left.storeOnStack(); // force any loads of the lhs, so the rhs won't clobber it
|
||||
right = expression(ast->right);
|
||||
|
@ -1495,7 +1469,7 @@ bool Codegen::visit(BinaryExpression *ast)
|
|||
if (hasError)
|
||||
return false;
|
||||
|
||||
_expr.setResult(binopHelper(static_cast<QSOperator::Op>(ast->op), left, right));
|
||||
setExprResult(binopHelper(static_cast<QSOperator::Op>(ast->op), left, right));
|
||||
|
||||
break;
|
||||
}
|
||||
|
@ -1672,7 +1646,7 @@ Codegen::Reference Codegen::binopHelper(QSOperator::Op oper, Reference &left, Re
|
|||
break;
|
||||
}
|
||||
case QSOperator::StrictEqual: {
|
||||
if (_expr.accept(cx))
|
||||
if (exprAccept(cx))
|
||||
return jumpBinop(oper, left, right);
|
||||
|
||||
Instruction::CmpStrictEqual cmp;
|
||||
|
@ -1683,7 +1657,7 @@ Codegen::Reference Codegen::binopHelper(QSOperator::Op oper, Reference &left, Re
|
|||
break;
|
||||
}
|
||||
case QSOperator::StrictNotEqual: {
|
||||
if (_expr.accept(cx))
|
||||
if (exprAccept(cx))
|
||||
return jumpBinop(oper, left, right);
|
||||
|
||||
Instruction::CmpStrictNotEqual cmp;
|
||||
|
@ -1694,7 +1668,7 @@ Codegen::Reference Codegen::binopHelper(QSOperator::Op oper, Reference &left, Re
|
|||
break;
|
||||
}
|
||||
case QSOperator::Equal: {
|
||||
if (_expr.accept(cx))
|
||||
if (exprAccept(cx))
|
||||
return jumpBinop(oper, left, right);
|
||||
|
||||
Instruction::CmpEq cmp;
|
||||
|
@ -1705,7 +1679,7 @@ Codegen::Reference Codegen::binopHelper(QSOperator::Op oper, Reference &left, Re
|
|||
break;
|
||||
}
|
||||
case QSOperator::NotEqual: {
|
||||
if (_expr.accept(cx))
|
||||
if (exprAccept(cx))
|
||||
return jumpBinop(oper, left, right);
|
||||
|
||||
Instruction::CmpNe cmp;
|
||||
|
@ -1716,7 +1690,7 @@ Codegen::Reference Codegen::binopHelper(QSOperator::Op oper, Reference &left, Re
|
|||
break;
|
||||
}
|
||||
case QSOperator::Gt: {
|
||||
if (_expr.accept(cx))
|
||||
if (exprAccept(cx))
|
||||
return jumpBinop(oper, left, right);
|
||||
|
||||
Instruction::CmpGt cmp;
|
||||
|
@ -1727,7 +1701,7 @@ Codegen::Reference Codegen::binopHelper(QSOperator::Op oper, Reference &left, Re
|
|||
break;
|
||||
}
|
||||
case QSOperator::Ge: {
|
||||
if (_expr.accept(cx))
|
||||
if (exprAccept(cx))
|
||||
return jumpBinop(oper, left, right);
|
||||
|
||||
Instruction::CmpGe cmp;
|
||||
|
@ -1738,7 +1712,7 @@ Codegen::Reference Codegen::binopHelper(QSOperator::Op oper, Reference &left, Re
|
|||
break;
|
||||
}
|
||||
case QSOperator::Lt: {
|
||||
if (_expr.accept(cx))
|
||||
if (exprAccept(cx))
|
||||
return jumpBinop(oper, left, right);
|
||||
|
||||
Instruction::CmpLt cmp;
|
||||
|
@ -1749,7 +1723,7 @@ Codegen::Reference Codegen::binopHelper(QSOperator::Op oper, Reference &left, Re
|
|||
break;
|
||||
}
|
||||
case QSOperator::Le:
|
||||
if (_expr.accept(cx))
|
||||
if (exprAccept(cx))
|
||||
return jumpBinop(oper, left, right);
|
||||
|
||||
Instruction::CmpLe cmp;
|
||||
|
@ -1902,8 +1876,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:
|
||||
|
@ -1953,7 +1925,7 @@ bool Codegen::visit(CallExpression *ast)
|
|||
bytecodeGenerator->addInstruction(call);
|
||||
}
|
||||
|
||||
_expr.setResult(Reference::fromAccumulator(this));
|
||||
setExprResult(Reference::fromAccumulator(this));
|
||||
return false;
|
||||
|
||||
}
|
||||
|
@ -1965,21 +1937,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();
|
||||
|
@ -2009,11 +1967,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();
|
||||
|
@ -2046,7 +2012,7 @@ void Codegen::handleCall(Reference &base, Arguments calldata, int slotForFunctio
|
|||
bytecodeGenerator->addTracingInstruction(call);
|
||||
}
|
||||
|
||||
_expr.setResult(Reference::fromAccumulator(this));
|
||||
setExprResult(Reference::fromAccumulator(this));
|
||||
}
|
||||
|
||||
Codegen::Arguments Codegen::pushArgs(ArgumentList *args)
|
||||
|
@ -2142,7 +2108,7 @@ bool Codegen::visit(ConditionalExpression *ast)
|
|||
ko.loadInAccumulator();
|
||||
|
||||
jump_endif.link();
|
||||
_expr.setResult(Reference::fromAccumulator(this));
|
||||
setExprResult(Reference::fromAccumulator(this));
|
||||
|
||||
return false;
|
||||
}
|
||||
|
@ -2172,7 +2138,7 @@ bool Codegen::visit(DeleteExpression *ast)
|
|||
throwSyntaxError(ast->deleteToken, QStringLiteral("Delete of an unqualified identifier in strict mode."));
|
||||
return false;
|
||||
}
|
||||
_expr.setResult(Reference::fromConst(this, QV4::Encode(false)));
|
||||
setExprResult(Reference::fromConst(this, QV4::Encode(false)));
|
||||
return false;
|
||||
case Reference::Name: {
|
||||
if (_context->isStrict) {
|
||||
|
@ -2182,7 +2148,7 @@ bool Codegen::visit(DeleteExpression *ast)
|
|||
Instruction::DeleteName del;
|
||||
del.name = expr.nameAsIndex();
|
||||
bytecodeGenerator->addInstruction(del);
|
||||
_expr.setResult(Reference::fromAccumulator(this));
|
||||
setExprResult(Reference::fromAccumulator(this));
|
||||
return false;
|
||||
}
|
||||
case Reference::Member: {
|
||||
|
@ -2197,7 +2163,7 @@ bool Codegen::visit(DeleteExpression *ast)
|
|||
del.base = expr.propertyBase.stackSlot();
|
||||
del.index = index.stackSlot();
|
||||
bytecodeGenerator->addInstruction(del);
|
||||
_expr.setResult(Reference::fromAccumulator(this));
|
||||
setExprResult(Reference::fromAccumulator(this));
|
||||
return false;
|
||||
}
|
||||
case Reference::Subscript: {
|
||||
|
@ -2207,14 +2173,14 @@ bool Codegen::visit(DeleteExpression *ast)
|
|||
del.base = expr.elementBase;
|
||||
del.index = expr.elementSubscript.stackSlot();
|
||||
bytecodeGenerator->addInstruction(del);
|
||||
_expr.setResult(Reference::fromAccumulator(this));
|
||||
setExprResult(Reference::fromAccumulator(this));
|
||||
return false;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
// [[11.4.1]] Return true if it's not a reference
|
||||
_expr.setResult(Reference::fromConst(this, QV4::Encode(true)));
|
||||
setExprResult(Reference::fromConst(this, QV4::Encode(true)));
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -2223,7 +2189,7 @@ bool Codegen::visit(FalseLiteral *)
|
|||
if (hasError)
|
||||
return false;
|
||||
|
||||
_expr.setResult(Reference::fromConst(this, QV4::Encode(false)));
|
||||
setExprResult(Reference::fromConst(this, QV4::Encode(false)));
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -2232,7 +2198,7 @@ bool Codegen::visit(SuperLiteral *)
|
|||
if (hasError)
|
||||
return false;
|
||||
|
||||
_expr.setResult(Reference::fromSuper(this));
|
||||
setExprResult(Reference::fromSuper(this));
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -2250,12 +2216,12 @@ bool Codegen::visit(FieldMemberExpression *ast)
|
|||
if (_context->isArrowFunction || _context->contextType == ContextType::Eval) {
|
||||
Reference r = referenceForName(QStringLiteral("new.target"), false);
|
||||
r.isReadonly = true;
|
||||
_expr.setResult(r);
|
||||
setExprResult(r);
|
||||
return false;
|
||||
}
|
||||
|
||||
Reference r = Reference::fromStackSlot(this, CallData::NewTarget);
|
||||
_expr.setResult(r);
|
||||
setExprResult(r);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
@ -2268,10 +2234,10 @@ bool Codegen::visit(FieldMemberExpression *ast)
|
|||
load.stringId = registerString(ast->name.toString());
|
||||
bytecodeGenerator->addInstruction(load);
|
||||
Reference property = Reference::fromAccumulator(this).storeOnStack();
|
||||
_expr.setResult(Reference::fromSuperProperty(property));
|
||||
setExprResult(Reference::fromSuperProperty(property));
|
||||
return false;
|
||||
}
|
||||
_expr.setResult(Reference::fromMember(base, ast->name.toString()));
|
||||
setExprResult(Reference::fromMember(base, ast->name.toString()));
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -2281,12 +2247,15 @@ bool Codegen::visit(TaggedTemplate *ast)
|
|||
return false;
|
||||
|
||||
RegisterScope scope(this);
|
||||
return handleTaggedTemplate(expression(ast->base), ast);
|
||||
}
|
||||
|
||||
int functionObject = -1, thisObject = -1;
|
||||
|
||||
Reference base = expression(ast->base);
|
||||
bool Codegen::handleTaggedTemplate(Reference base, TaggedTemplate *ast)
|
||||
{
|
||||
if (hasError)
|
||||
return false;
|
||||
|
||||
int functionObject = -1, thisObject = -1;
|
||||
switch (base.type) {
|
||||
case Reference::Member:
|
||||
case Reference::Subscript:
|
||||
|
@ -2347,7 +2316,7 @@ bool Codegen::visit(FunctionExpression *ast)
|
|||
if (hasError)
|
||||
return false;
|
||||
loadClosure(function);
|
||||
_expr.setResult(Reference::fromAccumulator(this));
|
||||
setExprResult(Reference::fromAccumulator(this));
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -2379,14 +2348,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;
|
||||
}
|
||||
|
@ -2402,18 +2367,12 @@ void Codegen::loadClosure(int closureId)
|
|||
}
|
||||
}
|
||||
|
||||
Codegen::Reference Codegen::fallbackNameLookup(const QString &name)
|
||||
{
|
||||
Q_UNUSED(name)
|
||||
return Reference();
|
||||
}
|
||||
|
||||
bool Codegen::visit(IdentifierExpression *ast)
|
||||
{
|
||||
if (hasError)
|
||||
return false;
|
||||
|
||||
_expr.setResult(referenceForName(ast->name.toString(), false, ast->firstSourceLocation()));
|
||||
setExprResult(referenceForName(ast->name.toString(), false, ast->firstSourceLocation()));
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -2463,7 +2422,7 @@ void Codegen::handleConstruct(const Reference &base, ArgumentList *arguments)
|
|||
// set the result up as the thisObject
|
||||
Reference::fromAccumulator(this).storeOnStack(CallData::This);
|
||||
|
||||
_expr.setResult(Reference::fromAccumulator(this));
|
||||
setExprResult(Reference::fromAccumulator(this));
|
||||
}
|
||||
|
||||
bool Codegen::visit(NewExpression *ast)
|
||||
|
@ -2512,7 +2471,7 @@ bool Codegen::visit(NotExpression *ast)
|
|||
return false;
|
||||
|
||||
TailCallBlocker blockTailCalls(this);
|
||||
_expr.setResult(unop(Not, expression(ast->expression)));
|
||||
setExprResult(unop(Not, expression(ast->expression)));
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -2521,10 +2480,10 @@ bool Codegen::visit(NullExpression *)
|
|||
if (hasError)
|
||||
return false;
|
||||
|
||||
if (_expr.accept(cx))
|
||||
bytecodeGenerator->jump().link(*_expr.iffalse());
|
||||
if (exprAccept(cx))
|
||||
bytecodeGenerator->jump().link(*currentExpr().iffalse());
|
||||
else
|
||||
_expr.setResult(Reference::fromConst(this, Encode::null()));
|
||||
setExprResult(Reference::fromConst(this, Encode::null()));
|
||||
|
||||
return false;
|
||||
}
|
||||
|
@ -2534,7 +2493,7 @@ bool Codegen::visit(NumericLiteral *ast)
|
|||
if (hasError)
|
||||
return false;
|
||||
|
||||
_expr.setResult(Reference::fromConst(this, QV4::Encode::smallestNumber(ast->value)));
|
||||
setExprResult(Reference::fromConst(this, QV4::Encode::smallestNumber(ast->value)));
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -2646,8 +2605,7 @@ bool Codegen::visit(ObjectPattern *ast)
|
|||
call.argc = argc;
|
||||
call.args = Moth::StackSlot::createRegister(args);
|
||||
bytecodeGenerator->addInstruction(call);
|
||||
Reference result = Reference::fromAccumulator(this);
|
||||
_expr.setResult(result);
|
||||
setExprResult(Reference::fromAccumulator(this));
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -2666,7 +2624,7 @@ bool Codegen::visit(PostDecrementExpression *ast)
|
|||
if (throwSyntaxErrorOnEvalOrArgumentsInStrictMode(expr, ast->decrementToken))
|
||||
return false;
|
||||
|
||||
_expr.setResult(unop(PostDecrement, expr));
|
||||
setExprResult(unop(PostDecrement, expr));
|
||||
|
||||
return false;
|
||||
}
|
||||
|
@ -2686,7 +2644,7 @@ bool Codegen::visit(PostIncrementExpression *ast)
|
|||
if (throwSyntaxErrorOnEvalOrArgumentsInStrictMode(expr, ast->incrementToken))
|
||||
return false;
|
||||
|
||||
_expr.setResult(unop(PostIncrement, expr));
|
||||
setExprResult(unop(PostIncrement, expr));
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -2704,7 +2662,7 @@ bool Codegen::visit(PreDecrementExpression *ast)
|
|||
|
||||
if (throwSyntaxErrorOnEvalOrArgumentsInStrictMode(expr, ast->decrementToken))
|
||||
return false;
|
||||
_expr.setResult(unop(PreDecrement, expr));
|
||||
setExprResult(unop(PreDecrement, expr));
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -2723,7 +2681,7 @@ bool Codegen::visit(PreIncrementExpression *ast)
|
|||
|
||||
if (throwSyntaxErrorOnEvalOrArgumentsInStrictMode(expr, ast->incrementToken))
|
||||
return false;
|
||||
_expr.setResult(unop(PreIncrement, expr));
|
||||
setExprResult(unop(PreIncrement, expr));
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -2734,7 +2692,7 @@ bool Codegen::visit(RegExpLiteral *ast)
|
|||
|
||||
auto r = Reference::fromStackSlot(this);
|
||||
r.isReadonly = true;
|
||||
_expr.setResult(r);
|
||||
setExprResult(r);
|
||||
|
||||
Instruction::MoveRegExp instr;
|
||||
instr.regExpId = jsUnitGenerator->registerRegExp(ast);
|
||||
|
@ -2750,7 +2708,7 @@ bool Codegen::visit(StringLiteral *ast)
|
|||
|
||||
auto r = Reference::fromAccumulator(this);
|
||||
r.isReadonly = true;
|
||||
_expr.setResult(r);
|
||||
setExprResult(r);
|
||||
|
||||
Instruction::LoadRuntimeString instr;
|
||||
instr.stringId = registerString(ast->value.toString());
|
||||
|
@ -2800,7 +2758,7 @@ bool Codegen::visit(TemplateLiteral *ast)
|
|||
auto r = Reference::fromAccumulator(this);
|
||||
r.isReadonly = true;
|
||||
|
||||
_expr.setResult(r);
|
||||
setExprResult(r);
|
||||
return false;
|
||||
|
||||
}
|
||||
|
@ -2813,10 +2771,10 @@ bool Codegen::visit(ThisExpression *)
|
|||
if (_context->isArrowFunction) {
|
||||
Reference r = referenceForName(QStringLiteral("this"), false);
|
||||
r.isReadonly = true;
|
||||
_expr.setResult(r);
|
||||
setExprResult(r);
|
||||
return false;
|
||||
}
|
||||
_expr.setResult(Reference::fromThis(this));
|
||||
setExprResult(Reference::fromThis(this));
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -2826,7 +2784,7 @@ bool Codegen::visit(TildeExpression *ast)
|
|||
return false;
|
||||
|
||||
TailCallBlocker blockTailCalls(this);
|
||||
_expr.setResult(unop(Compl, expression(ast->expression)));
|
||||
setExprResult(unop(Compl, expression(ast->expression)));
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -2835,7 +2793,7 @@ bool Codegen::visit(TrueLiteral *)
|
|||
if (hasError)
|
||||
return false;
|
||||
|
||||
_expr.setResult(Reference::fromConst(this, QV4::Encode(true)));
|
||||
setExprResult(Reference::fromConst(this, QV4::Encode(true)));
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -2861,7 +2819,7 @@ bool Codegen::visit(TypeOfExpression *ast)
|
|||
Instruction::TypeofValue instr;
|
||||
bytecodeGenerator->addInstruction(instr);
|
||||
}
|
||||
_expr.setResult(Reference::fromAccumulator(this));
|
||||
setExprResult(Reference::fromAccumulator(this));
|
||||
|
||||
return false;
|
||||
}
|
||||
|
@ -2872,7 +2830,7 @@ bool Codegen::visit(UnaryMinusExpression *ast)
|
|||
return false;
|
||||
|
||||
TailCallBlocker blockTailCalls(this);
|
||||
_expr.setResult(unop(UMinus, expression(ast->expression)));
|
||||
setExprResult(unop(UMinus, expression(ast->expression)));
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -2882,7 +2840,7 @@ bool Codegen::visit(UnaryPlusExpression *ast)
|
|||
return false;
|
||||
|
||||
TailCallBlocker blockTailCalls(this);
|
||||
_expr.setResult(unop(UPlus, expression(ast->expression)));
|
||||
setExprResult(unop(UPlus, expression(ast->expression)));
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -2895,7 +2853,7 @@ bool Codegen::visit(VoidExpression *ast)
|
|||
TailCallBlocker blockTailCalls(this);
|
||||
|
||||
statement(ast->expression);
|
||||
_expr.setResult(Reference::fromConst(this, Encode::undefined()));
|
||||
setExprResult(Reference::fromConst(this, Encode::undefined()));
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -2909,7 +2867,7 @@ bool Codegen::visit(FunctionDeclaration * ast)
|
|||
|
||||
if (_functionContext->contextType == ContextType::Binding)
|
||||
referenceForName(ast->name.toString(), true).loadInAccumulator();
|
||||
_expr.accept(nx);
|
||||
exprAccept(nx);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -2965,7 +2923,7 @@ bool Codegen::visit(YieldExpression *ast)
|
|||
done.link();
|
||||
|
||||
lhsValue.loadInAccumulator();
|
||||
_expr.setResult(acc);
|
||||
setExprResult(acc);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -2976,7 +2934,7 @@ bool Codegen::visit(YieldExpression *ast)
|
|||
BytecodeGenerator::Jump jump = bytecodeGenerator->addJumpInstruction(resume);
|
||||
emitReturn(acc);
|
||||
jump.link();
|
||||
_expr.setResult(acc);
|
||||
setExprResult(acc);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -3115,8 +3073,6 @@ int Codegen::defineFunction(const QString &name, AST::Node *ast,
|
|||
bytecodeGenerator->addInstruction(yield);
|
||||
}
|
||||
|
||||
beginFunctionBodyHook();
|
||||
|
||||
statementList(body);
|
||||
|
||||
if (!hasError) {
|
||||
|
@ -3855,8 +3811,14 @@ QQmlRefPointer<CompiledData::CompilationUnit> Codegen::createUnitForLoading()
|
|||
class Codegen::VolatileMemoryLocationScanner: protected QQmlJS::AST::Visitor
|
||||
{
|
||||
VolatileMemoryLocations locs;
|
||||
Codegen *parent;
|
||||
|
||||
public:
|
||||
VolatileMemoryLocationScanner(Codegen *parent) :
|
||||
QQmlJS::AST::Visitor(parent->recursionDepth()),
|
||||
parent(parent)
|
||||
{}
|
||||
|
||||
Codegen::VolatileMemoryLocations scan(AST::Node *s)
|
||||
{
|
||||
s->accept(this);
|
||||
|
@ -3921,25 +3883,41 @@ public:
|
|||
}
|
||||
}
|
||||
|
||||
void throwRecursionDepthError() override
|
||||
{
|
||||
parent->throwRecursionDepthError();
|
||||
}
|
||||
|
||||
private:
|
||||
void collectIdentifiers(QVector<QStringView> &ids, AST::Node *node) const {
|
||||
void collectIdentifiers(QVector<QStringView> &ids, AST::Node *node) {
|
||||
class Collector: public QQmlJS::AST::Visitor {
|
||||
private:
|
||||
QVector<QStringView> &ids;
|
||||
VolatileMemoryLocationScanner *parent;
|
||||
|
||||
public:
|
||||
Collector(QVector<QStringView> &ids): ids(ids) {}
|
||||
virtual bool visit(IdentifierExpression *ie) {
|
||||
Collector(QVector<QStringView> &ids, VolatileMemoryLocationScanner *parent) :
|
||||
QQmlJS::AST::Visitor(parent->recursionDepth()), ids(ids), parent(parent)
|
||||
{}
|
||||
|
||||
bool visit(IdentifierExpression *ie) final {
|
||||
ids.append(ie->name);
|
||||
return false;
|
||||
}
|
||||
|
||||
void throwRecursionDepthError() final
|
||||
{
|
||||
parent->throwRecursionDepthError();
|
||||
}
|
||||
};
|
||||
Collector collector(ids);
|
||||
Collector collector(ids, this);
|
||||
node->accept(&collector);
|
||||
}
|
||||
};
|
||||
|
||||
Codegen::VolatileMemoryLocations Codegen::scanVolatileMemoryLocations(AST::Node *ast) const
|
||||
Codegen::VolatileMemoryLocations Codegen::scanVolatileMemoryLocations(AST::Node *ast)
|
||||
{
|
||||
VolatileMemoryLocationScanner scanner;
|
||||
VolatileMemoryLocationScanner scanner(this);
|
||||
return scanner.scan(ast);
|
||||
}
|
||||
|
||||
|
@ -4041,10 +4019,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;
|
||||
}
|
||||
|
@ -4102,9 +4076,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());
|
||||
|
@ -4189,8 +4161,6 @@ bool Codegen::Reference::storeWipesAccumulator() const
|
|||
case Name:
|
||||
case Member:
|
||||
case Subscript:
|
||||
case QmlScopeObject:
|
||||
case QmlContextObject:
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
@ -4270,18 +4240,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:
|
||||
|
@ -4396,9 +4354,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();
|
||||
|
@ -4432,24 +4396,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;
|
||||
}
|
||||
|
|
|
@ -184,16 +184,31 @@ public:
|
|||
Member,
|
||||
Subscript,
|
||||
Import,
|
||||
QmlScopeObject,
|
||||
QmlContextObject,
|
||||
LastLValue = QmlContextObject,
|
||||
LastLValue = Import,
|
||||
Const
|
||||
} type = Invalid;
|
||||
|
||||
bool isLValue() const { return !isReadonly && type > Accumulator; }
|
||||
|
||||
Reference(Codegen *cg, Type type = Invalid) : type(type), constant(0), codegen(cg) {}
|
||||
Reference(): constant(0) {}
|
||||
Reference(Codegen *cg, Type t = Invalid) : Reference()
|
||||
{
|
||||
type = t;
|
||||
codegen = cg;
|
||||
}
|
||||
|
||||
Reference() :
|
||||
constant(0),
|
||||
isArgOrEval(false),
|
||||
isReadonly(false),
|
||||
isReferenceToConst(false),
|
||||
requiresTDZCheck(false),
|
||||
subscriptRequiresTDZCheck(false),
|
||||
stackSlotIsLocalOrArgument(false),
|
||||
isVolatile(false),
|
||||
global(false),
|
||||
qmlGlobal(false)
|
||||
{}
|
||||
|
||||
Reference(const Reference &) = default;
|
||||
Reference(Reference &&) = default;
|
||||
Reference &operator =(const Reference &) = default;
|
||||
|
@ -206,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:
|
||||
|
@ -228,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);
|
||||
}
|
||||
|
@ -316,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;
|
||||
|
@ -386,25 +359,21 @@ 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;
|
||||
mutable bool isArgOrEval = false;
|
||||
bool isReadonly = false;
|
||||
bool isReferenceToConst = false;
|
||||
bool requiresTDZCheck = false;
|
||||
bool subscriptRequiresTDZCheck = false;
|
||||
bool stackSlotIsLocalOrArgument = false;
|
||||
bool isVolatile = false;
|
||||
bool global = false;
|
||||
Codegen *codegen = nullptr;
|
||||
|
||||
quint32 isArgOrEval:1;
|
||||
quint32 isReadonly:1;
|
||||
quint32 isReferenceToConst:1;
|
||||
quint32 requiresTDZCheck:1;
|
||||
quint32 subscriptRequiresTDZCheck:1;
|
||||
quint32 stackSlotIsLocalOrArgument:1;
|
||||
quint32 isVolatile:1;
|
||||
quint32 global:1;
|
||||
quint32 qmlGlobal:1;
|
||||
|
||||
private:
|
||||
void storeAccumulator() const;
|
||||
Reference doStoreOnStack(int tempIndex) const;
|
||||
|
@ -499,6 +468,10 @@ protected:
|
|||
void setResult(const Reference &result) {
|
||||
_result = result;
|
||||
}
|
||||
|
||||
void setResult(Reference &&result) {
|
||||
_result = std::move(result);
|
||||
}
|
||||
};
|
||||
|
||||
void enterContext(AST::Node *node);
|
||||
|
@ -532,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,
|
||||
|
@ -544,9 +518,22 @@ protected:
|
|||
void condition(AST::ExpressionNode *ast, const BytecodeGenerator::Label *iftrue,
|
||||
const BytecodeGenerator::Label *iffalse,
|
||||
bool trueBlockFollowsCondition);
|
||||
Reference expression(AST::ExpressionNode *ast);
|
||||
|
||||
void accept(AST::Node *node);
|
||||
inline Reference expression(AST::ExpressionNode *ast)
|
||||
{
|
||||
if (!ast || hasError)
|
||||
return Reference();
|
||||
|
||||
pushExpr();
|
||||
ast->accept(this);
|
||||
return popResult();
|
||||
}
|
||||
|
||||
inline void accept(AST::Node *node)
|
||||
{
|
||||
if (!hasError && node)
|
||||
node->accept(this);
|
||||
}
|
||||
|
||||
void program(AST::Program *ast);
|
||||
void statementList(AST::StatementList *ast);
|
||||
|
@ -561,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
|
||||
|
@ -670,6 +651,11 @@ protected:
|
|||
bool throwSyntaxErrorOnEvalOrArgumentsInStrictMode(const Reference &r, const AST::SourceLocation &loc);
|
||||
virtual void throwSyntaxError(const AST::SourceLocation &loc, const QString &detail);
|
||||
virtual void throwReferenceError(const AST::SourceLocation &loc, const QString &detail);
|
||||
void throwRecursionDepthError() override
|
||||
{
|
||||
throwSyntaxError(AST::SourceLocation(),
|
||||
QStringLiteral("Maximum statement or expression depth exceeded"));
|
||||
}
|
||||
|
||||
public:
|
||||
QList<DiagnosticMessage> errors() const;
|
||||
|
@ -684,6 +670,7 @@ public:
|
|||
void handleCall(Reference &base, Arguments calldata, int slotForFunction, int slotForThisObject);
|
||||
|
||||
Arguments pushTemplateArgs(AST::TemplateLiteral *args);
|
||||
bool handleTaggedTemplate(Reference base, AST::TaggedTemplate *ast);
|
||||
void createTemplateObject(AST::TemplateLiteral *t);
|
||||
|
||||
void setUseFastLookups(bool b) { useFastLookups = b; }
|
||||
|
@ -714,13 +701,40 @@ public:
|
|||
m_globalNames = globalNames;
|
||||
}
|
||||
|
||||
static const char *s_globalNames[];
|
||||
|
||||
protected:
|
||||
friend class ScanFunctions;
|
||||
friend struct ControlFlow;
|
||||
friend struct ControlFlowCatch;
|
||||
friend struct ControlFlowFinally;
|
||||
Result _expr;
|
||||
|
||||
inline void setExprResult(const Reference &result) { m_expressions.back().setResult(result); }
|
||||
inline void setExprResult(Reference &&result) { m_expressions.back().setResult(std::move(result)); }
|
||||
inline Reference exprResult() const { return m_expressions.back().result(); }
|
||||
|
||||
inline bool exprAccept(Format f) { return m_expressions.back().accept(f); }
|
||||
|
||||
inline const Result ¤tExpr() const { return m_expressions.back(); }
|
||||
|
||||
inline void pushExpr(Result &&expr) { m_expressions.push_back(std::move(expr)); }
|
||||
inline void pushExpr(const Result &expr) { m_expressions.push_back(expr); }
|
||||
inline void pushExpr() { m_expressions.emplace_back(); }
|
||||
|
||||
inline Result popExpr()
|
||||
{
|
||||
const Result result = m_expressions.back();
|
||||
m_expressions.pop_back();
|
||||
return result;
|
||||
}
|
||||
|
||||
inline Reference popResult() {
|
||||
const Reference result = m_expressions.back().result();
|
||||
m_expressions.pop_back();
|
||||
return result;
|
||||
}
|
||||
|
||||
std::vector<Result> m_expressions;
|
||||
VolatileMemoryLocations _volatileMemoryLocations;
|
||||
Module *_module;
|
||||
int _returnAddress;
|
||||
|
@ -769,33 +783,8 @@ protected:
|
|||
bool _onoff;
|
||||
};
|
||||
|
||||
class RecursionDepthCheck {
|
||||
public:
|
||||
RecursionDepthCheck(Codegen *cg, const AST::SourceLocation &loc)
|
||||
: _cg(cg)
|
||||
{
|
||||
#ifdef QT_NO_DEBUG
|
||||
const int depthLimit = 4000; // limit to ~1000 deep
|
||||
#else
|
||||
const int depthLimit = 1000; // limit to ~250 deep
|
||||
#endif // QT_NO_DEBUG
|
||||
|
||||
++_cg->_recursionDepth;
|
||||
if (_cg->_recursionDepth > depthLimit)
|
||||
_cg->throwSyntaxError(loc, QStringLiteral("Maximum statement or expression depth exceeded"));
|
||||
}
|
||||
|
||||
~RecursionDepthCheck()
|
||||
{ --_cg->_recursionDepth; }
|
||||
|
||||
private:
|
||||
Codegen *_cg;
|
||||
};
|
||||
int _recursionDepth = 0;
|
||||
friend class RecursionDepthCheck;
|
||||
|
||||
private:
|
||||
VolatileMemoryLocations scanVolatileMemoryLocations(AST::Node *ast) const;
|
||||
VolatileMemoryLocations scanVolatileMemoryLocations(AST::Node *ast);
|
||||
void handleConstruct(const Reference &base, AST::ArgumentList *args);
|
||||
};
|
||||
|
||||
|
|
|
@ -50,6 +50,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>
|
||||
|
@ -167,6 +169,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;
|
||||
}
|
||||
}
|
||||
|
@ -269,6 +273,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;
|
||||
|
|
|
@ -79,7 +79,7 @@ QT_BEGIN_NAMESPACE
|
|||
// Also change the comment behind the number to describe the latest change. This has the added
|
||||
// benefit that if another patch changes the version too, it will result in a merge conflict, and
|
||||
// not get removed silently.
|
||||
#define QV4_DATA_STRUCTURE_VERSION 0x1c // Add trace slot to UPlus
|
||||
#define QV4_DATA_STRUCTURE_VERSION 0x22 // Add trace slot to UPlus
|
||||
|
||||
class QIODevice;
|
||||
class QQmlPropertyData;
|
||||
|
@ -165,9 +165,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 {
|
||||
|
@ -292,29 +293,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]
|
||||
|
@ -322,9 +310,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(); }
|
||||
|
@ -335,11 +320,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);
|
||||
|
@ -349,7 +332,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 {
|
||||
|
|
|
@ -154,11 +154,6 @@ int QV4::Compiler::JSUnitGenerator::registerSetterLookup(int nameIndex)
|
|||
return lookups.size() - 1;
|
||||
}
|
||||
|
||||
int QV4::Compiler::JSUnitGenerator::registerGlobalGetterLookup(const QString &name)
|
||||
{
|
||||
return registerGlobalGetterLookup(registerString(name));
|
||||
}
|
||||
|
||||
int QV4::Compiler::JSUnitGenerator::registerGlobalGetterLookup(int nameIndex)
|
||||
{
|
||||
CompiledData::Lookup l;
|
||||
|
@ -168,6 +163,15 @@ int QV4::Compiler::JSUnitGenerator::registerGlobalGetterLookup(int nameIndex)
|
|||
return lookups.size() - 1;
|
||||
}
|
||||
|
||||
int QV4::Compiler::JSUnitGenerator::registerQmlContextPropertyGetterLookup(int nameIndex)
|
||||
{
|
||||
CompiledData::Lookup l;
|
||||
l.type_and_flags = CompiledData::Lookup::Type_QmlContextPropertyGetter;
|
||||
l.nameIndex = nameIndex;
|
||||
lookups << l;
|
||||
return lookups.size() - 1;
|
||||
}
|
||||
|
||||
int QV4::Compiler::JSUnitGenerator::registerRegExp(QQmlJS::AST::RegExpLiteral *regexp)
|
||||
{
|
||||
CompiledData::RegExp re;
|
||||
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -57,7 +57,8 @@ using namespace QV4::Compiler;
|
|||
using namespace QQmlJS::AST;
|
||||
|
||||
ScanFunctions::ScanFunctions(Codegen *cg, const QString &sourceCode, ContextType defaultProgramType)
|
||||
: _cg(cg)
|
||||
: QQmlJS::AST::Visitor(cg->recursionDepth())
|
||||
, _cg(cg)
|
||||
, _sourceCode(sourceCode)
|
||||
, _context(nullptr)
|
||||
, _allowFuncDecls(true)
|
||||
|
@ -96,25 +97,6 @@ void ScanFunctions::leaveEnvironment()
|
|||
_context = _contextStack.isEmpty() ? nullptr : _contextStack.top();
|
||||
}
|
||||
|
||||
bool ScanFunctions::preVisit(Node *ast)
|
||||
{
|
||||
if (_cg->hasError)
|
||||
return false;
|
||||
++_recursionDepth;
|
||||
|
||||
if (_recursionDepth > 1000) {
|
||||
_cg->throwSyntaxError(ast->lastSourceLocation(), QStringLiteral("Maximum statement or expression depth exceeded"));
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void ScanFunctions::postVisit(Node *)
|
||||
{
|
||||
--_recursionDepth;
|
||||
}
|
||||
|
||||
void ScanFunctions::checkDirectivePrologue(StatementList *ast)
|
||||
{
|
||||
for (StatementList *it = ast; it; it = it->next) {
|
||||
|
@ -893,3 +875,8 @@ void ScanFunctions::calcEscapingVariables()
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ScanFunctions::throwRecursionDepthError()
|
||||
{
|
||||
_cg->throwRecursionDepthError();
|
||||
}
|
||||
|
|
|
@ -96,9 +96,6 @@ protected:
|
|||
using Visitor::visit;
|
||||
using Visitor::endVisit;
|
||||
|
||||
bool preVisit(AST::Node *ast) override;
|
||||
void postVisit(AST::Node *) override;
|
||||
|
||||
void checkDirectivePrologue(AST::StatementList *ast);
|
||||
|
||||
void checkName(const QStringRef &name, const AST::SourceLocation &loc);
|
||||
|
@ -160,6 +157,8 @@ protected:
|
|||
bool visit(AST::WithStatement *ast) override;
|
||||
void endVisit(AST::WithStatement *ast) override;
|
||||
|
||||
void throwRecursionDepthError() override;
|
||||
|
||||
protected:
|
||||
bool enterFunction(AST::Node *ast, const QString &name, AST::FormalParameterList *formals, AST::StatementList *body, bool enterName);
|
||||
|
||||
|
@ -173,8 +172,6 @@ protected:
|
|||
bool _allowFuncDecls;
|
||||
ContextType defaultProgramType;
|
||||
|
||||
unsigned _recursionDepth = 0;
|
||||
|
||||
private:
|
||||
static constexpr AST::Node *astNodeForGlobalEnvironment = nullptr;
|
||||
};
|
||||
|
|
|
@ -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)
|
||||
|
@ -730,14 +708,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)
|
||||
|
|
|
@ -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) \
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -27,7 +27,7 @@
|
|||
|
||||
/*!
|
||||
\qmlmodule QtQml.StateMachine 1.\QtMinorVersion
|
||||
\title Declarative State Machine QML Types
|
||||
\title Qt QML State Machine QML Types
|
||||
\brief Provides QML types to create and execute state graphs.
|
||||
|
||||
The following is a list of QML types provided by the module:
|
||||
|
@ -322,7 +322,7 @@
|
|||
\section1 Related Information
|
||||
|
||||
\list
|
||||
\li \l{Declarative State Machine QML Types}
|
||||
\li \l{Qt QML State Machine QML Types}
|
||||
\li \l{The State Machine Framework}
|
||||
\endlist
|
||||
*/
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -213,6 +213,14 @@ void BaselineJIT::generate_LoadGlobalLookup(int index, int /*traceSlot*/)
|
|||
BASELINEJIT_GENERATE_RUNTIME_CALL(LoadGlobalLookup, CallResultDestination::InAccumulator);
|
||||
}
|
||||
|
||||
void BaselineJIT::generate_LoadQmlContextPropertyLookup(int index, int /*traceSlot*/)
|
||||
{
|
||||
as->prepareCallWithArgCount(2);
|
||||
as->passInt32AsArg(index, 1);
|
||||
as->passEngineAsArg(0);
|
||||
BASELINEJIT_GENERATE_RUNTIME_CALL(LoadQmlContextPropertyLookup, CallResultDestination::InAccumulator);
|
||||
}
|
||||
|
||||
void BaselineJIT::generate_StoreNameSloppy(int name)
|
||||
{
|
||||
STORE_IP();
|
||||
|
@ -329,61 +337,6 @@ void BaselineJIT::generate_StoreSuperProperty(int property)
|
|||
BASELINEJIT_GENERATE_RUNTIME_CALL(StoreSuperProperty, CallResultDestination::Ignore);
|
||||
}
|
||||
|
||||
|
||||
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(StoreQmlScopeObjectProperty, CallResultDestination::Ignore);
|
||||
}
|
||||
|
||||
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(StoreQmlContextObjectProperty, CallResultDestination::Ignore);
|
||||
}
|
||||
|
||||
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(LoadQmlScopeObjectProperty, CallResultDestination::InAccumulator);
|
||||
}
|
||||
|
||||
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(LoadQmlContextObjectProperty, CallResultDestination::InAccumulator);
|
||||
}
|
||||
|
||||
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(LoadQmlIdObject, CallResultDestination::InAccumulator);
|
||||
}
|
||||
|
||||
void BaselineJIT::generate_Yield()
|
||||
{
|
||||
// #####
|
||||
|
@ -493,31 +446,18 @@ void BaselineJIT::generate_CallGlobalLookup(int index, int argc, int argv, int /
|
|||
BASELINEJIT_GENERATE_RUNTIME_CALL(CallGlobalLookup, CallResultDestination::InAccumulator);
|
||||
}
|
||||
|
||||
void BaselineJIT::generate_CallScopeObjectProperty(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(CallQmlScopeObjectProperty, CallResultDestination::InAccumulator);
|
||||
BASELINEJIT_GENERATE_RUNTIME_CALL(CallQmlContextPropertyLookup, CallResultDestination::InAccumulator);
|
||||
}
|
||||
|
||||
void BaselineJIT::generate_CallContextObjectProperty(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(CallQmlContextObjectProperty, CallResultDestination::InAccumulator);
|
||||
}
|
||||
|
||||
|
||||
void BaselineJIT::generate_CallWithSpread(int func, int thisObject, int argc, int argv, int /*traceSlot*/)
|
||||
{
|
||||
STORE_IP();
|
||||
|
@ -937,22 +877,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(LoadQmlContext, CallResultDestination::InAccumulator);
|
||||
as->storeReg(result);
|
||||
}
|
||||
|
||||
void BaselineJIT::generate_LoadQmlImportedScripts(int result)
|
||||
{
|
||||
as->prepareCallWithArgCount(1);
|
||||
as->passEngineAsArg(0);
|
||||
BASELINEJIT_GENERATE_RUNTIME_CALL(LoadQmlImportedScripts, CallResultDestination::InAccumulator);
|
||||
as->storeReg(result);
|
||||
}
|
||||
|
||||
void BaselineJIT::generate_InitializeBlockDeadTemporalZone(int firstReg, int count)
|
||||
{
|
||||
as->loadValue(Value::emptyValue().rawValue());
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -800,45 +800,10 @@ void GraphBuilder::generate_StoreSuperProperty(int property)
|
|||
env()->accumulator());
|
||||
}
|
||||
|
||||
void GraphBuilder::generate_StoreScopeObjectProperty(int base, int propertyIndex)
|
||||
void GraphBuilder::generate_LoadQmlContextPropertyLookup(int propertyIndex, int /*traceSlot*/)
|
||||
{
|
||||
createNode(opBuilder()->get<Meta::QMLStoreScopeObjectProperty>(),
|
||||
env()->slot(base),
|
||||
createConstant(propertyIndex),
|
||||
env()->accumulator());
|
||||
}
|
||||
|
||||
void GraphBuilder::generate_StoreContextObjectProperty(int base, int propertyIndex)
|
||||
{
|
||||
createNode(opBuilder()->get<Meta::QMLStoreContextObjectProperty>(),
|
||||
env()->slot(base),
|
||||
createConstant(propertyIndex),
|
||||
env()->accumulator());
|
||||
}
|
||||
|
||||
void GraphBuilder::generate_LoadScopeObjectProperty(int propertyIndex, int base,
|
||||
int captureRequired)
|
||||
{
|
||||
bindAcc(createNode(opBuilder()->get<Meta::QMLLoadScopeObjectProperty>(),
|
||||
env()->slot(base),
|
||||
createConstant(propertyIndex),
|
||||
createConstant(captureRequired)));
|
||||
}
|
||||
|
||||
void GraphBuilder::generate_LoadContextObjectProperty(int propertyIndex, int base,
|
||||
int captureRequired)
|
||||
{
|
||||
bindAcc(createNode(opBuilder()->get<Meta::QMLLoadContextObjectProperty>(),
|
||||
env()->slot(base),
|
||||
createConstant(propertyIndex),
|
||||
createConstant(captureRequired)));
|
||||
}
|
||||
|
||||
void GraphBuilder::generate_LoadIdObject(int index, int base)
|
||||
{
|
||||
bindAcc(createNode(opBuilder()->get<Meta::QMLLoadIdObject>(),
|
||||
env()->slot(base),
|
||||
createConstant(index)));
|
||||
bindAcc(createNode(opBuilder()->get<Meta::QMLLoadQmlContextPropertyLookup>(),
|
||||
createConstant(propertyIndex)));
|
||||
}
|
||||
|
||||
void GraphBuilder::generate_Yield() { Q_UNREACHABLE(); }
|
||||
|
@ -913,22 +878,12 @@ void GraphBuilder::generate_CallGlobalLookup(int index, int argc, int argv, int
|
|||
finalizeCall(Meta::JSCallGlobalLookup, args, argc, argv);
|
||||
}
|
||||
|
||||
void GraphBuilder::generate_CallScopeObjectProperty(int propIdx, int base, int argc, int argv,
|
||||
int /*traceSlot*/)
|
||||
void GraphBuilder::generate_CallQmlContextPropertyLookup(int index, int argc, int argv,
|
||||
int /*traceSlot*/)
|
||||
{
|
||||
VarArgNodes args;
|
||||
args.append(env()->slot(base));
|
||||
args.append(createConstant(propIdx));
|
||||
finalizeCall(Meta::QMLCallScopeObjectProperty, args, argc, argv);
|
||||
}
|
||||
|
||||
void GraphBuilder::generate_CallContextObjectProperty(int propIdx, int base, int argc, int argv,
|
||||
int /*traceSlot*/)
|
||||
{
|
||||
VarArgNodes args;
|
||||
args.append(env()->slot(base));
|
||||
args.append(createConstant(propIdx));
|
||||
finalizeCall(Meta::QMLCallContextObjectProperty, args, argc, argv);
|
||||
args.append(createConstant(index));
|
||||
finalizeCall(Meta::QMLCallQmlContextPropertyLookup, args, argc, argv);
|
||||
}
|
||||
|
||||
void GraphBuilder::generate_SetUnwindHandler(int offset)
|
||||
|
@ -1636,17 +1591,6 @@ void GraphBuilder::generate_Sub(int lhs, int /*traceSlot*/)
|
|||
env()->accumulator()));
|
||||
}
|
||||
|
||||
void GraphBuilder::generate_LoadQmlContext(int result)
|
||||
{
|
||||
env()->bindNodeToSlot(createNode(opBuilder()->get<Meta::QMLLoadContext>()), result);
|
||||
}
|
||||
|
||||
void GraphBuilder::generate_LoadQmlImportedScripts(int result)
|
||||
{
|
||||
env()->bindNodeToSlot(createNode(opBuilder()->get<Meta::QMLLoadImportedScripts>()),
|
||||
result);
|
||||
}
|
||||
|
||||
void GraphBuilder::generate_InitializeBlockDeadTemporalZone(int firstReg, int count)
|
||||
{
|
||||
for (int reg = firstReg; reg < firstReg + count; ++reg)
|
||||
|
|
|
@ -173,15 +173,7 @@ protected: // ByteCodeHandler
|
|||
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_LoadQmlContextPropertyLookup(int property, int traceSlot) override;
|
||||
void generate_Yield() override;
|
||||
void generate_YieldStar() override;
|
||||
void generate_Resume(int offset) override;
|
||||
|
@ -196,10 +188,7 @@ protected: // ByteCodeHandler
|
|||
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_SetUnwindHandler(int offset) override;
|
||||
void generate_UnwindDispatch() override;
|
||||
void generate_UnwindToLabel(int level, int offset) override;
|
||||
|
@ -284,8 +273,6 @@ protected: // ByteCodeHandler
|
|||
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;
|
||||
|
|
|
@ -223,11 +223,7 @@ inline Operation *createOperation(Operation::Kind kind, QQmlJS::MemoryPool *stat
|
|||
case K::JSDeleteName: return get(1, 1, 1, 1, 1, 2, any, F::CanThrow);
|
||||
case K::JSIn: return get(2, 1, 1, 1, 1, 2, any, F::CanThrow);
|
||||
case K::JSInstanceOf: return get(2, 1, 1, 1, 1, 2, any, F::CanThrow);
|
||||
case K::QMLLoadScopeObjectProperty: return get(3, 1, 1, 1, 1, 2, any, F::CanThrow);
|
||||
case K::QMLStoreScopeObjectProperty: return get(3, 1, 1, 0, 1, 2, none, F::CanThrow);
|
||||
case K::QMLLoadContextObjectProperty: return get(3, 1, 1, 1, 1, 2, any, F::CanThrow);
|
||||
case K::QMLStoreContextObjectProperty: return get(3, 1, 1, 1, 1, 2, none, F::CanThrow);
|
||||
case K::QMLLoadIdObject: return get(2, 1, 1, 1, 1, 2, any, F::CanThrow);
|
||||
case K::QMLLoadQmlContextPropertyLookup: return get(1, 1, 1, 1, 1, 2, any, F::CanThrow);
|
||||
|
||||
case K::JSEqual: return get(2, 1, 1, 1, 1, 2, boolean, F::CanThrow);
|
||||
case K::JSGreaterThan: return get(2, 1, 1, 1, 1, 2, boolean, F::CanThrow);
|
||||
|
@ -263,8 +259,6 @@ inline Operation *createOperation(Operation::Kind kind, QQmlJS::MemoryPool *stat
|
|||
case K::JSTypeofValue: return get(1, 0, 0, 1, 0, 0, any, F::Pure);
|
||||
case K::JSDeclareVar: return get(2, 1, 1, 1, 1, 2, any, F::CanThrow);
|
||||
case K::JSDestructureRestElement: return get(1, 1, 1, 1, 1, 2, any, F::CanThrow);
|
||||
case K::QMLLoadContext: return get(0, 0, 0, 1, 0, 0, any, F::NoFlags);
|
||||
case K::QMLLoadImportedScripts: return get(0, 0, 0, 1, 0, 0, any, F::NoFlags);
|
||||
|
||||
case K::JSCreateCallContext: return get(0, 1, 1, 0, 1, 1, none, F::NoFlags);
|
||||
case K::JSCreateCatchContext: return get(2, 1, 1, 1, 1, 1, none, F::NoFlags);
|
||||
|
@ -518,18 +512,12 @@ static ReturnValue operateOnRuntimeCall(Operation::Kind kind, bool abortOnMissin
|
|||
case K::JSDeleteName: return M<R::DeleteName>::doIt();
|
||||
case K::JSIn: return M<R::In>::doIt();
|
||||
case K::JSInstanceOf: return M<R::Instanceof>::doIt();
|
||||
case K::QMLLoadScopeObjectProperty: return M<R::LoadQmlScopeObjectProperty>::doIt();
|
||||
case K::QMLStoreScopeObjectProperty: return M<R::StoreQmlScopeObjectProperty>::doIt();
|
||||
case K::QMLLoadContextObjectProperty: return M<R::LoadQmlContextObjectProperty>::doIt();
|
||||
case K::QMLStoreContextObjectProperty: return M<R::StoreQmlContextObjectProperty>::doIt();
|
||||
case K::QMLLoadIdObject: return M<R::LoadQmlIdObject>::doIt();
|
||||
case K::QMLLoadQmlContextPropertyLookup: return M<R::LoadQmlContextPropertyLookup>::doIt();
|
||||
|
||||
case K::JSTypeofName: return M<R::TypeofName>::doIt();
|
||||
case K::JSTypeofValue: return M<R::TypeofValue>::doIt();
|
||||
case K::JSDeclareVar: return M<R::DeclareVar>::doIt();
|
||||
case K::JSDestructureRestElement: return M<R::DestructureRestElement>::doIt();
|
||||
case K::QMLLoadContext: return M<R::LoadQmlContext>::doIt();
|
||||
case K::QMLLoadImportedScripts: return M<R::LoadQmlImportedScripts>::doIt();
|
||||
case K::JSThisToObject: return M<R::ConvertThisToObject>::doIt();
|
||||
case K::JSCreateMappedArgumentsObject: return M<R::CreateMappedArgumentsObject>::doIt();
|
||||
case K::JSCreateUnmappedArgumentsObject: return M<R::CreateUnmappedArgumentsObject>::doIt();
|
||||
|
|
|
@ -123,12 +123,10 @@ enum OpKind: uint16_t {
|
|||
JSDeleteName,
|
||||
JSIn,
|
||||
JSInstanceOf,
|
||||
/* ok, these are qml object ops, but we don't care for now and treat them a s JS */
|
||||
QMLLoadScopeObjectProperty,
|
||||
QMLStoreScopeObjectProperty,
|
||||
QMLLoadContextObjectProperty,
|
||||
QMLStoreContextObjectProperty,
|
||||
QMLLoadIdObject,
|
||||
|
||||
/* ok, these are qml object ops, but we don't care for now and treat them as JS */
|
||||
QMLLoadQmlContextPropertyLookup,
|
||||
QMLCallQmlContextPropertyLookup,
|
||||
|
||||
JSEqual,
|
||||
JSGreaterThan,
|
||||
|
@ -168,16 +166,11 @@ enum OpKind: uint16_t {
|
|||
JSCreateClass,
|
||||
JSConstruct,
|
||||
JSConstructWithSpread,
|
||||
/* ok, these are qml vararg calls, but we don't care for now and treat them as JS */
|
||||
QMLCallScopeObjectProperty,
|
||||
QMLCallContextObjectProperty,
|
||||
|
||||
JSTypeofName,
|
||||
JSTypeofValue,
|
||||
JSDeclareVar,
|
||||
JSDestructureRestElement,
|
||||
QMLLoadContext,
|
||||
QMLLoadImportedScripts,
|
||||
JSThisToObject,
|
||||
JSCreateMappedArgumentsObject,
|
||||
JSCreateUnmappedArgumentsObject,
|
||||
|
|
|
@ -1189,6 +1189,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);
|
||||
|
|
|
@ -572,6 +572,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);
|
||||
|
|
|
@ -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));
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -69,37 +69,7 @@ void Lookup::resolveProtoGetter(PropertyKey name, const Heap::Object *proto)
|
|||
|
||||
ReturnedValue Lookup::resolveGetter(ExecutionEngine *engine, const Object *object)
|
||||
{
|
||||
Heap::Object *obj = object->d();
|
||||
PropertyKey name = engine->identifierTable->asPropertyKey(engine->currentStackFrame->v4Function->compilationUnit->runtimeStrings[nameIndex]);
|
||||
if (name.isArrayIndex()) {
|
||||
indexedLookup.index = name.asArrayIndex();
|
||||
getter = getterIndexed;
|
||||
return getter(this, engine, *object);
|
||||
}
|
||||
|
||||
auto index = obj->internalClass->findValueOrGetter(name);
|
||||
if (index.isValid()) {
|
||||
PropertyAttributes attrs = index.attrs;
|
||||
uint nInline = obj->vtable()->nInlineProperties;
|
||||
if (attrs.isData()) {
|
||||
if (index.index < obj->vtable()->nInlineProperties) {
|
||||
index.index += obj->vtable()->inlinePropertyOffset;
|
||||
getter = getter0Inline;
|
||||
} else {
|
||||
index.index -= nInline;
|
||||
getter = getter0MemberData;
|
||||
}
|
||||
} else {
|
||||
getter = getterAccessor;
|
||||
}
|
||||
objectLookup.ic = obj->internalClass;
|
||||
objectLookup.offset = index.index;
|
||||
return getter(this, engine, *object);
|
||||
}
|
||||
|
||||
protoLookup.protoId = obj->internalClass->protoId;
|
||||
resolveProtoGetter(name, obj->prototype());
|
||||
return getter(this, engine, *object);
|
||||
return object->resolveLookupGetter(engine, this);
|
||||
}
|
||||
|
||||
ReturnedValue Lookup::resolvePrimitiveGetter(ExecutionEngine *engine, const Value &object)
|
||||
|
@ -409,7 +379,7 @@ ReturnedValue Lookup::getterIndexed(Lookup *l, ExecutionEngine *engine, const Va
|
|||
|
||||
ReturnedValue Lookup::primitiveGetterProto(Lookup *l, ExecutionEngine *engine, const Value &object)
|
||||
{
|
||||
if (object.type() == l->primitiveLookup.type) {
|
||||
if (object.type() == l->primitiveLookup.type && !object.isObject()) {
|
||||
Heap::Object *o = l->primitiveLookup.proto;
|
||||
if (l->primitiveLookup.protoId == o->internalClass->protoId)
|
||||
return l->primitiveLookup.data->asReturnedValue();
|
||||
|
@ -420,7 +390,7 @@ ReturnedValue Lookup::primitiveGetterProto(Lookup *l, ExecutionEngine *engine, c
|
|||
|
||||
ReturnedValue Lookup::primitiveGetterAccessor(Lookup *l, ExecutionEngine *engine, const Value &object)
|
||||
{
|
||||
if (object.type() == l->primitiveLookup.type) {
|
||||
if (object.type() == l->primitiveLookup.type && !object.isObject()) {
|
||||
Heap::Object *o = l->primitiveLookup.proto;
|
||||
if (l->primitiveLookup.protoId == o->internalClass->protoId) {
|
||||
const Value *getter = l->primitiveLookup.data;
|
||||
|
@ -473,56 +443,7 @@ ReturnedValue Lookup::globalGetterProtoAccessor(Lookup *l, ExecutionEngine *engi
|
|||
|
||||
bool Lookup::resolveSetter(ExecutionEngine *engine, Object *object, const Value &value)
|
||||
{
|
||||
Scope scope(engine);
|
||||
ScopedString name(scope, scope.engine->currentStackFrame->v4Function->compilationUnit->runtimeStrings[nameIndex]);
|
||||
|
||||
Heap::InternalClass *c = object->internalClass();
|
||||
PropertyKey key = name->toPropertyKey();
|
||||
auto idx = c->findValueOrSetter(key);
|
||||
if (idx.isValid()) {
|
||||
if (object->isArrayObject() && idx.index == Heap::ArrayObject::LengthPropertyIndex) {
|
||||
Q_ASSERT(!idx.attrs.isAccessor());
|
||||
setter = arrayLengthSetter;
|
||||
return setter(this, engine, *object, value);
|
||||
} else if (idx.attrs.isData() && idx.attrs.isWritable()) {
|
||||
objectLookup.ic = object->internalClass();
|
||||
objectLookup.index = idx.index;
|
||||
const auto nInline = object->d()->vtable()->nInlineProperties;
|
||||
if (idx.index < nInline) {
|
||||
setter = Lookup::setter0Inline;
|
||||
objectLookup.offset = idx.index + object->d()->vtable()->inlinePropertyOffset;
|
||||
} else {
|
||||
setter = Lookup::setter0MemberData;
|
||||
objectLookup.offset = idx.index - nInline;
|
||||
}
|
||||
return setter(this, engine, *object, value);
|
||||
} else {
|
||||
// ### handle setter
|
||||
setter = setterFallback;
|
||||
}
|
||||
return setter(this, engine, *object, value);
|
||||
}
|
||||
|
||||
insertionLookup.protoId = c->protoId;
|
||||
if (!object->put(key, value)) {
|
||||
setter = Lookup::setterFallback;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (object->internalClass() == c) {
|
||||
// ### setter in the prototype, should handle this
|
||||
setter = setterFallback;
|
||||
return true;
|
||||
}
|
||||
idx = object->internalClass()->findValueOrSetter(key);
|
||||
if (!idx.isValid() || idx.attrs.isAccessor()) { // ### can this even happen?
|
||||
setter = setterFallback;
|
||||
return false;
|
||||
}
|
||||
insertionLookup.newClass = object->internalClass();
|
||||
insertionLookup.offset = idx.index;
|
||||
setter = setterInsert;
|
||||
return true;
|
||||
return object->resolveLookupSetter(engine, this, value);
|
||||
}
|
||||
|
||||
bool Lookup::setterGeneric(Lookup *l, ExecutionEngine *engine, Value &object, const Value &value)
|
||||
|
|
|
@ -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;
|
||||
|
@ -119,6 +121,39 @@ struct Lookup {
|
|||
uint index;
|
||||
uint unused;
|
||||
} 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;
|
||||
|
||||
|
|
|
@ -320,8 +320,11 @@ bool Object::virtualDeleteProperty(Managed *m, PropertyKey id)
|
|||
PropertyKey ObjectOwnPropertyKeyIterator::next(const Object *o, Property *pd, PropertyAttributes *attrs)
|
||||
{
|
||||
if (arrayIndex != UINT_MAX && o->arrayData()) {
|
||||
if (!arrayIndex)
|
||||
arrayNode = o->sparseBegin();
|
||||
SparseArrayNode *arrayNode = nullptr;
|
||||
if (o->arrayType() == Heap::ArrayData::Sparse) {
|
||||
SparseArray *sparse = o->arrayData()->sparse;
|
||||
arrayNode = arrayIndex ? sparse->lowerBound(arrayIndex) : sparse->begin();
|
||||
}
|
||||
|
||||
// sparse arrays
|
||||
if (arrayNode) {
|
||||
|
@ -339,7 +342,6 @@ PropertyKey ObjectOwnPropertyKeyIterator::next(const Object *o, Property *pd, Pr
|
|||
*attrs = a;
|
||||
return PropertyKey::fromArrayIndex(k);
|
||||
}
|
||||
arrayNode = nullptr;
|
||||
arrayIndex = UINT_MAX;
|
||||
}
|
||||
// dense arrays
|
||||
|
@ -734,6 +736,95 @@ ReturnedValue Object::virtualInstanceOf(const Object *typeObject, const Value &v
|
|||
return checkedInstanceOf(engine, function, var);
|
||||
}
|
||||
|
||||
ReturnedValue Object::virtualResolveLookupGetter(const Object *object, ExecutionEngine *engine, Lookup *lookup)
|
||||
{
|
||||
Heap::Object *obj = object->d();
|
||||
PropertyKey name = engine->identifierTable->asPropertyKey(engine->currentStackFrame->v4Function->compilationUnit->runtimeStrings[lookup->nameIndex]);
|
||||
if (name.isArrayIndex()) {
|
||||
lookup->indexedLookup.index = name.asArrayIndex();
|
||||
lookup->getter = Lookup::getterIndexed;
|
||||
return lookup->getter(lookup, engine, *object);
|
||||
}
|
||||
|
||||
auto index = obj->internalClass->findValueOrGetter(name);
|
||||
if (index.isValid()) {
|
||||
PropertyAttributes attrs = index.attrs;
|
||||
uint nInline = obj->vtable()->nInlineProperties;
|
||||
if (attrs.isData()) {
|
||||
if (index.index < obj->vtable()->nInlineProperties) {
|
||||
index.index += obj->vtable()->inlinePropertyOffset;
|
||||
lookup->getter = Lookup::getter0Inline;
|
||||
} else {
|
||||
index.index -= nInline;
|
||||
lookup->getter = Lookup::getter0MemberData;
|
||||
}
|
||||
} else {
|
||||
lookup->getter = Lookup::getterAccessor;
|
||||
}
|
||||
lookup->objectLookup.ic = obj->internalClass;
|
||||
lookup->objectLookup.offset = index.index;
|
||||
return lookup->getter(lookup, engine, *object);
|
||||
}
|
||||
|
||||
lookup->protoLookup.protoId = obj->internalClass->protoId;
|
||||
lookup->resolveProtoGetter(name, obj->prototype());
|
||||
return lookup->getter(lookup, engine, *object);
|
||||
}
|
||||
|
||||
bool Object::virtualResolveLookupSetter(Object *object, ExecutionEngine *engine, Lookup *lookup, const Value &value)
|
||||
{
|
||||
Scope scope(engine);
|
||||
ScopedString name(scope, scope.engine->currentStackFrame->v4Function->compilationUnit->runtimeStrings[lookup->nameIndex]);
|
||||
|
||||
Heap::InternalClass *c = object->internalClass();
|
||||
PropertyKey key = name->toPropertyKey();
|
||||
auto idx = c->findValueOrSetter(key);
|
||||
if (idx.isValid()) {
|
||||
if (object->isArrayObject() && idx.index == Heap::ArrayObject::LengthPropertyIndex) {
|
||||
Q_ASSERT(!idx.attrs.isAccessor());
|
||||
lookup->setter = Lookup::arrayLengthSetter;
|
||||
return lookup->setter(lookup, engine, *object, value);
|
||||
} else if (idx.attrs.isData() && idx.attrs.isWritable()) {
|
||||
lookup->objectLookup.ic = object->internalClass();
|
||||
lookup->objectLookup.index = idx.index;
|
||||
const auto nInline = object->d()->vtable()->nInlineProperties;
|
||||
if (idx.index < nInline) {
|
||||
lookup->setter = Lookup::setter0Inline;
|
||||
lookup->objectLookup.offset = idx.index + object->d()->vtable()->inlinePropertyOffset;
|
||||
} else {
|
||||
lookup->setter = Lookup::setter0MemberData;
|
||||
lookup->objectLookup.offset = idx.index - nInline;
|
||||
}
|
||||
return lookup->setter(lookup, engine, *object, value);
|
||||
} else {
|
||||
// ### handle setter
|
||||
lookup->setter = Lookup::setterFallback;
|
||||
}
|
||||
return lookup->setter(lookup, engine, *object, value);
|
||||
}
|
||||
|
||||
lookup->insertionLookup.protoId = c->protoId;
|
||||
if (!object->put(key, value)) {
|
||||
lookup->setter = Lookup::setterFallback;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (object->internalClass() == c) {
|
||||
// ### setter in the prototype, should handle this
|
||||
lookup->setter = Lookup::setterFallback;
|
||||
return true;
|
||||
}
|
||||
idx = object->internalClass()->findValueOrSetter(key);
|
||||
if (!idx.isValid() || idx.attrs.isAccessor()) { // ### can this even happen?
|
||||
lookup->setter = Lookup::setterFallback;
|
||||
return false;
|
||||
}
|
||||
lookup->insertionLookup.newClass = object->internalClass();
|
||||
lookup->insertionLookup.offset = idx.index;
|
||||
lookup->setter = Lookup::setterInsert;
|
||||
return true;
|
||||
}
|
||||
|
||||
ReturnedValue Object::checkedInstanceOf(ExecutionEngine *engine, const FunctionObject *f, const Value &var)
|
||||
{
|
||||
Scope scope(engine);
|
||||
|
|
|
@ -375,6 +375,11 @@ public:
|
|||
|
||||
bool setProtoFromNewTarget(const Value *newTarget);
|
||||
|
||||
ReturnedValue resolveLookupGetter(ExecutionEngine *engine, Lookup *lookup) const
|
||||
{ return vtable()->resolveLookupGetter(this, engine, lookup); }
|
||||
ReturnedValue resolveLookupSetter(ExecutionEngine *engine, Lookup *lookup, const Value &value)
|
||||
{ return vtable()->resolveLookupSetter(this, engine, lookup, 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);
|
||||
|
@ -389,6 +394,8 @@ protected:
|
|||
static OwnPropertyKeyIterator *virtualOwnPropertyKeys(const Object *m, Value *target);
|
||||
static qint64 virtualGetLength(const Managed *m);
|
||||
static ReturnedValue virtualInstanceOf(const Object *typeObject, const Value &var);
|
||||
static ReturnedValue virtualResolveLookupGetter(const Object *object, ExecutionEngine *engine, Lookup *lookup);
|
||||
static bool virtualResolveLookupSetter(Object *object, ExecutionEngine *engine, Lookup *lookup, const Value &value);
|
||||
public:
|
||||
// qv4runtime uses this directly
|
||||
static ReturnedValue checkedInstanceOf(ExecutionEngine *engine, const FunctionObject *typeObject, const Value &var);
|
||||
|
@ -408,7 +415,6 @@ struct ObjectOwnPropertyKeyIterator : OwnPropertyKeyIterator
|
|||
uint arrayIndex = 0;
|
||||
uint memberIndex = 0;
|
||||
bool iterateOverSymbols = false;
|
||||
SparseArrayNode *arrayNode = nullptr;
|
||||
~ObjectOwnPropertyKeyIterator() override = default;
|
||||
PropertyKey next(const Object *o, Property *pd = nullptr, PropertyAttributes *attrs = nullptr) override;
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
@ -1923,13 +1990,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();
|
||||
}
|
||||
|
||||
|
|
|
@ -60,6 +60,7 @@
|
|||
|
||||
#include <private/qv4value_p.h>
|
||||
#include <private/qv4functionobject_p.h>
|
||||
#include <private/qv4lookup_p.h>
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
|
||||
|
@ -165,7 +166,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);
|
||||
|
||||
|
@ -174,13 +175,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);
|
||||
|
||||
|
@ -216,6 +222,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
|
||||
|
@ -226,7 +273,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(); }
|
||||
|
|
|
@ -1130,6 +1130,12 @@ ReturnedValue Runtime::LoadGlobalLookup::call(ExecutionEngine *engine, Function
|
|||
return l->globalGetter(l, engine);
|
||||
}
|
||||
|
||||
ReturnedValue Runtime::LoadQmlContextPropertyLookup::call(ExecutionEngine *engine, uint index)
|
||||
{
|
||||
Lookup *l = engine->currentStackFrame->v4Function->compilationUnit->runtimeLookups + index;
|
||||
return l->qmlContextPropertyGetter(l, engine, nullptr);
|
||||
}
|
||||
|
||||
ReturnedValue Runtime::GetLookup::call(ExecutionEngine *engine, Function *f, const Value &base, int index)
|
||||
{
|
||||
Lookup *l = f->compilationUnit->runtimeLookups + index;
|
||||
|
@ -1390,18 +1396,43 @@ uint Runtime::CompareIn::call(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::CallGlobalLookup::call(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));
|
||||
if (!function.isFunctionObject())
|
||||
return engine->throwTypeError();
|
||||
|
||||
Value thisObject = Value::undefinedValue();
|
||||
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::CallQmlContextPropertyLookup::call(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::CallPossiblyDirectEval::call(ExecutionEngine *engine, Value *argv, int argc)
|
||||
{
|
||||
Scope scope(engine);
|
||||
|
@ -1412,13 +1443,8 @@ ReturnedValue Runtime::CallPossiblyDirectEval::call(ExecutionEngine *engine, Val
|
|||
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);
|
||||
|
@ -1437,15 +1463,9 @@ ReturnedValue Runtime::CallName::call(ExecutionEngine *engine, int nameIndex, Va
|
|||
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);
|
||||
}
|
||||
|
@ -1536,41 +1556,6 @@ ReturnedValue Runtime::CallWithReceiver::call(ExecutionEngine *engine, const Val
|
|||
return static_cast<const FunctionObject &>(func).call(&thisObject, argv, argc);
|
||||
}
|
||||
|
||||
ReturnedValue Runtime::CallQmlScopeObjectProperty::call(ExecutionEngine *engine, const Value &base,
|
||||
int propertyIndex, Value argv[], int argc)
|
||||
{
|
||||
Scope scope(engine);
|
||||
ScopedFunctionObject fo(scope, LoadQmlScopeObjectProperty::call(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<const QmlContext *>(&base)->d()->qml()->scopeObject;
|
||||
ScopedValue qmlScopeValue(scope, QObjectWrapper::wrap(engine, qmlScopeObj));
|
||||
return fo->call(qmlScopeValue, argv, argc);
|
||||
}
|
||||
|
||||
ReturnedValue Runtime::CallQmlContextObjectProperty::call(ExecutionEngine *engine,
|
||||
const Value &base,
|
||||
int propertyIndex,
|
||||
Value argv[],
|
||||
int argc)
|
||||
{
|
||||
Scope scope(engine);
|
||||
ScopedFunctionObject fo(scope, LoadQmlContextObjectProperty::call(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<const 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;
|
||||
|
@ -2013,66 +1998,12 @@ QV4::ReturnedValue Runtime::CreateRestParameter::call(ExecutionEngine *engine, i
|
|||
return engine->newArrayObject(values, nValues)->asReturnedValue();
|
||||
}
|
||||
|
||||
|
||||
ReturnedValue Runtime::LoadQmlContext::call(ExecutionEngine *engine)
|
||||
{
|
||||
Heap::QmlContext *ctx = engine->qmlContext();
|
||||
Q_ASSERT(ctx);
|
||||
return ctx->asReturnedValue();
|
||||
}
|
||||
|
||||
ReturnedValue Runtime::RegexpLiteral::call(ExecutionEngine *engine, int id)
|
||||
{
|
||||
Heap::RegExpObject *ro = engine->newRegExpObject(engine->currentStackFrame->v4Function->compilationUnit->runtimeRegularExpressions[id].as<RegExp>());
|
||||
return ro->asReturnedValue();
|
||||
}
|
||||
|
||||
ReturnedValue Runtime::LoadQmlScopeObjectProperty::call(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::LoadQmlContextObjectProperty::call(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::LoadQmlIdObject::call(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::StoreQmlScopeObjectProperty::call(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::StoreQmlContextObjectProperty::call(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::LoadQmlImportedScripts::call(ExecutionEngine *engine)
|
||||
{
|
||||
QQmlContextData *context = engine->callingQmlContext();
|
||||
if (!context)
|
||||
return Encode::undefined();
|
||||
return context->importedScripts.value();
|
||||
}
|
||||
|
||||
ReturnedValue Runtime::ToObject::call(ExecutionEngine *engine, const Value &obj)
|
||||
{
|
||||
if (obj.isObject())
|
||||
|
|
|
@ -58,7 +58,6 @@ namespace QV4 {
|
|||
|
||||
typedef uint Bool;
|
||||
|
||||
|
||||
struct Q_QML_PRIVATE_EXPORT Runtime {
|
||||
typedef ReturnedValue (*UnaryOperation)(const Value &value);
|
||||
typedef ReturnedValue (*BinaryOperation)(const Value &left, const Value &right);
|
||||
|
@ -87,6 +86,10 @@ struct Q_QML_PRIVATE_EXPORT Runtime {
|
|||
{
|
||||
static ReturnedValue call(ExecutionEngine *, uint, Value[], int);
|
||||
};
|
||||
struct Q_QML_PRIVATE_EXPORT CallQmlContextPropertyLookup : Method<Throws::Yes>
|
||||
{
|
||||
static ReturnedValue call(ExecutionEngine *, uint, Value[], int);
|
||||
};
|
||||
struct Q_QML_PRIVATE_EXPORT CallName : Method<Throws::Yes>
|
||||
{
|
||||
static ReturnedValue call(ExecutionEngine *, int, Value[], int);
|
||||
|
@ -187,6 +190,10 @@ struct Q_QML_PRIVATE_EXPORT Runtime {
|
|||
{
|
||||
static ReturnedValue call(ExecutionEngine *, Function *, int);
|
||||
};
|
||||
struct Q_QML_PRIVATE_EXPORT LoadQmlContextPropertyLookup : Method<Throws::Yes>
|
||||
{
|
||||
static ReturnedValue call(ExecutionEngine *, uint);
|
||||
};
|
||||
struct Q_QML_PRIVATE_EXPORT GetLookup : Method<Throws::Yes>
|
||||
{
|
||||
static ReturnedValue call(ExecutionEngine *, Function *, const Value &, int);
|
||||
|
@ -495,45 +502,6 @@ struct Q_QML_PRIVATE_EXPORT Runtime {
|
|||
static ReturnedValue call(Function *, int);
|
||||
};
|
||||
|
||||
/* qml */
|
||||
struct Q_QML_PRIVATE_EXPORT LoadQmlContext : Method<Throws::No>
|
||||
{
|
||||
static ReturnedValue call(ExecutionEngine *);
|
||||
};
|
||||
struct Q_QML_PRIVATE_EXPORT LoadQmlImportedScripts : Method<Throws::No>
|
||||
{
|
||||
static ReturnedValue call(ExecutionEngine *);
|
||||
};
|
||||
struct Q_QML_PRIVATE_EXPORT LoadQmlScopeObjectProperty : Method<Throws::Yes>
|
||||
{
|
||||
static ReturnedValue call(ExecutionEngine *, const Value &, int, Bool);
|
||||
};
|
||||
struct Q_QML_PRIVATE_EXPORT LoadQmlContextObjectProperty : Method<Throws::Yes>
|
||||
{
|
||||
static ReturnedValue call(ExecutionEngine *, const Value &, int, Bool);
|
||||
};
|
||||
struct Q_QML_PRIVATE_EXPORT LoadQmlIdObject : Method<Throws::Yes>
|
||||
{
|
||||
static ReturnedValue call(ExecutionEngine *, const Value &, uint);
|
||||
};
|
||||
struct Q_QML_PRIVATE_EXPORT CallQmlScopeObjectProperty : Method<Throws::Yes>
|
||||
{
|
||||
static ReturnedValue call(ExecutionEngine *, const Value &, int, Value[], int);
|
||||
};
|
||||
struct Q_QML_PRIVATE_EXPORT CallQmlContextObjectProperty : Method<Throws::Yes>
|
||||
{
|
||||
static ReturnedValue call(ExecutionEngine *, const Value &, int, Value[], int);
|
||||
};
|
||||
|
||||
struct Q_QML_PRIVATE_EXPORT StoreQmlScopeObjectProperty : Method<Throws::Yes>
|
||||
{
|
||||
static void call(ExecutionEngine *, const Value &, int, const Value &);
|
||||
};
|
||||
struct Q_QML_PRIVATE_EXPORT StoreQmlContextObjectProperty : Method<Throws::Yes>
|
||||
{
|
||||
static void call(ExecutionEngine *, const Value &, int, const Value &);
|
||||
};
|
||||
|
||||
struct StackOffsets {
|
||||
static const int tailCall_function = -1;
|
||||
static const int tailCall_thisObject = -2;
|
||||
|
|
|
@ -71,6 +71,7 @@ public:
|
|||
|
||||
void throwSyntaxError(const AST::SourceLocation &loc, const QString &detail) override;
|
||||
void throwReferenceError(const AST::SourceLocation &loc, const QString &detail) override;
|
||||
|
||||
private:
|
||||
ExecutionEngine *engine;
|
||||
};
|
||||
|
|
|
@ -130,7 +130,7 @@ PropertyKey StringObjectOwnPropertyKeyIterator::next(const QV4::Object *o, Prope
|
|||
return PropertyKey::fromArrayIndex(index);
|
||||
} else if (arrayIndex == slen) {
|
||||
if (s->arrayData()) {
|
||||
arrayNode = s->sparseBegin();
|
||||
SparseArrayNode *arrayNode = s->sparseBegin();
|
||||
// iterate until we're past the end of the string
|
||||
while (arrayNode && arrayNode->key() < slen)
|
||||
arrayNode = arrayNode->nextNode();
|
||||
|
|
|
@ -877,6 +877,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
|
||||
|
|
|
@ -669,6 +669,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();
|
||||
|
@ -719,7 +727,17 @@ QV4::ReturnedValue VME::interpret(CppStackFrame *frame, ExecutionEngine *engine,
|
|||
MOTH_BEGIN_INSTR(GetLookup)
|
||||
STORE_IP();
|
||||
STORE_ACC();
|
||||
|
||||
QV4::Lookup *l = function->compilationUnit->runtimeLookups + index;
|
||||
|
||||
if (accumulator.isNullOrUndefined()) {
|
||||
QString message = QStringLiteral("Cannot read property '%1' of %2")
|
||||
.arg(engine->currentStackFrame->v4Function->compilationUnit->runtimeStrings[l->nameIndex]->toQString())
|
||||
.arg(accumulator.toQStringNoThrow());
|
||||
acc = engine->throwTypeError(message);
|
||||
goto handleUnwind;
|
||||
}
|
||||
|
||||
acc = l->getter(l, engine, accumulator);
|
||||
CHECK_EXCEPTION;
|
||||
traceValue(acc, function, traceSlot);
|
||||
|
@ -755,37 +773,6 @@ QV4::ReturnedValue VME::interpret(CppStackFrame *frame, ExecutionEngine *engine,
|
|||
CHECK_EXCEPTION;
|
||||
MOTH_END_INSTR(StoreSuperProperty)
|
||||
|
||||
MOTH_BEGIN_INSTR(StoreScopeObjectProperty)
|
||||
STORE_ACC();
|
||||
Runtime::StoreQmlScopeObjectProperty::call(engine, STACK_VALUE(base), propertyIndex, accumulator);
|
||||
CHECK_EXCEPTION;
|
||||
MOTH_END_INSTR(StoreScopeObjectProperty)
|
||||
|
||||
MOTH_BEGIN_INSTR(LoadScopeObjectProperty)
|
||||
STORE_IP();
|
||||
acc = Runtime::LoadQmlScopeObjectProperty::call(engine, STACK_VALUE(base), propertyIndex, captureRequired);
|
||||
CHECK_EXCEPTION;
|
||||
MOTH_END_INSTR(LoadScopeObjectProperty)
|
||||
|
||||
MOTH_BEGIN_INSTR(StoreContextObjectProperty)
|
||||
STORE_IP();
|
||||
STORE_ACC();
|
||||
Runtime::StoreQmlContextObjectProperty::call(engine, STACK_VALUE(base), propertyIndex, accumulator);
|
||||
CHECK_EXCEPTION;
|
||||
MOTH_END_INSTR(StoreContextObjectProperty)
|
||||
|
||||
MOTH_BEGIN_INSTR(LoadContextObjectProperty)
|
||||
STORE_IP();
|
||||
acc = Runtime::LoadQmlContextObjectProperty::call(engine, STACK_VALUE(base), propertyIndex, captureRequired);
|
||||
CHECK_EXCEPTION;
|
||||
MOTH_END_INSTR(LoadContextObjectProperty)
|
||||
|
||||
MOTH_BEGIN_INSTR(LoadIdObject)
|
||||
STORE_IP();
|
||||
acc = Runtime::LoadQmlIdObject::call(engine, STACK_VALUE(base), index);
|
||||
CHECK_EXCEPTION;
|
||||
MOTH_END_INSTR(LoadIdObject)
|
||||
|
||||
MOTH_BEGIN_INSTR(Yield)
|
||||
frame->yield = code;
|
||||
frame->yieldIsIterator = false;
|
||||
|
@ -852,11 +839,23 @@ QV4::ReturnedValue VME::interpret(CppStackFrame *frame, ExecutionEngine *engine,
|
|||
MOTH_BEGIN_INSTR(CallPropertyLookup)
|
||||
STORE_IP();
|
||||
Lookup *l = function->compilationUnit->runtimeLookups + lookupIndex;
|
||||
|
||||
if (stack[base].isNullOrUndefined()) {
|
||||
QString message = QStringLiteral("Cannot call method '%1' of %2")
|
||||
.arg(engine->currentStackFrame->v4Function->compilationUnit->runtimeStrings[l->nameIndex]->toQString())
|
||||
.arg(stack[base].toQStringNoThrow());
|
||||
acc = engine->throwTypeError(message);
|
||||
goto handleUnwind;
|
||||
}
|
||||
|
||||
// ok to have the value on the stack here
|
||||
Value f = Value::fromReturnedValue(l->getter(l, engine, stack[base]));
|
||||
|
||||
if (Q_UNLIKELY(!f.isFunctionObject())) {
|
||||
acc = engine->throwTypeError();
|
||||
QString message = QStringLiteral("Property '%1' of object %2 is not a function")
|
||||
.arg(engine->currentStackFrame->v4Function->compilationUnit->runtimeStrings[l->nameIndex]->toQString())
|
||||
.arg(stack[base].toQStringNoThrow());
|
||||
acc = engine->throwTypeError(message);
|
||||
goto handleUnwind;
|
||||
}
|
||||
|
||||
|
@ -893,19 +892,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::CallQmlScopeObjectProperty::call(engine, stack[base], name, stack + argv, argc);
|
||||
acc = Runtime::CallQmlContextPropertyLookup::call(engine, index, stack + argv, argc);
|
||||
CHECK_EXCEPTION;
|
||||
traceValue(acc, function, traceSlot);
|
||||
MOTH_END_INSTR(CallScopeObjectProperty)
|
||||
|
||||
MOTH_BEGIN_INSTR(CallContextObjectProperty)
|
||||
STORE_IP();
|
||||
acc = Runtime::CallQmlContextObjectProperty::call(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();
|
||||
|
@ -1520,14 +1512,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::LoadQmlContext::call(engine);
|
||||
MOTH_END_INSTR(LoadQmlContext)
|
||||
|
||||
MOTH_BEGIN_INSTR(LoadQmlImportedScripts)
|
||||
STACK_VALUE(result) = Runtime::LoadQmlImportedScripts::call(engine);
|
||||
MOTH_END_INSTR(LoadQmlImportedScripts)
|
||||
|
||||
handleUnwind:
|
||||
Q_ASSERT(engine->hasException || frame->unwindLevel);
|
||||
if (!frame->unwindHandler) {
|
||||
|
|
|
@ -56,6 +56,8 @@ QT_BEGIN_NAMESPACE
|
|||
|
||||
namespace QV4 {
|
||||
|
||||
struct Lookup;
|
||||
|
||||
struct OwnPropertyKeyIterator {
|
||||
virtual ~OwnPropertyKeyIterator() = 0;
|
||||
virtual PropertyKey next(const Object *o, Property *p = nullptr, PropertyAttributes *attrs = nullptr) = 0;
|
||||
|
@ -84,6 +86,9 @@ struct VTable
|
|||
typedef ReturnedValue (*Call)(const FunctionObject *, const Value *thisObject, const Value *argv, int argc);
|
||||
typedef ReturnedValue (*CallAsConstructor)(const FunctionObject *, const Value *argv, int argc, const Value *newTarget);
|
||||
|
||||
typedef ReturnedValue (*ResolveLookupGetter)(const Object *, ExecutionEngine *, Lookup *);
|
||||
typedef bool (*ResolveLookupSetter)(Object *, ExecutionEngine *, Lookup *, const Value &);
|
||||
|
||||
const VTable * const parent;
|
||||
quint16 inlinePropertyOffset;
|
||||
quint16 nInlineProperties;
|
||||
|
@ -118,6 +123,9 @@ struct VTable
|
|||
|
||||
Call call;
|
||||
CallAsConstructor callAsConstructor;
|
||||
|
||||
ResolveLookupGetter resolveLookupGetter;
|
||||
ResolveLookupSetter resolveLookupSetter;
|
||||
};
|
||||
|
||||
|
||||
|
@ -142,6 +150,9 @@ protected:
|
|||
|
||||
static constexpr VTable::Call virtualCall = nullptr;
|
||||
static constexpr VTable::CallAsConstructor virtualCallAsConstructor = nullptr;
|
||||
|
||||
static constexpr VTable::ResolveLookupGetter virtualResolveLookupGetter = nullptr;
|
||||
static constexpr VTable::ResolveLookupSetter virtualResolveLookupSetter = nullptr;
|
||||
};
|
||||
|
||||
#define DEFINE_MANAGED_VTABLE_INT(classname, parentVTable) \
|
||||
|
@ -181,6 +192,9 @@ protected:
|
|||
\
|
||||
classname::virtualCall, \
|
||||
classname::virtualCallAsConstructor, \
|
||||
\
|
||||
classname::virtualResolveLookupGetter, \
|
||||
classname::virtualResolveLookupSetter \
|
||||
}
|
||||
|
||||
#define DEFINE_MANAGED_VTABLE(classname) \
|
||||
|
|
|
@ -614,16 +614,8 @@ bool Parser::parse(int startToken)
|
|||
program = 0;
|
||||
|
||||
do {
|
||||
if (++tos == stack_size) {
|
||||
if (++tos == stack_size)
|
||||
reallocateStack();
|
||||
if (stack_size > 10000) {
|
||||
// We're now in some serious right-recursive stuff, which will probably result in
|
||||
// an AST that's so deep that recursively visiting it will run out of stack space.
|
||||
const QString msg = QCoreApplication::translate("QQmlParser", "Maximum statement or expression depth exceeded");
|
||||
diagnostic_messages.append(DiagnosticMessage(DiagnosticMessage::Error, token_buffer[0].loc, msg));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
state_stack[tos] = action;
|
||||
|
||||
|
|
|
@ -65,21 +65,6 @@ ClassExpression *asAnonymousClassDefinition(Node *n)
|
|||
return c;
|
||||
}
|
||||
|
||||
|
||||
void Node::accept(Visitor *visitor)
|
||||
{
|
||||
if (visitor->preVisit(this)) {
|
||||
accept0(visitor);
|
||||
}
|
||||
visitor->postVisit(this);
|
||||
}
|
||||
|
||||
void Node::accept(Node *node, Visitor *visitor)
|
||||
{
|
||||
if (node)
|
||||
node->accept(visitor);
|
||||
}
|
||||
|
||||
ExpressionNode *Node::expressionCast()
|
||||
{
|
||||
return nullptr;
|
||||
|
|
|
@ -271,11 +271,29 @@ public:
|
|||
virtual FunctionExpression *asFunctionDefinition();
|
||||
virtual ClassExpression *asClassDefinition();
|
||||
|
||||
void accept(Visitor *visitor);
|
||||
static void accept(Node *node, Visitor *visitor);
|
||||
inline void accept(Visitor *visitor)
|
||||
{
|
||||
Visitor::RecursionDepthCheck recursionCheck(visitor);
|
||||
if (recursionCheck()) {
|
||||
if (visitor->preVisit(this))
|
||||
accept0(visitor);
|
||||
visitor->postVisit(this);
|
||||
} else {
|
||||
visitor->throwRecursionDepthError();
|
||||
}
|
||||
}
|
||||
|
||||
inline static void accept(Node *node, Visitor *visitor)
|
||||
{
|
||||
if (node)
|
||||
node->accept(visitor);
|
||||
}
|
||||
|
||||
// ### Remove when we can. This is part of the qmldevtools library, though.
|
||||
inline static void acceptChild(Node *node, Visitor *visitor)
|
||||
{ return accept(node, visitor); } // ### remove
|
||||
{
|
||||
return accept(node, visitor);
|
||||
}
|
||||
|
||||
virtual void accept0(Visitor *visitor) = 0;
|
||||
virtual SourceLocation firstSourceLocation() const = 0;
|
||||
|
|
|
@ -43,7 +43,7 @@ QT_QML_BEGIN_NAMESPACE
|
|||
|
||||
namespace QQmlJS { namespace AST {
|
||||
|
||||
Visitor::Visitor()
|
||||
Visitor::Visitor(quint16 parentRecursionDepth) : m_recursionDepth(parentRecursionDepth)
|
||||
{
|
||||
}
|
||||
|
||||
|
|
|
@ -61,7 +61,33 @@ namespace QQmlJS { namespace AST {
|
|||
class QML_PARSER_EXPORT Visitor
|
||||
{
|
||||
public:
|
||||
Visitor();
|
||||
class RecursionDepthCheck
|
||||
{
|
||||
Q_DISABLE_COPY(RecursionDepthCheck)
|
||||
public:
|
||||
RecursionDepthCheck(RecursionDepthCheck &&) = delete;
|
||||
RecursionDepthCheck &operator=(RecursionDepthCheck &&) = delete;
|
||||
|
||||
RecursionDepthCheck(Visitor *visitor) : m_visitor(visitor)
|
||||
{
|
||||
++(m_visitor->m_recursionDepth);
|
||||
}
|
||||
|
||||
~RecursionDepthCheck()
|
||||
{
|
||||
--(m_visitor->m_recursionDepth);
|
||||
}
|
||||
|
||||
bool operator()() const {
|
||||
return m_visitor->m_recursionDepth < s_recursionLimit;
|
||||
}
|
||||
|
||||
private:
|
||||
static const quint16 s_recursionLimit = 4096;
|
||||
Visitor *m_visitor;
|
||||
};
|
||||
|
||||
Visitor(quint16 parentRecursionDepth = 0);
|
||||
virtual ~Visitor();
|
||||
|
||||
virtual bool preVisit(Node *) { return true; }
|
||||
|
@ -374,6 +400,14 @@ public:
|
|||
|
||||
virtual bool visit(DebuggerStatement *) { return true; }
|
||||
virtual void endVisit(DebuggerStatement *) {}
|
||||
|
||||
virtual void throwRecursionDepthError() = 0;
|
||||
|
||||
quint16 recursionDepth() const { return m_recursionDepth; }
|
||||
|
||||
protected:
|
||||
quint16 m_recursionDepth = 0;
|
||||
friend class RecursionDepthCheck;
|
||||
};
|
||||
|
||||
} } // namespace AST
|
||||
|
|
|
@ -584,7 +584,6 @@ namespace QtQml {
|
|||
const QMetaObject *, bool create);
|
||||
#ifndef Q_QDOC
|
||||
}
|
||||
#endif
|
||||
|
||||
QT_WARNING_PUSH
|
||||
QT_WARNING_DISABLE_CLANG("-Wheader-hygiene")
|
||||
|
@ -594,6 +593,8 @@ using namespace QtQml;
|
|||
|
||||
QT_WARNING_POP
|
||||
|
||||
#endif // Q_QDOC
|
||||
|
||||
//The C++ version of protected namespaces in qmldir
|
||||
Q_QML_EXPORT bool qmlProtectModule(const char* uri, int majVersion);
|
||||
Q_QML_EXPORT void qmlRegisterModule(const char *uri, int versionMajor, int versionMinor);
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -1471,7 +1471,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;
|
||||
|
|
|
@ -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,63 +311,10 @@ 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);
|
||||
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);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
QQmlError QQmlJavaScriptExpression::error(QQmlEngine *engine) const
|
||||
{
|
||||
Q_UNUSED(engine);
|
||||
|
@ -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 =
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -48,6 +48,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
|
||||
|
||||
|
@ -170,6 +172,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())
|
||||
|
@ -426,6 +429,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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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);
|
||||
};
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
};
|
||||
|
||||
|
|
|
@ -525,7 +525,7 @@ public:
|
|||
|
||||
metaObject.reset(builder.toMetaObject());
|
||||
*static_cast<QMetaObject *>(this) = *metaObject;
|
||||
propertyCache = new QQmlPropertyCache(metaObject.data(), model.modelItemRevision);
|
||||
propertyCache.adopt(new QQmlPropertyCache(metaObject.data(), model.modelItemRevision));
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -659,8 +659,8 @@ public:
|
|||
{
|
||||
VDMListDelegateDataType *dataType = const_cast<VDMListDelegateDataType *>(this);
|
||||
if (!propertyCache) {
|
||||
dataType->propertyCache = new QQmlPropertyCache(
|
||||
&QQmlDMListAccessorData::staticMetaObject, model.modelItemRevision);
|
||||
dataType->propertyCache.adopt(new QQmlPropertyCache(
|
||||
&QQmlDMListAccessorData::staticMetaObject, model.modelItemRevision));
|
||||
}
|
||||
|
||||
return new QQmlDMListAccessorData(
|
||||
|
|
|
@ -120,7 +120,7 @@ interpolation behaviors are definable. The
|
|||
{Animation and Transitions} article has more information about creating state
|
||||
animations.
|
||||
|
||||
The \l {animation/states}{States and Transitions example}
|
||||
The \l {Qt Quick Examples - Animation}{Animation} example
|
||||
demonstrates how to declare a basic set of states and apply animated
|
||||
transitions between them.
|
||||
|
||||
|
|
|
@ -39,6 +39,8 @@
|
|||
#include "qquickdragaxis_p.h"
|
||||
#include <limits>
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
|
||||
QQuickDragAxis::QQuickDragAxis()
|
||||
: m_minimum(-std::numeric_limits<qreal>::max())
|
||||
, m_maximum(std::numeric_limits<qreal>::max())
|
||||
|
@ -73,3 +75,4 @@ void QQuickDragAxis::setEnabled(bool enabled)
|
|||
emit enabledChanged();
|
||||
}
|
||||
|
||||
QT_END_NAMESPACE
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2017 The Qt Company Ltd.
|
||||
** Copyright (C) 2019 The Qt Company Ltd.
|
||||
** Contact: https://www.qt.io/licensing/
|
||||
**
|
||||
** This file is part of the QtQuick module of the Qt Toolkit.
|
||||
|
@ -51,10 +51,11 @@
|
|||
// We mean it.
|
||||
//
|
||||
|
||||
#include <QtCore/qobject.h>
|
||||
#include <QtCore/qglobal.h>
|
||||
#include <private/qtquickglobal_p.h>
|
||||
|
||||
class Q_AUTOTEST_EXPORT QQuickDragAxis : public QObject
|
||||
QT_BEGIN_NAMESPACE
|
||||
|
||||
class Q_QUICK_PRIVATE_EXPORT QQuickDragAxis : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
Q_PROPERTY(qreal minimum READ minimum WRITE setMinimum NOTIFY minimumChanged)
|
||||
|
@ -84,4 +85,6 @@ private:
|
|||
bool m_enabled;
|
||||
};
|
||||
|
||||
QT_END_NAMESPACE
|
||||
|
||||
#endif // QQUICKDRAGAXIS_P_H
|
||||
|
|
|
@ -56,7 +56,7 @@
|
|||
|
||||
QT_BEGIN_NAMESPACE
|
||||
|
||||
class Q_AUTOTEST_EXPORT QQuickDragHandler : public QQuickMultiPointHandler
|
||||
class Q_QUICK_PRIVATE_EXPORT QQuickDragHandler : public QQuickMultiPointHandler
|
||||
{
|
||||
Q_OBJECT
|
||||
Q_PROPERTY(QQuickDragAxis * xAxis READ xAxis CONSTANT)
|
||||
|
|
|
@ -58,7 +58,7 @@
|
|||
|
||||
QT_BEGIN_NAMESPACE
|
||||
|
||||
class Q_AUTOTEST_EXPORT QQuickHoverHandler : public QQuickSinglePointHandler
|
||||
class Q_QUICK_PRIVATE_EXPORT QQuickHoverHandler : public QQuickSinglePointHandler
|
||||
{
|
||||
Q_OBJECT
|
||||
Q_PROPERTY(bool hovered READ isHovered NOTIFY hoveredChanged)
|
||||
|
|
|
@ -58,7 +58,7 @@
|
|||
|
||||
QT_BEGIN_NAMESPACE
|
||||
|
||||
class Q_AUTOTEST_EXPORT QQuickMultiPointHandler : public QQuickPointerDeviceHandler
|
||||
class Q_QUICK_PRIVATE_EXPORT QQuickMultiPointHandler : public QQuickPointerDeviceHandler
|
||||
{
|
||||
Q_OBJECT
|
||||
Q_PROPERTY(int minimumPointCount READ minimumPointCount WRITE setMinimumPointCount NOTIFY minimumPointCountChanged)
|
||||
|
|
|
@ -59,7 +59,7 @@
|
|||
|
||||
QT_BEGIN_NAMESPACE
|
||||
|
||||
class Q_AUTOTEST_EXPORT QQuickPinchHandler : public QQuickMultiPointHandler
|
||||
class Q_QUICK_PRIVATE_EXPORT QQuickPinchHandler : public QQuickMultiPointHandler
|
||||
{
|
||||
Q_OBJECT
|
||||
Q_PROPERTY(qreal minimumScale READ minimumScale WRITE setMinimumScale NOTIFY minimumScaleChanged)
|
||||
|
|
|
@ -56,7 +56,7 @@ QT_BEGIN_NAMESPACE
|
|||
|
||||
class QQuickPointerDeviceHandlerPrivate;
|
||||
|
||||
class Q_AUTOTEST_EXPORT QQuickPointerDeviceHandler : public QQuickPointerHandler
|
||||
class Q_QUICK_PRIVATE_EXPORT QQuickPointerDeviceHandler : public QQuickPointerHandler
|
||||
{
|
||||
Q_OBJECT
|
||||
Q_PROPERTY(QQuickPointerDevice::DeviceTypes acceptedDevices READ acceptedDevices WRITE setAcceptedDevices NOTIFY acceptedDevicesChanged)
|
||||
|
|
|
@ -56,7 +56,7 @@
|
|||
|
||||
QT_BEGIN_NAMESPACE
|
||||
|
||||
class Q_AUTOTEST_EXPORT QQuickPointerDeviceHandlerPrivate : public QQuickPointerHandlerPrivate
|
||||
class Q_QUICK_PRIVATE_EXPORT QQuickPointerDeviceHandlerPrivate : public QQuickPointerHandlerPrivate
|
||||
{
|
||||
Q_DECLARE_PUBLIC(QQuickPointerDeviceHandler)
|
||||
|
||||
|
|
|
@ -55,7 +55,7 @@
|
|||
|
||||
QT_BEGIN_NAMESPACE
|
||||
|
||||
class Q_AUTOTEST_EXPORT QQuickPointHandler : public QQuickSinglePointHandler
|
||||
class Q_QUICK_PRIVATE_EXPORT QQuickPointHandler : public QQuickSinglePointHandler
|
||||
{
|
||||
Q_OBJECT
|
||||
Q_PROPERTY(QVector2D translation READ translation NOTIFY translationChanged)
|
||||
|
|
|
@ -58,7 +58,7 @@
|
|||
|
||||
QT_BEGIN_NAMESPACE
|
||||
|
||||
class Q_AUTOTEST_EXPORT QQuickTapHandler : public QQuickSinglePointHandler
|
||||
class Q_QUICK_PRIVATE_EXPORT QQuickTapHandler : public QQuickSinglePointHandler
|
||||
{
|
||||
Q_OBJECT
|
||||
Q_PROPERTY(bool pressed READ isPressed NOTIFY pressedChanged)
|
||||
|
|
|
@ -43,6 +43,8 @@
|
|||
#include <QtGui/qvector2d.h>
|
||||
#include <QtCore/qmath.h>
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
|
||||
QQuickDefaultClipNode::QQuickDefaultClipNode(const QRectF &rect)
|
||||
: m_rect(rect)
|
||||
, m_radius(0)
|
||||
|
@ -117,3 +119,4 @@ void QQuickDefaultClipNode::updateGeometry()
|
|||
markDirty(DirtyGeometry);
|
||||
}
|
||||
|
||||
QT_END_NAMESPACE
|
||||
|
|
|
@ -54,6 +54,8 @@
|
|||
#include <private/qtquickglobal_p.h>
|
||||
#include <QtQuick/qsgnode.h>
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
|
||||
class Q_QUICK_PRIVATE_EXPORT QQuickDefaultClipNode : public QSGClipNode
|
||||
{
|
||||
public:
|
||||
|
@ -78,4 +80,6 @@ private:
|
|||
QSGGeometry m_geometry;
|
||||
};
|
||||
|
||||
QT_END_NAMESPACE
|
||||
|
||||
#endif // QQUICKCLIPNODE_P_H
|
||||
|
|
|
@ -96,7 +96,7 @@ public:
|
|||
// Uppermost 8 bits are reserved for internal use.
|
||||
IsVisitableNode = 0x01000000
|
||||
#ifdef Q_CLANG_QDOC
|
||||
InternalReserved = 0x01000000
|
||||
, InternalReserved = 0x01000000
|
||||
#endif
|
||||
};
|
||||
Q_DECLARE_FLAGS(Flags, Flag)
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -8,6 +8,8 @@ QtObject {
|
|||
signal testSignal
|
||||
onTestSignal: count++
|
||||
|
||||
readonly property string scopeObjectAsString: this.toString()
|
||||
|
||||
property int funcCount: 0
|
||||
function testFunction() {
|
||||
funcCount++;
|
||||
|
|
|
@ -364,6 +364,8 @@ private slots:
|
|||
void arrayAndException();
|
||||
void numberToStringWithRadix();
|
||||
void tailCallWithArguments();
|
||||
void deleteSparseInIteration();
|
||||
void saveAccumulatorBeforeToInt32();
|
||||
|
||||
private:
|
||||
// static void propertyVarWeakRefCallback(v8::Persistent<v8::Value> object, void* parameter);
|
||||
|
@ -1607,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);
|
||||
|
@ -6492,7 +6494,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");
|
||||
|
@ -8187,12 +8190,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()
|
||||
|
@ -8933,6 +8935,38 @@ void tst_qqmlecmascript::tailCallWithArguments()
|
|||
QCOMPARE(value.toInt(), 1);
|
||||
}
|
||||
|
||||
void tst_qqmlecmascript::deleteSparseInIteration()
|
||||
{
|
||||
QJSEngine engine;
|
||||
const QJSValue value = engine.evaluate(
|
||||
"(function() {\n"
|
||||
" var obj = { 1: null, 2: null, 4096: null };\n"
|
||||
" var iterated = [];\n"
|
||||
" for (var t in obj) {\n"
|
||||
" if (t == 2)\n"
|
||||
" delete obj[t];\n"
|
||||
" iterated.push(t);\n"
|
||||
" }\n"
|
||||
" return iterated;"
|
||||
"})()");
|
||||
QVERIFY(value.isArray());
|
||||
QCOMPARE(value.property("length").toInt(), 3);
|
||||
QCOMPARE(value.property("0").toInt(), 1);
|
||||
QCOMPARE(value.property("1").toInt(), 2);
|
||||
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"
|
||||
|
|
|
@ -0,0 +1,7 @@
|
|||
import QtQml 2.2
|
||||
|
||||
import "$(INTERCEPT)" as Intercepted
|
||||
|
||||
QtObject {
|
||||
property QtObject view: Intercepted.View {}
|
||||
}
|
|
@ -0,0 +1,5 @@
|
|||
import QtQml 2.2
|
||||
|
||||
QtObject {
|
||||
property int foo: 12
|
||||
}
|
|
@ -0,0 +1,2 @@
|
|||
module SomeModule
|
||||
View 1.0 View.qml
|
|
@ -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"
|
||||
|
|
|
@ -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
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
|
@ -0,0 +1,10 @@
|
|||
import QtQuick 2.9
|
||||
|
||||
Item {
|
||||
width: 200
|
||||
property int edgeWidth: edge.edgeWidth
|
||||
EdgeObject {
|
||||
id: edge
|
||||
anchors.fill: parent
|
||||
}
|
||||
}
|
|
@ -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()
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -105,6 +105,11 @@ public:
|
|||
{
|
||||
nodeStack.removeLast();
|
||||
}
|
||||
|
||||
void throwRecursionDepthError() final
|
||||
{
|
||||
QFAIL("Maximum statement or expression depth exceeded");
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -0,0 +1,2 @@
|
|||
[AnimatedImage::test_crashRaceCondition_replyFinished]
|
||||
osx-10.13
|
|
@ -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;
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
[enforceRange_withoutHighlight]
|
||||
osx
|
||||
opensuse-42.3
|
||||
opensuse-leap
|
||||
#QTBUG-53863
|
||||
[populateTransitions]
|
||||
opensuse-42.1
|
||||
|
|
|
@ -134,14 +134,12 @@ void tst_qquickrectangle::gradient_separate()
|
|||
|
||||
// Start off clean
|
||||
QQuickItemPrivate *rectPriv = QQuickItemPrivate::get(rect);
|
||||
bool isDirty = rectPriv->dirtyAttributes & QQuickItemPrivate::Content;
|
||||
QVERIFY(!isDirty);
|
||||
QTRY_COMPARE(rectPriv->dirtyAttributes & QQuickItemPrivate::Content, 0);
|
||||
|
||||
QMetaObject::invokeMethod(rect, "changeGradient");
|
||||
|
||||
// Changing the gradient should have scheduled an update of the item.
|
||||
isDirty = rectPriv->dirtyAttributes & QQuickItemPrivate::Content;
|
||||
QVERIFY(isDirty);
|
||||
QVERIFY((rectPriv->dirtyAttributes & QQuickItemPrivate::Content) != 0);
|
||||
}
|
||||
|
||||
// When a gradient is changed, every Rectangle connected to it must update.
|
||||
|
|
|
@ -1,2 +1,6 @@
|
|||
[buttonOnDelayedPressFlickable]
|
||||
windows gcc developer-build
|
||||
|
||||
# QTBUG-74517
|
||||
[buttonOnFlickable]
|
||||
windows gcc developer-build
|
||||
|
|
|
@ -55,17 +55,8 @@ QSet<QString> illegalNames;
|
|||
|
||||
void setupIllegalNames()
|
||||
{
|
||||
// #### this in incomplete
|
||||
illegalNames.insert(QStringLiteral("Math"));
|
||||
illegalNames.insert(QStringLiteral("Array"));
|
||||
illegalNames.insert(QStringLiteral("String"));
|
||||
illegalNames.insert(QStringLiteral("Function"));
|
||||
illegalNames.insert(QStringLiteral("Boolean"));
|
||||
illegalNames.insert(QStringLiteral("Number"));
|
||||
illegalNames.insert(QStringLiteral("Date"));
|
||||
illegalNames.insert(QStringLiteral("RegExp"));
|
||||
illegalNames.insert(QStringLiteral("Error"));
|
||||
illegalNames.insert(QStringLiteral("Object"));
|
||||
for (const char **g = QV4::Compiler::Codegen::s_globalNames; *g != nullptr; ++g)
|
||||
illegalNames.insert(QString::fromLatin1(*g));
|
||||
}
|
||||
|
||||
struct Error
|
||||
|
@ -212,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()) {
|
||||
|
@ -319,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);
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue