aboutsummaryrefslogtreecommitdiffstats
path: root/src/qml
diff options
context:
space:
mode:
Diffstat (limited to 'src/qml')
-rw-r--r--src/qml/compiler/qqmlirbuilder.cpp149
-rw-r--r--src/qml/compiler/qqmlirbuilder_p.h26
-rw-r--r--src/qml/compiler/qqmlpropertycachecreator_p.h19
-rw-r--r--src/qml/compiler/qqmltypecompiler.cpp47
-rw-r--r--src/qml/compiler/qqmltypecompiler_p.h2
-rw-r--r--src/qml/compiler/qv4codegen.cpp149
-rw-r--r--src/qml/compiler/qv4codegen_p.h24
-rw-r--r--src/qml/compiler/qv4compileddata.cpp12
-rw-r--r--src/qml/compiler/qv4compileddata_p.h337
-rw-r--r--src/qml/compiler/qv4compiler.cpp24
-rw-r--r--src/qml/compiler/qv4compiler_p.h4
-rw-r--r--src/qml/compiler/qv4jsir_p.h26
-rw-r--r--src/qml/debugger/qqmlprofiler_p.h11
-rw-r--r--src/qml/doc/qtqml.qdocconf2
-rw-r--r--src/qml/doc/snippets/code/src_script_qjsengine.cpp2
-rw-r--r--src/qml/doc/src/cppintegration/data.qdoc23
-rw-r--r--src/qml/doc/src/cppintegration/definetypes.qdoc3
-rw-r--r--src/qml/doc/src/cppintegration/extending-tutorial.qdoc19
-rw-r--r--src/qml/doc/src/cppintegration/interactqmlfromcpp.qdoc12
-rw-r--r--src/qml/doc/src/cppintegration/topic.qdoc2
-rw-r--r--src/qml/doc/src/cppintegration/warning.qdocinc6
-rw-r--r--src/qml/doc/src/javascript/functionlist.qdoc1
-rw-r--r--src/qml/doc/src/javascript/hostenvironment.qdoc13
-rw-r--r--src/qml/doc/src/qmllanguageref/syntax/objectattributes.qdoc38
-rw-r--r--src/qml/doc/src/qmllanguageref/syntax/propertybinding.qdoc20
-rw-r--r--src/qml/jit/qv4assembler.cpp56
-rw-r--r--src/qml/jit/qv4assembler_p.h346
-rw-r--r--src/qml/jit/qv4binop.cpp2
-rw-r--r--src/qml/jit/qv4isel_masm.cpp94
-rw-r--r--src/qml/jit/qv4isel_masm_p.h18
-rw-r--r--src/qml/jsapi/qjsvalue.cpp7
-rw-r--r--src/qml/jsapi/qjsvalue.h6
-rw-r--r--src/qml/jsruntime/qv4argumentsobject.cpp60
-rw-r--r--src/qml/jsruntime/qv4argumentsobject_p.h28
-rw-r--r--src/qml/jsruntime/qv4arraydata.cpp193
-rw-r--r--src/qml/jsruntime/qv4arraydata_p.h161
-rw-r--r--src/qml/jsruntime/qv4arrayobject.cpp4
-rw-r--r--src/qml/jsruntime/qv4context.cpp224
-rw-r--r--src/qml/jsruntime/qv4context_p.h161
-rw-r--r--src/qml/jsruntime/qv4dataview.cpp9
-rw-r--r--src/qml/jsruntime/qv4dataview_p.h13
-rw-r--r--src/qml/jsruntime/qv4dateobject.cpp51
-rw-r--r--src/qml/jsruntime/qv4dateobject_p.h2
-rw-r--r--src/qml/jsruntime/qv4engine.cpp95
-rw-r--r--src/qml/jsruntime/qv4engine_p.h47
-rw-r--r--src/qml/jsruntime/qv4enginebase_p.h6
-rw-r--r--src/qml/jsruntime/qv4errorobject.cpp44
-rw-r--r--src/qml/jsruntime/qv4errorobject_p.h14
-rw-r--r--src/qml/jsruntime/qv4function.cpp13
-rw-r--r--src/qml/jsruntime/qv4function_p.h6
-rw-r--r--src/qml/jsruntime/qv4functionobject.cpp66
-rw-r--r--src/qml/jsruntime/qv4functionobject_p.h28
-rw-r--r--src/qml/jsruntime/qv4global_p.h5
-rw-r--r--src/qml/jsruntime/qv4identifiertable_p.h4
-rw-r--r--src/qml/jsruntime/qv4internalclass.cpp58
-rw-r--r--src/qml/jsruntime/qv4internalclass_p.h3
-rw-r--r--src/qml/jsruntime/qv4jsonobject.cpp2
-rw-r--r--src/qml/jsruntime/qv4lookup.cpp76
-rw-r--r--src/qml/jsruntime/qv4lookup_p.h18
-rw-r--r--src/qml/jsruntime/qv4managed.cpp1
-rw-r--r--src/qml/jsruntime/qv4managed_p.h7
-rw-r--r--src/qml/jsruntime/qv4mathobject.cpp14
-rw-r--r--src/qml/jsruntime/qv4memberdata.cpp15
-rw-r--r--src/qml/jsruntime/qv4memberdata_p.h35
-rw-r--r--src/qml/jsruntime/qv4numberobject.cpp56
-rw-r--r--src/qml/jsruntime/qv4numberobject_p.h2
-rw-r--r--src/qml/jsruntime/qv4object.cpp228
-rw-r--r--src/qml/jsruntime/qv4object_p.h141
-rw-r--r--src/qml/jsruntime/qv4objectiterator.cpp8
-rw-r--r--src/qml/jsruntime/qv4objectiterator_p.h2
-rw-r--r--src/qml/jsruntime/qv4objectproto.cpp128
-rw-r--r--src/qml/jsruntime/qv4objectproto_p.h1
-rw-r--r--src/qml/jsruntime/qv4persistent.cpp21
-rw-r--r--src/qml/jsruntime/qv4persistent_p.h4
-rw-r--r--src/qml/jsruntime/qv4property_p.h15
-rw-r--r--src/qml/jsruntime/qv4qmlcontext.cpp61
-rw-r--r--src/qml/jsruntime/qv4qmlcontext_p.h19
-rw-r--r--src/qml/jsruntime/qv4qobjectwrapper.cpp299
-rw-r--r--src/qml/jsruntime/qv4qobjectwrapper_p.h29
-rw-r--r--src/qml/jsruntime/qv4regexp.cpp6
-rw-r--r--src/qml/jsruntime/qv4regexp_p.h2
-rw-r--r--src/qml/jsruntime/qv4regexpobject.cpp64
-rw-r--r--src/qml/jsruntime/qv4regexpobject_p.h41
-rw-r--r--src/qml/jsruntime/qv4runtime.cpp14
-rw-r--r--src/qml/jsruntime/qv4sequenceobject.cpp106
-rw-r--r--src/qml/jsruntime/qv4sequenceobject_p.h1
-rw-r--r--src/qml/jsruntime/qv4string.cpp6
-rw-r--r--src/qml/jsruntime/qv4string_p.h2
-rw-r--r--src/qml/jsruntime/qv4stringobject.cpp33
-rw-r--r--src/qml/jsruntime/qv4stringobject_p.h10
-rw-r--r--src/qml/jsruntime/qv4typedarray.cpp29
-rw-r--r--src/qml/jsruntime/qv4typedarray_p.h21
-rw-r--r--src/qml/jsruntime/qv4value_p.h3
-rw-r--r--src/qml/jsruntime/qv4variantobject.cpp4
-rw-r--r--src/qml/jsruntime/qv4variantobject_p.h4
-rw-r--r--src/qml/jsruntime/qv4vme_moth.cpp44
-rw-r--r--src/qml/memory/memory.pri3
-rw-r--r--src/qml/memory/qv4heap_p.h29
-rw-r--r--src/qml/memory/qv4mm.cpp373
-rw-r--r--src/qml/memory/qv4mm_p.h30
-rw-r--r--src/qml/memory/qv4mmdefs_p.h108
-rw-r--r--src/qml/memory/qv4writebarrier_p.h206
-rw-r--r--src/qml/parser/qqmljs.g85
-rw-r--r--src/qml/parser/qqmljsast.cpp17
-rw-r--r--src/qml/parser/qqmljsast_p.h102
-rw-r--r--src/qml/parser/qqmljsastfwd_p.h2
-rw-r--r--src/qml/parser/qqmljsastvisitor_p.h4
-rw-r--r--src/qml/parser/qqmljsgrammar.cpp2130
-rw-r--r--src/qml/parser/qqmljsgrammar_p.h294
-rw-r--r--src/qml/parser/qqmljskeywords_p.h11
-rw-r--r--src/qml/parser/qqmljslexer.cpp1
-rw-r--r--src/qml/parser/qqmljslexer_p.h1
-rw-r--r--src/qml/parser/qqmljsparser.cpp421
-rw-r--r--src/qml/parser/qqmljsparser_p.h5
-rw-r--r--src/qml/qml.pro2
-rw-r--r--src/qml/qml/qqmlbinding.cpp83
-rw-r--r--src/qml/qml/qqmlbinding_p.h11
-rw-r--r--src/qml/qml/qqmlcomponent.cpp68
-rw-r--r--src/qml/qml/qqmlcomponent_p.h7
-rw-r--r--src/qml/qml/qqmlcustomparser.cpp22
-rw-r--r--src/qml/qml/qqmlengine.cpp39
-rw-r--r--src/qml/qml/qqmlengine.h4
-rw-r--r--src/qml/qml/qqmlglobal.cpp2
-rw-r--r--src/qml/qml/qqmlglobal_p.h17
-rw-r--r--src/qml/qml/qqmlimport.cpp60
-rw-r--r--src/qml/qml/qqmlimport_p.h17
-rw-r--r--src/qml/qml/qqmljavascriptexpression.cpp13
-rw-r--r--src/qml/qml/qqmljavascriptexpression_p.h16
-rw-r--r--src/qml/qml/qqmllistwrapper.cpp3
-rw-r--r--src/qml/qml/qqmllistwrapper_p.h2
-rw-r--r--src/qml/qml/qqmlmetatype.cpp204
-rw-r--r--src/qml/qml/qqmlmetatype_p.h9
-rw-r--r--src/qml/qml/qqmlnotifier_p.h5
-rw-r--r--src/qml/qml/qqmlobjectcreator.cpp19
-rw-r--r--src/qml/qml/qqmlobjectcreator_p.h10
-rw-r--r--src/qml/qml/qqmlplatform.cpp6
-rw-r--r--src/qml/qml/qqmlplatform_p.h2
-rw-r--r--src/qml/qml/qqmlpropertycache.cpp21
-rw-r--r--src/qml/qml/qqmlpropertycache_p.h33
-rw-r--r--src/qml/qml/qqmltypeloader.cpp4
-rw-r--r--src/qml/qml/qqmltypenamecache.cpp5
-rw-r--r--src/qml/qml/qqmltypenamecache_p.h4
-rw-r--r--src/qml/qml/qqmltypewrapper.cpp147
-rw-r--r--src/qml/qml/qqmltypewrapper_p.h28
-rw-r--r--src/qml/qml/qqmlvaluetypeproxybinding.cpp5
-rw-r--r--src/qml/qml/qqmlvaluetypeproxybinding_p.h1
-rw-r--r--src/qml/qml/qqmlvaluetypewrapper.cpp40
-rw-r--r--src/qml/qml/qqmlvaluetypewrapper_p.h2
-rw-r--r--src/qml/qml/qqmlvmemetaobject.cpp62
-rw-r--r--src/qml/qml/qqmlvmemetaobject_p.h2
-rw-r--r--src/qml/qml/qqmlxmlhttprequest.cpp26
-rw-r--r--src/qml/qml/v8/qqmlbuiltinfunctions.cpp2
-rw-r--r--src/qml/types/qqmlconnections.cpp5
-rw-r--r--src/qml/types/qqmldelegatemodel.cpp27
-rw-r--r--src/qml/types/qqmldelegatemodel_p_p.h5
-rw-r--r--src/qml/types/qqmllistmodel.cpp22
-rw-r--r--src/qml/types/qqmllistmodel_p_p.h4
-rw-r--r--src/qml/types/qquickpackage.cpp2
-rw-r--r--src/qml/types/qquickworkerscript_p.h2
-rw-r--r--src/qml/util/qqmladaptormodel.cpp36
-rw-r--r--src/qml/util/qqmlpropertymap.cpp12
-rw-r--r--src/qml/util/qqmlpropertymap.h6
162 files changed, 5784 insertions, 3529 deletions
diff --git a/src/qml/compiler/qqmlirbuilder.cpp b/src/qml/compiler/qqmlirbuilder.cpp
index e82fe71934..60aea8e894 100644
--- a/src/qml/compiler/qqmlirbuilder.cpp
+++ b/src/qml/compiler/qqmlirbuilder.cpp
@@ -45,6 +45,7 @@
#include <private/qqmljslexer_p.h>
#include <QCoreApplication>
#include <QCryptographicHash>
+#include <cmath>
#ifndef V4_BOOTSTRAP
#include <private/qqmlglobal_p.h>
@@ -86,6 +87,7 @@ void Object::init(QQmlJS::MemoryPool *pool, int typeNameIndex, int idIndex, cons
flags = QV4::CompiledData::Object::NoFlag;
properties = pool->New<PoolList<Property> >();
aliases = pool->New<PoolList<Alias> >();
+ qmlEnums = pool->New<PoolList<Enum>>();
qmlSignals = pool->New<PoolList<Signal> >();
bindings = pool->New<PoolList<Binding> >();
functions = pool->New<PoolList<Function> >();
@@ -118,6 +120,21 @@ QString Object::sanityCheckFunctionNames(const QSet<QString> &illegalNames, QQml
return QString(); // no error
}
+QString Object::appendEnum(Enum *enumeration)
+{
+ Object *target = declarationsOverride;
+ if (!target)
+ target = this;
+
+ for (Enum *e = qmlEnums->first; e; e = e->next) {
+ if (e->nameIndex == enumeration->nameIndex)
+ return tr("Duplicate scoped enum name");
+ }
+
+ target->qmlEnums->append(enumeration);
+ return QString(); // no error
+}
+
QString Object::appendSignal(Signal *signal)
{
Object *target = declarationsOverride;
@@ -711,6 +728,52 @@ static QStringList astNodeToStringList(QQmlJS::AST::Node *node)
return QStringList();
}
+bool IRBuilder::visit(QQmlJS::AST::UiEnumDeclaration *node)
+{
+ Enum *enumeration = New<Enum>();
+ QString enumName = node->name.toString();
+ enumeration->nameIndex = registerString(enumName);
+
+ if (enumName.at(0).isLower())
+ COMPILE_EXCEPTION(node->enumToken, tr("Scoped enum names must begin with an upper case letter"));
+
+ enumeration->location.line = node->enumToken.startLine;
+ enumeration->location.column = node->enumToken.startColumn;
+
+ enumeration->enumValues = New<PoolList<EnumValue>>();
+
+ QQmlJS::AST::UiEnumMemberList *e = node->members;
+ while (e) {
+ EnumValue *enumValue = New<EnumValue>();
+ QString member = e->member.toString();
+ enumValue->nameIndex = registerString(member);
+ if (member.at(0).isLower())
+ COMPILE_EXCEPTION(e->memberToken, tr("Enum names must begin with an upper case letter"));
+
+ double part;
+ if (std::modf(e->value, &part) != 0.0)
+ COMPILE_EXCEPTION(e->valueToken, tr("Enum value must be an integer"));
+ if (e->value > std::numeric_limits<qint32>::max() || e->value < std::numeric_limits<qint32>::min())
+ COMPILE_EXCEPTION(e->valueToken, tr("Enum value out of range"));
+ enumValue->value = e->value;
+
+ enumValue->location.line = e->memberToken.startLine;
+ enumValue->location.column = e->memberToken.startColumn;
+ enumeration->enumValues->append(enumValue);
+
+ e = e->next;
+ }
+
+ QString error = _object->appendEnum(enumeration);
+ if (!error.isEmpty()) {
+ recordError(node->enumToken, error);
+ return false;
+ }
+
+ return false;
+}
+
+
bool IRBuilder::visit(QQmlJS::AST::UiPublicMember *node)
{
static const struct TypeNameToType {
@@ -1377,13 +1440,19 @@ QV4::CompiledData::Unit *QmlUnitGenerator::generate(Document &output, const QV4:
int objectsSize = 0;
for (Object *o : qAsConst(output.objects)) {
objectOffsets.insert(o, unitSize + importSize + objectOffsetTableSize + objectsSize);
- objectsSize += QV4::CompiledData::Object::calculateSizeExcludingSignals(o->functionCount(), o->propertyCount(), o->aliasCount(), o->signalCount(), o->bindingCount(), o->namedObjectsInComponent.count);
+ objectsSize += QV4::CompiledData::Object::calculateSizeExcludingSignalsAndEnums(o->functionCount(), o->propertyCount(), o->aliasCount(), o->enumCount(), o->signalCount(), o->bindingCount(), o->namedObjectsInComponent.count);
int signalTableSize = 0;
for (const Signal *s = o->firstSignal(); s; s = s->next)
signalTableSize += QV4::CompiledData::Signal::calculateSize(s->parameters->count);
objectsSize += signalTableSize;
+
+ int enumTableSize = 0;
+ for (const Enum *e = o->firstEnum(); e; e = e->next)
+ enumTableSize += QV4::CompiledData::Enum::calculateSize(e->enumValues->count);
+
+ objectsSize += enumTableSize;
}
const int totalSize = unitSize + importSize + objectOffsetTableSize + objectsSize + output.jsGenerator.stringTable.sizeOfTableAndData();
@@ -1429,7 +1498,7 @@ QV4::CompiledData::Unit *QmlUnitGenerator::generate(Document &output, const QV4:
}
// write objects
- QV4::CompiledData::LEUInt32 *objectTable = reinterpret_cast<QV4::CompiledData::LEUInt32*>(data + qmlUnit->offsetToObjects);
+ quint32_le *objectTable = reinterpret_cast<quint32_le*>(data + qmlUnit->offsetToObjects);
char *objectPtr = data + qmlUnit->offsetToObjects + objectOffsetTableSize;
for (int i = 0; i < output.objects.count(); ++i) {
const Object *o = output.objects.at(i);
@@ -1459,6 +1528,10 @@ QV4::CompiledData::Unit *QmlUnitGenerator::generate(Document &output, const QV4:
objectToWrite->offsetToAliases = nextOffset;
nextOffset += objectToWrite->nAliases * sizeof(QV4::CompiledData::Alias);
+ objectToWrite->nEnums = o->enumCount();
+ objectToWrite->offsetToEnums = nextOffset;
+ nextOffset += objectToWrite->nEnums * sizeof(quint32);
+
objectToWrite->nSignals = o->signalCount();
objectToWrite->offsetToSignals = nextOffset;
nextOffset += objectToWrite->nSignals * sizeof(quint32);
@@ -1471,7 +1544,7 @@ QV4::CompiledData::Unit *QmlUnitGenerator::generate(Document &output, const QV4:
objectToWrite->offsetToNamedObjectsInComponent = nextOffset;
nextOffset += objectToWrite->nNamedObjectsInComponent * sizeof(quint32);
- QV4::CompiledData::LEUInt32 *functionsTable = reinterpret_cast<QV4::CompiledData::LEUInt32*>(objectPtr + objectToWrite->offsetToFunctions);
+ quint32_le *functionsTable = reinterpret_cast<quint32_le *>(objectPtr + objectToWrite->offsetToFunctions);
for (const Function *f = o->firstFunction(); f; f = f->next)
*functionsTable++ = o->runtimeFunctionIndices.at(f->index);
@@ -1497,7 +1570,7 @@ QV4::CompiledData::Unit *QmlUnitGenerator::generate(Document &output, const QV4:
bindingPtr = writeBindings(bindingPtr, o, &QV4::CompiledData::Binding::isValueBindingToAlias);
Q_ASSERT((bindingPtr - objectToWrite->offsetToBindings - objectPtr) / sizeof(QV4::CompiledData::Binding) == unsigned(o->bindingCount()));
- QV4::CompiledData::LEUInt32 *signalOffsetTable = reinterpret_cast<QV4::CompiledData::LEUInt32*>(objectPtr + objectToWrite->offsetToSignals);
+ quint32_le *signalOffsetTable = reinterpret_cast<quint32_le *>(objectPtr + objectToWrite->offsetToSignals);
quint32 signalTableSize = 0;
char *signalPtr = objectPtr + nextOffset;
for (const Signal *s = o->firstSignal(); s; s = s->next) {
@@ -1516,14 +1589,36 @@ QV4::CompiledData::Unit *QmlUnitGenerator::generate(Document &output, const QV4:
signalTableSize += size;
signalPtr += size;
}
+ nextOffset += signalTableSize;
+
+ quint32_le *enumOffsetTable = reinterpret_cast<quint32_le*>(objectPtr + objectToWrite->offsetToEnums);
+ quint32 enumTableSize = 0;
+ char *enumPtr = objectPtr + nextOffset;
+ for (const Enum *e = o->firstEnum(); e; e = e->next) {
+ *enumOffsetTable++ = enumPtr - objectPtr;
+ QV4::CompiledData::Enum *enumToWrite = reinterpret_cast<QV4::CompiledData::Enum*>(enumPtr);
+
+ enumToWrite->nameIndex = e->nameIndex;
+ enumToWrite->location = e->location;
+ enumToWrite->nEnumValues = e->enumValues->count;
+
+ QV4::CompiledData::EnumValue *enumValueToWrite = reinterpret_cast<QV4::CompiledData::EnumValue*>(enumPtr + sizeof(*enumToWrite));
+ for (EnumValue *enumValue = e->enumValues->first; enumValue; enumValue = enumValue->next, ++enumValueToWrite)
+ *enumValueToWrite = *enumValue;
+
+ int size = QV4::CompiledData::Enum::calculateSize(e->enumValues->count);
+ enumTableSize += size;
+ enumPtr += size;
+ }
- QV4::CompiledData::LEUInt32 *namedObjectInComponentPtr = reinterpret_cast<QV4::CompiledData::LEUInt32*>(objectPtr + objectToWrite->offsetToNamedObjectsInComponent);
+ quint32_le *namedObjectInComponentPtr = reinterpret_cast<quint32_le *>(objectPtr + objectToWrite->offsetToNamedObjectsInComponent);
for (int i = 0; i < o->namedObjectsInComponent.count; ++i) {
*namedObjectInComponentPtr++ = o->namedObjectsInComponent.at(i);
}
- objectPtr += QV4::CompiledData::Object::calculateSizeExcludingSignals(o->functionCount(), o->propertyCount(), o->aliasCount(), o->signalCount(), o->bindingCount(), o->namedObjectsInComponent.count);
+ objectPtr += QV4::CompiledData::Object::calculateSizeExcludingSignalsAndEnums(o->functionCount(), o->propertyCount(), o->aliasCount(), o->enumCount(), o->signalCount(), o->bindingCount(), o->namedObjectsInComponent.count);
objectPtr += signalTableSize;
+ objectPtr += enumTableSize;
}
// enable flag if we encountered pragma Singleton
@@ -1612,7 +1707,7 @@ QVector<int> JSCodeGen::generateJSCodeForFunctionsAndBindings(const QList<Compil
scan.leaveEnvironment();
scan.leaveEnvironment();
- _env = 0;
+ _variableEnvironment = 0;
_function = _module->functions.at(defineFunction(QStringLiteral("context scope"), qmlRoot, 0, 0));
for (int i = 0; i < functions.count(); ++i) {
@@ -1695,6 +1790,7 @@ enum MetaObjectResolverFlags {
};
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,
@@ -1710,6 +1806,14 @@ static QV4::IR::DiscoveredType resolveQmlType(QQmlEnginePrivate *qmlEngine,
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);
+ }
}
}
@@ -1893,6 +1997,33 @@ static void initMetaObjectResolver(QV4::IR::MemberExpressionResolver *resolver,
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 // V4_BOOTSTRAP
void JSCodeGen::beginFunctionBodyHook()
@@ -2197,7 +2328,7 @@ QmlIR::Object *IRLoader::loadObject(const QV4::CompiledData::Object *serializedO
QQmlJS::Engine *jsParserEngine = &output->jsParserEngine;
- const QV4::CompiledData::LEUInt32 *functionIdx = serializedObject->functionOffsetTable();
+ const quint32_le *functionIdx = serializedObject->functionOffsetTable();
for (uint i = 0; i < serializedObject->nFunctions; ++i, ++functionIdx) {
QmlIR::Function *f = pool->New<QmlIR::Function>();
const QV4::CompiledData::Function *compiledFunction = unit->functionAt(*functionIdx);
@@ -2208,7 +2339,7 @@ QmlIR::Object *IRLoader::loadObject(const QV4::CompiledData::Object *serializedO
f->nameIndex = compiledFunction->nameIndex;
QQmlJS::AST::FormalParameterList *paramList = 0;
- const QV4::CompiledData::LEUInt32 *formalNameIdx = compiledFunction->formalsTable();
+ const quint32_le *formalNameIdx = compiledFunction->formalsTable();
for (uint i = 0; i < compiledFunction->nFormals; ++i, ++formalNameIdx) {
const QString formal = unit->stringAt(*formalNameIdx);
QStringRef paramNameRef = jsParserEngine->newStringRef(formal);
diff --git a/src/qml/compiler/qqmlirbuilder_p.h b/src/qml/compiler/qqmlirbuilder_p.h
index ad34864242..f4d5901f92 100644
--- a/src/qml/compiler/qqmlirbuilder_p.h
+++ b/src/qml/compiler/qqmlirbuilder_p.h
@@ -265,6 +265,25 @@ public:
struct Object;
+struct EnumValue : public QV4::CompiledData::EnumValue
+{
+ EnumValue *next;
+};
+
+struct Enum
+{
+ int nameIndex;
+ QV4::CompiledData::Location location;
+ PoolList<EnumValue> *enumValues;
+
+ int enumValueCount() const { return enumValues->count; }
+ PoolList<EnumValue>::Iterator enumValuesBegin() const { return enumValues->begin(); }
+ PoolList<EnumValue>::Iterator enumValuesEnd() const { return enumValues->end(); }
+
+ Enum *next;
+};
+
+
struct SignalParameter : public QV4::CompiledData::Parameter
{
SignalParameter *next;
@@ -359,6 +378,8 @@ public:
int propertyCount() const { return properties->count; }
Alias *firstAlias() const { return aliases->first; }
int aliasCount() const { return aliases->count; }
+ const Enum *firstEnum() const { return qmlEnums->first; }
+ int enumCount() const { return qmlEnums->count; }
const Signal *firstSignal() const { return qmlSignals->first; }
int signalCount() const { return qmlSignals->count; }
Binding *firstBinding() const { return bindings->first; }
@@ -372,6 +393,8 @@ public:
PoolList<Property>::Iterator propertiesEnd() const { return properties->end(); }
PoolList<Alias>::Iterator aliasesBegin() const { return aliases->begin(); }
PoolList<Alias>::Iterator aliasesEnd() const { return aliases->end(); }
+ PoolList<Enum>::Iterator enumsBegin() const { return qmlEnums->begin(); }
+ PoolList<Enum>::Iterator enumsEnd() const { return qmlEnums->end(); }
PoolList<Signal>::Iterator signalsBegin() const { return qmlSignals->begin(); }
PoolList<Signal>::Iterator signalsEnd() const { return qmlSignals->end(); }
PoolList<Function>::Iterator functionsBegin() const { return functions->begin(); }
@@ -385,6 +408,7 @@ public:
QString sanityCheckFunctionNames(const QSet<QString> &illegalNames, QQmlJS::AST::SourceLocation *errorLocation);
+ QString appendEnum(Enum *enumeration);
QString appendSignal(Signal *signal);
QString appendProperty(Property *prop, const QString &propertyName, bool isDefaultProperty, const QQmlJS::AST::SourceLocation &defaultToken, QQmlJS::AST::SourceLocation *errorLocation);
QString appendAlias(Alias *prop, const QString &aliasName, bool isDefaultProperty, const QQmlJS::AST::SourceLocation &defaultToken, QQmlJS::AST::SourceLocation *errorLocation);
@@ -408,6 +432,7 @@ private:
PoolList<Property> *properties;
PoolList<Alias> *aliases;
+ PoolList<Enum> *qmlEnums;
PoolList<Signal> *qmlSignals;
PoolList<Binding> *bindings;
PoolList<Function> *functions;
@@ -481,6 +506,7 @@ public:
bool visit(QQmlJS::AST::UiArrayBinding *ast) override;
bool visit(QQmlJS::AST::UiObjectBinding *ast) override;
bool visit(QQmlJS::AST::UiObjectDefinition *ast) override;
+ bool visit(QQmlJS::AST::UiEnumDeclaration *ast) override;
bool visit(QQmlJS::AST::UiPublicMember *ast) override;
bool visit(QQmlJS::AST::UiScriptBinding *ast) override;
bool visit(QQmlJS::AST::UiSourceElement *ast) override;
diff --git a/src/qml/compiler/qqmlpropertycachecreator_p.h b/src/qml/compiler/qqmlpropertycachecreator_p.h
index 8743a57d7a..ec546e4ab4 100644
--- a/src/qml/compiler/qqmlpropertycachecreator_p.h
+++ b/src/qml/compiler/qqmlpropertycachecreator_p.h
@@ -116,7 +116,7 @@ inline QQmlCompileError QQmlPropertyCacheCreator<ObjectContainer>::buildMetaObje
{
const CompiledObject *obj = objectContainer->objectAt(objectIndex);
- bool needVMEMetaObject = obj->propertyCount() != 0 || obj->aliasCount() != 0 || obj->signalCount() != 0 || obj->functionCount() != 0;
+ bool needVMEMetaObject = obj->propertyCount() != 0 || obj->aliasCount() != 0 || obj->signalCount() != 0 || obj->functionCount() != 0 || obj->enumCount() != 0;
if (!needVMEMetaObject) {
auto binding = obj->bindingsBegin();
auto end = obj->bindingsEnd();
@@ -244,7 +244,7 @@ inline QQmlCompileError QQmlPropertyCacheCreator<ObjectContainer>::createMetaObj
QQmlRefPointer<QQmlPropertyCache> cache;
cache.adopt(baseTypeCache->copyAndReserve(obj->propertyCount() + obj->aliasCount(),
obj->functionCount() + obj->propertyCount() + obj->aliasCount() + obj->signalCount(),
- obj->signalCount() + obj->propertyCount() + obj->aliasCount()));
+ obj->signalCount() + obj->propertyCount() + obj->aliasCount(), obj->enumCount()));
propertyCaches->set(objectIndex, cache);
propertyCaches->setNeedsVMEMetaObject(objectIndex);
@@ -370,6 +370,21 @@ inline QQmlCompileError QQmlPropertyCacheCreator<ObjectContainer>::createMetaObj
cache->appendSignal(changedSigName, flags, effectiveMethodIndex++);
}
+ auto e = obj->enumsBegin();
+ auto eend = obj->enumsEnd();
+ for ( ; e != eend; ++e) {
+ const int enumValueCount = e->enumValueCount();
+ QVector<QQmlEnumValue> values;
+ values.reserve(enumValueCount);
+
+ auto enumValue = e->enumValuesBegin();
+ auto end = e->enumValuesEnd();
+ for ( ; enumValue != end; ++enumValue)
+ values.append(QQmlEnumValue(stringAt(enumValue->nameIndex), enumValue->value));
+
+ cache->appendEnum(stringAt(e->nameIndex), values);
+ }
+
// Dynamic signals
auto s = obj->signalsBegin();
auto send = obj->signalsEnd();
diff --git a/src/qml/compiler/qqmltypecompiler.cpp b/src/qml/compiler/qqmltypecompiler.cpp
index 0eae909cf7..a6e80e3799 100644
--- a/src/qml/compiler/qqmltypecompiler.cpp
+++ b/src/qml/compiler/qqmltypecompiler.cpp
@@ -588,21 +588,32 @@ bool QQmlEnumTypeResolver::tryQualifiedEnumAssignment(const QmlIR::Object *obj,
if (!string.constData()->isUpper())
return true;
+ // we support one or two '.' in the enum phrase:
+ // * <TypeName>.<EnumValue>
+ // * <TypeName>.<ScopedEnumName>.<EnumValue>
+
int dot = string.indexOf(QLatin1Char('.'));
if (dot == -1 || dot == string.length()-1)
return true;
- if (string.indexOf(QLatin1Char('.'), dot+1) != -1)
- return true;
+ int dot2 = string.indexOf(QLatin1Char('.'), dot+1);
+ if (dot2 != -1 && dot2 != string.length()-1) {
+ if (!string.at(dot+1).isUpper())
+ return true;
+ if (string.indexOf(QLatin1Char('.'), dot2+1) != -1)
+ return true;
+ }
QHashedStringRef typeName(string.constData(), dot);
const bool isQtObject = (typeName == QLatin1String("Qt"));
- const QStringRef enumValue = string.midRef(dot + 1);
+ const QStringRef scopedEnumName = (dot2 != -1 ? string.midRef(dot + 1, dot2 - dot - 1) : QStringRef());
+ // ### consider supporting scoped enums in Qt namespace
+ const QStringRef enumValue = string.midRef(!isQtObject && dot2 != -1 ? dot2 + 1 : dot + 1);
- if (isIntProp) {
+ if (isIntProp) { // ### C++11 allows enums to be other integral types. Should we support other integral types here?
// Allow enum assignment to ints.
bool ok;
- int enumval = evaluateEnum(typeName.toString(), enumValue.toUtf8(), &ok);
+ int enumval = evaluateEnum(typeName.toString(), scopedEnumName, enumValue, &ok);
if (ok) {
if (!assignEnumToBinding(binding, enumValue, enumval, isQtObject))
return false;
@@ -620,18 +631,25 @@ bool QQmlEnumTypeResolver::tryQualifiedEnumAssignment(const QmlIR::Object *obj,
auto *tr = resolvedTypes->value(obj->inheritedTypeNameIndex);
if (type.isValid() && tr && tr->type == type) {
+ // When these two match, we can short cut the search
QMetaProperty mprop = propertyCache->firstCppMetaObject()->property(prop->coreIndex());
+ QMetaEnum menum = mprop.enumerator();
+ QByteArray enumName = enumValue.toUtf8();
+ if (menum.isScoped() && !scopedEnumName.isEmpty() && enumName != scopedEnumName.toUtf8())
+ return true;
- // When these two match, we can short cut the search
if (mprop.isFlagType()) {
- value = mprop.enumerator().keysToValue(enumValue.toUtf8().constData(), &ok);
+ value = menum.keysToValue(enumName.constData(), &ok);
} else {
- value = mprop.enumerator().keyToValue(enumValue.toUtf8().constData(), &ok);
+ value = menum.keyToValue(enumName.constData(), &ok);
}
} else {
// Otherwise we have to search the whole type
if (type.isValid()) {
- value = type.enumValue(compiler->enginePrivate(), QHashedStringRef(enumValue), &ok);
+ if (!scopedEnumName.isEmpty())
+ value = type.scopedEnumValue(compiler->enginePrivate(), scopedEnumName, enumValue, &ok);
+ else
+ value = type.enumValue(compiler->enginePrivate(), QHashedStringRef(enumValue), &ok);
} else {
QByteArray enumName = enumValue.toUtf8();
const QMetaObject *metaObject = StaticQtMetaObject::get();
@@ -648,7 +666,7 @@ bool QQmlEnumTypeResolver::tryQualifiedEnumAssignment(const QmlIR::Object *obj,
return assignEnumToBinding(binding, enumValue, value, isQtObject);
}
-int QQmlEnumTypeResolver::evaluateEnum(const QString &scope, const QByteArray &enumValue, bool *ok) const
+int QQmlEnumTypeResolver::evaluateEnum(const QString &scope, const QStringRef &enumName, const QStringRef &enumValue, bool *ok) const
{
Q_ASSERT_X(ok, "QQmlEnumTypeResolver::evaluateEnum", "ok must not be a null pointer");
*ok = false;
@@ -656,13 +674,18 @@ int QQmlEnumTypeResolver::evaluateEnum(const QString &scope, const QByteArray &e
if (scope != QLatin1String("Qt")) {
QQmlType type;
imports->resolveType(scope, &type, 0, 0, 0);
- return type.enumValue(compiler->enginePrivate(), QHashedCStringRef(enumValue.constData(), enumValue.length()), ok);
+ if (!type.isValid())
+ return -1;
+ if (!enumName.isEmpty())
+ return type.scopedEnumValue(compiler->enginePrivate(), enumName, enumValue, ok);
+ return type.enumValue(compiler->enginePrivate(), QHashedStringRef(enumValue.constData(), enumValue.length()), ok);
}
const QMetaObject *mo = StaticQtMetaObject::get();
int i = mo->enumeratorCount();
+ const QByteArray ba = enumValue.toUtf8();
while (i--) {
- int v = mo->enumerator(i).keyToValue(enumValue.constData(), ok);
+ int v = mo->enumerator(i).keyToValue(ba.constData(), ok);
if (*ok)
return v;
}
diff --git a/src/qml/compiler/qqmltypecompiler_p.h b/src/qml/compiler/qqmltypecompiler_p.h
index 0e953ec01e..4878a90641 100644
--- a/src/qml/compiler/qqmltypecompiler_p.h
+++ b/src/qml/compiler/qqmltypecompiler_p.h
@@ -208,7 +208,7 @@ private:
bool tryQualifiedEnumAssignment(const QmlIR::Object *obj, const QQmlPropertyCache *propertyCache,
const QQmlPropertyData *prop,
QmlIR::Binding *binding);
- int evaluateEnum(const QString &scope, const QByteArray &enumValue, bool *ok) const;
+ int evaluateEnum(const QString &scope, const QStringRef &enumName, const QStringRef &enumValue, bool *ok) const;
const QVector<QmlIR::Object*> &qmlObjects;
diff --git a/src/qml/compiler/qv4codegen.cpp b/src/qml/compiler/qv4codegen.cpp
index b07e9f55f5..06f7cce2c7 100644
--- a/src/qml/compiler/qv4codegen.cpp
+++ b/src/qml/compiler/qv4codegen.cpp
@@ -128,7 +128,7 @@ static inline bool isSimpleExpr(IR::Expr *e)
Codegen::ScanFunctions::ScanFunctions(Codegen *cg, const QString &sourceCode, CompilationMode defaultProgramMode)
: _cg(cg)
, _sourceCode(sourceCode)
- , _env(0)
+ , _variableEnvironment(0)
, _allowFuncDecls(true)
, defaultProgramMode(defaultProgramMode)
{
@@ -142,17 +142,17 @@ void Codegen::ScanFunctions::operator()(Node *node)
void Codegen::ScanFunctions::enterEnvironment(Node *node, CompilationMode compilationMode)
{
- Environment *e = _cg->newEnvironment(node, _env, compilationMode);
+ Environment *e = _cg->newEnvironment(node, _variableEnvironment, compilationMode);
if (!e->isStrict)
e->isStrict = _cg->_strictMode;
_envStack.append(e);
- _env = e;
+ _variableEnvironment = e;
}
void Codegen::ScanFunctions::leaveEnvironment()
{
_envStack.pop();
- _env = _envStack.isEmpty() ? 0 : _envStack.top();
+ _variableEnvironment = _envStack.isEmpty() ? 0 : _envStack.top();
}
void Codegen::ScanFunctions::checkDirectivePrologue(SourceElements *ast)
@@ -168,7 +168,7 @@ void Codegen::ScanFunctions::checkDirectivePrologue(SourceElements *ast)
continue;
QStringRef str = _sourceCode.midRef(strLit->literalToken.offset + 1, strLit->literalToken.length - 2);
if (str == QLatin1String("use strict")) {
- _env->isStrict = true;
+ _variableEnvironment->isStrict = true;
} else {
// TODO: give a warning.
}
@@ -183,7 +183,7 @@ void Codegen::ScanFunctions::checkDirectivePrologue(SourceElements *ast)
void Codegen::ScanFunctions::checkName(const QStringRef &name, const SourceLocation &loc)
{
- if (_env->isStrict) {
+ if (_variableEnvironment->isStrict) {
if (name == QLatin1String("implements")
|| name == QLatin1String("interface")
|| name == QLatin1String("let")
@@ -201,7 +201,7 @@ void Codegen::ScanFunctions::checkForArguments(AST::FormalParameterList *paramet
{
while (parameters) {
if (parameters->name == QLatin1String("arguments"))
- _env->usesArgumentsObject = Environment::ArgumentsObjectNotUsed;
+ _variableEnvironment->usesArgumentsObject = Environment::ArgumentsObjectNotUsed;
parameters = parameters->next;
}
}
@@ -220,19 +220,19 @@ void Codegen::ScanFunctions::endVisit(Program *)
bool Codegen::ScanFunctions::visit(CallExpression *ast)
{
- if (! _env->hasDirectEval) {
+ if (! _variableEnvironment->hasDirectEval) {
if (IdentifierExpression *id = cast<IdentifierExpression *>(ast->base)) {
if (id->name == QLatin1String("eval")) {
- if (_env->usesArgumentsObject == Environment::ArgumentsObjectUnknown)
- _env->usesArgumentsObject = Environment::ArgumentsObjectUsed;
- _env->hasDirectEval = true;
+ if (_variableEnvironment->usesArgumentsObject == Environment::ArgumentsObjectUnknown)
+ _variableEnvironment->usesArgumentsObject = Environment::ArgumentsObjectUsed;
+ _variableEnvironment->hasDirectEval = true;
}
}
}
int argc = 0;
for (ArgumentList *it = ast->arguments; it; it = it->next)
++argc;
- _env->maxNumberOfArguments = qMax(_env->maxNumberOfArguments, argc);
+ _variableEnvironment->maxNumberOfArguments = qMax(_variableEnvironment->maxNumberOfArguments, argc);
return true;
}
@@ -241,7 +241,7 @@ bool Codegen::ScanFunctions::visit(NewMemberExpression *ast)
int argc = 0;
for (ArgumentList *it = ast->arguments; it; it = it->next)
++argc;
- _env->maxNumberOfArguments = qMax(_env->maxNumberOfArguments, argc);
+ _variableEnvironment->maxNumberOfArguments = qMax(_variableEnvironment->maxNumberOfArguments, argc);
return true;
}
@@ -257,26 +257,38 @@ bool Codegen::ScanFunctions::visit(ArrayLiteral *ast)
for (Elision *elision = ast->elision->next; elision; elision = elision->next)
++index;
}
- _env->maxNumberOfArguments = qMax(_env->maxNumberOfArguments, index);
+ _variableEnvironment->maxNumberOfArguments = qMax(_variableEnvironment->maxNumberOfArguments, index);
return true;
}
bool Codegen::ScanFunctions::visit(VariableDeclaration *ast)
{
- if (_env->isStrict && (ast->name == QLatin1String("eval") || ast->name == QLatin1String("arguments")))
+ if (_variableEnvironment->isStrict && (ast->name == QLatin1String("eval") || ast->name == QLatin1String("arguments")))
_cg->throwSyntaxError(ast->identifierToken, QStringLiteral("Variable name may not be eval or arguments in strict mode"));
checkName(ast->name, ast->identifierToken);
if (ast->name == QLatin1String("arguments"))
- _env->usesArgumentsObject = Environment::ArgumentsObjectNotUsed;
- _env->enter(ast->name.toString(), ast->expression ? Environment::VariableDefinition : Environment::VariableDeclaration);
+ _variableEnvironment->usesArgumentsObject = Environment::ArgumentsObjectNotUsed;
+ if (ast->scope == AST::VariableDeclaration::VariableScope::ReadOnlyBlockScope && !ast->expression) {
+ _cg->throwSyntaxError(ast->identifierToken, QStringLiteral("Missing initializer in const declaration"));
+ return false;
+ }
+ QString name = ast->name.toString();
+ const Environment::Member *m = 0;
+ if (_variableEnvironment->memberInfo(name, &m)) {
+ if (m->isLexicallyScoped() || ast->isLexicallyScoped()) {
+ _cg->throwSyntaxError(ast->identifierToken, QStringLiteral("Identifier %1 has already been declared").arg(name));
+ return false;
+ }
+ }
+ _variableEnvironment->enter(ast->name.toString(), ast->expression ? Environment::VariableDefinition : Environment::VariableDeclaration, ast->scope);
return true;
}
bool Codegen::ScanFunctions::visit(IdentifierExpression *ast)
{
checkName(ast->name, ast->identifierToken);
- if (_env->usesArgumentsObject == Environment::ArgumentsObjectUnknown && ast->name == QLatin1String("arguments"))
- _env->usesArgumentsObject = Environment::ArgumentsObjectUsed;
+ if (_variableEnvironment->usesArgumentsObject == Environment::ArgumentsObjectUnknown && ast->name == QLatin1String("arguments"))
+ _variableEnvironment->usesArgumentsObject = Environment::ArgumentsObjectUsed;
return true;
}
@@ -308,7 +320,7 @@ bool Codegen::ScanFunctions::visit(FunctionExpression *ast)
void Codegen::ScanFunctions::enterFunction(FunctionExpression *ast, bool enterName, bool isExpression)
{
- if (_env->isStrict && (ast->name == QLatin1String("eval") || ast->name == QLatin1String("arguments")))
+ if (_variableEnvironment->isStrict && (ast->name == QLatin1String("eval") || ast->name == QLatin1String("arguments")))
_cg->throwSyntaxError(ast->identifierToken, QStringLiteral("Function name may not be eval or arguments in strict mode"));
enterFunction(ast, ast->name.toString(), ast->formals, ast->body, enterName ? ast : 0, isExpression);
}
@@ -329,7 +341,7 @@ bool Codegen::ScanFunctions::visit(ObjectLiteral *ast)
if (AST::cast<AST::PropertyGetterSetter *>(it->assignment))
++argc;
}
- _env->maxNumberOfArguments = qMax(_env->maxNumberOfArguments, argc);
+ _variableEnvironment->maxNumberOfArguments = qMax(_variableEnvironment->maxNumberOfArguments, argc);
TemporaryBoolAssignment allowFuncDecls(_allowFuncDecls, true);
Node::accept(ast->properties, this);
@@ -361,7 +373,7 @@ void Codegen::ScanFunctions::endVisit(FunctionDeclaration *)
bool Codegen::ScanFunctions::visit(WithStatement *ast)
{
- if (_env->isStrict) {
+ if (_variableEnvironment->isStrict) {
_cg->throwSyntaxError(ast->withToken, QStringLiteral("'with' statement is not allowed in strict mode"));
return false;
}
@@ -371,7 +383,7 @@ bool Codegen::ScanFunctions::visit(WithStatement *ast)
bool Codegen::ScanFunctions::visit(DoWhileStatement *ast) {
{
- TemporaryBoolAssignment allowFuncDecls(_allowFuncDecls, !_env->isStrict);
+ TemporaryBoolAssignment allowFuncDecls(_allowFuncDecls, !_variableEnvironment->isStrict);
Node::accept(ast->statement, this);
}
Node::accept(ast->expression, this);
@@ -383,7 +395,7 @@ bool Codegen::ScanFunctions::visit(ForStatement *ast) {
Node::accept(ast->condition, this);
Node::accept(ast->expression, this);
- TemporaryBoolAssignment allowFuncDecls(_allowFuncDecls, !_env->isStrict);
+ TemporaryBoolAssignment allowFuncDecls(_allowFuncDecls, !_variableEnvironment->isStrict);
Node::accept(ast->statement, this);
return false;
@@ -394,7 +406,7 @@ bool Codegen::ScanFunctions::visit(LocalForStatement *ast) {
Node::accept(ast->condition, this);
Node::accept(ast->expression, this);
- TemporaryBoolAssignment allowFuncDecls(_allowFuncDecls, !_env->isStrict);
+ TemporaryBoolAssignment allowFuncDecls(_allowFuncDecls, !_variableEnvironment->isStrict);
Node::accept(ast->statement, this);
return false;
@@ -404,7 +416,7 @@ bool Codegen::ScanFunctions::visit(ForEachStatement *ast) {
Node::accept(ast->initialiser, this);
Node::accept(ast->expression, this);
- TemporaryBoolAssignment allowFuncDecls(_allowFuncDecls, !_env->isStrict);
+ TemporaryBoolAssignment allowFuncDecls(_allowFuncDecls, !_variableEnvironment->isStrict);
Node::accept(ast->statement, this);
return false;
@@ -414,7 +426,7 @@ bool Codegen::ScanFunctions::visit(LocalForEachStatement *ast) {
Node::accept(ast->declaration, this);
Node::accept(ast->expression, this);
- TemporaryBoolAssignment allowFuncDecls(_allowFuncDecls, !_env->isStrict);
+ TemporaryBoolAssignment allowFuncDecls(_allowFuncDecls, !_variableEnvironment->isStrict);
Node::accept(ast->statement, this);
return false;
@@ -422,12 +434,12 @@ bool Codegen::ScanFunctions::visit(LocalForEachStatement *ast) {
bool Codegen::ScanFunctions::visit(ThisExpression *)
{
- _env->usesThis = true;
+ _variableEnvironment->usesThis = true;
return false;
}
bool Codegen::ScanFunctions::visit(Block *ast) {
- TemporaryBoolAssignment allowFuncDecls(_allowFuncDecls, _env->isStrict ? false : _allowFuncDecls);
+ TemporaryBoolAssignment allowFuncDecls(_allowFuncDecls, _variableEnvironment->isStrict ? false : _allowFuncDecls);
Node::accept(ast->statements, this);
return false;
}
@@ -435,26 +447,26 @@ bool Codegen::ScanFunctions::visit(Block *ast) {
void Codegen::ScanFunctions::enterFunction(Node *ast, const QString &name, FormalParameterList *formals, FunctionBody *body, FunctionExpression *expr, bool isExpression)
{
bool wasStrict = false;
- if (_env) {
- _env->hasNestedFunctions = true;
+ if (_variableEnvironment) {
+ _variableEnvironment->hasNestedFunctions = true;
// The identifier of a function expression cannot be referenced from the enclosing environment.
if (expr)
- _env->enter(name, Environment::FunctionDefinition, expr);
+ _variableEnvironment->enter(name, Environment::FunctionDefinition, AST::VariableDeclaration::FunctionScope, expr);
if (name == QLatin1String("arguments"))
- _env->usesArgumentsObject = Environment::ArgumentsObjectNotUsed;
- wasStrict = _env->isStrict;
+ _variableEnvironment->usesArgumentsObject = Environment::ArgumentsObjectNotUsed;
+ wasStrict = _variableEnvironment->isStrict;
}
enterEnvironment(ast, FunctionCode);
checkForArguments(formals);
- _env->isNamedFunctionExpression = isExpression && !name.isEmpty();
- _env->formals = formals;
+ _variableEnvironment->isNamedFunctionExpression = isExpression && !name.isEmpty();
+ _variableEnvironment->formals = formals;
if (body)
checkDirectivePrologue(body->elements);
- if (wasStrict || _env->isStrict) {
+ if (wasStrict || _variableEnvironment->isStrict) {
QStringList args;
for (FormalParameterList *it = formals; it; it = it->next) {
QString arg = it->name.toString();
@@ -478,7 +490,7 @@ Codegen::Codegen(bool strict)
, _block(0)
, _exitBlock(0)
, _returnAddress(0)
- , _env(0)
+ , _variableEnvironment(0)
, _loop(0)
, _labelledStatement(0)
, _scopeAndFinally(0)
@@ -499,7 +511,7 @@ void Codegen::generateFromProgram(const QString &fileName,
Q_ASSERT(node);
_module = module;
- _env = 0;
+ _variableEnvironment = 0;
_module->setFileName(fileName);
_module->setFinalUrl(finalUrl);
@@ -521,7 +533,7 @@ void Codegen::generateFromFunctionExpression(const QString &fileName,
_module = module;
_module->setFileName(fileName);
_module->setFinalUrl(finalUrl);
- _env = 0;
+ _variableEnvironment = 0;
ScanFunctions scan(this, sourceCode, GlobalCode);
// fake a global environment
@@ -538,14 +550,14 @@ void Codegen::generateFromFunctionExpression(const QString &fileName,
void Codegen::enterEnvironment(Node *node)
{
- _env = _envMap.value(node);
- Q_ASSERT(_env);
+ _variableEnvironment = _envMap.value(node);
+ Q_ASSERT(_variableEnvironment);
}
void Codegen::leaveEnvironment()
{
- Q_ASSERT(_env);
- _env = _env->parent;
+ Q_ASSERT(_variableEnvironment);
+ _variableEnvironment = _variableEnvironment->parent;
}
void Codegen::enterLoop(Statement *node, IR::BasicBlock *breakBlock, IR::BasicBlock *continueBlock)
@@ -1447,7 +1459,7 @@ bool Codegen::visit(DeleteExpression *ast)
return false;
// Temporaries cannot be deleted
IR::ArgLocal *al = expr->asArgLocal();
- if (al && al->index < static_cast<unsigned>(_env->members.size())) {
+ if (al && al->index < static_cast<unsigned>(_variableEnvironment->members.size())) {
// Trying to delete a function argument might throw.
if (_function->isStrict) {
throwSyntaxError(ast->deleteToken, QStringLiteral("Delete of an unqualified identifier in strict mode."));
@@ -1476,7 +1488,7 @@ bool Codegen::visit(DeleteExpression *ast)
}
if (expr->asTemp() ||
(expr->asArgLocal() &&
- expr->asArgLocal()->index >= static_cast<unsigned>(_env->members.size()))) {
+ expr->asArgLocal()->index >= static_cast<unsigned>(_variableEnvironment->members.size()))) {
_expr.code = _block->CONST(IR::BoolType, 1);
return false;
}
@@ -1529,7 +1541,7 @@ IR::Expr *Codegen::identifier(const QString &name, int line, int col)
return 0;
uint scope = 0;
- Environment *e = _env;
+ Environment *e = _variableEnvironment;
IR::Function *f = _function;
while (f && e->parent) {
@@ -1560,7 +1572,7 @@ IR::Expr *Codegen::identifier(const QString &name, int line, int col)
if (IR::Expr *fallback = fallbackNameLookup(name, line, col))
return fallback;
- if (!e->parent && (!f || !f->insideWithOrCatch) && _env->compilationMode != EvalCode && e->compilationMode != QmlBinding)
+ if (!e->parent && (!f || !f->insideWithOrCatch) && _variableEnvironment->compilationMode != EvalCode && e->compilationMode != QmlBinding)
return _block->GLOBALNAME(name, line, col);
// global context or with. Lookup by name
@@ -2076,7 +2088,7 @@ bool Codegen::visit(FunctionDeclaration * ast)
TempScope scope(_function);
- if (_env->compilationMode == QmlBinding)
+ if (_variableEnvironment->compilationMode == QmlBinding)
move(_block->TEMP(_returnAddress), _block->NAME(ast->name.toString(), 0, 0));
_expr.accept(nx);
return false;
@@ -2100,26 +2112,26 @@ int Codegen::defineFunction(const QString &name, AST::Node *ast,
IR::BasicBlock *entryBlock = function->newBasicBlock(0);
IR::BasicBlock *exitBlock = function->newBasicBlock(0, IR::Function::DontInsertBlock);
- function->hasDirectEval = _env->hasDirectEval || _env->compilationMode == EvalCode
+ function->hasDirectEval = _variableEnvironment->hasDirectEval || _variableEnvironment->compilationMode == EvalCode
|| _module->debugMode; // Conditional breakpoints are like eval in the function
- function->usesArgumentsObject = _env->parent && (_env->usesArgumentsObject == Environment::ArgumentsObjectUsed);
- function->usesThis = _env->usesThis;
- function->maxNumberOfArguments = qMax(_env->maxNumberOfArguments, (int)QV4::Global::ReservedArgumentCount);
- function->isStrict = _env->isStrict;
- function->isNamedExpression = _env->isNamedFunctionExpression;
- function->isQmlBinding = _env->compilationMode == QmlBinding;
+ function->usesArgumentsObject = _variableEnvironment->parent && (_variableEnvironment->usesArgumentsObject == Environment::ArgumentsObjectUsed);
+ function->usesThis = _variableEnvironment->usesThis;
+ function->maxNumberOfArguments = qMax(_variableEnvironment->maxNumberOfArguments, (int)QV4::Global::ReservedArgumentCount);
+ function->isStrict = _variableEnvironment->isStrict;
+ function->isNamedExpression = _variableEnvironment->isNamedFunctionExpression;
+ function->isQmlBinding = _variableEnvironment->compilationMode == QmlBinding;
AST::SourceLocation loc = ast->firstSourceLocation();
function->line = loc.startLine;
function->column = loc.startColumn;
if (function->usesArgumentsObject)
- _env->enter(QStringLiteral("arguments"), Environment::VariableDeclaration);
+ _variableEnvironment->enter(QStringLiteral("arguments"), Environment::VariableDeclaration, AST::VariableDeclaration::FunctionScope);
// variables in global code are properties of the global context object, not locals as with other functions.
- if (_env->compilationMode == FunctionCode || _env->compilationMode == QmlBinding) {
+ if (_variableEnvironment->compilationMode == FunctionCode || _variableEnvironment->compilationMode == QmlBinding) {
unsigned t = 0;
- for (Environment::MemberMap::iterator it = _env->members.begin(), end = _env->members.end(); it != end; ++it) {
+ for (Environment::MemberMap::iterator it = _variableEnvironment->members.begin(), end = _variableEnvironment->members.end(); it != end; ++it) {
const QString &local = it.key();
function->LOCAL(local);
(*it).index = t;
@@ -2127,18 +2139,19 @@ int Codegen::defineFunction(const QString &name, AST::Node *ast,
++t;
}
} else {
- if (!_env->isStrict) {
+ if (!_variableEnvironment->isStrict) {
for (const QString &inheritedLocal : qAsConst(inheritedLocals)) {
function->LOCAL(inheritedLocal);
unsigned tempIndex = entryBlock->newTemp();
Environment::Member member = { Environment::UndefinedMember,
- static_cast<int>(tempIndex), 0 };
- _env->members.insert(inheritedLocal, member);
+ static_cast<int>(tempIndex), 0,
+ AST::VariableDeclaration::VariableScope::FunctionScope };
+ _variableEnvironment->members.insert(inheritedLocal, member);
}
}
IR::ExprList *args = 0;
- for (Environment::MemberMap::const_iterator it = _env->members.constBegin(), cend = _env->members.constEnd(); it != cend; ++it) {
+ for (Environment::MemberMap::const_iterator it = _variableEnvironment->members.constBegin(), cend = _variableEnvironment->members.constEnd(); it != cend; ++it) {
const QString &local = it.key();
IR::ExprList *next = function->New<IR::ExprList>();
next->expr = entryBlock->NAME(local, 0, 0);
@@ -2170,11 +2183,11 @@ int Codegen::defineFunction(const QString &name, AST::Node *ast,
_function->RECEIVE(it->name.toString());
}
- for (const Environment::Member &member : qAsConst(_env->members)) {
+ for (const Environment::Member &member : qAsConst(_variableEnvironment->members)) {
if (member.function) {
const int function = defineFunction(member.function->name.toString(), member.function, member.function->formals,
member.function->body ? member.function->body->elements : 0);
- if (! _env->parent) {
+ if (! _variableEnvironment->parent) {
move(_block->NAME(member.function->name.toString(), member.function->identifierToken.startLine, member.function->identifierToken.startColumn),
_block->CLOSURE(function));
} else {
@@ -2360,7 +2373,7 @@ bool Codegen::visit(ExpressionStatement *ast)
TempScope scope(_function);
- if (_env->compilationMode == EvalCode || _env->compilationMode == QmlBinding) {
+ if (_variableEnvironment->compilationMode == EvalCode || _variableEnvironment->compilationMode == QmlBinding) {
Result e = expression(ast->expression);
if (*e)
move(_block->TEMP(_returnAddress), *e);
@@ -2608,7 +2621,7 @@ bool Codegen::visit(ReturnStatement *ast)
if (hasError)
return true;
- if (_env->compilationMode != FunctionCode && _env->compilationMode != QmlBinding) {
+ if (_variableEnvironment->compilationMode != FunctionCode && _variableEnvironment->compilationMode != QmlBinding) {
throwSyntaxError(ast->returnToken, QStringLiteral("Return statement outside of function"));
return false;
}
@@ -2996,7 +3009,7 @@ bool Codegen::visit(UiSourceElement *)
bool Codegen::throwSyntaxErrorOnEvalOrArgumentsInStrictMode(IR::Expr *expr, const SourceLocation& loc)
{
- if (!_env->isStrict)
+ if (!_variableEnvironment->isStrict)
return false;
if (IR::Name *n = expr->asName()) {
if (*n->id != QLatin1String("eval") && *n->id != QLatin1String("arguments"))
diff --git a/src/qml/compiler/qv4codegen_p.h b/src/qml/compiler/qv4codegen_p.h
index a08b9c1d68..f1066b88c5 100644
--- a/src/qml/compiler/qv4codegen_p.h
+++ b/src/qml/compiler/qv4codegen_p.h
@@ -143,10 +143,14 @@ protected:
VariableDeclaration,
FunctionDefinition
};
+
struct Member {
MemberType type;
int index;
AST::FunctionExpression *function;
+ AST::VariableDeclaration::VariableScope scope;
+
+ bool isLexicallyScoped() const { return this->scope != AST::VariableDeclaration::FunctionScope; }
};
typedef QMap<QString, Member> MemberMap;
@@ -193,6 +197,18 @@ protected:
return (*it).index;
}
+ bool memberInfo(const QString &name, const Member **m) const
+ {
+ Q_ASSERT(m);
+ MemberMap::const_iterator it = members.find(name);
+ if (it == members.end()) {
+ *m = 0;
+ return false;
+ }
+ *m = &(*it);
+ return true;
+ }
+
bool lookupMember(const QString &name, Environment **scope, int *index, int *distance)
{
Environment *it = this;
@@ -208,7 +224,7 @@ protected:
return false;
}
- void enter(const QString &name, MemberType type, AST::FunctionExpression *function = 0)
+ void enter(const QString &name, MemberType type, AST::VariableDeclaration::VariableScope scope, AST::FunctionExpression *function = 0)
{
if (! name.isEmpty()) {
if (type != FunctionDefinition) {
@@ -222,8 +238,10 @@ protected:
m.index = -1;
m.type = type;
m.function = function;
+ m.scope = scope;
members.insert(name, m);
} else {
+ Q_ASSERT(scope == (*it).scope);
if ((*it).type <= type) {
(*it).type = type;
(*it).function = function;
@@ -460,7 +478,7 @@ protected:
QV4::IR::BasicBlock *_block;
QV4::IR::BasicBlock *_exitBlock;
unsigned _returnAddress;
- Environment *_env;
+ Environment *_variableEnvironment;
Loop *_loop;
AST::LabelledStatement *_labelledStatement;
ScopeAndFinally *_scopeAndFinally;
@@ -538,7 +556,7 @@ protected:
// fields:
Codegen *_cg;
const QString _sourceCode;
- Environment *_env;
+ Environment *_variableEnvironment;
QStack<Environment *> _envStack;
bool _allowFuncDecls;
diff --git a/src/qml/compiler/qv4compileddata.cpp b/src/qml/compiler/qv4compileddata.cpp
index 7735cd03d8..cacc3752ee 100644
--- a/src/qml/compiler/qv4compileddata.cpp
+++ b/src/qml/compiler/qv4compileddata.cpp
@@ -173,8 +173,6 @@ QV4::Function *CompilationUnit::linkToEngine(ExecutionEngine *engine)
l->level = -1;
l->index = UINT_MAX;
l->nameIndex = compiledLookups[i].nameIndex;
- if (type == CompiledData::Lookup::Type_IndexedGetter || type == CompiledData::Lookup::Type_IndexedSetter)
- l->engine = engine;
}
}
@@ -193,7 +191,7 @@ QV4::Function *CompilationUnit::linkToEngine(ExecutionEngine *engine)
#if Q_BYTE_ORDER == Q_BIG_ENDIAN
Value *bigEndianConstants = new Value[data->constantTableSize];
- const LEUInt64 *littleEndianConstants = data->constants();
+ const quint64_le *littleEndianConstants = data->constants();
for (uint i = 0; i < data->constantTableSize; ++i)
bigEndianConstants[i] = Value::fromReturnedValue(littleEndianConstants[i]);
constants = bigEndianConstants;
@@ -251,14 +249,14 @@ void CompilationUnit::unlink()
#endif
}
-void CompilationUnit::markObjects(QV4::ExecutionEngine *e)
+void CompilationUnit::markObjects(QV4::MarkStack *markStack)
{
for (uint i = 0; i < data->stringTableSize; ++i)
if (runtimeStrings[i])
- runtimeStrings[i]->mark(e);
+ runtimeStrings[i]->mark(markStack);
if (runtimeRegularExpressions) {
for (uint i = 0; i < data->regexpTableSize; ++i)
- runtimeRegularExpressions[i].mark(e);
+ runtimeRegularExpressions[i].mark(markStack);
}
}
@@ -276,7 +274,7 @@ IdentifierHash<int> CompilationUnit::namedObjectsPerComponent(int componentObjec
if (it == namedObjectsPerComponentCache.end()) {
IdentifierHash<int> namedObjectCache(engine);
const CompiledData::Object *component = data->objectAt(componentObjectIndex);
- const LEUInt32 *namedObjectIndexPtr = component->namedObjectsInComponentTable();
+ const quint32_le *namedObjectIndexPtr = component->namedObjectsInComponentTable();
for (quint32 i = 0; i < component->nNamedObjectsInComponent; ++i, ++namedObjectIndexPtr) {
const CompiledData::Object *namedObject = data->objectAt(*namedObjectIndexPtr);
namedObjectCache.add(runtimeStrings[namedObject->idNameIndex], namedObject->id);
diff --git a/src/qml/compiler/qv4compileddata_p.h b/src/qml/compiler/qv4compileddata_p.h
index 188a571394..dc18a78681 100644
--- a/src/qml/compiler/qv4compileddata_p.h
+++ b/src/qml/compiler/qv4compileddata_p.h
@@ -62,7 +62,7 @@
#include <private/qqmlnullablevalue_p.h>
#include <private/qv4identifier_p.h>
#include <private/qflagpointer_p.h>
-#include <private/qjson_p.h>
+#include <private/qendian_p.h>
#ifndef V4_BOOTSTRAP
#include <private/qqmltypenamecache_p.h>
#include <private/qqmlpropertycache_p.h>
@@ -97,13 +97,6 @@ class CompilationUnitMapper;
namespace CompiledData {
-typedef QJsonPrivate::q_littleendian<qint16> LEInt16;
-typedef QJsonPrivate::q_littleendian<quint16> LEUInt16;
-typedef QJsonPrivate::q_littleendian<quint32> LEUInt32;
-typedef QJsonPrivate::q_littleendian<qint32> LEInt32;
-typedef QJsonPrivate::q_littleendian<quint64> LEUInt64;
-typedef QJsonPrivate::q_littleendian<qint64> LEInt64;
-
struct String;
struct Function;
struct Lookup;
@@ -126,11 +119,12 @@ struct TableIterator
struct Location
{
union {
- QJsonPrivate::qle_bitfield<0, 20> line;
- QJsonPrivate::qle_bitfield<20, 12> column;
+ quint32 _dummy;
+ quint32_le_bitfield<0, 20> line;
+ quint32_le_bitfield<20, 12> column;
};
- Location() { line.val = 0; column.val = 0; }
+ Location() : _dummy(0) { }
inline bool operator<(const Location &other) const {
return line < other.line ||
@@ -147,11 +141,12 @@ struct RegExp
RegExp_Multiline = 0x04
};
union {
- QJsonPrivate::qle_bitfield<0, 4> flags;
- QJsonPrivate::qle_bitfield<4, 28> stringIndex;
+ quint32 _dummy;
+ quint32_le_bitfield<0, 4> flags;
+ quint32_le_bitfield<4, 28> stringIndex;
};
- RegExp() { flags.val = 0; stringIndex.val = 0; }
+ RegExp() : _dummy(0) { }
};
static_assert(sizeof(RegExp) == 4, "RegExp structure needs to have the expected size to be binary compatible on disk when generated by host compiler and loaded by target");
@@ -166,28 +161,30 @@ struct Lookup
};
union {
- QJsonPrivate::qle_bitfield<0, 4> type_and_flags;
- QJsonPrivate::qle_bitfield<4, 28> nameIndex;
+ quint32 _dummy;
+ quint32_le_bitfield<0, 4> type_and_flags;
+ quint32_le_bitfield<4, 28> nameIndex;
};
- Lookup() { type_and_flags.val = 0; nameIndex.val = 0; }
+ Lookup() : _dummy(0) { }
};
static_assert(sizeof(Lookup) == 4, "Lookup structure needs to have the expected size to be binary compatible on disk when generated by host compiler and loaded by target");
struct JSClassMember
{
union {
- QJsonPrivate::qle_bitfield<0, 31> nameOffset;
- QJsonPrivate::qle_bitfield<31, 1> isAccessor;
+ quint32 _dummy;
+ quint32_le_bitfield<0, 31> nameOffset;
+ quint32_le_bitfield<31, 1> isAccessor;
};
- JSClassMember() { nameOffset = 0; isAccessor = 0; }
+ JSClassMember() : _dummy(0) { }
};
static_assert(sizeof(JSClassMember) == 4, "JSClassMember structure needs to have the expected size to be binary compatible on disk when generated by host compiler and loaded by target");
struct JSClass
{
- LEUInt32 nMembers;
+ quint32_le nMembers;
// JSClassMember[nMembers]
static int calculateSize(int nMembers) { return (sizeof(JSClass) + nMembers * sizeof(JSClassMember) + 7) & ~7; }
@@ -196,7 +193,7 @@ static_assert(sizeof(JSClass) == 4, "JSClass structure needs to have the expecte
struct String
{
- LEInt32 size;
+ qint32_le size;
// uint16 strdata[]
static int calculateSize(const QString &str) {
@@ -214,29 +211,30 @@ struct Function
HasDirectEval = 0x2,
UsesArgumentsObject = 0x4,
IsNamedExpression = 0x8,
- HasCatchOrWith = 0x10
+ HasCatchOrWith = 0x10,
+ CanUseSimpleCall = 0x20
};
// Absolute offset into file where the code for this function is located. Only used when the function
// is serialized.
- LEUInt64 codeOffset;
- LEUInt64 codeSize;
-
- LEUInt32 nameIndex;
- LEUInt32 nFormals;
- LEUInt32 formalsOffset;
- LEUInt32 nLocals;
- LEUInt32 localsOffset;
- LEUInt32 nInnerFunctions;
+ quint64_le codeOffset;
+ quint64_le codeSize;
+
+ quint32_le nameIndex;
+ quint32_le nFormals;
+ quint32_le formalsOffset;
+ quint32_le nLocals;
+ quint32_le localsOffset;
+ quint32_le nInnerFunctions;
Location location;
// Qml Extensions Begin
- LEUInt32 nDependingIdObjects;
- LEUInt32 dependingIdObjectsOffset; // Array of resolved ID objects
- LEUInt32 nDependingContextProperties;
- LEUInt32 dependingContextPropertiesOffset; // Array of int pairs (property index and notify index)
- LEUInt32 nDependingScopeProperties;
- LEUInt32 dependingScopePropertiesOffset; // Array of int pairs (property index and notify index)
+ quint32_le nDependingIdObjects;
+ quint32_le dependingIdObjectsOffset; // Array of resolved ID objects
+ quint32_le nDependingContextProperties;
+ quint32_le dependingContextPropertiesOffset; // Array of int pairs (property index and notify index)
+ quint32_le nDependingScopeProperties;
+ quint32_le dependingScopePropertiesOffset; // Array of int pairs (property index and notify index)
// Qml Extensions End
// quint32 formalsIndex[nFormals]
@@ -247,17 +245,17 @@ struct Function
// Keep all unaligned data at the end
quint8 flags;
quint8 padding1;
- LEUInt16 padding2;
+ quint16_le padding2;
- const LEUInt32 *formalsTable() const { return reinterpret_cast<const LEUInt32 *>(reinterpret_cast<const char *>(this) + formalsOffset); }
- const LEUInt32 *localsTable() const { return reinterpret_cast<const LEUInt32 *>(reinterpret_cast<const char *>(this) + localsOffset); }
- const LEUInt32 *qmlIdObjectDependencyTable() const { return reinterpret_cast<const LEUInt32 *>(reinterpret_cast<const char *>(this) + dependingIdObjectsOffset); }
- const LEUInt32 *qmlContextPropertiesDependencyTable() const { return reinterpret_cast<const LEUInt32 *>(reinterpret_cast<const char *>(this) + dependingContextPropertiesOffset); }
- const LEUInt32 *qmlScopePropertiesDependencyTable() const { return reinterpret_cast<const LEUInt32 *>(reinterpret_cast<const char *>(this) + dependingScopePropertiesOffset); }
+ 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 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 LEUInt32 *formalsBegin() const { return formalsTable(); }
- const LEUInt32 *formalsEnd() const { return formalsTable() + nFormals; }
+ const quint32_le *formalsBegin() const { return formalsTable(); }
+ const quint32_le *formalsEnd() const { return formalsTable() + nFormals; }
// ---
inline bool hasQmlDependencies() const { return nDependingIdObjects > 0 || nDependingContextProperties > 0 || nDependingScopeProperties > 0; }
@@ -271,14 +269,14 @@ static_assert(sizeof(Function) == 72, "Function structure needs to have the expe
// Qml data structures
struct Q_QML_EXPORT TranslationData {
- LEUInt32 commentIndex;
- LEInt32 number;
+ quint32_le commentIndex;
+ qint32_le number;
};
static_assert(sizeof(TranslationData) == 8, "TranslationData structure needs to have the expected size to be binary compatible on disk when generated by host compiler and loaded by target");
struct Q_QML_PRIVATE_EXPORT Binding
{
- LEUInt32 propertyNameIndex;
+ quint32_le propertyNameIndex;
enum ValueType : unsigned int {
Type_Invalid,
@@ -305,24 +303,23 @@ struct Q_QML_PRIVATE_EXPORT Binding
IsCustomParserBinding = 0x100,
};
- LEUInt32 stringIndex; // Set for Type_String, Type_Translation and Type_Script (the latter because of script strings)
+ union {
+ quint32_le_bitfield<0, 16> flags;
+ quint32_le_bitfield<16, 16> type;
+ };
union {
bool b;
quint64 doubleValue; // do not access directly, needs endian protected access
- LEUInt32 compiledScriptIndex; // used when Type_Script
- LEUInt32 objectIndex;
+ quint32_le compiledScriptIndex; // used when Type_Script
+ quint32_le objectIndex;
TranslationData translationData; // used when Type_Translation
} value;
-
- union {
- QJsonPrivate::qle_bitfield<0, 16> flags;
- QJsonPrivate::qle_bitfield<16, 16> type;
- };
+ quint32_le stringIndex; // Set for Type_String, Type_Translation and Type_Script (the latter because of script strings)
Location location;
Location valueLocation;
- LEUInt32 padding;
+ quint32_le padding;
bool isValueBinding() const
{
@@ -373,7 +370,8 @@ struct Q_QML_PRIVATE_EXPORT Binding
static QString escapedString(const QString &string);
- bool evaluatesToString() const { return type == Type_String || type == Type_Translation || type == Type_TranslationById; }
+ bool containsTranslations() const { return type == Type_Translation || type == Type_TranslationById; }
+ bool evaluatesToString() const { return type == Type_String || containsTranslations(); }
QString valueAsString(const Unit *unit) const;
QString valueAsScriptString(const Unit *unit) const;
@@ -404,19 +402,49 @@ struct Q_QML_PRIVATE_EXPORT Binding
static_assert(sizeof(Binding) == 32, "Binding structure needs to have the expected size to be binary compatible on disk when generated by host compiler and loaded by target");
+struct EnumValue
+{
+ quint32_le nameIndex;
+ qint32_le value;
+ Location location;
+};
+
+struct Enum
+{
+ quint32_le nameIndex;
+ quint32_le nEnumValues;
+ Location location;
+
+ const EnumValue *enumValueAt(int idx) const {
+ return reinterpret_cast<const EnumValue*>(this + 1) + idx;
+ }
+
+ static int calculateSize(int nEnumValues) {
+ return (sizeof(Enum)
+ + nEnumValues * sizeof(EnumValue)
+ + 7) & ~0x7;
+ }
+
+ // --- QQmlPropertyCacheCreatorInterface
+ const EnumValue *enumValuesBegin() const { return enumValueAt(0); }
+ const EnumValue *enumValuesEnd() const { return enumValueAt(nEnumValues); }
+ int enumValueCount() const { return nEnumValues; }
+ // ---
+};
+
struct Parameter
{
- LEUInt32 nameIndex;
- LEUInt32 type;
- LEUInt32 customTypeNameIndex;
+ quint32_le nameIndex;
+ quint32_le type;
+ quint32_le customTypeNameIndex;
Location location;
};
static_assert(sizeof(Parameter) == 16, "Parameter structure needs to have the expected size to be binary compatible on disk when generated by host compiler and loaded by target");
struct Signal
{
- LEUInt32 nameIndex;
- LEUInt32 nParameters;
+ quint32_le nameIndex;
+ quint32_le nParameters;
Location location;
// Parameter parameters[1];
@@ -449,12 +477,12 @@ struct Property
IsReadOnly = 0x1
};
- LEUInt32 nameIndex;
+ quint32_le nameIndex;
union {
- QJsonPrivate::qle_bitfield<0, 31> type;
- QJsonPrivate::qle_bitfield<31, 1> flags; // readonly
+ quint32_le_bitfield<0, 31> type;
+ quint32_le_bitfield<31, 1> flags; // readonly
};
- LEUInt32 customTypeNameIndex; // If type >= Custom
+ quint32_le customTypeNameIndex; // If type >= Custom
Location location;
};
static_assert(sizeof(Property) == 16, "Property structure needs to have the expected size to be binary compatible on disk when generated by host compiler and loaded by target");
@@ -466,18 +494,18 @@ struct Alias {
AliasPointsToPointerObject = 0x4
};
union {
- QJsonPrivate::qle_bitfield<0, 29> nameIndex;
- QJsonPrivate::qle_bitfield<29, 3> flags;
+ quint32_le_bitfield<0, 29> nameIndex;
+ quint32_le_bitfield<29, 3> flags;
};
union {
- LEUInt32 idIndex; // string index
- QJsonPrivate::qle_bitfield<0, 31> targetObjectId; // object id index (in QQmlContextData::idValues)
- QJsonPrivate::qle_bitfield<31, 1> aliasToLocalAlias;
+ quint32_le idIndex; // string index
+ quint32_le_bitfield<0, 31> targetObjectId; // object id index (in QQmlContextData::idValues)
+ quint32_le_bitfield<31, 1> aliasToLocalAlias;
};
union {
- LEUInt32 propertyNameIndex; // string index
- LEInt32 encodedMetaPropertyIndex;
- LEUInt32 localAliasIndex; // index in list of aliases local to the object (if targetObjectId == objectId)
+ quint32_le propertyNameIndex; // string index
+ qint32_le encodedMetaPropertyIndex;
+ quint32_le localAliasIndex; // index in list of aliases local to the object (if targetObjectId == objectId)
};
Location location;
Location referenceLocation;
@@ -501,26 +529,28 @@ struct Object
// Depending on the use, this may be the type name to instantiate before instantiating this
// object. For grouped properties the type name will be empty and for attached properties
// it will be the name of the attached type.
- LEUInt32 inheritedTypeNameIndex;
- LEUInt32 idNameIndex;
+ quint32_le inheritedTypeNameIndex;
+ quint32_le idNameIndex;
union {
- QJsonPrivate::qle_bitfield<0, 15> flags;
- QJsonPrivate::qle_bitfield<15, 1> defaultPropertyIsAlias;
- QJsonPrivate::qle_signedbitfield<16, 16> id;
+ quint32_le_bitfield<0, 15> flags;
+ quint32_le_bitfield<15, 1> defaultPropertyIsAlias;
+ qint32_le_bitfield<16, 16> id;
};
- LEInt32 indexOfDefaultPropertyOrAlias; // -1 means no default property declared in this object
- LEUInt32 nFunctions;
- LEUInt32 offsetToFunctions;
- LEUInt32 nProperties;
- LEUInt32 offsetToProperties;
- LEUInt32 nAliases;
- LEUInt32 offsetToAliases;
- LEUInt32 nSignals;
- LEUInt32 offsetToSignals; // which in turn will be a table with offsets to variable-sized Signal objects
- LEUInt32 nBindings;
- LEUInt32 offsetToBindings;
- LEUInt32 nNamedObjectsInComponent;
- LEUInt32 offsetToNamedObjectsInComponent;
+ qint32_le indexOfDefaultPropertyOrAlias; // -1 means no default property declared in this object
+ quint32_le nFunctions;
+ quint32_le offsetToFunctions;
+ quint32_le nProperties;
+ quint32_le offsetToProperties;
+ quint32_le nAliases;
+ quint32_le offsetToAliases;
+ quint32_le nEnums;
+ quint32_le offsetToEnums; // which in turn will be a table with offsets to variable-sized Enum objects
+ quint32_le nSignals;
+ quint32_le offsetToSignals; // which in turn will be a table with offsets to variable-sized Signal objects
+ quint32_le nBindings;
+ quint32_le offsetToBindings;
+ quint32_le nNamedObjectsInComponent;
+ quint32_le offsetToNamedObjectsInComponent;
Location location;
Location locationOfIdProperty;
// Function[]
@@ -528,12 +558,13 @@ struct Object
// Signal[]
// Binding[]
- static int calculateSizeExcludingSignals(int nFunctions, int nProperties, int nAliases, int nSignals, int nBindings, int nNamedObjectsInComponent)
+ static int calculateSizeExcludingSignalsAndEnums(int nFunctions, int nProperties, int nAliases, int nEnums, int nSignals, int nBindings, int nNamedObjectsInComponent)
{
return ( sizeof(Object)
+ nFunctions * sizeof(quint32)
+ nProperties * sizeof(Property)
+ nAliases * sizeof(Alias)
+ + nEnums * sizeof(quint32)
+ nSignals * sizeof(quint32)
+ nBindings * sizeof(Binding)
+ nNamedObjectsInComponent * sizeof(int)
@@ -541,9 +572,9 @@ struct Object
) & ~0x7;
}
- const LEUInt32 *functionOffsetTable() const
+ const quint32_le *functionOffsetTable() const
{
- return reinterpret_cast<const LEUInt32*>(reinterpret_cast<const char *>(this) + offsetToFunctions);
+ return reinterpret_cast<const quint32_le*>(reinterpret_cast<const char *>(this) + offsetToFunctions);
}
const Property *propertyTable() const
@@ -561,21 +592,29 @@ struct Object
return reinterpret_cast<const Binding*>(reinterpret_cast<const char *>(this) + offsetToBindings);
}
+ const Enum *enumAt(int idx) const
+ {
+ const quint32_le *offsetTable = reinterpret_cast<const quint32_le*>((reinterpret_cast<const char *>(this)) + offsetToEnums);
+ const quint32_le offset = offsetTable[idx];
+ return reinterpret_cast<const Enum*>(reinterpret_cast<const char*>(this) + offset);
+ }
+
const Signal *signalAt(int idx) const
{
- const LEUInt32 *offsetTable = reinterpret_cast<const LEUInt32*>((reinterpret_cast<const char *>(this)) + offsetToSignals);
- const LEUInt32 offset = offsetTable[idx];
+ const quint32_le *offsetTable = reinterpret_cast<const quint32_le*>((reinterpret_cast<const char *>(this)) + offsetToSignals);
+ const quint32_le offset = offsetTable[idx];
return reinterpret_cast<const Signal*>(reinterpret_cast<const char*>(this) + offset);
}
- const LEUInt32 *namedObjectsInComponentTable() const
+ const quint32_le *namedObjectsInComponentTable() const
{
- return reinterpret_cast<const LEUInt32*>(reinterpret_cast<const char *>(this) + offsetToNamedObjectsInComponent);
+ return reinterpret_cast<const quint32_le*>(reinterpret_cast<const char *>(this) + offsetToNamedObjectsInComponent);
}
// --- QQmlPropertyCacheCreator interface
int propertyCount() const { return nProperties; }
int aliasCount() const { return nAliases; }
+ int enumCount() const { return nEnums; }
int signalCount() const { return nSignals; }
int functionCount() const { return nFunctions; }
@@ -588,6 +627,10 @@ struct Object
const Alias *aliasesBegin() const { return aliasTable(); }
const Alias *aliasesEnd() const { return aliasTable() + nAliases; }
+ typedef TableIterator<Enum, Object, &Object::enumAt> EnumIterator;
+ EnumIterator enumsBegin() const { return EnumIterator(this, 0); }
+ EnumIterator enumsEnd() const { return EnumIterator(this, nEnums); }
+
typedef TableIterator<Signal, Object, &Object::signalAt> SignalIterator;
SignalIterator signalsBegin() const { return SignalIterator(this, 0); }
SignalIterator signalsEnd() const { return SignalIterator(this, nSignals); }
@@ -595,7 +638,7 @@ struct Object
int namedObjectsInComponentCount() const { return nNamedObjectsInComponent; }
// ---
};
-static_assert(sizeof(Object) == 72, "Object 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(Object) == 80, "Object structure needs to have the expected size to be binary compatible on disk when generated by host compiler and loaded by target");
struct Import
{
@@ -604,13 +647,13 @@ struct Import
ImportFile = 0x2,
ImportScript = 0x3
};
- LEUInt32 type;
+ quint32_le type;
- LEUInt32 uriIndex;
- LEUInt32 qualifierIndex;
+ quint32_le uriIndex;
+ quint32_le qualifierIndex;
- LEInt32 majorVersion;
- LEInt32 minorVersion;
+ qint32_le majorVersion;
+ qint32_le minorVersion;
Location location;
@@ -624,17 +667,17 @@ struct Unit
{
// DO NOT CHANGE THESE FIELDS EVER
char magic[8];
- LEUInt32 version;
- LEUInt32 qtVersion;
- LEInt64 sourceTimeStamp;
- LEUInt32 unitSize; // Size of the Unit and any depending data.
+ quint32_le version;
+ quint32_le qtVersion;
+ qint64_le sourceTimeStamp;
+ quint32_le unitSize; // Size of the Unit and any depending data.
// END DO NOT CHANGE THESE FIELDS EVER
char md5Checksum[16]; // checksum of all bytes following this field.
void generateChecksum();
- LEUInt32 architectureIndex; // string index to QSysInfo::buildAbi()
- LEUInt32 codeGeneratorIndex;
+ quint32_le architectureIndex; // string index to QSysInfo::buildAbi()
+ quint32_le codeGeneratorIndex;
char dependencyMD5Checksum[16];
enum : unsigned int {
@@ -646,38 +689,38 @@ struct Unit
ContainsMachineCode = 0x20, // used to determine if we need to mmap with execute permissions
PendingTypeCompilation = 0x40 // the QML data structures present are incomplete and require type compilation
};
- LEUInt32 flags;
- LEUInt32 stringTableSize;
- LEUInt32 offsetToStringTable;
- LEUInt32 functionTableSize;
- LEUInt32 offsetToFunctionTable;
- LEUInt32 lookupTableSize;
- LEUInt32 offsetToLookupTable;
- LEUInt32 regexpTableSize;
- LEUInt32 offsetToRegexpTable;
- LEUInt32 constantTableSize;
- LEUInt32 offsetToConstantTable;
- LEUInt32 jsClassTableSize;
- LEUInt32 offsetToJSClassTable;
- LEInt32 indexOfRootFunction;
- LEUInt32 sourceFileIndex;
- LEUInt32 finalUrlIndex;
+ quint32_le flags;
+ quint32_le stringTableSize;
+ quint32_le offsetToStringTable;
+ quint32_le functionTableSize;
+ quint32_le offsetToFunctionTable;
+ quint32_le lookupTableSize;
+ quint32_le offsetToLookupTable;
+ quint32_le regexpTableSize;
+ quint32_le offsetToRegexpTable;
+ quint32_le constantTableSize;
+ quint32_le offsetToConstantTable;
+ quint32_le jsClassTableSize;
+ quint32_le offsetToJSClassTable;
+ qint32_le indexOfRootFunction;
+ quint32_le sourceFileIndex;
+ quint32_le finalUrlIndex;
/* QML specific fields */
- LEUInt32 nImports;
- LEUInt32 offsetToImports;
- LEUInt32 nObjects;
- LEUInt32 offsetToObjects;
+ quint32_le nImports;
+ quint32_le offsetToImports;
+ quint32_le nObjects;
+ quint32_le offsetToObjects;
- LEUInt32 padding;
+ quint32_le padding;
const Import *importAt(int idx) const {
return reinterpret_cast<const Import*>((reinterpret_cast<const char *>(this)) + offsetToImports + idx * sizeof(Import));
}
const Object *objectAt(int idx) const {
- const LEUInt32 *offsetTable = reinterpret_cast<const LEUInt32*>((reinterpret_cast<const char *>(this)) + offsetToObjects);
- const LEUInt32 offset = offsetTable[idx];
+ const quint32_le *offsetTable = reinterpret_cast<const quint32_le*>((reinterpret_cast<const char *>(this)) + offsetToObjects);
+ const quint32_le offset = offsetTable[idx];
return reinterpret_cast<const Object*>(reinterpret_cast<const char*>(this) + offset);
}
@@ -687,8 +730,8 @@ struct Unit
/* end QML specific fields*/
QString stringAt(int idx) const {
- const LEUInt32 *offsetTable = reinterpret_cast<const LEUInt32*>((reinterpret_cast<const char *>(this)) + offsetToStringTable);
- const LEUInt32 offset = offsetTable[idx];
+ const quint32_le *offsetTable = reinterpret_cast<const quint32_le*>((reinterpret_cast<const char *>(this)) + offsetToStringTable);
+ const quint32_le offset = offsetTable[idx];
const String *str = reinterpret_cast<const String*>(reinterpret_cast<const char *>(this) + offset);
if (str->size == 0)
return QString();
@@ -700,7 +743,7 @@ struct Unit
// return QString::fromRawData(characters, str->size);
return QString(characters, str->size);
#else
- const LEUInt16 *characters = reinterpret_cast<const LEUInt16 *>(str + 1);
+ const quint16_le *characters = reinterpret_cast<const quint16_le *>(str + 1);
QString qstr(str->size, Qt::Uninitialized);
QChar *ch = qstr.data();
for (int i = 0; i < str->size; ++i)
@@ -709,11 +752,11 @@ struct Unit
#endif
}
- const LEUInt32 *functionOffsetTable() const { return reinterpret_cast<const LEUInt32*>((reinterpret_cast<const char *>(this)) + offsetToFunctionTable); }
+ const quint32_le *functionOffsetTable() const { return reinterpret_cast<const quint32_le*>((reinterpret_cast<const char *>(this)) + offsetToFunctionTable); }
const Function *functionAt(int idx) const {
- const LEUInt32 *offsetTable = functionOffsetTable();
- const LEUInt32 offset = offsetTable[idx];
+ const quint32_le *offsetTable = functionOffsetTable();
+ const quint32_le offset = offsetTable[idx];
return reinterpret_cast<const Function*>(reinterpret_cast<const char *>(this) + offset);
}
@@ -721,13 +764,13 @@ struct Unit
const RegExp *regexpAt(int index) const {
return reinterpret_cast<const RegExp*>(reinterpret_cast<const char *>(this) + offsetToRegexpTable + index * sizeof(RegExp));
}
- const LEUInt64 *constants() const {
- return reinterpret_cast<const LEUInt64*>(reinterpret_cast<const char *>(this) + offsetToConstantTable);
+ const quint64_le *constants() const {
+ return reinterpret_cast<const quint64_le*>(reinterpret_cast<const char *>(this) + offsetToConstantTable);
}
const JSClassMember *jsClassAt(int idx, int *nMembers) const {
- const LEUInt32 *offsetTable = reinterpret_cast<const LEUInt32 *>(reinterpret_cast<const char *>(this) + offsetToJSClassTable);
- const LEUInt32 offset = offsetTable[idx];
+ const quint32_le *offsetTable = reinterpret_cast<const quint32_le *>(reinterpret_cast<const char *>(this) + offsetToJSClassTable);
+ const quint32_le offset = offsetTable[idx];
const char *ptr = reinterpret_cast<const char *>(this) + offset;
const JSClass *klass = reinterpret_cast<const JSClass *>(ptr);
*nMembers = klass->nMembers;
@@ -930,7 +973,7 @@ struct Q_QML_PRIVATE_EXPORT CompilationUnit : public CompilationUnitBase, public
QV4::Function *linkToEngine(QV4::ExecutionEngine *engine);
void unlink();
- void markObjects(QV4::ExecutionEngine *e);
+ void markObjects(MarkStack *markStack);
void destroy() Q_DECL_OVERRIDE;
diff --git a/src/qml/compiler/qv4compiler.cpp b/src/qml/compiler/qv4compiler.cpp
index 0dc40d9698..fc03320a20 100644
--- a/src/qml/compiler/qv4compiler.cpp
+++ b/src/qml/compiler/qv4compiler.cpp
@@ -78,7 +78,7 @@ void QV4::Compiler::StringTableGenerator::clear()
void QV4::Compiler::StringTableGenerator::serialize(CompiledData::Unit *unit)
{
char *dataStart = reinterpret_cast<char *>(unit);
- CompiledData::LEUInt32 *stringTable = reinterpret_cast<CompiledData::LEUInt32 *>(dataStart + unit->offsetToStringTable);
+ quint32_le *stringTable = reinterpret_cast<quint32_le *>(dataStart + unit->offsetToStringTable);
char *stringData = dataStart + unit->offsetToStringTable + unit->stringTableSize * sizeof(uint);
for (int i = 0; i < strings.size(); ++i) {
stringTable[i] = stringData - dataStart;
@@ -221,7 +221,7 @@ QV4::CompiledData::Unit *QV4::Compiler::JSUnitGenerator::generateUnit(GeneratorO
registerString(*f->locals.at(i));
}
- Q_ALLOCA_VAR(CompiledData::LEUInt32, functionOffsets, irModule->functions.size() * sizeof(CompiledData::LEUInt32));
+ Q_ALLOCA_VAR(quint32_le, functionOffsets, irModule->functions.size() * sizeof(quint32_le));
uint jsClassDataOffset = 0;
char *dataPtr;
@@ -234,7 +234,7 @@ QV4::CompiledData::Unit *QV4::Compiler::JSUnitGenerator::generateUnit(GeneratorO
memcpy(unit, &tempHeader, sizeof(tempHeader));
}
- memcpy(dataPtr + unit->offsetToFunctionTable, functionOffsets, unit->functionTableSize * sizeof(CompiledData::LEUInt32));
+ memcpy(dataPtr + unit->offsetToFunctionTable, functionOffsets, unit->functionTableSize * sizeof(quint32_le));
for (int i = 0; i < irModule->functions.size(); ++i) {
QV4::IR::Function *function = irModule->functions.at(i);
@@ -255,7 +255,7 @@ QV4::CompiledData::Unit *QV4::Compiler::JSUnitGenerator::generateUnit(GeneratorO
ReturnedValue *constantTable = reinterpret_cast<ReturnedValue *>(dataPtr + unit->offsetToConstantTable);
memcpy(constantTable, constants.constData(), constants.size() * sizeof(ReturnedValue));
#else
- CompiledData::LEUInt64 *constantTable = reinterpret_cast<CompiledData::LEUInt64 *>(dataPtr + unit->offsetToConstantTable);
+ quint64_le *constantTable = reinterpret_cast<quint64_le *>(dataPtr + unit->offsetToConstantTable);
for (int i = 0; i < constants.count(); ++i)
constantTable[i] = constants.at(i);
#endif
@@ -264,7 +264,7 @@ QV4::CompiledData::Unit *QV4::Compiler::JSUnitGenerator::generateUnit(GeneratorO
memcpy(dataPtr + jsClassDataOffset, jsClassData.constData(), jsClassData.size());
// write js classes and js class lookup table
- CompiledData::LEUInt32 *jsClassOffsetTable = reinterpret_cast<CompiledData::LEUInt32 *>(dataPtr + unit->offsetToJSClassTable);
+ quint32_le *jsClassOffsetTable = reinterpret_cast<quint32_le *>(dataPtr + unit->offsetToJSClassTable);
for (int i = 0; i < jsClassOffsets.count(); ++i)
jsClassOffsetTable[i] = jsClassDataOffset + jsClassOffsets.at(i);
}
@@ -297,6 +297,8 @@ void QV4::Compiler::JSUnitGenerator::writeFunction(char *f, QV4::IR::Function *i
function->flags |= CompiledData::Function::IsNamedExpression;
if (irFunction->hasTry || irFunction->hasWith)
function->flags |= CompiledData::Function::HasCatchOrWith;
+ if (irFunction->canUseSimpleCall())
+ function->flags |= CompiledData::Function::CanUseSimpleCall;
function->nFormals = irFunction->formals.size();
function->formalsOffset = currentOffset;
currentOffset += function->nFormals * sizeof(quint32);
@@ -336,36 +338,36 @@ void QV4::Compiler::JSUnitGenerator::writeFunction(char *f, QV4::IR::Function *i
function->codeSize = 0;
// write formals
- CompiledData::LEUInt32 *formals = (CompiledData::LEUInt32 *)(f + function->formalsOffset);
+ quint32_le *formals = (quint32_le *)(f + function->formalsOffset);
for (int i = 0; i < irFunction->formals.size(); ++i)
formals[i] = getStringId(*irFunction->formals.at(i));
// write locals
- CompiledData::LEUInt32 *locals = (CompiledData::LEUInt32 *)(f + function->localsOffset);
+ quint32_le *locals = (quint32_le *)(f + function->localsOffset);
for (int i = 0; i < irFunction->locals.size(); ++i)
locals[i] = getStringId(*irFunction->locals.at(i));
// write QML dependencies
- CompiledData::LEUInt32 *writtenDeps = (CompiledData::LEUInt32 *)(f + function->dependingIdObjectsOffset);
+ quint32_le *writtenDeps = (quint32_le *)(f + function->dependingIdObjectsOffset);
for (int id : irFunction->idObjectDependencies) {
Q_ASSERT(id >= 0);
*writtenDeps++ = static_cast<quint32>(id);
}
- writtenDeps = (CompiledData::LEUInt32 *)(f + function->dependingContextPropertiesOffset);
+ writtenDeps = (quint32_le *)(f + function->dependingContextPropertiesOffset);
for (auto property : irFunction->contextObjectPropertyDependencies) {
*writtenDeps++ = property.key(); // property index
*writtenDeps++ = property.value(); // notify index
}
- writtenDeps = (CompiledData::LEUInt32 *)(f + function->dependingScopePropertiesOffset);
+ writtenDeps = (quint32_le *)(f + function->dependingScopePropertiesOffset);
for (auto property : irFunction->scopeObjectPropertyDependencies) {
*writtenDeps++ = property.key(); // property index
*writtenDeps++ = property.value(); // notify index
}
}
-QV4::CompiledData::Unit QV4::Compiler::JSUnitGenerator::generateHeader(QV4::Compiler::JSUnitGenerator::GeneratorOption option, QJsonPrivate::q_littleendian<quint32> *functionOffsets, uint *jsClassDataOffset)
+QV4::CompiledData::Unit QV4::Compiler::JSUnitGenerator::generateHeader(QV4::Compiler::JSUnitGenerator::GeneratorOption option, quint32_le *functionOffsets, uint *jsClassDataOffset)
{
CompiledData::Unit unit;
memset(&unit, 0, sizeof(unit));
diff --git a/src/qml/compiler/qv4compiler_p.h b/src/qml/compiler/qv4compiler_p.h
index 49b8664513..9c51a44bad 100644
--- a/src/qml/compiler/qv4compiler_p.h
+++ b/src/qml/compiler/qv4compiler_p.h
@@ -52,7 +52,7 @@
#include <QtCore/qstring.h>
#include "qv4jsir_p.h"
-#include <private/qjson_p.h>
+#include <private/qendian_p.h>
QT_BEGIN_NAMESPACE
@@ -120,7 +120,7 @@ struct Q_QML_PRIVATE_EXPORT JSUnitGenerator {
StringTableGenerator stringTable;
QString codeGeneratorName;
private:
- CompiledData::Unit generateHeader(GeneratorOption option, QJsonPrivate::q_littleendian<quint32> *functionOffsets, uint *jsClassDataOffset);
+ CompiledData::Unit generateHeader(GeneratorOption option, quint32_le *functionOffsets, uint *jsClassDataOffset);
IR::Module *irModule;
diff --git a/src/qml/compiler/qv4jsir_p.h b/src/qml/compiler/qv4jsir_p.h
index 317abd09bb..8c314a9635 100644
--- a/src/qml/compiler/qv4jsir_p.h
+++ b/src/qml/compiler/qv4jsir_p.h
@@ -1369,6 +1369,31 @@ struct Function {
int getNewStatementId() { return _statementCount++; }
int statementCount() const { return _statementCount; }
+ bool canUseSimpleCall() const {
+ return nestedFunctions.isEmpty() &&
+ locals.isEmpty() && formals.size() <= QV4::Global::ReservedArgumentCount &&
+ !hasTry && !hasWith && !isNamedExpression && !usesArgumentsObject && !hasDirectEval;
+ }
+
+ bool argLocalRequiresWriteBarrier(ArgLocal *al) const {
+ uint scope = al->scope;
+ const IR::Function *f = this;
+ while (scope) {
+ f = f->outer;
+ --scope;
+ }
+ return !f->canUseSimpleCall();
+ }
+ int localsCountForScope(ArgLocal *al) const {
+ uint scope = al->scope;
+ const IR::Function *f = this;
+ while (scope) {
+ f = f->outer;
+ --scope;
+ }
+ return f->locals.size();
+ }
+
private:
BasicBlock *getOrCreateBasicBlock(int index);
void setStatementCount(int cnt);
@@ -1437,6 +1462,7 @@ public:
ArgLocal *newArgLocal = f->New<ArgLocal>();
newArgLocal->init(argLocal->kind, argLocal->index, argLocal->scope);
newArgLocal->type = argLocal->type;
+ newArgLocal->isArgumentsOrEval = argLocal->isArgumentsOrEval;
return newArgLocal;
}
diff --git a/src/qml/debugger/qqmlprofiler_p.h b/src/qml/debugger/qqmlprofiler_p.h
index a220e9cfc8..54efbb5d73 100644
--- a/src/qml/debugger/qqmlprofiler_p.h
+++ b/src/qml/debugger/qqmlprofiler_p.h
@@ -238,14 +238,19 @@ public:
// produce. The +1 makes the pointer point into the middle of the QV4::Function. Thus it
// still points to valid memory but we cannot accidentally create a duplicate key from
// another object.
- quintptr locationId(id(function) + 1);
+ // If there is no function, use a static but valid address: The profiler itself.
+ quintptr locationId = function ? id(function) + 1 : id(this);
m_data.append(QQmlProfilerData(m_timer.nsecsElapsed(),
(1 << RangeStart | 1 << RangeLocation), Binding,
locationId));
RefLocation &location = m_locations[locationId];
- if (!location.isValid())
- location = RefLocation(function);
+ if (!location.isValid()) {
+ if (function)
+ location = RefLocation(function);
+ else // Make it valid without actually providing a location
+ location.locationType = Binding;
+ }
}
// Have toByteArrays() construct another RangeData event from the same QString later.
diff --git a/src/qml/doc/qtqml.qdocconf b/src/qml/doc/qtqml.qdocconf
index 74b61fd6e1..6161760471 100644
--- a/src/qml/doc/qtqml.qdocconf
+++ b/src/qml/doc/qtqml.qdocconf
@@ -53,6 +53,8 @@ manifestmeta.thumbnail.names += "QtQml/Chapter 4*" \
"QtQml/Chapter 6*" \
"QtQml/C++ Extensions: *"
+manifestmeta.highlighted.names = "QtQml/Writing QML Extensions with C++"
+
navigation.landingpage = "Qt QML"
navigation.cppclassespage = "Qt QML C++ Classes"
navigation.qmltypespage = "Qt QML QML Types"
diff --git a/src/qml/doc/snippets/code/src_script_qjsengine.cpp b/src/qml/doc/snippets/code/src_script_qjsengine.cpp
index 0310ae042c..6c58fd8a18 100644
--- a/src/qml/doc/snippets/code/src_script_qjsengine.cpp
+++ b/src/qml/doc/snippets/code/src_script_qjsengine.cpp
@@ -58,7 +58,7 @@ QJSValue three = myEngine.evaluate("1 + 2");
QJSValue fun = myEngine.evaluate("(function(a, b) { return a + b; })");
QJSValueList args;
args << 1 << 2;
-QJSValue threeAgain = fun.call(QJSValue(), args);
+QJSValue threeAgain = fun.call(args);
//! [1]
diff --git a/src/qml/doc/src/cppintegration/data.qdoc b/src/qml/doc/src/cppintegration/data.qdoc
index 3e02bbc458..9b2771c18e 100644
--- a/src/qml/doc/src/cppintegration/data.qdoc
+++ b/src/qml/doc/src/cppintegration/data.qdoc
@@ -271,10 +271,17 @@ In particular, QML currently supports:
\li \c {QList<qreal>}
\li \c {QList<bool>}
\li \c {QList<QString>} and \c{QStringList}
+ \li \c {QVector<QString>}
+ \li \c {std::vector<QString>}
\li \c {QList<QUrl>}
+ \li \c {QVector<QUrl>}
+ \li \c {std::vector<QUrl>}
\li \c {QVector<int>}
\li \c {QVector<qreal>}
\li \c {QVector<bool>}
+ \li \c {std::vector<int>}
+ \li \c {std::vector<qreal>}
+ \li \c {std::vector<bool>}
\endlist
These sequence types are implemented directly in terms of the underlying C++
@@ -294,6 +301,10 @@ If the sequence is returned from a Q_INVOKABLE function, access and mutation
is much cheaper, as no QObject property read or write occurs; instead, the
C++ sequence data is accessed and modified directly.
+In both the Q_PROPERTY and return from Q_INVOKABLE cases, the elements
+of a std::vector are copied. This copying may be an expensive operation,
+so std::vector should be used judiciously.
+
Other sequence types are not supported transparently, and instead an
instance of any other sequence type will be passed between QML and C++ as an
opaque QVariantList.
@@ -316,10 +327,17 @@ The default-constructed values for each sequence type are as follows:
\row \li QList<qreal> \li real value 0.0
\row \li QList<bool> \li boolean value \c {false}
\row \li QList<QString> and QStringList \li empty QString
+\row \li QVector<QString> \li empty QString
+\row \li std::vector<QString> \li empty QString
\row \li QList<QUrl> \li empty QUrl
+\row \li QVector<QUrl> \li empty QUrl
+\row \li std::vector<QUrl> \li empty QUrl
\row \li QVector<int> \li integer value 0
\row \li QVector<qreal> \li real value 0.0
\row \li QVector<bool> \li boolean value \c {false}
+\row \li std::vector<int> \li integer value 0
+\row \li std::vector<qreal> \li real value 0.0
+\row \li std::vector<bool> \li boolean value \c {false}
\endtable
If you wish to remove elements from a sequence rather than simply replace
@@ -327,6 +345,11 @@ them with default constructed values, do not use the indexed delete operator
("delete sequence[i]") but instead use the \c {splice} function
("sequence.splice(startIndex, deleteCount)").
+\section2 QByteArray to JavaScript ArrayBuffer
+
+The QML engine provides automatic type conversion between QByteArray values and
+JavaScript \c ArrayBuffer objects.
+
\section2 Value Types
Some value types in Qt such as QPoint are represented in JavaScript as objects
diff --git a/src/qml/doc/src/cppintegration/definetypes.qdoc b/src/qml/doc/src/cppintegration/definetypes.qdoc
index 7f88dc6836..027e4b9923 100644
--- a/src/qml/doc/src/cppintegration/definetypes.qdoc
+++ b/src/qml/doc/src/cppintegration/definetypes.qdoc
@@ -606,7 +606,6 @@ public:
RandomNumberGenerator(QObject *parent)
: QObject(parent), m_maxValue(100)
{
- qsrand(QDateTime::currentMSecsSinceEpoch() / 1000);
QObject::connect(&m_timer, SIGNAL(timeout()), SLOT(updateProperty()));
m_timer.start(500);
}
@@ -621,7 +620,7 @@ signals:
private slots:
void updateProperty() {
- m_targetProperty.write(qrand() % m_maxValue);
+ m_targetProperty.write(QRandomGenerator::global()->bounded(m_maxValue));
}
private:
diff --git a/src/qml/doc/src/cppintegration/extending-tutorial.qdoc b/src/qml/doc/src/cppintegration/extending-tutorial.qdoc
index ef6f2b52b3..26556644d6 100644
--- a/src/qml/doc/src/cppintegration/extending-tutorial.qdoc
+++ b/src/qml/doc/src/cppintegration/extending-tutorial.qdoc
@@ -150,6 +150,10 @@ Now we can build and run the application:
cannot update the binding if the \c name value changes. This is addressed in
the following chapters.
+The source code from the following files are referred to in this chapter:
+\noautolist
+\generatelist examplefiles .*chapter1.*
+
\section1 Chapter 2: Connecting to C++ Methods and Signals
\c extending-qml/chapter2-methods
@@ -189,6 +193,9 @@ disappears, and the application outputs:
qml: The chart has been cleared
\endcode
+The source code from the following files are referred to in this chapter:
+\generatelist examplefiles .*chapter2.*
+
\section1 Chapter 3: Adding Property Bindings
\c extending-qml/chapter3-bindings
@@ -237,6 +244,9 @@ automatically updated and cannot be used as flexibly in QML. Also, since
bindings are invoked so often and relied upon in QML usage, users of your
custom QML types may see unexpected behavior if bindings are not implemented.
+The source code from the following files are referred to in this chapter:
+\generatelist examplefiles .*chapter3.*
+
\section1 Chapter 4: Using Custom Property Types
\c extending-qml/chapter4-customPropertyTypes
@@ -314,6 +324,9 @@ type to the "Charts" type namespace, version 1.0:
\dots
\snippet tutorials/extending-qml/chapter4-customPropertyTypes/main.cpp 2
+The source code from the following files are referred to in this chapter:
+\generatelist examplefiles .*chapter4.*
+
\section1 Chapter 5: Using List Property Types
\c extending-qml/chapter5-listproperties
@@ -356,6 +369,9 @@ The \c PieSlice class has also been modified to include \c fromAngle and \c angl
properties and to draw the slice according to these values. This is a straightforward
modification if you have read the previous pages in this tutorial, so the code is not shown here.
+The source code from the following files are referred to in this chapter:
+\generatelist examplefiles .*chapter5.*
+
\section1 Chapter 6: Writing an Extension Plugin
\c extending-qml/chapter6-plugins
@@ -429,6 +445,9 @@ import path to the current directory so that it finds the \c qmldir file:
The module "Charts" will be loaded by the QML engine, and the types provided by that
module will be available for use in any QML document which imports it.
+The source code from the following files are referred to in this chapter:
+\generatelist examplefiles .*chapter6.*
+
\section1 Chapter 7: Summary
In this tutorial, we've shown the basic steps for creating a QML extension:
diff --git a/src/qml/doc/src/cppintegration/interactqmlfromcpp.qdoc b/src/qml/doc/src/cppintegration/interactqmlfromcpp.qdoc
index 4dc32e3588..7c2ff703c6 100644
--- a/src/qml/doc/src/cppintegration/interactqmlfromcpp.qdoc
+++ b/src/qml/doc/src/cppintegration/interactqmlfromcpp.qdoc
@@ -114,17 +114,7 @@ multiple children with the same \c objectName. In this case,
QObject::findChildren() can be used to find all children with a matching
\c objectName.
-\warning While it is possible to use C++ to access and manipulate QML objects
-deep into the object tree, we recommend that you do not take this approach
-outside of application testing and prototyping. One strength of QML and C++
-integration is the ability to implement the QML user interface separately
-from the C++ logic and dataset backend, and this strategy breaks if the C++
-side reaches deep into the QML components to manipulate them directly. This
-would make it difficult to, for example, swap a QML view component for
-another view, if the new component was missing a required \c objectName. It
-is better for the C++ implementation to know as little as possible about the
-QML user interface implementation and the composition of the QML object tree.
-
+\include warning.qdocinc
\section1 Accessing Members of a QML Object Type from C++
diff --git a/src/qml/doc/src/cppintegration/topic.qdoc b/src/qml/doc/src/cppintegration/topic.qdoc
index da06c195dc..6b6e308edf 100644
--- a/src/qml/doc/src/cppintegration/topic.qdoc
+++ b/src/qml/doc/src/cppintegration/topic.qdoc
@@ -190,6 +190,8 @@ invoke their methods and receive their signal notifications. This is possible du
all QML object types are implemented using QObject-derived classes, enabling the QML engine to
dynamically load and introspect objects through the Qt meta object system.
+\include warning.qdocinc
+
For more information on accessing QML objects from C++, see the documentation on
\l{qtqml-cppintegration-interactqmlfromcpp.html}{Interacting with QML Objects from C++}.
diff --git a/src/qml/doc/src/cppintegration/warning.qdocinc b/src/qml/doc/src/cppintegration/warning.qdocinc
new file mode 100644
index 0000000000..a5da22b2a7
--- /dev/null
+++ b/src/qml/doc/src/cppintegration/warning.qdocinc
@@ -0,0 +1,6 @@
+\warning Although it is possible to access QML objects from C++ and manipulate
+them, it is not the recommended approach, except for testing and prototyping
+purposes. One of the strengths of QML and C++ integration is the ability to
+implement UIs in QML separate from the C++ logic and dataset backend, and this
+fails if the C++ side starts manipulating QML directly. Such an approach also
+makes changing the QML UI difficult without affecting its C++ counterpart.
diff --git a/src/qml/doc/src/javascript/functionlist.qdoc b/src/qml/doc/src/javascript/functionlist.qdoc
index b99e92cf52..24ff640284 100644
--- a/src/qml/doc/src/javascript/functionlist.qdoc
+++ b/src/qml/doc/src/javascript/functionlist.qdoc
@@ -182,6 +182,7 @@
\li lastIndexOf(searchString, position)
\li localeCompare(that)
\li match(regexp)
+ \li repeat(count) // ECMAScript 6: Added in Qt 5.9
\li replace(searchValue, replaceValue)
\li search(regexp)
\li slice(start, end)
diff --git a/src/qml/doc/src/javascript/hostenvironment.qdoc b/src/qml/doc/src/javascript/hostenvironment.qdoc
index 3c3624f78d..d11e96df2b 100644
--- a/src/qml/doc/src/javascript/hostenvironment.qdoc
+++ b/src/qml/doc/src/javascript/hostenvironment.qdoc
@@ -74,6 +74,19 @@ Note that QML makes the following modifications to native objects:
\li Locale-aware conversion functions are added to the \l Date and \l Number prototypes.
\endlist
+In addition, QML also extends the behavior of the instanceof function to
+allow for type checking against QML types. This means that you may use it to
+verify that a variable is indeed the type you expect, for example:
+
+\qml
+ var v = something();
+ if (!v instanceof Item) {
+ throw new TypeError("I need an Item type!");
+ }
+
+ ...
+\endqml
+
\section1 JavaScript Environment Restrictions
diff --git a/src/qml/doc/src/qmllanguageref/syntax/objectattributes.qdoc b/src/qml/doc/src/qmllanguageref/syntax/objectattributes.qdoc
index 568ad930f2..31650db7c0 100644
--- a/src/qml/doc/src/qmllanguageref/syntax/objectattributes.qdoc
+++ b/src/qml/doc/src/qmllanguageref/syntax/objectattributes.qdoc
@@ -50,6 +50,7 @@ The set of QML object-type attribute types is as follows:
\li signal handler attributes
\li method attributes
\li attached properties and attached signal handler attributes
+\li enumeration attributes
\endlist
These attributes are discussed in detail below.
@@ -999,4 +1000,41 @@ ListView {
Now \c delegateItem.ListView.isCurrentItem correctly refers to the
\c isCurrentItem attached property of the delegate.
+\section2 Enumeration Attributes
+
+Enumerations provide a fixed set of named choices. They can be declared in QML using the \c enum keyword:
+
+\qml
+// MyText.qml
+Text {
+ enum TextType {
+ Normal,
+ Heading
+ }
+}
+\endqml
+
+As shown above, enumeration types (e.g. \c TextType) and values (e.g. \c Normal) must begin with an uppercase letter.
+
+Values are referred to via \c {<Type>.<EnumerationType>.<Value>} or \c {<Type>.<Value>}.
+
+\qml
+// MyText.qml
+Text {
+ enum TextType {
+ Normal,
+ Heading
+ }
+
+ property int textType: MyText.TextType.Normal
+
+ font.bold: textType == MyText.TextType.Heading
+ font.pixelSize: textType == MyText.TextType.Heading ? 24 : 12
+}
+\endqml
+
+More information on enumeration usage in QML can be found in the \l {QML Basic Types} \l enumeration documentation.
+
+The ability to declare enumerations in QML was introduced in Qt 5.10.
+
*/
diff --git a/src/qml/doc/src/qmllanguageref/syntax/propertybinding.qdoc b/src/qml/doc/src/qmllanguageref/syntax/propertybinding.qdoc
index b506de471f..a5ad6af4a2 100644
--- a/src/qml/doc/src/qmllanguageref/syntax/propertybinding.qdoc
+++ b/src/qml/doc/src/qmllanguageref/syntax/propertybinding.qdoc
@@ -179,6 +179,26 @@ Rectangle {
Now, after the space key is pressed, the rectangle's height will continue
auto-updating to always be three times its width.
+\section3 Debugging overwriting of bindings
+
+A common cause of bugs in QML applications is accidentally overwriting bindings
+with static values from JavaScript statements. To help developers track down
+problems of this kind, the QML engine is able to emit messages whenever a
+binding is lost due to imperative assignments.
+
+In order to generate such messages, you need to enable the informational output
+for the \c{qt.qml.binding.removal} logging category, for instance by calling:
+
+\code
+QLoggingCategory::setFilterRules(QStringLiteral("qt.qml.binding.removal.info=true"));
+\endcode
+
+Please refer to the QLoggingCategory documentation for more information about
+enabling output from logging categories.
+
+Note that is perfectly reasonable in some circumstances to overwrite bindings.
+Any message generated by the QML engine should be treated as a diagnostic aid,
+and not necessarily as evidence of a problem without further investigation.
\section2 Using \c this with Property Binding
diff --git a/src/qml/jit/qv4assembler.cpp b/src/qml/jit/qv4assembler.cpp
index 71dabcd590..d062f3bbb2 100644
--- a/src/qml/jit/qv4assembler.cpp
+++ b/src/qml/jit/qv4assembler.cpp
@@ -249,13 +249,16 @@ void Assembler<TargetConfiguration>::generateCJumpOnCompare(RelationalCondition
}
template <typename TargetConfiguration>
-typename Assembler<TargetConfiguration>::Pointer Assembler<TargetConfiguration>::loadAddress(RegisterID tmp, IR::Expr *e)
+typename Assembler<TargetConfiguration>::Pointer
+Assembler<TargetConfiguration>::loadAddressForWriting(RegisterID tmp, IR::Expr *e, WriteBarrier::Type *barrier)
{
+ if (barrier)
+ *barrier = WriteBarrier::NoBarrier;
IR::Temp *t = e->asTemp();
if (t)
return loadTempAddress(t);
else
- return loadArgLocalAddress(tmp, e->asArgLocal());
+ return loadArgLocalAddressForWriting(tmp, e->asArgLocal(), barrier);
}
template <typename TargetConfiguration>
@@ -268,34 +271,42 @@ typename Assembler<TargetConfiguration>::Pointer Assembler<TargetConfiguration>:
}
template <typename TargetConfiguration>
-typename Assembler<TargetConfiguration>::Pointer Assembler<TargetConfiguration>::loadArgLocalAddress(RegisterID baseReg, IR::ArgLocal *al)
+typename Assembler<TargetConfiguration>::Pointer
+Assembler<TargetConfiguration>::loadArgLocalAddressForWriting(RegisterID baseReg, IR::ArgLocal *al, WriteBarrier::Type *barrier)
{
+ if (barrier)
+ *barrier = _function->argLocalRequiresWriteBarrier(al) ? WriteBarrier::Barrier : WriteBarrier::NoBarrier;
+
int32_t offset = 0;
int scope = al->scope;
loadPtr(Address(EngineRegister, targetStructureOffset(offsetof(EngineBase, current))), baseReg);
- const qint32 outerOffset = targetStructureOffset(Heap::ExecutionContext::baseOffset + offsetof(Heap::ExecutionContextData, outer));
+ const qint32 outerOffset = targetStructureOffset(Heap::ExecutionContextData::baseOffset + offsetof(Heap::ExecutionContextData, outer));
+ const qint32 localsOffset = targetStructureOffset(Heap::CallContextData::baseOffset + offsetof(Heap::CallContextData, function))
+ + 8 // locals is always 8 bytes away from function, regardless of pointer size.
+ + offsetof(ValueArray<0>, values);
- if (scope) {
+ while (scope) {
loadPtr(Address(baseReg, outerOffset), baseReg);
--scope;
- while (scope) {
- loadPtr(Address(baseReg, outerOffset), baseReg);
- --scope;
- }
}
switch (al->kind) {
case IR::ArgLocal::Formal:
case IR::ArgLocal::ScopedFormal: {
- const qint32 callDataOffset = targetStructureOffset(Heap::ExecutionContext::baseOffset + offsetof(Heap::ExecutionContextData, callData));
- loadPtr(Address(baseReg, callDataOffset), baseReg);
- offset = sizeof(CallData) + (al->index - 1) * sizeof(Value);
+ if (barrier && *barrier == WriteBarrier::Barrier) {
+ // if we need a barrier, the baseReg has to point to the ExecutionContext
+ // callData comes directly after locals, calculate the offset using that
+ offset = localsOffset + _function->localsCountForScope(al) * sizeof(Value);
+ offset += sizeof(CallData) + (al->index - 1) * sizeof(Value);
+ } else {
+ const qint32 callDataOffset = targetStructureOffset(Heap::ExecutionContextData::baseOffset + offsetof(Heap::ExecutionContextData, callData));
+ loadPtr(Address(baseReg, callDataOffset), baseReg);
+ offset = sizeof(CallData) + (al->index - 1) * sizeof(Value);
+ }
} break;
case IR::ArgLocal::Local:
case IR::ArgLocal::ScopedLocal: {
- const qint32 localsOffset = targetStructureOffset(Heap::CallContext::baseOffset + offsetof(Heap::CallContextData, locals));
- loadPtr(Address(baseReg, localsOffset), baseReg);
- offset = al->index * sizeof(Value);
+ offset = localsOffset + al->index * sizeof(Value);
} break;
default:
Q_UNREACHABLE();
@@ -307,7 +318,7 @@ template <typename TargetConfiguration>
typename Assembler<TargetConfiguration>::Pointer Assembler<TargetConfiguration>::loadStringAddress(RegisterID reg, const QString &string)
{
loadPtr(Address(Assembler::EngineRegister, targetStructureOffset(offsetof(QV4::EngineBase, current))), Assembler::ScratchRegister);
- loadPtr(Address(Assembler::ScratchRegister, targetStructureOffset(Heap::ExecutionContext::baseOffset + offsetof(Heap::ExecutionContextData, compilationUnit))), Assembler::ScratchRegister);
+ loadPtr(Address(Assembler::ScratchRegister, targetStructureOffset(Heap::ExecutionContextData::baseOffset + offsetof(Heap::ExecutionContextData, compilationUnit))), Assembler::ScratchRegister);
loadPtr(Address(Assembler::ScratchRegister, offsetof(CompiledData::CompilationUnitBase, runtimeStrings)), reg);
const int id = _jsGenerator->registerString(string);
return Pointer(reg, id * RegisterSize);
@@ -323,7 +334,7 @@ template <typename TargetConfiguration>
typename Assembler<TargetConfiguration>::Address Assembler<TargetConfiguration>::loadConstant(const TargetPrimitive &v, RegisterID baseReg)
{
loadPtr(Address(Assembler::EngineRegister, targetStructureOffset(offsetof(QV4::EngineBase, current))), baseReg);
- loadPtr(Address(baseReg, targetStructureOffset(Heap::ExecutionContext::baseOffset + offsetof(Heap::ExecutionContextData, constantTable))), baseReg);
+ loadPtr(Address(baseReg, targetStructureOffset(Heap::ExecutionContextData::baseOffset + offsetof(Heap::ExecutionContextData, constantTable))), baseReg);
const int index = _jsGenerator->registerConstant(v.rawValue());
return Address(baseReg, index * sizeof(QV4::Value));
}
@@ -338,8 +349,9 @@ void Assembler<TargetConfiguration>::loadStringRef(RegisterID reg, const QString
template <typename TargetConfiguration>
void Assembler<TargetConfiguration>::storeValue(TargetPrimitive value, IR::Expr *destination)
{
- Address addr = loadAddress(ScratchRegister, destination);
- storeValue(value, addr);
+ WriteBarrier::Type barrier;
+ Address addr = loadAddressForWriting(ScratchRegister, destination, &barrier);
+ storeValue(value, addr, barrier);
}
template <typename TargetConfiguration>
@@ -428,7 +440,7 @@ typename Assembler<TargetConfiguration>::Jump Assembler<TargetConfiguration>::ge
// It's not a number type, so it cannot be in a register.
Q_ASSERT(src->asArgLocal() || src->asTemp()->kind != IR::Temp::PhysicalRegister || src->type == IR::BoolType);
- Assembler::Pointer tagAddr = loadAddress(Assembler::ScratchRegister, src);
+ Assembler::Pointer tagAddr = loadAddressForReading(Assembler::ScratchRegister, src);
tagAddr.offset += 4;
load32(tagAddr, Assembler::ScratchRegister);
@@ -548,7 +560,7 @@ public:
~QIODevicePrintStream()
{}
- void vprintf(const char* format, va_list argList) WTF_ATTRIBUTE_PRINTF(2, 0)
+ void vprintf(const char* format, va_list argList) override WTF_ATTRIBUTE_PRINTF(2, 0)
{
const int written = qvsnprintf(buf.data(), buf.size(), format, argList);
if (written > 0)
@@ -556,7 +568,7 @@ public:
memset(buf.data(), 0, qMin(written, buf.size()));
}
- void flush()
+ void flush() override
{}
private:
diff --git a/src/qml/jit/qv4assembler_p.h b/src/qml/jit/qv4assembler_p.h
index 8b5b307e84..9e38696d7a 100644
--- a/src/qml/jit/qv4assembler_p.h
+++ b/src/qml/jit/qv4assembler_p.h
@@ -57,6 +57,7 @@
#include "private/qv4value_p.h"
#include "private/qv4context_p.h"
#include "private/qv4engine_p.h"
+#include "private/qv4writebarrier_p.h"
#include "qv4targetplatform_p.h"
#include <config.h>
@@ -152,38 +153,86 @@ struct RegisterSizeDependentAssembler<JITAssembler, MacroAssembler, TargetPlatfo
using TrustedImm64 = typename JITAssembler::TrustedImm64;
using Jump = typename JITAssembler::Jump;
using Label = typename JITAssembler::Label;
-
using ValueTypeInternal = Value::ValueTypeInternal_32;
using TargetPrimitive = TargetPrimitive32;
+ static void emitSetGrayBit(JITAssembler *as, RegisterID base)
+ {
+ bool returnValueUsed = (base == TargetPlatform::ReturnValueRegister);
+
+ as->push(TargetPlatform::EngineRegister); // free up one register for work
+
+ RegisterID grayBitmap = returnValueUsed ? TargetPlatform::ScratchRegister : TargetPlatform::ReturnValueRegister;
+ as->move(base, grayBitmap);
+ Q_ASSERT(base != grayBitmap);
+ as->urshift32(TrustedImm32(Chunk::ChunkShift), grayBitmap);
+ as->lshift32(TrustedImm32(Chunk::ChunkShift), grayBitmap);
+ Q_STATIC_ASSERT(offsetof(Chunk, grayBitmap) == 0);
+
+ RegisterID index = base;
+ as->move(base, index);
+ as->sub32(grayBitmap, index);
+ as->urshift32(TrustedImm32(Chunk::SlotSizeShift), index);
+ RegisterID grayIndex = TargetPlatform::EngineRegister;
+ as->move(index, grayIndex);
+ as->urshift32(TrustedImm32(Chunk::BitShift), grayIndex);
+ as->lshift32(TrustedImm32(2), grayIndex); // 4 bytes per quintptr
+ as->add32(grayIndex, grayBitmap);
+ as->and32(TrustedImm32(Chunk::Bits - 1), index);
+
+ RegisterID bit = TargetPlatform::EngineRegister;
+ as->move(TrustedImm32(1), bit);
+ as->lshift32(index, bit);
+
+ as->load32(Pointer(grayBitmap, 0), index);
+ as->or32(bit, index);
+ as->store32(index, Pointer(grayBitmap, 0));
+
+ as->pop(TargetPlatform::EngineRegister);
+ }
+
+#if WRITEBARRIER(none)
+ static Q_ALWAYS_INLINE void emitWriteBarrier(JITAssembler *, Address) {}
+#endif
+
static void loadDouble(JITAssembler *as, Address addr, FPRegisterID dest)
{
as->MacroAssembler::loadDouble(addr, dest);
}
- static void storeDouble(JITAssembler *as, FPRegisterID source, Address addr)
+ static void storeDouble(JITAssembler *as, FPRegisterID source, Address addr, WriteBarrier::Type barrier)
{
as->MacroAssembler::storeDouble(source, addr);
+ if (WriteBarrier::isRequired<WriteBarrier::Primitive>() && barrier == WriteBarrier::Barrier)
+ emitWriteBarrier(as, addr);
}
static void storeDouble(JITAssembler *as, FPRegisterID source, IR::Expr* target)
{
- Pointer ptr = as->loadAddress(TargetPlatform::ScratchRegister, target);
- as->storeDouble(source, ptr);
+ WriteBarrier::Type barrier;
+ Pointer ptr = as->loadAddressForWriting(TargetPlatform::ScratchRegister, target, &barrier);
+ as->storeDouble(source, ptr, barrier);
}
- static void storeValue(JITAssembler *as, TargetPrimitive value, Address destination)
+ static void storeValue(JITAssembler *as, TargetPrimitive value, Address destination, WriteBarrier::Type barrier)
{
as->store32(TrustedImm32(value.value()), destination);
destination.offset += 4;
as->store32(TrustedImm32(value.tag()), destination);
+ if (WriteBarrier::isRequired<WriteBarrier::Primitive>() && barrier == WriteBarrier::Barrier)
+ emitWriteBarrier(as, destination);
}
template <typename Source, typename Destination>
- static void copyValueViaRegisters(JITAssembler *as, Source source, Destination destination)
+ static void copyValueViaRegisters(JITAssembler *as, Source source, Destination destination, WriteBarrier::Type barrier)
{
as->loadDouble(source, TargetPlatform::FPGpr0);
- as->storeDouble(TargetPlatform::FPGpr0, destination);
+ // We need to pass NoBarrier to storeDouble and call emitWriteBarrier ourselves, as the
+ // code in storeDouble assumes the type we're storing is actually a double, something
+ // that isn't always the case here.
+ as->storeDouble(TargetPlatform::FPGpr0, destination, WriteBarrier::NoBarrier);
+ if (WriteBarrier::isRequired<WriteBarrier::Unknown>() && barrier == WriteBarrier::Barrier)
+ emitWriteBarrier(as, destination);
}
static void loadDoubleConstant(JITAssembler *as, IR::Const *c, FPRegisterID target)
@@ -196,12 +245,14 @@ struct RegisterSizeDependentAssembler<JITAssembler, MacroAssembler, TargetPlatfo
as->moveIntsToDouble(TargetPlatform::LowReturnValueRegister, TargetPlatform::HighReturnValueRegister, dest, TargetPlatform::FPGpr0);
}
- static void storeReturnValue(JITAssembler *as, const Pointer &dest)
+ static void storeReturnValue(JITAssembler *as, const Pointer &dest, WriteBarrier::Type barrier)
{
Address destination = dest;
as->store32(TargetPlatform::LowReturnValueRegister, destination);
destination.offset += 4;
as->store32(TargetPlatform::HighReturnValueRegister, destination);
+ if (WriteBarrier::isRequired<WriteBarrier::Unknown>() && barrier == WriteBarrier::Barrier)
+ emitWriteBarrier(as, dest);
}
static void setFunctionReturnValueFromTemp(JITAssembler *as, IR::Temp *t)
@@ -237,7 +288,7 @@ struct RegisterSizeDependentAssembler<JITAssembler, MacroAssembler, TargetPlatfo
Q_UNREACHABLE();
}
} else {
- Pointer addr = as->loadAddress(TargetPlatform::ScratchRegister, t);
+ Pointer addr = as->loadAddressForReading(TargetPlatform::ScratchRegister, t);
as->load32(addr, lowReg);
addr.offset += 4;
as->load32(addr, highReg);
@@ -298,7 +349,7 @@ struct RegisterSizeDependentAssembler<JITAssembler, MacroAssembler, TargetPlatfo
IR::BasicBlock *nextBlock, IR::BasicBlock *currentBlock,
IR::BasicBlock *trueBlock, IR::BasicBlock *falseBlock)
{
- Pointer tagAddr = as->loadAddress(scratchRegister, right);
+ Pointer tagAddr = as->loadAddressForReading(scratchRegister, right);
as->load32(tagAddr, tagRegister);
Jump j = as->branch32(JITAssembler::invert(cond), tagRegister, TrustedImm32(0));
as->addPatch(falseBlock, j);
@@ -315,7 +366,7 @@ struct RegisterSizeDependentAssembler<JITAssembler, MacroAssembler, TargetPlatfo
{
Q_ASSERT(source->type == IR::VarType);
// load the tag:
- Pointer addr = as->loadAddress(TargetPlatform::ScratchRegister, source);
+ Pointer addr = as->loadAddressForReading(TargetPlatform::ScratchRegister, source);
Pointer tagAddr = addr;
tagAddr.offset += 4;
as->load32(tagAddr, TargetPlatform::ReturnValueRegister);
@@ -326,10 +377,13 @@ struct RegisterSizeDependentAssembler<JITAssembler, MacroAssembler, TargetPlatfo
IR::Temp *targetTemp = target->asTemp();
if (!targetTemp || targetTemp->kind == IR::Temp::StackSlot) {
as->load32(addr, TargetPlatform::ReturnValueRegister);
- Pointer targetAddr = as->loadAddress(TargetPlatform::ScratchRegister, target);
+ WriteBarrier::Type barrier;
+ Pointer targetAddr = as->loadAddressForWriting(TargetPlatform::ScratchRegister, target, &barrier);
as->store32(TargetPlatform::ReturnValueRegister, targetAddr);
targetAddr.offset += 4;
as->store32(TrustedImm32(quint32(Value::ValueTypeInternal_32::Integer)), targetAddr);
+ if (WriteBarrier::isRequired<WriteBarrier::Primitive>() && barrier == WriteBarrier::Barrier)
+ emitWriteBarrier(as, targetAddr);
} else {
as->load32(addr, (RegisterID) targetTemp->index);
}
@@ -338,17 +392,19 @@ struct RegisterSizeDependentAssembler<JITAssembler, MacroAssembler, TargetPlatfo
// not an int:
fallback.link(as);
generateRuntimeCall(as, TargetPlatform::ReturnValueRegister, toInt,
- as->loadAddress(TargetPlatform::ScratchRegister, source));
+ as->loadAddressForReading(TargetPlatform::ScratchRegister, source));
as->storeInt32(TargetPlatform::ReturnValueRegister, target);
intDone.link(as);
}
- static void loadManagedPointer(JITAssembler *as, RegisterID registerWithPtr, Pointer destAddr)
+ static void loadManagedPointer(JITAssembler *as, RegisterID registerWithPtr, Pointer destAddr, WriteBarrier::Type barrier)
{
as->store32(registerWithPtr, destAddr);
destAddr.offset += 4;
as->store32(TrustedImm32(QV4::Value::Managed_Type_Internal_32), destAddr);
+ if (WriteBarrier::isRequired<WriteBarrier::Object>() && barrier == WriteBarrier::Barrier)
+ emitWriteBarrier(as, destAddr);
}
static Jump generateIsDoubleCheck(JITAssembler *as, RegisterID tagOrValueRegister)
@@ -393,10 +449,48 @@ struct RegisterSizeDependentAssembler<JITAssembler, MacroAssembler, TargetPlatfo
using BranchTruncateType = typename JITAssembler::BranchTruncateType;
using Jump = typename JITAssembler::Jump;
using Label = typename JITAssembler::Label;
-
using ValueTypeInternal = Value::ValueTypeInternal_64;
using TargetPrimitive = TargetPrimitive64;
+ static void emitSetGrayBit(JITAssembler *as, RegisterID base)
+ {
+ bool returnValueUsed = (base == TargetPlatform::ReturnValueRegister);
+
+ as->push(TargetPlatform::EngineRegister); // free up one register for work
+
+ RegisterID grayBitmap = returnValueUsed ? TargetPlatform::ScratchRegister : TargetPlatform::ReturnValueRegister;
+ as->move(base, grayBitmap);
+ Q_ASSERT(base != grayBitmap);
+ as->urshift64(TrustedImm32(Chunk::ChunkShift), grayBitmap);
+ as->lshift64(TrustedImm32(Chunk::ChunkShift), grayBitmap);
+ Q_STATIC_ASSERT(offsetof(Chunk, grayBitmap) == 0);
+
+ RegisterID index = base;
+ as->move(base, index);
+ as->sub64(grayBitmap, index);
+ as->urshift64(TrustedImm32(Chunk::SlotSizeShift), index);
+ RegisterID grayIndex = TargetPlatform::EngineRegister;
+ as->move(index, grayIndex);
+ as->urshift64(TrustedImm32(Chunk::BitShift), grayIndex);
+ as->lshift64(TrustedImm32(3), grayIndex); // 8 bytes per quintptr
+ as->add64(grayIndex, grayBitmap);
+ as->and64(TrustedImm32(Chunk::Bits - 1), index);
+
+ RegisterID bit = TargetPlatform::EngineRegister;
+ as->move(TrustedImm32(1), bit);
+ as->lshift64(index, bit);
+
+ as->load64(Pointer(grayBitmap, 0), index);
+ as->or64(bit, index);
+ as->store64(index, Pointer(grayBitmap, 0));
+
+ as->pop(TargetPlatform::EngineRegister);
+ }
+
+#if WRITEBARRIER(none)
+ static Q_ALWAYS_INLINE void emitWriteBarrier(JITAssembler *, Address) {}
+#endif
+
static void loadDouble(JITAssembler *as, Address addr, FPRegisterID dest)
{
as->load64(addr, TargetPlatform::ReturnValueRegister);
@@ -404,19 +498,24 @@ struct RegisterSizeDependentAssembler<JITAssembler, MacroAssembler, TargetPlatfo
as->move64ToDouble(TargetPlatform::ReturnValueRegister, dest);
}
- static void storeDouble(JITAssembler *as, FPRegisterID source, Address addr)
+ static void storeDouble(JITAssembler *as, FPRegisterID source, Address addr, WriteBarrier::Type barrier)
{
as->moveDoubleTo64(source, TargetPlatform::ReturnValueRegister);
as->xor64(TargetPlatform::DoubleMaskRegister, TargetPlatform::ReturnValueRegister);
as->store64(TargetPlatform::ReturnValueRegister, addr);
+ if (WriteBarrier::isRequired<WriteBarrier::Primitive>() && barrier == WriteBarrier::Barrier)
+ emitWriteBarrier(as, addr);
}
static void storeDouble(JITAssembler *as, FPRegisterID source, IR::Expr* target)
{
as->moveDoubleTo64(source, TargetPlatform::ReturnValueRegister);
as->xor64(TargetPlatform::DoubleMaskRegister, TargetPlatform::ReturnValueRegister);
- Pointer ptr = as->loadAddress(TargetPlatform::ScratchRegister, target);
+ WriteBarrier::Type barrier;
+ Pointer ptr = as->loadAddressForWriting(TargetPlatform::ScratchRegister, target, &barrier);
as->store64(TargetPlatform::ReturnValueRegister, ptr);
+ if (WriteBarrier::isRequired<WriteBarrier::Primitive>() && barrier == WriteBarrier::Barrier)
+ emitWriteBarrier(as, ptr);
}
static void storeReturnValue(JITAssembler *as, FPRegisterID dest)
@@ -425,9 +524,11 @@ struct RegisterSizeDependentAssembler<JITAssembler, MacroAssembler, TargetPlatfo
as->move64ToDouble(TargetPlatform::ReturnValueRegister, dest);
}
- static void storeReturnValue(JITAssembler *as, const Pointer &dest)
+ static void storeReturnValue(JITAssembler *as, const Pointer &dest, WriteBarrier::Type barrier)
{
as->store64(TargetPlatform::ReturnValueRegister, dest);
+ if (WriteBarrier::isRequired<WriteBarrier::Unknown>() && barrier == WriteBarrier::Barrier)
+ emitWriteBarrier(as, dest);
}
static void setFunctionReturnValueFromTemp(JITAssembler *as, IR::Temp *t)
@@ -468,7 +569,7 @@ struct RegisterSizeDependentAssembler<JITAssembler, MacroAssembler, TargetPlatfo
TargetPlatform::ReturnValueRegister);
}
} else {
- as->copyValue(TargetPlatform::ReturnValueRegister, t);
+ as->copyValue(TargetPlatform::ReturnValueRegister, t, WriteBarrier::NoBarrier);
}
}
@@ -477,18 +578,20 @@ struct RegisterSizeDependentAssembler<JITAssembler, MacroAssembler, TargetPlatfo
as->move(TrustedImm64(retVal.rawValue()), TargetPlatform::ReturnValueRegister);
}
- static void storeValue(JITAssembler *as, TargetPrimitive value, Address destination)
+ static void storeValue(JITAssembler *as, TargetPrimitive value, Address destination, WriteBarrier::Type barrier)
{
as->store64(TrustedImm64(value.rawValue()), destination);
+ if (WriteBarrier::isRequired<WriteBarrier::Unknown>() && barrier == WriteBarrier::Barrier)
+ emitWriteBarrier(as, destination);
}
template <typename Source, typename Destination>
- static void copyValueViaRegisters(JITAssembler *as, Source source, Destination destination)
+ static void copyValueViaRegisters(JITAssembler *as, Source source, Destination destination, WriteBarrier::Type barrier)
{
// Use ReturnValueRegister as "scratch" register because loadArgument
// and storeArgument are functions that may need a scratch register themselves.
loadArgumentInRegister(as, source, TargetPlatform::ReturnValueRegister, 0);
- as->storeReturnValue(destination);
+ as->storeReturnValue(destination, barrier);
}
static void loadDoubleConstant(JITAssembler *as, IR::Const *c, FPRegisterID target)
@@ -524,7 +627,7 @@ struct RegisterSizeDependentAssembler<JITAssembler, MacroAssembler, TargetPlatfo
Q_UNUSED(argumentNumber);
if (al) {
- Pointer addr = as->loadArgLocalAddress(dest, al);
+ Pointer addr = as->loadArgLocalAddressForReading(dest, al);
as->load64(addr, dest);
} else {
auto undefined = TargetPrimitive::undefinedValue();
@@ -593,7 +696,7 @@ struct RegisterSizeDependentAssembler<JITAssembler, MacroAssembler, TargetPlatfo
IR::BasicBlock *nextBlock, IR::BasicBlock *currentBlock,
IR::BasicBlock *trueBlock, IR::BasicBlock *falseBlock)
{
- Pointer addr = as->loadAddress(scratchRegister, right);
+ Pointer addr = as->loadAddressForReading(scratchRegister, right);
as->load64(addr, tagRegister);
const TrustedImm64 tag(0);
generateCJumpOnCompare(as, cond, tagRegister, tag, nextBlock, currentBlock, trueBlock, falseBlock);
@@ -602,7 +705,7 @@ struct RegisterSizeDependentAssembler<JITAssembler, MacroAssembler, TargetPlatfo
static void convertVarToSInt32(JITAssembler *as, IR::Expr *source, IR::Expr *target)
{
Q_ASSERT(source->type == IR::VarType);
- Pointer addr = as->loadAddress(TargetPlatform::ScratchRegister, source);
+ Pointer addr = as->loadAddressForReading(TargetPlatform::ScratchRegister, source);
as->load64(addr, TargetPlatform::ScratchRegister);
as->move(TargetPlatform::ScratchRegister, TargetPlatform::ReturnValueRegister);
@@ -626,25 +729,30 @@ struct RegisterSizeDependentAssembler<JITAssembler, MacroAssembler, TargetPlatfo
// not an int:
fallback.link(as);
generateRuntimeCall(as, TargetPlatform::ReturnValueRegister, toInt,
- as->loadAddress(TargetPlatform::ScratchRegister, source));
+ as->loadAddressForReading(TargetPlatform::ScratchRegister, source));
isIntConvertible.link(as);
success.link(as);
IR::Temp *targetTemp = target->asTemp();
if (!targetTemp || targetTemp->kind == IR::Temp::StackSlot) {
- Pointer targetAddr = as->loadAddress(TargetPlatform::ScratchRegister, target);
+ WriteBarrier::Type barrier;
+ Pointer targetAddr = as->loadAddressForWriting(TargetPlatform::ScratchRegister, target, &barrier);
as->store32(TargetPlatform::ReturnValueRegister, targetAddr);
targetAddr.offset += 4;
as->store32(TrustedImm32(quint32(Value::ValueTypeInternal_64::Integer)), targetAddr);
+ if (WriteBarrier::isRequired<WriteBarrier::Primitive>() && barrier == WriteBarrier::Barrier)
+ emitWriteBarrier(as, targetAddr);
} else {
as->storeInt32(TargetPlatform::ReturnValueRegister, target);
}
}
- static void loadManagedPointer(JITAssembler *as, RegisterID registerWithPtr, Pointer destAddr)
+ static void loadManagedPointer(JITAssembler *as, RegisterID registerWithPtr, Pointer destAddr, WriteBarrier::Type barrier)
{
as->store64(registerWithPtr, destAddr);
+ if (WriteBarrier::isRequired<WriteBarrier::Object>() && barrier == WriteBarrier::Barrier)
+ emitWriteBarrier(as, destAddr);
}
static Jump generateIsDoubleCheck(JITAssembler *as, RegisterID tagOrValueRegister)
@@ -990,9 +1098,16 @@ public:
Jump branchDouble(bool invertCondition, IR::AluOp op, IR::Expr *left, IR::Expr *right);
Jump branchInt32(bool invertCondition, IR::AluOp op, IR::Expr *left, IR::Expr *right);
- Pointer loadAddress(RegisterID tmp, IR::Expr *t);
+ Pointer loadAddressForWriting(RegisterID tmp, IR::Expr *t, WriteBarrier::Type *barrier);
+ Pointer loadAddressForReading(RegisterID tmp, IR::Expr *t) {
+ return loadAddressForWriting(tmp, t, 0);
+ }
+
Pointer loadTempAddress(IR::Temp *t);
- Pointer loadArgLocalAddress(RegisterID baseReg, IR::ArgLocal *al);
+ Pointer loadArgLocalAddressForWriting(RegisterID baseReg, IR::ArgLocal *al, WriteBarrier::Type *barrier);
+ Pointer loadArgLocalAddressForReading(RegisterID baseReg, IR::ArgLocal *al) {
+ return loadArgLocalAddressForWriting(baseReg, al, 0);
+ }
Pointer loadStringAddress(RegisterID reg, const QString &string);
Address loadConstant(IR::Const *c, RegisterID baseReg);
Address loadConstant(const TargetPrimitive &v, RegisterID baseReg);
@@ -1014,16 +1129,16 @@ public:
Pointer addr(_stackLayout->savedRegPointer(argumentNumber));
switch (t->type) {
case IR::BoolType:
- storeBool((RegisterID) t->index, addr);
+ storeBool((RegisterID) t->index, addr, WriteBarrier::NoBarrier);
break;
case IR::SInt32Type:
- storeInt32((RegisterID) t->index, addr);
+ storeInt32((RegisterID) t->index, addr, WriteBarrier::NoBarrier);
break;
case IR::UInt32Type:
- storeUInt32((RegisterID) t->index, addr);
+ storeUInt32((RegisterID) t->index, addr, WriteBarrier::NoBarrier);
break;
case IR::DoubleType:
- storeDouble((FPRegisterID) t->index, addr);
+ storeDouble((FPRegisterID) t->index, addr, WriteBarrier::NoBarrier);
break;
default:
Q_UNIMPLEMENTED();
@@ -1054,7 +1169,7 @@ public:
if (!temp.value) {
RegisterSizeDependentOps::zeroRegister(this, dest);
} else {
- Pointer addr = toAddress(dest, temp.value, argumentNumber);
+ Pointer addr = toAddress(dest, temp.value, argumentNumber, 0);
loadArgumentInRegister(addr, dest, argumentNumber);
}
}
@@ -1067,7 +1182,7 @@ public:
void loadArgumentInRegister(Reference temp, RegisterID dest, int argumentNumber)
{
Q_ASSERT(temp.value);
- Pointer addr = loadAddress(dest, temp.value);
+ Pointer addr = loadAddressForReading(dest, temp.value);
loadArgumentInRegister(addr, dest, argumentNumber);
}
@@ -1100,8 +1215,10 @@ public:
move(imm32, dest);
}
- void storeReturnValue(RegisterID dest)
+ void storeReturnValue(RegisterID dest, WriteBarrier::Type barrier = WriteBarrier::NoBarrier)
{
+ Q_UNUSED(barrier);
+ Q_ASSERT(barrier == WriteBarrier::NoBarrier);
move(ReturnValueRegister, dest);
}
@@ -1109,7 +1226,7 @@ public:
{
subPtr(TrustedImm32(sizeof(QV4::Value)), StackPointerRegister);
Pointer tmp(StackPointerRegister, 0);
- storeReturnValue(tmp);
+ storeReturnValue(tmp, WriteBarrier::NoBarrier);
toUInt32Register(tmp, dest);
addPtr(TrustedImm32(sizeof(QV4::Value)), StackPointerRegister);
}
@@ -1119,9 +1236,9 @@ public:
RegisterSizeDependentOps::storeReturnValue(this, dest);
}
- void storeReturnValue(const Pointer &dest)
+ void storeReturnValue(const Pointer &dest, WriteBarrier::Type barrier)
{
- RegisterSizeDependentOps::storeReturnValue(this, dest);
+ RegisterSizeDependentOps::storeReturnValue(this, dest, barrier);
}
void storeReturnValue(IR::Expr *target)
@@ -1129,22 +1246,19 @@ public:
if (!target)
return;
- if (IR::Temp *temp = target->asTemp()) {
- if (temp->kind == IR::Temp::PhysicalRegister) {
- if (temp->type == IR::DoubleType)
- storeReturnValue((FPRegisterID) temp->index);
- else if (temp->type == IR::UInt32Type)
- storeUInt32ReturnValue((RegisterID) temp->index);
- else
- storeReturnValue((RegisterID) temp->index);
- return;
- } else {
- Pointer addr = loadTempAddress(temp);
- storeReturnValue(addr);
- }
- } else if (IR::ArgLocal *al = target->asArgLocal()) {
- Pointer addr = loadArgLocalAddress(ScratchRegister, al);
- storeReturnValue(addr);
+ IR::Temp *temp = target->asTemp();
+ if (temp && temp->kind == IR::Temp::PhysicalRegister) {
+ if (temp->type == IR::DoubleType)
+ storeReturnValue((FPRegisterID) temp->index);
+ else if (temp->type == IR::UInt32Type)
+ storeUInt32ReturnValue((RegisterID) temp->index);
+ else
+ storeReturnValue((RegisterID) temp->index);
+ return;
+ } else {
+ WriteBarrier::Type barrier;
+ Pointer addr = loadAddressForWriting(ScratchRegister, target, &barrier);
+ storeReturnValue(addr, barrier);
}
}
@@ -1181,7 +1295,7 @@ public:
void loadArgumentOnStack(PointerToValue temp, int argumentNumber)
{
if (temp.value) {
- Pointer ptr = toAddress(ScratchRegister, temp.value, argumentNumber);
+ Pointer ptr = toAddress(ScratchRegister, temp.value, argumentNumber, 0);
loadArgumentOnStack<StackSlot>(ptr, argumentNumber);
} else {
RegisterSizeDependentOps::zeroStackSlot(this, StackSlot);
@@ -1201,7 +1315,7 @@ public:
{
Q_ASSERT (temp.value);
- Pointer ptr = loadAddress(ScratchRegister, temp.value);
+ Pointer ptr = loadAddressForReading(ScratchRegister, temp.value);
loadArgumentOnStack<StackSlot>(ptr, argumentNumber);
}
@@ -1212,7 +1326,7 @@ public:
moveDouble((FPRegisterID) sourceTemp->index, dest);
return;
}
- Pointer ptr = loadAddress(ScratchRegister, source);
+ Pointer ptr = loadAddressForReading(ScratchRegister, source);
loadDouble(ptr, dest);
}
@@ -1231,46 +1345,65 @@ public:
RegisterSizeDependentOps::loadDouble(this, addr, dest);
}
- void storeDouble(FPRegisterID source, Address addr)
+ void storeDouble(FPRegisterID source, Address addr, WriteBarrier::Type barrier)
{
- RegisterSizeDependentOps::storeDouble(this, source, addr);
+ RegisterSizeDependentOps::storeDouble(this, source, addr, barrier);
}
template <typename Result, typename Source>
- void copyValue(Result result, Source source);
+ void copyValue(Result result, Source source, WriteBarrier::Type barrier);
template <typename Result>
- void copyValue(Result result, IR::Expr* source);
+ void copyValue(Result result, IR::Expr* source, WriteBarrier::Type barrier);
// The scratch register is used to calculate the temp address for the source.
- void memcopyValue(Pointer target, IR::Expr *source, RegisterID scratchRegister)
+ void memcopyValue(Pointer target, IR::Expr *source, RegisterID scratchRegister, WriteBarrier::Type barrier)
{
Q_ASSERT(!source->asTemp() || source->asTemp()->kind != IR::Temp::PhysicalRegister);
Q_ASSERT(target.base != scratchRegister);
- TargetConfiguration::MacroAssembler::loadDouble(loadAddress(scratchRegister, source), FPGpr0);
- TargetConfiguration::MacroAssembler::storeDouble(FPGpr0, target);
+ loadRawValue(loadAddressForReading(scratchRegister, source), FPGpr0);
+ storeRawValue(FPGpr0, target, barrier);
}
// The scratch register is used to calculate the temp address for the source.
void memcopyValue(IR::Expr *target, Pointer source, FPRegisterID fpScratchRegister, RegisterID scratchRegister)
{
- TargetConfiguration::MacroAssembler::loadDouble(source, fpScratchRegister);
- TargetConfiguration::MacroAssembler::storeDouble(fpScratchRegister, loadAddress(scratchRegister, target));
+ loadRawValue(source, fpScratchRegister);
+ WriteBarrier::Type barrier;
+ Pointer dest = loadAddressForWriting(scratchRegister, target, &barrier);
+ storeRawValue(fpScratchRegister, dest, barrier);
+ }
+
+ void loadRawValue(Pointer source, FPRegisterID dest)
+ {
+ TargetConfiguration::MacroAssembler::loadDouble(source, dest);
}
- void storeValue(TargetPrimitive value, Address destination)
+ void storeRawValue(FPRegisterID source, Pointer dest, WriteBarrier::Type barrier)
{
- RegisterSizeDependentOps::storeValue(this, value, destination);
+ TargetConfiguration::MacroAssembler::storeDouble(source, dest);
+ if (WriteBarrier::isRequired<WriteBarrier::Unknown>() && barrier == WriteBarrier::Barrier)
+ RegisterSizeDependentOps::emitWriteBarrier(this, dest);
+ }
+
+ void storeValue(TargetPrimitive value, Address destination, WriteBarrier::Type barrier)
+ {
+ RegisterSizeDependentOps::storeValue(this, value, destination, barrier);
}
void storeValue(TargetPrimitive value, IR::Expr* temp);
+ void emitWriteBarrier(Address addr, WriteBarrier::Type barrier) {
+ if (WriteBarrier::isRequired<WriteBarrier::Primitive>() && barrier == WriteBarrier::Barrier)
+ RegisterSizeDependentOps::emitWriteBarrier(this, addr);
+ }
+
void enterStandardStackFrame(const RegisterInformation &regularRegistersToSave,
const RegisterInformation &fpRegistersToSave);
void leaveStandardStackFrame(const RegisterInformation &regularRegistersToSave,
const RegisterInformation &fpRegistersToSave);
void checkException() {
- load32(Address(EngineRegister, targetStructureOffset(offsetof(QV4::EngineBase, hasException))), ScratchRegister);
+ this->load8(Address(EngineRegister, targetStructureOffset(offsetof(QV4::EngineBase, hasException))), ScratchRegister);
Jump exceptionThrown = branch32(RelationalCondition::NotEqual, ScratchRegister, TrustedImm32(0));
if (catchBlock)
addPatch(catchBlock, exceptionThrown);
@@ -1333,7 +1466,7 @@ public:
// load the table from the context
loadPtr(Address(EngineRegister, targetStructureOffset(offsetof(QV4::EngineBase, current))), ScratchRegister);
- loadPtr(Address(ScratchRegister, targetStructureOffset(Heap::ExecutionContext::baseOffset + offsetof(Heap::ExecutionContextData, lookups))),
+ loadPtr(Address(ScratchRegister, targetStructureOffset(Heap::ExecutionContextData::baseOffset + offsetof(Heap::ExecutionContextData, lookups))),
lookupCall.addr.base);
// pre-calculate the indirect address for the lookupCall table:
if (lookupCall.addr.offset)
@@ -1426,8 +1559,10 @@ public:
generateFunctionCallImp(needsExceptionCheck, r, functionName, function, arg1, VoidType(), VoidType(), VoidType(), VoidType(), VoidType());
}
- Pointer toAddress(RegisterID tmpReg, IR::Expr *e, int offset)
+ Pointer toAddress(RegisterID tmpReg, IR::Expr *e, int offset, WriteBarrier::Type *barrier)
{
+ if (barrier)
+ *barrier = WriteBarrier::NoBarrier;
if (IR::Const *c = e->asConst()) {
Address addr = _stackLayout->savedRegPointer(offset);
Address tagAddr = addr;
@@ -1443,14 +1578,16 @@ public:
if (t->kind == IR::Temp::PhysicalRegister)
return Pointer(_stackLayout->savedRegPointer(offset));
- return loadAddress(tmpReg, e);
+ return loadAddressForWriting(tmpReg, e, barrier);
}
- void storeBool(RegisterID reg, Pointer addr)
+ void storeBool(RegisterID reg, Pointer addr, WriteBarrier::Type barrier)
{
store32(reg, addr);
addr.offset += 4;
store32(TrustedImm32(TargetPrimitive::fromBoolean(0).tag()), addr);
+ if (WriteBarrier::isRequired<WriteBarrier::Primitive>() && barrier == WriteBarrier::Barrier)
+ RegisterSizeDependentOps::emitWriteBarrier(this, addr);
}
void storeBool(RegisterID src, RegisterID dest)
@@ -1467,8 +1604,9 @@ public:
}
}
- Pointer addr = loadAddress(ScratchRegister, target);
- storeBool(reg, addr);
+ WriteBarrier::Type barrier;
+ Pointer addr = loadAddressForWriting(ScratchRegister, target, &barrier);
+ storeBool(reg, addr, barrier);
}
void storeBool(bool value, IR::Expr *target) {
@@ -1490,25 +1628,24 @@ public:
move(src, dest);
}
- void storeInt32(RegisterID reg, Pointer addr)
+ void storeInt32(RegisterID reg, Pointer addr, WriteBarrier::Type barrier)
{
store32(reg, addr);
addr.offset += 4;
store32(TrustedImm32(TargetPrimitive::fromInt32(0).tag()), addr);
+ if (WriteBarrier::isRequired<WriteBarrier::Primitive>() && barrier == WriteBarrier::Barrier)
+ RegisterSizeDependentOps::emitWriteBarrier(this, addr);
}
void storeInt32(RegisterID reg, IR::Expr *target)
{
- if (IR::Temp *targetTemp = target->asTemp()) {
- if (targetTemp->kind == IR::Temp::PhysicalRegister) {
- move(reg, (RegisterID) targetTemp->index);
- } else {
- Pointer addr = loadTempAddress(targetTemp);
- storeInt32(reg, addr);
- }
- } else if (IR::ArgLocal *al = target->asArgLocal()) {
- Pointer addr = loadArgLocalAddress(ScratchRegister, al);
- storeInt32(reg, addr);
+ IR::Temp *targetTemp = target->asTemp();
+ if (targetTemp && targetTemp->kind == IR::Temp::PhysicalRegister) {
+ move(reg, (RegisterID) targetTemp->index);
+ } else {
+ WriteBarrier::Type barrier;
+ Pointer addr = loadAddressForWriting(ScratchRegister, target, &barrier);
+ storeInt32(reg, addr, barrier);
}
}
@@ -1517,15 +1654,15 @@ public:
move(src, dest);
}
- void storeUInt32(RegisterID reg, Pointer addr)
+ void storeUInt32(RegisterID reg, Pointer addr, WriteBarrier::Type barrier)
{
// The UInt32 representation in QV4::Value is really convoluted. See also toUInt32Register.
Jump intRange = branch32(RelationalCondition::GreaterThanOrEqual, reg, TrustedImm32(0));
convertUInt32ToDouble(reg, FPGpr0, ReturnValueRegister);
- storeDouble(FPGpr0, addr);
+ storeDouble(FPGpr0, addr, barrier);
Jump done = jump();
intRange.link(this);
- storeInt32(reg, addr);
+ storeInt32(reg, addr, barrier);
done.link(this);
}
@@ -1535,8 +1672,9 @@ public:
if (targetTemp && targetTemp->kind == IR::Temp::PhysicalRegister) {
move(reg, (RegisterID) targetTemp->index);
} else {
- Pointer addr = loadAddress(ScratchRegister, target);
- storeUInt32(reg, addr);
+ WriteBarrier::Type barrier;
+ Pointer addr = loadAddressForWriting(ScratchRegister, target, &barrier);
+ storeUInt32(reg, addr, barrier);
}
}
@@ -1571,7 +1709,7 @@ public:
if (t->kind == IR::Temp::PhysicalRegister)
return (RegisterID) t->index;
- return toInt32Register(loadAddress(scratchReg, e), scratchReg);
+ return toInt32Register(loadAddressForReading(scratchReg, e), scratchReg);
}
RegisterID toInt32Register(Pointer addr, RegisterID scratchReg)
@@ -1591,7 +1729,7 @@ public:
if (t->kind == IR::Temp::PhysicalRegister)
return (RegisterID) t->index;
- return toUInt32Register(loadAddress(scratchReg, e), scratchReg);
+ return toUInt32Register(loadAddressForReading(scratchReg, e), scratchReg);
}
RegisterID toUInt32Register(Pointer addr, RegisterID scratchReg)
@@ -1666,31 +1804,31 @@ const typename Assembler<TargetConfiguration>::VoidType Assembler<TargetConfigur
template <typename TargetConfiguration>
template <typename Result, typename Source>
-void Assembler<TargetConfiguration>::copyValue(Result result, Source source)
+void Assembler<TargetConfiguration>::copyValue(Result result, Source source, WriteBarrier::Type barrier)
{
- RegisterSizeDependentOps::copyValueViaRegisters(this, source, result);
+ RegisterSizeDependentOps::copyValueViaRegisters(this, source, result, barrier);
}
template <typename TargetConfiguration>
template <typename Result>
-void Assembler<TargetConfiguration>::copyValue(Result result, IR::Expr* source)
+void Assembler<TargetConfiguration>::copyValue(Result result, IR::Expr* source, WriteBarrier::Type barrier)
{
if (source->type == IR::BoolType) {
RegisterID reg = toInt32Register(source, ScratchRegister);
- storeBool(reg, result);
+ storeBool(reg, result, barrier);
} else if (source->type == IR::SInt32Type) {
RegisterID reg = toInt32Register(source, ScratchRegister);
- storeInt32(reg, result);
+ storeInt32(reg, result, barrier);
} else if (source->type == IR::UInt32Type) {
RegisterID reg = toUInt32Register(source, ScratchRegister);
- storeUInt32(reg, result);
+ storeUInt32(reg, result, barrier);
} else if (source->type == IR::DoubleType) {
- storeDouble(toDoubleRegister(source), result);
+ storeDouble(toDoubleRegister(source), result, barrier);
} else if (source->asTemp() || source->asArgLocal()) {
- RegisterSizeDependentOps::copyValueViaRegisters(this, source, result);
+ RegisterSizeDependentOps::copyValueViaRegisters(this, source, result, barrier);
} else if (IR::Const *c = source->asConst()) {
auto v = convertToValue<TargetPrimitive>(c);
- storeValue(v, result);
+ storeValue(v, result, barrier);
} else {
Q_UNREACHABLE();
}
diff --git a/src/qml/jit/qv4binop.cpp b/src/qml/jit/qv4binop.cpp
index feb30ee298..a1c65f644c 100644
--- a/src/qml/jit/qv4binop.cpp
+++ b/src/qml/jit/qv4binop.cpp
@@ -492,7 +492,7 @@ bool Binop<JITAssembler>::int32Binop(IR::Expr *leftSource, IR::Expr *rightSource
return false;
}
} else if (inplaceOpWithAddress) { // All cases of X = X op [address-of-Y]
- Pointer rhsAddr = as->loadAddress(JITAssembler::ScratchRegister, rightSource);
+ Pointer rhsAddr = as->loadAddressForReading(JITAssembler::ScratchRegister, rightSource);
switch (op) {
case IR::OpBitAnd: as->and32(rhsAddr, targetReg); break;
case IR::OpBitOr: as->or32 (rhsAddr, targetReg); break;
diff --git a/src/qml/jit/qv4isel_masm.cpp b/src/qml/jit/qv4isel_masm.cpp
index 9ddab8f838..a35b12d51e 100644
--- a/src/qml/jit/qv4isel_masm.cpp
+++ b/src/qml/jit/qv4isel_masm.cpp
@@ -133,7 +133,7 @@ void InstructionSelection<JITAssembler>::run(int functionIndex)
if (s->location.isValid()) {
if (int(s->location.startLine) != lastLine) {
_as->loadPtr(Address(JITTargetPlatform::EngineRegister, JITAssembler::targetStructureOffset(offsetof(QV4::EngineBase, current))), JITTargetPlatform::ScratchRegister);
- Address lineAddr(JITTargetPlatform::ScratchRegister, JITAssembler::targetStructureOffset(Heap::ExecutionContext::baseOffset + offsetof(Heap::ExecutionContextData, lineNumber)));
+ Address lineAddr(JITTargetPlatform::ScratchRegister, JITAssembler::targetStructureOffset(Heap::ExecutionContextData::baseOffset + offsetof(Heap::ExecutionContextData, lineNumber)));
_as->store32(TrustedImm32(s->location.startLine), lineAddr);
lastLine = s->location.startLine;
}
@@ -350,11 +350,11 @@ void InstructionSelection<JITAssembler>::callBuiltinDefineObjectLiteral(IR::Expr
bool isData = it->expr->asConst()->value;
it = it->next;
- _as->copyValue(_as->stackLayout().argumentAddressForCall(argc++), it->expr);
+ _as->copyValue(_as->stackLayout().argumentAddressForCall(argc++), it->expr, WriteBarrier::NoBarrier);
if (!isData) {
it = it->next;
- _as->copyValue(_as->stackLayout().argumentAddressForCall(argc++), it->expr);
+ _as->copyValue(_as->stackLayout().argumentAddressForCall(argc++), it->expr, WriteBarrier::NoBarrier);
}
}
@@ -376,10 +376,10 @@ void InstructionSelection<JITAssembler>::callBuiltinDefineObjectLiteral(IR::Expr
++arrayValueCount;
// Index
- _as->storeValue(JITAssembler::TargetPrimitive::fromUInt32(index), _as->stackLayout().argumentAddressForCall(argc++));
+ _as->storeValue(JITAssembler::TargetPrimitive::fromUInt32(index), _as->stackLayout().argumentAddressForCall(argc++), WriteBarrier::NoBarrier);
// Value
- _as->copyValue(_as->stackLayout().argumentAddressForCall(argc++), it->expr);
+ _as->copyValue(_as->stackLayout().argumentAddressForCall(argc++), it->expr, WriteBarrier::NoBarrier);
it = it->next;
}
@@ -400,14 +400,14 @@ void InstructionSelection<JITAssembler>::callBuiltinDefineObjectLiteral(IR::Expr
++arrayGetterSetterCount;
// Index
- _as->storeValue(JITAssembler::TargetPrimitive::fromUInt32(index), _as->stackLayout().argumentAddressForCall(argc++));
+ _as->storeValue(JITAssembler::TargetPrimitive::fromUInt32(index), _as->stackLayout().argumentAddressForCall(argc++), WriteBarrier::NoBarrier);
// Getter
- _as->copyValue(_as->stackLayout().argumentAddressForCall(argc++), it->expr);
+ _as->copyValue(_as->stackLayout().argumentAddressForCall(argc++), it->expr, WriteBarrier::NoBarrier);
it = it->next;
// Setter
- _as->copyValue(_as->stackLayout().argumentAddressForCall(argc++), it->expr);
+ _as->copyValue(_as->stackLayout().argumentAddressForCall(argc++), it->expr, WriteBarrier::NoBarrier);
it = it->next;
}
@@ -447,9 +447,11 @@ void InstructionSelection<JITAssembler>::callValue(IR::Expr *value, IR::ExprList
template <typename JITAssembler>
void InstructionSelection<JITAssembler>::loadThisObject(IR::Expr *temp)
{
- _as->loadPtr(Address(JITTargetPlatform::EngineRegister, JITAssembler::targetStructureOffset(offsetof(QV4::EngineBase, current))), JITTargetPlatform::ScratchRegister);
- _as->loadPtr(Address(JITTargetPlatform::ScratchRegister, JITAssembler::targetStructureOffset(Heap::ExecutionContext::baseOffset + offsetof(Heap::ExecutionContextData, callData))), JITTargetPlatform::ScratchRegister);
- _as->copyValue(temp, Address(JITTargetPlatform::ScratchRegister, offsetof(CallData, thisObject)));
+ WriteBarrier::Type barrier;
+ Pointer addr = _as->loadAddressForWriting(JITTargetPlatform::ScratchRegister, temp, &barrier);
+ _as->loadPtr(Address(JITTargetPlatform::EngineRegister, JITAssembler::targetStructureOffset(offsetof(QV4::EngineBase, current))), JITTargetPlatform::ReturnValueRegister);
+ _as->loadPtr(Address(JITTargetPlatform::ReturnValueRegister,JITAssembler::targetStructureOffset(Heap::ExecutionContextData::baseOffset + offsetof(Heap::ExecutionContextData, callData))), JITTargetPlatform::ReturnValueRegister);
+ _as->copyValue(addr, Address(JITTargetPlatform::ReturnValueRegister, offsetof(CallData, thisObject)), barrier);
}
template <typename JITAssembler>
@@ -503,8 +505,9 @@ void InstructionSelection<JITAssembler>::loadString(const QString &str, IR::Expr
{
Pointer srcAddr = _as->loadStringAddress(JITTargetPlatform::ReturnValueRegister, str);
_as->loadPtr(srcAddr, JITTargetPlatform::ReturnValueRegister);
- Pointer destAddr = _as->loadAddress(JITTargetPlatform::ScratchRegister, target);
- JITAssembler::RegisterSizeDependentOps::loadManagedPointer(_as, JITTargetPlatform::ReturnValueRegister, destAddr);
+ WriteBarrier::Type barrier;
+ Pointer destAddr = _as->loadAddressForWriting(JITTargetPlatform::ScratchRegister, target, &barrier);
+ JITAssembler::RegisterSizeDependentOps::loadManagedPointer(_as, JITTargetPlatform::ReturnValueRegister, destAddr, barrier);
}
template <typename JITAssembler>
@@ -621,6 +624,7 @@ void InstructionSelection<JITAssembler>::getElement(IR::Expr *base, IR::Expr *in
if (0 && useFastLookups) {
uint lookup = registerIndexedGetterLookup();
generateLookupCall(target, lookup, offsetof(QV4::Lookup, indexedGetter),
+ JITTargetPlatform::EngineRegister,
PointerToValue(base),
PointerToValue(index));
return;
@@ -636,6 +640,7 @@ void InstructionSelection<JITAssembler>::setElement(IR::Expr *source, IR::Expr *
if (0 && useFastLookups) {
uint lookup = registerIndexedSetterLookup();
generateLookupCall(JITAssembler::Void, lookup, offsetof(QV4::Lookup, indexedSetter),
+ JITTargetPlatform::EngineRegister,
PointerToValue(targetBase), PointerToValue(targetIndex),
PointerToValue(source));
return;
@@ -711,8 +716,10 @@ void InstructionSelection<JITAssembler>::copyValue(IR::Expr *source, IR::Expr *t
}
}
+ WriteBarrier::Type barrier;
+ Pointer addr = _as->loadAddressForWriting(JITTargetPlatform::ReturnValueRegister, target, &barrier);
// The target is not a physical register, nor is the source. So we can do a memory-to-memory copy:
- _as->memcopyValue(_as->loadAddress(JITTargetPlatform::ReturnValueRegister, target), source, JITTargetPlatform::ScratchRegister);
+ _as->memcopyValue(addr, source, JITTargetPlatform::ScratchRegister, barrier);
}
template <typename JITAssembler>
@@ -739,14 +746,13 @@ void InstructionSelection<JITAssembler>::swapValues(IR::Expr *source, IR::Expr *
} else if (!sourceTemp || sourceTemp->kind == IR::Temp::StackSlot) {
if (!targetTemp || targetTemp->kind == IR::Temp::StackSlot) {
// Note: a swap for two stack-slots can involve different types.
- Pointer sAddr = _as->loadAddress(JITTargetPlatform::ScratchRegister, source);
- Pointer tAddr = _as->loadAddress(JITTargetPlatform::ReturnValueRegister, target);
- // use the implementation in JSC::MacroAssembler, as it doesn't do bit swizzling
- auto platformAs = static_cast<typename JITAssembler::MacroAssembler*>(_as);
- platformAs->loadDouble(sAddr, JITTargetPlatform::FPGpr0);
- platformAs->loadDouble(tAddr, JITTargetPlatform::FPGpr1);
- platformAs->storeDouble(JITTargetPlatform::FPGpr1, sAddr);
- platformAs->storeDouble(JITTargetPlatform::FPGpr0, tAddr);
+ WriteBarrier::Type barrierForSource, barrierForTarget;
+ Pointer sAddr = _as->loadAddressForWriting(JITTargetPlatform::ScratchRegister, source, &barrierForSource);
+ Pointer tAddr = _as->loadAddressForWriting(JITTargetPlatform::ReturnValueRegister, target, &barrierForTarget);
+ _as->loadRawValue(sAddr, JITTargetPlatform::FPGpr0);
+ _as->loadRawValue(tAddr, JITTargetPlatform::FPGpr1);
+ _as->storeRawValue(JITTargetPlatform::FPGpr1, sAddr, barrierForSource);
+ _as->storeRawValue(JITTargetPlatform::FPGpr0, tAddr, barrierForTarget);
return;
}
}
@@ -757,14 +763,15 @@ void InstructionSelection<JITAssembler>::swapValues(IR::Expr *source, IR::Expr *
Q_ASSERT(memExpr);
Q_ASSERT(regTemp);
- Pointer addr = _as->loadAddress(JITTargetPlatform::ReturnValueRegister, memExpr);
+ WriteBarrier::Type barrier;
+ Pointer addr = _as->loadAddressForWriting(JITTargetPlatform::ReturnValueRegister, memExpr, &barrier);
if (regTemp->type == IR::DoubleType) {
_as->loadDouble(addr, JITTargetPlatform::FPGpr0);
- _as->storeDouble((FPRegisterID) regTemp->index, addr);
+ _as->storeDouble((FPRegisterID) regTemp->index, addr, barrier);
_as->moveDouble(JITTargetPlatform::FPGpr0, (FPRegisterID) regTemp->index);
} else if (regTemp->type == IR::UInt32Type) {
_as->toUInt32Register(addr, JITTargetPlatform::ScratchRegister);
- _as->storeUInt32((RegisterID) regTemp->index, addr);
+ _as->storeUInt32((RegisterID) regTemp->index, addr, barrier);
_as->move(JITTargetPlatform::ScratchRegister, (RegisterID) regTemp->index);
} else {
_as->load32(addr, JITTargetPlatform::ScratchRegister);
@@ -784,6 +791,7 @@ void InstructionSelection<JITAssembler>::swapValues(IR::Expr *source, IR::Expr *
Q_UNREACHABLE();
}
_as->store32(TrustedImm32(tag), addr);
+ _as->emitWriteBarrier(addr, barrier);
}
_as->move(JITTargetPlatform::ScratchRegister, (RegisterID) regTemp->index);
}
@@ -913,13 +921,13 @@ void InstructionSelection<JITAssembler>::convertTypeToDouble(IR::Expr *source, I
convertUIntToDouble(source, target);
break;
case IR::UndefinedType:
- _as->loadDouble(_as->loadAddress(JITTargetPlatform::ScratchRegister, source), JITTargetPlatform::FPGpr0);
+ _as->loadDouble(_as->loadAddressForReading(JITTargetPlatform::ScratchRegister, source), JITTargetPlatform::FPGpr0);
_as->storeDouble(JITTargetPlatform::FPGpr0, target);
break;
case IR::StringType:
case IR::VarType: {
// load the tag:
- Pointer tagAddr = _as->loadAddress(JITTargetPlatform::ScratchRegister, source);
+ Pointer tagAddr = _as->loadAddressForReading(JITTargetPlatform::ScratchRegister, source);
tagAddr.offset += 4;
_as->load32(tagAddr, JITTargetPlatform::ScratchRegister);
@@ -938,7 +946,7 @@ void InstructionSelection<JITAssembler>::convertTypeToDouble(IR::Expr *source, I
// it is a double:
isDbl.link(_as);
- Pointer addr2 = _as->loadAddress(JITTargetPlatform::ScratchRegister, source);
+ Pointer addr2 = _as->loadAddressForReading(JITTargetPlatform::ScratchRegister, source);
IR::Temp *targetTemp = target->asTemp();
if (!targetTemp || targetTemp->kind == IR::Temp::StackSlot) {
_as->memcopyValue(target, addr2, JITTargetPlatform::FPGpr0, JITTargetPlatform::ReturnValueRegister);
@@ -997,7 +1005,7 @@ void InstructionSelection<JITAssembler>::convertTypeToBool(IR::Expr *source, IR:
Q_FALLTHROUGH();
case IR::VarType:
default:
- Pointer addr = _as->loadAddress(JITTargetPlatform::ScratchRegister, source);
+ Pointer addr = _as->loadAddressForReading(JITTargetPlatform::ScratchRegister, source);
Pointer tagAddr = addr;
tagAddr.offset += 4;
_as->load32(tagAddr, JITTargetPlatform::ReturnValueRegister);
@@ -1062,7 +1070,7 @@ void InstructionSelection<JITAssembler>::convertTypeToSInt32(IR::Expr *source, I
case IR::StringType:
default:
generateRuntimeCall(_as, JITTargetPlatform::ReturnValueRegister, toInt,
- _as->loadAddress(JITTargetPlatform::ScratchRegister, source));
+ _as->loadAddressForReading(JITTargetPlatform::ScratchRegister, source));
_as->storeInt32(JITTargetPlatform::ReturnValueRegister, target);
break;
} // switch (source->type)
@@ -1074,21 +1082,21 @@ void InstructionSelection<JITAssembler>::convertTypeToUInt32(IR::Expr *source, I
switch (source->type) {
case IR::VarType: {
// load the tag:
- Pointer tagAddr = _as->loadAddress(JITTargetPlatform::ScratchRegister, source);
+ Pointer tagAddr = _as->loadAddressForReading(JITTargetPlatform::ScratchRegister, source);
tagAddr.offset += 4;
_as->load32(tagAddr, JITTargetPlatform::ScratchRegister);
// check if it's an int32:
Jump isNoInt = _as->branch32(RelationalCondition::NotEqual, JITTargetPlatform::ScratchRegister,
TrustedImm32(quint32(JITAssembler::ValueTypeInternal::Integer)));
- Pointer addr = _as->loadAddress(JITTargetPlatform::ScratchRegister, source);
+ Pointer addr = _as->loadAddressForReading(JITTargetPlatform::ScratchRegister, source);
_as->storeUInt32(_as->toInt32Register(addr, JITTargetPlatform::ScratchRegister), target);
Jump intDone = _as->jump();
// not an int:
isNoInt.link(_as);
generateRuntimeCall(_as, JITTargetPlatform::ReturnValueRegister, toUInt,
- _as->loadAddress(JITTargetPlatform::ScratchRegister, source));
+ _as->loadAddressForReading(JITTargetPlatform::ScratchRegister, source));
_as->storeInt32(JITTargetPlatform::ReturnValueRegister, target);
intDone.link(_as);
@@ -1193,7 +1201,7 @@ void InstructionSelection<JITAssembler>::visitCJump(IR::CJump *s)
reg = JITTargetPlatform::ReturnValueRegister;
_as->toInt32Register(t, reg);
} else {
- Address temp = _as->loadAddress(JITTargetPlatform::ScratchRegister, s->cond);
+ Address temp = _as->loadAddressForReading(JITTargetPlatform::ScratchRegister, s->cond);
Address tag = temp;
tag.offset += QV4::Value::tagOffset();
Jump booleanConversion = _as->branch32(RelationalCondition::NotEqual, tag,
@@ -1299,9 +1307,9 @@ int InstructionSelection<JITAssembler>::prepareVariableArguments(IR::ExprList* a
Q_ASSERT(arg != 0);
Pointer dst(_as->stackLayout().argumentAddressForCall(i));
if (arg->asTemp() && arg->asTemp()->kind != IR::Temp::PhysicalRegister)
- _as->memcopyValue(dst, arg->asTemp(), JITTargetPlatform::ScratchRegister);
+ _as->memcopyValue(dst, arg->asTemp(), JITTargetPlatform::ScratchRegister, WriteBarrier::NoBarrier);
else
- _as->copyValue(dst, arg);
+ _as->copyValue(dst, arg, WriteBarrier::NoBarrier);
}
return argc;
@@ -1321,9 +1329,9 @@ int InstructionSelection<JITAssembler>::prepareCallData(IR::ExprList* args, IR::
_as->store32(TrustedImm32(argc), p);
p = _as->stackLayout().callDataAddress(offsetof(CallData, thisObject));
if (!thisObject)
- _as->storeValue(JITAssembler::TargetPrimitive::undefinedValue(), p);
+ _as->storeValue(JITAssembler::TargetPrimitive::undefinedValue(), p, WriteBarrier::NoBarrier);
else
- _as->copyValue(p, thisObject);
+ _as->copyValue(p, thisObject, WriteBarrier::NoBarrier);
int i = 0;
for (IR::ExprList *it = args; it; it = it->next, ++i) {
@@ -1331,9 +1339,9 @@ int InstructionSelection<JITAssembler>::prepareCallData(IR::ExprList* args, IR::
Q_ASSERT(arg != 0);
Pointer dst(_as->stackLayout().argumentAddressForCall(i));
if (arg->asTemp() && arg->asTemp()->kind != IR::Temp::PhysicalRegister)
- _as->memcopyValue(dst, arg->asTemp(), JITTargetPlatform::ScratchRegister);
+ _as->memcopyValue(dst, arg->asTemp(), JITTargetPlatform::ScratchRegister, WriteBarrier::NoBarrier);
else
- _as->copyValue(dst, arg);
+ _as->copyValue(dst, arg, WriteBarrier::NoBarrier);
}
return argc;
}
@@ -1451,7 +1459,7 @@ bool InstructionSelection<JITAssembler>::visitCJumpStrictNull(IR::Binop *binop,
return true;
}
- Pointer tagAddr = _as->loadAddress(JITTargetPlatform::ScratchRegister, varSrc);
+ Pointer tagAddr = _as->loadAddressForReading(JITTargetPlatform::ScratchRegister, varSrc);
tagAddr.offset += 4;
const RegisterID tagReg = JITTargetPlatform::ScratchRegister;
_as->load32(tagAddr, tagReg);
@@ -1534,7 +1542,7 @@ bool InstructionSelection<JITAssembler>::visitCJumpStrictBool(IR::Binop *binop,
return true;
}
- Pointer otherAddr = _as->loadAddress(JITTargetPlatform::ReturnValueRegister, otherSrc);
+ Pointer otherAddr = _as->loadAddressForReading(JITTargetPlatform::ReturnValueRegister, otherSrc);
otherAddr.offset += 4; // tag address
// check if the tag of the var operand is indicates 'boolean'
@@ -1583,7 +1591,7 @@ bool InstructionSelection<JITAssembler>::visitCJumpNullUndefined(IR::Type nullOr
return true;
}
- Pointer tagAddr = _as->loadAddress(JITTargetPlatform::ScratchRegister, varSrc);
+ Pointer tagAddr = _as->loadAddressForReading(JITTargetPlatform::ScratchRegister, varSrc);
tagAddr.offset += 4;
const RegisterID tagReg = JITTargetPlatform::ReturnValueRegister;
_as->load32(tagAddr, tagReg);
diff --git a/src/qml/jit/qv4isel_masm_p.h b/src/qml/jit/qv4isel_masm_p.h
index 0992e96e8b..7019a117a2 100644
--- a/src/qml/jit/qv4isel_masm_p.h
+++ b/src/qml/jit/qv4isel_masm_p.h
@@ -209,7 +209,7 @@ private:
_as->convertInt32ToDouble((RegisterID) sourceTemp->index,
(FPRegisterID) targetTemp->index);
} else {
- _as->convertInt32ToDouble(_as->loadAddress(JITTargetPlatform::ReturnValueRegister, sourceTemp),
+ _as->convertInt32ToDouble(_as->loadAddressForReading(JITTargetPlatform::ReturnValueRegister, sourceTemp),
(FPRegisterID) targetTemp->index);
}
} else {
@@ -223,7 +223,7 @@ private:
_as->convertInt32ToDouble(_as->toInt32Register(source, JITTargetPlatform::ScratchRegister),
JITTargetPlatform::FPGpr0);
- _as->storeDouble(JITTargetPlatform::FPGpr0, _as->loadAddress(JITTargetPlatform::ReturnValueRegister, target));
+ _as->storeDouble(JITTargetPlatform::FPGpr0, target);
}
void convertUIntToDouble(IR::Expr *source, IR::Expr *target)
@@ -240,7 +240,7 @@ private:
_as->convertUInt32ToDouble(_as->toUInt32Register(source, tmpReg),
JITTargetPlatform::FPGpr0, tmpReg);
- _as->storeDouble(JITTargetPlatform::FPGpr0, _as->loadAddress(tmpReg, target));
+ _as->storeDouble(JITTargetPlatform::FPGpr0, target);
}
void convertIntToBool(IR::Expr *source, IR::Expr *target)
@@ -260,8 +260,8 @@ private:
void calculateRegistersToSave(const RegisterInformation &used);
- template <typename Retval, typename Arg1, typename Arg2, typename Arg3>
- void generateLookupCall(Retval retval, uint index, uint getterSetterOffset, Arg1 arg1, Arg2 arg2, Arg3 arg3)
+ template <typename Retval, typename Arg1, typename Arg2, typename Arg3, typename Arg4>
+ void generateLookupCall(Retval retval, uint index, uint getterSetterOffset, Arg1 arg1, Arg2 arg2, Arg3 arg3, Arg4 arg4)
{
// Note: using the return value register is intentional: for ABIs where the first parameter
// goes into the same register as the return value (currently only ARM), the prepareCall
@@ -271,7 +271,7 @@ private:
_as->generateFunctionCallImp(true, retval, "lookup getter/setter",
typename JITAssembler::LookupCall(lookupAddr, getterSetterOffset), lookupAddr,
- arg1, arg2, arg3);
+ arg1, arg2, arg3, arg4);
}
template <typename Retval, typename Arg1, typename Arg2>
@@ -280,6 +280,12 @@ private:
generateLookupCall(retval, index, getterSetterOffset, arg1, arg2, typename JITAssembler::VoidType());
}
+ template <typename Retval, typename Arg1, typename Arg2, typename Arg3>
+ void generateLookupCall(Retval retval, uint index, uint getterSetterOffset, Arg1 arg1, Arg2 arg2, Arg3 arg3)
+ {
+ generateLookupCall(retval, index, getterSetterOffset, arg1, arg2, arg3, typename JITAssembler::VoidType());
+ }
+
IR::BasicBlock *_block;
BitVector _removableJumps;
JITAssembler* _as;
diff --git a/src/qml/jsapi/qjsvalue.cpp b/src/qml/jsapi/qjsvalue.cpp
index 3a3cf46ddb..953e5d3ef6 100644
--- a/src/qml/jsapi/qjsvalue.cpp
+++ b/src/qml/jsapi/qjsvalue.cpp
@@ -120,6 +120,13 @@
\value NullValue A null value.
*/
+/*!
+ \typedef QJSValueList
+ \relates QJSValue
+
+ This is a typedef for a QList<QJSValue>.
+*/
+
QT_BEGIN_NAMESPACE
using namespace QV4;
diff --git a/src/qml/jsapi/qjsvalue.h b/src/qml/jsapi/qjsvalue.h
index ab20a2607d..56bd64eec1 100644
--- a/src/qml/jsapi/qjsvalue.h
+++ b/src/qml/jsapi/qjsvalue.h
@@ -133,9 +133,9 @@ public:
bool deleteProperty(const QString &name);
bool isCallable() const;
- QJSValue call(const QJSValueList &args = QJSValueList());
- QJSValue callWithInstance(const QJSValue &instance, const QJSValueList &args = QJSValueList());
- QJSValue callAsConstructor(const QJSValueList &args = QJSValueList());
+ QJSValue call(const QJSValueList &args = QJSValueList()); // ### Qt6: Make const
+ QJSValue callWithInstance(const QJSValue &instance, const QJSValueList &args = QJSValueList()); // ### Qt6: Make const
+ QJSValue callAsConstructor(const QJSValueList &args = QJSValueList()); // ### Qt6: Make const
#ifdef QT_DEPRECATED
QT_DEPRECATED QJSEngine *engine() const;
diff --git a/src/qml/jsruntime/qv4argumentsobject.cpp b/src/qml/jsruntime/qv4argumentsobject.cpp
index 6ab838c387..0905c2828a 100644
--- a/src/qml/jsruntime/qv4argumentsobject.cpp
+++ b/src/qml/jsruntime/qv4argumentsobject.cpp
@@ -48,32 +48,33 @@ DEFINE_OBJECT_VTABLE(ArgumentsObject);
void Heap::ArgumentsObject::init(QV4::CallContext *context)
{
+ ExecutionEngine *v4 = internalClass->engine;
+
Object::init();
fullyCreated = false;
- this->context = context->d();
+ this->context.set(v4, context->d());
Q_ASSERT(vtable() == QV4::ArgumentsObject::staticVTable());
- ExecutionEngine *v4 = context->engine();
Scope scope(v4);
Scoped<QV4::ArgumentsObject> args(scope, this);
if (context->d()->strictMode) {
Q_ASSERT(CalleePropertyIndex == args->internalClass()->find(v4->id_callee()));
Q_ASSERT(CallerPropertyIndex == args->internalClass()->find(v4->id_caller()));
- *args->propertyData(CalleePropertyIndex + QV4::Object::GetterOffset) = v4->thrower();
- *args->propertyData(CalleePropertyIndex + QV4::Object::SetterOffset) = v4->thrower();
- *args->propertyData(CallerPropertyIndex + QV4::Object::GetterOffset) = v4->thrower();
- *args->propertyData(CallerPropertyIndex + QV4::Object::SetterOffset) = v4->thrower();
+ args->setProperty(CalleePropertyIndex + QV4::Object::GetterOffset, *v4->thrower());
+ args->setProperty(CalleePropertyIndex + QV4::Object::SetterOffset, *v4->thrower());
+ args->setProperty(CallerPropertyIndex + QV4::Object::GetterOffset, *v4->thrower());
+ args->setProperty(CallerPropertyIndex + QV4::Object::SetterOffset, *v4->thrower());
args->arrayReserve(context->argc());
args->arrayPut(0, context->args(), context->argc());
args->d()->fullyCreated = true;
} else {
Q_ASSERT(CalleePropertyIndex == args->internalClass()->find(v4->id_callee()));
- *args->propertyData(CalleePropertyIndex) = context->d()->function->asReturnedValue();
+ args->setProperty(CalleePropertyIndex, context->d()->function);
}
Q_ASSERT(LengthPropertyIndex == args->internalClass()->find(v4->id_length()));
- *args->propertyData(LengthPropertyIndex) = Primitive::fromInt32(context->d()->callData->argc);
+ args->setProperty(LengthPropertyIndex, Primitive::fromInt32(context->d()->callData->argc));
}
void ArgumentsObject::fullyCreate()
@@ -90,9 +91,9 @@ void ArgumentsObject::fullyCreate()
Scoped<MemberData> md(scope, d()->mappedArguments);
if (numAccessors) {
- d()->mappedArguments = md->allocate(scope.engine, numAccessors);
+ d()->mappedArguments.set(scope.engine, md->allocate(scope.engine, numAccessors));
for (uint i = 0; i < numAccessors; ++i) {
- d()->mappedArguments->data[i] = context()->callData->args[i];
+ d()->mappedArguments->values.set(scope.engine, i, context()->callData->args[i]);
arraySet(i, scope.engine->argumentsAccessors + i, Attr_Accessor);
}
}
@@ -108,22 +109,22 @@ bool ArgumentsObject::defineOwnProperty(ExecutionEngine *engine, uint index, con
fullyCreate();
Scope scope(engine);
- Property *pd = arrayData() ? arrayData()->getProperty(index) : 0;
ScopedProperty map(scope);
PropertyAttributes mapAttrs;
+ uint numAccessors = qMin(context()->formalParameterCount(), static_cast<uint>(context()->callData->argc));
bool isMapped = false;
- uint numAccessors = qMin((int)context()->formalParameterCount(), context()->callData->argc);
- if (pd && index < (uint)numAccessors)
- isMapped = arrayData()->attributes(index).isAccessor() &&
- pd->getter() == scope.engine->argumentsAccessors[index].getter();
+ if (arrayData() && index < numAccessors &&
+ arrayData()->attributes(index).isAccessor() &&
+ arrayData()->get(index) == scope.engine->argumentsAccessors[index].getter()->asReturnedValue())
+ isMapped = true;
if (isMapped) {
Q_ASSERT(arrayData());
mapAttrs = arrayData()->attributes(index);
- map->copy(pd, mapAttrs);
+ arrayData()->getProperty(index, map, &mapAttrs);
setArrayAttributes(index, Attr_Data);
- pd = arrayData()->getProperty(index);
- pd->value = d()->mappedArguments->data[index];
+ ArrayData::Index arrayIndex{ arrayData(), arrayData()->mappedIndex(index) };
+ arrayIndex.set(scope.engine, d()->mappedArguments->values[index]);
}
bool strict = engine->current->strictMode;
@@ -141,8 +142,7 @@ bool ArgumentsObject::defineOwnProperty(ExecutionEngine *engine, uint index, con
if (attrs.isWritable()) {
setArrayAttributes(index, mapAttrs);
- pd = arrayData()->getProperty(index);
- pd->copy(map, mapAttrs);
+ arrayData()->setProperty(engine, index, map);
}
}
@@ -167,18 +167,17 @@ ReturnedValue ArgumentsObject::getIndexed(const Managed *m, uint index, bool *ha
return Encode::undefined();
}
-void ArgumentsObject::putIndexed(Managed *m, uint index, const Value &value)
+bool ArgumentsObject::putIndexed(Managed *m, uint index, const Value &value)
{
ArgumentsObject *args = static_cast<ArgumentsObject *>(m);
if (!args->fullyCreated() && index >= static_cast<uint>(args->context()->callData->argc))
args->fullyCreate();
- if (args->fullyCreated()) {
- Object::putIndexed(m, index, value);
- return;
- }
+ if (args->fullyCreated())
+ return Object::putIndexed(m, index, value);
args->context()->callData->args[index] = value;
+ return true;
}
bool ArgumentsObject::deleteIndexedProperty(Managed *m, uint index)
@@ -237,17 +236,6 @@ void ArgumentsSetterFunction::call(const Managed *setter, Scope &scope, CallData
scope.result = Encode::undefined();
}
-void ArgumentsObject::markObjects(Heap::Base *that, ExecutionEngine *e)
-{
- ArgumentsObject::Data *o = static_cast<ArgumentsObject::Data *>(that);
- if (o->context)
- o->context->mark(e);
- if (o->mappedArguments)
- o->mappedArguments->mark(e);
-
- Object::markObjects(that, e);
-}
-
uint ArgumentsObject::getLength(const Managed *m)
{
const ArgumentsObject *a = static_cast<const ArgumentsObject *>(m);
diff --git a/src/qml/jsruntime/qv4argumentsobject_p.h b/src/qml/jsruntime/qv4argumentsobject_p.h
index 0a2ea3b42a..46e1f884e8 100644
--- a/src/qml/jsruntime/qv4argumentsobject_p.h
+++ b/src/qml/jsruntime/qv4argumentsobject_p.h
@@ -59,26 +59,35 @@ namespace QV4 {
namespace Heap {
-struct ArgumentsGetterFunction : FunctionObject {
+#define ArgumentsGetterFunctionMembers(class, Member) \
+ Member(class, NoMark, uint, index)
+
+DECLARE_HEAP_OBJECT(ArgumentsGetterFunction, FunctionObject) {
+ DECLARE_MARK_TABLE(ArgumentsGetterFunction);
inline void init(QV4::ExecutionContext *scope, uint index);
- uint index;
};
-struct ArgumentsSetterFunction : FunctionObject {
+#define ArgumentsSetterFunctionMembers(class, Member) \
+ Member(class, NoMark, uint, index)
+
+DECLARE_HEAP_OBJECT(ArgumentsSetterFunction, FunctionObject) {
+ DECLARE_MARK_TABLE(ArgumentsSetterFunction);
inline void init(QV4::ExecutionContext *scope, uint index);
- uint index;
};
-struct ArgumentsObject : Object {
+#define ArgumentsObjectMembers(class, Member) \
+ Member(class, Pointer, CallContext *, context) \
+ Member(class, Pointer, MemberData *, mappedArguments) \
+ Member(class, NoMark, bool, fullyCreated)
+
+DECLARE_HEAP_OBJECT(ArgumentsObject, Object) {
+ DECLARE_MARK_TABLE(ArgumentsObject);
enum {
LengthPropertyIndex = 0,
CalleePropertyIndex = 1,
CallerPropertyIndex = 3
};
void init(QV4::CallContext *context);
- Pointer<CallContext> context;
- bool fullyCreated;
- Pointer<MemberData> mappedArguments;
};
}
@@ -128,10 +137,9 @@ struct ArgumentsObject: Object {
bool defineOwnProperty(ExecutionEngine *engine, uint index, const Property *desc, PropertyAttributes attrs);
static ReturnedValue getIndexed(const Managed *m, uint index, bool *hasProperty);
- static void putIndexed(Managed *m, uint index, const Value &value);
+ static bool putIndexed(Managed *m, uint index, const Value &value);
static bool deleteIndexedProperty(Managed *m, uint index);
static PropertyAttributes queryIndexed(const Managed *m, uint index);
- static void markObjects(Heap::Base *that, ExecutionEngine *e);
static uint getLength(const Managed *m);
void fullyCreate();
diff --git a/src/qml/jsruntime/qv4arraydata.cpp b/src/qml/jsruntime/qv4arraydata.cpp
index 6d1fb62e0a..df9884d84a 100644
--- a/src/qml/jsruntime/qv4arraydata.cpp
+++ b/src/qml/jsruntime/qv4arraydata.cpp
@@ -52,6 +52,7 @@ const QV4::VTable QV4::ArrayData::static_vtbl = {
0,
0,
0,
+ 0,
QV4::ArrayData::IsExecutionContext,
QV4::ArrayData::IsString,
QV4::ArrayData::IsObject,
@@ -130,7 +131,7 @@ void ArrayData::realloc(Object *o, Type newType, uint requested, bool enforceAtt
if (d->type() < Heap::ArrayData::Sparse) {
offset = d->d()->offset;
- toCopy = d->d()->len;
+ toCopy = d->d()->values.size;
} else {
toCopy = d->alloc();
}
@@ -151,7 +152,7 @@ void ArrayData::realloc(Object *o, Type newType, uint requested, bool enforceAtt
Heap::SimpleArrayData *n = scope.engine->memoryManager->allocManaged<SimpleArrayData>(size);
n->init();
n->offset = 0;
- n->len = d ? d->d()->len : 0;
+ n->values.size = d ? d->d()->values.size : 0;
newData = n;
} else {
Heap::SparseArrayData *n = scope.engine->memoryManager->allocManaged<SparseArrayData>(size);
@@ -160,7 +161,7 @@ void ArrayData::realloc(Object *o, Type newType, uint requested, bool enforceAtt
}
newData->setAlloc(alloc);
newData->setType(newType);
- newData->setAttrs(enforceAttributes ? reinterpret_cast<PropertyAttributes *>(newData->d()->arrayData + alloc) : 0);
+ newData->setAttrs(enforceAttributes ? reinterpret_cast<PropertyAttributes *>(newData->d()->values.values + alloc) : 0);
o->setArrayData(newData);
if (d) {
@@ -172,12 +173,14 @@ void ArrayData::realloc(Object *o, Type newType, uint requested, bool enforceAtt
newData->attrs()[i] = Attr_Data;
}
- if (toCopy > d->d()->alloc - offset) {
- uint copyFromStart = toCopy - (d->d()->alloc - offset);
- memcpy(newData->d()->arrayData + toCopy - copyFromStart, d->d()->arrayData, sizeof(Value)*copyFromStart);
+ if (toCopy > d->d()->values.alloc - offset) {
+ uint copyFromStart = toCopy - (d->d()->values.alloc - offset);
+ // no write barrier required here
+ memcpy(newData->d()->values.values + toCopy - copyFromStart, d->d()->values.values, sizeof(Value)*copyFromStart);
toCopy -= copyFromStart;
}
- memcpy(newData->d()->arrayData, d->d()->arrayData + offset, sizeof(Value)*toCopy);
+ // no write barrier required here
+ memcpy(newData->d()->values.values, d->d()->values.values + offset, sizeof(Value)*toCopy);
}
if (newType != Heap::ArrayData::Sparse)
@@ -197,22 +200,22 @@ void ArrayData::realloc(Object *o, Type newType, uint requested, bool enforceAtt
lastFree = &sparse->freeList;
storeValue(lastFree, 0);
for (uint i = 0; i < toCopy; ++i) {
- if (!sparse->arrayData[i].isEmpty()) {
+ if (!sparse->values[i].isEmpty()) {
SparseArrayNode *n = sparse->sparse->insert(i);
n->value = i;
} else {
storeValue(lastFree, i);
- sparse->arrayData[i].setEmpty();
- lastFree = &sparse->arrayData[i].rawValueRef();
+ sparse->values.values[i].setEmpty();
+ lastFree = &sparse->values.values[i].rawValueRef();
}
}
}
- if (toCopy < sparse->alloc) {
- for (uint i = toCopy; i < sparse->alloc; ++i) {
+ if (toCopy < sparse->values.alloc) {
+ for (uint i = toCopy; i < sparse->values.alloc; ++i) {
storeValue(lastFree, i);
- sparse->arrayData[i].setEmpty();
- lastFree = &sparse->arrayData[i].rawValueRef();
+ sparse->values.values[i].setEmpty();
+ lastFree = &sparse->values.values[i].rawValueRef();
}
storeValue(lastFree, UINT_MAX);
}
@@ -235,24 +238,10 @@ void ArrayData::ensureAttributes(Object *o)
ArrayData::realloc(o, Heap::ArrayData::Simple, 0, true);
}
-
-void SimpleArrayData::markObjects(Heap::Base *d, ExecutionEngine *e)
-{
- Heap::SimpleArrayData *dd = static_cast<Heap::SimpleArrayData *>(d);
- uint end = dd->offset + dd->len;
- if (end > dd->alloc) {
- for (uint i = 0; i < end - dd->alloc; ++i)
- dd->arrayData[i].mark(e);
- end = dd->alloc;
- }
- for (uint i = dd->offset; i < end; ++i)
- dd->arrayData[i].mark(e);
-}
-
ReturnedValue SimpleArrayData::get(const Heap::ArrayData *d, uint index)
{
const Heap::SimpleArrayData *dd = static_cast<const Heap::SimpleArrayData *>(d);
- if (index >= dd->len)
+ if (index >= dd->values.size)
return Primitive::emptyValue().asReturnedValue();
return dd->data(index).asReturnedValue();
}
@@ -260,13 +249,13 @@ ReturnedValue SimpleArrayData::get(const Heap::ArrayData *d, uint index)
bool SimpleArrayData::put(Object *o, uint index, const Value &value)
{
Heap::SimpleArrayData *dd = o->d()->arrayData.cast<Heap::SimpleArrayData>();
- Q_ASSERT(index >= dd->len || !dd->attrs || !dd->attrs[index].isAccessor());
+ Q_ASSERT(index >= dd->values.size || !dd->attrs || !dd->attrs[index].isAccessor());
// ### honour attributes
- dd->data(index) = value;
- if (index >= dd->len) {
+ dd->setData(o->engine(), index, value);
+ if (index >= dd->values.size) {
if (dd->attrs)
dd->attrs[index] = Attr_Data;
- dd->len = index + 1;
+ dd->values.size = index + 1;
}
return true;
}
@@ -274,11 +263,11 @@ bool SimpleArrayData::put(Object *o, uint index, const Value &value)
bool SimpleArrayData::del(Object *o, uint index)
{
Heap::SimpleArrayData *dd = o->d()->arrayData.cast<Heap::SimpleArrayData>();
- if (index >= dd->len)
+ if (index >= dd->values.size)
return true;
if (!dd->attrs || dd->attrs[index].isConfigurable()) {
- dd->data(index) = Primitive::emptyValue();
+ dd->setData(o->engine(), index, Primitive::emptyValue());
if (dd->attrs)
dd->attrs[index] = Attr_Data;
return true;
@@ -297,8 +286,8 @@ void SimpleArrayData::push_front(Object *o, const Value *values, uint n)
{
Heap::SimpleArrayData *dd = o->d()->arrayData.cast<Heap::SimpleArrayData>();
Q_ASSERT(!dd->attrs);
- if (dd->len + n > dd->alloc) {
- realloc(o, Heap::ArrayData::Simple, dd->len + n, false);
+ if (dd->values.size + n > dd->values.alloc) {
+ realloc(o, Heap::ArrayData::Simple, dd->values.size + n, false);
Q_ASSERT(o->d()->arrayData->type == Heap::ArrayData::Simple);
dd = o->d()->arrayData.cast<Heap::SimpleArrayData>();
}
@@ -306,70 +295,71 @@ void SimpleArrayData::push_front(Object *o, const Value *values, uint n)
dd->offset -= n; // there is enough space left in front
} else {
// we need to wrap around, so:
- dd->offset = dd->alloc - // start at the back, but subtract:
+ dd->offset = dd->values.alloc - // start at the back, but subtract:
(n - dd->offset); // the number of items we can put in the free space at the start of the allocated array
}
- dd->len += n;
+ dd->values.size += n;
for (uint i = 0; i < n; ++i)
- dd->data(i) = values[i].asReturnedValue();
+ dd->setData(o->engine(), i, values[i]);
}
ReturnedValue SimpleArrayData::pop_front(Object *o)
{
Heap::SimpleArrayData *dd = o->d()->arrayData.cast<Heap::SimpleArrayData>();
Q_ASSERT(!dd->attrs);
- if (!dd->len)
+ if (!dd->values.size)
return Encode::undefined();
ReturnedValue v = dd->data(0).isEmpty() ? Encode::undefined() : dd->data(0).asReturnedValue();
- dd->offset = (dd->offset + 1) % dd->alloc;
- --dd->len;
+ dd->offset = (dd->offset + 1) % dd->values.alloc;
+ --dd->values.size;
return v;
}
uint SimpleArrayData::truncate(Object *o, uint newLen)
{
Heap::SimpleArrayData *dd = o->d()->arrayData.cast<Heap::SimpleArrayData>();
- if (dd->len < newLen)
+ if (dd->values.size < newLen)
return newLen;
if (!dd->attrs) {
- dd->len = newLen;
+ dd->values.size = newLen;
return newLen;
}
- while (dd->len > newLen) {
- if (!dd->data(dd->len - 1).isEmpty() && !dd->attrs[dd->len - 1].isConfigurable())
- return dd->len;
- --dd->len;
+ while (dd->values.size > newLen) {
+ if (!dd->data(dd->values.size - 1).isEmpty() && !dd->attrs[dd->values.size - 1].isConfigurable())
+ return dd->values.size;
+ --dd->values.size;
}
- return dd->len;
+ return dd->values.size;
}
uint SimpleArrayData::length(const Heap::ArrayData *d)
{
- return d->len;
+ return d->values.size;
}
bool SimpleArrayData::putArray(Object *o, uint index, const Value *values, uint n)
{
Heap::SimpleArrayData *dd = o->d()->arrayData.cast<Heap::SimpleArrayData>();
- if (index + n > dd->alloc) {
+ if (index + n > dd->values.alloc) {
reallocate(o, index + n + 1, false);
dd = o->d()->arrayData.cast<Heap::SimpleArrayData>();
}
- for (uint i = dd->len; i < index; ++i)
- dd->data(i) = Primitive::emptyValue();
+ QV4::ExecutionEngine *e = o->engine();
+ for (uint i = dd->values.size; i < index; ++i)
+ dd->setData(e, i, Primitive::emptyValue());
for (uint i = 0; i < n; ++i)
- dd->data(index + i) = values[i];
- dd->len = qMax(dd->len, index + n);
+ dd->setData(e, index + i, values[i]);
+ dd->values.size = qMax(dd->values.size, index + n);
return true;
}
void SparseArrayData::free(Heap::ArrayData *d, uint idx)
{
Q_ASSERT(d && d->type == Heap::ArrayData::Sparse);
- Value *v = d->arrayData + idx;
+ Value *v = d->values.values + idx;
if (d->attrs && d->attrs[idx].isAccessor()) {
// double slot, free both. Order is important, so we have a double slot for allocation again afterwards.
v[1].setEmpty(Value::fromReturnedValue(d->freeList).emptyValue());
@@ -382,15 +372,6 @@ void SparseArrayData::free(Heap::ArrayData *d, uint idx)
d->attrs[idx].clear();
}
-
-void SparseArrayData::markObjects(Heap::Base *d, ExecutionEngine *e)
-{
- Heap::SparseArrayData *dd = static_cast<Heap::SparseArrayData *>(d);
- uint l = dd->alloc;
- for (uint i = 0; i < l; ++i)
- dd->arrayData[i].mark(e);
-}
-
Heap::ArrayData *SparseArrayData::reallocate(Object *o, uint n, bool enforceAttributes)
{
realloc(o, Heap::ArrayData::Sparse, n, enforceAttributes);
@@ -406,32 +387,32 @@ uint SparseArrayData::allocate(Object *o, bool doubleSlot)
ReturnedValue *last = &dd->freeList;
while (1) {
if (Value::fromReturnedValue(*last).value() == UINT_MAX) {
- reallocate(o, dd->alloc + 2, true);
+ reallocate(o, dd->values.alloc + 2, true);
dd = o->d()->arrayData.cast<Heap::SimpleArrayData>();
last = &dd->freeList;
Q_ASSERT(Value::fromReturnedValue(*last).value() != UINT_MAX);
}
- Q_ASSERT(dd->arrayData[Value::fromReturnedValue(*last).value()].value() != Value::fromReturnedValue(*last).value());
- if (dd->arrayData[Value::fromReturnedValue(*last).value()].value() == (Value::fromReturnedValue(*last).value() + 1)) {
+ Q_ASSERT(dd->values[Value::fromReturnedValue(*last).value()].value() != Value::fromReturnedValue(*last).value());
+ if (dd->values[Value::fromReturnedValue(*last).value()].value() == (Value::fromReturnedValue(*last).value() + 1)) {
// found two slots in a row
uint idx = Value::fromReturnedValue(*last).emptyValue();
Value lastV = Value::fromReturnedValue(*last);
- lastV.setEmpty(dd->arrayData[lastV.emptyValue() + 1].value());
+ lastV.setEmpty(dd->values[lastV.emptyValue() + 1].value());
*last = lastV.rawValue();
dd->attrs[idx] = Attr_Accessor;
return idx;
}
- last = &dd->arrayData[Value::fromReturnedValue(*last).value()].rawValueRef();
+ last = &dd->values.values[Value::fromReturnedValue(*last).value()].rawValueRef();
}
} else {
if (Value::fromReturnedValue(dd->freeList).value() == UINT_MAX) {
- reallocate(o, dd->alloc + 1, false);
+ reallocate(o, dd->values.alloc + 1, false);
dd = o->d()->arrayData.cast<Heap::SimpleArrayData>();
}
uint idx = Value::fromReturnedValue(dd->freeList).value();
Q_ASSERT(idx != UINT_MAX);
- dd->freeList = dd->arrayData[idx].asReturnedValue();
+ dd->freeList = dd->values[idx].asReturnedValue();
Q_ASSERT(Value::fromReturnedValue(dd->freeList).isEmpty());
if (dd->attrs)
dd->attrs[idx] = Attr_Data;
@@ -445,7 +426,7 @@ ReturnedValue SparseArrayData::get(const Heap::ArrayData *d, uint index)
index = s->mappedIndex(index);
if (index == UINT_MAX)
return Primitive::emptyValue().asReturnedValue();
- return s->arrayData[index].asReturnedValue();
+ return s->values[index].asReturnedValue();
}
bool SparseArrayData::put(Object *o, uint index, const Value &value)
@@ -459,7 +440,7 @@ bool SparseArrayData::put(Object *o, uint index, const Value &value)
if (n->value == UINT_MAX)
n->value = allocate(o);
s = o->d()->arrayData.cast<Heap::SparseArrayData>();
- s->arrayData[n->value] = value;
+ s->setArrayData(o->engine(), n->value, value);
if (s->attrs)
s->attrs[n->value] = Attr_Data;
return true;
@@ -474,7 +455,7 @@ bool SparseArrayData::del(Object *o, uint index)
return true;
uint pidx = n->value;
- Q_ASSERT(!dd->arrayData[pidx].isEmpty());
+ Q_ASSERT(!dd->values[pidx].isEmpty());
bool isAccessor = false;
if (dd->attrs) {
@@ -487,11 +468,11 @@ bool SparseArrayData::del(Object *o, uint index)
if (isAccessor) {
// free up both indices
- dd->arrayData[pidx + 1].setEmpty(Value::fromReturnedValue(dd->freeList).emptyValue());
- dd->arrayData[pidx].setEmpty(pidx + 1);
+ dd->values.values[pidx + 1].setEmpty(Value::fromReturnedValue(dd->freeList).emptyValue());
+ dd->values.values[pidx].setEmpty(pidx + 1);
} else {
Q_ASSERT(dd->type == Heap::ArrayData::Sparse);
- dd->arrayData[pidx].setEmpty(Value::fromReturnedValue(dd->freeList).emptyValue());
+ dd->values.values[pidx].setEmpty(Value::fromReturnedValue(dd->freeList).emptyValue());
}
dd->freeList = Primitive::emptyValue(pidx).asReturnedValue();
@@ -520,10 +501,10 @@ void SparseArrayData::push_front(Object *o, const Value *values, uint n)
{
Heap::SparseArrayData *d = o->d()->arrayData.cast<Heap::SparseArrayData>();
Q_ASSERT(!d->attrs);
- for (int i = n - 1; i >= 0; --i) {
+ for (int i = static_cast<int>(n) - 1; i >= 0; --i) {
uint idx = allocate(o);
d = o->d()->arrayData.cast<Heap::SparseArrayData>();
- d->arrayData[idx] = values[i];
+ d->setArrayData(o->engine(), idx, values[i]);
d->sparse->push_front(idx);
}
}
@@ -535,7 +516,7 @@ ReturnedValue SparseArrayData::pop_front(Object *o)
uint idx = d->sparse->pop_front();
ReturnedValue v;
if (idx != UINT_MAX) {
- v = d->arrayData[idx].asReturnedValue();
+ v = d->values[idx].asReturnedValue();
free(o->arrayData(), idx);
} else {
v = Encode::undefined();
@@ -613,24 +594,24 @@ uint ArrayData::append(Object *obj, ArrayObject *otherObj, uint n)
ScopedValue v(scope);
for (const SparseArrayNode *it = os->sparse->begin();
it != os->sparse->end(); it = it->nextNode()) {
- v = otherObj->getValue(os->arrayData[it->value], other->d()->attrs[it->value]);
+ v = otherObj->getValue(os->values[it->value], other->d()->attrs[it->value]);
obj->arraySet(oldSize + it->key(), v);
}
} else {
for (const SparseArrayNode *it = other->d()->sparse->begin();
it != os->sparse->end(); it = it->nextNode())
- obj->arraySet(oldSize + it->key(), os->arrayData[it->value]);
+ obj->arraySet(oldSize + it->key(), os->values[it->value]);
}
} else {
Heap::SimpleArrayData *os = static_cast<Heap::SimpleArrayData *>(other->d());
uint toCopy = n;
uint chunk = toCopy;
- if (chunk > os->alloc - os->offset)
- chunk -= os->alloc - os->offset;
- obj->arrayPut(oldSize, os->arrayData + os->offset, chunk);
+ if (chunk > os->values.alloc - os->offset)
+ chunk -= os->values.alloc - os->offset;
+ obj->arrayPut(oldSize, os->values.data() + os->offset, chunk);
toCopy -= chunk;
if (toCopy)
- obj->arrayPut(oldSize + chunk, os->arrayData, toCopy);
+ obj->arrayPut(oldSize + chunk, os->values.data(), toCopy);
}
return oldSize + n;
@@ -640,18 +621,18 @@ void ArrayData::insert(Object *o, uint index, const Value *v, bool isAccessor)
{
if (!isAccessor && o->d()->arrayData->type != Heap::ArrayData::Sparse) {
Heap::SimpleArrayData *d = o->d()->arrayData.cast<Heap::SimpleArrayData>();
- if (index < 0x1000 || index < d->len + (d->len >> 2)) {
- if (index >= d->alloc) {
+ if (index < 0x1000 || index < d->values.size + (d->values.size >> 2)) {
+ if (index >= d->values.alloc) {
o->arrayReserve(index + 1);
d = o->d()->arrayData.cast<Heap::SimpleArrayData>();
}
- if (index >= d->len) {
+ if (index >= d->values.size) {
// mark possible hole in the array
- for (uint i = d->len; i < index; ++i)
- d->data(i) = Primitive::emptyValue();
- d->len = index + 1;
+ for (uint i = d->values.size; i < index; ++i)
+ d->setData(o->engine(), i, Primitive::emptyValue());
+ d->values.size = index + 1;
}
- d->arrayData[d->mappedIndex(index)] = *v;
+ d->setData(o->engine(), index, *v);
return;
}
}
@@ -662,9 +643,9 @@ void ArrayData::insert(Object *o, uint index, const Value *v, bool isAccessor)
if (n->value == UINT_MAX)
n->value = SparseArrayData::allocate(o, isAccessor);
s = o->d()->arrayData.cast<Heap::SparseArrayData>();
- s->arrayData[n->value] = *v;
+ s->setArrayData(o->engine(), n->value, *v);
if (isAccessor)
- s->arrayData[n->value + Object::SetterOffset] = v[Object::SetterOffset];
+ s->setArrayData(o->engine(), n->value + Object::SetterOffset, v[Object::SetterOffset]);
}
@@ -801,7 +782,7 @@ void ArrayData::sort(ExecutionEngine *engine, Object *thisObject, const Value &c
break;
PropertyAttributes a = sparse->attrs() ? sparse->attrs()[n->value] : Attr_Data;
- d->data(i) = thisObject->getValue(sparse->arrayData()[n->value], a);
+ d->setData(engine, i, Value::fromReturnedValue(thisObject->getValue(sparse->arrayData()[n->value], a)));
d->attrs[i] = a.isAccessor() ? Attr_Data : a;
n = n->nextNode();
@@ -811,12 +792,12 @@ void ArrayData::sort(ExecutionEngine *engine, Object *thisObject, const Value &c
while (n != sparse->sparse()->end()) {
if (n->value >= len)
break;
- d->data(i) = sparse->arrayData()[n->value];
+ d->setData(engine, i, sparse->arrayData()[n->value]);
n = n->nextNode();
++i;
}
}
- d->len = i;
+ d->values.size = i;
if (len > i)
len = i;
if (n != sparse->sparse()->end()) {
@@ -824,7 +805,7 @@ void ArrayData::sort(ExecutionEngine *engine, Object *thisObject, const Value &c
thisObject->initSparseArray();
while (n != sparse->sparse()->end()) {
PropertyAttributes a = sparse->attrs() ? sparse->attrs()[n->value] : Attr_Data;
- thisObject->arraySet(n->value, reinterpret_cast<Property *>(sparse->arrayData() + n->value), a);
+ thisObject->arraySet(n->value, reinterpret_cast<const Property *>(sparse->arrayData() + n->value), a);
n = n->nextNode();
}
@@ -832,8 +813,8 @@ void ArrayData::sort(ExecutionEngine *engine, Object *thisObject, const Value &c
}
} else {
Heap::SimpleArrayData *d = thisObject->d()->arrayData.cast<Heap::SimpleArrayData>();
- if (len > d->len)
- len = d->len;
+ if (len > d->values.size)
+ len = d->values.size;
// sort empty values to the end
for (uint i = 0; i < len; i++) {
@@ -842,8 +823,8 @@ void ArrayData::sort(ExecutionEngine *engine, Object *thisObject, const Value &c
if (!d->data(len).isEmpty())
break;
Q_ASSERT(!d->attrs || !d->attrs[len].isAccessor());
- d->data(i) = d->data(len);
- d->data(len) = Primitive::emptyValue();
+ d->setData(engine, i, d->data(len));
+ d->setData(engine, len, Primitive::emptyValue());
}
}
@@ -854,7 +835,7 @@ void ArrayData::sort(ExecutionEngine *engine, Object *thisObject, const Value &c
ArrayElementLessThan lessThan(engine, thisObject, comparefn);
- Value *begin = thisObject->arrayData()->arrayData;
+ Value *begin = thisObject->arrayData()->values.values;
sortHelper(begin, begin + len, *begin, lessThan);
#ifdef CHECK_SPARSE_ARRAYS
diff --git a/src/qml/jsruntime/qv4arraydata_p.h b/src/qml/jsruntime/qv4arraydata_p.h
index daf8c36814..e1de2e82e6 100644
--- a/src/qml/jsruntime/qv4arraydata_p.h
+++ b/src/qml/jsruntime/qv4arraydata_p.h
@@ -90,27 +90,31 @@ struct ArrayVTable
namespace Heap {
-struct ArrayData : public Base {
- enum Type {
- Simple = 0,
- Complex = 1,
- Sparse = 2,
- Custom = 3
+#define ArrayDataMembers(class, Member) \
+ Member(class, NoMark, uint, type) \
+ Member(class, NoMark, uint, offset) \
+ Member(class, NoMark, PropertyAttributes *, attrs) \
+ Member(class, NoMark, ReturnedValue, freeList) \
+ Member(class, NoMark, SparseArray *, sparse) \
+ Member(class, ValueArray, ValueArray, values)
+
+DECLARE_HEAP_OBJECT(ArrayData, Base) {
+ DECLARE_MARK_TABLE(ArrayData);
+
+ enum Type { Simple = 0, Complex = 1, Sparse = 2, Custom = 3 };
+
+ struct Index {
+ Heap::ArrayData *arrayData;
+ uint index;
+
+ void set(EngineBase *e, Value newVal) {
+ arrayData->values.set(e, index, newVal);
+ }
+ const Value *operator->() const { return &arrayData->values[index]; }
+ const Value &operator*() const { return arrayData->values[index]; }
+ bool isNull() const { return !arrayData; }
};
- uint alloc;
- Type type;
- PropertyAttributes *attrs;
- union {
- uint len;
- ReturnedValue freeList;
- };
- union {
- uint offset;
- SparseArray *sparse;
- };
- Value arrayData[1];
-
bool isSparse() const { return type == Sparse; }
const ArrayVTable *vtable() const { return reinterpret_cast<const ArrayVTable *>(Base::vtable()); }
@@ -118,35 +122,32 @@ struct ArrayData : public Base {
inline ReturnedValue get(uint i) const {
return vtable()->get(this, i);
}
- inline void getProperty(uint index, Property *p, PropertyAttributes *attrs);
- inline void setProperty(uint index, const Property *p);
- inline Property *getProperty(uint index);
- inline Value *getValueOrSetter(uint index, PropertyAttributes *attrs);
+ inline bool getProperty(uint index, Property *p, PropertyAttributes *attrs);
+ inline void setProperty(EngineBase *e, uint index, const Property *p);
+ inline Index getValueOrSetter(uint index, PropertyAttributes *attrs);
inline PropertyAttributes attributes(uint i) const;
bool isEmpty(uint i) const {
return get(i) == Primitive::emptyValue().asReturnedValue();
}
- inline ReturnedValue length() const {
+ inline uint length() const {
return vtable()->length(this);
}
+ void setArrayData(EngineBase *e, uint index, Value newVal) {
+ values.set(e, index, newVal);
+ }
+
+ uint mappedIndex(uint index) const;
};
V4_ASSERT_IS_TRIVIAL(ArrayData)
struct SimpleArrayData : public ArrayData {
- uint mappedIndex(uint index) const { return (index + offset) % alloc; }
- Value data(uint index) const { return arrayData[mappedIndex(index)]; }
- Value &data(uint index) { return arrayData[mappedIndex(index)]; }
-
- Property *getProperty(uint index) {
- if (index >= len)
- return 0;
- index = mappedIndex(index);
- if (arrayData[index].isEmpty())
- return 0;
- return reinterpret_cast<Property *>(arrayData + index);
+ uint mappedIndex(uint index) const { return (index + offset) % values.alloc; }
+ const Value &data(uint index) const { return values[mappedIndex(index)]; }
+ void setData(EngineBase *e, uint index, Value newVal) {
+ values.set(e, mappedIndex(index), newVal);
}
PropertyAttributes attributes(uint i) const {
@@ -168,13 +169,6 @@ struct SparseArrayData : public ArrayData {
return n->value;
}
- Property *getProperty(uint index) {
- SparseArrayNode *n = sparse->findNode(index);
- if (!n)
- return 0;
- return reinterpret_cast<Property *>(arrayData + n->value);
- }
-
PropertyAttributes attributes(uint i) const {
if (!attrs)
return Attr_Data;
@@ -189,16 +183,23 @@ struct Q_QML_EXPORT ArrayData : public Managed
{
typedef Heap::ArrayData::Type Type;
V4_MANAGED(ArrayData, Managed)
+ enum {
+ IsArrayData = true
+ };
- uint alloc() const { return d()->alloc; }
- uint &alloc() { return d()->alloc; }
- void setAlloc(uint a) { d()->alloc = a; }
- Type type() const { return d()->type; }
+ typedef Heap::ArrayData::Index Index;
+
+ uint alloc() const { return d()->values.alloc; }
+ uint &alloc() { return d()->values.alloc; }
+ void setAlloc(uint a) { d()->values.alloc = a; }
+ Type type() const { return static_cast<Type>(d()->type); }
void setType(Type t) { d()->type = t; }
PropertyAttributes *attrs() const { return d()->attrs; }
void setAttrs(PropertyAttributes *a) { d()->attrs = a; }
- const Value *arrayData() const { return &d()->arrayData[0]; }
- Value *arrayData() { return &d()->arrayData[0]; }
+ const Value *arrayData() const { return d()->values.data(); }
+ void setArrayData(EngineBase *e, uint index, Value newVal) {
+ d()->setArrayData(e, index, newVal);
+ }
const ArrayVTable *vtable() const { return d()->vtable(); }
bool isSparse() const { return type() == Heap::ArrayData::Sparse; }
@@ -221,9 +222,6 @@ struct Q_QML_EXPORT ArrayData : public Managed
ReturnedValue get(uint i) const {
return d()->get(i);
}
- inline Property *getProperty(uint index) {
- return d()->getProperty(index);
- }
static void ensureAttributes(Object *o);
static void realloc(Object *o, Type newType, uint alloc, bool enforceAttributes);
@@ -240,15 +238,12 @@ struct Q_QML_EXPORT SimpleArrayData : public ArrayData
uint mappedIndex(uint index) const { return d()->mappedIndex(index); }
Value data(uint index) const { return d()->data(index); }
- Value &data(uint index) { return d()->data(index); }
- uint &len() { return d()->len; }
- uint len() const { return d()->len; }
+ uint &len() { return d()->values.size; }
+ uint len() const { return d()->values.size; }
static Heap::ArrayData *reallocate(Object *o, uint n, bool enforceAttributes);
- static void markObjects(Heap::Base *d, ExecutionEngine *e);
-
static ReturnedValue get(const Heap::ArrayData *d, uint index);
static bool put(Object *o, uint index, const Value &value);
static bool putArray(Object *o, uint index, const Value *values, uint n);
@@ -276,8 +271,6 @@ struct Q_QML_EXPORT SparseArrayData : public ArrayData
uint mappedIndex(uint index) const { return d()->mappedIndex(index); }
- static void markObjects(Heap::Base *d, ExecutionEngine *e);
-
static Heap::ArrayData *reallocate(Object *o, uint n, bool enforceAttributes);
static ReturnedValue get(const Heap::ArrayData *d, uint index);
static bool put(Object *o, uint index, const Value &value);
@@ -292,30 +285,38 @@ struct Q_QML_EXPORT SparseArrayData : public ArrayData
namespace Heap {
-void ArrayData::getProperty(uint index, Property *p, PropertyAttributes *attrs)
+inline uint ArrayData::mappedIndex(uint index) const
{
- Property *pd = getProperty(index);
- Q_ASSERT(pd);
- *attrs = attributes(index);
- p->value = pd->value;
- if (attrs->isAccessor())
- p->set = pd->set;
+ if (isSparse())
+ return static_cast<const SparseArrayData *>(this)->mappedIndex(index);
+ if (index >= values.size)
+ return UINT_MAX;
+ uint idx = static_cast<const SimpleArrayData *>(this)->mappedIndex(index);
+ return values[idx].isEmpty() ? UINT_MAX : idx;
}
-void ArrayData::setProperty(uint index, const Property *p)
+bool ArrayData::getProperty(uint index, Property *p, PropertyAttributes *attrs)
{
- Property *pd = getProperty(index);
- Q_ASSERT(pd);
- pd->value = p->value;
- if (attributes(index).isAccessor())
- pd->set = p->set;
+ uint mapped = mappedIndex(index);
+ if (mapped == UINT_MAX) {
+ *attrs = Attr_Invalid;
+ return false;
+ }
+
+ *attrs = attributes(index);
+ p->value = *(Index{ this, mapped });
+ if (attrs->isAccessor())
+ p->set = *(Index{ this, mapped + 1 /*Object::SetterOffset*/ });
+ return true;
}
-inline Property *ArrayData::getProperty(uint index)
+void ArrayData::setProperty(QV4::EngineBase *e, uint index, const Property *p)
{
- if (isSparse())
- return static_cast<SparseArrayData *>(this)->getProperty(index);
- return static_cast<SimpleArrayData *>(this)->getProperty(index);
+ uint mapped = mappedIndex(index);
+ Q_ASSERT(mapped != UINT_MAX);
+ values.set(e, mapped, p->value);
+ if (attributes(index).isAccessor())
+ values.set(e, mapped + 1 /*QV4::Object::SetterOffset*/, p->set);
}
inline PropertyAttributes ArrayData::attributes(uint i) const
@@ -325,16 +326,16 @@ inline PropertyAttributes ArrayData::attributes(uint i) const
return static_cast<const SimpleArrayData *>(this)->attributes(i);
}
-Value *ArrayData::getValueOrSetter(uint index, PropertyAttributes *attrs)
+ArrayData::Index ArrayData::getValueOrSetter(uint index, PropertyAttributes *attrs)
{
- Property *p = getProperty(index);
- if (!p) {
+ uint idx = mappedIndex(index);
+ if (idx == UINT_MAX) {
*attrs = Attr_Invalid;
- return 0;
+ return { 0, 0 };
}
*attrs = attributes(index);
- return attrs->isAccessor() ? &p->set : &p->value;
+ return { this, attrs->isAccessor() ? idx + 1 /* QV4::Object::SetterOffset*/ : idx };
}
diff --git a/src/qml/jsruntime/qv4arrayobject.cpp b/src/qml/jsruntime/qv4arrayobject.cpp
index 759354f4e2..a2c19e1f2d 100644
--- a/src/qml/jsruntime/qv4arrayobject.cpp
+++ b/src/qml/jsruntime/qv4arrayobject.cpp
@@ -690,8 +690,8 @@ void ArrayPrototype::method_indexOf(const BuiltinFunction *, Scope &scope, CallD
} else {
Q_ASSERT(instance->arrayType() == Heap::ArrayData::Simple || instance->arrayType() == Heap::ArrayData::Complex);
Heap::SimpleArrayData *sa = instance->d()->arrayData.cast<Heap::SimpleArrayData>();
- if (len > sa->len)
- len = sa->len;
+ if (len > sa->values.size)
+ len = sa->values.size;
uint idx = fromIndex;
while (idx < len) {
value = sa->data(idx);
diff --git a/src/qml/jsruntime/qv4context.cpp b/src/qml/jsruntime/qv4context.cpp
index 3ff864d7b9..6807c835b0 100644
--- a/src/qml/jsruntime/qv4context.cpp
+++ b/src/qml/jsruntime/qv4context.cpp
@@ -54,41 +54,44 @@
using namespace QV4;
DEFINE_MANAGED_VTABLE(ExecutionContext);
+DEFINE_MANAGED_VTABLE(SimpleCallContext);
DEFINE_MANAGED_VTABLE(CallContext);
DEFINE_MANAGED_VTABLE(WithContext);
DEFINE_MANAGED_VTABLE(CatchContext);
DEFINE_MANAGED_VTABLE(GlobalContext);
-/* Function *f, int argc */
-#define requiredMemoryForExecutionContect(f, argc) \
- ((sizeof(CallContext::Data) + 7) & ~7) + \
- sizeof(Value) * (f->compiledFunction->nLocals + qMax((uint)argc, f->nFormals)) + sizeof(CallData)
-
Heap::CallContext *ExecutionContext::newCallContext(Function *function, CallData *callData)
{
- Heap::CallContext *c = engine()->memoryManager->allocManaged<CallContext>(
- requiredMemoryForExecutionContect(function, callData->argc));
+ uint localsAndFormals = function->compiledFunction->nLocals + sizeof(CallData)/sizeof(Value) - 1 + qMax(static_cast<uint>(callData->argc), function->nFormals);
+ size_t requiredMemory = sizeof(CallContext::Data) - sizeof(Value) + sizeof(Value) * (localsAndFormals);
+
+ ExecutionEngine *v4 = engine();
+ Heap::CallContext *c = v4->memoryManager->allocManaged<CallContext>(requiredMemory);
c->init(Heap::ExecutionContext::Type_CallContext);
c->v4Function = function;
c->strictMode = function->isStrict();
- c->outer = this->d();
-
- c->activation = 0;
+ c->outer.set(v4, this->d());
c->compilationUnit = function->compilationUnit;
c->lookups = function->compilationUnit->runtimeLookups;
c->constantTable = function->compilationUnit->constants;
- c->locals = (Value *)((quintptr(c + 1) + 7) & ~7);
const CompiledData::Function *compiledFunction = function->compiledFunction;
- int nLocals = compiledFunction->nLocals;
+ uint nLocals = compiledFunction->nLocals;
+ c->locals.size = nLocals;
+ c->locals.alloc = localsAndFormals;
+#if QT_POINTER_SIZE == 8
+ // memory allocated from the JS heap is 0 initialized, so skip the std::fill() below
+ Q_ASSERT(Primitive::undefinedValue().asReturnedValue() == 0);
+#else
if (nLocals)
- std::fill(c->locals, c->locals + nLocals, Primitive::undefinedValue());
+ std::fill(c->locals.values, c->locals.values + nLocals, Primitive::undefinedValue());
+#endif
- c->callData = reinterpret_cast<CallData *>(c->locals + nLocals);
- ::memcpy(c->callData, callData, sizeof(CallData) + (callData->argc - 1) * sizeof(Value));
+ c->callData = reinterpret_cast<CallData *>(c->locals.values + nLocals);
+ ::memcpy(c->callData, callData, sizeof(CallData) - sizeof(Value) + static_cast<uint>(callData->argc) * sizeof(Value));
if (callData->argc < static_cast<int>(compiledFunction->nFormals))
std::fill(c->callData->args + c->callData->argc, c->callData->args + compiledFunction->nFormals, Primitive::undefinedValue());
@@ -118,10 +121,10 @@ void ExecutionContext::createMutableBinding(String *name, bool deletable)
switch (ctx->d()->type) {
case Heap::ExecutionContext::Type_CallContext:
case Heap::ExecutionContext::Type_SimpleCallContext: {
- Heap::CallContext *c = static_cast<Heap::CallContext *>(ctx->d());
+ Heap::SimpleCallContext *c = static_cast<Heap::SimpleCallContext *>(ctx->d());
if (!activation) {
if (!c->activation)
- c->activation = scope.engine->newObject();
+ c->activation.set(scope.engine, scope.engine->newObject());
activation = c->activation;
}
break;
@@ -144,7 +147,7 @@ void ExecutionContext::createMutableBinding(String *name, bool deletable)
ctx = ctx->d()->outer;
}
- if (activation->hasProperty(name))
+ if (activation->hasOwnProperty(name))
return;
ScopedProperty desc(scope);
PropertyAttributes attrs(Attr_Data);
@@ -155,41 +158,52 @@ void ExecutionContext::createMutableBinding(String *name, bool deletable)
void Heap::GlobalContext::init(ExecutionEngine *eng)
{
Heap::ExecutionContext::init(Heap::ExecutionContext::Type_GlobalContext);
- global = eng->globalObject->d();
+ global.set(eng, eng->globalObject->d());
}
void Heap::CatchContext::init(ExecutionContext *outerContext, String *exceptionVarName,
const Value &exceptionValue)
{
Heap::ExecutionContext::init(Heap::ExecutionContext::Type_CatchContext);
- outer = outerContext;
+ outer.set(internalClass->engine, outerContext);
strictMode = outer->strictMode;
callData = outer->callData;
lookups = outer->lookups;
constantTable = outer->constantTable;
compilationUnit = outer->compilationUnit;
- this->exceptionVarName = exceptionVarName;
- this->exceptionValue = exceptionValue;
+ this->exceptionVarName.set(internalClass->engine, exceptionVarName);
+ this->exceptionValue.set(internalClass->engine, exceptionValue);
}
+void Heap::WithContext::init(ExecutionContext *outerContext, Object *with)
+{
+ Heap::ExecutionContext::init(Heap::ExecutionContext::Type_WithContext);
+ outer.set(internalClass->engine, outerContext);
+ callData = outer->callData;
+ lookups = outer->lookups;
+ constantTable = outer->constantTable;
+ compilationUnit = outer->compilationUnit;
-Identifier * const *CallContext::formals() const
+ withObject.set(internalClass->engine, with);
+}
+
+Identifier * const *SimpleCallContext::formals() const
{
return d()->v4Function ? d()->v4Function->internalClass->nameMap.constData() : 0;
}
-unsigned int CallContext::formalCount() const
+unsigned int SimpleCallContext::formalCount() const
{
return d()->v4Function ? d()->v4Function->nFormals : 0;
}
-Identifier * const *CallContext::variables() const
+Identifier * const *SimpleCallContext::variables() const
{
return d()->v4Function ? d()->v4Function->internalClass->nameMap.constData() + d()->v4Function->nFormals : 0;
}
-unsigned int CallContext::variableCount() const
+unsigned int SimpleCallContext::variableCount() const
{
return d()->v4Function ? d()->v4Function->compiledFunction->nLocals : 0;
}
@@ -202,7 +216,6 @@ bool ExecutionContext::deleteProperty(String *name)
Identifier *id = name->identifier();
Scope scope(this);
- bool hasWith = false;
ScopedContext ctx(scope, this);
for (; ctx; ctx = ctx->d()->outer) {
switch (ctx->d()->type) {
@@ -213,7 +226,6 @@ bool ExecutionContext::deleteProperty(String *name)
break;
}
case Heap::ExecutionContext::Type_WithContext: {
- hasWith = true;
ScopedObject withObject(scope, static_cast<Heap::WithContext *>(ctx->d())->withObject);
if (withObject->hasProperty(name))
return withObject->deleteProperty(name);
@@ -226,14 +238,13 @@ bool ExecutionContext::deleteProperty(String *name)
break;
}
case Heap::ExecutionContext::Type_CallContext:
+ Q_FALLTHROUGH();
case Heap::ExecutionContext::Type_SimpleCallContext: {
- Heap::CallContext *c = static_cast<Heap::CallContext *>(ctx->d());
- if (c->v4Function && (c->v4Function->needsActivation() || hasWith)) {
- uint index = c->v4Function->internalClass->find(id);
- if (index < UINT_MAX)
- // ### throw in strict mode?
- return false;
- }
+ Heap::SimpleCallContext *c = static_cast<Heap::SimpleCallContext *>(ctx->d());
+ uint index = c->v4Function->internalClass->find(id);
+ if (index < UINT_MAX)
+ // ### throw in strict mode?
+ return false;
ScopedObject qml(scope, c->activation);
if (qml && qml->hasProperty(name))
return qml->deleteProperty(name);
@@ -250,61 +261,6 @@ bool ExecutionContext::deleteProperty(String *name)
return true;
}
-bool CallContext::needsOwnArguments() const
-{
- QV4::Function *f = d()->v4Function;
- return (f && f->needsActivation()) || (argc() < (f ? static_cast<int>(f->nFormals) : 0));
-}
-
-void ExecutionContext::markObjects(Heap::Base *m, ExecutionEngine *engine)
-{
- ExecutionContext::Data *ctx = static_cast<ExecutionContext::Data *>(m);
-
- if (ctx->outer)
- ctx->outer->mark(engine);
-
- switch (ctx->type) {
- case Heap::ExecutionContext::Type_CatchContext: {
- CatchContext::Data *c = static_cast<CatchContext::Data *>(ctx);
- c->exceptionVarName->mark(engine);
- c->exceptionValue.mark(engine);
- break;
- }
- case Heap::ExecutionContext::Type_WithContext: {
- WithContext::Data *w = static_cast<WithContext::Data *>(ctx);
- if (w->withObject)
- w->withObject->mark(engine);
- break;
- }
- case Heap::ExecutionContext::Type_GlobalContext: {
- GlobalContext::Data *g = static_cast<GlobalContext::Data *>(ctx);
- g->global->mark(engine);
- break;
- }
- case Heap::ExecutionContext::Type_SimpleCallContext:
- break;
- case Heap::ExecutionContext::Type_CallContext: {
- QV4::Heap::CallContext *c = static_cast<Heap::CallContext *>(ctx);
- Q_ASSERT(c->v4Function);
- ctx->callData->thisObject.mark(engine);
- for (int arg = 0; arg < qMax(ctx->callData->argc, (int)c->v4Function->nFormals); ++arg)
- ctx->callData->args[arg].mark(engine);
- for (unsigned local = 0, lastLocal = c->v4Function->compiledFunction->nLocals; local < lastLocal; ++local)
- c->locals[local].mark(engine);
- if (c->activation)
- c->activation->mark(engine);
- if (c->function)
- c->function->mark(engine);
- break;
- }
- case Heap::ExecutionContext::Type_QmlContext: {
- QmlContext::Data *g = static_cast<QmlContext::Data *>(ctx);
- g->qml->mark(engine);
- break;
- }
- }
-}
-
// Do a standard call with this execution context as the outer scope
void ExecutionContext::call(Scope &scope, CallData *callData, Function *function, const FunctionObject *f)
{
@@ -312,7 +268,7 @@ void ExecutionContext::call(Scope &scope, CallData *callData, Function *function
Scoped<CallContext> ctx(scope, newCallContext(function, callData));
if (f)
- ctx->d()->function = f->d();
+ ctx->d()->function.set(scope.engine, f->d());
scope.engine->pushContext(ctx);
scope.result = Q_V4_PROFILE(scope.engine, function);
@@ -328,7 +284,7 @@ void QV4::ExecutionContext::simpleCall(Scope &scope, CallData *callData, Functio
ExecutionContextSaver ctxSaver(scope);
- CallContext::Data *ctx = scope.engine->memoryManager->allocSimpleCallContext();
+ SimpleCallContext::Data *ctx = scope.engine->memoryManager->allocSimpleCallContext();
ctx->strictMode = function->isStrict();
ctx->callData = callData;
@@ -336,8 +292,7 @@ void QV4::ExecutionContext::simpleCall(Scope &scope, CallData *callData, Functio
ctx->compilationUnit = function->compilationUnit;
ctx->lookups = function->compilationUnit->runtimeLookups;
ctx->constantTable = function->compilationUnit->constants;
- ctx->outer = this->d();
- ctx->locals = scope.alloc(function->compiledFunction->nLocals);
+ ctx->outer.set(scope.engine, this->d());
for (int i = callData->argc; i < (int)function->nFormals; ++i)
callData->args[i] = Encode::undefined();
@@ -366,7 +321,7 @@ void ExecutionContext::setProperty(String *name, const Value &value)
case Heap::ExecutionContext::Type_CatchContext: {
Heap::CatchContext *c = static_cast<Heap::CatchContext *>(ctx->d());
if (c->exceptionVarName->isEqualTo(name->d())) {
- c->exceptionValue = value;
+ c->exceptionValue.set(scope.engine, value);
return;
}
break;
@@ -385,15 +340,16 @@ void ExecutionContext::setProperty(String *name, const Value &value)
}
case Heap::ExecutionContext::Type_CallContext:
case Heap::ExecutionContext::Type_SimpleCallContext: {
- Heap::CallContext *c = static_cast<Heap::CallContext *>(ctx->d());
+ Heap::SimpleCallContext *c = static_cast<Heap::SimpleCallContext *>(ctx->d());
if (c->v4Function) {
uint index = c->v4Function->internalClass->find(id);
if (index < UINT_MAX) {
if (index < c->v4Function->nFormals) {
c->callData->args[c->v4Function->nFormals - index - 1] = value;
} else {
+ Q_ASSERT(c->type == Heap::ExecutionContext::Type_CallContext);
index -= c->v4Function->nFormals;
- c->locals[index] = value;
+ static_cast<Heap::CallContext *>(c)->locals.set(scope.engine, index, value);
}
return;
}
@@ -434,13 +390,10 @@ ReturnedValue ExecutionContext::getProperty(String *name)
if (name->equals(engine()->id_this()))
return thisObject().asReturnedValue();
- bool hasWith = false;
- bool hasCatchScope = false;
ScopedContext ctx(scope, this);
for (; ctx; ctx = ctx->d()->outer) {
switch (ctx->d()->type) {
case Heap::ExecutionContext::Type_CatchContext: {
- hasCatchScope = true;
Heap::CatchContext *c = static_cast<Heap::CatchContext *>(ctx->d());
if (c->exceptionVarName->isEqualTo(name->d()))
return c->exceptionValue.asReturnedValue();
@@ -448,7 +401,6 @@ ReturnedValue ExecutionContext::getProperty(String *name)
}
case Heap::ExecutionContext::Type_WithContext: {
ScopedObject w(scope, static_cast<Heap::WithContext *>(ctx->d())->withObject);
- hasWith = true;
bool hasProperty = false;
v = w->get(name, &hasProperty);
if (hasProperty) {
@@ -465,19 +417,20 @@ ReturnedValue ExecutionContext::getProperty(String *name)
break;
}
case Heap::ExecutionContext::Type_CallContext:
+ Q_FALLTHROUGH();
case Heap::ExecutionContext::Type_SimpleCallContext: {
- Heap::CallContext *c = static_cast<Heap::CallContext *>(ctx->d());
- if (c->v4Function && (c->v4Function->needsActivation() || hasWith || hasCatchScope)) {
- name->makeIdentifier();
- Identifier *id = name->identifier();
-
- uint index = c->v4Function->internalClass->find(id);
- if (index < UINT_MAX) {
- if (index < c->v4Function->nFormals)
- return c->callData->args[c->v4Function->nFormals - index - 1].asReturnedValue();
- return c->locals[index - c->v4Function->nFormals].asReturnedValue();
- }
+ Heap::SimpleCallContext *c = static_cast<Heap::SimpleCallContext *>(ctx->d());
+
+ name->makeIdentifier();
+ Identifier *id = name->identifier();
+ uint index = c->v4Function->internalClass->find(id);
+ if (index < UINT_MAX) {
+ if (index < c->v4Function->nFormals)
+ return c->callData->args[c->v4Function->nFormals - index - 1].asReturnedValue();
+ if (c->type == Heap::ExecutionContext::Type_CallContext)
+ return static_cast<Heap::CallContext *>(c)->locals[index - c->v4Function->nFormals].asReturnedValue();
}
+
ScopedObject activation(scope, c->activation);
if (activation) {
bool hasProperty = false;
@@ -485,9 +438,12 @@ ReturnedValue ExecutionContext::getProperty(String *name)
if (hasProperty)
return v->asReturnedValue();
}
- if (c->function && c->v4Function->isNamedExpression()
- && name->equals(ScopedString(scope, c->v4Function->name())))
- return c->function->asReturnedValue();
+
+ if (c->v4Function->isNamedExpression() && c->type == Heap::ExecutionContext::Type_CallContext) {
+ if (name->equals(ScopedString(scope, c->v4Function->name())))
+ if (auto func = static_cast<Heap::CallContext *>(c)->function)
+ return func->asReturnedValue();
+ }
break;
}
case Heap::ExecutionContext::Type_QmlContext: {
@@ -514,13 +470,10 @@ ReturnedValue ExecutionContext::getPropertyAndBase(String *name, Value *base)
if (name->equals(engine()->id_this()))
return thisObject().asReturnedValue();
- bool hasWith = false;
- bool hasCatchScope = false;
ScopedContext ctx(scope, this);
for (; ctx; ctx = ctx->d()->outer) {
switch (ctx->d()->type) {
case Heap::ExecutionContext::Type_CatchContext: {
- hasCatchScope = true;
Heap::CatchContext *c = static_cast<Heap::CatchContext *>(ctx->d());
if (c->exceptionVarName->isEqualTo(name->d()))
return c->exceptionValue.asReturnedValue();
@@ -528,7 +481,6 @@ ReturnedValue ExecutionContext::getPropertyAndBase(String *name, Value *base)
}
case Heap::ExecutionContext::Type_WithContext: {
ScopedObject w(scope, static_cast<Heap::WithContext *>(ctx->d())->withObject);
- hasWith = true;
bool hasProperty = false;
v = w->get(name, &hasProperty);
if (hasProperty) {
@@ -546,19 +498,20 @@ ReturnedValue ExecutionContext::getPropertyAndBase(String *name, Value *base)
break;
}
case Heap::ExecutionContext::Type_CallContext:
+ Q_FALLTHROUGH();
case Heap::ExecutionContext::Type_SimpleCallContext: {
- Heap::CallContext *c = static_cast<Heap::CallContext *>(ctx->d());
- if (c->v4Function && (c->v4Function->needsActivation() || hasWith || hasCatchScope)) {
- name->makeIdentifier();
- Identifier *id = name->identifier();
-
- uint index = c->v4Function->internalClass->find(id);
- if (index < UINT_MAX) {
- if (index < c->v4Function->nFormals)
- return c->callData->args[c->v4Function->nFormals - index - 1].asReturnedValue();
- return c->locals[index - c->v4Function->nFormals].asReturnedValue();
- }
+ Heap::SimpleCallContext *c = static_cast<Heap::SimpleCallContext *>(ctx->d());
+
+ name->makeIdentifier();
+ Identifier *id = name->identifier();
+ uint index = c->v4Function->internalClass->find(id);
+ if (index < UINT_MAX) {
+ if (index < c->v4Function->nFormals)
+ return c->callData->args[c->v4Function->nFormals - index - 1].asReturnedValue();
+ if (c->type == Heap::ExecutionContext::Type_CallContext)
+ return static_cast<Heap::CallContext *>(c)->locals[index - c->v4Function->nFormals].asReturnedValue();
}
+
ScopedObject activation(scope, c->activation);
if (activation) {
bool hasProperty = false;
@@ -566,9 +519,12 @@ ReturnedValue ExecutionContext::getPropertyAndBase(String *name, Value *base)
if (hasProperty)
return v->asReturnedValue();
}
- if (c->function && c->v4Function->isNamedExpression()
- && name->equals(ScopedString(scope, c->v4Function->name())))
- return c->function->asReturnedValue();
+
+ if (c->v4Function->isNamedExpression() && c->type == Heap::ExecutionContext::Type_CallContext) {
+ if (name->equals(ScopedString(scope, c->v4Function->name())))
+ if (auto func = static_cast<Heap::CallContext *>(c)->function)
+ return func->asReturnedValue();
+ }
break;
}
case Heap::ExecutionContext::Type_QmlContext: {
@@ -592,7 +548,7 @@ Function *ExecutionContext::getFunction() const
Scope scope(engine());
ScopedContext it(scope, this->d());
for (; it; it = it->d()->outer) {
- if (const CallContext *callCtx = it->asCallContext())
+ if (const SimpleCallContext *callCtx = it->asSimpleCallContext())
return callCtx->d()->v4Function;
else if (it->asCatchContext() || it->asWithContext())
continue; // look in the parent context for a FunctionObject
diff --git a/src/qml/jsruntime/qv4context_p.h b/src/qml/jsruntime/qv4context_p.h
index 0b63922a4b..a854c324d0 100644
--- a/src/qml/jsruntime/qv4context_p.h
+++ b/src/qml/jsruntime/qv4context_p.h
@@ -68,10 +68,11 @@ struct Function;
struct Function;
struct Identifier;
struct CallContext;
+struct SimpleCallContext;
struct CatchContext;
struct WithContext;
struct QmlContext;
-struct QmlContextWrapper;
+struct QQmlContextWrapper;
// Attention: Make sure that this structure is the same size on 32-bit and 64-bit
// architecture or you'll have to change the JIT code.
@@ -101,34 +102,17 @@ namespace Heap {
struct QmlContext;
-// ### Temporary arrangment until this code hits the dev branch and
-// can use the Members macro
-struct ExecutionContextData {
- CallData *callData;
- ExecutionContext *outer;
- Lookup *lookups;
- const QV4::Value *constantTable;
- CompiledData::CompilationUnitBase *compilationUnit;
- // as member of non-pointer size this has to come last to preserve the ability to
- // translate offsetof of it between 64-bit and 32-bit.
- int lineNumber;
-#if QT_POINTER_SIZE == 8
- uint padding_;
-#endif
-};
-
-Q_STATIC_ASSERT(std::is_standard_layout<ExecutionContextData>::value);
-Q_STATIC_ASSERT(offsetof(ExecutionContextData, callData) == 0);
-Q_STATIC_ASSERT(offsetof(ExecutionContextData, outer) == offsetof(ExecutionContextData, callData) + QT_POINTER_SIZE);
-Q_STATIC_ASSERT(offsetof(ExecutionContextData, lookups) == offsetof(ExecutionContextData, outer) + QT_POINTER_SIZE);
-Q_STATIC_ASSERT(offsetof(ExecutionContextData, constantTable) == offsetof(ExecutionContextData, lookups) + QT_POINTER_SIZE);
-Q_STATIC_ASSERT(offsetof(ExecutionContextData, compilationUnit) == offsetof(ExecutionContextData, constantTable) + QT_POINTER_SIZE);
-Q_STATIC_ASSERT(offsetof(ExecutionContextData, lineNumber) == offsetof(ExecutionContextData, compilationUnit) + QT_POINTER_SIZE);
+#define ExecutionContextMembers(class, Member) \
+ Member(class, NoMark, CallData *, callData) \
+ Member(class, Pointer, ExecutionContext *, outer) \
+ Member(class, NoMark, Lookup *, lookups) \
+ Member(class, NoMark, const QV4::Value *, constantTable) \
+ Member(class, NoMark, CompiledData::CompilationUnitBase *, compilationUnit) \
+ Member(class, NoMark, int, lineNumber) // as member of non-pointer size this has to come last to preserve the ability to
+ // translate offsetof of it between 64-bit and 32-bit.
-struct ExecutionContextSizeStruct : public Base, public ExecutionContextData {};
-
-struct ExecutionContext : Base, public ExecutionContextData {
- static Q_CONSTEXPR size_t baseOffset = sizeof(ExecutionContextSizeStruct) - sizeof(ExecutionContextData);
+DECLARE_HEAP_OBJECT(ExecutionContext, Base) {
+ DECLARE_MARK_TABLE(ExecutionContext);
enum ContextType {
Type_GlobalContext = 0x1,
@@ -158,17 +142,20 @@ struct ExecutionContext : Base, public ExecutionContextData {
V4_ASSERT_IS_TRIVIAL(ExecutionContext)
Q_STATIC_ASSERT(sizeof(ExecutionContext) == sizeof(Base) + sizeof(ExecutionContextData) + QT_POINTER_SIZE);
-struct CallContextData {
- Value *locals;
-};
-
-Q_STATIC_ASSERT(std::is_standard_layout<CallContextData>::value);
-Q_STATIC_ASSERT(offsetof(CallContextData, locals) == 0);
+Q_STATIC_ASSERT(std::is_standard_layout<ExecutionContextData>::value);
+Q_STATIC_ASSERT(offsetof(ExecutionContextData, callData) == 0);
+Q_STATIC_ASSERT(offsetof(ExecutionContextData, outer) == offsetof(ExecutionContextData, callData) + QT_POINTER_SIZE);
+Q_STATIC_ASSERT(offsetof(ExecutionContextData, lookups) == offsetof(ExecutionContextData, outer) + QT_POINTER_SIZE);
+Q_STATIC_ASSERT(offsetof(ExecutionContextData, constantTable) == offsetof(ExecutionContextData, lookups) + QT_POINTER_SIZE);
+Q_STATIC_ASSERT(offsetof(ExecutionContextData, compilationUnit) == offsetof(ExecutionContextData, constantTable) + QT_POINTER_SIZE);
+Q_STATIC_ASSERT(offsetof(ExecutionContextData, lineNumber) == offsetof(ExecutionContextData, compilationUnit) + QT_POINTER_SIZE);
-struct CallContextSizeStruct : public ExecutionContext, public CallContextData {};
+#define SimpleCallContextMembers(class, Member) \
+ Member(class, Pointer, Object *, activation) \
+ Member(class, NoMark, QV4::Function *, v4Function)
-struct CallContext : ExecutionContext, public CallContextData {
- static Q_CONSTEXPR size_t baseOffset = sizeof(CallContextSizeStruct) - sizeof(CallContextData);
+DECLARE_HEAP_OBJECT(SimpleCallContext, ExecutionContext) {
+ DECLARE_MARK_TABLE(SimpleCallContext);
void init(ContextType t = Type_SimpleCallContext)
{
@@ -177,39 +164,66 @@ struct CallContext : ExecutionContext, public CallContextData {
inline unsigned int formalParameterCount() const;
- Pointer<FunctionObject> function;
- QV4::Function *v4Function;
- Pointer<Object> activation;
};
-V4_ASSERT_IS_TRIVIAL(CallContext)
+V4_ASSERT_IS_TRIVIAL(SimpleCallContext)
+Q_STATIC_ASSERT(std::is_standard_layout<SimpleCallContextData>::value);
+Q_STATIC_ASSERT(offsetof(SimpleCallContextData, activation) == 0);
+Q_STATIC_ASSERT(offsetof(SimpleCallContextData, v4Function) == offsetof(SimpleCallContextData, activation) + QT_POINTER_SIZE);
+Q_STATIC_ASSERT(sizeof(SimpleCallContextData) == 2 * QT_POINTER_SIZE);
+Q_STATIC_ASSERT(sizeof(SimpleCallContext) == sizeof(ExecutionContext) + sizeof(SimpleCallContextData));
+
+#if QT_POINTER_SIZE == 8
+#define CallContextMembers(class, Member) \
+ Member(class, Pointer, FunctionObject *, function) \
+ Member(class, ValueArray, ValueArray, locals)
+#else
+#define CallContextMembers(class, Member) \
+ Member(class, Pointer, FunctionObject *, function) \
+ Member(class, NoMark, void *, padding) \
+ Member(class, ValueArray, ValueArray, locals)
+#endif
+
+DECLARE_HEAP_OBJECT(CallContext, SimpleCallContext) {
+ DECLARE_MARK_TABLE(CallContext);
+
+ using SimpleCallContext::formalParameterCount;
+};
+
+Q_STATIC_ASSERT(std::is_standard_layout<CallContextData>::value);
+Q_STATIC_ASSERT(offsetof(CallContextData, function) == 0);
+// IMPORTANT: we cannot do offsetof(CallContextData, locals) in the JIT as the offset does not scale with
+// the pointer size. On 32-bit ARM the offset of the ValueArray is aligned to 8 bytes, on 32-bit x86 for
+// example it is not. Therefore we have a padding in place and always have a distance of 8 bytes.
+Q_STATIC_ASSERT(offsetof(CallContextData, locals) == offsetof(CallContextData, function) + 8);
+
+#define GlobalContextMembers(class, Member) \
+ Member(class, Pointer, Object *, global)
+
+DECLARE_HEAP_OBJECT(GlobalContext, ExecutionContext) {
+ DECLARE_MARK_TABLE(GlobalContext);
-struct GlobalContext : ExecutionContext {
void init(ExecutionEngine *engine);
- Pointer<Object> global;
};
V4_ASSERT_IS_TRIVIAL(GlobalContext)
-struct CatchContext : ExecutionContext {
+#define CatchContextMembers(class, Member) \
+ Member(class, Pointer, String *, exceptionVarName) \
+ Member(class, HeapValue, HeapValue, exceptionValue)
+
+DECLARE_HEAP_OBJECT(CatchContext, ExecutionContext) {
+ DECLARE_MARK_TABLE(CatchContext);
+
void init(ExecutionContext *outerContext, String *exceptionVarName, const Value &exceptionValue);
- Pointer<String> exceptionVarName;
- Value exceptionValue;
};
V4_ASSERT_IS_TRIVIAL(CatchContext)
-struct WithContext : ExecutionContext {
- void init(ExecutionContext *outerContext, Object *with)
- {
- Heap::ExecutionContext::init(Heap::ExecutionContext::Type_WithContext);
- outer = outerContext;
- callData = outer->callData;
- lookups = outer->lookups;
- constantTable = outer->constantTable;
- compilationUnit = outer->compilationUnit;
-
- withObject = with;
- }
+#define WithContextMembers(class, Member) \
+ Member(class, Pointer, Object *, withObject)
+
+DECLARE_HEAP_OBJECT(WithContext, ExecutionContext) {
+ DECLARE_MARK_TABLE(WithContext);
- Pointer<Object> withObject;
+ void init(ExecutionContext *outerContext, Object *with);
};
V4_ASSERT_IS_TRIVIAL(WithContext)
@@ -236,15 +250,13 @@ struct Q_QML_EXPORT ExecutionContext : public Managed
ReturnedValue getPropertyAndBase(String *name, Value *base);
bool deleteProperty(String *name);
- inline CallContext *asCallContext();
- inline const CallContext *asCallContext() const;
+ inline SimpleCallContext *asSimpleCallContext();
+ inline const SimpleCallContext *asSimpleCallContext() const;
inline const CatchContext *asCatchContext() const;
inline const WithContext *asWithContext() const;
Function *getFunction() const;
- static void markObjects(Heap::Base *m, ExecutionEngine *e);
-
Value &thisObject() const {
return d()->callData->thisObject;
}
@@ -262,10 +274,10 @@ struct Q_QML_EXPORT ExecutionContext : public Managed
void simpleCall(Scope &scope, CallData *callData, QV4::Function *function);
};
-struct Q_QML_EXPORT CallContext : public ExecutionContext
+struct Q_QML_EXPORT SimpleCallContext : public ExecutionContext
{
- V4_MANAGED(CallContext, ExecutionContext)
- V4_INTERNALCLASS(CallContext)
+ V4_MANAGED(SimpleCallContext, ExecutionContext)
+ V4_INTERNALCLASS(SimpleCallContext)
// formals are in reverse order
Identifier * const *formals() const;
@@ -274,14 +286,17 @@ struct Q_QML_EXPORT CallContext : public ExecutionContext
unsigned int variableCount() const;
inline ReturnedValue argument(int i) const;
- bool needsOwnArguments() const;
-
};
-inline ReturnedValue CallContext::argument(int i) const {
+inline ReturnedValue SimpleCallContext::argument(int i) const {
return i < argc() ? args()[i].asReturnedValue() : Primitive::undefinedValue().asReturnedValue();
}
+struct Q_QML_EXPORT CallContext : public SimpleCallContext
+{
+ V4_MANAGED(CallContext, SimpleCallContext)
+};
+
struct GlobalContext : public ExecutionContext
{
V4_MANAGED(GlobalContext, ExecutionContext)
@@ -298,14 +313,14 @@ struct WithContext : public ExecutionContext
V4_MANAGED(WithContext, ExecutionContext)
};
-inline CallContext *ExecutionContext::asCallContext()
+inline SimpleCallContext *ExecutionContext::asSimpleCallContext()
{
- return d()->type >= Heap::ExecutionContext::Type_SimpleCallContext ? static_cast<CallContext *>(this) : 0;
+ return d()->type >= Heap::ExecutionContext::Type_SimpleCallContext ? static_cast<SimpleCallContext *>(this) : 0;
}
-inline const CallContext *ExecutionContext::asCallContext() const
+inline const SimpleCallContext *ExecutionContext::asSimpleCallContext() const
{
- return d()->type >= Heap::ExecutionContext::Type_SimpleCallContext ? static_cast<const CallContext *>(this) : 0;
+ return d()->type >= Heap::ExecutionContext::Type_SimpleCallContext ? static_cast<const SimpleCallContext *>(this) : 0;
}
inline const CatchContext *ExecutionContext::asCatchContext() const
diff --git a/src/qml/jsruntime/qv4dataview.cpp b/src/qml/jsruntime/qv4dataview.cpp
index a810b38f24..f1405e08ee 100644
--- a/src/qml/jsruntime/qv4dataview.cpp
+++ b/src/qml/jsruntime/qv4dataview.cpp
@@ -73,7 +73,7 @@ void DataViewCtor::construct(const Managed *, Scope &scope, CallData *callData)
}
Scoped<DataView> a(scope, scope.engine->memoryManager->allocObject<DataView>());
- a->d()->buffer = buffer->d();
+ a->d()->buffer.set(scope.engine, buffer->d());
a->d()->byteLength = byteLength;
a->d()->byteOffset = byteOffset;
scope.result = a.asReturnedValue();
@@ -84,13 +84,6 @@ void DataViewCtor::call(const Managed *that, Scope &scope, CallData *callData)
construct(that, scope, callData);
}
-
-void DataView::markObjects(Heap::Base *that, ExecutionEngine *e)
-{
- DataView::Data *v = static_cast<DataView::Data *>(that);
- v->buffer->mark(e);
-}
-
void DataViewPrototype::init(ExecutionEngine *engine, Object *ctor)
{
Scope scope(engine);
diff --git a/src/qml/jsruntime/qv4dataview_p.h b/src/qml/jsruntime/qv4dataview_p.h
index 11cc0a6bd9..5c50df4655 100644
--- a/src/qml/jsruntime/qv4dataview_p.h
+++ b/src/qml/jsruntime/qv4dataview_p.h
@@ -63,11 +63,14 @@ struct DataViewCtor : FunctionObject {
void init(QV4::ExecutionContext *scope);
};
-struct DataView : Object {
+#define DataViewMembers(class, Member) \
+ Member(class, Pointer, ArrayBuffer *, buffer) \
+ Member(class, NoMark, uint, byteLength) \
+ Member(class, NoMark, uint, byteOffset)
+
+DECLARE_HEAP_OBJECT(DataView, Object) {
+ DECLARE_MARK_TABLE(DataView);
void init() { Object::init(); }
- Pointer<ArrayBuffer> buffer;
- uint byteLength;
- uint byteOffset;
};
}
@@ -84,8 +87,6 @@ struct DataView : Object
{
V4_OBJECT2(DataView, Object)
V4_PROTOTYPE(dataViewPrototype)
-
- static void markObjects(Heap::Base *that, ExecutionEngine *e);
};
struct DataViewPrototype: Object
diff --git a/src/qml/jsruntime/qv4dateobject.cpp b/src/qml/jsruntime/qv4dateobject.cpp
index b90c335b1c..c56d007028 100644
--- a/src/qml/jsruntime/qv4dateobject.cpp
+++ b/src/qml/jsruntime/qv4dateobject.cpp
@@ -340,7 +340,9 @@ static inline double TimeClip(double t)
{
if (! qt_is_finite(t) || fabs(t) > 8.64e15)
return qt_qnan();
- return Primitive::toInteger(t);
+
+ // +0 looks weird, but is correct. See ES6 20.3.1.15. We must not return -0.
+ return Primitive::toInteger(t) + 0;
}
static inline double ParseString(const QString &s)
@@ -724,7 +726,7 @@ void DatePrototype::init(ExecutionEngine *engine, Object *ctor)
Scope scope(engine);
ScopedObject o(scope);
ctor->defineReadonlyProperty(engine->id_prototype(), (o = this));
- ctor->defineReadonlyProperty(engine->id_length(), Primitive::fromInt32(7));
+ ctor->defineReadonlyConfigurableProperty(engine->id_length(), Primitive::fromInt32(7));
LocalTZA = getLocalTZA();
ctor->defineDefaultProperty(QStringLiteral("parse"), method_parse, 1);
@@ -774,8 +776,21 @@ void DatePrototype::init(ExecutionEngine *engine, Object *ctor)
defineDefaultProperty(QStringLiteral("setYear"), method_setYear, 1);
defineDefaultProperty(QStringLiteral("setFullYear"), method_setFullYear, 3);
defineDefaultProperty(QStringLiteral("setUTCFullYear"), method_setUTCFullYear, 3);
- defineDefaultProperty(QStringLiteral("toUTCString"), method_toUTCString, 0);
- defineDefaultProperty(QStringLiteral("toGMTString"), method_toUTCString, 0);
+
+ // ES6: B.2.4.3 & 20.3.4.43:
+ // We have to use the *same object* for toUTCString and toGMTString
+ {
+ QString toUtcString(QStringLiteral("toUTCString"));
+ QString toGmtString(QStringLiteral("toGMTString"));
+ ScopedString us(scope, engine->newIdentifier(toUtcString));
+ ScopedString gs(scope, engine->newIdentifier(toGmtString));
+ ExecutionContext *global = engine->rootContext();
+ ScopedFunctionObject toUtcGmtStringFn(scope, BuiltinFunction::create(global, us, method_toUTCString));
+ toUtcGmtStringFn->defineReadonlyConfigurableProperty(engine->id_length(), Primitive::fromInt32(0));
+ defineDefaultProperty(us, toUtcGmtStringFn);
+ defineDefaultProperty(gs, toUtcGmtStringFn);
+ }
+
defineDefaultProperty(QStringLiteral("toISOString"), method_toISOString, 0);
defineDefaultProperty(QStringLiteral("toJSON"), method_toJSON, 1);
}
@@ -1025,6 +1040,7 @@ void DatePrototype::method_setTime(const BuiltinFunction *, Scope &scope, CallDa
THROW_TYPE_ERROR();
double t = callData->argc ? callData->args[0].toNumber() : qt_qnan();
+ CHECK_EXCEPTION();
self->setDate(TimeClip(t));
scope.result = Encode(self->date());
}
@@ -1036,7 +1052,9 @@ void DatePrototype::method_setMilliseconds(const BuiltinFunction *, Scope &scope
THROW_TYPE_ERROR();
double t = LocalTime(self->date());
+ CHECK_EXCEPTION();
double ms = callData->argc ? callData->args[0].toNumber() : qt_qnan();
+ CHECK_EXCEPTION();
self->setDate(TimeClip(UTC(MakeDate(Day(t), MakeTime(HourFromTime(t), MinFromTime(t), SecFromTime(t), ms)))));
scope.result = Encode(self->date());
}
@@ -1048,7 +1066,9 @@ void DatePrototype::method_setUTCMilliseconds(const BuiltinFunction *, Scope &sc
THROW_TYPE_ERROR();
double t = self->date();
+ CHECK_EXCEPTION();
double ms = callData->argc ? callData->args[0].toNumber() : qt_qnan();
+ CHECK_EXCEPTION();
self->setDate(TimeClip(MakeDate(Day(t), MakeTime(HourFromTime(t), MinFromTime(t), SecFromTime(t), ms))));
scope.result = Encode(self->date());
}
@@ -1060,8 +1080,11 @@ void DatePrototype::method_setSeconds(const BuiltinFunction *, Scope &scope, Cal
THROW_TYPE_ERROR();
double t = LocalTime(self->date());
+ CHECK_EXCEPTION();
double sec = callData->argc ? callData->args[0].toNumber() : qt_qnan();
+ CHECK_EXCEPTION();
double ms = (callData->argc < 2) ? msFromTime(t) : callData->args[1].toNumber();
+ CHECK_EXCEPTION();
t = TimeClip(UTC(MakeDate(Day(t), MakeTime(HourFromTime(t), MinFromTime(t), sec, ms))));
self->setDate(t);
scope.result = Encode(self->date());
@@ -1088,9 +1111,13 @@ void DatePrototype::method_setMinutes(const BuiltinFunction *, Scope &scope, Cal
THROW_TYPE_ERROR();
double t = LocalTime(self->date());
+ CHECK_EXCEPTION();
double min = callData->argc ? callData->args[0].toNumber() : qt_qnan();
+ CHECK_EXCEPTION();
double sec = (callData->argc < 2) ? SecFromTime(t) : callData->args[1].toNumber();
+ CHECK_EXCEPTION();
double ms = (callData->argc < 3) ? msFromTime(t) : callData->args[2].toNumber();
+ CHECK_EXCEPTION();
t = TimeClip(UTC(MakeDate(Day(t), MakeTime(HourFromTime(t), min, sec, ms))));
self->setDate(t);
scope.result = Encode(self->date());
@@ -1118,10 +1145,15 @@ void DatePrototype::method_setHours(const BuiltinFunction *, Scope &scope, CallD
THROW_TYPE_ERROR();
double t = LocalTime(self->date());
+ CHECK_EXCEPTION();
double hour = callData->argc ? callData->args[0].toNumber() : qt_qnan();
+ CHECK_EXCEPTION();
double min = (callData->argc < 2) ? MinFromTime(t) : callData->args[1].toNumber();
+ CHECK_EXCEPTION();
double sec = (callData->argc < 3) ? SecFromTime(t) : callData->args[2].toNumber();
+ CHECK_EXCEPTION();
double ms = (callData->argc < 4) ? msFromTime(t) : callData->args[3].toNumber();
+ CHECK_EXCEPTION();
t = TimeClip(UTC(MakeDate(Day(t), MakeTime(hour, min, sec, ms))));
self->setDate(t);
scope.result = Encode(self->date());
@@ -1150,7 +1182,9 @@ void DatePrototype::method_setDate(const BuiltinFunction *, Scope &scope, CallDa
THROW_TYPE_ERROR();
double t = LocalTime(self->date());
+ CHECK_EXCEPTION();
double date = callData->argc ? callData->args[0].toNumber() : qt_qnan();
+ CHECK_EXCEPTION();
t = TimeClip(UTC(MakeDate(MakeDay(YearFromTime(t), MonthFromTime(t), date), TimeWithinDay(t))));
self->setDate(t);
scope.result = Encode(self->date());
@@ -1163,7 +1197,9 @@ void DatePrototype::method_setUTCDate(const BuiltinFunction *, Scope &scope, Cal
THROW_TYPE_ERROR();
double t = self->date();
+ CHECK_EXCEPTION();
double date = callData->argc ? callData->args[0].toNumber() : qt_qnan();
+ CHECK_EXCEPTION();
t = TimeClip(MakeDate(MakeDay(YearFromTime(t), MonthFromTime(t), date), TimeWithinDay(t)));
self->setDate(t);
scope.result = Encode(self->date());
@@ -1176,8 +1212,11 @@ void DatePrototype::method_setMonth(const BuiltinFunction *, Scope &scope, CallD
THROW_TYPE_ERROR();
double t = LocalTime(self->date());
+ CHECK_EXCEPTION();
double month = callData->argc ? callData->args[0].toNumber() : qt_qnan();
+ CHECK_EXCEPTION();
double date = (callData->argc < 2) ? DateFromTime(t) : callData->args[1].toNumber();
+ CHECK_EXCEPTION();
t = TimeClip(UTC(MakeDate(MakeDay(YearFromTime(t), month, date), TimeWithinDay(t))));
self->setDate(t);
scope.result = Encode(self->date());
@@ -1245,11 +1284,15 @@ void DatePrototype::method_setFullYear(const BuiltinFunction *, Scope &scope, Ca
THROW_TYPE_ERROR();
double t = LocalTime(self->date());
+ CHECK_EXCEPTION();
if (std::isnan(t))
t = 0;
double year = callData->argc ? callData->args[0].toNumber() : qt_qnan();
+ CHECK_EXCEPTION();
double month = (callData->argc < 2) ? MonthFromTime(t) : callData->args[1].toNumber();
+ CHECK_EXCEPTION();
double date = (callData->argc < 3) ? DateFromTime(t) : callData->args[2].toNumber();
+ CHECK_EXCEPTION();
t = TimeClip(UTC(MakeDate(MakeDay(year, month, date), TimeWithinDay(t))));
self->setDate(t);
scope.result = Encode(self->date());
diff --git a/src/qml/jsruntime/qv4dateobject_p.h b/src/qml/jsruntime/qv4dateobject_p.h
index ecd57bcd8d..b0373884dd 100644
--- a/src/qml/jsruntime/qv4dateobject_p.h
+++ b/src/qml/jsruntime/qv4dateobject_p.h
@@ -112,7 +112,7 @@ struct DateCtor: FunctionObject
static void call(const Managed *that, Scope &scope, CallData *);
};
-struct DatePrototype: DateObject
+struct DatePrototype: Object
{
V4_PROTOTYPE(objectPrototype)
diff --git a/src/qml/jsruntime/qv4engine.cpp b/src/qml/jsruntime/qv4engine.cpp
index 0d3f29d089..f19f134c53 100644
--- a/src/qml/jsruntime/qv4engine.cpp
+++ b/src/qml/jsruntime/qv4engine.cpp
@@ -134,6 +134,7 @@ ExecutionEngine::ExecutionEngine(EvalISelFactory *factory)
, regExpAllocator(new QV4::ExecutableAllocator)
, bumperPointerAllocator(new WTF::BumpPointerAllocator)
, jsStack(new WTF::PageAllocation)
+ , gcStack(new WTF::PageAllocation)
, globalCode(0)
, v8Engine(0)
, argumentsAccessors(0)
@@ -182,18 +183,22 @@ ExecutionEngine::ExecutionEngine(EvalISelFactory *factory)
iselFactory.reset(factory);
// reserve space for the JS stack
- // we allow it to grow to 2 times JSStackLimit, as we can overshoot due to garbage collection
- // and ScopedValues allocated outside of JIT'ed methods.
- *jsStack = WTF::PageAllocation::allocate(2 * JSStackLimit, WTF::OSAllocator::JSVMStackPages,
+ // we allow it to grow to a bit more than JSStackLimit, as we can overshoot due to ScopedValues
+ // allocated outside of JIT'ed methods.
+ *jsStack = WTF::PageAllocation::allocate(JSStackLimit + 256*1024, WTF::OSAllocator::JSVMStackPages,
/* writable */ true, /* executable */ false,
/* includesGuardPages */ true);
jsStackBase = (Value *)jsStack->base();
#ifdef V4_USE_VALGRIND
- VALGRIND_MAKE_MEM_UNDEFINED(jsStackBase, 2*JSStackLimit);
+ VALGRIND_MAKE_MEM_UNDEFINED(jsStackBase, JSStackLimit + 256*1024);
#endif
jsStackTop = jsStackBase;
+ *gcStack = WTF::PageAllocation::allocate(GCStackLimit, WTF::OSAllocator::JSVMStackPages,
+ /* writable */ true, /* executable */ false,
+ /* includesGuardPages */ true);
+
exceptionValue = jsAlloca(1);
globalObject = static_cast<Object *>(jsAlloca(1));
jsObjects = jsAlloca(NJSObjects);
@@ -215,7 +220,7 @@ ExecutionEngine::ExecutionEngine(EvalISelFactory *factory)
internalClasses[Class_SparseArrayData] = internalClasses[EngineBase::Class_Empty]->changeVTable(QV4::SparseArrayData::staticVTable());
internalClasses[Class_ExecutionContext] = internalClasses[EngineBase::Class_Empty]->changeVTable(QV4::ExecutionContext::staticVTable());
internalClasses[EngineBase::Class_QmlContext] = internalClasses[EngineBase::Class_ExecutionContext]->changeVTable(QV4::QmlContext::staticVTable());
- internalClasses[Class_CallContext] = internalClasses[EngineBase::Class_Empty]->changeVTable(QV4::CallContext::staticVTable());
+ internalClasses[Class_SimpleCallContext] = internalClasses[EngineBase::Class_Empty]->changeVTable(QV4::CallContext::staticVTable());
jsStrings[String_Empty] = newIdentifier(QString());
jsStrings[String_undefined] = newIdentifier(QStringLiteral("undefined"));
@@ -257,7 +262,7 @@ ExecutionEngine::ExecutionEngine(EvalISelFactory *factory)
InternalClass *ic = internalClasses[Class_Empty]->changeVTable(QV4::Object::staticVTable());
jsObjects[ObjectProto] = memoryManager->allocObject<ObjectPrototype>(ic);
internalClasses[Class_Object] = ic->changePrototype(objectPrototype()->d());
- internalClasses[EngineBase::Class_QmlContextWrapper] = internalClasses[Class_Object]->changeVTable(QV4::QmlContextWrapper::staticVTable());
+ internalClasses[EngineBase::Class_QmlContextWrapper] = internalClasses[Class_Object]->changeVTable(QV4::QQmlContextWrapper::staticVTable());
ic = newInternalClass(ArrayPrototype::staticVTable(), objectPrototype());
Q_ASSERT(ic->prototype);
@@ -422,13 +427,14 @@ ExecutionEngine::ExecutionEngine(EvalISelFactory *factory)
//
// set up the global object
//
- rootContext()->d()->global = globalObject->d();
+ rootContext()->d()->global.set(scope.engine, globalObject->d());
rootContext()->d()->callData->thisObject = globalObject;
Q_ASSERT(globalObject->d()->vtable());
globalObject->defineDefaultProperty(QStringLiteral("Object"), *objectCtor());
globalObject->defineDefaultProperty(QStringLiteral("String"), *stringCtor());
- globalObject->defineDefaultProperty(QStringLiteral("Number"), *numberCtor());
+ FunctionObject *numberObject = numberCtor();
+ globalObject->defineDefaultProperty(QStringLiteral("Number"), *numberObject);
globalObject->defineDefaultProperty(QStringLiteral("Boolean"), *booleanCtor());
globalObject->defineDefaultProperty(QStringLiteral("Array"), *arrayCtor());
globalObject->defineDefaultProperty(QStringLiteral("Function"), *functionCtor());
@@ -458,8 +464,26 @@ ExecutionEngine::ExecutionEngine(EvalISelFactory *factory)
jsObjects[Eval_Function] = memoryManager->allocObject<EvalFunction>(global);
globalObject->defineDefaultProperty(QStringLiteral("eval"), *evalFunction());
- globalObject->defineDefaultProperty(QStringLiteral("parseInt"), GlobalFunctions::method_parseInt, 2);
- globalObject->defineDefaultProperty(QStringLiteral("parseFloat"), GlobalFunctions::method_parseFloat, 1);
+ // ES6: 20.1.2.12 & 20.1.2.13:
+ // parseInt and parseFloat must be the same FunctionObject on the global &
+ // Number object.
+ {
+ QString piString(QStringLiteral("parseInt"));
+ QString pfString(QStringLiteral("parseFloat"));
+ Scope scope(this);
+ ScopedString pi(scope, newIdentifier(piString));
+ ScopedString pf(scope, newIdentifier(pfString));
+ ExecutionContext *global = rootContext();
+ ScopedFunctionObject parseIntFn(scope, BuiltinFunction::create(global, pi, GlobalFunctions::method_parseInt));
+ ScopedFunctionObject parseFloatFn(scope, BuiltinFunction::create(global, pf, GlobalFunctions::method_parseFloat));
+ parseIntFn->defineReadonlyConfigurableProperty(id_length(), Primitive::fromInt32(2));
+ parseFloatFn->defineReadonlyConfigurableProperty(id_length(), Primitive::fromInt32(1));
+ globalObject->defineDefaultProperty(piString, parseIntFn);
+ globalObject->defineDefaultProperty(pfString, parseFloatFn);
+ numberObject->defineDefaultProperty(piString, parseIntFn);
+ numberObject->defineDefaultProperty(pfString, parseFloatFn);
+ }
+
globalObject->defineDefaultProperty(QStringLiteral("isNaN"), GlobalFunctions::method_isNaN, 1);
globalObject->defineDefaultProperty(QStringLiteral("isFinite"), GlobalFunctions::method_isFinite, 1);
globalObject->defineDefaultProperty(QStringLiteral("decodeURI"), GlobalFunctions::method_decodeURI, 1);
@@ -491,6 +515,8 @@ ExecutionEngine::~ExecutionEngine()
delete executableAllocator;
jsStack->deallocate();
delete jsStack;
+ gcStack->deallocate();
+ delete gcStack;
delete [] argumentsAccessors;
}
@@ -602,12 +628,14 @@ Heap::ArrayObject *ExecutionEngine::newArrayObject(const Value *values, int leng
size_t size = sizeof(Heap::ArrayData) + (length-1)*sizeof(Value);
Heap::SimpleArrayData *d = scope.engine->memoryManager->allocManaged<SimpleArrayData>(size);
d->init();
- d->alloc = length;
d->type = Heap::ArrayData::Simple;
d->offset = 0;
- d->len = length;
- memcpy(&d->arrayData, values, length*sizeof(Value));
- a->d()->arrayData = d;
+ d->values.alloc = length;
+ d->values.size = length;
+ // this doesn't require a write barrier, things will be ok, when the new array data gets inserted into
+ // the parent object
+ memcpy(&d->values.values, values, length*sizeof(Value));
+ a->d()->arrayData.set(this, d);
a->setArrayLengthUnchecked(length);
}
return a->d();
@@ -884,7 +912,7 @@ QUrl ExecutionEngine::resolvedUrl(const QString &file)
QUrl base;
ExecutionContext *c = currentContext;
while (c) {
- CallContext *callCtx = c->asCallContext();
+ SimpleCallContext *callCtx = c->asSimpleCallContext();
if (callCtx && callCtx->d()->v4Function) {
base = callCtx->d()->v4Function->finalUrl();
break;
@@ -927,35 +955,24 @@ void ExecutionEngine::requireArgumentsAccessors(int n)
}
}
-static void drainMarkStack(ExecutionEngine *engine, QV4::Value *markBase)
+void ExecutionEngine::markObjects(MarkStack *markStack)
{
- while (engine->jsStackTop > markBase) {
- Heap::Base *h = engine->popForGC();
- Q_ASSERT (h->vtable()->markObjects);
- h->vtable()->markObjects(h, engine);
- }
-}
-
-void ExecutionEngine::markObjects()
-{
- Value *markBase = jsStackTop;
- identifierTable->mark(this);
+ identifierTable->mark(markStack);
for (int i = 0; i < nArgumentsAccessors; ++i) {
const Property &pd = argumentsAccessors[i];
if (Heap::FunctionObject *getter = pd.getter())
- getter->mark(this);
+ getter->mark(markStack);
if (Heap::FunctionObject *setter = pd.setter())
- setter->mark(this);
+ setter->mark(markStack);
}
- classPool->markObjects(this);
-
- drainMarkStack(this, markBase);
+ classPool->markObjects(markStack);
+ markStack->drain();
for (auto compilationUnit: compilationUnits) {
- compilationUnit->markObjects(this);
- drainMarkStack(this, markBase);
+ compilationUnit->markObjects(markStack);
+ markStack->drain();
}
}
@@ -1150,9 +1167,9 @@ static QVariant toVariant(QV4::ExecutionEngine *e, const QV4::Value &value, int
return QVariant::fromValue(QV4::JsonObject::toJsonObject(object));
} else if (QV4::QObjectWrapper *wrapper = object->as<QV4::QObjectWrapper>()) {
return qVariantFromValue<QObject *>(wrapper->object());
- } else if (object->as<QV4::QmlContextWrapper>()) {
+ } else if (object->as<QV4::QQmlContextWrapper>()) {
return QVariant();
- } else if (QV4::QmlTypeWrapper *w = object->as<QV4::QmlTypeWrapper>()) {
+ } else if (QV4::QQmlTypeWrapper *w = object->as<QV4::QQmlTypeWrapper>()) {
return w->toVariant();
} else if (QV4::QQmlValueTypeWrapper *v = object->as<QV4::QQmlValueTypeWrapper>()) {
return v->toVariant();
@@ -1574,12 +1591,6 @@ QV4::ReturnedValue ExecutionEngine::metaTypeToJS(int type, const void *data)
return 0;
}
-void ExecutionEngine::assertObjectBelongsToEngine(const Heap::Base &baseObject)
-{
- Q_ASSERT(!baseObject.vtable()->isObject || static_cast<const Heap::Object&>(baseObject).internalClass->engine == this);
- Q_UNUSED(baseObject);
-}
-
void ExecutionEngine::failStackLimitCheck(Scope &scope)
{
scope.result = throwRangeError(QStringLiteral("Maximum call stack size exceeded."));
diff --git a/src/qml/jsruntime/qv4engine_p.h b/src/qml/jsruntime/qv4engine_p.h
index fee06ebc58..4549cda5b9 100644
--- a/src/qml/jsruntime/qv4engine_p.h
+++ b/src/qml/jsruntime/qv4engine_p.h
@@ -104,17 +104,13 @@ public:
WTF::BumpPointerAllocator *bumperPointerAllocator; // Used by Yarr Regex engine.
- enum { JSStackLimit = 4*1024*1024 };
+ enum {
+ JSStackLimit = 4*1024*1024,
+ GCStackLimit = 2*1024*1024
+ };
WTF::PageAllocation *jsStack;
- void pushForGC(Heap::Base *m) {
- *jsStackTop = m;
- ++jsStackTop;
- }
- Heap::Base *popForGC() {
- --jsStackTop;
- return jsStackTop->heapObject();
- }
+ WTF::PageAllocation *gcStack;
QML_NEARLY_ALWAYS_INLINE Value *jsAlloca(int nValues) {
Value *ptr = jsStackTop;
@@ -422,7 +418,7 @@ public:
void requireArgumentsAccessors(int n);
- void markObjects();
+ void markObjects(MarkStack *markStack);
void initRootContext();
@@ -459,8 +455,6 @@ public:
bool metaTypeFromJS(const Value *value, int type, void *data);
QV4::ReturnedValue metaTypeToJS(int type, const void *data);
- void assertObjectBelongsToEngine(const Heap::Base &baseObject);
-
bool checkStackLimits(Scope &scope);
private:
@@ -519,23 +513,32 @@ inline ExecutionContext *ExecutionEngine::parentContext(ExecutionContext *contex
}
inline
-void Heap::Base::mark(QV4::ExecutionEngine *engine)
+void Heap::Base::mark(QV4::MarkStack *markStack)
{
Q_ASSERT(inUse());
- if (isMarked())
- return;
-#ifndef QT_NO_DEBUG
- engine->assertObjectBelongsToEngine(*this);
-#endif
- setMarkBit();
- engine->pushForGC(this);
+ const HeapItem *h = reinterpret_cast<const HeapItem *>(this);
+ Chunk *c = h->chunk();
+ size_t index = h - c->realBase();
+ Q_ASSERT(!Chunk::testBit(c->extendsBitmap, index));
+ quintptr *bitmap = c->blackBitmap + Chunk::bitmapIndex(index);
+ quintptr bit = Chunk::bitForIndex(index);
+ if (!(*bitmap & bit)) {
+ *bitmap |= bit;
+ markStack->push(this);
+ }
}
-inline void Value::mark(ExecutionEngine *e)
+inline void Value::mark(MarkStack *markStack)
{
Heap::Base *o = heapObject();
if (o)
- o->mark(e);
+ o->mark(markStack);
+}
+
+inline void Managed::mark(MarkStack *markStack)
+{
+ Q_ASSERT(m());
+ m()->mark(markStack);
}
#define CHECK_STACK_LIMITS(v4, scope) if ((v4)->checkStackLimits(scope)) return; \
diff --git a/src/qml/jsruntime/qv4enginebase_p.h b/src/qml/jsruntime/qv4enginebase_p.h
index 38b5ed8909..8258d644ff 100644
--- a/src/qml/jsruntime/qv4enginebase_p.h
+++ b/src/qml/jsruntime/qv4enginebase_p.h
@@ -66,7 +66,9 @@ struct EngineBase {
Heap::ExecutionContext *current = 0;
Value *jsStackTop = 0;
- quint32 hasException = false;
+ quint8 hasException = false;
+ quint8 writeBarrierActive = false;
+ quint16 unused = 0;
#if QT_POINTER_SIZE == 8
quint8 padding[4];
#endif
@@ -88,7 +90,7 @@ struct EngineBase {
Class_SimpleArrayData,
Class_SparseArrayData,
Class_ExecutionContext,
- Class_CallContext,
+ Class_SimpleCallContext,
Class_Object,
Class_ArrayObject,
Class_FunctionObject,
diff --git a/src/qml/jsruntime/qv4errorobject.cpp b/src/qml/jsruntime/qv4errorobject.cpp
index 6811438915..b3bd28e18b 100644
--- a/src/qml/jsruntime/qv4errorobject.cpp
+++ b/src/qml/jsruntime/qv4errorobject.cpp
@@ -78,10 +78,10 @@ void Heap::ErrorObject::init()
if (internalClass == scope.engine->internalClasses[EngineBase::Class_ErrorProto])
return;
- *propertyData(QV4::ErrorObject::Index_Stack) = scope.engine->getStackFunction();
- *propertyData(QV4::ErrorObject::Index_Stack + QV4::Object::SetterOffset) = Encode::undefined();
- *propertyData(QV4::ErrorObject::Index_FileName) = Encode::undefined();
- *propertyData(QV4::ErrorObject::Index_LineNumber) = Encode::undefined();
+ setProperty(scope.engine, QV4::ErrorObject::Index_Stack, scope.engine->getStackFunction()->d());
+ setProperty(scope.engine, QV4::ErrorObject::Index_Stack + QV4::Object::SetterOffset, Primitive::undefinedValue());
+ setProperty(scope.engine, QV4::ErrorObject::Index_FileName, Primitive::undefinedValue());
+ setProperty(scope.engine, QV4::ErrorObject::Index_LineNumber, Primitive::undefinedValue());
}
void Heap::ErrorObject::init(const Value &message, ErrorType t)
@@ -92,17 +92,17 @@ void Heap::ErrorObject::init(const Value &message, ErrorType t)
Scope scope(internalClass->engine);
Scoped<QV4::ErrorObject> e(scope, this);
- *propertyData(QV4::ErrorObject::Index_Stack) = scope.engine->getStackFunction();
- *propertyData(QV4::ErrorObject::Index_Stack + QV4::Object::SetterOffset) = Encode::undefined();
+ setProperty(scope.engine, QV4::ErrorObject::Index_Stack, scope.engine->getStackFunction()->d());
+ setProperty(scope.engine, QV4::ErrorObject::Index_Stack + QV4::Object::SetterOffset, Primitive::undefinedValue());
e->d()->stackTrace = new StackTrace(scope.engine->stackTrace());
if (!e->d()->stackTrace->isEmpty()) {
- *propertyData(QV4::ErrorObject::Index_FileName) = scope.engine->newString(e->d()->stackTrace->at(0).source);
- *propertyData(QV4::ErrorObject::Index_LineNumber) = Primitive::fromInt32(e->d()->stackTrace->at(0).line);
+ setProperty(scope.engine, QV4::ErrorObject::Index_FileName, scope.engine->newString(e->d()->stackTrace->at(0).source));
+ setProperty(scope.engine, QV4::ErrorObject::Index_LineNumber, Primitive::fromInt32(e->d()->stackTrace->at(0).line));
}
if (!message.isUndefined())
- *propertyData(QV4::ErrorObject::Index_Message) = message;
+ setProperty(scope.engine, QV4::ErrorObject::Index_Message, message);
}
void Heap::ErrorObject::init(const Value &message, const QString &fileName, int line, int column, ErrorObject::ErrorType t)
@@ -113,8 +113,8 @@ void Heap::ErrorObject::init(const Value &message, const QString &fileName, int
Scope scope(internalClass->engine);
Scoped<QV4::ErrorObject> e(scope, this);
- *propertyData(QV4::ErrorObject::Index_Stack) = scope.engine->getStackFunction();
- *propertyData(QV4::ErrorObject::Index_Stack + QV4::Object::SetterOffset) = Encode::undefined();
+ setProperty(scope.engine, QV4::ErrorObject::Index_Stack, scope.engine->getStackFunction()->d());
+ setProperty(scope.engine, QV4::ErrorObject::Index_Stack + QV4::Object::SetterOffset, Primitive::undefinedValue());
e->d()->stackTrace = new StackTrace(scope.engine->stackTrace());
StackFrame frame;
@@ -124,12 +124,12 @@ void Heap::ErrorObject::init(const Value &message, const QString &fileName, int
e->d()->stackTrace->prepend(frame);
if (!e->d()->stackTrace->isEmpty()) {
- *propertyData(QV4::ErrorObject::Index_FileName) = scope.engine->newString(e->d()->stackTrace->at(0).source);
- *propertyData(QV4::ErrorObject::Index_LineNumber) = Primitive::fromInt32(e->d()->stackTrace->at(0).line);
+ setProperty(scope.engine, QV4::ErrorObject::Index_FileName, scope.engine->newString(e->d()->stackTrace->at(0).source));
+ setProperty(scope.engine, QV4::ErrorObject::Index_LineNumber, Primitive::fromInt32(e->d()->stackTrace->at(0).line));
}
if (!message.isUndefined())
- *propertyData(QV4::ErrorObject::Index_Message) = message;
+ setProperty(scope.engine, QV4::ErrorObject::Index_Message, message);
}
const char *ErrorObject::className(Heap::ErrorObject::ErrorType t)
@@ -168,19 +168,11 @@ void ErrorObject::method_get_stack(const BuiltinFunction *, Scope &scope, CallDa
if (frame.line >= 0)
trace += QLatin1Char(':') + QString::number(frame.line);
}
- This->d()->stack = scope.engine->newString(trace);
+ This->d()->stack.set(scope.engine, scope.engine->newString(trace));
}
scope.result = This->d()->stack;
}
-void ErrorObject::markObjects(Heap::Base *that, ExecutionEngine *e)
-{
- ErrorObject::Data *This = static_cast<ErrorObject::Data *>(that);
- if (This->stack)
- This->stack->mark(e);
- Object::markObjects(that, e);
-}
-
DEFINE_OBJECT_VTABLE(ErrorObject);
void Heap::SyntaxErrorObject::init(const Value &msg)
@@ -325,9 +317,9 @@ void ErrorPrototype::init(ExecutionEngine *engine, Object *ctor, Object *obj, He
ScopedObject o(scope);
ctor->defineReadonlyProperty(engine->id_prototype(), (o = obj));
ctor->defineReadonlyProperty(engine->id_length(), Primitive::fromInt32(1));
- *obj->propertyData(Index_Constructor) = ctor;
- *obj->propertyData(Index_Message) = engine->id_empty();
- *obj->propertyData(Index_Name) = engine->newString(QString::fromLatin1(ErrorObject::className(t)));
+ obj->setProperty(Index_Constructor, ctor->d());
+ obj->setProperty(Index_Message, engine->id_empty()->d());
+ obj->setProperty(Index_Name, engine->newString(QString::fromLatin1(ErrorObject::className(t))));
obj->defineDefaultProperty(engine->id_toString(), method_toString, 0);
}
diff --git a/src/qml/jsruntime/qv4errorobject_p.h b/src/qml/jsruntime/qv4errorobject_p.h
index 12531c9309..d556617b48 100644
--- a/src/qml/jsruntime/qv4errorobject_p.h
+++ b/src/qml/jsruntime/qv4errorobject_p.h
@@ -62,7 +62,12 @@ struct SyntaxErrorObject;
namespace Heap {
-struct ErrorObject : Object {
+
+#define ErrorObjectMembers(class, Member) \
+ Member(class, Pointer, String *, stack)
+
+DECLARE_HEAP_OBJECT(ErrorObject, Object) {
+ DECLARE_MARK_TABLE(ErrorObject);
enum ErrorType {
Error,
EvalError,
@@ -72,6 +77,8 @@ struct ErrorObject : Object {
TypeError,
URIError
};
+ StackTrace *stackTrace;
+ ErrorType errorType;
void init();
void init(const Value &message, ErrorType t = Error);
@@ -80,10 +87,6 @@ struct ErrorObject : Object {
delete stackTrace;
Object::destroy();
}
-
- ErrorType errorType;
- StackTrace *stackTrace;
- Pointer<String> stack;
};
struct EvalErrorObject : ErrorObject {
@@ -173,7 +176,6 @@ struct ErrorObject: Object {
static const char *className(Heap::ErrorObject::ErrorType t);
static void method_get_stack(const BuiltinFunction *, Scope &scope, CallData *callData);
- static void markObjects(Heap::Base *that, ExecutionEngine *e);
};
template<>
diff --git a/src/qml/jsruntime/qv4function.cpp b/src/qml/jsruntime/qv4function.cpp
index f78555dbda..4b88d85e68 100644
--- a/src/qml/jsruntime/qv4function.cpp
+++ b/src/qml/jsruntime/qv4function.cpp
@@ -59,7 +59,7 @@ Function::Function(ExecutionEngine *engine, CompiledData::CompilationUnit *unit,
, hasQmlDependencies(function->hasQmlDependencies())
{
internalClass = engine->internalClasses[EngineBase::Class_Empty];
- const CompiledData::LEUInt32 *formalsIndices = compiledFunction->formalsTable();
+ const quint32_le *formalsIndices = compiledFunction->formalsTable();
// iterate backwards, so we get the right ordering for duplicate names
Scope scope(engine);
ScopedString arg(scope);
@@ -78,14 +78,11 @@ Function::Function(ExecutionEngine *engine, CompiledData::CompilationUnit *unit,
}
nFormals = compiledFunction->nFormals;
- const CompiledData::LEUInt32 *localsIndices = compiledFunction->localsTable();
+ const quint32_le *localsIndices = compiledFunction->localsTable();
for (quint32 i = 0; i < compiledFunction->nLocals; ++i)
internalClass = internalClass->addMember(engine->identifierTable->identifier(compilationUnit->runtimeStrings[localsIndices[i]]), Attr_NotConfigurable);
- activationRequired = compiledFunction->nInnerFunctions > 0 || (compiledFunction->flags & (CompiledData::Function::HasDirectEval | CompiledData::Function::UsesArgumentsObject));
-
- canUseSimpleCall = !needsActivation() && !(compiledFunction->flags & CompiledData::Function::HasCatchOrWith) &&
- !(compiledFunction->nFormals > QV4::Global::ReservedArgumentCount) && !isNamedExpression();
+ canUseSimpleCall = compiledFunction->flags & CompiledData::Function::CanUseSimpleCall;
}
Function::~Function()
@@ -113,11 +110,11 @@ void Function::updateInternalClass(ExecutionEngine *engine, const QList<QByteArr
}
nFormals = parameters.size();
- const CompiledData::LEUInt32 *localsIndices = compiledFunction->localsTable();
+ const quint32_le *localsIndices = compiledFunction->localsTable();
for (quint32 i = 0; i < compiledFunction->nLocals; ++i)
internalClass = internalClass->addMember(engine->identifierTable->identifier(compilationUnit->runtimeStrings[localsIndices[i]]), Attr_NotConfigurable);
- activationRequired = true;
+ canUseSimpleCall = false;
}
QT_END_NAMESPACE
diff --git a/src/qml/jsruntime/qv4function_p.h b/src/qml/jsruntime/qv4function_p.h
index b212b3d027..8b2d14a0cf 100644
--- a/src/qml/jsruntime/qv4function_p.h
+++ b/src/qml/jsruntime/qv4function_p.h
@@ -69,7 +69,6 @@ struct Q_QML_EXPORT Function {
// first nArguments names in internalClass are the actual arguments
InternalClass *internalClass;
uint nFormals;
- bool activationRequired;
bool hasQmlDependencies;
bool canUseSimpleCall;
@@ -90,9 +89,6 @@ struct Q_QML_EXPORT Function {
inline bool isStrict() const { return compiledFunction->flags & CompiledData::Function::IsStrict; }
inline bool isNamedExpression() const { return compiledFunction->flags & CompiledData::Function::IsNamedExpression; }
- inline bool needsActivation() const
- { return activationRequired; }
-
inline bool canUseSimpleFunction() const { return canUseSimpleCall; }
QQmlSourceLocation sourceLocation() const
@@ -103,7 +99,7 @@ struct Q_QML_EXPORT Function {
};
-inline unsigned int Heap::CallContext::formalParameterCount() const
+inline unsigned int Heap::SimpleCallContext::formalParameterCount() const
{
return v4Function ? v4Function->nFormals : 0;
}
diff --git a/src/qml/jsruntime/qv4functionobject.cpp b/src/qml/jsruntime/qv4functionobject.cpp
index 63396998fa..2375aae92b 100644
--- a/src/qml/jsruntime/qv4functionobject.cpp
+++ b/src/qml/jsruntime/qv4functionobject.cpp
@@ -69,11 +69,13 @@ using namespace QV4;
DEFINE_OBJECT_VTABLE(FunctionObject);
+Q_STATIC_ASSERT((Heap::FunctionObject::markTable & Heap::Object::markTable) == Heap::Object::markTable);
+
void Heap::FunctionObject::init(QV4::ExecutionContext *scope, QV4::String *name, bool createProto)
{
Object::init();
function = nullptr;
- this->scope = scope->d();
+ this->scope.set(scope->engine(), scope->d());
Scope s(scope->engine());
ScopedFunctionObject f(s, this);
f->init(name, createProto);
@@ -84,7 +86,7 @@ void Heap::FunctionObject::init(QV4::ExecutionContext *scope, Function *function
Object::init();
this->function = function;
function->compilationUnit->addref();
- this->scope = scope->d();
+ this->scope.set(scope->engine(), scope->d());
Scope s(scope->engine());
ScopedString name(s, function->name());
ScopedFunctionObject f(s, this);
@@ -102,9 +104,9 @@ void Heap::FunctionObject::init()
{
Object::init();
function = nullptr;
- this->scope = internalClass->engine->rootContext()->d();
+ this->scope.set(internalClass->engine, internalClass->engine->rootContext()->d());
Q_ASSERT(internalClass && internalClass->find(internalClass->engine->id_prototype()) == Index_Prototype);
- *propertyData(Index_Prototype) = Encode::undefined();
+ setProperty(internalClass->engine, Index_Prototype, Primitive::undefinedValue());
}
@@ -124,14 +126,14 @@ void FunctionObject::init(String *n, bool createProto)
if (createProto) {
ScopedObject proto(s, s.engine->newObject(s.engine->internalClasses[EngineBase::Class_ObjectProto], s.engine->objectPrototype()));
Q_ASSERT(s.engine->internalClasses[EngineBase::Class_ObjectProto]->find(s.engine->id_constructor()) == Heap::FunctionObject::Index_ProtoConstructor);
- *proto->propertyData(Heap::FunctionObject::Index_ProtoConstructor) = this->asReturnedValue();
- *propertyData(Heap::FunctionObject::Index_Prototype) = proto.asReturnedValue();
+ proto->setProperty(Heap::FunctionObject::Index_ProtoConstructor, d());
+ setProperty(Heap::FunctionObject::Index_Prototype, proto);
} else {
- *propertyData(Heap::FunctionObject::Index_Prototype) = Encode::undefined();
+ setProperty(Heap::FunctionObject::Index_Prototype, Primitive::undefinedValue());
}
if (n)
- defineReadonlyProperty(s.engine->id_name(), *n);
+ defineReadonlyConfigurableProperty(s.engine->id_name(), *n);
}
ReturnedValue FunctionObject::name() const
@@ -149,15 +151,6 @@ void FunctionObject::call(const Managed *, Scope &scope, CallData *)
scope.result = Encode::undefined();
}
-void FunctionObject::markObjects(Heap::Base *that, ExecutionEngine *e)
-{
- Heap::FunctionObject *o = static_cast<Heap::FunctionObject *>(that);
- if (o->scope)
- o->scope->mark(e);
-
- Object::markObjects(that, e);
-}
-
Heap::FunctionObject *FunctionObject::createScriptFunction(ExecutionContext *scope, Function *function)
{
return scope->engine()->memoryManager->allocObject<ScriptFunction>(scope, function);
@@ -258,10 +251,10 @@ void FunctionPrototype::init(ExecutionEngine *engine, Object *ctor)
Scope scope(engine);
ScopedObject o(scope);
- ctor->defineReadonlyProperty(engine->id_length(), Primitive::fromInt32(1));
+ ctor->defineReadonlyConfigurableProperty(engine->id_length(), Primitive::fromInt32(1));
ctor->defineReadonlyProperty(engine->id_prototype(), (o = this));
- defineReadonlyProperty(engine->id_length(), Primitive::fromInt32(0));
+ defineReadonlyConfigurableProperty(engine->id_length(), Primitive::fromInt32(0));
defineDefaultProperty(QStringLiteral("constructor"), (o = ctor));
defineDefaultProperty(engine->id_toString(), method_toString, 0);
defineDefaultProperty(QStringLiteral("apply"), method_apply, 2);
@@ -309,7 +302,7 @@ void FunctionPrototype::method_apply(const BuiltinFunction *, Scope &scope, Call
cData->args[i] = Primitive::undefinedValue();
} else if (arr->arrayType() == Heap::ArrayData::Simple && !arr->protoHasArray()) {
auto sad = static_cast<Heap::SimpleArrayData *>(arr->arrayData());
- uint alen = sad ? sad->len : 0;
+ uint alen = sad ? sad->values.size : 0;
if (alen > len)
alen = len;
for (uint i = 0; i < alen; ++i)
@@ -352,8 +345,9 @@ void FunctionPrototype::method_bind(const BuiltinFunction *, Scope &scope, CallD
Scoped<MemberData> boundArgs(scope, (Heap::MemberData *)0);
if (callData->argc > 1) {
boundArgs = MemberData::allocate(scope.engine, callData->argc - 1);
- boundArgs->d()->size = callData->argc - 1;
- memcpy(boundArgs->data(), callData->args + 1, (callData->argc - 1)*sizeof(Value));
+ boundArgs->d()->values.size = callData->argc - 1;
+ for (uint i = 0; i < static_cast<uint>(callData->argc - 1); ++i)
+ boundArgs->set(scope.engine, i, callData->args[i + 1]);
}
ExecutionContext *global = scope.engine->rootContext();
@@ -420,7 +414,7 @@ void ScriptFunction::call(const Managed *that, Scope &scope, CallData *callData)
void Heap::ScriptFunction::init(QV4::ExecutionContext *scope, Function *function)
{
FunctionObject::init();
- this->scope = scope->d();
+ this->scope.set(scope->engine(), scope->d());
this->function = function;
function->compilationUnit->addref();
@@ -433,7 +427,7 @@ void Heap::ScriptFunction::init(QV4::ExecutionContext *scope, Function *function
ScopedString name(s, function->name());
f->init(name, true);
Q_ASSERT(internalClass && internalClass->find(s.engine->id_length()) == Index_Length);
- *propertyData(Index_Length) = Primitive::fromInt32(f->formalParameterCount());
+ setProperty(s.engine, Index_Length, Primitive::fromInt32(f->formalParameterCount()));
if (scope->d()->strictMode) {
ScopedProperty pd(s);
@@ -459,7 +453,6 @@ InternalClass *ScriptFunction::classForConstructor() const
return ic;
}
-
DEFINE_OBJECT_VTABLE(BuiltinFunction);
void Heap::BuiltinFunction::init(QV4::ExecutionContext *scope, QV4::String *name, void (*code)(const QV4::BuiltinFunction *, Scope &, CallData *))
@@ -497,7 +490,7 @@ void IndexedBuiltinFunction::call(const Managed *that, Scope &scope, CallData *c
ExecutionContextSaver ctxSaver(scope);
- CallContext::Data *ctx = v4->memoryManager->allocSimpleCallContext();
+ SimpleCallContext::Data *ctx = v4->memoryManager->allocSimpleCallContext();
ctx->strictMode = f->scope()->strictMode; // ### needed? scope or parent context?
ctx->callData = callData;
v4->pushContext(ctx);
@@ -514,12 +507,12 @@ DEFINE_OBJECT_VTABLE(BoundFunction);
void Heap::BoundFunction::init(QV4::ExecutionContext *scope, QV4::FunctionObject *target,
const Value &boundThis, QV4::MemberData *boundArgs)
{
+ Scope s(scope);
Heap::FunctionObject::init(scope, QStringLiteral("__bound function__"));
- this->target = target->d();
- this->boundArgs = boundArgs ? boundArgs->d() : 0;
- this->boundThis = boundThis;
+ this->target.set(s.engine, target->d());
+ this->boundArgs.set(s.engine, boundArgs ? boundArgs->d() : 0);
+ this->boundThis.set(scope->engine(), boundThis);
- Scope s(scope);
ScopedObject f(s, this);
ScopedValue l(s, target->get(s.engine->id_length()));
@@ -528,7 +521,7 @@ void Heap::BoundFunction::init(QV4::ExecutionContext *scope, QV4::FunctionObject
len -= boundArgs->size();
if (len < 0)
len = 0;
- f->defineReadonlyProperty(s.engine->id_length(), Primitive::fromInt32(len));
+ f->defineReadonlyConfigurableProperty(s.engine->id_length(), Primitive::fromInt32(len));
ScopedProperty pd(s);
pd->value = s.engine->thrower();
@@ -577,14 +570,3 @@ void BoundFunction::construct(const Managed *that, Scope &scope, CallData *dd)
ScopedFunctionObject t(scope, f->target());
t->construct(scope, callData);
}
-
-void BoundFunction::markObjects(Heap::Base *that, ExecutionEngine *e)
-{
- BoundFunction::Data *o = static_cast<BoundFunction::Data *>(that);
- if (o->target)
- o->target->mark(e);
- o->boundThis.mark(e);
- if (o->boundArgs)
- o->boundArgs->mark(e);
- FunctionObject::markObjects(that, e);
-}
diff --git a/src/qml/jsruntime/qv4functionobject_p.h b/src/qml/jsruntime/qv4functionobject_p.h
index d691b869fe..6ce5734b6d 100644
--- a/src/qml/jsruntime/qv4functionobject_p.h
+++ b/src/qml/jsruntime/qv4functionobject_p.h
@@ -65,7 +65,12 @@ struct BuiltinFunction;
namespace Heap {
-struct Q_QML_PRIVATE_EXPORT FunctionObject : Object {
+#define FunctionObjectMembers(class, Member) \
+ Member(class, Pointer, ExecutionContext *, scope) \
+ Member(class, NoMark, Function *, function)
+
+DECLARE_HEAP_OBJECT(FunctionObject, Object) {
+ DECLARE_MARK_TABLE(FunctionObject);
enum {
Index_Prototype = 0,
Index_ProtoConstructor = 0
@@ -79,12 +84,8 @@ struct Q_QML_PRIVATE_EXPORT FunctionObject : Object {
unsigned int formalParameterCount() { return function ? function->nFormals : 0; }
unsigned int varCount() { return function ? function->compiledFunction->nLocals : 0; }
- bool needsActivation() const { return function ? function->needsActivation() : false; }
const QV4::Object *protoProperty() const { return propertyData(Index_Prototype)->as<QV4::Object>(); }
-
- Pointer<ExecutionContext> scope;
- Function *function;
};
struct FunctionCtor : FunctionObject {
@@ -121,11 +122,15 @@ struct ScriptFunction : FunctionObject {
QV4::InternalClass *cachedClassForConstructor;
};
-struct BoundFunction : FunctionObject {
+#define BoundFunctionMembers(class, Member) \
+ Member(class, Pointer, FunctionObject *, target) \
+ Member(class, HeapValue, HeapValue, boundThis) \
+ Member(class, Pointer, MemberData *, boundArgs)
+
+DECLARE_HEAP_OBJECT(BoundFunction, FunctionObject) {
+ DECLARE_MARK_TABLE(BoundFunction);
+
void init(QV4::ExecutionContext *scope, QV4::FunctionObject *target, const Value &boundThis, QV4::MemberData *boundArgs);
- Pointer<FunctionObject> target;
- Value boundThis;
- Pointer<MemberData> boundArgs;
};
}
@@ -156,14 +161,11 @@ struct Q_QML_EXPORT FunctionObject: Object {
static Heap::FunctionObject *createScriptFunction(ExecutionContext *scope, Function *function);
- bool needsActivation() const { return d()->needsActivation(); }
bool strictMode() const { return d()->function ? d()->function->isStrict() : false; }
bool isBinding() const;
bool isBoundFunction() const;
QQmlSourceLocation sourceLocation() const;
-
- static void markObjects(Heap::Base *that, ExecutionEngine *e);
};
template<>
@@ -251,8 +253,6 @@ struct BoundFunction: FunctionObject {
static void construct(const Managed *, Scope &scope, CallData *d);
static void call(const Managed *that, Scope &scope, CallData *dd);
-
- static void markObjects(Heap::Base *that, ExecutionEngine *e);
};
}
diff --git a/src/qml/jsruntime/qv4global_p.h b/src/qml/jsruntime/qv4global_p.h
index a3ef395076..5cddf2eaa6 100644
--- a/src/qml/jsruntime/qv4global_p.h
+++ b/src/qml/jsruntime/qv4global_p.h
@@ -178,6 +178,7 @@ namespace Heap {
struct DataView;
struct TypedArray;
+ template <typename T, size_t> struct Pointer;
}
class MemoryManager;
@@ -192,9 +193,12 @@ struct ScriptFunction;
struct InternalClass;
struct Property;
struct Value;
+template<size_t> struct HeapValue;
+template<size_t> struct ValueArray;
struct Lookup;
struct ArrayData;
struct VTable;
+struct Function;
struct BooleanObject;
struct NumberObject;
@@ -252,6 +256,7 @@ enum PropertyFlag {
Attr_NotEnumerable = 0x4,
Attr_NotConfigurable = 0x8,
Attr_ReadOnly = Attr_NotWritable|Attr_NotEnumerable|Attr_NotConfigurable,
+ Attr_ReadOnly_ButConfigurable = Attr_NotWritable|Attr_NotEnumerable,
Attr_Invalid = 0xff
};
diff --git a/src/qml/jsruntime/qv4identifiertable_p.h b/src/qml/jsruntime/qv4identifiertable_p.h
index 89af5db731..b0b08f1e54 100644
--- a/src/qml/jsruntime/qv4identifiertable_p.h
+++ b/src/qml/jsruntime/qv4identifiertable_p.h
@@ -93,14 +93,14 @@ public:
Heap::String *stringFromIdentifier(Identifier *i);
- void mark(ExecutionEngine *e) {
+ void mark(MarkStack *markStack) {
for (int i = 0; i < alloc; ++i) {
Heap::String *entry = entries[i];
if (!entry || entry->isMarked())
continue;
entry->setMarkBit();
Q_ASSERT(entry->vtable()->markObjects);
- entry->vtable()->markObjects(entry, e);
+ entry->vtable()->markObjects(entry, markStack);
}
}
};
diff --git a/src/qml/jsruntime/qv4internalclass.cpp b/src/qml/jsruntime/qv4internalclass.cpp
index 0bcd510541..603da1df7b 100644
--- a/src/qml/jsruntime/qv4internalclass.cpp
+++ b/src/qml/jsruntime/qv4internalclass.cpp
@@ -133,48 +133,20 @@ InternalClass::InternalClass(const QV4::InternalClass &other)
static void insertHoleIntoPropertyData(Object *object, int idx)
{
- int inlineSize = object->d()->vtable()->nInlineProperties;
- int icSize = object->internalClass()->size;
- int from = qMax(idx, inlineSize);
- int to = from + 1;
- if (from < icSize) {
- memmove(object->propertyData(to), object->propertyData(from),
- (icSize - from - 1) * sizeof(Value));
- }
- if (from == idx)
- return;
- if (inlineSize < icSize)
- *object->propertyData(inlineSize) = *object->propertyData(inlineSize - 1);
- from = idx;
- to = from + 1;
- if (from < inlineSize - 1) {
- memmove(object->propertyData(to), object->propertyData(from),
- (inlineSize - from - 1) * sizeof(Value));
- }
+ Heap::Object *o = object->d();
+ ExecutionEngine *v4 = o->internalClass->engine;
+ int size = o->internalClass->size;
+ for (int i = size - 1; i > idx; --i)
+ o->setProperty(v4, i, *o->propertyData(i - 1));
}
static void removeFromPropertyData(Object *object, int idx, bool accessor = false)
{
- int inlineSize = object->d()->vtable()->nInlineProperties;
- int delta = (accessor ? 2 : 1);
- int oldSize = object->internalClass()->size + delta;
- int to = idx;
- int from = to + delta;
- if (from < inlineSize) {
- memmove(object->propertyData(to), object->d()->propertyData(from), (inlineSize - from)*sizeof(Value));
- to = inlineSize - delta;
- from = inlineSize;
- }
- if (to < inlineSize && from < oldSize) {
- Q_ASSERT(from >= inlineSize);
- memcpy(object->propertyData(to), object->d()->propertyData(from), (inlineSize - to)*sizeof(Value));
- to = inlineSize;
- from = inlineSize + delta;
- }
- if (from < oldSize) {
- Q_ASSERT(to >= inlineSize && from > to);
- memmove(object->propertyData(to), object->d()->propertyData(from), (oldSize - to)*sizeof(Value));
- }
+ Heap::Object *o = object->d();
+ ExecutionEngine *v4 = o->internalClass->engine;
+ int size = o->internalClass->size;
+ for (int i = idx; i < size; ++i)
+ o->setProperty(v4, i, *o->propertyData(i + (accessor ? 2 : 1)));
}
void InternalClass::changeMember(Object *object, String *string, PropertyAttributes data, uint *index)
@@ -188,7 +160,7 @@ void InternalClass::changeMember(Object *object, String *string, PropertyAttribu
object->setInternalClass(newClass);
if (newClass->size > oldClass->size) {
Q_ASSERT(newClass->size == oldClass->size + 1);
- insertHoleIntoPropertyData(object, idx + 1);
+ insertHoleIntoPropertyData(object, idx);
} else if (newClass->size < oldClass->size) {
Q_ASSERT(newClass->size == oldClass->size - 1);
removeFromPropertyData(object, idx + 1);
@@ -506,9 +478,9 @@ void InternalClass::destroy()
}
}
-void InternalClassPool::markObjects(ExecutionEngine *engine)
+void InternalClassPool::markObjects(MarkStack *markStack)
{
- InternalClass *ic = engine->internalClasses[EngineBase::Class_Empty];
+ InternalClass *ic = markStack->engine->internalClasses[EngineBase::Class_Empty];
Q_ASSERT(!ic->prototype);
// only need to go two levels into the IC hierarchy, as prototype changes
@@ -519,10 +491,10 @@ void InternalClassPool::markObjects(ExecutionEngine *engine)
InternalClass *ic2 = t.lookup;
for (auto &t2 : ic2->transitions) {
if (t2.flags == InternalClassTransition::PrototypeChange)
- t2.lookup->prototype->mark(engine);
+ t2.lookup->prototype->mark(markStack);
}
} else if (t.flags == InternalClassTransition::PrototypeChange) {
- t.lookup->prototype->mark(engine);
+ t.lookup->prototype->mark(markStack);
}
}
}
diff --git a/src/qml/jsruntime/qv4internalclass_p.h b/src/qml/jsruntime/qv4internalclass_p.h
index 9e8ab9e73e..df17074e72 100644
--- a/src/qml/jsruntime/qv4internalclass_p.h
+++ b/src/qml/jsruntime/qv4internalclass_p.h
@@ -64,6 +64,7 @@ struct String;
struct Object;
struct Identifier;
struct VTable;
+struct MarkStack;
struct PropertyHashData;
struct PropertyHash
@@ -305,7 +306,7 @@ private:
struct InternalClassPool : public QQmlJS::MemoryPool
{
- void markObjects(ExecutionEngine *engine);
+ void markObjects(MarkStack *markStack);
};
}
diff --git a/src/qml/jsruntime/qv4jsonobject.cpp b/src/qml/jsruntime/qv4jsonobject.cpp
index 1d571f53f3..0f021c8bd0 100644
--- a/src/qml/jsruntime/qv4jsonobject.cpp
+++ b/src/qml/jsruntime/qv4jsonobject.cpp
@@ -705,7 +705,7 @@ QString Stringify::Str(const QString &key, const Value &v)
if (replacerFunction) {
ScopedObject holder(scope, v4->newObject());
- holder->put(scope.engine, QString(), scope.result);
+ holder->put(scope.engine->id_empty(), scope.result);
ScopedCallData callData(scope, 2);
callData->args[0] = v4->newString(key);
callData->args[1] = scope.result;
diff --git a/src/qml/jsruntime/qv4lookup.cpp b/src/qml/jsruntime/qv4lookup.cpp
index 7a158ece35..afadf59bd5 100644
--- a/src/qml/jsruntime/qv4lookup.cpp
+++ b/src/qml/jsruntime/qv4lookup.cpp
@@ -60,7 +60,7 @@ ReturnedValue Lookup::lookup(const Value &thisObject, Object *o, PropertyAttribu
if (index != UINT_MAX) {
level = i;
*attrs = obj->internalClass->propertyData.at(index);
- Value *v = obj->propertyData(index);
+ const Value *v = obj->propertyData(index);
return !attrs->isAccessor() ? v->asReturnedValue() : Object::getValue(thisObject, *v, *attrs);
}
@@ -73,7 +73,7 @@ ReturnedValue Lookup::lookup(const Value &thisObject, Object *o, PropertyAttribu
index = obj->internalClass->find(name);
if (index != UINT_MAX) {
*attrs = obj->internalClass->propertyData.at(index);
- Value *v = obj->propertyData(index);
+ const Value *v = obj->propertyData(index);
return !attrs->isAccessor() ? v->asReturnedValue() : Object::getValue(thisObject, *v, *attrs);
}
@@ -95,7 +95,7 @@ ReturnedValue Lookup::lookup(const Object *thisObject, PropertyAttributes *attrs
if (index != UINT_MAX) {
level = i;
*attrs = obj->internalClass->propertyData.at(index);
- Value *v = obj->propertyData(index);
+ const Value *v = obj->propertyData(index);
return !attrs->isAccessor() ? v->asReturnedValue() : thisObject->getValue(*v, *attrs);
}
@@ -108,7 +108,7 @@ ReturnedValue Lookup::lookup(const Object *thisObject, PropertyAttributes *attrs
index = obj->internalClass->find(name);
if (index != UINT_MAX) {
*attrs = obj->internalClass->propertyData.at(index);
- Value *v = obj->propertyData(index);
+ const Value *v = obj->propertyData(index);
return !attrs->isAccessor() ? v->asReturnedValue() : thisObject->getValue(*v, *attrs);
}
@@ -117,20 +117,20 @@ ReturnedValue Lookup::lookup(const Object *thisObject, PropertyAttributes *attrs
return Primitive::emptyValue().asReturnedValue();
}
-ReturnedValue Lookup::indexedGetterGeneric(Lookup *l, const Value &object, const Value &index)
+ReturnedValue Lookup::indexedGetterGeneric(Lookup *l, ExecutionEngine *engine, const Value &object, const Value &index)
{
uint idx;
if (object.isObject() && index.asArrayIndex(idx)) {
l->indexedGetter = indexedGetterObjectInt;
- return indexedGetterObjectInt(l, object, index);
+ return indexedGetterObjectInt(l, engine, object, index);
}
- return indexedGetterFallback(l, object, index);
+ return indexedGetterFallback(l, engine, object, index);
}
-ReturnedValue Lookup::indexedGetterFallback(Lookup *l, const Value &object, const Value &index)
+ReturnedValue Lookup::indexedGetterFallback(Lookup *l, ExecutionEngine *engine, const Value &object, const Value &index)
{
Q_UNUSED(l);
- Scope scope(l->engine);
+ Scope scope(engine);
uint idx = 0;
bool isInt = index.asArrayIndex(idx);
@@ -148,7 +148,7 @@ ReturnedValue Lookup::indexedGetterFallback(Lookup *l, const Value &object, cons
if (object.isNullOrUndefined()) {
QString message = QStringLiteral("Cannot read property '%1' of %2").arg(index.toQStringNoThrow()).arg(object.toQStringNoThrow());
- return l->engine->throwTypeError(message);
+ return engine->throwTypeError(message);
}
o = RuntimeHelpers::convertToObject(scope.engine, object);
@@ -174,7 +174,7 @@ ReturnedValue Lookup::indexedGetterFallback(Lookup *l, const Value &object, cons
}
-ReturnedValue Lookup::indexedGetterObjectInt(Lookup *l, const Value &object, const Value &index)
+ReturnedValue Lookup::indexedGetterObjectInt(Lookup *l, ExecutionEngine *engine, const Value &object, const Value &index)
{
uint idx;
if (index.asArrayIndex(idx)) {
@@ -183,7 +183,7 @@ ReturnedValue Lookup::indexedGetterObjectInt(Lookup *l, const Value &object, con
Heap::Object *o = static_cast<Heap::Object *>(b);
if (o->arrayData && o->arrayData->type == Heap::ArrayData::Simple) {
Heap::SimpleArrayData *s = o->arrayData.cast<Heap::SimpleArrayData>();
- if (idx < s->len)
+ if (idx < s->values.size)
if (!s->data(idx).isEmpty())
return s->data(idx).asReturnedValue();
}
@@ -191,25 +191,25 @@ ReturnedValue Lookup::indexedGetterObjectInt(Lookup *l, const Value &object, con
}
}
- return indexedGetterFallback(l, object, index);
+ return indexedGetterFallback(l, engine, object, index);
}
-void Lookup::indexedSetterGeneric(Lookup *l, const Value &object, const Value &index, const Value &v)
+void Lookup::indexedSetterGeneric(Lookup *l, ExecutionEngine *engine, const Value &object, const Value &index, const Value &v)
{
if (Object *o = object.objectValue()) {
uint idx;
if (o->d()->arrayData && o->d()->arrayData->type == Heap::ArrayData::Simple && index.asArrayIndex(idx)) {
l->indexedSetter = indexedSetterObjectInt;
- indexedSetterObjectInt(l, object, index, v);
+ indexedSetterObjectInt(l, engine, object, index, v);
return;
}
}
- indexedSetterFallback(l, object, index, v);
+ indexedSetterFallback(l, engine, object, index, v);
}
-void Lookup::indexedSetterFallback(Lookup *l, const Value &object, const Value &index, const Value &value)
+void Lookup::indexedSetterFallback(Lookup *, ExecutionEngine *engine, const Value &object, const Value &index, const Value &value)
{
- Scope scope(l->engine);
+ Scope scope(engine);
ScopedObject o(scope, object.toObject(scope.engine));
if (scope.engine->hasException)
return;
@@ -218,8 +218,8 @@ void Lookup::indexedSetterFallback(Lookup *l, const Value &object, const Value &
if (index.asArrayIndex(idx)) {
if (o->d()->arrayData && o->d()->arrayData->type == Heap::ArrayData::Simple) {
Heap::SimpleArrayData *s = o->d()->arrayData.cast<Heap::SimpleArrayData>();
- if (idx < s->len) {
- s->data(idx) = value;
+ if (idx < s->values.size) {
+ s->setData(engine, idx, value);
return;
}
}
@@ -231,7 +231,7 @@ void Lookup::indexedSetterFallback(Lookup *l, const Value &object, const Value &
o->put(name, value);
}
-void Lookup::indexedSetterObjectInt(Lookup *l, const Value &object, const Value &index, const Value &v)
+void Lookup::indexedSetterObjectInt(Lookup *l, ExecutionEngine *engine, const Value &object, const Value &index, const Value &v)
{
uint idx;
if (index.asArrayIndex(idx)) {
@@ -240,15 +240,15 @@ void Lookup::indexedSetterObjectInt(Lookup *l, const Value &object, const Value
Heap::Object *o = static_cast<Heap::Object *>(b);
if (o->arrayData && o->arrayData->type == Heap::ArrayData::Simple) {
Heap::SimpleArrayData *s = o->arrayData.cast<Heap::SimpleArrayData>();
- if (idx < s->len) {
- s->data(idx) = v;
+ if (idx < s->values.size) {
+ s->setData(engine, idx, v);
return;
}
}
}
}
}
- indexedSetterFallback(l, object, index, v);
+ indexedSetterFallback(l, engine, object, index, v);
}
ReturnedValue Lookup::getterGeneric(Lookup *l, ExecutionEngine *engine, const Value &object)
@@ -380,7 +380,7 @@ ReturnedValue Lookup::getter0MemberData(Lookup *l, ExecutionEngine *engine, cons
Heap::Object *o = static_cast<Heap::Object *>(object.heapObject());
if (o) {
if (l->classList[0] == o->internalClass)
- return o->memberData->data[l->index].asReturnedValue();
+ return o->memberData->values.data()[l->index].asReturnedValue();
}
return getterTwoClasses(l, engine, object);
}
@@ -452,7 +452,7 @@ ReturnedValue Lookup::getter0Inlinegetter0MemberData(Lookup *l, ExecutionEngine
if (l->classList[0] == o->internalClass)
return o->inlinePropertyData(l->index)->asReturnedValue();
if (l->classList[2] == o->internalClass)
- return o->memberData->data[l->index2].asReturnedValue();
+ return o->memberData->values.data()[l->index2].asReturnedValue();
}
l->getter = getterFallback;
return getterFallback(l, engine, object);
@@ -465,9 +465,9 @@ ReturnedValue Lookup::getter0MemberDatagetter0MemberData(Lookup *l, ExecutionEng
Heap::Object *o = static_cast<Heap::Object *>(object.heapObject());
if (o) {
if (l->classList[0] == o->internalClass)
- return o->memberData->data[l->index].asReturnedValue();
+ return o->memberData->values.data()[l->index].asReturnedValue();
if (l->classList[2] == o->internalClass)
- return o->memberData->data[l->index2].asReturnedValue();
+ return o->memberData->values.data()[l->index2].asReturnedValue();
}
l->getter = getterFallback;
return getterFallback(l, engine, object);
@@ -495,7 +495,7 @@ ReturnedValue Lookup::getter0MemberDatagetter1(Lookup *l, ExecutionEngine *engin
Heap::Object *o = static_cast<Heap::Object *>(object.heapObject());
if (o) {
if (l->classList[0] == o->internalClass)
- return o->memberData->data[l->index].asReturnedValue();
+ return o->memberData->values.data()[l->index].asReturnedValue();
if (l->classList[2] == o->internalClass && l->classList[3] == o->prototype()->internalClass)
return o->prototype()->propertyData(l->index2)->asReturnedValue();
}
@@ -611,7 +611,7 @@ ReturnedValue Lookup::primitiveGetter0MemberData(Lookup *l, ExecutionEngine *eng
if (object.type() == l->type) {
Heap::Object *o = l->proto;
if (l->classList[0] == o->internalClass)
- return o->memberData->data[l->index].asReturnedValue();
+ return o->memberData->values.data()[l->index].asReturnedValue();
}
l->getter = getterGeneric;
return getterGeneric(l, engine, object);
@@ -738,7 +738,7 @@ ReturnedValue Lookup::globalGetter0MemberData(Lookup *l, ExecutionEngine *engine
{
Object *o = engine->globalObject;
if (l->classList[0] == o->internalClass())
- return o->d()->memberData->data[l->index].asReturnedValue();
+ return o->d()->memberData->values.data()[l->index].asReturnedValue();
l->globalGetter = globalGetterGeneric;
return globalGetterGeneric(l, engine);
@@ -880,7 +880,7 @@ void Lookup::setter0(Lookup *l, ExecutionEngine *engine, Value &object, const Va
{
Object *o = static_cast<Object *>(object.managed());
if (o && o->internalClass() == l->classList[0]) {
- *o->propertyData(l->index) = value;
+ o->setProperty(engine, l->index, value);
return;
}
@@ -891,7 +891,7 @@ void Lookup::setter0Inline(Lookup *l, ExecutionEngine *engine, Value &object, co
{
Object *o = static_cast<Object *>(object.managed());
if (o && o->internalClass() == l->classList[0]) {
- *o->d()->inlinePropertyData(l->index) = value;
+ o->d()->setInlineProperty(engine, l->index, value);
return;
}
@@ -904,7 +904,7 @@ void Lookup::setterInsert0(Lookup *l, ExecutionEngine *engine, Value &object, co
if (o && o->internalClass() == l->classList[0]) {
Q_ASSERT(!o->prototype());
o->setInternalClass(l->classList[3]);
- *o->propertyData(l->index) = value;
+ o->setProperty(l->index, value);
return;
}
@@ -921,7 +921,7 @@ void Lookup::setterInsert1(Lookup *l, ExecutionEngine *engine, Value &object, co
if (p->internalClass == l->classList[1]) {
Q_ASSERT(!p->prototype());
o->setInternalClass(l->classList[3]);
- *o->propertyData(l->index) = value;
+ o->setProperty(l->index, value);
return;
}
}
@@ -942,7 +942,7 @@ void Lookup::setterInsert2(Lookup *l, ExecutionEngine *engine, Value &object, co
if (p->internalClass == l->classList[2]) {
Q_ASSERT(!p->prototype());
o->setInternalClass(l->classList[3]);
- *o->propertyData(l->index) = value;
+ o->setProperty(l->index, value);
return;
}
}
@@ -957,11 +957,11 @@ void Lookup::setter0setter0(Lookup *l, ExecutionEngine *engine, Value &object, c
Object *o = static_cast<Object *>(object.managed());
if (o) {
if (o->internalClass() == l->classList[0]) {
- *o->propertyData(l->index) = value;
+ o->setProperty(l->index, value);
return;
}
if (o->internalClass() == l->classList[1]) {
- *o->propertyData(l->index2) = value;
+ o->setProperty(l->index2, value);
return;
}
}
diff --git a/src/qml/jsruntime/qv4lookup_p.h b/src/qml/jsruntime/qv4lookup_p.h
index 151231991f..ce5189a780 100644
--- a/src/qml/jsruntime/qv4lookup_p.h
+++ b/src/qml/jsruntime/qv4lookup_p.h
@@ -67,14 +67,13 @@ namespace QV4 {
struct Lookup {
enum { Size = 4 };
union {
- ReturnedValue (*indexedGetter)(Lookup *l, const Value &object, const Value &index);
- void (*indexedSetter)(Lookup *l, const Value &object, const Value &index, const Value &v);
+ ReturnedValue (*indexedGetter)(Lookup *l, ExecutionEngine *engine, const Value &object, const Value &index);
+ void (*indexedSetter)(Lookup *l, ExecutionEngine *engine, const Value &object, const Value &index, const Value &v);
ReturnedValue (*getter)(Lookup *l, ExecutionEngine *engine, const Value &object);
ReturnedValue (*globalGetter)(Lookup *l, ExecutionEngine *engine);
void (*setter)(Lookup *l, ExecutionEngine *engine, Value &object, const Value &v);
};
union {
- ExecutionEngine *engine;
InternalClass *classList[Size];
struct {
void *dummy0;
@@ -91,13 +90,13 @@ struct Lookup {
uint index;
uint nameIndex;
- static ReturnedValue indexedGetterGeneric(Lookup *l, const Value &object, const Value &index);
- static ReturnedValue indexedGetterFallback(Lookup *l, const Value &object, const Value &index);
- static ReturnedValue indexedGetterObjectInt(Lookup *l, const Value &object, const Value &index);
+ static ReturnedValue indexedGetterGeneric(Lookup *l, ExecutionEngine *engine, const Value &object, const Value &index);
+ static ReturnedValue indexedGetterFallback(Lookup *l, ExecutionEngine *engine, const Value &object, const Value &index);
+ static ReturnedValue indexedGetterObjectInt(Lookup *l, ExecutionEngine *engine, const Value &object, const Value &index);
- static void indexedSetterGeneric(Lookup *l, const Value &object, const Value &index, const Value &v);
- static void indexedSetterFallback(Lookup *l, const Value &object, const Value &index, const Value &value);
- static void indexedSetterObjectInt(Lookup *l, const Value &object, const Value &index, const Value &v);
+ static void indexedSetterGeneric(Lookup *l, ExecutionEngine *engine, const Value &object, const Value &index, const Value &v);
+ static void indexedSetterFallback(Lookup *l, ExecutionEngine *engine, const Value &object, const Value &index, const Value &value);
+ static void indexedSetterObjectInt(Lookup *l, ExecutionEngine *engine, const Value &object, const Value &index, const Value &v);
static ReturnedValue getterGeneric(Lookup *l, ExecutionEngine *engine, const Value &object);
static ReturnedValue getterTwoClasses(Lookup *l, ExecutionEngine *engine, const Value &object);
@@ -154,7 +153,6 @@ Q_STATIC_ASSERT(std::is_standard_layout<Lookup>::value);
// across 32-bit and 64-bit (matters when cross-compiling).
Q_STATIC_ASSERT(offsetof(Lookup, indexedGetter) == 0);
Q_STATIC_ASSERT(offsetof(Lookup, getter) == 0);
-Q_STATIC_ASSERT(offsetof(Lookup, engine) == offsetof(Lookup, getter) + QT_POINTER_SIZE);
}
diff --git a/src/qml/jsruntime/qv4managed.cpp b/src/qml/jsruntime/qv4managed.cpp
index 200380eda0..e00eaa0d9b 100644
--- a/src/qml/jsruntime/qv4managed.cpp
+++ b/src/qml/jsruntime/qv4managed.cpp
@@ -49,6 +49,7 @@ const VTable Managed::static_vtbl =
0,
0,
0,
+ 0,
Managed::IsExecutionContext,
Managed::IsString,
Managed::IsObject,
diff --git a/src/qml/jsruntime/qv4managed_p.h b/src/qml/jsruntime/qv4managed_p.h
index 6859334797..40dfc244ea 100644
--- a/src/qml/jsruntime/qv4managed_p.h
+++ b/src/qml/jsruntime/qv4managed_p.h
@@ -54,6 +54,7 @@
#include "qv4value_p.h"
#include "qv4enginebase_p.h"
#include <private/qv4heap_p.h>
+#include <private/qv4writebarrier_p.h>
QT_BEGIN_NAMESPACE
@@ -92,6 +93,7 @@ inline void qYouForgotTheQ_MANAGED_Macro(T1, T2) {}
dptr->_checkIsInitialized(); \
return dptr; \
} \
+ static Q_CONSTEXPR quint64 markTable = QV4::Heap::DataClass::markTable; \
V4_ASSERT_IS_TRIVIAL(QV4::Heap::DataClass)
#define V4_MANAGED(DataClass, superClass) \
@@ -130,6 +132,7 @@ inline void qYouForgotTheQ_MANAGED_Macro(T1, T2) {}
#define DEFINE_MANAGED_VTABLE_INT(classname, parentVTable) \
{ \
parentVTable, \
+ markTable, \
(sizeof(classname::Data) + sizeof(QV4::Value) - 1)/sizeof(QV4::Value), \
(sizeof(classname::Data) + (std::is_same<classname, Object>::value ? 2*sizeof(QV4::Value) : 0) + QV4::Chunk::SlotSize - 1)/QV4::Chunk::SlotSize*QV4::Chunk::SlotSize/sizeof(QV4::Value) \
- (sizeof(classname::Data) + sizeof(QV4::Value) - 1)/sizeof(QV4::Value), \
@@ -143,7 +146,7 @@ inline void qYouForgotTheQ_MANAGED_Macro(T1, T2) {}
classname::MyType, \
#classname, \
Q_VTABLE_FUNCTION(classname, destroy), \
- markObjects, \
+ Q_VTABLE_FUNCTION(classname, markObjects), \
isEqualTo \
}
@@ -215,8 +218,10 @@ public:
bool inUse() const { return d()->inUse(); }
bool markBit() const { return d()->isMarked(); }
+ inline void mark(MarkStack *markStack);
static void destroy(Heap::Base *) {}
+ static void markObjects(Heap::Base *, MarkStack *) {}
Q_ALWAYS_INLINE Heap::Base *heapObject() const {
return m();
diff --git a/src/qml/jsruntime/qv4mathobject.cpp b/src/qml/jsruntime/qv4mathobject.cpp
index 109d6c38b5..8782e6deae 100644
--- a/src/qml/jsruntime/qv4mathobject.cpp
+++ b/src/qml/jsruntime/qv4mathobject.cpp
@@ -42,6 +42,7 @@
#include <QtCore/qdatetime.h>
#include <QtCore/qmath.h>
+#include <QtCore/qrandom.h>
#include <QtCore/private/qnumeric_p.h>
#include <QtCore/qthreadstorage.h>
@@ -272,20 +273,9 @@ void MathObject::method_pow(const BuiltinFunction *, Scope &scope, CallData *cal
RETURN_RESULT(Encode(qt_qnan()));
}
-Q_GLOBAL_STATIC(QThreadStorage<bool *>, seedCreatedStorage);
-
void MathObject::method_random(const BuiltinFunction *, Scope &scope, CallData *)
{
- if (!seedCreatedStorage()->hasLocalData()) {
- int msecs = QTime(0,0,0).msecsTo(QTime::currentTime());
- Q_ASSERT(msecs >= 0);
- qsrand(uint(uint(msecs) ^ reinterpret_cast<quintptr>(scope.engine)));
- seedCreatedStorage()->setLocalData(new bool(true));
- }
- // rand()/qrand() return a value where the upperbound is RAND_MAX inclusive. So, instead of
- // dividing by RAND_MAX (which would return 0..RAND_MAX inclusive), we divide by RAND_MAX + 1.
- qint64 upperLimit = qint64(RAND_MAX) + 1;
- RETURN_RESULT(Encode(qrand() / double(upperLimit)));
+ RETURN_RESULT(Encode(QRandomGenerator::global()->generateDouble()));
}
void MathObject::method_round(const BuiltinFunction *, Scope &scope, CallData *callData)
diff --git a/src/qml/jsruntime/qv4memberdata.cpp b/src/qml/jsruntime/qv4memberdata.cpp
index db45c77472..8f862d63e9 100644
--- a/src/qml/jsruntime/qv4memberdata.cpp
+++ b/src/qml/jsruntime/qv4memberdata.cpp
@@ -45,24 +45,19 @@ using namespace QV4;
DEFINE_MANAGED_VTABLE(MemberData);
-void MemberData::markObjects(Heap::Base *that, ExecutionEngine *e)
-{
- Heap::MemberData *m = static_cast<Heap::MemberData *>(that);
- for (uint i = 0; i < m->size; ++i)
- m->data[i].mark(e);
-}
-
Heap::MemberData *MemberData::allocate(ExecutionEngine *e, uint n, Heap::MemberData *old)
{
- Q_ASSERT(!old || old->size < n);
+ Q_ASSERT(!old || old->values.size < n);
Q_ASSERT(n);
size_t alloc = MemoryManager::align(sizeof(Heap::MemberData) + (n - 1)*sizeof(Value));
Heap::MemberData *m = e->memoryManager->allocManaged<MemberData>(alloc);
if (old)
- memcpy(m, old, sizeof(Heap::MemberData) + (old->size - 1)* sizeof(Value));
+ // no write barrier required here
+ memcpy(m, old, sizeof(Heap::MemberData) + (old->values.size - 1) * sizeof(Value));
else
m->init();
- m->size = static_cast<uint>((alloc - sizeof(Heap::MemberData) + sizeof(Value))/sizeof(Value));
+ m->values.alloc = static_cast<uint>((alloc - sizeof(Heap::MemberData) + sizeof(Value))/sizeof(Value));
+ m->values.size = m->values.alloc;
return m;
}
diff --git a/src/qml/jsruntime/qv4memberdata_p.h b/src/qml/jsruntime/qv4memberdata_p.h
index e239458849..bae524d088 100644
--- a/src/qml/jsruntime/qv4memberdata_p.h
+++ b/src/qml/jsruntime/qv4memberdata_p.h
@@ -59,12 +59,11 @@ namespace QV4 {
namespace Heap {
-struct MemberData : Base {
- union {
- uint size;
- double _dummy;
- };
- Value data[1];
+#define MemberDataMembers(class, Member) \
+ Member(class, ValueArray, ValueArray, values)
+
+DECLARE_HEAP_OBJECT(MemberData, Base) {
+ DECLARE_MARK_TABLE(MemberData);
};
V4_ASSERT_IS_TRIVIAL(MemberData)
@@ -75,14 +74,26 @@ struct MemberData : Managed
V4_MANAGED(MemberData, Managed)
V4_INTERNALCLASS(MemberData)
- Value &operator[] (uint idx) { return d()->data[idx]; }
- const Value *data() const { return d()->data; }
- Value *data() { return d()->data; }
- inline uint size() const { return d()->size; }
+ struct Index {
+ Heap::Base *base;
+ Value *slot;
- static Heap::MemberData *allocate(QV4::ExecutionEngine *e, uint n, Heap::MemberData *old = 0);
+ void set(EngineBase *e, Value newVal) {
+ WriteBarrier::write(e, base, slot, newVal);
+ }
+ const Value *operator->() const { return slot; }
+ const Value &operator*() const { return *slot; }
+ bool isNull() const { return !slot; }
+ };
- static void markObjects(Heap::Base *that, ExecutionEngine *e);
+ const Value &operator[] (uint idx) const { return d()->values[idx]; }
+ const Value *data() const { return d()->values.data(); }
+ void set(EngineBase *e, uint index, Value v) { d()->values.set(e, index, v); }
+ void set(EngineBase *e, uint index, Heap::Base *b) { d()->values.set(e, index, b); }
+
+ inline uint size() const { return d()->values.size; }
+
+ static Heap::MemberData *allocate(QV4::ExecutionEngine *e, uint n, Heap::MemberData *old = 0);
};
}
diff --git a/src/qml/jsruntime/qv4numberobject.cpp b/src/qml/jsruntime/qv4numberobject.cpp
index 255d0212c1..d5c80dbf80 100644
--- a/src/qml/jsruntime/qv4numberobject.cpp
+++ b/src/qml/jsruntime/qv4numberobject.cpp
@@ -102,6 +102,8 @@ void NumberPrototype::init(ExecutionEngine *engine, Object *ctor)
ctor->defineReadonlyProperty(QStringLiteral("POSITIVE_INFINITY"), Primitive::fromDouble(qInf()));
ctor->defineReadonlyProperty(QStringLiteral("MAX_VALUE"), Primitive::fromDouble(1.7976931348623158e+308));
ctor->defineReadonlyProperty(QStringLiteral("EPSILON"), Primitive::fromDouble(std::numeric_limits<double>::epsilon()));
+ ctor->defineReadonlyProperty(QStringLiteral("MAX_SAFE_INTEGER"), Primitive::fromDouble(9007199254740991));
+ ctor->defineReadonlyProperty(QStringLiteral("MIN_SAFE_INTEGER"), Primitive::fromDouble(-9007199254740991));
QT_WARNING_PUSH
QT_WARNING_DISABLE_INTEL(239)
@@ -109,15 +111,17 @@ QT_WARNING_DISABLE_INTEL(239)
QT_WARNING_POP
ctor->defineDefaultProperty(QStringLiteral("isFinite"), method_isFinite, 1);
+ ctor->defineDefaultProperty(QStringLiteral("isInteger"), method_isInteger, 1);
+ ctor->defineDefaultProperty(QStringLiteral("isSafeInteger"), method_isSafeInteger, 1);
ctor->defineDefaultProperty(QStringLiteral("isNaN"), method_isNaN, 1);
defineDefaultProperty(QStringLiteral("constructor"), (o = ctor));
- defineDefaultProperty(engine->id_toString(), method_toString);
+ defineDefaultProperty(engine->id_toString(), method_toString, 1);
defineDefaultProperty(QStringLiteral("toLocaleString"), method_toLocaleString);
defineDefaultProperty(engine->id_valueOf(), method_valueOf);
defineDefaultProperty(QStringLiteral("toFixed"), method_toFixed, 1);
- defineDefaultProperty(QStringLiteral("toExponential"), method_toExponential);
- defineDefaultProperty(QStringLiteral("toPrecision"), method_toPrecision);
+ defineDefaultProperty(QStringLiteral("toExponential"), method_toExponential, 1);
+ defineDefaultProperty(QStringLiteral("toPrecision"), method_toPrecision, 1);
}
inline ReturnedValue thisNumberValue(Scope &scope, CallData *callData)
@@ -155,6 +159,52 @@ void NumberPrototype::method_isFinite(const BuiltinFunction *, Scope &scope, Cal
scope.result = Encode(!std::isnan(v) && !qt_is_inf(v));
}
+void NumberPrototype::method_isInteger(const BuiltinFunction *, Scope &scope, CallData *callData)
+{
+ if (!callData->argc) {
+ scope.result = Encode(false);
+ return;
+ }
+
+ const Value &v = callData->args[0];
+ if (!v.isNumber()) {
+ scope.result = Encode(false);
+ return;
+ }
+
+ double dv = v.toNumber();
+ if (std::isnan(dv) || qt_is_inf(dv)) {
+ scope.result = Encode(false);
+ return;
+ }
+
+ double iv = v.toInteger();
+ scope.result = Encode(dv == iv);
+}
+
+void NumberPrototype::method_isSafeInteger(const BuiltinFunction *, Scope &scope, CallData *callData)
+{
+ if (!callData->argc) {
+ scope.result = Encode(false);
+ return;
+ }
+
+ const Value &v = callData->args[0];
+ if (!v.isNumber()) {
+ scope.result = Encode(false);
+ return;
+ }
+
+ double dv = v.toNumber();
+ if (std::isnan(dv) || qt_is_inf(dv)) {
+ scope.result = Encode(false);
+ return;
+ }
+
+ double iv = v.toInteger();
+ scope.result = Encode(dv == iv && std::fabs(iv) <= (2^53)-1);
+}
+
void NumberPrototype::method_isNaN(const BuiltinFunction *, Scope &scope, CallData *callData)
{
if (!callData->argc) {
diff --git a/src/qml/jsruntime/qv4numberobject_p.h b/src/qml/jsruntime/qv4numberobject_p.h
index 85d306020c..0bc2cd8c65 100644
--- a/src/qml/jsruntime/qv4numberobject_p.h
+++ b/src/qml/jsruntime/qv4numberobject_p.h
@@ -89,6 +89,8 @@ struct NumberPrototype: NumberObject
void init(ExecutionEngine *engine, Object *ctor);
static void method_isFinite(const BuiltinFunction *, Scope &scope, CallData *callData);
+ static void method_isInteger(const BuiltinFunction *, Scope &scope, CallData *callData);
+ static void method_isSafeInteger(const BuiltinFunction *, Scope &scope, CallData *callData);
static void method_isNaN(const BuiltinFunction *, Scope &scope, CallData *callData);
static void method_toString(const BuiltinFunction *, Scope &scope, CallData *callData);
static void method_toLocaleString(const BuiltinFunction *, Scope &scope, CallData *callData);
diff --git a/src/qml/jsruntime/qv4object.cpp b/src/qml/jsruntime/qv4object.cpp
index 98f5c7464f..94d5a74fe5 100644
--- a/src/qml/jsruntime/qv4object.cpp
+++ b/src/qml/jsruntime/qv4object.cpp
@@ -67,8 +67,8 @@ void Object::setInternalClass(InternalClass *ic)
return;
bool hasMD = d()->memberData != nullptr;
uint requiredSize = ic->size - nInline;
- if (!hasMD || (hasMD && d()->memberData->size < requiredSize))
- d()->memberData = MemberData::allocate(ic->engine, requiredSize, d()->memberData);
+ if (!(hasMD && requiredSize) || (hasMD && d()->memberData->values.size < requiredSize))
+ d()->memberData.set(ic->engine, MemberData::allocate(ic->engine, requiredSize, d()->memberData));
}
void Object::getProperty(uint index, Property *p, PropertyAttributes *attrs) const
@@ -81,9 +81,9 @@ void Object::getProperty(uint index, Property *p, PropertyAttributes *attrs) con
void Object::setProperty(uint index, const Property *p)
{
- *propertyData(index) = p->value;
+ setProperty(index, p->value);
if (internalClass()->propertyData.at(index).isAccessor())
- *propertyData(index + SetterOffset) = p->set;
+ setProperty(index + SetterOffset, p->set);
}
bool Object::setPrototype(Object *proto)
@@ -99,13 +99,6 @@ bool Object::setPrototype(Object *proto)
return true;
}
-void Object::put(ExecutionEngine *engine, const QString &name, const Value &value)
-{
- Scope scope(engine);
- ScopedString n(scope, engine->newString(name));
- put(n, value);
-}
-
ReturnedValue Object::getValue(const Value &thisObject, const Value &v, PropertyAttributes attrs)
{
if (!attrs.isAccessor())
@@ -121,16 +114,16 @@ ReturnedValue Object::getValue(const Value &thisObject, const Value &v, Property
return scope.result.asReturnedValue();
}
-void Object::putValue(uint memberIndex, const Value &value)
+bool Object::putValue(uint memberIndex, const Value &value)
{
QV4::InternalClass *ic = internalClass();
if (ic->engine->hasException)
- return;
+ return false;
PropertyAttributes attrs = ic->propertyData[memberIndex];
if (attrs.isAccessor()) {
- FunctionObject *set = propertyData(memberIndex + SetterOffset)->as<FunctionObject>();
+ const FunctionObject *set = propertyData(memberIndex + SetterOffset)->as<FunctionObject>();
if (set) {
Scope scope(ic->engine);
ScopedFunctionObject setter(scope, set);
@@ -138,7 +131,7 @@ void Object::putValue(uint memberIndex, const Value &value)
callData->args[0] = value;
callData->thisObject = this;
setter->call(scope, callData);
- return;
+ return !ic->engine->hasException;
}
goto reject;
}
@@ -146,12 +139,13 @@ void Object::putValue(uint memberIndex, const Value &value)
if (!attrs.isWritable())
goto reject;
- *propertyData(memberIndex) = value;
- return;
+ setProperty(memberIndex, value);
+ return true;
reject:
if (engine()->current->strictMode)
engine()->throwTypeError();
+ return false;
}
void Object::defineDefaultProperty(const QString &name, const Value &value)
@@ -169,7 +163,7 @@ void Object::defineDefaultProperty(const QString &name, void (*code)(const Built
ScopedString s(scope, e->newIdentifier(name));
ExecutionContext *global = e->rootContext();
ScopedFunctionObject function(scope, BuiltinFunction::create(global, s, code));
- function->defineReadonlyProperty(e->id_length(), Primitive::fromInt32(argumentCount));
+ function->defineReadonlyConfigurableProperty(e->id_length(), Primitive::fromInt32(argumentCount));
defineDefaultProperty(s, function);
}
@@ -179,7 +173,7 @@ void Object::defineDefaultProperty(String *name, void (*code)(const BuiltinFunct
Scope scope(e);
ExecutionContext *global = e->rootContext();
ScopedFunctionObject function(scope, BuiltinFunction::create(global, name, code));
- function->defineReadonlyProperty(e->id_length(), Primitive::fromInt32(argumentCount));
+ function->defineReadonlyConfigurableProperty(e->id_length(), Primitive::fromInt32(argumentCount));
defineDefaultProperty(name, function);
}
@@ -217,19 +211,27 @@ void Object::defineReadonlyProperty(String *name, const Value &value)
insertMember(name, value, Attr_ReadOnly);
}
-void Object::markObjects(Heap::Base *that, ExecutionEngine *e)
+void Object::defineReadonlyConfigurableProperty(const QString &name, const Value &value)
{
- Heap::Object *o = static_cast<Heap::Object *>(that);
+ QV4::ExecutionEngine *e = engine();
+ Scope scope(e);
+ ScopedString s(scope, e->newIdentifier(name));
+ defineReadonlyConfigurableProperty(s, value);
+}
- if (o->memberData)
- o->memberData->mark(e);
- if (o->arrayData)
- o->arrayData->mark(e);
+void Object::defineReadonlyConfigurableProperty(String *name, const Value &value)
+{
+ insertMember(name, value, Attr_ReadOnly_ButConfigurable);
+}
+
+void Object::markObjects(Heap::Base *b, MarkStack *stack)
+{
+ Heap::Object *o = static_cast<Heap::Object *>(b);
uint nInline = o->vtable()->nInlineProperties;
Value *v = reinterpret_cast<Value *>(o) + o->vtable()->inlinePropertyOffset;
const Value *end = v + nInline;
while (v < end) {
- v->mark(e);
+ v->mark(stack);
++v;
}
}
@@ -240,10 +242,10 @@ void Object::insertMember(String *s, const Property *p, PropertyAttributes attri
InternalClass::addMember(this, s, attributes, &idx);
if (attributes.isAccessor()) {
- *propertyData(idx + GetterOffset) = p->value;
- *propertyData(idx + SetterOffset) = p->set;
+ setProperty(idx + GetterOffset, p->value);
+ setProperty(idx + SetterOffset, p->set);
} else {
- *propertyData(idx) = p->value;
+ setProperty(idx, p->value);
}
}
@@ -275,12 +277,9 @@ void Object::getOwnProperty(String *name, PropertyAttributes *attrs, Property *p
void Object::getOwnProperty(uint index, PropertyAttributes *attrs, Property *p)
{
- Property *pd = arrayData() ? arrayData()->getProperty(index) : 0;
- if (pd) {
- *attrs = arrayData()->attributes(index);
- if (p)
- p->copy(pd, *attrs);
- return;
+ if (arrayData()) {
+ if (arrayData()->getProperty(index, p, attrs))
+ return;
}
if (isStringObject()) {
*attrs = Attr_NotConfigurable|Attr_NotWritable;
@@ -295,7 +294,7 @@ void Object::getOwnProperty(uint index, PropertyAttributes *attrs, Property *p)
}
// Section 8.12.2
-Value *Object::getValueOrSetter(String *name, PropertyAttributes *attrs)
+MemberData::Index Object::getValueOrSetter(String *name, PropertyAttributes *attrs)
{
Q_ASSERT(name->asArrayIndex() == UINT_MAX);
@@ -307,36 +306,38 @@ Value *Object::getValueOrSetter(String *name, PropertyAttributes *attrs)
uint idx = o->internalClass->find(id);
if (idx < UINT_MAX) {
*attrs = o->internalClass->propertyData[idx];
- return o->propertyData(attrs->isAccessor() ? idx + SetterOffset : idx);
+ return o->writablePropertyData(attrs->isAccessor() ? idx + SetterOffset : idx );
}
o = o->prototype();
}
*attrs = Attr_Invalid;
- return 0;
+ return { 0, 0 };
}
-Value *Object::getValueOrSetter(uint index, PropertyAttributes *attrs)
+ArrayData::Index Object::getValueOrSetter(uint index, PropertyAttributes *attrs)
{
Heap::Object *o = d();
while (o) {
- Property *p = o->arrayData ? o->arrayData->getProperty(index) : 0;
- if (p) {
- *attrs = o->arrayData->attributes(index);
- return attrs->isAccessor() ? &p->set : &p->value;
+ if (o->arrayData) {
+ uint idx = o->arrayData->mappedIndex(index);
+ if (idx != UINT_MAX) {
+ *attrs = o->arrayData->attributes(index);
+ return { o->arrayData , attrs->isAccessor() ? idx + SetterOffset : idx };
+ }
}
if (o->vtable()->type == Type_StringObject) {
if (index < static_cast<const Heap::StringObject *>(o)->length()) {
// this is an evil hack, but it works, as the method is only ever called from putIndexed,
// where we don't use the returned pointer there for non writable attributes
*attrs = (Attr_NotWritable|Attr_NotConfigurable);
- return reinterpret_cast<Value *>(0x1);
+ return { reinterpret_cast<Heap::ArrayData *>(0x1), 0 };
}
}
o = o->prototype();
}
*attrs = Attr_Invalid;
- return 0;
+ return { 0, 0 };
}
bool Object::hasProperty(String *name) const
@@ -421,14 +422,14 @@ ReturnedValue Object::getIndexed(const Managed *m, uint index, bool *hasProperty
return static_cast<const Object *>(m)->internalGetIndexed(index, hasProperty);
}
-void Object::put(Managed *m, String *name, const Value &value)
+bool Object::put(Managed *m, String *name, const Value &value)
{
- static_cast<Object *>(m)->internalPut(name, value);
+ return static_cast<Object *>(m)->internalPut(name, value);
}
-void Object::putIndexed(Managed *m, uint index, const Value &value)
+bool Object::putIndexed(Managed *m, uint index, const Value &value)
{
- static_cast<Object *>(m)->internalPutIndexed(index, value);
+ return static_cast<Object *>(m)->internalPutIndexed(index, value);
}
PropertyAttributes Object::query(const Managed *m, String *name)
@@ -524,7 +525,7 @@ void Object::setLookup(Managed *m, Lookup *l, const Value &value)
l->classList[0] = o->internalClass();
l->index = idx;
l->setter = idx < o->d()->vtable()->nInlineProperties ? Lookup::setter0Inline : Lookup::setter0;
- *o->propertyData(idx) = value;
+ o->setProperty(idx, value);
return;
}
@@ -579,7 +580,7 @@ void Object::advanceIterator(Managed *m, ObjectIterator *it, Value *name, uint *
int k = it->arrayNode->key();
uint pidx = it->arrayNode->value;
Heap::SparseArrayData *sa = o->d()->arrayData.cast<Heap::SparseArrayData>();
- Property *p = reinterpret_cast<Property *>(sa->arrayData + pidx);
+ const Property *p = reinterpret_cast<const Property *>(sa->values.data() + pidx);
it->arrayNode = it->arrayNode->nextNode();
PropertyAttributes a = sa->attrs ? sa->attrs[pidx] : Attr_Data;
if (!(it->flags & ObjectIterator::EnumerableOnly) || a.isEnumerable()) {
@@ -594,9 +595,9 @@ void Object::advanceIterator(Managed *m, ObjectIterator *it, Value *name, uint *
it->arrayIndex = UINT_MAX;
}
// dense arrays
- while (it->arrayIndex < o->d()->arrayData->len) {
+ while (it->arrayIndex < o->d()->arrayData->values.size) {
Heap::SimpleArrayData *sa = o->d()->arrayData.cast<Heap::SimpleArrayData>();
- Value &val = sa->data(it->arrayIndex);
+ const Value &val = sa->data(it->arrayIndex);
PropertyAttributes a = o->arrayData()->attributes(it->arrayIndex);
++it->arrayIndex;
if (!val.isEmpty()
@@ -663,15 +664,14 @@ ReturnedValue Object::internalGet(String *name, bool *hasProperty) const
ReturnedValue Object::internalGetIndexed(uint index, bool *hasProperty) const
{
- Property *pd = 0;
PropertyAttributes attrs;
Scope scope(engine());
ScopedObject o(scope, this);
+ ScopedProperty pd(scope);
+ bool exists = false;
while (o) {
- Property *p = o->arrayData() ? o->arrayData()->getProperty(index) : 0;
- if (p) {
- pd = p;
- attrs = o->arrayData()->attributes(index);
+ if (o->arrayData() && o->arrayData()->getProperty(index, pd, &attrs)) {
+ exists = true;
break;
}
if (o->isStringObject()) {
@@ -686,7 +686,7 @@ ReturnedValue Object::internalGetIndexed(uint index, bool *hasProperty) const
o = o->prototype();
}
- if (pd) {
+ if (exists) {
if (hasProperty)
*hasProperty = true;
return getValue(pd->value, attrs);
@@ -699,10 +699,11 @@ ReturnedValue Object::internalGetIndexed(uint index, bool *hasProperty) const
// Section 8.12.5
-void Object::internalPut(String *name, const Value &value)
+bool Object::internalPut(String *name, const Value &value)
{
- if (internalClass()->engine->hasException)
- return;
+ ExecutionEngine *engine = this->engine();
+ if (engine->hasException)
+ return false;
uint idx = name->asArrayIndex();
if (idx != UINT_MAX)
@@ -711,45 +712,46 @@ void Object::internalPut(String *name, const Value &value)
name->makeIdentifier();
Identifier *id = name->identifier();
+ MemberData::Index memberIndex{0, 0};
uint member = internalClass()->find(id);
- Value *v = 0;
PropertyAttributes attrs;
if (member < UINT_MAX) {
attrs = internalClass()->propertyData[member];
- v = propertyData(attrs.isAccessor() ? member + SetterOffset : member);
+ memberIndex = d()->writablePropertyData(attrs.isAccessor() ? member + SetterOffset : member);
}
// clause 1
- if (v) {
+ if (!memberIndex.isNull()) {
if (attrs.isAccessor()) {
- if (v->as<FunctionObject>())
+ if (memberIndex->as<FunctionObject>())
goto cont;
goto reject;
} else if (!attrs.isWritable())
goto reject;
- else if (isArrayObject() && name->equals(engine()->id_length())) {
+ else if (isArrayObject() && name->equals(engine->id_length())) {
bool ok;
uint l = value.asArrayLength(&ok);
if (!ok) {
- engine()->throwRangeError(value);
- return;
+ engine->throwRangeError(value);
+ return false;
}
ok = setArrayLength(l);
if (!ok)
goto reject;
} else {
- *v = value;
+ memberIndex.set(engine, value);
}
- return;
+ return true;
} else if (!prototype()) {
if (!isExtensible())
goto reject;
} else {
// clause 4
- Scope scope(engine());
- if ((v = ScopedObject(scope, prototype())->getValueOrSetter(name, &attrs))) {
+ Scope scope(engine);
+ memberIndex = ScopedObject(scope, prototype())->getValueOrSetter(name, &attrs);
+ if (!memberIndex.isNull()) {
if (attrs.isAccessor()) {
- if (!v->as<FunctionObject>())
+ if (!memberIndex->as<FunctionObject>())
goto reject;
} else if (!isExtensible() || !attrs.isWritable()) {
goto reject;
@@ -762,64 +764,68 @@ void Object::internalPut(String *name, const Value &value)
cont:
// Clause 5
- if (v && attrs.isAccessor()) {
- Q_ASSERT(v->as<FunctionObject>());
+ if (!memberIndex.isNull() && attrs.isAccessor()) {
+ Q_ASSERT(memberIndex->as<FunctionObject>());
- Scope scope(engine());
- ScopedFunctionObject setter(scope, *v);
+ Scope scope(engine);
+ ScopedFunctionObject setter(scope, *memberIndex);
ScopedCallData callData(scope, 1);
callData->args[0] = value;
callData->thisObject = this;
setter->call(scope, callData);
- return;
+ return !internalClass()->engine->hasException;
}
insertMember(name, value);
- return;
+ return true;
reject:
- if (engine()->current->strictMode) {
+ // ### this should be removed once everything is ported to use Object::set()
+ if (engine->current->strictMode) {
QString message = QLatin1String("Cannot assign to read-only property \"") +
name->toQString() + QLatin1Char('\"');
- engine()->throwTypeError(message);
+ engine->throwTypeError(message);
}
+ return false;
}
-void Object::internalPutIndexed(uint index, const Value &value)
+bool Object::internalPutIndexed(uint index, const Value &value)
{
- if (internalClass()->engine->hasException)
- return;
+ ExecutionEngine *engine = this->engine();
+ if (engine->hasException)
+ return false;
PropertyAttributes attrs;
- Value *v = arrayData() ? arrayData()->getValueOrSetter(index, &attrs) : 0;
+ ArrayData::Index arrayIndex = arrayData() ? arrayData()->getValueOrSetter(index, &attrs) : ArrayData::Index{ 0, 0 };
- if (!v && isStringObject()) {
+ if (arrayIndex.isNull() && isStringObject()) {
if (index < static_cast<StringObject *>(this)->length())
// not writable
goto reject;
}
// clause 1
- if (v) {
+ if (!arrayIndex.isNull()) {
if (attrs.isAccessor()) {
- if (v->as<FunctionObject>())
+ if (arrayIndex->as<FunctionObject>())
goto cont;
goto reject;
} else if (!attrs.isWritable())
goto reject;
- else
- *v = value;
- return;
+
+ arrayIndex.set(engine, value);
+ return true;
} else if (!prototype()) {
if (!isExtensible())
goto reject;
} else {
// clause 4
- Scope scope(engine());
- if ((v = ScopedObject(scope, prototype())->getValueOrSetter(index, &attrs))) {
+ Scope scope(engine);
+ arrayIndex = ScopedObject(scope, prototype())->getValueOrSetter(index, &attrs);
+ if (!arrayIndex.isNull()) {
if (attrs.isAccessor()) {
- if (!v->as<FunctionObject>())
+ if (!arrayIndex->as<FunctionObject>())
goto reject;
} else if (!isExtensible() || !attrs.isWritable()) {
goto reject;
@@ -832,24 +838,26 @@ void Object::internalPutIndexed(uint index, const Value &value)
cont:
// Clause 5
- if (v && attrs.isAccessor()) {
- Q_ASSERT(v->as<FunctionObject>());
+ if (!arrayIndex.isNull() && attrs.isAccessor()) {
+ Q_ASSERT(arrayIndex->as<FunctionObject>());
- Scope scope(engine());
- ScopedFunctionObject setter(scope, *v);
+ Scope scope(engine);
+ ScopedFunctionObject setter(scope, *arrayIndex);
ScopedCallData callData(scope, 1);
callData->args[0] = value;
callData->thisObject = this;
setter->call(scope, callData);
- return;
+ return !internalClass()->engine->hasException;
}
arraySet(index, value);
- return;
+ return true;
reject:
- if (engine()->current->strictMode)
- engine()->throwTypeError();
+ // ### this should be removed once everything is ported to use Object::setIndexed()
+ if (engine->current->strictMode)
+ engine->throwTypeError();
+ return false;
}
// Section 8.12.7
@@ -978,8 +986,8 @@ bool Object::defineOwnProperty2(ExecutionEngine *engine, uint index, const Prope
// Clause 1
if (arrayData()) {
- hasProperty = arrayData()->getProperty(index);
- if (!hasProperty && isStringObject())
+ hasProperty = arrayData()->mappedIndex(index) != UINT_MAX;
+ if (!hasProperty && isStringObject())
hasProperty = (index < static_cast<StringObject *>(this)->length());
}
@@ -1091,7 +1099,7 @@ bool Object::__defineOwnProperty__(ExecutionEngine *engine, uint index, String *
setProperty(index, current);
} else {
setArrayAttributes(index, cattrs);
- arrayData()->setProperty(index, current);
+ arrayData()->setProperty(scope.engine, index, current);
}
return true;
reject:
@@ -1127,7 +1135,8 @@ void Object::copyArrayData(Object *other)
;
} else {
Q_ASSERT(!arrayData() && other->arrayData());
- ArrayData::realloc(this, other->d()->arrayData->type, other->d()->arrayData->alloc, false);
+ ArrayData::realloc(this, static_cast<ArrayData::Type>(other->d()->arrayData->type),
+ other->d()->arrayData->values.alloc, false);
if (other->arrayType() == Heap::ArrayData::Sparse) {
Heap::ArrayData *od = other->d()->arrayData;
Heap::ArrayData *dd = d()->arrayData;
@@ -1135,10 +1144,11 @@ void Object::copyArrayData(Object *other)
dd->freeList = od->freeList;
} else {
Heap::ArrayData *dd = d()->arrayData;
- dd->len = other->d()->arrayData->len;
+ dd->values.size = other->d()->arrayData->values.size;
dd->offset = other->d()->arrayData->offset;
}
- memcpy(d()->arrayData->arrayData, other->d()->arrayData->arrayData, other->d()->arrayData->alloc*sizeof(Value));
+ // ### need a write barrier
+ memcpy(d()->arrayData->values.values, other->d()->arrayData->values.values, other->d()->arrayData->values.alloc*sizeof(Value));
}
setArrayLengthUnchecked(other->getLength());
}
diff --git a/src/qml/jsruntime/qv4object_p.h b/src/qml/jsruntime/qv4object_p.h
index 9592ff5d1b..066a93cc61 100644
--- a/src/qml/jsruntime/qv4object_p.h
+++ b/src/qml/jsruntime/qv4object_p.h
@@ -67,7 +67,12 @@ struct BuiltinFunction;
namespace Heap {
-struct Object : Base {
+#define ObjectMembers(class, Member) \
+ Member(class, Pointer, MemberData *, memberData) \
+ Member(class, Pointer, ArrayData *, arrayData)
+
+DECLARE_HEAP_OBJECT(Object, Base) {
+ DECLARE_MARK_TABLE(Object);
void init() { Base::init(); }
void destroy() { Base::destroy(); }
@@ -75,9 +80,23 @@ struct Object : Base {
Q_ASSERT(index < vtable()->nInlineProperties);
return reinterpret_cast<const Value *>(this) + vtable()->inlinePropertyOffset + index;
}
- Value *inlinePropertyData(uint index) {
+ void setInlineProperty(ExecutionEngine *e, uint index, Value v) {
+ Q_ASSERT(index < vtable()->nInlineProperties);
+ Value *prop = reinterpret_cast<Value *>(this) + vtable()->inlinePropertyOffset + index;
+ WriteBarrier::write(e, this, prop, v);
+ }
+ void setInlineProperty(ExecutionEngine *e, uint index, Heap::Base *b) {
Q_ASSERT(index < vtable()->nInlineProperties);
- return reinterpret_cast<Value *>(this) + vtable()->inlinePropertyOffset + index;
+ Value *prop = reinterpret_cast<Value *>(this) + vtable()->inlinePropertyOffset + index;
+ WriteBarrier::write(e, this, prop, b);
+ }
+
+ QV4::MemberData::Index writablePropertyData(uint index) {
+ uint nInline = vtable()->nInlineProperties;
+ if (index < nInline)
+ return { this, reinterpret_cast<Value *>(this) + vtable()->inlinePropertyOffset + index};
+ index -= nInline;
+ return { memberData, memberData->values.values + index };
}
const Value *propertyData(uint index) const {
@@ -85,21 +104,32 @@ struct Object : Base {
if (index < nInline)
return reinterpret_cast<const Value *>(this) + vtable()->inlinePropertyOffset + index;
index -= nInline;
- return memberData->data + index;
+ return memberData->values.data() + index;
}
- Value *propertyData(uint index) {
+ void setProperty(ExecutionEngine *e, uint index, Value v) {
uint nInline = vtable()->nInlineProperties;
- if (index < nInline)
- return reinterpret_cast<Value *>(this) + vtable()->inlinePropertyOffset + index;
+ if (index < nInline) {
+ setInlineProperty(e, index, v);
+ return;
+ }
+ index -= nInline;
+ memberData->values.set(e, index, v);
+ }
+ void setProperty(ExecutionEngine *e, uint index, Heap::Base *b) {
+ uint nInline = vtable()->nInlineProperties;
+ if (index < nInline) {
+ setInlineProperty(e, index, b);
+ return;
+ }
index -= nInline;
- return memberData->data + index;
+ memberData->values.set(e, index, b);
}
Heap::Object *prototype() const { return internalClass->prototype; }
- Pointer<MemberData> memberData;
- Pointer<ArrayData> arrayData;
};
+Q_STATIC_ASSERT(Object::markTable == ((2 << 2) | (2 << 4)));
+
}
#define V4_OBJECT(superClass) \
@@ -134,7 +164,8 @@ struct Object : Base {
dptr->_checkIsInitialized(); \
return dptr; \
} \
- V4_ASSERT_IS_TRIVIAL(QV4::Heap::DataClass);
+ V4_ASSERT_IS_TRIVIAL(QV4::Heap::DataClass); \
+ static Q_CONSTEXPR quint64 markTable = QV4::Heap::DataClass::markTable;
#define V4_PROTOTYPE(p) \
static QV4::Object *defaultPrototype(QV4::ExecutionEngine *e) \
@@ -147,8 +178,8 @@ struct ObjectVTable
void (*construct)(const Managed *, Scope &scope, CallData *data);
ReturnedValue (*get)(const Managed *, String *name, bool *hasProperty);
ReturnedValue (*getIndexed)(const Managed *, uint index, bool *hasProperty);
- void (*put)(Managed *, String *name, const Value &value);
- void (*putIndexed)(Managed *, uint index, const Value &value);
+ bool (*put)(Managed *, String *name, const Value &value);
+ bool (*putIndexed)(Managed *, uint index, const Value &value);
PropertyAttributes (*query)(const Managed *, String *name);
PropertyAttributes (*queryIndexed)(const Managed *, uint index);
bool (*deleteProperty)(Managed *m, String *name);
@@ -206,13 +237,16 @@ struct Q_QML_EXPORT Object: Managed {
void setInternalClass(InternalClass *ic);
const Value *propertyData(uint index) const { return d()->propertyData(index); }
- Value *propertyData(uint index) { return d()->propertyData(index); }
Heap::ArrayData *arrayData() const { return d()->arrayData; }
- void setArrayData(ArrayData *a) { d()->arrayData = a->d(); }
+ void setArrayData(ArrayData *a) { d()->arrayData.set(engine(), a->d()); }
void getProperty(uint index, Property *p, PropertyAttributes *attrs) const;
void setProperty(uint index, const Property *p);
+ void setProperty(uint index, Value v) const { d()->setProperty(engine(), index, v); }
+ void setProperty(uint index, Heap::Base *b) const { d()->setProperty(engine(), index, b); }
+ void setProperty(ExecutionEngine *engine, uint index, Value v) const { d()->setProperty(engine, index, v); }
+ void setProperty(ExecutionEngine *engine, uint index, Heap::Base *b) const { d()->setProperty(engine, index, b); }
const ObjectVTable *vtable() const { return reinterpret_cast<const ObjectVTable *>(d()->vtable()); }
Heap::Object *prototype() const { return d()->prototype(); }
@@ -221,8 +255,8 @@ struct Q_QML_EXPORT Object: Managed {
void getOwnProperty(String *name, PropertyAttributes *attrs, Property *p = 0);
void getOwnProperty(uint index, PropertyAttributes *attrs, Property *p = 0);
- Value *getValueOrSetter(String *name, PropertyAttributes *attrs);
- Value *getValueOrSetter(uint index, PropertyAttributes *attrs);
+ MemberData::Index getValueOrSetter(String *name, PropertyAttributes *attrs);
+ ArrayData::Index getValueOrSetter(uint index, PropertyAttributes *attrs);
bool hasProperty(String *name) const;
bool hasProperty(uint index) const;
@@ -239,8 +273,6 @@ struct Q_QML_EXPORT Object: Managed {
//
// helpers
//
- void put(ExecutionEngine *engine, const QString &name, const Value &value);
-
static ReturnedValue getValue(const Value &thisObject, const Value &v, PropertyAttributes attrs);
ReturnedValue getValue(const Value &v, PropertyAttributes attrs) const {
Scope scope(this->engine());
@@ -248,7 +280,7 @@ struct Q_QML_EXPORT Object: Managed {
return getValue(t, v, attrs);
}
- void putValue(uint memberIndex, const Value &value);
+ bool putValue(uint memberIndex, const Value &value);
/* The spec default: Writable: true, Enumerable: false, Configurable: true */
void defineDefaultProperty(String *name, const Value &value) {
@@ -265,6 +297,10 @@ struct Q_QML_EXPORT Object: Managed {
void defineReadonlyProperty(const QString &name, const Value &value);
void defineReadonlyProperty(String *name, const Value &value);
+ /* Fixed: Writable: false, Enumerable: false, Configurable: true */
+ void defineReadonlyConfigurableProperty(const QString &name, const Value &value);
+ void defineReadonlyConfigurableProperty(String *name, const Value &value);
+
void insertMember(String *s, const Value &v, PropertyAttributes attributes = Attr_Data) {
Scope scope(engine());
ScopedProperty p(scope);
@@ -304,7 +340,7 @@ public:
void push_back(const Value &v);
ArrayData::Type arrayType() const {
- return arrayData() ? d()->arrayData->type : Heap::ArrayData::Simple;
+ return arrayData() ? static_cast<ArrayData::Type>(d()->arrayData->type) : Heap::ArrayData::Simple;
}
// ### remove me
void setArrayType(ArrayData::Type t) {
@@ -344,10 +380,47 @@ public:
{ return vtable()->get(this, name, hasProperty); }
inline ReturnedValue getIndexed(uint idx, bool *hasProperty = 0) const
{ return vtable()->getIndexed(this, idx, hasProperty); }
- inline void put(String *name, const Value &v)
- { vtable()->put(this, name, v); }
- inline void putIndexed(uint idx, const Value &v)
- { vtable()->putIndexed(this, idx, v); }
+
+ // use the set variants instead, to customize throw behavior
+ inline bool put(String *name, const Value &v)
+ { return vtable()->put(this, name, v); }
+ inline bool putIndexed(uint idx, const Value &v)
+ { return vtable()->putIndexed(this, idx, v); }
+
+ enum ThrowOnFailure {
+ DoThrowOnRejection,
+ DoNotThrow
+ };
+
+ // ES6: 7.3.3 Set (O, P, V, Throw)
+ inline bool set(String *name, const Value &v, ThrowOnFailure shouldThrow)
+ {
+ bool ret = vtable()->put(this, name, v);
+ // ES6: 7.3.3, 6: If success is false and Throw is true, throw a TypeError exception.
+ if (!ret && shouldThrow == ThrowOnFailure::DoThrowOnRejection) {
+ ExecutionEngine *e = engine();
+ if (!e->hasException) { // allow a custom set impl to throw itself
+ QString message = QLatin1String("Cannot assign to read-only property \"") +
+ name->toQString() + QLatin1Char('\"');
+ e->throwTypeError(message);
+ }
+ }
+ return ret;
+ }
+
+ inline bool setIndexed(uint idx, const Value &v, ThrowOnFailure shouldThrow)
+ {
+ bool ret = vtable()->putIndexed(this, idx, v);
+ if (!ret && shouldThrow == ThrowOnFailure::DoThrowOnRejection) {
+ ExecutionEngine *e = engine();
+ if (!e->hasException) { // allow a custom set impl to throw itself
+ e->throwTypeError();
+ }
+ }
+ return ret;
+ }
+
+
PropertyAttributes query(String *name) const
{ return vtable()->query(this, name); }
PropertyAttributes queryIndexed(uint index) const
@@ -371,13 +444,12 @@ public:
inline void call(Scope &scope, CallData *d) const
{ vtable()->call(this, scope, d); }
protected:
- static void markObjects(Heap::Base *that, ExecutionEngine *e);
static void construct(const Managed *m, Scope &scope, CallData *);
static void call(const Managed *m, Scope &scope, CallData *);
static ReturnedValue get(const Managed *m, String *name, bool *hasProperty);
static ReturnedValue getIndexed(const Managed *m, uint index, bool *hasProperty);
- static void put(Managed *m, String *name, const Value &value);
- static void putIndexed(Managed *m, uint index, const Value &value);
+ static bool put(Managed *m, String *name, const Value &value);
+ static bool putIndexed(Managed *m, uint index, const Value &value);
static PropertyAttributes query(const Managed *m, String *name);
static PropertyAttributes queryIndexed(const Managed *m, uint index);
static bool deleteProperty(Managed *m, String *name);
@@ -387,12 +459,13 @@ protected:
static void advanceIterator(Managed *m, ObjectIterator *it, Value *name, uint *index, Property *p, PropertyAttributes *attributes);
static uint getLength(const Managed *m);
static ReturnedValue instanceOf(const Object *typeObject, const Value &var);
+ static void markObjects(Heap::Base *, MarkStack *);
private:
ReturnedValue internalGet(String *name, bool *hasProperty) const;
ReturnedValue internalGetIndexed(uint index, bool *hasProperty) const;
- void internalPut(String *name, const Value &value);
- void internalPutIndexed(uint index, const Value &value);
+ bool internalPut(String *name, const Value &value);
+ bool internalPutIndexed(uint index, const Value &value);
bool internalDeleteProperty(String *name);
bool internalDeleteIndexedProperty(uint index);
@@ -436,7 +509,7 @@ struct ArrayObject : Object {
private:
void commonInit()
- { *propertyData(LengthPropertyIndex) = Primitive::fromInt32(0); }
+ { setProperty(internalClass->engine, LengthPropertyIndex, Primitive::fromInt32(0)); }
};
}
@@ -476,7 +549,7 @@ struct ArrayObject: Object {
inline void Object::setArrayLengthUnchecked(uint l)
{
if (isArrayObject())
- *propertyData(Heap::ArrayObject::LengthPropertyIndex) = Primitive::fromUInt32(l);
+ setProperty(Heap::ArrayObject::LengthPropertyIndex, Primitive::fromUInt32(l));
}
inline void Object::push_back(const Value &v)
@@ -493,7 +566,7 @@ inline void Object::arraySet(uint index, const Property *p, PropertyAttributes a
{
// ### Clean up
arrayCreate();
- if (attributes.isAccessor() || (index > 0x1000 && index > 2*d()->arrayData->alloc)) {
+ if (attributes.isAccessor() || (index > 0x1000 && index > 2*d()->arrayData->values.alloc)) {
initSparseArray();
} else {
arrayData()->vtable()->reallocate(this, index + 1, false);
@@ -508,7 +581,7 @@ inline void Object::arraySet(uint index, const Property *p, PropertyAttributes a
inline void Object::arraySet(uint index, const Value &value)
{
arrayCreate();
- if (index > 0x1000 && index > 2*d()->arrayData->alloc) {
+ if (index > 0x1000 && index > 2*d()->arrayData->values.alloc) {
initSparseArray();
}
ArrayData::insert(this, index, &value);
diff --git a/src/qml/jsruntime/qv4objectiterator.cpp b/src/qml/jsruntime/qv4objectiterator.cpp
index 59115dfe21..3427ee89fe 100644
--- a/src/qml/jsruntime/qv4objectiterator.cpp
+++ b/src/qml/jsruntime/qv4objectiterator.cpp
@@ -177,10 +177,10 @@ ReturnedValue ObjectIterator::nextPropertyNameAsString()
DEFINE_OBJECT_VTABLE(ForEachIteratorObject);
-void ForEachIteratorObject::markObjects(Heap::Base *that, ExecutionEngine *e)
+void ForEachIteratorObject::markObjects(Heap::Base *that, MarkStack *markStack)
{
ForEachIteratorObject::Data *o = static_cast<ForEachIteratorObject::Data *>(that);
- o->workArea[0].mark(e);
- o->workArea[1].mark(e);
- Object::markObjects(that, e);
+ o->workArea[0].mark(markStack);
+ o->workArea[1].mark(markStack);
+ Object::markObjects(that, markStack);
}
diff --git a/src/qml/jsruntime/qv4objectiterator_p.h b/src/qml/jsruntime/qv4objectiterator_p.h
index 98e94a95ea..6168d59914 100644
--- a/src/qml/jsruntime/qv4objectiterator_p.h
+++ b/src/qml/jsruntime/qv4objectiterator_p.h
@@ -129,7 +129,7 @@ struct ForEachIteratorObject: Object {
ReturnedValue nextPropertyName() { return d()->it().nextPropertyNameAsString(); }
protected:
- static void markObjects(Heap::Base *that, ExecutionEngine *e);
+ static void markObjects(Heap::Base *that, MarkStack *markStack);
};
inline
diff --git a/src/qml/jsruntime/qv4objectproto.cpp b/src/qml/jsruntime/qv4objectproto.cpp
index 97dbe24339..2e72c0f13f 100644
--- a/src/qml/jsruntime/qv4objectproto.cpp
+++ b/src/qml/jsruntime/qv4objectproto.cpp
@@ -1,5 +1,6 @@
/****************************************************************************
**
+** Copyright (C) 2017 Crimson AS <info@crimson.no>
** Copyright (C) 2016 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
@@ -89,10 +90,11 @@ void ObjectPrototype::init(ExecutionEngine *v4, Object *ctor)
ScopedObject o(scope, this);
ctor->defineReadonlyProperty(v4->id_prototype(), o);
- ctor->defineReadonlyProperty(v4->id_length(), Primitive::fromInt32(1));
+ ctor->defineReadonlyConfigurableProperty(v4->id_length(), Primitive::fromInt32(1));
ctor->defineDefaultProperty(QStringLiteral("getPrototypeOf"), method_getPrototypeOf, 1);
ctor->defineDefaultProperty(QStringLiteral("getOwnPropertyDescriptor"), method_getOwnPropertyDescriptor, 2);
ctor->defineDefaultProperty(QStringLiteral("getOwnPropertyNames"), method_getOwnPropertyNames, 1);
+ ctor->defineDefaultProperty(QStringLiteral("assign"), method_assign, 2);
ctor->defineDefaultProperty(QStringLiteral("create"), method_create, 2);
ctor->defineDefaultProperty(QStringLiteral("defineProperty"), method_defineProperty, 3);
ctor->defineDefaultProperty(QStringLiteral("defineProperties"), method_defineProperties, 2);
@@ -123,9 +125,8 @@ void ObjectPrototype::init(ExecutionEngine *v4, Object *ctor)
void ObjectPrototype::method_getPrototypeOf(const BuiltinFunction *, Scope &scope, CallData *callData)
{
- ScopedObject o(scope, callData->argument(0));
- if (!o)
- THROW_TYPE_ERROR();
+ ScopedObject o(scope, callData->args[0].toObject(scope.engine));
+ CHECK_EXCEPTION();
ScopedObject p(scope, o->prototype());
scope.result = !!p ? p->asReturnedValue() : Encode::null();
@@ -133,11 +134,8 @@ void ObjectPrototype::method_getPrototypeOf(const BuiltinFunction *, Scope &scop
void ObjectPrototype::method_getOwnPropertyDescriptor(const BuiltinFunction *, Scope &scope, CallData *callData)
{
- ScopedObject O(scope, callData->argument(0));
- if (!O) {
- scope.result = scope.engine->throwTypeError();
- return;
- }
+ ScopedObject O(scope, callData->args[0].toObject(scope.engine));
+ CHECK_EXCEPTION();
if (ArgumentsObject::isNonStrictArgumentsObject(O))
static_cast<ArgumentsObject *>(O.getPointer())->fullyCreate();
@@ -154,13 +152,54 @@ void ObjectPrototype::method_getOwnPropertyDescriptor(const BuiltinFunction *, S
void ObjectPrototype::method_getOwnPropertyNames(const BuiltinFunction *, Scope &scope, CallData *callData)
{
- ScopedObject O(scope, callData->argument(0));
- if (!O) {
- scope.result = scope.engine->throwTypeError();
+ ScopedObject O(scope, callData->args[0].toObject(scope.engine));
+ CHECK_EXCEPTION();
+
+ scope.result = getOwnPropertyNames(scope.engine, callData->args[0]);
+}
+
+// 19.1.2.1
+void ObjectPrototype::method_assign(const BuiltinFunction *, Scope &scope, CallData *callData)
+{
+ ScopedObject to(scope, callData->args[0].toObject(scope.engine));
+ CHECK_EXCEPTION();
+
+ if (callData->argc == 1) {
+ scope.result = to;
return;
}
- scope.result = getOwnPropertyNames(scope.engine, callData->args[0]);
+ for (int i = 1; i < callData->argc; ++i) {
+ if (callData->args[i].isUndefined() || callData->args[i].isNull())
+ continue;
+
+ ScopedObject from(scope, callData->args[i].toObject(scope.engine));
+ CHECK_EXCEPTION();
+ QV4::ScopedArrayObject keys(scope, QV4::ObjectPrototype::getOwnPropertyNames(scope.engine, from));
+ quint32 length = keys->getLength();
+
+ ScopedString nextKey(scope);
+ ScopedValue propValue(scope);
+ for (quint32 i = 0; i < length; ++i) {
+ nextKey = Value::fromReturnedValue(keys->getIndexed(i)).toString(scope.engine);
+
+ PropertyAttributes attrs;
+ ScopedProperty prop(scope);
+ from->getOwnProperty(nextKey, &attrs, prop);
+
+ if (attrs == PropertyFlag::Attr_Invalid)
+ continue;
+
+ if (!attrs.isEnumerable())
+ continue;
+
+ propValue = from->get(nextKey);
+ to->set(nextKey, propValue, Object::DoThrowOnRejection);
+ CHECK_EXCEPTION();
+ }
+ }
+
+ scope.result = to;
}
void ObjectPrototype::method_create(const BuiltinFunction *builtin, Scope &scope, CallData *callData)
@@ -246,14 +285,17 @@ void ObjectPrototype::method_defineProperties(const BuiltinFunction *, Scope &sc
void ObjectPrototype::method_seal(const BuiltinFunction *, Scope &scope, CallData *callData)
{
ScopedObject o(scope, callData->argument(0));
- if (!o)
- THROW_TYPE_ERROR();
+ if (!o) {
+ // 19.1.2.17, 1
+ scope.result = callData->argument(0);
+ return;
+ }
o->setInternalClass(o->internalClass()->sealed());
if (o->arrayData()) {
ArrayData::ensureAttributes(o);
- for (uint i = 0; i < o->d()->arrayData->alloc; ++i) {
+ for (uint i = 0; i < o->d()->arrayData->values.alloc; ++i) {
if (!o->arrayData()->isEmpty(i))
o->d()->arrayData->attrs[i].setConfigurable(false);
}
@@ -265,8 +307,11 @@ void ObjectPrototype::method_seal(const BuiltinFunction *, Scope &scope, CallDat
void ObjectPrototype::method_freeze(const BuiltinFunction *, Scope &scope, CallData *callData)
{
ScopedObject o(scope, callData->argument(0));
- if (!o)
- THROW_TYPE_ERROR();
+ if (!o) {
+ // 19.1.2.5, 1
+ scope.result = callData->argument(0);
+ return;
+ }
if (ArgumentsObject::isNonStrictArgumentsObject(o))
static_cast<ArgumentsObject *>(o.getPointer())->fullyCreate();
@@ -275,7 +320,7 @@ void ObjectPrototype::method_freeze(const BuiltinFunction *, Scope &scope, CallD
if (o->arrayData()) {
ArrayData::ensureAttributes(o);
- for (uint i = 0; i < o->arrayData()->alloc; ++i) {
+ for (uint i = 0; i < o->arrayData()->values.alloc; ++i) {
if (!o->arrayData()->isEmpty(i))
o->arrayData()->attrs[i].setConfigurable(false);
if (o->arrayData()->attrs[i].isData())
@@ -287,9 +332,11 @@ void ObjectPrototype::method_freeze(const BuiltinFunction *, Scope &scope, CallD
void ObjectPrototype::method_preventExtensions(const BuiltinFunction *, Scope &scope, CallData *callData)
{
- ScopedObject o(scope, callData->argument(0));
- if (!o)
- THROW_TYPE_ERROR();
+ ScopedObject o(scope, callData->args[0].toObject(scope.engine));
+ if (!o) {
+ scope.result = callData->argument(0);
+ return;
+ }
o->setInternalClass(o->internalClass()->nonExtensible());
scope.result = o;
@@ -297,9 +344,11 @@ void ObjectPrototype::method_preventExtensions(const BuiltinFunction *, Scope &s
void ObjectPrototype::method_isSealed(const BuiltinFunction *, Scope &scope, CallData *callData)
{
- ScopedObject o(scope, callData->argument(0));
- if (!o)
- THROW_TYPE_ERROR();
+ ScopedObject o(scope, callData->args[0].toObject(scope.engine));
+ if (!o) {
+ scope.result = Encode(true);
+ return;
+ }
if (o->isExtensible()) {
scope.result = Encode(false);
@@ -322,7 +371,7 @@ void ObjectPrototype::method_isSealed(const BuiltinFunction *, Scope &scope, Cal
return;
}
- for (uint i = 0; i < o->arrayData()->alloc; ++i) {
+ for (uint i = 0; i < o->arrayData()->values.alloc; ++i) {
if (!o->arrayData()->isEmpty(i))
if (o->arrayData()->attributes(i).isConfigurable()) {
scope.result = Encode(false);
@@ -335,9 +384,11 @@ void ObjectPrototype::method_isSealed(const BuiltinFunction *, Scope &scope, Cal
void ObjectPrototype::method_isFrozen(const BuiltinFunction *, Scope &scope, CallData *callData)
{
- ScopedObject o(scope, callData->argument(0));
- if (!o)
- THROW_TYPE_ERROR();
+ ScopedObject o(scope, callData->args[0].toObject(scope.engine));
+ if (!o) {
+ scope.result = Encode(true);
+ return;
+ }
if (o->isExtensible()) {
scope.result = Encode(false);
@@ -360,7 +411,7 @@ void ObjectPrototype::method_isFrozen(const BuiltinFunction *, Scope &scope, Cal
return;
}
- for (uint i = 0; i < o->arrayData()->alloc; ++i) {
+ for (uint i = 0; i < o->arrayData()->values.alloc; ++i) {
if (!o->arrayData()->isEmpty(i))
if (o->arrayData()->attributes(i).isConfigurable() || o->arrayData()->attributes(i).isWritable()) {
scope.result = Encode(false);
@@ -373,18 +424,19 @@ void ObjectPrototype::method_isFrozen(const BuiltinFunction *, Scope &scope, Cal
void ObjectPrototype::method_isExtensible(const BuiltinFunction *, Scope &scope, CallData *callData)
{
- ScopedObject o(scope, callData->argument(0));
- if (!o)
- THROW_TYPE_ERROR();
+ ScopedObject o(scope, callData->args[0].toObject(scope.engine));
+ if (!o) {
+ scope.result = Encode(false);
+ return;
+ }
scope.result = Encode((bool)o->isExtensible());
}
void ObjectPrototype::method_keys(const BuiltinFunction *, Scope &scope, CallData *callData)
{
- ScopedObject o(scope, callData->argument(0));
- if (!o)
- THROW_TYPE_ERROR();
+ ScopedObject o(scope, callData->args[0].toObject(scope.engine));
+ CHECK_EXCEPTION();
ScopedArrayObject a(scope, scope.engine->newArrayObject());
@@ -670,12 +722,12 @@ ReturnedValue ObjectPrototype::fromPropertyDescriptor(ExecutionEngine *engine, c
return o.asReturnedValue();
}
-
+// es6: GetOwnPropertyKeys
Heap::ArrayObject *ObjectPrototype::getOwnPropertyNames(ExecutionEngine *v4, const Value &o)
{
Scope scope(v4);
ScopedArrayObject array(scope, v4->newArrayObject());
- ScopedObject O(scope, o);
+ ScopedObject O(scope, o.toObject(v4));
if (O) {
ObjectIterator it(scope, O, ObjectIterator::NoFlags);
ScopedValue name(scope);
diff --git a/src/qml/jsruntime/qv4objectproto_p.h b/src/qml/jsruntime/qv4objectproto_p.h
index 1db8615511..44b54267f3 100644
--- a/src/qml/jsruntime/qv4objectproto_p.h
+++ b/src/qml/jsruntime/qv4objectproto_p.h
@@ -81,6 +81,7 @@ struct ObjectPrototype: Object
static void method_getPrototypeOf(const BuiltinFunction *, Scope &scope, CallData *callData);
static void method_getOwnPropertyDescriptor(const BuiltinFunction *, Scope &scope, CallData *callData);
static void method_getOwnPropertyNames(const BuiltinFunction *, Scope &scope, CallData *callData);
+ static void method_assign(const BuiltinFunction *, Scope &scope, CallData *callData);
static void method_create(const BuiltinFunction *, Scope &scope, CallData *callData);
static void method_defineProperty(const BuiltinFunction *, Scope &scope, CallData *callData);
static void method_defineProperties(const BuiltinFunction *, Scope &scope, CallData *callData);
diff --git a/src/qml/jsruntime/qv4persistent.cpp b/src/qml/jsruntime/qv4persistent.cpp
index 75f7c95dde..973541553a 100644
--- a/src/qml/jsruntime/qv4persistent.cpp
+++ b/src/qml/jsruntime/qv4persistent.cpp
@@ -232,26 +232,15 @@ void PersistentValueStorage::free(Value *v)
freePage(p);
}
-static void drainMarkStack(QV4::ExecutionEngine *engine, Value *markBase)
+void PersistentValueStorage::mark(MarkStack *markStack)
{
- while (engine->jsStackTop > markBase) {
- Heap::Base *h = engine->popForGC();
- Q_ASSERT (h->vtable()->markObjects);
- h->vtable()->markObjects(h, engine);
- }
-}
-
-void PersistentValueStorage::mark(ExecutionEngine *e)
-{
- Value *markBase = e->jsStackTop;
-
Page *p = static_cast<Page *>(firstPage);
while (p) {
for (int i = 0; i < kEntriesPerPage; ++i) {
if (Managed *m = p->values[i].as<Managed>())
- m->mark(e);
+ m->mark(markStack);
}
- drainMarkStack(e, markBase);
+ markStack->drain();
p = p->header.next;
}
@@ -407,11 +396,11 @@ void WeakValue::allocVal(ExecutionEngine *engine)
val = engine->memoryManager->m_weakValues->allocate();
}
-void WeakValue::markOnce(ExecutionEngine *e)
+void WeakValue::markOnce(MarkStack *markStack)
{
if (!val)
return;
- val->mark(e);
+ val->mark(markStack);
}
void WeakValue::free()
diff --git a/src/qml/jsruntime/qv4persistent_p.h b/src/qml/jsruntime/qv4persistent_p.h
index c1cd1f34df..1f838f5531 100644
--- a/src/qml/jsruntime/qv4persistent_p.h
+++ b/src/qml/jsruntime/qv4persistent_p.h
@@ -65,7 +65,7 @@ struct Q_QML_EXPORT PersistentValueStorage
Value *allocate();
static void free(Value *e);
- void mark(ExecutionEngine *e);
+ void mark(MarkStack *markStack);
struct Iterator {
Iterator(void *p, int idx);
@@ -203,7 +203,7 @@ public:
bool isNullOrUndefined() const { return !val || val->isNullOrUndefined(); }
void clear() { free(); }
- void markOnce(ExecutionEngine *e);
+ void markOnce(MarkStack *markStack);
private:
Value *val;
diff --git a/src/qml/jsruntime/qv4property_p.h b/src/qml/jsruntime/qv4property_p.h
index 5069d7690b..2a5b6f7f74 100644
--- a/src/qml/jsruntime/qv4property_p.h
+++ b/src/qml/jsruntime/qv4property_p.h
@@ -78,12 +78,6 @@ struct Property {
attrs->resolve();
}
- static Property genericDescriptor() {
- Property pd;
- pd.value = Primitive::emptyValue();
- return pd;
- }
-
inline bool isSubset(const PropertyAttributes &attrs, const Property *other, PropertyAttributes otherAttrs) const;
inline void merge(PropertyAttributes &attrs, const Property *other, PropertyAttributes otherAttrs);
@@ -99,19 +93,12 @@ struct Property {
}
explicit Property() { value = Encode::undefined(); set = Value::fromHeapObject(0); }
- explicit Property(Value v) : value(v) { set = Value::fromHeapObject(0); }
- Property(FunctionObject *getter, FunctionObject *setter) {
- value = reinterpret_cast<Managed *>(getter);
- set = reinterpret_cast<Managed *>(setter);
- }
Property(Heap::FunctionObject *getter, Heap::FunctionObject *setter) {
value.setM(reinterpret_cast<Heap::Base *>(getter));
set.setM(reinterpret_cast<Heap::Base *>(setter));
}
- Property &operator=(Value v) { value = v; return *this; }
private:
- Property(const Property &);
- Property &operator=(const Property &);
+ Q_DISABLE_COPY(Property)
};
inline bool Property::isSubset(const PropertyAttributes &attrs, const Property *other, PropertyAttributes otherAttrs) const
diff --git a/src/qml/jsruntime/qv4qmlcontext.cpp b/src/qml/jsruntime/qv4qmlcontext.cpp
index d97d44379d..8b9ef149d6 100644
--- a/src/qml/jsruntime/qv4qmlcontext.cpp
+++ b/src/qml/jsruntime/qv4qmlcontext.cpp
@@ -59,10 +59,10 @@ QT_BEGIN_NAMESPACE
using namespace QV4;
-DEFINE_OBJECT_VTABLE(QmlContextWrapper);
+DEFINE_OBJECT_VTABLE(QQmlContextWrapper);
DEFINE_MANAGED_VTABLE(QmlContext);
-void Heap::QmlContextWrapper::init(QQmlContextData *context, QObject *scopeObject)
+void Heap::QQmlContextWrapper::init(QQmlContextData *context, QObject *scopeObject)
{
Object::init();
readOnly = true;
@@ -71,17 +71,17 @@ void Heap::QmlContextWrapper::init(QQmlContextData *context, QObject *scopeObjec
this->scopeObject.init(scopeObject);
}
-void Heap::QmlContextWrapper::destroy()
+void Heap::QQmlContextWrapper::destroy()
{
delete context;
scopeObject.destroy();
Object::destroy();
}
-ReturnedValue QmlContextWrapper::get(const Managed *m, String *name, bool *hasProperty)
+ReturnedValue QQmlContextWrapper::get(const Managed *m, String *name, bool *hasProperty)
{
- Q_ASSERT(m->as<QmlContextWrapper>());
- const QmlContextWrapper *resource = static_cast<const QmlContextWrapper *>(m);
+ Q_ASSERT(m->as<QQmlContextWrapper>());
+ const QQmlContextWrapper *resource = static_cast<const QQmlContextWrapper *>(m);
QV4::ExecutionEngine *v4 = resource->engine();
QV4::Scope scope(v4);
@@ -131,7 +131,7 @@ ReturnedValue QmlContextWrapper::get(const Managed *m, String *name, bool *hasPr
if (context->imports && name->startsWithUpper()) {
// Search for attached properties, enums and imported scripts
- QQmlTypeNameCache::Result r = context->imports->query(name);
+ QQmlTypeNameCache::Result r = context->imports->query(name, QQmlImport::AllowRecursion);
if (r.isValid()) {
if (hasProperty)
@@ -140,9 +140,9 @@ ReturnedValue QmlContextWrapper::get(const Managed *m, String *name, bool *hasPr
QV4::ScopedObject scripts(scope, context->importedScripts.valueRef());
return scripts->getIndexed(r.scriptIndex);
} else if (r.type.isValid()) {
- return QmlTypeWrapper::create(v4, scopeObject, r.type);
+ return QQmlTypeWrapper::create(v4, scopeObject, r.type);
} else if (r.importNamespace) {
- return QmlTypeWrapper::create(v4, scopeObject, context->imports, r.importNamespace);
+ return QQmlTypeWrapper::create(v4, scopeObject, context->imports, r.importNamespace);
}
Q_ASSERT(!"Unreachable");
}
@@ -222,21 +222,19 @@ ReturnedValue QmlContextWrapper::get(const Managed *m, String *name, bool *hasPr
return Encode::undefined();
}
-void QmlContextWrapper::put(Managed *m, String *name, const Value &value)
+bool QQmlContextWrapper::put(Managed *m, String *name, const Value &value)
{
- Q_ASSERT(m->as<QmlContextWrapper>());
- QmlContextWrapper *resource = static_cast<QmlContextWrapper *>(m);
+ Q_ASSERT(m->as<QQmlContextWrapper>());
+ QQmlContextWrapper *resource = static_cast<QQmlContextWrapper *>(m);
ExecutionEngine *v4 = resource->engine();
QV4::Scope scope(v4);
if (scope.hasException())
- return;
- QV4::Scoped<QmlContextWrapper> wrapper(scope, resource);
+ return false;
+ QV4::Scoped<QQmlContextWrapper> wrapper(scope, resource);
uint member = wrapper->internalClass()->find(name);
- if (member < UINT_MAX) {
- wrapper->putValue(member, value);
- return;
- }
+ if (member < UINT_MAX)
+ return wrapper->putValue(member, value);
if (wrapper->d()->isNullWrapper) {
if (wrapper && wrapper->d()->readOnly) {
@@ -244,11 +242,10 @@ void QmlContextWrapper::put(Managed *m, String *name, const Value &value)
QLatin1Char('"');
ScopedString e(scope, v4->newString(error));
v4->throwError(e);
- return;
+ return false;
}
- Object::put(m, name, value);
- return;
+ return Object::put(m, name, value);
}
// Its possible we could delay the calculation of the "actual" context (in the case
@@ -257,7 +254,7 @@ void QmlContextWrapper::put(Managed *m, String *name, const Value &value)
QQmlContextData *expressionContext = context;
if (!context)
- return;
+ return false;
// See QV8ContextWrapper::Getter for resolution order
@@ -267,18 +264,18 @@ void QmlContextWrapper::put(Managed *m, String *name, const Value &value)
const QV4::IdentifierHash<int> &properties = context->propertyNames();
// Search context properties
if (properties.count() && properties.value(name) != -1)
- return;
+ return false;
// Search scope object
if (scopeObject &&
QV4::QObjectWrapper::setQmlProperty(v4, context, scopeObject, name, QV4::QObjectWrapper::CheckRevision, value))
- return;
+ return true;
scopeObject = 0;
// Search context object
if (context->contextObject &&
QV4::QObjectWrapper::setQmlProperty(v4, context, context->contextObject, name, QV4::QObjectWrapper::CheckRevision, value))
- return;
+ return true;
context = context->parent;
}
@@ -289,23 +286,23 @@ void QmlContextWrapper::put(Managed *m, String *name, const Value &value)
QString error = QLatin1String("Invalid write to global property \"") + name->toQString() +
QLatin1Char('"');
v4->throwError(error);
- return;
+ return false;
}
- Object::put(m, name, value);
+ return Object::put(m, name, value);
}
-void Heap::QmlContext::init(QV4::ExecutionContext *outerContext, QV4::QmlContextWrapper *qml)
+void Heap::QmlContext::init(QV4::ExecutionContext *outerContext, QV4::QQmlContextWrapper *qml)
{
Heap::ExecutionContext::init(Heap::ExecutionContext::Type_QmlContext);
- outer = outerContext->d();
+ outer.set(internalClass->engine, outerContext->d());
strictMode = false;
callData = outer->callData;
lookups = outer->lookups;
constantTable = outer->constantTable;
compilationUnit = outer->compilationUnit;
- this->qml = qml->d();
+ this->qml.set(internalClass->engine, qml->d());
}
Heap::QmlContext *QmlContext::createWorkerContext(ExecutionContext *parent, const QUrl &source, Value *sendFunction)
@@ -318,7 +315,7 @@ Heap::QmlContext *QmlContext::createWorkerContext(ExecutionContext *parent, cons
context->isInternal = true;
context->isJSContext = true;
- Scoped<QmlContextWrapper> qml(scope, scope.engine->memoryManager->allocObject<QmlContextWrapper>(context, (QObject*)0));
+ Scoped<QQmlContextWrapper> qml(scope, scope.engine->memoryManager->allocObject<QQmlContextWrapper>(context, (QObject*)0));
qml->d()->isNullWrapper = true;
qml->setReadOnly(false);
@@ -336,7 +333,7 @@ Heap::QmlContext *QmlContext::create(ExecutionContext *parent, QQmlContextData *
{
Scope scope(parent);
- Scoped<QmlContextWrapper> qml(scope, scope.engine->memoryManager->allocObject<QmlContextWrapper>(context, scopeObject));
+ Scoped<QQmlContextWrapper> qml(scope, scope.engine->memoryManager->allocObject<QQmlContextWrapper>(context, scopeObject));
Heap::QmlContext *c = scope.engine->memoryManager->alloc<QmlContext>(parent, qml);
Q_ASSERT(c->vtable() == staticVTable());
return c;
diff --git a/src/qml/jsruntime/qv4qmlcontext_p.h b/src/qml/jsruntime/qv4qmlcontext_p.h
index 8ef7356f4c..65bf4c60ce 100644
--- a/src/qml/jsruntime/qv4qmlcontext_p.h
+++ b/src/qml/jsruntime/qv4qmlcontext_p.h
@@ -62,11 +62,11 @@ QT_BEGIN_NAMESPACE
namespace QV4 {
-struct QmlContextWrapper;
+struct QQmlContextWrapper;
namespace Heap {
-struct QmlContextWrapper : Object {
+struct QQmlContextWrapper : Object {
void init(QQmlContextData *context, QObject *scopeObject);
void destroy();
bool readOnly;
@@ -76,17 +76,20 @@ struct QmlContextWrapper : Object {
QQmlQPointer<QObject> scopeObject;
};
-struct QmlContext : ExecutionContext {
- void init(QV4::ExecutionContext *outerContext, QV4::QmlContextWrapper *qml);
+#define QmlContextMembers(class, Member) \
+ Member(class, Pointer, QQmlContextWrapper *, qml)
- Pointer<QmlContextWrapper> qml;
+DECLARE_HEAP_OBJECT(QmlContext, ExecutionContext) {
+ DECLARE_MARK_TABLE(QmlContext);
+
+ void init(QV4::ExecutionContext *outerContext, QV4::QQmlContextWrapper *qml);
};
}
-struct Q_QML_EXPORT QmlContextWrapper : Object
+struct Q_QML_EXPORT QQmlContextWrapper : Object
{
- V4_OBJECT2(QmlContextWrapper, Object)
+ V4_OBJECT2(QQmlContextWrapper, Object)
V4_NEEDS_DESTROY
V4_INTERNALCLASS(QmlContextWrapper)
@@ -96,7 +99,7 @@ struct Q_QML_EXPORT QmlContextWrapper : Object
void setReadOnly(bool b) { d()->readOnly = b; }
static ReturnedValue get(const Managed *m, String *name, bool *hasProperty);
- static void put(Managed *m, String *name, const Value &value);
+ static bool put(Managed *m, String *name, const Value &value);
};
struct Q_QML_EXPORT QmlContext : public ExecutionContext
diff --git a/src/qml/jsruntime/qv4qobjectwrapper.cpp b/src/qml/jsruntime/qv4qobjectwrapper.cpp
index 89c10e0995..51a957acc9 100644
--- a/src/qml/jsruntime/qv4qobjectwrapper.cpp
+++ b/src/qml/jsruntime/qv4qobjectwrapper.cpp
@@ -74,9 +74,14 @@
#include <QtCore/qtimer.h>
#include <QtCore/qatomic.h>
#include <QtCore/qmetaobject.h>
+#include <QtCore/qabstractitemmodel.h>
+#include <QtCore/qloggingcategory.h>
+#include <vector>
QT_BEGIN_NAMESPACE
+Q_LOGGING_CATEGORY(lcBindingRemoval, "qt.qml.binding.removal", QtWarningMsg)
+
// The code in this file does not violate strict aliasing, but GCC thinks it does
// so turn off the warnings for us to have a clean build
QT_WARNING_DISABLE_GCC("-Wstrict-aliasing")
@@ -202,19 +207,61 @@ void QObjectWrapper::initializeBindings(ExecutionEngine *engine)
QQmlPropertyData *QObjectWrapper::findProperty(ExecutionEngine *engine, QQmlContextData *qmlContext, String *name, RevisionMode revisionMode, QQmlPropertyData *local) const
{
+ QObject *o = d()->object();
+ return findProperty(engine, o, qmlContext, name, revisionMode, local);
+}
+
+QQmlPropertyData *QObjectWrapper::findProperty(ExecutionEngine *engine, QObject *o, QQmlContextData *qmlContext, String *name, RevisionMode revisionMode, QQmlPropertyData *local)
+{
Q_UNUSED(revisionMode);
- QQmlData *ddata = QQmlData::get(d()->object(), false);
- if (!ddata)
- return 0;
+ QQmlData *ddata = QQmlData::get(o, false);
QQmlPropertyData *result = 0;
if (ddata && ddata->propertyCache)
- result = ddata->propertyCache->property(name, d()->object(), qmlContext);
+ result = ddata->propertyCache->property(name, o, qmlContext);
else
- result = QQmlPropertyCache::property(engine->jsEngine(), d()->object(), name, qmlContext, *local);
+ result = QQmlPropertyCache::property(engine->jsEngine(), o, name, qmlContext, *local);
return result;
}
+ReturnedValue QObjectWrapper::getProperty(ExecutionEngine *engine, QObject *object, QQmlPropertyData *property, bool captureRequired)
+{
+ QQmlData::flushPendingBinding(object, QQmlPropertyIndex(property->coreIndex()));
+
+ if (property->isFunction() && !property->isVarProperty()) {
+ if (property->isVMEFunction()) {
+ QQmlVMEMetaObject *vmemo = QQmlVMEMetaObject::get(object);
+ Q_ASSERT(vmemo);
+ return vmemo->vmeMethod(property->coreIndex());
+ } else if (property->isV4Function()) {
+ Scope scope(engine);
+ ScopedContext global(scope, engine->qmlContext());
+ if (!global)
+ global = engine->rootContext();
+ return QV4::QObjectMethod::create(global, object, property->coreIndex());
+ } else if (property->isSignalHandler()) {
+ QmlSignalHandler::initProto(engine);
+ return engine->memoryManager->allocObject<QV4::QmlSignalHandler>(object, property->coreIndex())->asReturnedValue();
+ } else {
+ ExecutionContext *global = engine->rootContext();
+ return QV4::QObjectMethod::create(global, object, property->coreIndex());
+ }
+ }
+
+ QQmlEnginePrivate *ep = engine->qmlEngine() ? QQmlEnginePrivate::get(engine->qmlEngine()) : 0;
+
+ if (captureRequired && ep && ep->propertyCapture && !property->isConstant())
+ ep->propertyCapture->captureProperty(object, property->coreIndex(), property->notifyIndex());
+
+ if (property->isVarProperty()) {
+ QQmlVMEMetaObject *vmemo = QQmlVMEMetaObject::get(object);
+ Q_ASSERT(vmemo);
+ return vmemo->vmeProperty(property->coreIndex());
+ } else {
+ return loadProperty(engine, object, *property);
+ }
+}
+
ReturnedValue QObjectWrapper::getQmlProperty(QQmlContextData *qmlContext, String *name, QObjectWrapper::RevisionMode revisionMode,
bool *hasProperty, bool includeImports) const
{
@@ -250,11 +297,11 @@ ReturnedValue QObjectWrapper::getQmlProperty(QQmlContextData *qmlContext, String
if (r.scriptIndex != -1) {
return QV4::Encode::undefined();
} else if (r.type.isValid()) {
- return QmlTypeWrapper::create(v4, d()->object(),
- r.type, Heap::QmlTypeWrapper::ExcludeEnums);
+ return QQmlTypeWrapper::create(v4, d()->object(),
+ r.type, Heap::QQmlTypeWrapper::ExcludeEnums);
} else if (r.importNamespace) {
- return QmlTypeWrapper::create(v4, d()->object(),
- qmlContext->imports, r.importNamespace, Heap::QmlTypeWrapper::ExcludeEnums);
+ return QQmlTypeWrapper::create(v4, d()->object(),
+ qmlContext->imports, r.importNamespace, Heap::QQmlTypeWrapper::ExcludeEnums);
}
Q_ASSERT(!"Unreachable");
}
@@ -279,42 +326,19 @@ ReturnedValue QObjectWrapper::getQmlProperty(QQmlContextData *qmlContext, String
return getProperty(v4, d()->object(), result);
}
-ReturnedValue QObjectWrapper::getProperty(ExecutionEngine *engine, QObject *object, QQmlPropertyData *property, bool captureRequired)
+ReturnedValue QObjectWrapper::getProperty(ExecutionEngine *engine, QObject *object, int propertyIndex, bool captureRequired)
{
- QQmlData::flushPendingBinding(object, QQmlPropertyIndex(property->coreIndex()));
-
- if (property->isFunction() && !property->isVarProperty()) {
- if (property->isVMEFunction()) {
- QQmlVMEMetaObject *vmemo = QQmlVMEMetaObject::get(object);
- Q_ASSERT(vmemo);
- return vmemo->vmeMethod(property->coreIndex());
- } else if (property->isV4Function()) {
- Scope scope(engine);
- ScopedContext global(scope, engine->qmlContext());
- if (!global)
- global = engine->rootContext();
- return QV4::QObjectMethod::create(global, object, property->coreIndex());
- } else if (property->isSignalHandler()) {
- QmlSignalHandler::initProto(engine);
- return engine->memoryManager->allocObject<QV4::QmlSignalHandler>(object, property->coreIndex())->asReturnedValue();
- } else {
- ExecutionContext *global = engine->rootContext();
- return QV4::QObjectMethod::create(global, object, property->coreIndex());
- }
- }
-
- QQmlEnginePrivate *ep = engine->qmlEngine() ? QQmlEnginePrivate::get(engine->qmlEngine()) : 0;
-
- if (captureRequired && ep && ep->propertyCapture && !property->isConstant())
- ep->propertyCapture->captureProperty(object, property->coreIndex(), property->notifyIndex());
+ if (QQmlData::wasDeleted(object))
+ return QV4::Encode::null();
+ QQmlData *ddata = QQmlData::get(object, /*create*/false);
+ if (!ddata)
+ return QV4::Encode::undefined();
- if (property->isVarProperty()) {
- QQmlVMEMetaObject *vmemo = QQmlVMEMetaObject::get(object);
- Q_ASSERT(vmemo);
- return vmemo->vmeProperty(property->coreIndex());
- } else {
- return loadProperty(engine, object, *property);
- }
+ 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)
@@ -325,12 +349,49 @@ ReturnedValue QObjectWrapper::getQmlProperty(QV4::ExecutionEngine *engine, QQmlC
return QV4::Encode::null();
}
- if (!QQmlData::get(object, true)) {
+ 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 = false;
- return QV4::Encode::null();
+ *hasProperty = true;
+ ExecutionContext *global = engine->rootContext();
+ return QV4::QObjectMethod::create(global, object, index);
+ }
+
+ QQmlData *ddata = QQmlData::get(object, false);
+ QQmlPropertyData local;
+ QQmlPropertyData *result = findProperty(engine, object, qmlContext, name, revisionMode, &local);
+
+ if (result) {
+ if (revisionMode == QV4::QObjectWrapper::CheckRevision && result->hasRevision()) {
+ if (ddata && ddata->propertyCache && !ddata->propertyCache->isAllowedInRevision(result)) {
+ if (hasProperty)
+ *hasProperty = false;
+ return QV4::Encode::undefined();
+ }
+ }
+
+ if (hasProperty)
+ *hasProperty = true;
+
+ return getProperty(engine, object, result);
+ } else {
+ // Check if this object is already wrapped.
+ if (!ddata || (ddata->jsWrapper.isUndefined() &&
+ (ddata->jsEngineId == 0 || // Nobody owns the QObject
+ !ddata->hasTaintedV4Object))) { // Someone else has used the QObject, but it isn't tainted
+
+ // Not wrapped. Last chance: try query QObjectWrapper's prototype.
+ // If it can't handle this, then there is no point
+ // to wrap the QObject just to look at an empty set of JS props.
+ QV4::Object *proto = QObjectWrapper::defaultPrototype(engine);
+ return proto->get(name, hasProperty);
+ }
}
+ // If we get here, we must already be wrapped (which implies a ddata).
+ // There's no point wrapping again, as there wouldn't be any new props.
+ Q_ASSERT(ddata);
+
QV4::Scope scope(engine);
QV4::Scoped<QObjectWrapper> wrapper(scope, wrap(engine, object));
if (!wrapper) {
@@ -341,6 +402,7 @@ ReturnedValue QObjectWrapper::getQmlProperty(QV4::ExecutionEngine *engine, QQmlC
return wrapper->getQmlProperty(qmlContext, name, revisionMode, hasProperty);
}
+
bool QObjectWrapper::setQmlProperty(ExecutionEngine *engine, QQmlContextData *qmlContext, QObject *object, String *name,
QObjectWrapper::RevisionMode revisionMode, const Value &value)
{
@@ -399,10 +461,23 @@ void QObjectWrapper::setProperty(ExecutionEngine *engine, QObject *object, QQmlP
}
}
- if (newBinding)
+ if (newBinding) {
QQmlPropertyPrivate::setBinding(newBinding);
- else
+ } else {
+ if (Q_UNLIKELY(lcBindingRemoval().isInfoEnabled())) {
+ if (auto binding = QQmlPropertyPrivate::binding(object, QQmlPropertyIndex(property->coreIndex()))) {
+ Q_ASSERT(!binding->isValueTypeProxy());
+ const auto qmlBinding = static_cast<const QQmlBinding*>(binding);
+ const auto stackFrame = engine->currentStackFrame();
+ qCInfo(lcBindingRemoval,
+ "Overwriting binding on %s::%s at %s:%d that was initially bound at %s",
+ object->metaObject()->className(), qPrintable(property->name(object)),
+ qPrintable(stackFrame.source), stackFrame.line,
+ qPrintable(qmlBinding->expressionIdentifier()));
+ }
+ }
QQmlPropertyPrivate::removeBinding(object, QQmlPropertyIndex(property->coreIndex()));
+ }
if (!newBinding && property->isVarProperty()) {
// allow assignment of "special" values (null, undefined, function) to var properties
@@ -539,7 +614,7 @@ ReturnedValue QObjectWrapper::wrap_slowPath(ExecutionEngine *engine, QObject *ob
}
}
-void QObjectWrapper::markWrapper(QObject *object, ExecutionEngine *engine)
+void QObjectWrapper::markWrapper(QObject *object, MarkStack *markStack)
{
if (QQmlData::wasDeleted(object))
return;
@@ -548,25 +623,10 @@ void QObjectWrapper::markWrapper(QObject *object, ExecutionEngine *engine)
if (!ddata)
return;
- if (ddata->jsEngineId == engine->m_engineId)
- ddata->jsWrapper.markOnce(engine);
- else if (engine->m_multiplyWrappedQObjects && ddata->hasTaintedV4Object)
- engine->m_multiplyWrappedQObjects->mark(object, engine);
-}
-
-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();
-
- 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);
+ if (ddata->jsEngineId == markStack->engine->m_engineId)
+ ddata->jsWrapper.markOnce(markStack);
+ else if (markStack->engine->m_multiplyWrappedQObjects && ddata->hasTaintedV4Object)
+ markStack->engine->m_multiplyWrappedQObjects->mark(object, markStack);
}
void QObjectWrapper::setProperty(ExecutionEngine *engine, int propertyIndex, const Value &value)
@@ -598,7 +658,7 @@ bool QObjectWrapper::isEqualTo(Managed *a, Managed *b)
QV4::QObjectWrapper *qobjectWrapper = static_cast<QV4::QObjectWrapper *>(a);
QV4::Object *o = b->as<Object>();
if (o) {
- if (QV4::QmlTypeWrapper *qmlTypeWrapper = o->as<QV4::QmlTypeWrapper>())
+ if (QV4::QQmlTypeWrapper *qmlTypeWrapper = o->as<QV4::QQmlTypeWrapper>())
return qmlTypeWrapper->toVariant().value<QObject*>() == qobjectWrapper->object();
}
@@ -625,13 +685,13 @@ QV4::ReturnedValue QObjectWrapper::get(const Managed *m, String *name, bool *has
return that->getQmlProperty(qmlContext, name, IgnoreRevision, hasProperty, /*includeImports*/ true);
}
-void QObjectWrapper::put(Managed *m, String *name, const Value &value)
+bool QObjectWrapper::put(Managed *m, String *name, const Value &value)
{
QObjectWrapper *that = static_cast<QObjectWrapper*>(m);
ExecutionEngine *v4 = that->engine();
if (v4->hasException || QQmlData::wasDeleted(that->d()->object()))
- return;
+ return false;
QQmlContextData *qmlContext = v4->callingQmlContext();
if (!setQmlProperty(v4, qmlContext, that->d()->object(), name, QV4::QObjectWrapper::IgnoreRevision, value)) {
@@ -642,10 +702,13 @@ void QObjectWrapper::put(Managed *m, String *name, const Value &value)
QString error = QLatin1String("Cannot assign to non-existent property \"") +
name->toQString() + QLatin1Char('\"');
v4->throwError(error);
+ return false;
} else {
- QV4::Object::put(m, name, value);
+ return QV4::Object::put(m, name, value);
}
}
+
+ return true;
}
PropertyAttributes QObjectWrapper::query(const Managed *m, String *name)
@@ -939,36 +1002,36 @@ void QObjectWrapper::method_disconnect(const BuiltinFunction *, Scope &scope, Ca
RETURN_UNDEFINED();
}
-static void markChildQObjectsRecursively(QObject *parent, QV4::ExecutionEngine *e)
+static void markChildQObjectsRecursively(QObject *parent, QV4::MarkStack *markStack)
{
const QObjectList &children = parent->children();
for (int i = 0; i < children.count(); ++i) {
QObject *child = children.at(i);
if (!child)
continue;
- QObjectWrapper::markWrapper(child, e);
- markChildQObjectsRecursively(child, e);
+ QObjectWrapper::markWrapper(child, markStack);
+ markChildQObjectsRecursively(child, markStack);
}
}
-void QObjectWrapper::markObjects(Heap::Base *that, QV4::ExecutionEngine *e)
+void QObjectWrapper::markObjects(Heap::Base *that, QV4::MarkStack *markStack)
{
QObjectWrapper::Data *This = static_cast<QObjectWrapper::Data *>(that);
if (QObject *o = This->object()) {
QQmlVMEMetaObject *vme = QQmlVMEMetaObject::get(o);
if (vme)
- vme->mark(e);
+ vme->mark(markStack);
// Children usually don't need to be marked, the gc keeps them alive.
// But in the rare case of a "floating" QObject without a parent that
// _gets_ marked (we've been called here!) then we also need to
// propagate the marking down to the children recursively.
if (!o->parent())
- markChildQObjectsRecursively(o, e);
+ markChildQObjectsRecursively(o, markStack);
}
- QV4::Object::markObjects(that, e);
+ QV4::Object::markObjects(that, markStack);
}
void QObjectWrapper::destroyObject(bool lastCall)
@@ -1038,12 +1101,21 @@ private:
inline void cleanup();
+ template <class T, class M>
+ void fromContainerValue(const QV4::Object *object, int type, M CallArgument::*member, bool &queryEngine);
+
union {
float floatValue;
double doubleValue;
quint32 intValue;
bool boolValue;
QObject *qobjectPtr;
+ std::vector<int> *stdVectorIntPtr;
+ std::vector<qreal> *stdVectorRealPtr;
+ std::vector<bool> *stdVectorBoolPtr;
+ std::vector<QString> *stdVectorQStringPtr;
+ std::vector<QUrl> *stdVectorQUrlPtr;
+ std::vector<QModelIndex> *stdVectorQModelIndexPtr;
char allocData[MaxSizeOf8<QVariant,
QString,
@@ -1473,6 +1545,18 @@ void *CallArgument::dataPtr()
{
if (type == -1)
return qvariantPtr->data();
+ else if (type == qMetaTypeId<std::vector<int>>())
+ return stdVectorIntPtr;
+ else if (type == qMetaTypeId<std::vector<qreal>>())
+ return stdVectorRealPtr;
+ else if (type == qMetaTypeId<std::vector<bool>>())
+ return stdVectorBoolPtr;
+ else if (type == qMetaTypeId<std::vector<QString>>())
+ return stdVectorQStringPtr;
+ else if (type == qMetaTypeId<std::vector<QUrl>>())
+ return stdVectorQUrlPtr;
+ else if (type == qMetaTypeId<std::vector<QModelIndex>>())
+ return stdVectorQModelIndexPtr;
else if (type != 0)
return (void *)&allocData;
return 0;
@@ -1522,6 +1606,19 @@ void CallArgument::initAsType(int callType)
}
}
+template <class T, class M>
+void CallArgument::fromContainerValue(const QV4::Object *object, int callType, M CallArgument::*member, bool &queryEngine)
+{
+ if (object && object->isListType()) {
+ T* ptr = static_cast<T*>(QV4::SequencePrototype::getRawContainerPtr(object, callType));
+ if (ptr) {
+ (this->*member) = ptr;
+ type = callType;
+ queryEngine = false;
+ }
+ }
+}
+
void CallArgument::fromValue(int callType, QV4::ExecutionEngine *engine, const QV4::Value &value)
{
if (type != 0) {
@@ -1560,7 +1657,7 @@ void CallArgument::fromValue(int callType, QV4::ExecutionEngine *engine, const Q
qobjectPtr = 0;
if (const QV4::QObjectWrapper *qobjectWrapper = value.as<QV4::QObjectWrapper>())
qobjectPtr = qobjectWrapper->object();
- else if (const QV4::QmlTypeWrapper *qmlTypeWrapper = value.as<QV4::QmlTypeWrapper>())
+ else if (const QV4::QQmlTypeWrapper *qmlTypeWrapper = value.as<QV4::QQmlTypeWrapper>())
queryEngine = qmlTypeWrapper->isSingleton();
type = callType;
} else if (callType == qMetaTypeId<QVariant>()) {
@@ -1603,6 +1700,33 @@ void CallArgument::fromValue(int callType, QV4::ExecutionEngine *engine, const Q
type = callType;
} else if (callType == QMetaType::Void) {
*qvariantPtr = QVariant();
+ } else if (callType == qMetaTypeId<std::vector<int>>()
+ || callType == qMetaTypeId<std::vector<qreal>>()
+ || callType == qMetaTypeId<std::vector<bool>>()
+ || callType == qMetaTypeId<std::vector<QString>>()
+ || callType == qMetaTypeId<std::vector<QUrl>>()
+ || callType == qMetaTypeId<std::vector<QModelIndex>>()) {
+ queryEngine = true;
+ const QV4::Object* object = value.as<Object>();
+ if (callType == qMetaTypeId<std::vector<int>>()) {
+ stdVectorIntPtr = nullptr;
+ fromContainerValue<std::vector<int>>(object, callType, &CallArgument::stdVectorIntPtr, queryEngine);
+ } else if (callType == qMetaTypeId<std::vector<qreal>>()) {
+ stdVectorRealPtr = nullptr;
+ fromContainerValue<std::vector<qreal>>(object, callType, &CallArgument::stdVectorRealPtr, queryEngine);
+ } else if (callType == qMetaTypeId<std::vector<bool>>()) {
+ stdVectorBoolPtr = nullptr;
+ fromContainerValue<std::vector<bool>>(object, callType, &CallArgument::stdVectorBoolPtr, queryEngine);
+ } else if (callType == qMetaTypeId<std::vector<QString>>()) {
+ stdVectorQStringPtr = nullptr;
+ fromContainerValue<std::vector<QString>>(object, callType, &CallArgument::stdVectorQStringPtr, queryEngine);
+ } else if (callType == qMetaTypeId<std::vector<QUrl>>()) {
+ stdVectorQUrlPtr = nullptr;
+ fromContainerValue<std::vector<QUrl>>(object, callType, &CallArgument::stdVectorQUrlPtr, queryEngine);
+ } else if (callType == qMetaTypeId<std::vector<QModelIndex>>()) {
+ stdVectorQModelIndexPtr = nullptr;
+ fromContainerValue<std::vector<QModelIndex>>(object, callType, &CallArgument::stdVectorQModelIndexPtr, queryEngine);
+ }
} else {
queryEngine = true;
}
@@ -1712,7 +1836,7 @@ ReturnedValue QObjectMethod::create(ExecutionContext *scope, const QQmlValueType
Scoped<QObjectMethod> method(valueScope, valueScope.engine->memoryManager->allocObject<QObjectMethod>(scope));
method->d()->setPropertyCache(valueType->d()->propertyCache());
method->d()->index = index;
- method->d()->valueTypeWrapper = valueType->d();
+ method->d()->valueTypeWrapper.set(valueScope.engine, valueType->d());
return method.asReturnedValue();
}
@@ -1849,15 +1973,6 @@ void QObjectMethod::callInternal(CallData *callData, Scope &scope) const
}
}
-void QObjectMethod::markObjects(Heap::Base *that, ExecutionEngine *e)
-{
- QObjectMethod::Data *This = static_cast<QObjectMethod::Data*>(that);
- if (This->valueTypeWrapper)
- This->valueTypeWrapper->mark(e);
-
- FunctionObject::markObjects(that, e);
-}
-
DEFINE_OBJECT_VTABLE(QObjectMethod);
@@ -2083,12 +2198,12 @@ void MultiplyWrappedQObjectMap::remove(QObject *key)
erase(it);
}
-void MultiplyWrappedQObjectMap::mark(QObject *key, ExecutionEngine *engine)
+void MultiplyWrappedQObjectMap::mark(QObject *key, MarkStack *markStack)
{
Iterator it = find(key);
if (it == end())
return;
- it->markOnce(engine);
+ it->markOnce(markStack);
}
void MultiplyWrappedQObjectMap::removeDestroyedObject(QObject *object)
diff --git a/src/qml/jsruntime/qv4qobjectwrapper_p.h b/src/qml/jsruntime/qv4qobjectwrapper_p.h
index 6494c20bd2..018e444f7c 100644
--- a/src/qml/jsruntime/qv4qobjectwrapper_p.h
+++ b/src/qml/jsruntime/qv4qobjectwrapper_p.h
@@ -95,7 +95,15 @@ private:
QQmlQPointer<QObject> qObj;
};
-struct QObjectMethod : FunctionObject {
+#define QObjectMethodMembers(class, Member) \
+ Member(class, Pointer, QQmlValueTypeWrapper *, valueTypeWrapper) \
+ Member(class, NoMark, QQmlQPointer<QObject>, qObj) \
+ Member(class, NoMark, QQmlPropertyCache *, _propertyCache) \
+ Member(class, NoMark, int, index)
+
+DECLARE_HEAP_OBJECT(QObjectMethod, FunctionObject) {
+ DECLARE_MARK_TABLE(QObjectMethod);
+
void init(QV4::ExecutionContext *scope);
void destroy()
{
@@ -113,18 +121,10 @@ struct QObjectMethod : FunctionObject {
_propertyCache = c;
}
- Pointer<QQmlValueTypeWrapper> valueTypeWrapper;
-
const QMetaObject *metaObject();
QObject *object() const { return qObj.data(); }
void setObject(QObject *o) { qObj = o; }
-private:
- QQmlQPointer<QObject> qObj;
- QQmlPropertyCache *_propertyCache;
-
-public:
- int index;
};
struct QMetaObjectWrapper : FunctionObject {
@@ -171,7 +171,7 @@ struct Q_QML_EXPORT QObjectWrapper : public Object
static bool setQmlProperty(ExecutionEngine *engine, QQmlContextData *qmlContext, QObject *object, String *name, RevisionMode revisionMode, const Value &value);
static ReturnedValue wrap(ExecutionEngine *engine, QObject *object);
- static void markWrapper(QObject *object, ExecutionEngine *engine);
+ static void markWrapper(QObject *object, MarkStack *markStack);
using Object::get;
@@ -189,13 +189,14 @@ protected:
static ReturnedValue create(ExecutionEngine *engine, QObject *object);
+ static QQmlPropertyData *findProperty(ExecutionEngine *engine, QObject *o, QQmlContextData *qmlContext, String *name, RevisionMode revisionMode, QQmlPropertyData *local);
QQmlPropertyData *findProperty(ExecutionEngine *engine, QQmlContextData *qmlContext, String *name, RevisionMode revisionMode, QQmlPropertyData *local) const;
static ReturnedValue get(const Managed *m, String *name, bool *hasProperty);
- static void put(Managed *m, String *name, const Value &value);
+ static bool put(Managed *m, String *name, const Value &value);
static PropertyAttributes query(const Managed *, String *name);
static void advanceIterator(Managed *m, ObjectIterator *it, Value *name, uint *index, Property *p, PropertyAttributes *attributes);
- static void markObjects(Heap::Base *that, QV4::ExecutionEngine *e);
+ static void markObjects(Heap::Base *that, QV4::MarkStack *markStack);
static void method_connect(const BuiltinFunction *, Scope &scope, CallData *callData);
static void method_disconnect(const BuiltinFunction *, Scope &scope, CallData *callData);
@@ -240,8 +241,6 @@ struct Q_QML_EXPORT QObjectMethod : public QV4::FunctionObject
void callInternal(CallData *callData, Scope &scope) const;
- static void markObjects(Heap::Base *that, QV4::ExecutionEngine *e);
-
static QPair<QObject *, int> extractQtMethod(const QV4::FunctionObject *function);
};
@@ -294,7 +293,7 @@ public:
ReturnedValue value(QObject *key) const { return QHash<QObject*, QV4::WeakValue>::value(key).value(); }
Iterator erase(Iterator it);
void remove(QObject *key);
- void mark(QObject *key, ExecutionEngine *engine);
+ void mark(QObject *key, MarkStack *markStack);
private Q_SLOTS:
void removeDestroyedObject(QObject*);
diff --git a/src/qml/jsruntime/qv4regexp.cpp b/src/qml/jsruntime/qv4regexp.cpp
index 8cb15b9d7e..162f0fba57 100644
--- a/src/qml/jsruntime/qv4regexp.cpp
+++ b/src/qml/jsruntime/qv4regexp.cpp
@@ -127,9 +127,3 @@ void Heap::RegExp::destroy()
delete pattern;
Base::destroy();
}
-
-void RegExp::markObjects(Heap::Base *that, ExecutionEngine *e)
-{
- Q_UNUSED(that);
- Q_UNUSED(e);
-}
diff --git a/src/qml/jsruntime/qv4regexp_p.h b/src/qml/jsruntime/qv4regexp_p.h
index d9b536406c..998f6e3da3 100644
--- a/src/qml/jsruntime/qv4regexp_p.h
+++ b/src/qml/jsruntime/qv4regexp_p.h
@@ -122,8 +122,6 @@ struct RegExp : public Managed
int captureCount() const { return subPatternCount() + 1; }
- static void markObjects(Heap::Base *that, QV4::ExecutionEngine *e);
-
friend class RegExpCache;
};
diff --git a/src/qml/jsruntime/qv4regexpobject.cpp b/src/qml/jsruntime/qv4regexpobject.cpp
index 82b0f67075..83bfe21c67 100644
--- a/src/qml/jsruntime/qv4regexpobject.cpp
+++ b/src/qml/jsruntime/qv4regexpobject.cpp
@@ -74,15 +74,15 @@ void Heap::RegExpObject::init()
Object::init();
Scope scope(internalClass->engine);
Scoped<QV4::RegExpObject> o(scope, this);
- o->d()->value = QV4::RegExp::create(scope.engine, QString(), false, false, false);
+ value.set(scope.engine, QV4::RegExp::create(scope.engine, QString(), false, false));
o->initProperties();
}
void Heap::RegExpObject::init(QV4::RegExp *value)
{
Object::init();
- this->value = value->d();
Scope scope(internalClass->engine);
+ this->value.set(scope.engine, value->d());
Scoped<QV4::RegExpObject> o(scope, this);
o->initProperties();
}
@@ -134,14 +134,15 @@ void Heap::RegExpObject::init(const QRegExp &re)
Scope scope(internalClass->engine);
Scoped<QV4::RegExpObject> o(scope, this);
- o->d()->value = QV4::RegExp::create(scope.engine, pattern, re.caseSensitivity() == Qt::CaseInsensitive, false);
+ o->d()->value.set(scope.engine,
+ QV4::RegExp::create(scope.engine, pattern, re.caseSensitivity() == Qt::CaseInsensitive, false));
o->initProperties();
}
void RegExpObject::initProperties()
{
- *propertyData(Index_LastIndex) = Primitive::fromInt32(0);
+ setProperty(Index_LastIndex, Primitive::fromInt32(0));
Q_ASSERT(value());
@@ -153,25 +154,10 @@ void RegExpObject::initProperties()
p.replace('/', QLatin1String("\\/"));
}
- *propertyData(Index_Source) = engine()->newString(p);
- *propertyData(Index_Global) = Primitive::fromBoolean(global());
- *propertyData(Index_IgnoreCase) = Primitive::fromBoolean(value()->ignoreCase);
- *propertyData(Index_Multiline) = Primitive::fromBoolean(value()->multiLine);
-}
-
-
-void RegExpObject::markObjects(Heap::Base *that, ExecutionEngine *e)
-{
- RegExpObject::Data *re = static_cast<RegExpObject::Data *>(that);
- if (re->value)
- re->value->mark(e);
- Object::markObjects(that, e);
-}
-
-Value *RegExpObject::lastIndexProperty()
-{
- Q_ASSERT(0 == internalClass()->find(engine()->id_lastIndex()));
- return propertyData(0);
+ setProperty(Index_Source, engine()->newString(p));
+ setProperty(Index_Global, Primitive::fromBoolean(global()));
+ setProperty(Index_IgnoreCase, Primitive::fromBoolean(value()->ignoreCase));
+ setProperty(Index_Multiline, Primitive::fromBoolean(value()->multiLine));
}
// Converts a JS RegExp to a QRegExp.
@@ -225,8 +211,8 @@ void Heap::RegExpCtor::init(QV4::ExecutionContext *scope)
void Heap::RegExpCtor::clearLastMatch()
{
- lastMatch = Primitive::nullValue();
- lastInput = internalClass->engine->id_empty()->d();
+ lastMatch.set(internalClass->engine, Primitive::nullValue());
+ lastInput.set(internalClass->engine, internalClass->engine->id_empty()->d());
lastMatchStart = 0;
lastMatchEnd = 0;
}
@@ -300,15 +286,6 @@ void RegExpCtor::call(const Managed *that, Scope &scope, CallData *callData)
construct(that, scope, callData);
}
-void RegExpCtor::markObjects(Heap::Base *that, ExecutionEngine *e)
-{
- RegExpCtor::Data *This = static_cast<RegExpCtor::Data *>(that);
- This->lastMatch.mark(e);
- if (This->lastInput)
- This->lastInput->mark(e);
- FunctionObject::markObjects(that, e);
-}
-
void RegExpPrototype::init(ExecutionEngine *engine, Object *constructor)
{
Scope scope(engine);
@@ -358,9 +335,9 @@ void RegExpPrototype::method_exec(const BuiltinFunction *, Scope &scope, CallDat
RETURN_UNDEFINED();
QString s = str->toQString();
- int offset = r->global() ? r->lastIndexProperty()->toInt32() : 0;
+ int offset = r->global() ? r->lastIndex() : 0;
if (offset < 0 || offset > s.length()) {
- *r->lastIndexProperty() = Primitive::fromInt32(0);
+ r->setLastIndex(0);
RETURN_RESULT(Encode::null());
}
@@ -371,7 +348,7 @@ void RegExpPrototype::method_exec(const BuiltinFunction *, Scope &scope, CallDat
regExpCtor->d()->clearLastMatch();
if (result == -1) {
- *r->lastIndexProperty() = Primitive::fromInt32(0);
+ r->setLastIndex(0);
RETURN_RESULT(Encode::null());
}
@@ -387,17 +364,17 @@ void RegExpPrototype::method_exec(const BuiltinFunction *, Scope &scope, CallDat
array->arrayPut(i, v);
}
array->setArrayLengthUnchecked(len);
- *array->propertyData(Index_ArrayIndex) = Primitive::fromInt32(result);
- *array->propertyData(Index_ArrayInput) = str;
+ array->setProperty(Index_ArrayIndex, Primitive::fromInt32(result));
+ array->setProperty(Index_ArrayInput, str);
RegExpCtor::Data *dd = regExpCtor->d();
- dd->lastMatch = array;
- dd->lastInput = str->d();
+ dd->lastMatch.set(scope.engine, array);
+ dd->lastInput.set(scope.engine, str->d());
dd->lastMatchStart = matchOffsets[0];
dd->lastMatchEnd = matchOffsets[1];
if (r->global())
- *r->lastIndexProperty() = Primitive::fromInt32(matchOffsets[1]);
+ r->setLastIndex(matchOffsets[1]);
scope.result = array;
}
@@ -429,8 +406,7 @@ void RegExpPrototype::method_compile(const BuiltinFunction *, Scope &scope, Call
scope.engine->regExpCtor()->as<FunctionObject>()->construct(scope, cData);
Scoped<RegExpObject> re(scope, scope.result.asReturnedValue());
- r->d()->value = re->value();
- RETURN_UNDEFINED();
+ r->d()->value.set(scope.engine, re->value());
}
template <int index>
diff --git a/src/qml/jsruntime/qv4regexpobject_p.h b/src/qml/jsruntime/qv4regexpobject_p.h
index af49a1bf5e..65055ccc81 100644
--- a/src/qml/jsruntime/qv4regexpobject_p.h
+++ b/src/qml/jsruntime/qv4regexpobject_p.h
@@ -55,8 +55,8 @@
#include "qv4context_p.h"
#include "qv4functionobject_p.h"
#include "qv4string_p.h"
-#include "qv4codegen_p.h"
-#include "qv4isel_p.h"
+#include <qv4codegen_p.h>
+#include <qv4isel_p.h>
#include "qv4managed_p.h"
#include "qv4property_p.h"
#include "qv4objectiterator_p.h"
@@ -74,20 +74,27 @@ namespace QV4 {
namespace Heap {
-struct RegExpObject : Object {
+#define RegExpObjectMembers(class, Member) \
+ Member(class, Pointer, RegExp *, value)
+
+DECLARE_HEAP_OBJECT(RegExpObject, Object) {
+ DECLARE_MARK_TABLE(RegExpObject);
+
void init();
void init(QV4::RegExp *value);
void init(const QRegExp &re);
-
- Pointer<RegExp> value;
};
-struct RegExpCtor : FunctionObject {
+#define RegExpCtorMembers(class, Member) \
+ Member(class, HeapValue, HeapValue, lastMatch) \
+ Member(class, Pointer, String *, lastInput) \
+ Member(class, NoMark, int, lastMatchStart) \
+ Member(class, NoMark, int, lastMatchEnd)
+
+DECLARE_HEAP_OBJECT(RegExpCtor, FunctionObject) {
+ DECLARE_MARK_TABLE(RegExpCtor);
+
void init(QV4::ExecutionContext *scope);
- Value lastMatch;
- Pointer<String> lastInput;
- int lastMatchStart;
- int lastMatchEnd;
void clearLastMatch();
};
@@ -121,14 +128,19 @@ struct RegExpObject: Object {
void initProperties();
- Value *lastIndexProperty();
+ int lastIndex() const {
+ Q_ASSERT(Index_LastIndex == internalClass()->find(engine()->id_lastIndex()));
+ return propertyData(Index_LastIndex)->toInt32();
+ }
+ void setLastIndex(int index) {
+ Q_ASSERT(Index_LastIndex == internalClass()->find(engine()->id_lastIndex()));
+ return setProperty(Index_LastIndex, Primitive::fromInt32(index));
+ }
+
QRegExp toQRegExp() const;
QString toString() const;
QString source() const;
uint flags() const;
-
-protected:
- static void markObjects(Heap::Base *that, ExecutionEngine *e);
};
struct RegExpCtor: FunctionObject
@@ -142,7 +154,6 @@ struct RegExpCtor: FunctionObject
static void construct(const Managed *m, Scope &scope, CallData *callData);
static void call(const Managed *that, Scope &scope, CallData *callData);
- static void markObjects(Heap::Base *that, ExecutionEngine *e);
};
struct RegExpPrototype: RegExpObject
diff --git a/src/qml/jsruntime/qv4runtime.cpp b/src/qml/jsruntime/qv4runtime.cpp
index 28b344d154..4b952bcbbc 100644
--- a/src/qml/jsruntime/qv4runtime.cpp
+++ b/src/qml/jsruntime/qv4runtime.cpp
@@ -665,7 +665,7 @@ ReturnedValue Runtime::method_getElement(ExecutionEngine *engine, const Value &o
Heap::Object *o = static_cast<Heap::Object *>(b);
if (o->arrayData && o->arrayData->type == Heap::ArrayData::Simple) {
Heap::SimpleArrayData *s = o->arrayData.cast<Heap::SimpleArrayData>();
- if (idx < s->len)
+ if (idx < s->values.size)
if (!s->data(idx).isEmpty())
return s->data(idx).asReturnedValue();
}
@@ -688,8 +688,8 @@ static Q_NEVER_INLINE void setElementFallback(ExecutionEngine *engine, const Val
if (index.asArrayIndex(idx)) {
if (o->d()->arrayData && o->d()->arrayData->type == Heap::ArrayData::Simple) {
Heap::SimpleArrayData *s = o->d()->arrayData.cast<Heap::SimpleArrayData>();
- if (idx < s->len) {
- s->data(idx) = value;
+ if (idx < s->values.size) {
+ s->setData(engine, idx, value);
return;
}
}
@@ -710,8 +710,8 @@ void Runtime::method_setElement(ExecutionEngine *engine, const Value &object, co
Heap::Object *o = static_cast<Heap::Object *>(b);
if (o->arrayData && o->arrayData->type == Heap::ArrayData::Simple) {
Heap::SimpleArrayData *s = o->arrayData.cast<Heap::SimpleArrayData>();
- if (idx < s->len) {
- s->data(idx) = value;
+ if (idx < s->values.size) {
+ s->setData(engine, idx, value);
return;
}
}
@@ -1377,7 +1377,7 @@ ReturnedValue Runtime::method_objectLiteral(ExecutionEngine *engine, const QV4::
}
for (uint i = 0; i < klass->size; ++i)
- *o->propertyData(i) = *args++;
+ o->setProperty(i, *args++);
if (arrayValueCount > 0) {
ScopedValue entry(scope);
@@ -1521,7 +1521,7 @@ ReturnedValue Runtime::method_getQmlContextObjectProperty(ExecutionEngine *engin
ReturnedValue Runtime::method_getQmlSingletonQObjectProperty(ExecutionEngine *engine, const Value &object, int propertyIndex, bool captureRequired)
{
Scope scope(engine);
- QV4::Scoped<QmlTypeWrapper> wrapper(scope, object);
+ QV4::Scoped<QQmlTypeWrapper> wrapper(scope, object);
if (!wrapper) {
scope.engine->throwTypeError(QStringLiteral("Cannot read property of null"));
return Encode::undefined();
diff --git a/src/qml/jsruntime/qv4sequenceobject.cpp b/src/qml/jsruntime/qv4sequenceobject.cpp
index 8ce10e326d..8afc672aa2 100644
--- a/src/qml/jsruntime/qv4sequenceobject.cpp
+++ b/src/qml/jsruntime/qv4sequenceobject.cpp
@@ -78,13 +78,22 @@ static void generateWarning(QV4::ExecutionEngine *v4, const QString& description
F(int, IntVector, QVector<int>, 0) \
F(qreal, RealVector, QVector<qreal>, 0.0) \
F(bool, BoolVector, QVector<bool>, false) \
+ F(int, IntStdVector, std::vector<int>, 0) \
+ F(qreal, RealStdVector, std::vector<qreal>, 0.0) \
+ F(bool, BoolStdVector, std::vector<bool>, false) \
F(int, Int, QList<int>, 0) \
F(qreal, Real, QList<qreal>, 0.0) \
F(bool, Bool, QList<bool>, false) \
F(QString, String, QList<QString>, QString()) \
F(QString, QString, QStringList, QString()) \
+ F(QString, StringVector, QVector<QString>, QString()) \
+ F(QString, StringStdVector, std::vector<QString>, QString()) \
F(QUrl, Url, QList<QUrl>, QUrl()) \
+ F(QUrl, UrlVector, QVector<QUrl>, QUrl()) \
+ F(QUrl, UrlStdVector, std::vector<QUrl>, QUrl()) \
F(QModelIndex, QModelIndex, QModelIndexList, QModelIndex()) \
+ F(QModelIndex, QModelIndexVector, QVector<QModelIndex>, QModelIndex()) \
+ F(QModelIndex, QModelIndexStdVector, std::vector<QModelIndex>, QModelIndex()) \
F(QItemSelectionRange, QItemSelectionRange, QItemSelection, QItemSelectionRange())
static QV4::ReturnedValue convertElementToValue(QV4::ExecutionEngine *engine, const QString &element)
@@ -263,56 +272,54 @@ public:
}
loadReference();
}
- qint32 signedIdx = static_cast<qint32>(index);
- if (signedIdx < d()->container->count()) {
+ if (index < size_t(d()->container->size())) {
if (hasProperty)
*hasProperty = true;
- return convertElementToValue(engine(), d()->container->at(signedIdx));
+ return convertElementToValue(engine(), qAsConst(*(d()->container))[index]);
}
if (hasProperty)
*hasProperty = false;
return Encode::undefined();
}
- void containerPutIndexed(uint index, const QV4::Value &value)
+ bool containerPutIndexed(uint index, const QV4::Value &value)
{
if (internalClass()->engine->hasException)
- return;
+ return false;
/* Qt containers have int (rather than uint) allowable indexes. */
if (index > INT_MAX) {
generateWarning(engine(), QLatin1String("Index out of range during indexed set"));
- return;
+ return false;
}
if (d()->isReference) {
if (!d()->object)
- return;
+ return false;
loadReference();
}
- qint32 signedIdx = static_cast<qint32>(index);
-
- int count = d()->container->count();
+ size_t count = size_t(d()->container->size());
typename Container::value_type element = convertValueToElement<typename Container::value_type>(value);
- if (signedIdx == count) {
- d()->container->append(element);
- } else if (signedIdx < count) {
- (*d()->container)[signedIdx] = element;
+ if (index == count) {
+ d()->container->push_back(element);
+ } else if (index < count) {
+ (*d()->container)[index] = element;
} else {
/* according to ECMA262r3 we need to insert */
/* the value at the given index, increasing length to index+1. */
- d()->container->reserve(signedIdx + 1);
- while (signedIdx > count++) {
- d()->container->append(typename Container::value_type());
+ d()->container->reserve(index + 1);
+ while (index > count++) {
+ d()->container->push_back(typename Container::value_type());
}
- d()->container->append(element);
+ d()->container->push_back(element);
}
if (d()->isReference)
storeReference();
+ return true;
}
QV4::PropertyAttributes containerQueryIndexed(uint index) const
@@ -327,8 +334,7 @@ public:
return QV4::Attr_Invalid;
loadReference();
}
- qint32 signedIdx = static_cast<qint32>(index);
- return (signedIdx < d()->container->count()) ? QV4::Attr_Data : QV4::Attr_Invalid;
+ return (index < size_t(d()->container->size())) ? QV4::Attr_Data : QV4::Attr_Invalid;
}
void containerAdvanceIterator(ObjectIterator *it, Value *name, uint *index, Property *p, PropertyAttributes *attrs)
@@ -344,7 +350,7 @@ public:
loadReference();
}
- if (it->arrayIndex < static_cast<uint>(d()->container->count())) {
+ if (it->arrayIndex < static_cast<uint>(d()->container->size())) {
*index = it->arrayIndex;
++it->arrayIndex;
*attrs = QV4::Attr_Data;
@@ -364,14 +370,13 @@ public:
return false;
loadReference();
}
- qint32 signedIdx = static_cast<qint32>(index);
- if (signedIdx >= d()->container->count())
+ if (index >= size_t(d()->container->size()))
return false;
/* according to ECMA262r3 it should be Undefined, */
/* but we cannot, so we insert a default-value instead. */
- d()->container->replace(signedIdx, typename Container::value_type());
+ (*d()->container)[index] = typename Container::value_type();
if (d()->isReference)
storeReference();
@@ -456,7 +461,7 @@ public:
RETURN_RESULT(Encode(0));
This->loadReference();
}
- RETURN_RESULT(Encode(This->d()->container->count()));
+ RETURN_RESULT(Encode(qint32(This->d()->container->size())));
}
static void method_set_length(const BuiltinFunction *, Scope &scope, CallData *callData)
@@ -478,8 +483,8 @@ public:
This->loadReference();
}
/* Determine whether we need to modify the sequence */
- qint32 newCount = static_cast<qint32>(newLength);
- qint32 count = This->d()->container->count();
+ quint32 newCount = static_cast<quint32>(newLength);
+ quint32 count = static_cast<quint32>(This->d()->container->size());
if (newCount == count) {
RETURN_UNDEFINED();
} else if (newCount > count) {
@@ -488,14 +493,13 @@ public:
/* We cannot, so we insert default-values instead. */
This->d()->container->reserve(newCount);
while (newCount > count++) {
- This->d()->container->append(typename Container::value_type());
+ This->d()->container->push_back(typename Container::value_type());
}
} else {
/* according to ECMA262r3 we need to remove */
/* elements until the sequence is the required length. */
- while (newCount < count) {
- count--;
- This->d()->container->removeAt(count);
+ if (newCount < count) {
+ This->d()->container->erase(This->d()->container->begin() + newCount, This->d()->container->end());
}
}
/* write back if required. */
@@ -516,10 +520,13 @@ public:
quint32 length = array->getLength();
QV4::ScopedValue v(scope);
for (quint32 i = 0; i < length; ++i)
- result << convertValueToElement<typename Container::value_type>((v = array->getIndexed(i)));
+ result.push_back(convertValueToElement<typename Container::value_type>((v = array->getIndexed(i))));
return QVariant::fromValue(result);
}
+ void* getRawContainerPtr() const
+ { return d()->container; }
+
void loadReference() const
{
Q_ASSERT(d()->object);
@@ -540,8 +547,8 @@ public:
static QV4::ReturnedValue getIndexed(const QV4::Managed *that, uint index, bool *hasProperty)
{ return static_cast<const QQmlSequence<Container> *>(that)->containerGetIndexed(index, hasProperty); }
- static void putIndexed(Managed *that, uint index, const QV4::Value &value)
- { static_cast<QQmlSequence<Container> *>(that)->containerPutIndexed(index, value); }
+ static bool putIndexed(Managed *that, uint index, const QV4::Value &value)
+ { return static_cast<QQmlSequence<Container> *>(that)->containerPutIndexed(index, value); }
static QV4::PropertyAttributes queryIndexed(const QV4::Managed *that, uint index)
{ return static_cast<const QQmlSequence<Container> *>(that)->containerQueryIndexed(index); }
static bool deleteIndexedProperty(QV4::Managed *that, uint index)
@@ -594,16 +601,34 @@ typedef QQmlSequence<QVector<qreal> > QQmlRealVectorList;
DEFINE_OBJECT_TEMPLATE_VTABLE(QQmlRealVectorList);
typedef QQmlSequence<QVector<bool> > QQmlBoolVectorList;
DEFINE_OBJECT_TEMPLATE_VTABLE(QQmlBoolVectorList);
+typedef QQmlSequence<std::vector<int> > QQmlIntStdVectorList;
+DEFINE_OBJECT_TEMPLATE_VTABLE(QQmlIntStdVectorList);
+typedef QQmlSequence<std::vector<qreal> > QQmlRealStdVectorList;
+DEFINE_OBJECT_TEMPLATE_VTABLE(QQmlRealStdVectorList);
+typedef QQmlSequence<std::vector<bool> > QQmlBoolStdVectorList;
+DEFINE_OBJECT_TEMPLATE_VTABLE(QQmlBoolStdVectorList);
typedef QQmlSequence<QStringList> QQmlQStringList;
DEFINE_OBJECT_TEMPLATE_VTABLE(QQmlQStringList);
typedef QQmlSequence<QList<QString> > QQmlStringList;
DEFINE_OBJECT_TEMPLATE_VTABLE(QQmlStringList);
+typedef QQmlSequence<QVector<QString> > QQmlStringVectorList;
+DEFINE_OBJECT_TEMPLATE_VTABLE(QQmlStringVectorList);
+typedef QQmlSequence<std::vector<QString> > QQmlStringStdVectorList;
+DEFINE_OBJECT_TEMPLATE_VTABLE(QQmlStringStdVectorList);
typedef QQmlSequence<QList<int> > QQmlIntList;
DEFINE_OBJECT_TEMPLATE_VTABLE(QQmlIntList);
typedef QQmlSequence<QList<QUrl> > QQmlUrlList;
DEFINE_OBJECT_TEMPLATE_VTABLE(QQmlUrlList);
+typedef QQmlSequence<QVector<QUrl> > QQmlUrlVectorList;
+DEFINE_OBJECT_TEMPLATE_VTABLE(QQmlUrlVectorList);
+typedef QQmlSequence<std::vector<QUrl> > QQmlUrlStdVectorList;
+DEFINE_OBJECT_TEMPLATE_VTABLE(QQmlUrlStdVectorList);
typedef QQmlSequence<QModelIndexList> QQmlQModelIndexList;
DEFINE_OBJECT_TEMPLATE_VTABLE(QQmlQModelIndexList);
+typedef QQmlSequence<QVector<QModelIndex> > QQmlQModelIndexVectorList;
+DEFINE_OBJECT_TEMPLATE_VTABLE(QQmlQModelIndexVectorList);
+typedef QQmlSequence<std::vector<QModelIndex> > QQmlQModelIndexStdVectorList;
+DEFINE_OBJECT_TEMPLATE_VTABLE(QQmlQModelIndexStdVectorList);
typedef QQmlSequence<QItemSelection> QQmlQItemSelectionRangeList;
DEFINE_OBJECT_TEMPLATE_VTABLE(QQmlQItemSelectionRangeList);
typedef QQmlSequence<QList<bool> > QQmlBoolList;
@@ -724,6 +749,19 @@ QVariant SequencePrototype::toVariant(const QV4::Value &array, int typeHint, boo
#undef SEQUENCE_TO_VARIANT
+#define SEQUENCE_GET_RAWCONTAINERPTR(ElementType, ElementTypeName, SequenceType, unused) \
+ if (const QQml##ElementTypeName##List *list = [&]() -> const QQml##ElementTypeName##List* \
+ { if (typeHint == qMetaTypeId<SequenceType>()) return object->as<QQml##ElementTypeName##List>(); return nullptr;}()) \
+ return list->getRawContainerPtr(); \
+ else
+
+void* SequencePrototype::getRawContainerPtr(const Object *object, int typeHint)
+{
+ FOREACH_QML_SEQUENCE_TYPE(SEQUENCE_GET_RAWCONTAINERPTR) { /* else */ return nullptr; }
+}
+
+#undef SEQUENCE_GET_RAWCONTAINERPTR
+
#define MAP_META_TYPE(ElementType, ElementTypeName, SequenceType, unused) \
if (object->as<QQml##ElementTypeName##List>()) { \
return qMetaTypeId<SequenceType>(); \
diff --git a/src/qml/jsruntime/qv4sequenceobject_p.h b/src/qml/jsruntime/qv4sequenceobject_p.h
index 0879f149fa..2b8d1ea716 100644
--- a/src/qml/jsruntime/qv4sequenceobject_p.h
+++ b/src/qml/jsruntime/qv4sequenceobject_p.h
@@ -81,6 +81,7 @@ struct SequencePrototype : public QV4::Object
static int metaTypeForSequence(const Object *object);
static QVariant toVariant(Object *object);
static QVariant toVariant(const Value &array, int typeHint, bool *succeeded);
+ static void* getRawContainerPtr(const Object *object, int typeHint);
};
}
diff --git a/src/qml/jsruntime/qv4string.cpp b/src/qml/jsruntime/qv4string.cpp
index 515d61c8e4..c0183a46a7 100644
--- a/src/qml/jsruntime/qv4string.cpp
+++ b/src/qml/jsruntime/qv4string.cpp
@@ -54,12 +54,12 @@ using namespace QV4;
DEFINE_MANAGED_VTABLE(String);
-void String::markObjects(Heap::Base *that, ExecutionEngine *e)
+void String::markObjects(Heap::Base *that, MarkStack *markStack)
{
String::Data *s = static_cast<String::Data *>(that);
if (s->largestSubLength) {
- s->left->mark(e);
- s->right->mark(e);
+ s->left->mark(markStack);
+ s->right->mark(markStack);
}
}
diff --git a/src/qml/jsruntime/qv4string_p.h b/src/qml/jsruntime/qv4string_p.h
index f5311ae5d4..2f34dd6139 100644
--- a/src/qml/jsruntime/qv4string_p.h
+++ b/src/qml/jsruntime/qv4string_p.h
@@ -205,7 +205,7 @@ struct Q_QML_PRIVATE_EXPORT String : public Managed {
Identifier *identifier() const { return d()->identifier; }
protected:
- static void markObjects(Heap::Base *that, ExecutionEngine *e);
+ static void markObjects(Heap::Base *that, MarkStack *markStack);
static bool isEqualTo(Managed *that, Managed *o);
static uint getLength(const Managed *m);
#endif
diff --git a/src/qml/jsruntime/qv4stringobject.cpp b/src/qml/jsruntime/qv4stringobject.cpp
index 7ccb7a762f..7c65c97d73 100644
--- a/src/qml/jsruntime/qv4stringobject.cpp
+++ b/src/qml/jsruntime/qv4stringobject.cpp
@@ -77,15 +77,15 @@ void Heap::StringObject::init()
{
Object::init();
Q_ASSERT(vtable() == QV4::StringObject::staticVTable());
- string = internalClass->engine->id_empty()->d();
- *propertyData(LengthPropertyIndex) = Primitive::fromInt32(0);
+ string.set(internalClass->engine, internalClass->engine->id_empty()->d());
+ setProperty(internalClass->engine, LengthPropertyIndex, Primitive::fromInt32(0));
}
void Heap::StringObject::init(const QV4::String *str)
{
Object::init();
- string = str->d();
- *propertyData(LengthPropertyIndex) = Primitive::fromInt32(length());
+ string.set(internalClass->engine, str->d());
+ setProperty(internalClass->engine, LengthPropertyIndex, Primitive::fromInt32(length()));
}
Heap::String *Heap::StringObject::getIndex(uint index) const
@@ -145,13 +145,6 @@ void StringObject::advanceIterator(Managed *m, ObjectIterator *it, Value *name,
return Object::advanceIterator(m, it, name, index, p, attrs);
}
-void StringObject::markObjects(Heap::Base *that, ExecutionEngine *e)
-{
- StringObject::Data *o = static_cast<StringObject::Data *>(that);
- o->string->mark(e);
- Object::markObjects(that, e);
-}
-
DEFINE_OBJECT_VTABLE(StringCtor);
void Heap::StringCtor::init(QV4::ExecutionContext *scope)
@@ -200,6 +193,7 @@ void StringPrototype::init(ExecutionEngine *engine, Object *ctor)
defineDefaultProperty(QStringLiteral("lastIndexOf"), method_lastIndexOf, 1);
defineDefaultProperty(QStringLiteral("localeCompare"), method_localeCompare, 1);
defineDefaultProperty(QStringLiteral("match"), method_match, 1);
+ defineDefaultProperty(QStringLiteral("repeat"), method_repeat, 1);
defineDefaultProperty(QStringLiteral("replace"), method_replace, 2);
defineDefaultProperty(QStringLiteral("search"), method_search, 1);
defineDefaultProperty(QStringLiteral("slice"), method_slice, 2);
@@ -458,6 +452,21 @@ void StringPrototype::method_match(const BuiltinFunction *, Scope &scope, CallDa
scope.result = a;
}
+void StringPrototype::method_repeat(const BuiltinFunction *, Scope &scope, CallData *callData)
+{
+ QString value = getThisString(scope, callData);
+ CHECK_EXCEPTION();
+
+ double repeats = callData->args[0].toInteger();
+
+ if (repeats < 0 || qIsInf(repeats)) {
+ scope.result = scope.engine->throwRangeError(QLatin1String("Invalid count value"));
+ return;
+ }
+
+ scope.result = scope.engine->newString(value.repeated(int(repeats)));
+}
+
static void appendReplacementString(QString *result, const QString &input, const QString& replaceValue, uint* matchOffsets, int captureCount)
{
result->reserve(result->length() + replaceValue.length());
@@ -547,7 +556,7 @@ void StringPrototype::method_replace(const BuiltinFunction *, Scope &scope, Call
offset = qMax(offset + 1, matchOffsets[oldSize + 1]);
}
if (regExp->global())
- *regExp->lastIndexProperty() = Primitive::fromUInt32(0);
+ regExp->setLastIndex(0);
numStringMatches = nMatchOffsets / (regExp->value()->captureCount() * 2);
numCaptures = regExp->value()->captureCount();
} else {
diff --git a/src/qml/jsruntime/qv4stringobject_p.h b/src/qml/jsruntime/qv4stringobject_p.h
index 2e64364f9f..ce046f4844 100644
--- a/src/qml/jsruntime/qv4stringobject_p.h
+++ b/src/qml/jsruntime/qv4stringobject_p.h
@@ -60,14 +60,18 @@ namespace QV4 {
namespace Heap {
-struct StringObject : Object {
+#define StringObjectMembers(class, Member) \
+ Member(class, Pointer, String *, string)
+
+DECLARE_HEAP_OBJECT(StringObject, Object) {
+ DECLARE_MARK_TABLE(StringObject);
+
enum {
LengthPropertyIndex = 0
};
void init();
void init(const QV4::String *string);
- String *string;
Heap::String *getIndex(uint index) const;
uint length() const;
@@ -96,7 +100,6 @@ struct StringObject: Object {
protected:
static void advanceIterator(Managed *m, ObjectIterator *it, Value *name, uint *index, Property *p, PropertyAttributes *attrs);
- static void markObjects(Heap::Base *that, ExecutionEngine *e);
};
struct StringCtor: FunctionObject
@@ -122,6 +125,7 @@ struct StringPrototype: StringObject
static void method_lastIndexOf(const BuiltinFunction *, Scope &scope, CallData *callData);
static void method_localeCompare(const BuiltinFunction *, Scope &scope, CallData *callData);
static void method_match(const BuiltinFunction *, Scope &scope, CallData *callData);
+ static void method_repeat(const BuiltinFunction *, Scope &scope, CallData *callData);
static void method_replace(const BuiltinFunction *, Scope &scope, CallData *callData);
static void method_search(const BuiltinFunction *, Scope &scope, CallData *callData);
static void method_slice(const BuiltinFunction *, Scope &scope, CallData *callData);
diff --git a/src/qml/jsruntime/qv4typedarray.cpp b/src/qml/jsruntime/qv4typedarray.cpp
index 80655aded6..fe27d7c2d2 100644
--- a/src/qml/jsruntime/qv4typedarray.cpp
+++ b/src/qml/jsruntime/qv4typedarray.cpp
@@ -229,8 +229,8 @@ void TypedArrayCtor::construct(const Managed *m, Scope &scope, CallData *callDat
return;
}
- Scoped<TypedArray > array(scope, TypedArray::create(scope.engine, that->d()->type));
- array->d()->buffer = buffer->d();
+ Scoped<TypedArray> array(scope, TypedArray::create(scope.engine, that->d()->type));
+ array->d()->buffer.set(scope.engine, buffer->d());
array->d()->byteLength = byteLength;
array->d()->byteOffset = 0;
@@ -252,8 +252,8 @@ void TypedArrayCtor::construct(const Managed *m, Scope &scope, CallData *callDat
return;
}
- Scoped<TypedArray > array(scope, TypedArray::create(scope.engine, that->d()->type));
- array->d()->buffer = newBuffer->d();
+ Scoped<TypedArray> array(scope, TypedArray::create(scope.engine, that->d()->type));
+ array->d()->buffer.set(scope.engine, newBuffer->d());
array->d()->byteLength = destByteLength;
array->d()->byteOffset = 0;
@@ -311,8 +311,8 @@ void TypedArrayCtor::construct(const Managed *m, Scope &scope, CallData *callDat
byteLength = (uint)l;
}
- Scoped<TypedArray > array(scope, TypedArray::create(scope.engine, that->d()->type));
- array->d()->buffer = buffer->d();
+ Scoped<TypedArray> array(scope, TypedArray::create(scope.engine, that->d()->type));
+ array->d()->buffer.set(scope.engine, buffer->d());
array->d()->byteLength = byteLength;
array->d()->byteOffset = byteOffset;
scope.result = array.asReturnedValue();
@@ -335,8 +335,8 @@ void TypedArrayCtor::construct(const Managed *m, Scope &scope, CallData *callDat
return;
}
- Scoped<TypedArray > array(scope, TypedArray::create(scope.engine, that->d()->type));
- array->d()->buffer = newBuffer->d();
+ Scoped<TypedArray> array(scope, TypedArray::create(scope.engine, that->d()->type));
+ array->d()->buffer.set(scope.engine, newBuffer->d());
array->d()->byteLength = l * elementSize;
array->d()->byteOffset = 0;
@@ -377,12 +377,6 @@ Heap::TypedArray *TypedArray::create(ExecutionEngine *e, Heap::TypedArray::Type
return e->memoryManager->allocObject<TypedArray>(ic, e->typedArrayPrototype + t, t);
}
-void TypedArray::markObjects(Heap::Base *that, ExecutionEngine *e)
-{
- static_cast<TypedArray::Data *>(that)->buffer->mark(e);
- Object::markObjects(that, e);
-}
-
ReturnedValue TypedArray::getIndexed(const Managed *m, uint index, bool *hasProperty)
{
Scope scope(static_cast<const Object *>(m)->engine());
@@ -400,11 +394,11 @@ ReturnedValue TypedArray::getIndexed(const Managed *m, uint index, bool *hasProp
return a->d()->type->read(a->d()->buffer->data->data(), byteOffset);
}
-void TypedArray::putIndexed(Managed *m, uint index, const Value &value)
+bool TypedArray::putIndexed(Managed *m, uint index, const Value &value)
{
ExecutionEngine *v4 = static_cast<Object *>(m)->engine();
if (v4->hasException)
- return;
+ return false;
Scope scope(v4);
Scoped<TypedArray> a(scope, static_cast<TypedArray *>(m));
@@ -415,11 +409,12 @@ void TypedArray::putIndexed(Managed *m, uint index, const Value &value)
goto reject;
a->d()->type->write(scope.engine, a->d()->buffer->data->data(), byteOffset, value);
- return;
+ return true;
reject:
if (scope.engine->current->strictMode)
scope.engine->throwTypeError();
+ return false;
}
void TypedArrayPrototype::init(ExecutionEngine *engine, TypedArrayCtor *ctor)
diff --git a/src/qml/jsruntime/qv4typedarray_p.h b/src/qml/jsruntime/qv4typedarray_p.h
index a6a74e4b9b..a472dfa607 100644
--- a/src/qml/jsruntime/qv4typedarray_p.h
+++ b/src/qml/jsruntime/qv4typedarray_p.h
@@ -72,7 +72,15 @@ struct TypedArrayOperations {
namespace Heap {
-struct TypedArray : Object {
+#define TypedArrayMembers(class, Member) \
+ Member(class, Pointer, ArrayBuffer *, buffer) \
+ Member(class, NoMark, const TypedArrayOperations *, type) \
+ Member(class, NoMark, uint, byteLength) \
+ Member(class, NoMark, uint, byteOffset) \
+ Member(class, NoMark, uint, arrayType)
+
+DECLARE_HEAP_OBJECT(TypedArray, Object) {
+ DECLARE_MARK_TABLE(TypedArray);
enum Type {
Int8Array,
UInt8Array,
@@ -87,12 +95,6 @@ struct TypedArray : Object {
};
void init(Type t);
-
- const TypedArrayOperations *type;
- Pointer<ArrayBuffer> buffer;
- uint byteLength;
- uint byteOffset;
- Type arrayType;
};
struct TypedArrayCtor : FunctionObject {
@@ -128,12 +130,11 @@ struct Q_QML_PRIVATE_EXPORT TypedArray : Object
}
Heap::TypedArray::Type arrayType() const {
- return d()->arrayType;
+ return static_cast<Heap::TypedArray::Type>(d()->arrayType);
}
- static void markObjects(Heap::Base *that, ExecutionEngine *e);
static ReturnedValue getIndexed(const Managed *m, uint index, bool *hasProperty);
- static void putIndexed(Managed *m, uint index, const Value &value);
+ static bool putIndexed(Managed *m, uint index, const Value &value);
};
struct TypedArrayCtor: FunctionObject
diff --git a/src/qml/jsruntime/qv4value_p.h b/src/qml/jsruntime/qv4value_p.h
index 94233d4ddb..1158b82318 100644
--- a/src/qml/jsruntime/qv4value_p.h
+++ b/src/qml/jsruntime/qv4value_p.h
@@ -491,7 +491,7 @@ public:
// Section 9.12
bool sameValue(Value other) const;
- inline void mark(ExecutionEngine *e);
+ inline void mark(MarkStack *markStack);
Value &operator =(const ScopedValue &v);
Value &operator=(ReturnedValue v) { _val = v; return *this; }
@@ -722,7 +722,6 @@ inline unsigned int Value::toUInt32() const
return (unsigned int)toInt32();
}
-
}
QT_END_NAMESPACE
diff --git a/src/qml/jsruntime/qv4variantobject.cpp b/src/qml/jsruntime/qv4variantobject.cpp
index 5cab4c5386..f2ff5d307e 100644
--- a/src/qml/jsruntime/qv4variantobject.cpp
+++ b/src/qml/jsruntime/qv4variantobject.cpp
@@ -84,7 +84,7 @@ bool VariantObject::isEqualTo(Managed *m, Managed *other)
return false;
}
-void VariantObject::addVmePropertyReference()
+void VariantObject::addVmePropertyReference() const
{
if (d()->isScarce() && ++d()->vmePropertyReferenceCount == 1) {
// remove from the ep->scarceResources list
@@ -94,7 +94,7 @@ void VariantObject::addVmePropertyReference()
}
}
-void VariantObject::removeVmePropertyReference()
+void VariantObject::removeVmePropertyReference() const
{
if (d()->isScarce() && --d()->vmePropertyReferenceCount == 0) {
// and add to the ep->scarceResources list
diff --git a/src/qml/jsruntime/qv4variantobject_p.h b/src/qml/jsruntime/qv4variantobject_p.h
index dba14b13fb..a7c6fa320c 100644
--- a/src/qml/jsruntime/qv4variantobject_p.h
+++ b/src/qml/jsruntime/qv4variantobject_p.h
@@ -96,8 +96,8 @@ struct VariantObject : Object
V4_PROTOTYPE(variantPrototype)
V4_NEEDS_DESTROY
- void addVmePropertyReference();
- void removeVmePropertyReference();
+ void addVmePropertyReference() const;
+ void removeVmePropertyReference() const;
static bool isEqualTo(Managed *m, Managed *other);
};
diff --git a/src/qml/jsruntime/qv4vme_moth.cpp b/src/qml/jsruntime/qv4vme_moth.cpp
index 3d95353fc0..5749d0aef3 100644
--- a/src/qml/jsruntime/qv4vme_moth.cpp
+++ b/src/qml/jsruntime/qv4vme_moth.cpp
@@ -338,18 +338,24 @@ Param traceParam(const Param &param)
return param;
}
# define VALUE(param) (*VALUEPTR(param))
-# define VALUEPTR(param) (scopes[traceParam(param).scope] + param.index)
+# define VALUEPTR(param) (scopes[traceParam(param).scope].values + param.index)
#else
# define VALUE(param) (*VALUEPTR(param))
-# define VALUEPTR(param) (scopes[param.scope] + param.index)
+# define VALUEPTR(param) (scopes[param.scope].values + param.index)
#endif
+// ### add write barrier here
#define STOREVALUE(param, value) { \
QV4::ReturnedValue tmp = (value); \
if (engine->hasException) \
goto catchException; \
- VALUE(param) = tmp; \
- }
+ if (Q_LIKELY(!engine->writeBarrierActive || !scopes[param.scope].base)) { \
+ VALUE(param) = tmp; \
+ } else { \
+ QV4::WriteBarrier::write(engine, scopes[param.scope].base, VALUEPTR(param), QV4::Value::fromReturnedValue(tmp)); \
+ } \
+}
+
// qv4scopedvalue_p.h also defines a CHECK_EXCEPTION macro
#ifdef CHECK_EXCEPTION
#undef CHECK_EXCEPTION
@@ -396,21 +402,29 @@ QV4::ReturnedValue VME::run(ExecutionEngine *engine, const uchar *code)
}
}
- Q_ALLOCA_VAR(QV4::Value*, scopes, sizeof(QV4::Value *)*(2 + 2*scopeDepth));
+ struct Scopes {
+ QV4::Value *values;
+ QV4::Heap::Base *base; // non 0 if a write barrier is required
+ };
+ Q_ALLOCA_VAR(Scopes, scopes, sizeof(Scopes)*(2 + 2*scopeDepth));
{
- scopes[0] = const_cast<QV4::Value *>(static_cast<CompiledData::CompilationUnit*>(engine->current->compilationUnit)->constants);
+ scopes[0] = { const_cast<QV4::Value *>(static_cast<CompiledData::CompilationUnit*>(engine->current->compilationUnit)->constants), 0 };
// stack gets setup in push instruction
- scopes[1] = 0;
+ scopes[1] = { 0, 0 };
QV4::Heap::ExecutionContext *scope = engine->current;
int i = 0;
while (scope) {
- if (scope->type >= QV4::Heap::ExecutionContext::Type_SimpleCallContext) {
+ if (scope->type == QV4::Heap::ExecutionContext::Type_SimpleCallContext) {
+ QV4::Heap::SimpleCallContext *cc = static_cast<QV4::Heap::SimpleCallContext *>(scope);
+ scopes[2*i + 2] = { cc->callData->args, 0 };
+ scopes[2*i + 3] = { 0, 0 };
+ } else if (scope->type == QV4::Heap::ExecutionContext::Type_CallContext) {
QV4::Heap::CallContext *cc = static_cast<QV4::Heap::CallContext *>(scope);
- scopes[2*i + 2] = cc->callData->args;
- scopes[2*i + 3] = cc->locals;
+ scopes[2*i + 2] = { cc->callData->args, cc };
+ scopes[2*i + 3] = { cc->locals.values, cc };
} else {
- scopes[2*i + 2] = 0;
- scopes[2*i + 3] = 0;
+ scopes[2*i + 2] = { 0, 0 };
+ scopes[2*i + 3] = { 0, 0 };
}
++i;
scope = scope->outer;
@@ -477,7 +491,7 @@ QV4::ReturnedValue VME::run(ExecutionEngine *engine, const uchar *code)
MOTH_BEGIN_INSTR(LoadElementLookup)
QV4::Lookup *l = engine->current->lookups + instr.lookup;
- STOREVALUE(instr.result, l->indexedGetter(l, VALUE(instr.base), VALUE(instr.index)));
+ STOREVALUE(instr.result, l->indexedGetter(l, engine, VALUE(instr.base), VALUE(instr.index)));
MOTH_END_INSTR(LoadElementLookup)
MOTH_BEGIN_INSTR(StoreElement)
@@ -487,7 +501,7 @@ QV4::ReturnedValue VME::run(ExecutionEngine *engine, const uchar *code)
MOTH_BEGIN_INSTR(StoreElementLookup)
QV4::Lookup *l = engine->current->lookups + instr.lookup;
- l->indexedSetter(l, VALUE(instr.base), VALUE(instr.index), VALUE(instr.source));
+ l->indexedSetter(l, engine, VALUE(instr.base), VALUE(instr.index), VALUE(instr.source));
CHECK_EXCEPTION;
MOTH_END_INSTR(StoreElementLookup)
@@ -554,7 +568,7 @@ QV4::ReturnedValue VME::run(ExecutionEngine *engine, const uchar *code)
TRACE(inline, "stack size: %u", instr.value);
stackSize = instr.value;
stack = scope.alloc(stackSize);
- scopes[1] = stack;
+ scopes[1].values = stack;
MOTH_END_INSTR(Push)
MOTH_BEGIN_INSTR(CallValue)
diff --git a/src/qml/memory/memory.pri b/src/qml/memory/memory.pri
index 38fadbf23f..7956e4a9a1 100644
--- a/src/qml/memory/memory.pri
+++ b/src/qml/memory/memory.pri
@@ -7,7 +7,8 @@ SOURCES += \
HEADERS += \
$$PWD/qv4mm_p.h \
- $$PWD/qv4mmdefs_p.h
+ $$PWD/qv4mmdefs_p.h \
+ $$PWD/qv4writebarrier_p.h
}
HEADERS += \
diff --git a/src/qml/memory/qv4heap_p.h b/src/qml/memory/qv4heap_p.h
index a4e96b4c84..f00ce4283c 100644
--- a/src/qml/memory/qv4heap_p.h
+++ b/src/qml/memory/qv4heap_p.h
@@ -75,6 +75,7 @@ struct InternalClass;
struct VTable
{
const VTable * const parent;
+ const quint64 markTable;
uint inlinePropertyOffset : 16;
uint nInlineProperties : 16;
uint isExecutionContext : 1;
@@ -87,7 +88,7 @@ struct VTable
uint type : 8;
const char *className;
void (*destroy)(Heap::Base *);
- void (*markObjects)(Heap::Base *, ExecutionEngine *e);
+ void (*markObjects)(Heap::Base *, MarkStack *markStack);
bool (*isEqualTo)(Managed *m, Managed *other);
};
@@ -96,10 +97,12 @@ namespace Heap {
struct Q_QML_EXPORT Base {
void *operator new(size_t) = delete;
+ static Q_CONSTEXPR quint64 markTable = 0;
+
InternalClass *internalClass;
inline ReturnedValue asReturnedValue() const;
- inline void mark(QV4::ExecutionEngine *engine);
+ inline void mark(QV4::MarkStack *markStack);
const VTable *vtable() const { return internalClass->vtable; }
inline bool isMarked() const {
@@ -114,6 +117,12 @@ struct Q_QML_EXPORT Base {
Q_ASSERT(!Chunk::testBit(c->extendsBitmap, h - c->realBase()));
return Chunk::setBit(c->blackBitmap, h - c->realBase());
}
+ inline void setGrayBit() {
+ const HeapItem *h = reinterpret_cast<const HeapItem *>(this);
+ Chunk *c = h->chunk();
+ Q_ASSERT(!Chunk::testBit(c->extendsBitmap, h - c->realBase()));
+ return Chunk::setBit(c->grayBitmap, h - c->realBase());
+ }
inline bool inUse() const {
const HeapItem *h = reinterpret_cast<const HeapItem *>(this);
@@ -122,6 +131,8 @@ struct Q_QML_EXPORT Base {
return Chunk::testBit(c->objectBitmap, h - c->realBase());
}
+ inline void markChildren(MarkStack *markStack);
+
void *operator new(size_t, Managed *m) { return m; }
void *operator new(size_t, Heap::Base *m) { return m; }
void operator delete(void *, Heap::Base *) {}
@@ -171,20 +182,6 @@ Q_STATIC_ASSERT(std::is_standard_layout<Base>::value);
Q_STATIC_ASSERT(offsetof(Base, internalClass) == 0);
Q_STATIC_ASSERT(sizeof(Base) == QT_POINTER_SIZE);
-template <typename T>
-struct Pointer {
- T *operator->() const { return ptr; }
- operator T *() const { return ptr; }
-
- Pointer &operator =(T *t) { ptr = t; return *this; }
-
- template <typename Type>
- Type *cast() { return static_cast<Type *>(ptr); }
-
- T *ptr;
-};
-V4_ASSERT_IS_TRIVIAL(Pointer<void>)
-
}
#ifdef QT_NO_QOBJECT
diff --git a/src/qml/memory/qv4mm.cpp b/src/qml/memory/qv4mm.cpp
index 418c3444a4..d420572606 100644
--- a/src/qml/memory/qv4mm.cpp
+++ b/src/qml/memory/qv4mm.cpp
@@ -61,7 +61,11 @@
#include "qv4alloca_p.h"
#include "qv4profiling_p.h"
-#define MM_DEBUG 0
+//#define MM_STATS
+
+#if !defined(MM_STATS) && !defined(QT_NO_DEBUG)
+#define MM_STATS
+#endif
#if MM_DEBUG
#define DEBUG qDebug() << "MM:"
@@ -281,6 +285,76 @@ QString binary(quintptr) { return QString(); }
#define SDUMP if (1) ; else qDebug
#endif
+void Heap::Base::markChildren(MarkStack *markStack)
+{
+ if (vtable()->markObjects)
+ vtable()->markObjects(this, markStack);
+ if (quint64 m = vtable()->markTable) {
+// qDebug() << "using mark table:" << hex << m << "for" << h;
+ void **mem = reinterpret_cast<void **>(this);
+ while (m) {
+ MarkFlags mark = static_cast<MarkFlags>(m & 3);
+ switch (mark) {
+ case Mark_NoMark:
+ break;
+ case Mark_Value:
+// qDebug() << "marking value at " << mem;
+ reinterpret_cast<Value *>(mem)->mark(markStack);
+ break;
+ case Mark_Pointer: {
+// qDebug() << "marking pointer at " << mem;
+ Heap::Base *p = *reinterpret_cast<Heap::Base **>(mem);
+ if (p)
+ p->mark(markStack);
+ break;
+ }
+ case Mark_ValueArray: {
+ Q_ASSERT(m == Mark_ValueArray);
+// qDebug() << "marking Value Array at offset" << hex << (mem - reinterpret_cast<void **>(h));
+ ValueArray<0> *a = reinterpret_cast<ValueArray<0> *>(mem);
+ Value *v = a->values;
+ const Value *end = v + a->alloc;
+ if (a->alloc > 32*1024) {
+ // drain from time to time to avoid overflows in the js stack
+ Heap::Base **currentBase = markStack->top;
+ while (v < end) {
+ v->mark(markStack);
+ ++v;
+ if (markStack->top >= currentBase + 32*1024) {
+ Heap::Base **oldBase = markStack->base;
+ markStack->base = currentBase;
+ markStack->drain();
+ markStack->base = oldBase;
+ }
+ }
+ } else {
+ while (v < end) {
+ v->mark(markStack);
+ ++v;
+ }
+ }
+ break;
+ }
+ }
+
+ m >>= 2;
+ ++mem;
+ }
+ }
+}
+
+// Stores a classname -> freed count mapping.
+typedef QHash<const char*, int> MMStatsHash;
+Q_GLOBAL_STATIC(MMStatsHash, freedObjectStatsGlobal)
+
+// This indirection avoids sticking QHash code in each of the call sites, which
+// shaves off some instructions in the case that it's unused.
+static void increaseFreedCountForClass(const char *className)
+{
+ (*freedObjectStatsGlobal())[className]++;
+}
+
+//bool Chunk::sweep(ClassDestroyStatsCallback classCountPtr)
bool Chunk::sweep(ExecutionEngine *engine)
{
bool hasUsedSlots = false;
@@ -288,7 +362,9 @@ bool Chunk::sweep(ExecutionEngine *engine)
HeapItem *o = realBase();
bool lastSlotFree = false;
for (uint i = 0; i < Chunk::EntriesInBitmap; ++i) {
+#if WRITEBARRIER(none)
Q_ASSERT((grayBitmap[i] | blackBitmap[i]) == blackBitmap[i]); // check that we don't have gray only objects
+#endif
quintptr toFree = objectBitmap[i] ^ blackBitmap[i];
Q_ASSERT((toFree & objectBitmap[i]) == toFree); // check all black objects are marked as being used
quintptr e = extendsBitmap[i];
@@ -317,8 +393,11 @@ bool Chunk::sweep(ExecutionEngine *engine)
HeapItem *itemToFree = o + index;
Heap::Base *b = *itemToFree;
- if (b->vtable()->destroy) {
- b->vtable()->destroy(b);
+ const VTable *v = b->vtable();
+// if (Q_UNLIKELY(classCountPtr))
+// classCountPtr(v->className);
+ if (v->destroy) {
+ v->destroy(b);
b->_checkIsDestroyed();
}
#ifdef V4_USE_HEAPTRACK
@@ -329,8 +408,8 @@ bool Chunk::sweep(ExecutionEngine *engine)
- (blackBitmap[i] | e)) * Chunk::SlotSize,
Profiling::SmallItem);
objectBitmap[i] = blackBitmap[i];
+ grayBitmap[i] = 0;
hasUsedSlots |= (blackBitmap[i] != 0);
- blackBitmap[i] = 0;
extendsBitmap[i] = e;
lastSlotFree = !((objectBitmap[i]|extendsBitmap[i]) >> (sizeof(quintptr)*8 - 1));
SDUMP() << " new extends =" << binary(e);
@@ -379,13 +458,56 @@ void Chunk::freeAll(ExecutionEngine *engine)
Q_V4_PROFILE_DEALLOC(engine, (qPopulationCount(objectBitmap[i]|extendsBitmap[i])
- qPopulationCount(e)) * Chunk::SlotSize, Profiling::SmallItem);
objectBitmap[i] = 0;
- blackBitmap[i] = 0;
+ grayBitmap[i] = 0;
extendsBitmap[i] = e;
o += Chunk::Bits;
}
// DEBUG << "swept chunk" << this << "freed" << slotsFreed << "slots.";
}
+void Chunk::resetBlackBits()
+{
+ memset(blackBitmap, 0, sizeof(blackBitmap));
+}
+
+#ifdef MM_STATS
+static uint nGrayItems = 0;
+#endif
+
+void Chunk::collectGrayItems(MarkStack *markStack)
+{
+ // DEBUG << "sweeping chunk" << this << (*freeList);
+ HeapItem *o = realBase();
+ for (uint i = 0; i < Chunk::EntriesInBitmap; ++i) {
+#if WRITEBARRIER(none)
+ Q_ASSERT((grayBitmap[i] | blackBitmap[i]) == blackBitmap[i]); // check that we don't have gray only objects
+#endif
+ quintptr toMark = blackBitmap[i] & grayBitmap[i]; // correct for a Steele type barrier
+ Q_ASSERT((toMark & objectBitmap[i]) == toMark); // check all black objects are marked as being used
+ // DEBUG << hex << " index=" << i << toFree;
+ while (toMark) {
+ uint index = qCountTrailingZeroBits(toMark);
+ quintptr bit = (static_cast<quintptr>(1) << index);
+
+ toMark ^= bit; // mask out marked slot
+ // DEBUG << " index" << hex << index << toFree;
+
+ HeapItem *itemToFree = o + index;
+ Heap::Base *b = *itemToFree;
+ Q_ASSERT(b->inUse());
+ markStack->push(b);
+#ifdef MM_STATS
+ ++nGrayItems;
+// qDebug() << "adding gray item" << b << "to mark stack";
+#endif
+ }
+ grayBitmap[i] = 0;
+ o += Chunk::Bits;
+ }
+ // DEBUG << "swept chunk" << this << "freed" << slotsFreed << "slots.";
+
+}
+
void Chunk::sortIntoBins(HeapItem **bins, uint nBins)
{
// qDebug() << "sortIntoBins:";
@@ -395,7 +517,7 @@ void Chunk::sortIntoBins(HeapItem **bins, uint nBins)
#else
const int start = 1;
#endif
-#ifndef QT_NO_DEBUG
+#ifdef MM_STATS
uint freeSlots = 0;
uint allocatedSlots = 0;
#endif
@@ -405,7 +527,7 @@ void Chunk::sortIntoBins(HeapItem **bins, uint nBins)
if (!i)
usedSlots |= (static_cast<quintptr>(1) << (HeaderSize/SlotSize)) - 1;
#endif
-#ifndef QT_NO_DEBUG
+#ifdef MM_STATS
allocatedSlots += qPopulationCount(usedSlots);
// qDebug() << hex << " i=" << i << "used=" << usedSlots;
#endif
@@ -422,7 +544,7 @@ void Chunk::sortIntoBins(HeapItem **bins, uint nBins)
break;
}
usedSlots = (objectBitmap[i]|extendsBitmap[i]);
-#ifndef QT_NO_DEBUG
+#ifdef MM_STATS
allocatedSlots += qPopulationCount(usedSlots);
// qDebug() << hex << " i=" << i << "used=" << usedSlots;
#endif
@@ -433,7 +555,7 @@ void Chunk::sortIntoBins(HeapItem **bins, uint nBins)
usedSlots |= (quintptr(1) << index) - 1;
uint freeEnd = i*Bits + index;
uint nSlots = freeEnd - freeStart;
-#ifndef QT_NO_DEBUG
+#ifdef MM_STATS
// qDebug() << hex << " got free slots from" << freeStart << "to" << freeEnd << "n=" << nSlots << "usedSlots=" << usedSlots;
freeSlots += nSlots;
#endif
@@ -444,7 +566,7 @@ void Chunk::sortIntoBins(HeapItem **bins, uint nBins)
bins[bin] = freeItem;
}
}
-#ifndef QT_NO_DEBUG
+#ifdef MM_STATS
Q_ASSERT(freeSlots + allocatedSlots == (EntriesInBitmap - start) * 8 * sizeof(quintptr));
#endif
}
@@ -631,6 +753,18 @@ void BlockAllocator::freeAll()
}
}
+void BlockAllocator::resetBlackBits()
+{
+ for (auto c : chunks)
+ c->resetBlackBits();
+}
+
+void BlockAllocator::collectGrayItems(MarkStack *markStack)
+{
+ for (auto c : chunks)
+ c->collectGrayItems(markStack);
+
+}
HeapItem *HugeItemAllocator::allocate(size_t size) {
Chunk *c = chunkAllocator->allocate(size);
@@ -643,12 +777,16 @@ HeapItem *HugeItemAllocator::allocate(size_t size) {
return c->first();
}
-static void freeHugeChunk(ChunkAllocator *chunkAllocator, const HugeItemAllocator::HugeChunk &c)
+static void freeHugeChunk(ChunkAllocator *chunkAllocator, const HugeItemAllocator::HugeChunk &c, ClassDestroyStatsCallback classCountPtr)
{
HeapItem *itemToFree = c.chunk->first();
Heap::Base *b = *itemToFree;
- if (b->vtable()->destroy) {
- b->vtable()->destroy(b);
+ const VTable *v = b->vtable();
+ if (Q_UNLIKELY(classCountPtr))
+ classCountPtr(v->className);
+
+ if (v->destroy) {
+ v->destroy(b);
b->_checkIsDestroyed();
}
chunkAllocator->free(c.chunk, c.size);
@@ -657,13 +795,14 @@ static void freeHugeChunk(ChunkAllocator *chunkAllocator, const HugeItemAllocato
#endif
}
-void HugeItemAllocator::sweep() {
- auto isBlack = [this] (const HugeChunk &c) {
+void HugeItemAllocator::sweep(ClassDestroyStatsCallback classCountPtr)
+{
+ auto isBlack = [this, classCountPtr] (const HugeChunk &c) {
bool b = c.chunk->first()->isBlack();
Chunk::clearBit(c.chunk->blackBitmap, c.chunk->first() - c.chunk->realBase());
if (!b) {
Q_V4_PROFILE_DEALLOC(engine, c.size, Profiling::LargeItem);
- freeHugeChunk(chunkAllocator, c);
+ freeHugeChunk(chunkAllocator, c, classCountPtr);
}
return !b;
};
@@ -672,11 +811,29 @@ void HugeItemAllocator::sweep() {
chunks.erase(newEnd, chunks.end());
}
+void HugeItemAllocator::resetBlackBits()
+{
+ for (auto c : chunks)
+ Chunk::clearBit(c.chunk->blackBitmap, c.chunk->first() - c.chunk->realBase());
+}
+
+void HugeItemAllocator::collectGrayItems(MarkStack *markStack)
+{
+ for (auto c : chunks)
+ // Correct for a Steele type barrier
+ if (Chunk::testBit(c.chunk->blackBitmap, c.chunk->first() - c.chunk->realBase()) &&
+ Chunk::testBit(c.chunk->grayBitmap, c.chunk->first() - c.chunk->realBase())) {
+ HeapItem *i = c.chunk->first();
+ Heap::Base *b = *i;
+ b->mark(markStack);
+ }
+}
+
void HugeItemAllocator::freeAll()
{
for (auto &c : chunks) {
Q_V4_PROFILE_DEALLOC(engine, c.size, Profiling::LargeItem);
- freeHugeChunk(chunkAllocator, c);
+ freeHugeChunk(chunkAllocator, c, nullptr);
}
}
@@ -702,15 +859,17 @@ MemoryManager::MemoryManager(ExecutionEngine *engine)
blockAllocator.allocationStats = statistics.allocations;
}
-#ifndef QT_NO_DEBUG
+#ifdef MM_STATS
+static int allocationCount = 0;
static size_t lastAllocRequestedSlots = 0;
#endif
Heap::Base *MemoryManager::allocString(std::size_t unmanagedSize)
{
const size_t stringSize = align(sizeof(Heap::String));
-#ifndef QT_NO_DEBUG
+#ifdef MM_STATS
lastAllocRequestedSlots = stringSize >> Chunk::SlotSizeShift;
+ ++allocationCount;
#endif
bool didGCRun = false;
@@ -721,7 +880,8 @@ Heap::Base *MemoryManager::allocString(std::size_t unmanagedSize)
unmanagedHeapSize += unmanagedSize;
if (unmanagedHeapSize > unmanagedHeapSizeGCLimit) {
- runGC();
+ if (!didGCRun)
+ runGC();
if (3*unmanagedHeapSizeGCLimit <= 4*unmanagedHeapSize)
// more than 75% full, raise limit
@@ -739,14 +899,16 @@ Heap::Base *MemoryManager::allocString(std::size_t unmanagedSize)
m = blockAllocator.allocate(stringSize, true);
}
+// qDebug() << "allocated string" << m;
memset(m, 0, stringSize);
return *m;
}
Heap::Base *MemoryManager::allocData(std::size_t size)
{
-#ifndef QT_NO_DEBUG
+#ifdef MM_STATS
lastAllocRequestedSlots = size >> Chunk::SlotSizeShift;
+ ++allocationCount;
#endif
bool didRunGC = false;
@@ -760,8 +922,11 @@ Heap::Base *MemoryManager::allocData(std::size_t size)
// qDebug() << "unmanagedHeapSize:" << unmanagedHeapSize << "limit:" << unmanagedHeapSizeGCLimit << "unmanagedSize:" << unmanagedSize;
- if (size > Chunk::DataSize)
- return *hugeItemAllocator.allocate(size);
+ if (size > Chunk::DataSize) {
+ HeapItem *h = hugeItemAllocator.allocate(size);
+// qDebug() << "allocating huge item" << h;
+ return *h;
+ }
HeapItem *m = blockAllocator.allocate(size);
if (!m) {
@@ -771,6 +936,7 @@ Heap::Base *MemoryManager::allocData(std::size_t size)
}
memset(m, 0, size);
+// qDebug() << "allocating data" << m;
return *m;
}
@@ -778,48 +944,74 @@ Heap::Object *MemoryManager::allocObjectWithMemberData(const QV4::VTable *vtable
{
uint size = (vtable->nInlineProperties + vtable->inlinePropertyOffset)*sizeof(Value);
Q_ASSERT(!(size % sizeof(HeapItem)));
- Heap::Object *o = static_cast<Heap::Object *>(allocData(size));
- // ### Could optimize this and allocate both in one go through the block allocator
- if (nMembers > vtable->nInlineProperties) {
+ Heap::Object *o;
+ if (nMembers <= vtable->nInlineProperties) {
+ o = static_cast<Heap::Object *>(allocData(size));
+ } else {
+ // Allocate both in one go through the block allocator
nMembers -= vtable->nInlineProperties;
std::size_t memberSize = align(sizeof(Heap::MemberData) + (nMembers - 1)*sizeof(Value));
-// qDebug() << "allocating member data for" << o << nMembers << memberSize;
- Heap::Base *m;
- if (memberSize > Chunk::DataSize)
- m = *hugeItemAllocator.allocate(memberSize);
- else
- m = *blockAllocator.allocate(memberSize, true);
- memset(m, 0, memberSize);
- o->memberData = static_cast<Heap::MemberData *>(m);
- o->memberData->internalClass = engine->internalClasses[EngineBase::Class_MemberData];
+ size_t totalSize = size + memberSize;
+ Heap::MemberData *m;
+ if (totalSize > Chunk::DataSize) {
+ o = static_cast<Heap::Object *>(allocData(size));
+ m = hugeItemAllocator.allocate(memberSize)->as<Heap::MemberData>();
+ } else {
+ HeapItem *mh = reinterpret_cast<HeapItem *>(allocData(totalSize));
+ Heap::Base *b = *mh;
+ o = static_cast<Heap::Object *>(b);
+ mh += (size >> Chunk::SlotSizeShift);
+ m = mh->as<Heap::MemberData>();
+ Chunk *c = mh->chunk();
+ size_t index = mh - c->realBase();
+ Chunk::setBit(c->objectBitmap, index);
+ Chunk::clearBit(c->extendsBitmap, index);
+ }
+ o->memberData.set(engine, m);
+ m->internalClass = engine->internalClasses[EngineBase::Class_MemberData];
Q_ASSERT(o->memberData->internalClass);
- o->memberData->size = static_cast<uint>((memberSize - sizeof(Heap::MemberData) + sizeof(Value))/sizeof(Value));
- o->memberData->init();
+ m->values.alloc = static_cast<uint>((memberSize - sizeof(Heap::MemberData) + sizeof(Value))/sizeof(Value));
+ m->values.size = o->memberData->values.alloc;
+ m->init();
// qDebug() << " got" << o->memberData << o->memberData->size;
}
+// qDebug() << "allocating object with memberData" << o << o->memberData.operator->();
return o;
}
-static void drainMarkStack(QV4::ExecutionEngine *engine, Value *markBase)
+static uint markStackSize = 0;
+
+MarkStack::MarkStack(ExecutionEngine *engine)
+ : engine(engine)
+{
+ base = (Heap::Base **)engine->gcStack->base();
+ top = base;
+ limit = base + ExecutionEngine::GCStackLimit/sizeof(Heap::Base)*3/4;
+}
+
+void MarkStack::drain()
{
- while (engine->jsStackTop > markBase) {
- Heap::Base *h = engine->popForGC();
+ while (top > base) {
+ Heap::Base *h = pop();
+ ++markStackSize;
Q_ASSERT(h); // at this point we should only have Heap::Base objects in this area on the stack. If not, weird things might happen.
- Q_ASSERT (h->vtable()->markObjects);
- h->vtable()->markObjects(h, engine);
+ h->markChildren(this);
}
}
-void MemoryManager::mark()
+void MemoryManager::collectRoots(MarkStack *markStack)
{
- Value *markBase = engine->jsStackTop;
+ engine->markObjects(markStack);
+
+// qDebug() << " mark stack after engine->mark" << (engine->jsStackTop - markBase);
- engine->markObjects();
+ collectFromJSStack(markStack);
- collectFromJSStack();
+// qDebug() << " mark stack after js stack collect" << (engine->jsStackTop - markBase);
+ m_persistentValues->mark(markStack);
- m_persistentValues->mark(engine);
+// qDebug() << " mark stack after persistants" << (engine->jsStackTop - markBase);
// Preserve QObject ownership rules within JavaScript: A parent with c++ ownership
// keeps all of its children alive in JavaScript.
@@ -846,16 +1038,24 @@ void MemoryManager::mark()
}
if (keepAlive)
- qobjectWrapper->mark(engine);
+ qobjectWrapper->mark(markStack);
- if (engine->jsStackTop >= engine->jsStackLimit)
- drainMarkStack(engine, markBase);
+ if (markStack->top >= markStack->limit)
+ markStack->drain();
}
+}
+
+void MemoryManager::mark()
+{
+ markStackSize = 0;
+
+ MarkStack markStack(engine);
+ collectRoots(&markStack);
- drainMarkStack(engine, markBase);
+ markStack.drain();
}
-void MemoryManager::sweep(bool lastSweep)
+void MemoryManager::sweep(bool lastSweep, ClassDestroyStatsCallback classCountPtr)
{
for (PersistentValueStorage::Iterator it = m_weakValues->begin(); it != m_weakValues->end(); ++it) {
Managed *m = (*it).managed();
@@ -903,14 +1103,13 @@ void MemoryManager::sweep(bool lastSweep)
}
blockAllocator.sweep();
- hugeItemAllocator.sweep();
+ hugeItemAllocator.sweep(classCountPtr);
}
bool MemoryManager::shouldRunGC() const
{
size_t total = blockAllocator.totalSlots();
- size_t usedSlots = blockAllocator.usedSlotsAfterLastSweep;
- if (total > MinSlotsGCLimit && usedSlots * GCOverallocation < total * 100)
+ if (total > MinSlotsGCLimit && usedSlotsAfterLastFullSweep * GCOverallocation < total * 100)
return true;
return false;
}
@@ -918,15 +1117,15 @@ bool MemoryManager::shouldRunGC() const
size_t dumpBins(BlockAllocator *b, bool printOutput = true)
{
const QLoggingCategory &stats = lcGcAllocatorStats();
- size_t totalFragmentedSlots = 0;
+ size_t totalSlotMem = 0;
if (printOutput)
- qDebug(stats) << "Fragmentation map:";
+ qDebug(stats) << "Slot map:";
for (uint i = 0; i < BlockAllocator::NumBins; ++i) {
uint nEntries = 0;
HeapItem *h = b->freeBins[i];
while (h) {
++nEntries;
- totalFragmentedSlots += h->freeData.availableSlots;
+ totalSlotMem += h->freeData.availableSlots;
h = h->freeData.next;
}
if (printOutput)
@@ -940,8 +1139,8 @@ size_t dumpBins(BlockAllocator *b, bool printOutput = true)
}
if (printOutput)
- qDebug(stats) << " total mem in bins" << totalFragmentedSlots*Chunk::SlotSize;
- return totalFragmentedSlots*Chunk::SlotSize;
+ qDebug(stats) << " total mem in bins" << totalSlotMem*Chunk::SlotSize;
+ return totalSlotMem*Chunk::SlotSize;
}
void MemoryManager::runGC()
@@ -952,6 +1151,7 @@ void MemoryManager::runGC()
}
QScopedValueRollback<bool> gcBlocker(gcBlocked, true);
+// qDebug() << "runGC";
if (gcStats) {
statistics.maxReservedMem = qMax(statistics.maxReservedMem, getAllocatedMem());
@@ -971,22 +1171,29 @@ void MemoryManager::runGC()
const QLoggingCategory &stats = lcGcAllocatorStats();
qDebug(stats) << "========== GC ==========";
-#ifndef QT_NO_DEBUG
+#ifdef MM_STATS
qDebug(stats) << " Triggered by alloc request of" << lastAllocRequestedSlots << "slots.";
+ qDebug(stats) << " Allocations since last GC" << allocationCount;
+ allocationCount = 0;
#endif
size_t oldChunks = blockAllocator.chunks.size();
qDebug(stats) << "Allocated" << totalMem << "bytes in" << oldChunks << "chunks";
qDebug(stats) << "Fragmented memory before GC" << (totalMem - usedBefore);
dumpBins(&blockAllocator);
+#ifdef MM_STATS
+ nGrayItems = 0;
+#endif
+
QElapsedTimer t;
t.start();
mark();
- qint64 markTime = t.restart();
- sweep();
+ qint64 markTime = t.nsecsElapsed()/1000;
+ t.restart();
+ sweep(false, increaseFreedCountForClass);
const size_t usedAfter = getUsedMem();
const size_t largeItemsAfter = getLargeItemsMem();
- qint64 sweepTime = t.elapsed();
+ qint64 sweepTime = t.nsecsElapsed()/1000;
if (triggeredByUnmanagedHeap) {
qDebug(stats) << "triggered by unmanaged heap:";
@@ -995,12 +1202,27 @@ void MemoryManager::runGC()
qDebug(stats) << " unmanaged heap limit:" << unmanagedHeapSizeGCLimit;
}
size_t memInBins = dumpBins(&blockAllocator);
- qDebug(stats) << "Marked object in" << markTime << "ms.";
- qDebug(stats) << "Sweeped object in" << sweepTime << "ms.";
+ qDebug(stats) << "Marked object in" << markTime << "us.";
+ qDebug(stats) << " " << markStackSize << "objects marked";
+ qDebug(stats) << "Sweeped object in" << sweepTime << "us.";
+
+ // sort our object types by number of freed instances
+ MMStatsHash freedObjectStats;
+ std::swap(freedObjectStats, *freedObjectStatsGlobal());
+ typedef std::pair<const char*, int> ObjectStatInfo;
+ std::vector<ObjectStatInfo> freedObjectsSorted;
+ freedObjectsSorted.reserve(freedObjectStats.count());
+ for (auto it = freedObjectStats.constBegin(); it != freedObjectStats.constEnd(); ++it) {
+ freedObjectsSorted.push_back(std::make_pair(it.key(), it.value()));
+ }
+ std::sort(freedObjectsSorted.begin(), freedObjectsSorted.end(), [](const ObjectStatInfo &a, const ObjectStatInfo &b) {
+ return a.second > b.second && strcmp(a.first, b.first) < 0;
+ });
+
qDebug(stats) << "Used memory before GC:" << usedBefore;
qDebug(stats) << "Used memory after GC:" << usedAfter;
- qDebug(stats) << "Freed up bytes:" << (usedBefore - usedAfter);
- qDebug(stats) << "Freed up chunks:" << (oldChunks - blockAllocator.chunks.size());
+ qDebug(stats) << "Freed up bytes :" << (usedBefore - usedAfter);
+ qDebug(stats) << "Freed up chunks :" << (oldChunks - blockAllocator.chunks.size());
size_t lost = blockAllocator.allocatedMem() - memInBins - usedAfter;
if (lost)
qDebug(stats) << "!!!!!!!!!!!!!!!!!!!!! LOST MEM:" << lost << "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!";
@@ -1009,6 +1231,11 @@ void MemoryManager::runGC()
qDebug(stats) << "Large item memory after GC:" << largeItemsAfter;
qDebug(stats) << "Large item memory freed up:" << (largeItemsBefore - largeItemsAfter);
}
+
+ for (auto it = freedObjectsSorted.cbegin(); it != freedObjectsSorted.cend(); ++it) {
+ qDebug(stats).noquote() << QString::fromLatin1("Freed JS type: %1 (%2 instances)").arg(QString::fromLatin1(it->first), QString::number(it->second));
+ }
+
qDebug(stats) << "======== End GC ========";
}
@@ -1019,6 +1246,12 @@ void MemoryManager::runGC()
// ensure we don't 'loose' any memory
Q_ASSERT(blockAllocator.allocatedMem() == getUsedMem() + dumpBins(&blockAllocator, false));
}
+
+ usedSlotsAfterLastFullSweep = blockAllocator.usedSlotsAfterLastSweep;
+
+ // reset all black bits
+ blockAllocator.resetBlackBits();
+ hugeItemAllocator.resetBlackBits();
}
size_t MemoryManager::getUsedMem() const
@@ -1071,7 +1304,7 @@ void MemoryManager::dumpStats() const
qDebug(stats) << " >=" << ((BlockAllocator::NumBins - 1) << Chunk::SlotSizeShift) << " bytes: " << statistics.allocations[BlockAllocator::NumBins - 1];
}
-void MemoryManager::collectFromJSStack() const
+void MemoryManager::collectFromJSStack(MarkStack *markStack) const
{
Value *v = engine->jsStackBase;
Value *top = engine->jsStackTop;
@@ -1079,7 +1312,7 @@ void MemoryManager::collectFromJSStack() const
Managed *m = v->managed();
if (m && m->inUse())
// Skip pointers to already freed objects, they are bogus as well
- m->mark(engine);
+ m->mark(markStack);
++v;
}
}
diff --git a/src/qml/memory/qv4mm_p.h b/src/qml/memory/qv4mm_p.h
index aa8d13de8c..fb21481d5b 100644
--- a/src/qml/memory/qv4mm_p.h
+++ b/src/qml/memory/qv4mm_p.h
@@ -78,27 +78,28 @@ struct StackAllocator {
StackAllocator(ChunkAllocator *chunkAlloc);
T *allocate() {
- T *m = nextFree->as<T>();
+ HeapItem *m = nextFree;
if (Q_UNLIKELY(nextFree == lastInChunk)) {
nextChunk();
} else {
nextFree += requiredSlots;
}
-#if MM_DEBUG
+#if MM_DEBUG || !defined(QT_NO_DEBUG) || defined(QT_FORCE_ASSERTS)
Chunk *c = m->chunk();
Chunk::setBit(c->objectBitmap, m - c->realBase());
#endif
- return m;
+ return m->as<T>();
}
void free() {
-#if MM_DEBUG
- Chunk::clearBit(item->chunk()->objectBitmap, item - item->chunk()->realBase());
-#endif
if (Q_UNLIKELY(nextFree == firstInChunk)) {
prevChunk();
} else {
nextFree -= requiredSlots;
}
+#if MM_DEBUG || !defined(QT_NO_DEBUG) || defined(QT_FORCE_ASSERTS)
+ Chunk *c = nextFree->chunk();
+ Chunk::clearBit(c->objectBitmap, nextFree - c->realBase());
+#endif
}
void nextChunk();
@@ -145,6 +146,8 @@ struct BlockAllocator {
void sweep();
void freeAll();
+ void resetBlackBits();
+ void collectGrayItems(MarkStack *markStack);
// bump allocations
HeapItem *nextFree = 0;
@@ -163,8 +166,10 @@ struct HugeItemAllocator {
{}
HeapItem *allocate(size_t size);
- void sweep();
+ void sweep(ClassDestroyStatsCallback classCountPtr);
void freeAll();
+ void resetBlackBits();
+ void collectGrayItems(MarkStack *markStack);
size_t usedMem() const {
size_t used = 0;
@@ -200,8 +205,8 @@ public:
QV4::Heap::CallContext *allocSimpleCallContext()
{
Heap::CallContext *ctxt = stackAllocator.allocate();
- memset(ctxt, 0, sizeof(Heap::CallContext));
- ctxt->internalClass = CallContext::defaultInternalClass(engine);
+ memset(ctxt, 0, sizeof(Heap::SimpleCallContext));
+ ctxt->internalClass = SimpleCallContext::defaultInternalClass(engine);
Q_ASSERT(ctxt->internalClass && ctxt->internalClass->vtable);
ctxt->init();
return ctxt;
@@ -431,7 +436,6 @@ public:
// called when a JS object grows itself. Specifically: Heap::String::append
void changeUnmanagedHeapSizeUsage(qptrdiff delta) { unmanagedHeapSize += delta; }
-
protected:
/// expects size to be aligned
Heap::Base *allocString(std::size_t unmanagedSize);
@@ -439,10 +443,11 @@ protected:
Heap::Object *allocObjectWithMemberData(const QV4::VTable *vtable, uint nMembers);
private:
- void collectFromJSStack() const;
+ void collectFromJSStack(MarkStack *markStack) const;
void mark();
- void sweep(bool lastSweep = false);
+ void sweep(bool lastSweep = false, ClassDestroyStatsCallback classCountPtr = nullptr);
bool shouldRunGC() const;
+ void collectRoots(MarkStack *markStack);
public:
QV4::ExecutionEngine *engine;
@@ -456,6 +461,7 @@ public:
std::size_t unmanagedHeapSize = 0; // the amount of bytes of heap that is not managed by the memory manager, but which is held onto by managed items.
std::size_t unmanagedHeapSizeGCLimit;
+ std::size_t usedSlotsAfterLastFullSweep = 0;
bool gcBlocked = false;
bool aggressiveGC = false;
diff --git a/src/qml/memory/qv4mmdefs_p.h b/src/qml/memory/qv4mmdefs_p.h
index 7c82fef056..df69f928ef 100644
--- a/src/qml/memory/qv4mmdefs_p.h
+++ b/src/qml/memory/qv4mmdefs_p.h
@@ -116,22 +116,29 @@ struct Chunk {
HeapItem *realBase();
HeapItem *first();
+ static Q_ALWAYS_INLINE size_t bitmapIndex(size_t index) {
+ return index >> BitShift;
+ }
+ static Q_ALWAYS_INLINE quintptr bitForIndex(size_t index) {
+ return static_cast<quintptr>(1) << (index & (Bits - 1));
+ }
+
static void setBit(quintptr *bitmap, size_t index) {
// Q_ASSERT(index >= HeaderSize/SlotSize && index < ChunkSize/SlotSize);
- bitmap += index >> BitShift;
- quintptr bit = static_cast<quintptr>(1) << (index & (Bits - 1));
+ bitmap += bitmapIndex(index);
+ quintptr bit = bitForIndex(index);
*bitmap |= bit;
}
static void clearBit(quintptr *bitmap, size_t index) {
// Q_ASSERT(index >= HeaderSize/SlotSize && index < ChunkSize/SlotSize);
- bitmap += index >> BitShift;
- quintptr bit = static_cast<quintptr>(1) << (index & (Bits - 1));
+ bitmap += bitmapIndex(index);
+ quintptr bit = bitForIndex(index);
*bitmap &= ~bit;
}
static bool testBit(quintptr *bitmap, size_t index) {
// Q_ASSERT(index >= HeaderSize/SlotSize && index < ChunkSize/SlotSize);
- bitmap += index >> BitShift;
- quintptr bit = static_cast<quintptr>(1) << (index & (Bits - 1));
+ bitmap += bitmapIndex(index);
+ quintptr bit = bitForIndex(index);
return (*bitmap & bit);
}
static void setBits(quintptr *bitmap, size_t index, size_t nBits) {
@@ -179,6 +186,10 @@ struct Chunk {
return usedSlots;
}
+ bool sweep(ClassDestroyStatsCallback classCountPtr);
+ void freeAll();
+ void resetBlackBits();
+ void collectGrayItems(QV4::MarkStack *markStack);
bool sweep(ExecutionEngine *engine);
void freeAll(ExecutionEngine *engine);
@@ -260,6 +271,91 @@ Q_STATIC_ASSERT(sizeof(HeapItem) == Chunk::SlotSize);
Q_STATIC_ASSERT(QT_POINTER_SIZE*8 == Chunk::Bits);
Q_STATIC_ASSERT((1 << Chunk::BitShift) == Chunk::Bits);
+struct MarkStack {
+ MarkStack(ExecutionEngine *engine);
+ Heap::Base **top = 0;
+ Heap::Base **base = 0;
+ Heap::Base **limit = 0;
+ ExecutionEngine *engine;
+ void push(Heap::Base *m) {
+ *top = m;
+ ++top;
+ }
+ Heap::Base *pop() {
+ --top;
+ return *top;
+ }
+ void drain();
+
+};
+
+// Some helper classes and macros to automate the generation of our
+// tables used for marking objects
+
+enum MarkFlags {
+ Mark_NoMark = 0,
+ Mark_Value = 1,
+ Mark_Pointer = 2,
+ Mark_ValueArray = 3
+};
+
+template <typename T>
+struct MarkFlagEvaluator {
+ static Q_CONSTEXPR quint64 value = 0;
+};
+template <typename T, size_t o>
+struct MarkFlagEvaluator<Heap::Pointer<T, o>> {
+ static Q_CONSTEXPR quint64 value = static_cast<quint64>(Mark_Pointer) << (2*o / sizeof(quintptr));
+};
+template <size_t o>
+struct MarkFlagEvaluator<ValueArray<o>> {
+ static Q_CONSTEXPR quint64 value = static_cast<quint64>(Mark_ValueArray) << (2*o / sizeof(quintptr));
+};
+template <size_t o>
+struct MarkFlagEvaluator<HeapValue<o>> {
+ static Q_CONSTEXPR quint64 value = static_cast<quint64>(Mark_Value) << (2 *o / sizeof(quintptr));
+};
+
+#define HEAP_OBJECT_OFFSET_MEMBER_EXPANSION(c, gcType, type, name) \
+ HEAP_OBJECT_OFFSET_MEMBER_EXPANSION_##gcType(c, type, name)
+
+#define HEAP_OBJECT_OFFSET_MEMBER_EXPANSION_Pointer(c, type, name) Pointer<type, 0> name;
+#define HEAP_OBJECT_OFFSET_MEMBER_EXPANSION_NoMark(c, type, name) type name;
+#define HEAP_OBJECT_OFFSET_MEMBER_EXPANSION_HeapValue(c, type, name) HeapValue<0> name;
+#define HEAP_OBJECT_OFFSET_MEMBER_EXPANSION_ValueArray(c, type, name) type<0> name;
+
+#define HEAP_OBJECT_MEMBER_EXPANSION(c, gcType, type, name) \
+ HEAP_OBJECT_MEMBER_EXPANSION_##gcType(c, type, name)
+
+#define HEAP_OBJECT_MEMBER_EXPANSION_Pointer(c, type, name) \
+ Pointer<type, offsetof(c##OffsetStruct, name) + baseOffset> name;
+#define HEAP_OBJECT_MEMBER_EXPANSION_NoMark(c, type, name) \
+ type name;
+#define HEAP_OBJECT_MEMBER_EXPANSION_HeapValue(c, type, name) \
+ HeapValue<offsetof(c##OffsetStruct, name) + baseOffset> name;
+#define HEAP_OBJECT_MEMBER_EXPANSION_ValueArray(c, type, name) \
+ type<offsetof(c##OffsetStruct, name) + baseOffset> name;
+
+#define HEAP_OBJECT_MARK_EXPANSION(class, gcType, type, name) \
+ MarkFlagEvaluator<decltype(class::name)>::value |
+
+#define DECLARE_HEAP_OBJECT(name, base) \
+struct name##OffsetStruct { \
+ name##Members(name, HEAP_OBJECT_OFFSET_MEMBER_EXPANSION) \
+}; \
+struct name##SizeStruct : base, name##OffsetStruct {}; \
+struct name##Data { \
+ static Q_CONSTEXPR size_t baseOffset = sizeof(name##SizeStruct) - sizeof(name##OffsetStruct); \
+ name##Members(name, HEAP_OBJECT_MEMBER_EXPANSION) \
+}; \
+Q_STATIC_ASSERT(sizeof(name##SizeStruct) == sizeof(name##Data) + name##Data::baseOffset); \
+static Q_CONSTEXPR quint64 name##_markTable = \
+ (name##Members(name##Data, HEAP_OBJECT_MARK_EXPANSION) 0) | QV4::Heap::base::markTable; \
+ \
+struct name : base, name##Data
+
+#define DECLARE_MARK_TABLE(class) static Q_CONSTEXPR quint64 markTable = class##_markTable
+
}
QT_END_NAMESPACE
diff --git a/src/qml/memory/qv4writebarrier_p.h b/src/qml/memory/qv4writebarrier_p.h
new file mode 100644
index 0000000000..86fd28000d
--- /dev/null
+++ b/src/qml/memory/qv4writebarrier_p.h
@@ -0,0 +1,206 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+#ifndef QV4WRITEBARRIER_P_H
+#define QV4WRITEBARRIER_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <private/qv4global_p.h>
+#include <private/qv4value_p.h>
+
+QT_BEGIN_NAMESPACE
+
+#define WRITEBARRIER_none 1
+
+#define WRITEBARRIER(x) (1/WRITEBARRIER_##x == 1)
+
+namespace QV4 {
+
+namespace WriteBarrier {
+
+enum Type {
+ NoBarrier,
+ Barrier
+};
+
+enum NewValueType {
+ Primitive,
+ Object,
+ Unknown
+};
+
+// ### this needs to be filled with a real memory fence once marking is concurrent
+Q_ALWAYS_INLINE void fence() {}
+
+#if WRITEBARRIER(none)
+
+template <NewValueType type>
+static Q_CONSTEXPR inline bool isRequired() {
+ return false;
+}
+
+inline void write(EngineBase *engine, Heap::Base *base, Value *slot, Value value)
+{
+ Q_UNUSED(engine);
+ Q_UNUSED(base);
+ *slot = value;
+}
+
+inline void write(EngineBase *engine, Heap::Base *base, Value *slot, Heap::Base *value)
+{
+ Q_UNUSED(engine);
+ Q_UNUSED(base);
+ *slot = value;
+}
+
+inline void write(EngineBase *engine, Heap::Base *base, Heap::Base **slot, Heap::Base *value)
+{
+ Q_UNUSED(engine);
+ Q_UNUSED(base);
+ *slot = value;
+}
+
+#endif
+
+}
+
+namespace Heap {
+
+template <typename T, size_t o>
+struct Pointer {
+ static Q_CONSTEXPR size_t offset = o;
+ T operator->() const { return ptr; }
+ operator T () const { return ptr; }
+
+ Heap::Base *base() {
+ Heap::Base *base = reinterpret_cast<Heap::Base *>(this) - (offset/sizeof(Heap::Base));
+ Q_ASSERT(base->inUse());
+ return base;
+ }
+
+ void set(EngineBase *e, T newVal) {
+ WriteBarrier::write(e, base(), reinterpret_cast<Heap::Base **>(&ptr), reinterpret_cast<Heap::Base *>(newVal));
+ }
+
+ template <typename Type>
+ Type *cast() { return static_cast<Type *>(ptr); }
+
+private:
+ T ptr;
+};
+typedef Pointer<char *, 0> V4PointerCheck;
+V4_ASSERT_IS_TRIVIAL(V4PointerCheck)
+
+}
+
+template <size_t offset>
+struct HeapValue : Value {
+ Heap::Base *base() {
+ Heap::Base *base = reinterpret_cast<Heap::Base *>(this) - (offset/sizeof(Heap::Base));
+ Q_ASSERT(base->inUse());
+ return base;
+ }
+
+ void set(EngineBase *e, const Value &newVal) {
+ WriteBarrier::write(e, base(), this, newVal);
+ }
+ void set(EngineBase *e, Heap::Base *b) {
+ WriteBarrier::write(e, base(), this, b);
+ }
+};
+
+template <size_t offset>
+struct ValueArray {
+ uint size;
+ uint alloc;
+ Value values[1];
+
+ Heap::Base *base() {
+ Heap::Base *base = reinterpret_cast<Heap::Base *>(this) - (offset/sizeof(Heap::Base));
+ Q_ASSERT(base->inUse());
+ return base;
+ }
+
+ void set(EngineBase *e, uint index, Value v) {
+ WriteBarrier::write(e, base(), values + index, v);
+ }
+ void set(EngineBase *e, uint index, Heap::Base *b) {
+ WriteBarrier::write(e, base(), values + index, b);
+ }
+ inline const Value &operator[] (uint index) const {
+ Q_ASSERT(index < alloc);
+ return values[index];
+ }
+ inline const Value *data() const {
+ return values;
+ }
+
+ void insertData(EngineBase *e, uint index, Value v) {
+ for (uint i = size - 1; i > index; --i) {
+ values[i] = values[i - 1];
+ }
+ set(e, index, v);
+ }
+ void removeData(EngineBase *e, uint index, int n = 1) {
+ Q_UNUSED(e);
+ for (uint i = index; i < size - n; ++i) {
+ values[i] = values[i + n];
+ }
+ }
+};
+
+// It's really important that the offset of values in this structure is
+// constant across all architecture, otherwise JIT cross-compiled code will
+// have wrong offsets between host and target.
+Q_STATIC_ASSERT(offsetof(ValueArray<0>, values) == 8);
+
+}
+
+QT_END_NAMESPACE
+
+#endif
diff --git a/src/qml/parser/qqmljs.g b/src/qml/parser/qqmljs.g
index 9cd212015e..d2d947e55c 100644
--- a/src/qml/parser/qqmljs.g
+++ b/src/qml/parser/qqmljs.g
@@ -71,12 +71,13 @@
%token T_VAR "var" T_VOID "void" T_WHILE "while"
%token T_WITH "with" T_XOR "^" T_XOR_EQ "^="
%token T_NULL "null" T_TRUE "true" T_FALSE "false"
-%token T_CONST "const"
+%token T_CONST "const" T_LET "let"
%token T_DEBUGGER "debugger"
%token T_RESERVED_WORD "reserved word"
%token T_MULTILINE_STRING_LITERAL "multiline string literal"
%token T_COMMENT "comment"
%token T_COMPATIBILITY_SEMICOLON
+%token T_ENUM "enum"
--- context keywords.
%token T_PUBLIC "public"
@@ -281,6 +282,7 @@ public:
AST::UiArrayMemberList *UiArrayMemberList;
AST::UiQualifiedId *UiQualifiedId;
AST::UiQualifiedPragmaId *UiQualifiedPragmaId;
+ AST::UiEnumMemberList *UiEnumMemberList;
};
public:
@@ -449,6 +451,7 @@ Parser::Parser(Engine *engine):
location_stack(0),
string_stack(0),
program(0),
+ yylval(0),
first_token(0),
last_token(0)
{
@@ -1207,6 +1210,59 @@ case $rule_number: {
} break;
./
+UiObjectMember: T_ENUM T_IDENTIFIER T_LBRACE EnumMemberList T_RBRACE;
+/.
+case $rule_number: {
+ AST::UiEnumDeclaration *enumDeclaration = new (pool) AST::UiEnumDeclaration(stringRef(2), sym(4).UiEnumMemberList->finish());
+ enumDeclaration->enumToken = loc(1);
+ enumDeclaration->rbraceToken = loc(5);
+ sym(1).Node = enumDeclaration;
+ break;
+}
+./
+
+EnumMemberList: T_IDENTIFIER;
+/.
+case $rule_number: {
+ AST::UiEnumMemberList *node = new (pool) AST::UiEnumMemberList(stringRef(1));
+ node->memberToken = loc(1);
+ sym(1).Node = node;
+ break;
+}
+./
+
+EnumMemberList: T_IDENTIFIER T_EQ T_NUMERIC_LITERAL;
+/.
+case $rule_number: {
+ AST::UiEnumMemberList *node = new (pool) AST::UiEnumMemberList(stringRef(1), sym(3).dval);
+ node->memberToken = loc(1);
+ node->valueToken = loc(3);
+ sym(1).Node = node;
+ break;
+}
+./
+
+EnumMemberList: EnumMemberList T_COMMA T_IDENTIFIER;
+/.
+case $rule_number: {
+ AST::UiEnumMemberList *node = new (pool) AST::UiEnumMemberList(sym(1).UiEnumMemberList, stringRef(3));
+ node->memberToken = loc(3);
+ sym(1).Node = node;
+ break;
+}
+./
+
+EnumMemberList: EnumMemberList T_COMMA T_IDENTIFIER T_EQ T_NUMERIC_LITERAL;
+/.
+case $rule_number: {
+ AST::UiEnumMemberList *node = new (pool) AST::UiEnumMemberList(sym(1).UiEnumMemberList, stringRef(3), sym(5).dval);
+ node->memberToken = loc(3);
+ node->valueToken = loc(5);
+ sym(1).Node = node;
+ break;
+}
+./
+
JsIdentifier: T_IDENTIFIER;
JsIdentifier: T_PROPERTY ;
@@ -1602,6 +1658,7 @@ ReservedIdentifier: T_DEFAULT ;
ReservedIdentifier: T_DELETE ;
ReservedIdentifier: T_DO ;
ReservedIdentifier: T_ELSE ;
+ReservedIdentifier: T_ENUM ;
ReservedIdentifier: T_FALSE ;
ReservedIdentifier: T_FINALLY ;
ReservedIdentifier: T_FOR ;
@@ -1622,6 +1679,7 @@ ReservedIdentifier: T_VAR ;
ReservedIdentifier: T_VOID ;
ReservedIdentifier: T_WHILE ;
ReservedIdentifier: T_CONST ;
+ReservedIdentifier: T_LET ;
ReservedIdentifier: T_DEBUGGER ;
ReservedIdentifier: T_RESERVED_WORD ;
ReservedIdentifier: T_WITH ;
@@ -2486,14 +2544,26 @@ VariableStatement: VariableDeclarationKind VariableDeclarationList T_AUTOMATIC_S
VariableStatement: VariableDeclarationKind VariableDeclarationList T_SEMICOLON ;
/.
case $rule_number: {
- AST::VariableStatement *node = new (pool) AST::VariableStatement(
- sym(2).VariableDeclarationList->finish (/*readOnly=*/sym(1).ival == T_CONST));
+ AST::VariableDeclaration::VariableScope s = AST::VariableDeclaration::FunctionScope;
+ if (sym(1).ival == T_LET)
+ s = AST::VariableDeclaration::BlockScope;
+ else if (sym(1).ival == T_CONST)
+ s = AST::VariableDeclaration::ReadOnlyBlockScope;
+
+ AST::VariableStatement *node = new (pool) AST::VariableStatement(sym(2).VariableDeclarationList->finish(s));
node->declarationKindToken = loc(1);
node->semicolonToken = loc(3);
sym(1).Node = node;
} break;
./
+VariableDeclarationKind: T_LET ;
+/.
+case $rule_number: {
+ sym(1).ival = T_LET;
+} break;
+./
+
VariableDeclarationKind: T_CONST ;
/.
case $rule_number: {
@@ -2542,7 +2612,8 @@ case $rule_number: {
VariableDeclaration: JsIdentifier InitialiserOpt ;
/.
case $rule_number: {
- AST::VariableDeclaration *node = new (pool) AST::VariableDeclaration(stringRef(1), sym(2).Expression);
+ AST::VariableDeclaration::VariableScope s = AST::VariableDeclaration::FunctionScope;
+ AST::VariableDeclaration *node = new (pool) AST::VariableDeclaration(stringRef(1), sym(2).Expression, s);
node->identifierToken = loc(1);
sym(1).Node = node;
} break;
@@ -2551,7 +2622,8 @@ case $rule_number: {
VariableDeclarationNotIn: JsIdentifier InitialiserNotInOpt ;
/.
case $rule_number: {
- AST::VariableDeclaration *node = new (pool) AST::VariableDeclaration(stringRef(1), sym(2).Expression);
+ AST::VariableDeclaration::VariableScope s = AST::VariableDeclaration::FunctionScope;
+ AST::VariableDeclaration *node = new (pool) AST::VariableDeclaration(stringRef(1), sym(2).Expression, s);
node->identifierToken = loc(1);
sym(1).Node = node;
} break;
@@ -2677,8 +2749,9 @@ case $rule_number: {
IterationStatement: T_FOR T_LPAREN T_VAR VariableDeclarationListNotIn T_SEMICOLON ExpressionOpt T_SEMICOLON ExpressionOpt T_RPAREN Statement ;
/.
case $rule_number: {
+ AST::VariableDeclaration::VariableScope s = AST::VariableDeclaration::FunctionScope;
AST::LocalForStatement *node = new (pool) AST::LocalForStatement(
- sym(4).VariableDeclarationList->finish (/*readOnly=*/false), sym(6).Expression,
+ sym(4).VariableDeclarationList->finish(s), sym(6).Expression,
sym(8).Expression, sym(10).Statement);
node->forToken = loc(1);
node->lparenToken = loc(2);
diff --git a/src/qml/parser/qqmljsast.cpp b/src/qml/parser/qqmljsast.cpp
index 7f8cecca8f..2433522f42 100644
--- a/src/qml/parser/qqmljsast.cpp
+++ b/src/qml/parser/qqmljsast.cpp
@@ -967,6 +967,23 @@ void UiSourceElement::accept0(Visitor *visitor)
visitor->endVisit(this);
}
+void UiEnumDeclaration::accept0(Visitor *visitor)
+{
+ if (visitor->visit(this)) {
+ accept(members, visitor);
+ }
+
+ visitor->endVisit(this);
+}
+
+void UiEnumMemberList::accept0(Visitor *visitor)
+{
+ if (visitor->visit(this)) {
+ }
+
+ visitor->endVisit(this);
+}
+
} } // namespace QQmlJS::AST
QT_QML_END_NAMESPACE
diff --git a/src/qml/parser/qqmljsast_p.h b/src/qml/parser/qqmljsast_p.h
index 9b06bf3d31..aa48accfe0 100644
--- a/src/qml/parser/qqmljsast_p.h
+++ b/src/qml/parser/qqmljsast_p.h
@@ -218,7 +218,9 @@ public:
Kind_UiQualifiedPragmaId,
Kind_UiScriptBinding,
Kind_UiSourceElement,
- Kind_UiHeaderItemList
+ Kind_UiHeaderItemList,
+ Kind_UiEnumDeclaration,
+ Kind_UiEnumMemberList
};
inline Node()
@@ -1315,10 +1317,18 @@ class QML_PARSER_EXPORT VariableDeclaration: public Node
public:
QQMLJS_DECLARE_AST_NODE(VariableDeclaration)
- VariableDeclaration(const QStringRef &n, ExpressionNode *e):
- name (n), expression (e), readOnly(false)
+ enum VariableScope {
+ FunctionScope,
+ BlockScope, // let
+ ReadOnlyBlockScope // const
+ };
+
+ VariableDeclaration(const QStringRef &n, ExpressionNode *e, VariableScope s):
+ name (n), expression (e), scope(s)
{ kind = K; }
+ bool isLexicallyScoped() const { return scope != FunctionScope; }
+
void accept0(Visitor *visitor) override;
SourceLocation firstSourceLocation() const override
@@ -1330,8 +1340,8 @@ public:
// attributes
QStringRef name;
ExpressionNode *expression;
- bool readOnly;
SourceLocation identifierToken;
+ VariableScope scope;
};
class QML_PARSER_EXPORT VariableDeclarationList: public Node
@@ -1363,14 +1373,13 @@ public:
return declaration->lastSourceLocation();
}
- inline VariableDeclarationList *finish (bool readOnly)
+ inline VariableDeclarationList *finish(VariableDeclaration::VariableScope s)
{
VariableDeclarationList *front = next;
next = 0;
- if (readOnly) {
- VariableDeclarationList *vdl;
- for (vdl = front; vdl != 0; vdl = vdl->next)
- vdl->declaration->readOnly = true;
+ VariableDeclarationList *vdl;
+ for (vdl = front; vdl != 0; vdl = vdl->next) {
+ vdl->declaration->scope = s;
}
return front;
}
@@ -2778,6 +2787,81 @@ public:
SourceLocation rbracketToken;
};
+class QML_PARSER_EXPORT UiEnumMemberList: public Node
+{
+ QQMLJS_DECLARE_AST_NODE(UiEnumMemberList)
+public:
+ UiEnumMemberList(const QStringRef &member, double v = 0.0)
+ : next(this), member(member), value(v)
+ { kind = K; }
+
+ UiEnumMemberList(UiEnumMemberList *previous, const QStringRef &member)
+ : member(member)
+ {
+ kind = K;
+ next = previous->next;
+ previous->next = this;
+ value = previous->value + 1;
+ }
+
+ UiEnumMemberList(UiEnumMemberList *previous, const QStringRef &member, double v)
+ : member(member), value(v)
+ {
+ kind = K;
+ next = previous->next;
+ previous->next = this;
+ }
+
+ SourceLocation firstSourceLocation() const override
+ { return memberToken; }
+
+ SourceLocation lastSourceLocation() const override
+ { return next ? next->lastSourceLocation() :
+ valueToken.isValid() ? valueToken : memberToken; }
+
+ void accept0(Visitor *visitor) override;
+
+ UiEnumMemberList *finish()
+ {
+ UiEnumMemberList *head = next;
+ next = 0;
+ return head;
+ }
+
+// attributes
+ UiEnumMemberList *next;
+ QStringRef member;
+ double value;
+ SourceLocation memberToken;
+ SourceLocation valueToken;
+};
+
+class QML_PARSER_EXPORT UiEnumDeclaration: public UiObjectMember
+{
+public:
+ QQMLJS_DECLARE_AST_NODE(UiEnumDeclaration)
+
+ UiEnumDeclaration(const QStringRef &name,
+ UiEnumMemberList *members)
+ : name(name)
+ , members(members)
+ { kind = K; }
+
+ SourceLocation firstSourceLocation() const override
+ { return enumToken; }
+
+ SourceLocation lastSourceLocation() const override
+ { return rbraceToken; }
+
+ void accept0(Visitor *visitor) override;
+
+// attributes
+ SourceLocation enumToken;
+ SourceLocation rbraceToken;
+ QStringRef name;
+ UiEnumMemberList *members;
+};
+
} } // namespace AST
diff --git a/src/qml/parser/qqmljsastfwd_p.h b/src/qml/parser/qqmljsastfwd_p.h
index 189eb72a57..140a757e51 100644
--- a/src/qml/parser/qqmljsastfwd_p.h
+++ b/src/qml/parser/qqmljsastfwd_p.h
@@ -181,6 +181,8 @@ class UiArrayMemberList;
class UiQualifiedId;
class UiQualifiedPragmaId;
class UiHeaderItemList;
+class UiEnumDeclaration;
+class UiEnumMemberList;
} } // namespace AST
diff --git a/src/qml/parser/qqmljsastvisitor_p.h b/src/qml/parser/qqmljsastvisitor_p.h
index e582a8f6a7..13218f0e98 100644
--- a/src/qml/parser/qqmljsastvisitor_p.h
+++ b/src/qml/parser/qqmljsastvisitor_p.h
@@ -84,6 +84,8 @@ public:
virtual bool visit(UiArrayMemberList *) { return true; }
virtual bool visit(UiQualifiedId *) { return true; }
virtual bool visit(UiQualifiedPragmaId *) { return true; }
+ virtual bool visit(UiEnumDeclaration *) { return true; }
+ virtual bool visit(UiEnumMemberList *) { return true; }
virtual void endVisit(UiProgram *) {}
virtual void endVisit(UiImport *) {}
@@ -101,6 +103,8 @@ public:
virtual void endVisit(UiArrayMemberList *) {}
virtual void endVisit(UiQualifiedId *) {}
virtual void endVisit(UiQualifiedPragmaId *) {}
+ virtual void endVisit(UiEnumDeclaration *) {}
+ virtual void endVisit(UiEnumMemberList *) { }
// QQmlJS
virtual bool visit(ThisExpression *) { return true; }
diff --git a/src/qml/parser/qqmljsgrammar.cpp b/src/qml/parser/qqmljsgrammar.cpp
index b27f4af080..f345990ff9 100644
--- a/src/qml/parser/qqmljsgrammar.cpp
+++ b/src/qml/parser/qqmljsgrammar.cpp
@@ -43,1049 +43,1125 @@
QT_BEGIN_NAMESPACE
const char *const QQmlJSGrammar::spell [] = {
- "end of file", "&", "&&", "&=", "break", "case", "catch", ":", ",", "continue",
- "default", "delete", "/", "/=", "do", ".", "else", "=", "==", "===",
- "finally", "for", "function", ">=", ">", ">>", ">>=", ">>>", ">>>=", "identifier",
- "if", "in", "instanceof", "{", "[", "<=", "(", "<", "<<", "<<=",
- "-", "-=", "--", "new", "!", "!=", "!==", "numeric literal", "|", "|=",
- "||", "+", "+=", "++", "?", "}", "]", "%", "%=", "return",
- ")", ";", 0, "*", "*=", "string literal", "property", "signal", "readonly", "switch",
- "this", "throw", "~", "try", "typeof", "var", "void", "while", "with", "^",
- "^=", "null", "true", "false", "const", "debugger", "reserved word", "multiline string literal", "comment", 0,
- "public", "import", "pragma", "as", "on", "get", "set", 0, 0, 0,
- 0, 0, 0, 0, 0, 0};
+ "end of file", "&", "&&", "&=", "break", "case", "catch", ":", ",", "continue",
+ "default", "delete", "/", "/=", "do", ".", "else", "=", "==", "===",
+ "finally", "for", "function", ">=", ">", ">>", ">>=", ">>>", ">>>=", "identifier",
+ "if", "in", "instanceof", "{", "[", "<=", "(", "<", "<<", "<<=",
+ "-", "-=", "--", "new", "!", "!=", "!==", "numeric literal", "|", "|=",
+ "||", "+", "+=", "++", "?", "}", "]", "%", "%=", "return",
+ ")", ";", 0, "*", "*=", "string literal", "property", "signal", "readonly", "switch",
+ "this", "throw", "~", "try", "typeof", "var", "void", "while", "with", "^",
+ "^=", "null", "true", "false", "const", "let", "debugger", "reserved word", "multiline string literal", "comment",
+ 0, "enum", "public", "import", "pragma", "as", "on", "get", "set", 0,
+ 0, 0, 0, 0, 0, 0, 0, 0
+};
const short QQmlJSGrammar::lhs [] = {
- 106, 106, 106, 106, 106, 106, 107, 113, 113, 116,
- 116, 116, 116, 119, 121, 117, 117, 118, 118, 118,
- 118, 118, 118, 118, 118, 122, 123, 115, 114, 126,
- 126, 127, 127, 128, 128, 125, 111, 111, 111, 111,
- 130, 130, 130, 130, 130, 130, 130, 111, 138, 138,
- 138, 138, 139, 139, 140, 140, 111, 111, 111, 111,
- 111, 111, 111, 111, 111, 111, 111, 111, 111, 111,
- 111, 111, 111, 111, 111, 111, 124, 124, 124, 124,
- 124, 124, 124, 143, 143, 143, 143, 143, 143, 143,
- 143, 143, 143, 143, 143, 143, 143, 143, 143, 143,
- 143, 129, 145, 145, 145, 145, 144, 144, 149, 149,
- 149, 147, 147, 150, 150, 150, 150, 153, 153, 153,
- 153, 153, 153, 153, 153, 153, 153, 153, 153, 153,
- 153, 153, 153, 153, 153, 153, 153, 153, 153, 153,
- 153, 153, 153, 153, 153, 153, 153, 153, 154, 154,
- 120, 120, 120, 120, 120, 157, 157, 158, 158, 158,
- 158, 156, 156, 159, 159, 160, 160, 161, 161, 161,
- 162, 162, 162, 162, 162, 162, 162, 162, 162, 162,
- 163, 163, 163, 163, 164, 164, 164, 165, 165, 165,
- 165, 166, 166, 166, 166, 166, 166, 166, 167, 167,
- 167, 167, 167, 167, 168, 168, 168, 168, 168, 169,
- 169, 169, 169, 169, 170, 170, 171, 171, 172, 172,
- 173, 173, 174, 174, 175, 175, 176, 176, 177, 177,
- 178, 178, 179, 179, 180, 180, 181, 181, 148, 148,
- 182, 182, 183, 183, 183, 183, 183, 183, 183, 183,
- 183, 183, 183, 183, 109, 109, 184, 184, 185, 185,
- 186, 186, 108, 108, 108, 108, 108, 108, 108, 108,
- 108, 108, 108, 108, 108, 108, 108, 131, 195, 195,
- 194, 194, 142, 142, 196, 196, 197, 197, 199, 199,
- 198, 200, 203, 201, 201, 204, 202, 202, 132, 133,
- 133, 134, 134, 187, 187, 187, 187, 187, 187, 187,
- 187, 188, 188, 188, 188, 189, 189, 189, 189, 190,
- 190, 135, 136, 205, 205, 208, 208, 206, 206, 209,
- 207, 191, 192, 192, 137, 137, 137, 210, 211, 193,
- 193, 212, 141, 155, 155, 213, 213, 152, 152, 151,
- 151, 214, 112, 112, 215, 215, 110, 110, 146, 146,
- 216};
+ 108, 108, 108, 108, 108, 108, 109, 115, 115, 118,
+ 118, 118, 118, 121, 123, 119, 119, 120, 120, 120,
+ 120, 120, 120, 120, 120, 124, 125, 117, 116, 128,
+ 128, 129, 129, 130, 130, 127, 113, 113, 113, 113,
+ 132, 132, 132, 132, 132, 132, 132, 113, 140, 140,
+ 140, 140, 141, 141, 142, 142, 113, 113, 113, 113,
+ 113, 113, 113, 113, 113, 113, 113, 113, 113, 113,
+ 113, 113, 113, 113, 113, 113, 113, 145, 145, 145,
+ 145, 126, 126, 126, 126, 126, 126, 126, 146, 146,
+ 146, 146, 146, 146, 146, 146, 146, 146, 146, 146,
+ 146, 146, 146, 146, 146, 146, 131, 148, 148, 148,
+ 148, 147, 147, 152, 152, 152, 150, 150, 153, 153,
+ 153, 153, 156, 156, 156, 156, 156, 156, 156, 156,
+ 156, 156, 156, 156, 156, 156, 156, 156, 156, 156,
+ 156, 156, 156, 156, 156, 156, 156, 156, 156, 156,
+ 156, 156, 156, 156, 156, 157, 157, 122, 122, 122,
+ 122, 122, 160, 160, 161, 161, 161, 161, 159, 159,
+ 162, 162, 163, 163, 164, 164, 164, 165, 165, 165,
+ 165, 165, 165, 165, 165, 165, 165, 166, 166, 166,
+ 166, 167, 167, 167, 168, 168, 168, 168, 169, 169,
+ 169, 169, 169, 169, 169, 170, 170, 170, 170, 170,
+ 170, 171, 171, 171, 171, 171, 172, 172, 172, 172,
+ 172, 173, 173, 174, 174, 175, 175, 176, 176, 177,
+ 177, 178, 178, 179, 179, 180, 180, 181, 181, 182,
+ 182, 183, 183, 184, 184, 151, 151, 185, 185, 186,
+ 186, 186, 186, 186, 186, 186, 186, 186, 186, 186,
+ 186, 111, 111, 187, 187, 188, 188, 189, 189, 110,
+ 110, 110, 110, 110, 110, 110, 110, 110, 110, 110,
+ 110, 110, 110, 110, 133, 198, 198, 197, 197, 144,
+ 144, 199, 199, 199, 200, 200, 202, 202, 201, 203,
+ 206, 204, 204, 207, 205, 205, 134, 135, 135, 136,
+ 136, 190, 190, 190, 190, 190, 190, 190, 190, 191,
+ 191, 191, 191, 192, 192, 192, 192, 193, 193, 137,
+ 138, 208, 208, 211, 211, 209, 209, 212, 210, 194,
+ 195, 195, 139, 139, 139, 213, 214, 196, 196, 215,
+ 143, 158, 158, 216, 216, 155, 155, 154, 154, 217,
+ 114, 114, 218, 218, 112, 112, 149, 149, 219
+};
const short QQmlJSGrammar::rhs [] = {
- 2, 2, 2, 2, 2, 2, 2, 1, 1, 1,
- 1, 2, 2, 1, 1, 2, 2, 2, 2, 3,
- 3, 5, 5, 4, 4, 2, 2, 0, 1, 1,
- 2, 1, 3, 2, 3, 2, 1, 5, 4, 4,
- 1, 1, 1, 1, 1, 1, 1, 3, 1, 1,
- 1, 3, 0, 1, 2, 4, 6, 6, 3, 3,
- 7, 7, 4, 4, 5, 5, 8, 8, 5, 6,
- 6, 10, 6, 7, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 2, 3, 3, 4, 5, 3, 4,
- 3, 1, 1, 2, 3, 4, 1, 2, 3, 7,
- 8, 1, 3, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 4, 3, 5, 1, 2, 4, 4, 4,
- 3, 0, 1, 1, 3, 1, 1, 1, 2, 2,
- 1, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 1, 3, 3, 3, 1, 3, 3, 1, 3, 3,
- 3, 1, 3, 3, 3, 3, 3, 3, 1, 3,
- 3, 3, 3, 3, 1, 3, 3, 3, 3, 1,
- 3, 3, 3, 3, 1, 3, 1, 3, 1, 3,
- 1, 3, 1, 3, 1, 3, 1, 3, 1, 3,
- 1, 3, 1, 3, 1, 5, 1, 5, 1, 3,
- 1, 3, 1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 1, 3, 0, 1, 1, 3,
- 0, 1, 1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 1, 1, 1, 3, 1, 2,
- 0, 1, 3, 3, 1, 1, 1, 3, 1, 3,
- 2, 2, 2, 0, 1, 2, 0, 1, 1, 2,
- 2, 7, 5, 7, 7, 7, 5, 9, 10, 7,
- 8, 2, 2, 3, 3, 2, 2, 3, 3, 3,
- 3, 5, 5, 3, 5, 1, 2, 0, 1, 4,
- 3, 3, 3, 3, 3, 3, 4, 5, 2, 2,
- 2, 1, 8, 8, 7, 1, 3, 0, 1, 0,
- 1, 1, 1, 1, 1, 2, 1, 1, 0, 1,
- 2};
+ 2, 2, 2, 2, 2, 2, 2, 1, 1, 1,
+ 1, 2, 2, 1, 1, 2, 2, 2, 2, 3,
+ 3, 5, 5, 4, 4, 2, 2, 0, 1, 1,
+ 2, 1, 3, 2, 3, 2, 1, 5, 4, 4,
+ 1, 1, 1, 1, 1, 1, 1, 3, 1, 1,
+ 1, 3, 0, 1, 2, 4, 6, 6, 3, 3,
+ 7, 7, 4, 4, 5, 5, 8, 8, 5, 6,
+ 6, 10, 6, 7, 1, 1, 5, 1, 3, 3,
+ 5, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 2, 3,
+ 3, 4, 5, 3, 4, 3, 1, 1, 2, 3,
+ 4, 1, 2, 3, 7, 8, 1, 3, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 4,
+ 3, 5, 1, 2, 4, 4, 4, 3, 0, 1,
+ 1, 3, 1, 1, 1, 2, 2, 1, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 1, 3, 3,
+ 3, 1, 3, 3, 1, 3, 3, 3, 1, 3,
+ 3, 3, 3, 3, 3, 1, 3, 3, 3, 3,
+ 3, 1, 3, 3, 3, 3, 1, 3, 3, 3,
+ 3, 1, 3, 1, 3, 1, 3, 1, 3, 1,
+ 3, 1, 3, 1, 3, 1, 3, 1, 3, 1,
+ 3, 1, 5, 1, 5, 1, 3, 1, 3, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 3, 0, 1, 1, 3, 0, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 3, 1, 2, 0, 1, 3,
+ 3, 1, 1, 1, 1, 3, 1, 3, 2, 2,
+ 2, 0, 1, 2, 0, 1, 1, 2, 2, 7,
+ 5, 7, 7, 7, 5, 9, 10, 7, 8, 2,
+ 2, 3, 3, 2, 2, 3, 3, 3, 3, 5,
+ 5, 3, 5, 1, 2, 0, 1, 4, 3, 3,
+ 3, 3, 3, 3, 4, 5, 2, 2, 2, 1,
+ 8, 8, 7, 1, 3, 0, 1, 0, 1, 1,
+ 1, 1, 1, 2, 1, 1, 0, 1, 2
+};
const short QQmlJSGrammar::action_default [] = {
- 0, 0, 28, 0, 0, 0, 28, 0, 188, 255,
- 219, 227, 223, 167, 239, 215, 3, 152, 85, 168,
- 231, 235, 156, 185, 166, 171, 151, 205, 192, 0,
- 92, 93, 88, 0, 82, 77, 359, 0, 0, 0,
- 0, 90, 0, 0, 86, 89, 81, 0, 0, 78,
- 80, 83, 79, 91, 84, 0, 87, 0, 0, 181,
- 0, 0, 168, 187, 170, 169, 0, 0, 0, 183,
- 184, 182, 186, 0, 216, 0, 0, 0, 0, 206,
- 0, 0, 0, 0, 0, 0, 196, 0, 0, 0,
- 190, 191, 189, 194, 198, 197, 195, 193, 208, 207,
- 209, 0, 224, 0, 220, 0, 0, 162, 149, 161,
- 150, 118, 119, 120, 145, 121, 146, 122, 123, 124,
- 125, 126, 127, 128, 129, 130, 131, 132, 133, 134,
- 147, 135, 136, 137, 138, 139, 140, 141, 142, 143,
- 144, 148, 0, 0, 160, 256, 163, 0, 164, 0,
- 165, 159, 0, 252, 245, 243, 250, 251, 249, 248,
- 254, 247, 246, 244, 253, 240, 0, 228, 0, 0,
- 232, 0, 0, 236, 0, 0, 162, 154, 0, 153,
- 0, 158, 172, 0, 348, 348, 349, 0, 346, 0,
- 347, 0, 350, 263, 270, 269, 277, 265, 0, 266,
- 0, 351, 0, 358, 267, 268, 85, 273, 271, 355,
- 352, 357, 274, 0, 285, 0, 0, 0, 0, 342,
- 0, 359, 257, 299, 0, 0, 0, 286, 0, 0,
- 275, 276, 0, 264, 272, 300, 301, 0, 348, 0,
- 0, 350, 0, 343, 344, 0, 332, 356, 0, 316,
- 317, 318, 319, 0, 312, 313, 314, 315, 340, 341,
- 0, 0, 0, 0, 0, 304, 305, 306, 261, 259,
- 221, 229, 225, 241, 217, 262, 0, 168, 233, 237,
- 210, 199, 0, 0, 218, 0, 0, 0, 0, 211,
- 0, 0, 0, 0, 0, 203, 201, 204, 202, 200,
- 213, 212, 214, 0, 226, 0, 222, 0, 260, 168,
- 0, 242, 257, 258, 0, 257, 0, 0, 308, 0,
- 0, 0, 310, 0, 230, 0, 0, 234, 0, 0,
- 238, 297, 0, 289, 298, 292, 0, 296, 0, 257,
- 290, 0, 257, 0, 0, 309, 0, 0, 0, 311,
- 0, 0, 0, 303, 0, 302, 85, 112, 360, 0,
- 0, 117, 279, 282, 0, 118, 285, 121, 146, 123,
- 124, 88, 128, 129, 82, 130, 133, 86, 89, 257,
- 83, 91, 136, 84, 138, 87, 140, 141, 286, 143,
- 144, 148, 0, 114, 113, 116, 100, 115, 99, 0,
- 109, 280, 278, 0, 0, 0, 350, 0, 110, 156,
- 157, 162, 0, 155, 0, 320, 321, 0, 348, 0,
- 0, 350, 0, 111, 0, 0, 0, 323, 328, 326,
- 329, 0, 0, 327, 328, 0, 324, 0, 325, 281,
- 331, 0, 281, 330, 0, 333, 334, 0, 281, 335,
- 336, 0, 0, 337, 0, 0, 0, 338, 339, 174,
- 173, 0, 0, 0, 307, 0, 0, 0, 322, 294,
- 287, 0, 295, 291, 0, 293, 283, 0, 284, 288,
- 0, 0, 350, 0, 345, 103, 0, 0, 107, 94,
- 0, 96, 105, 0, 97, 106, 108, 98, 104, 95,
- 0, 101, 178, 176, 180, 177, 175, 179, 353, 6,
- 354, 4, 2, 75, 102, 0, 0, 78, 80, 79,
- 37, 5, 0, 76, 0, 51, 50, 49, 0, 0,
- 51, 0, 0, 0, 52, 0, 67, 68, 0, 65,
- 0, 66, 41, 42, 43, 44, 46, 47, 71, 45,
- 0, 51, 0, 0, 0, 0, 0, 61, 0, 62,
- 0, 0, 32, 0, 0, 72, 33, 0, 36, 34,
- 30, 0, 35, 31, 0, 63, 0, 64, 156, 0,
- 69, 73, 0, 0, 0, 0, 156, 281, 0, 70,
- 85, 118, 285, 121, 146, 123, 124, 88, 128, 129,
- 130, 133, 86, 89, 257, 91, 136, 84, 138, 87,
- 140, 141, 286, 143, 144, 148, 74, 0, 59, 53,
- 60, 54, 0, 0, 0, 0, 56, 0, 57, 58,
- 55, 0, 0, 0, 0, 48, 0, 38, 39, 0,
- 40, 8, 0, 0, 9, 0, 11, 0, 10, 0,
- 1, 27, 15, 14, 26, 13, 12, 29, 7, 0,
- 18, 0, 19, 0, 24, 25, 0, 20, 21, 0,
- 22, 23, 16, 17, 361};
+ 0, 0, 28, 0, 0, 0, 28, 0, 195, 262,
+ 226, 234, 230, 174, 246, 222, 3, 159, 90, 175,
+ 238, 242, 163, 192, 173, 178, 158, 212, 199, 0,
+ 97, 98, 93, 0, 87, 82, 367, 0, 0, 0,
+ 0, 95, 0, 0, 91, 94, 86, 0, 0, 83,
+ 85, 88, 84, 96, 89, 0, 92, 0, 0, 188,
+ 0, 0, 175, 194, 177, 176, 0, 0, 0, 190,
+ 191, 189, 193, 0, 223, 0, 0, 0, 0, 213,
+ 0, 0, 0, 0, 0, 0, 203, 0, 0, 0,
+ 197, 198, 196, 201, 205, 204, 202, 200, 215, 214,
+ 216, 0, 231, 0, 227, 0, 0, 169, 156, 168,
+ 157, 123, 124, 125, 151, 126, 153, 127, 128, 129,
+ 130, 131, 132, 133, 134, 135, 136, 137, 138, 152,
+ 139, 140, 154, 141, 142, 143, 144, 145, 146, 147,
+ 148, 149, 150, 155, 0, 0, 167, 263, 170, 0,
+ 171, 0, 172, 166, 0, 259, 252, 250, 257, 258,
+ 256, 255, 261, 254, 253, 251, 260, 247, 0, 235,
+ 0, 0, 239, 0, 0, 243, 0, 0, 169, 161,
+ 0, 160, 0, 165, 179, 0, 356, 356, 357, 0,
+ 354, 0, 355, 0, 358, 270, 277, 276, 284, 272,
+ 0, 273, 0, 359, 0, 366, 274, 275, 90, 280,
+ 278, 363, 360, 365, 281, 0, 293, 0, 0, 0,
+ 0, 350, 0, 367, 292, 264, 307, 0, 0, 0,
+ 294, 0, 0, 282, 283, 0, 271, 279, 308, 309,
+ 0, 356, 0, 0, 358, 0, 351, 352, 0, 340,
+ 364, 0, 324, 325, 326, 327, 0, 320, 321, 322,
+ 323, 348, 349, 0, 0, 0, 0, 0, 312, 313,
+ 314, 268, 266, 228, 236, 232, 248, 224, 269, 0,
+ 175, 240, 244, 217, 206, 0, 0, 225, 0, 0,
+ 0, 0, 218, 0, 0, 0, 0, 0, 210, 208,
+ 211, 209, 207, 220, 219, 221, 0, 233, 0, 229,
+ 0, 267, 175, 0, 249, 264, 265, 0, 264, 0,
+ 0, 316, 0, 0, 0, 318, 0, 237, 0, 0,
+ 241, 0, 0, 245, 305, 0, 297, 306, 300, 0,
+ 304, 0, 264, 298, 0, 264, 0, 0, 317, 0,
+ 0, 0, 319, 0, 0, 0, 311, 0, 310, 90,
+ 117, 368, 0, 0, 122, 286, 289, 0, 123, 293,
+ 126, 153, 128, 129, 93, 134, 135, 87, 136, 292,
+ 139, 91, 94, 264, 88, 96, 142, 89, 144, 92,
+ 146, 147, 294, 149, 150, 155, 0, 119, 118, 121,
+ 105, 120, 104, 0, 114, 287, 285, 0, 0, 0,
+ 358, 0, 115, 163, 164, 169, 0, 162, 0, 328,
+ 329, 0, 356, 0, 0, 358, 0, 116, 0, 0,
+ 0, 331, 336, 334, 337, 0, 0, 335, 336, 0,
+ 332, 0, 333, 288, 339, 0, 288, 338, 0, 341,
+ 342, 0, 288, 343, 344, 0, 0, 345, 0, 0,
+ 0, 346, 347, 181, 180, 0, 0, 0, 315, 0,
+ 0, 0, 330, 302, 295, 0, 303, 299, 0, 301,
+ 290, 0, 291, 296, 0, 0, 358, 0, 353, 108,
+ 0, 0, 112, 99, 0, 101, 110, 0, 102, 111,
+ 113, 103, 109, 100, 0, 106, 185, 183, 187, 184,
+ 182, 186, 361, 6, 362, 4, 2, 75, 107, 0,
+ 0, 0, 83, 85, 84, 37, 5, 0, 76, 0,
+ 51, 50, 49, 0, 0, 51, 0, 0, 0, 52,
+ 0, 67, 68, 0, 65, 0, 66, 41, 42, 43,
+ 44, 46, 47, 71, 45, 0, 0, 0, 78, 0,
+ 77, 80, 0, 81, 0, 79, 0, 51, 0, 0,
+ 0, 0, 0, 61, 0, 62, 0, 0, 32, 0,
+ 0, 72, 33, 0, 36, 34, 30, 0, 35, 31,
+ 0, 63, 0, 64, 163, 0, 69, 73, 0, 0,
+ 0, 0, 163, 288, 0, 70, 90, 123, 293, 126,
+ 153, 128, 129, 93, 134, 135, 136, 292, 139, 91,
+ 94, 264, 96, 142, 89, 144, 92, 146, 147, 294,
+ 149, 150, 155, 74, 0, 59, 53, 60, 54, 0,
+ 0, 0, 0, 56, 0, 57, 58, 55, 0, 0,
+ 0, 0, 48, 0, 38, 39, 0, 40, 8, 0,
+ 0, 9, 0, 11, 0, 10, 0, 1, 27, 15,
+ 14, 26, 13, 12, 29, 7, 0, 18, 0, 19,
+ 0, 24, 25, 0, 20, 21, 0, 22, 23, 16,
+ 17, 369
+};
const short QQmlJSGrammar::goto_default [] = {
- 7, 650, 211, 198, 209, 521, 509, 645, 658, 508,
- 644, 648, 646, 654, 22, 651, 649, 647, 18, 520,
- 571, 561, 568, 563, 548, 193, 197, 199, 204, 234,
- 212, 231, 552, 622, 621, 203, 233, 26, 487, 486,
- 359, 358, 9, 357, 360, 202, 480, 361, 109, 17,
- 147, 24, 13, 146, 19, 25, 59, 23, 8, 28,
- 27, 280, 15, 274, 10, 270, 12, 272, 11, 271,
- 20, 278, 21, 279, 14, 273, 269, 310, 414, 275,
- 276, 205, 195, 194, 208, 207, 230, 196, 364, 363,
- 232, 471, 470, 332, 333, 473, 335, 472, 334, 427,
- 431, 434, 430, 429, 449, 450, 200, 186, 201, 210,
- 0};
+ 7, 667, 213, 200, 211, 526, 513, 662, 675, 512,
+ 661, 665, 663, 671, 22, 668, 666, 664, 18, 525,
+ 587, 577, 584, 579, 553, 195, 199, 201, 206, 237,
+ 214, 234, 568, 639, 638, 205, 236, 557, 26, 491,
+ 490, 362, 361, 9, 360, 363, 204, 484, 364, 109,
+ 17, 149, 24, 13, 148, 19, 25, 59, 23, 8,
+ 28, 27, 283, 15, 277, 10, 273, 12, 275, 11,
+ 274, 20, 281, 21, 282, 14, 276, 272, 313, 418,
+ 278, 279, 207, 197, 196, 210, 209, 233, 198, 367,
+ 366, 235, 475, 474, 335, 336, 477, 338, 476, 337,
+ 431, 435, 438, 434, 433, 453, 454, 202, 188, 203,
+ 212, 0
+};
const short QQmlJSGrammar::action_index [] = {
- 246, 1285, 2768, 2768, 2666, 998, 98, 198, 86, -106,
- 26, -15, -39, 234, -106, 314, 54, -106, -106, 714,
- 89, 151, 212, 219, -106, -106, -106, 412, 279, 1285,
- -106, -106, -106, 525, -106, -106, 2360, 1675, 1285, 1285,
- 1285, -106, 902, 1285, -106, -106, -106, 1285, 1285, -106,
- -106, -106, -106, -106, -106, 1285, -106, 1285, 1285, -106,
- 1285, 1285, 103, 197, -106, -106, 1285, 1285, 1285, -106,
- -106, -106, 214, 1285, 297, 1285, 1285, 1285, 1285, 392,
- 1285, 1285, 1285, 1285, 1285, 1285, 213, 1285, 1285, 1285,
- 96, 100, 101, 279, 279, 195, 190, 181, 402, 372,
- 382, 1285, -10, 1285, 106, 2258, 1285, 1285, -106, -106,
- -106, -106, -106, -106, -106, -106, -106, -106, -106, -106,
- -106, -106, -106, -106, -106, -106, -106, -106, -106, -106,
- -106, -106, -106, -106, -106, -106, -106, -106, -106, -106,
- -106, -106, 136, 1285, -106, -106, 65, 29, -106, 1285,
- -106, -106, 1285, -106, -106, -106, -106, -106, -106, -106,
- -106, -106, -106, -106, -106, -106, 1285, -46, 1285, 1285,
- 30, 27, 1285, -106, 2258, 1285, 1285, -106, 130, -106,
- -31, -106, -106, -16, 520, 520, 71, 21, -106, 421,
- -106, 38, 2768, -106, -106, -106, -106, -106, 237, -106,
- 520, -106, -52, -106, -106, -106, 23, -106, -106, -106,
- 2768, -106, -106, 596, -106, 588, 141, 2666, 2, 1,
- -1, 2972, 1285, -106, 13, 1285, 28, -106, -28, -30,
- -106, -106, 435, -106, -106, -106, -106, 60, 520, 52,
- 67, 2768, 64, -106, -106, 2666, -106, -106, 126, -106,
- -106, -106, -106, 73, -106, -106, -106, -106, -106, -106,
- -18, 34, 1285, 156, 168, -106, -106, -106, 1479, -106,
- 79, 40, 48, -106, 312, 75, 42, 672, 80, 143,
- 331, 279, 442, 1285, 316, 1285, 1285, 1285, 1285, 341,
- 1285, 1285, 1285, 1285, 1285, 279, 360, 360, 196, 225,
- 443, 357, 351, 1285, -4, 1285, 63, 1285, -106, 714,
- 1285, -106, 1285, 102, 68, 1285, 62, 2666, -106, 1285,
- 147, 2666, -106, 1285, 56, 1285, 1285, 91, 87, 1285,
- -106, 81, 149, 74, -106, -106, 1285, -106, 439, 1285,
- -106, -44, 1285, -42, 2666, -106, 1285, 153, 2666, -106,
- 1285, 154, 2666, 10, 2666, -106, 0, -106, 15, -54,
- 92, -106, -106, 2666, -50, 539, -7, 536, 121, 1285,
- 2666, 5, -8, 445, 2462, 24, 902, 51, 50, 1384,
- 2462, 47, 20, 46, 1285, 44, 19, 1285, 41, 1285,
- 3, -5, 2564, -106, -106, -106, -106, -106, -106, 1285,
- -106, -106, -106, 6, -17, 11, 2768, -9, -106, 249,
- -106, 1285, -13, -106, 105, -106, -106, -12, 520, -41,
- -20, 2768, -45, -106, 1285, 115, 12, -106, 36, -106,
- 31, 122, 1285, -106, 58, 4, -106, -51, -106, 2666,
- -106, 146, 2666, -106, 235, -106, -106, 140, 2666, 93,
- -106, 84, 76, -106, 520, 17, 33, -106, -106, -106,
- -106, 1285, 134, 2666, -106, 1285, 125, 2666, -106, 55,
- -106, 163, -106, -106, 1285, -106, -106, 520, -106, -106,
- 7, 45, 2768, 32, -106, -106, 120, 1773, -106, -106,
- 1577, -106, -106, 1871, -106, -106, -106, -106, -106, -106,
- 113, -106, -106, -106, -106, -106, -106, -106, -106, -106,
- 2768, -106, -106, -106, 109, 35, 808, 206, 49, 61,
- -106, -106, 229, -106, 203, 37, -106, -106, 611, 183,
- -106, 124, 39, 389, -106, 97, -106, -106, 252, -106,
- 2061, -106, -106, -106, -106, -106, -106, -106, -106, -106,
- 269, -23, 611, 243, 180, 424, 232, -106, 16, -106,
- 808, 162, -106, 22, 808, -106, -106, 1190, -106, -106,
- -106, 1094, -106, -106, 248, -106, 2061, -106, 305, -24,
- -106, -106, 215, 457, 18, 2156, 292, 2870, -11, -106,
- 14, 599, 9, 528, 119, 1285, 2666, 8, 70, 514,
- 72, 902, 95, 90, 1384, 85, 59, 77, 1285, 110,
- 83, 1285, 104, 1285, 82, 78, -106, 205, -106, 236,
- -106, 57, 25, 611, 167, 517, -106, 107, -106, -106,
- -106, 1966, 808, 1675, 43, -106, 155, -106, -106, 53,
- -106, -106, 808, 808, 108, 808, -106, 289, -106, 117,
- -106, -106, 150, 157, -106, -106, -106, -106, -106, 364,
- -106, 226, -106, 69, -106, -106, 432, -106, -106, 88,
- -106, -106, -106, -106, -106,
+ 350, 1528, 3041, 3041, 2937, 1235, 115, 105, 239, -108,
+ 102, 93, 95, 205, -108, 422, 110, -108, -108, 727,
+ 92, 118, 265, 256, -108, -108, -108, 507, 247, 1528,
+ -108, -108, -108, 665, -108, -108, 2729, 1826, 1528, 1528,
+ 1528, -108, 1041, 1528, -108, -108, -108, 1528, 1528, -108,
+ -108, -108, -108, -108, -108, 1528, -108, 1528, 1528, -108,
+ 1528, 1528, 174, 221, -108, -108, 1528, 1528, 1528, -108,
+ -108, -108, 177, 1528, 422, 1528, 1528, 1528, 1528, 411,
+ 1528, 1528, 1528, 1528, 1528, 1528, 211, 1528, 1528, 1528,
+ 142, 148, 154, 217, 223, 226, 227, 231, 507, 385,
+ 395, 1528, 57, 1528, 83, 2521, 1528, 1528, -108, -108,
+ -108, -108, -108, -108, -108, -108, -108, -108, -108, -108,
+ -108, -108, -108, -108, -108, -108, -108, -108, -108, -108,
+ -108, -108, -108, -108, -108, -108, -108, -108, -108, -108,
+ -108, -108, -108, -108, 179, 1528, -108, -108, 77, 36,
+ -108, 1528, -108, -108, 1528, -108, -108, -108, -108, -108,
+ -108, -108, -108, -108, -108, -108, -108, -108, 1528, 56,
+ 1528, 1528, 80, 74, 1528, -108, 2521, 1528, 1528, -108,
+ 125, -108, 55, -108, -108, 53, 410, 418, 72, 52,
+ -108, 392, -108, 46, 3041, -108, -108, -108, -108, -108,
+ 273, -108, 396, -108, 44, -108, -108, -108, 76, -108,
+ -108, -108, 3041, -108, -108, 744, -108, 589, 98, 2937,
+ 91, 90, 88, 3249, -108, 1528, -108, 86, 1528, 81,
+ -108, 75, 73, -108, -108, 586, -108, -108, -108, -108,
+ 71, 491, 69, 65, 3041, 64, -108, -108, 2937, -108,
+ -108, 139, -108, -108, -108, -108, 134, -108, -108, -108,
+ -108, -108, -108, 63, 66, 1528, 147, 264, -108, -108,
+ -108, 1726, -108, 87, 68, 70, -108, 334, 82, 78,
+ 796, 89, 121, 349, 318, 469, 1528, 330, 1528, 1528,
+ 1528, 1528, 359, 1528, 1528, 1528, 1528, 1528, 284, 289,
+ 303, 306, 313, 365, 369, 375, 1528, 58, 1528, 85,
+ 1528, -108, 849, 1528, -108, 1528, 79, 59, 1528, 61,
+ 2937, -108, 1528, 146, 2937, -108, 1528, 62, 1528, 1528,
+ 106, 99, 1528, -108, 96, 176, 171, -108, -108, 1528,
+ -108, 407, 1528, -108, 97, 1528, -52, 2937, -108, 1528,
+ 120, 2937, -108, 1528, 123, 2937, 101, 2937, -108, 116,
+ -108, 84, 45, 0, -108, -108, 2937, -39, 641, -3,
+ 652, 156, 1528, 2937, -7, -11, 567, 2625, -21, 5,
+ 945, 2, 94, 1629, 2625, -1, -26, 6, 1528, 10,
+ -15, 1528, 14, 1528, -25, -12, 2833, -108, -108, -108,
+ -108, -108, -108, 1528, -108, -108, -108, -14, -58, -13,
+ 3041, -36, -108, 287, -108, 1528, -46, -108, 153, -108,
+ -108, -31, 586, -57, -32, 3041, 11, -108, 1528, 168,
+ 29, -108, 47, -108, 48, 169, 1528, -108, 49, 50,
+ -108, 9, -108, 2937, -108, 136, 2937, -108, 275, -108,
+ -108, 126, 2937, 35, -108, 33, 37, -108, 466, -4,
+ 38, -108, -108, -108, -108, 1528, 130, 2937, -108, 1528,
+ 117, 2937, -108, 34, -108, 296, -108, -108, 1528, -108,
+ -108, 404, -108, -108, 12, 40, 3041, 13, -108, -108,
+ 155, 1926, -108, -108, 2026, -108, -108, 2126, -108, -108,
+ -108, -108, -108, -108, 144, -108, -108, -108, -108, -108,
+ -108, -108, -108, -108, 3041, -108, -108, -108, 132, -27,
+ 15, 1137, 218, -23, 17, -108, -108, 196, -108, 242,
+ 8, -108, -108, 579, 237, -108, 127, 18, 415, -108,
+ 103, -108, -108, 236, -108, 2223, -108, -108, -108, -108,
+ -108, -108, -108, -108, -108, 27, 21, 137, 31, 20,
+ -108, 23, -5, -108, -9, -108, 332, -10, 571, 201,
+ 195, 586, 225, -108, 7, -108, 1137, 165, -108, 4,
+ 1137, -108, -108, 1333, -108, -108, -108, 1431, -108, -108,
+ 184, -108, 2223, -108, 331, 3, -108, -108, 202, 531,
+ 26, 2417, 327, 3145, 1, -108, 25, 629, 24, 649,
+ 124, 1528, 2937, 22, -6, 514, -8, 19, 1041, 16,
+ 94, 1629, 28, 42, 67, 1528, 60, 43, 1528, 54,
+ 1528, 41, 39, -108, 234, -108, 228, -108, 51, -2,
+ 564, 233, 575, -108, 100, -108, -108, -108, 2320, 1137,
+ 1826, 32, -108, 122, -108, -108, 30, -108, -108, 1137,
+ 1137, 104, 903, -108, 308, -108, 108, -108, -108, 133,
+ 119, -108, -108, -108, -108, -108, 451, -108, 164, -108,
+ 161, -108, -108, 458, -108, -108, 151, -108, -108, -108,
+ -108, -108,
- -111, 8, 65, 83, 84, 317, 1, -111, -111, -111,
- -111, -111, -111, -111, -111, -111, -111, -111, -111, -77,
- -111, -111, -111, -111, -111, -111, -111, -111, -111, 96,
- -111, -111, -111, 2, -111, -111, -5, -28, 12, 106,
- 95, -111, 61, 55, -111, -111, -111, 63, 70, -111,
- -111, -111, -111, -111, -111, 54, -111, 172, 177, -111,
- 180, 191, -111, -111, -111, -111, 197, 202, 203, -111,
- -111, -111, -111, 210, -111, 209, 195, 109, 116, -111,
- 146, 125, 126, 127, 135, 138, -111, 141, 144, 110,
- -111, -111, -111, -111, -111, -111, -111, -111, -111, -111,
- -111, 150, -111, 155, -111, 192, 4, -33, -111, -111,
- -111, -111, -111, -111, -111, -111, -111, -111, -111, -111,
- -111, -111, -111, -111, -111, -111, -111, -111, -111, -111,
- -111, -111, -111, -111, -111, -111, -111, -111, -111, -111,
- -111, -111, -111, -9, -111, -111, -111, -111, -111, 7,
- -111, -111, 40, -111, -111, -111, -111, -111, -111, -111,
- -111, -111, -111, -111, -111, -111, 99, -111, 52, 31,
- -111, -111, 30, -111, 253, 44, 87, -111, -111, -111,
- -111, -111, -111, -111, 45, 86, -111, -111, -111, 41,
- -111, -111, 5, -111, -111, -111, -111, -111, -111, -111,
- 50, -111, -111, -111, -111, -111, -111, -111, -111, -111,
- 154, -111, -111, 26, -111, 49, -111, 330, -111, 28,
- -111, 248, 27, -111, -111, 124, 51, -111, -111, -111,
- -111, -111, 46, -111, -111, -111, -111, -111, 196, -111,
- -111, 185, -111, -111, -111, 194, -111, -111, -111, -111,
- -111, -111, -111, -111, -111, -111, -111, -111, -111, -111,
- -111, -111, 15, -111, -111, -111, -111, -111, 74, -111,
- -111, -111, -111, -111, -111, -111, -111, -111, -111, -111,
- -111, -111, -16, 230, -111, 233, 269, 251, 265, -111,
- 80, 81, 82, 88, 89, -111, -111, -111, -111, -111,
- -111, -111, -111, 216, -111, 255, -111, 259, -111, -111,
- 223, -111, 68, -111, -111, 217, -111, 236, -111, 24,
- -111, 244, -111, 227, -111, 226, 257, -111, -111, 263,
- -111, -111, -111, -111, -111, -111, 249, -111, 113, 163,
- -111, -111, 212, -111, 173, -111, 48, -111, 211, -111,
- 53, -111, 206, -111, 204, -111, -111, -111, -111, -111,
- -111, -111, -111, 199, -111, 23, -111, 25, -111, 134,
- 175, -111, -111, 37, 200, -111, 222, -111, -111, 57,
- 56, -111, -111, -111, 124, -111, 32, 43, -111, 105,
- -111, -111, 139, -111, -111, -111, -111, -111, -111, 38,
- -111, -111, -111, -111, -111, -111, 75, -111, -111, -111,
- -111, 71, -111, -111, -111, -111, -111, -111, 72, -111,
- -111, 85, -111, -111, 59, -111, -111, -111, -111, -111,
- -37, -111, 62, -111, -58, -111, -111, -111, -111, 286,
- -111, -111, 250, -111, -111, -111, -111, -111, 153, -57,
- -111, -111, 33, -111, 34, -111, 36, -111, -111, -111,
- -111, 47, -111, 77, -111, 29, -111, 67, -111, -111,
- -111, -111, -111, -111, 42, -111, -111, 214, -111, -111,
- -111, -111, 229, -111, -111, -111, -111, 35, -111, -111,
- 145, -111, -111, 3, -111, -111, -111, -111, -111, -111,
- -111, -111, -111, -111, -111, -111, -111, -111, -111, -111,
- 207, -111, -111, -111, -111, -111, 39, -111, -111, -111,
- -111, -111, -111, -111, -24, -111, -111, -111, -12, -27,
- -111, -111, -111, -14, -111, -111, -111, -111, -111, -111,
- 333, -111, -111, -111, -111, -111, -111, -111, -111, -111,
- -111, -111, 6, 22, -111, 20, -111, -111, -111, -111,
- 159, -111, -111, -111, 246, -111, -111, 332, -111, -111,
- -111, 436, -111, -111, -111, -111, 388, -111, -111, 18,
- -111, -111, -6, 19, -111, 352, -111, 225, 14, -111,
- -111, 13, -111, 11, -111, 167, 136, -111, -111, 10,
- -111, 64, -111, -111, 9, -111, -111, -111, 124, -111,
- 0, 69, -111, 60, -111, -111, -111, -111, -111, -10,
- -111, -111, -111, -1, -11, -2, -111, -111, -111, -111,
- -111, 370, 142, 315, -3, -111, -111, -111, -111, 17,
- -111, -111, -13, 21, 133, 221, -111, -111, -111, -111,
- -111, -111, -111, -111, -111, -111, -111, -111, -111, 16,
- -111, -111, -111, -111, -111, -111, -15, -111, -111, -111,
- -111, -111, -111, -111, -111};
+ -112, 18, 86, 97, 69, 316, 7, -112, -112, -112,
+ -112, -112, -112, -112, -112, -112, -112, -112, -112, -64,
+ -112, -112, -112, -112, -112, -112, -112, -112, -112, 66,
+ -112, -112, -112, -17, -112, -112, -10, -36, 3, 90,
+ 95, -112, 149, 74, -112, -112, -112, 67, 13, -112,
+ -112, -112, -112, -112, -112, 178, -112, 181, 185, -112,
+ 189, 190, -112, -112, -112, -112, 198, 208, 212, -112,
+ -112, -112, -112, 209, -112, 201, 164, 111, 113, -112,
+ 116, 130, 131, 132, 134, 142, -112, 118, 124, 144,
+ -112, -112, -112, -112, -112, -112, -112, -112, -112, -112,
+ -112, 154, -112, 155, -112, 268, 28, -8, -112, -112,
+ -112, -112, -112, -112, -112, -112, -112, -112, -112, -112,
+ -112, -112, -112, -112, -112, -112, -112, -112, -112, -112,
+ -112, -112, -112, -112, -112, -112, -112, -112, -112, -112,
+ -112, -112, -112, -112, -112, 42, -112, -112, -112, -112,
+ -112, 47, -112, -112, 50, -112, -112, -112, -112, -112,
+ -112, -112, -112, -112, -112, -112, -112, -112, 159, -112,
+ 158, 56, -112, -112, 57, -112, 362, 60, 157, -112,
+ -112, -112, -112, -112, -112, -112, 20, 151, -112, -112,
+ -112, 25, -112, -112, 30, -112, -112, -112, -112, -112,
+ -112, -112, 31, -112, -112, -112, -112, -112, -112, -112,
+ -112, -112, 233, -112, -112, 34, -112, 35, -112, 225,
+ -112, 36, -112, 216, -112, 55, -112, -112, 53, 39,
+ -112, -112, -112, -112, -112, 19, -112, -112, -112, -112,
+ -112, 94, -112, -112, 92, -112, -112, -112, 117, -112,
+ -112, -112, -112, -112, -112, -112, -112, -112, -112, -112,
+ -112, -112, -112, -112, -112, 33, -112, -112, -112, -112,
+ -112, 88, -112, -112, -112, -112, -112, -112, -112, -112,
+ -112, -112, -112, -112, -112, 51, 220, -112, 227, 235,
+ 236, 244, -112, 21, 17, 102, 91, 89, -112, -112,
+ -112, -112, -112, -112, -112, -112, 211, -112, 247, -112,
+ 257, -112, -112, 264, -112, 75, -112, -112, 103, -112,
+ 112, -112, 29, -112, 73, -112, 263, -112, 255, 254,
+ -112, -112, 245, -112, -112, -112, -112, -112, -112, 248,
+ -112, 65, 105, -112, -112, 99, -112, 162, -112, 37,
+ -112, 115, -112, 44, -112, 135, -112, 137, -112, -112,
+ -112, -112, -112, -112, -112, -112, 138, -112, 24, -112,
+ 26, -112, 104, 140, -112, -112, 32, 64, -112, -112,
+ 174, -112, -112, 48, 87, -112, -112, -112, 54, -112,
+ 40, 71, -112, 150, -112, -112, 197, -112, -112, -112,
+ -112, -112, -112, 12, -112, -112, -112, -112, -112, -112,
+ 206, -112, -112, -112, -112, 207, -112, -112, -112, -112,
+ -112, -112, 231, -112, -112, 239, -112, -112, 43, -112,
+ -112, -112, -112, -112, -59, -112, 38, -112, -62, -112,
+ -112, -112, -112, 258, -112, -112, 259, -112, -112, -112,
+ -112, -112, 163, -72, -112, -112, 41, -112, 62, -112,
+ 61, -112, -112, -112, -112, 59, -112, 193, -112, 58,
+ -112, 204, -112, -112, -112, -112, -112, -112, 52, -112,
+ -112, 175, -112, -112, -112, -112, 186, -112, -112, -112,
+ -112, 49, -112, -112, 173, -112, -112, 45, -112, -112,
+ -112, -112, -112, -112, -112, -112, -112, -112, -112, -112,
+ -112, -112, -112, -112, 213, -112, -112, -112, -112, -112,
+ -112, 46, -112, -112, -112, -112, -112, -112, -112, 27,
+ -112, -112, -112, -18, -9, -112, -112, -112, 15, -112,
+ -112, -112, -112, -112, -112, 331, -112, -112, -112, -112,
+ -112, -112, -112, -112, -112, -112, -112, -112, -112, -112,
+ -112, -112, -112, -112, -112, -112, -112, -112, 11, -6,
+ -112, 10, -112, -112, -112, -112, 156, -112, -112, -112,
+ 240, -112, -112, 330, -112, -112, -112, 332, -112, -112,
+ -112, -112, 376, -112, -112, 8, -112, -112, -7, 76,
+ -112, 358, -112, 228, 5, -112, -112, 6, -112, 4,
+ -112, 79, 221, -112, -112, 2, -112, -112, 174, -112,
+ -112, 16, -112, -112, -112, 14, -112, -16, 70, -112,
+ 63, -112, -112, -112, -112, -112, -30, -112, -112, -112,
+ -15, -28, -13, -112, -112, -112, -112, -112, 460, 93,
+ 307, -12, -112, -112, -112, -112, -11, -112, -112, -2,
+ -1, 85, 84, -112, -112, -112, -112, -112, -112, -112,
+ -112, -112, -112, -112, -112, -112, -3, -112, -112, -112,
+ -112, -112, -112, 0, -112, -112, -112, -112, -112, -112,
+ -112, -112
+};
const short QQmlJSGrammar::action_info [] = {
- -145, 398, 101, 244, 438, 402, 465, 245, 461, 567,
- 423, 439, -126, 421, 553, -126, -145, 342, 344, 420,
- 185, 245, 567, 392, 418, 585, 354, 73, 268, 181,
- 245, 465, 166, 101, 172, 350, 432, 184, 268, 461,
- 103, 432, 404, 405, 406, 428, 408, 413, -142, 424,
- 560, -139, 448, -137, -115, 567, 424, -116, -134, 261,
- 350, 448, 143, 432, 283, 624, 448, 481, 534, 103,
- 262, 192, 474, 149, 529, 305, 567, 456, 482, 189,
- 283, 191, 323, 307, -137, 627, 567, 484, 303, 151,
- 617, 166, -115, 323, 329, 424, 238, -116, 336, 399,
- 241, 524, -134, 312, 303, 346, 268, 73, 350, 448,
- 143, -142, 240, 452, 465, 582, 448, -139, 461, 243,
- 454, 143, 317, 143, 174, 0, 60, 305, 490, 315,
- 665, 664, 435, 143, 257, 256, 60, 61, 143, 532,
- 60, 60, 143, 175, 143, 64, 451, 61, 533, 671,
- 670, 61, 61, 442, 143, 143, 65, 338, 537, 536,
- 452, 143, 143, 564, 143, 174, 416, 415, 629, 628,
- 564, 477, 174, 501, 0, 426, 491, 436, 673, 672,
- 259, 258, 259, 258, 175, 467, 179, 252, 251, 642,
- 643, 175, 144, 325, 463, 532, 530, 326, 674, 642,
- 643, 168, 259, 258, 555, 169, 87, 321, 88, 66,
- 339, 637, 530, 348, 352, 87, 264, 88, 565, 89,
- 87, 87, 88, 88, 478, 476, 66, 174, 89, 267,
- 265, 66, 525, 89, 89, 551, 631, 0, 87, 558,
- 88, 619, 527, 143, 530, 143, 175, 0, 176, 105,
- 87, 89, 88, 526, 67, 576, 0, 266, 527, 540,
- 68, 0, 567, 89, 174, 530, 620, 618, 106, 526,
- 107, 67, 530, 0, 0, 0, 67, 68, 527, 0,
- 0, 527, 68, 175, 174, 411, 0, 668, 667, 526,
- 527, 0, 526, 559, 557, 0, 446, 445, 236, 235,
- 0, 526, 0, 175, 87, 411, 88, 174, 0, 577,
- 575, 527, 0, 541, 539, 75, 76, 89, 527, 666,
- 174, 0, 526, 632, 0, -102, 175, 0, 176, 526,
- 285, 286, 75, 76, 285, 286, 661, 0, -102, 175,
- 0, 176, 77, 78, 6, 5, 4, 1, 3, 2,
- 662, 660, 0, 0, 290, 291, 0, 287, 288, 77,
- 78, 287, 288, 292, 290, 291, 293, 0, 294, 0,
- 0, 0, 0, 292, 290, 291, 293, 0, 294, 0,
- 290, 291, 659, 292, 0, 87, 293, 88, 294, 292,
- 0, 0, 293, 35, 294, 80, 81, 0, 89, 0,
- 0, 0, 0, 82, 83, 80, 81, 84, 0, 85,
- 0, 0, 0, 82, 83, 80, 81, 84, 35, 85,
- 0, 0, 0, 82, 83, 80, 81, 84, 0, 85,
- 49, 52, 50, 82, 83, 80, 81, 84, 0, 85,
- 0, 0, 0, 82, 83, 0, 0, 84, 0, 85,
- 35, 0, 0, 35, 0, 49, 52, 50, 46, 34,
- 51, 35, 0, 0, 35, 0, 290, 291, 35, 0,
- 0, 35, 532, 0, 35, 292, 0, 0, 293, 0,
- 294, 184, 0, 46, 34, 51, 35, 49, 52, 50,
- 49, 52, 50, 0, 0, 0, 0, 0, 49, 52,
- 50, 49, 52, 50, 0, 49, 52, 50, 49, 52,
- 50, 49, 52, 50, 0, 46, 34, 51, 46, 34,
- 51, 0, 0, 49, 52, 50, 46, 34, 51, 46,
- 34, 51, 532, 46, 34, 51, 46, 34, 51, 46,
- 34, 51, 0, 35, 0, 0, 35, 0, 0, 35,
- 184, 46, 34, 51, 35, 0, 0, 35, 0, 0,
- 0, 184, 0, 0, 0, 35, 0, 0, 35, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 49, 52, 50, 49, 52, 50, 49, 52, 50, 255,
- 254, 49, 52, 50, 49, 52, 50, 255, 254, 0,
- 250, 249, 49, 52, 50, 49, 52, 50, 46, 34,
- 51, 46, 34, 51, 46, 34, 51, 35, 0, 46,
- 34, 51, 46, 34, 51, 35, 532, 0, 35, 0,
- 46, 34, 51, 46, 34, 51, 0, 0, 0, 0,
- 35, 0, 0, 0, 0, 0, 0, 0, 0, 255,
- 254, 0, 0, 0, 49, 52, 50, 250, 249, 0,
- 250, 249, 49, 52, 50, 49, 52, 50, 0, 0,
- 0, 0, 0, 0, 0, 153, 0, 49, 52, 50,
- 0, 0, 46, 34, 51, 154, 0, 0, 0, 155,
- 46, 34, 51, 46, 34, 51, 0, 0, 156, 0,
- 157, 0, 0, 319, 0, 46, 34, 51, 0, 0,
- 0, 158, 0, 159, 64, 0, 0, 153, 0, 0,
- 0, 160, 0, 0, 161, 65, 0, 154, 0, 0,
- 162, 155, 0, 0, 0, 0, 163, 0, 0, 0,
- 156, 0, 157, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 164, 158, 0, 159, 64, 0, 0, 0,
- 0, 0, 0, 160, 0, 0, 161, 65, 0, 0,
- 0, 0, 162, 0, 0, 0, 0, 0, 163, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 164, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 30, 31, 0, 0, 0, 0, 0, 0, 0, 0,
- 33, 0, 0, 0, 0, 0, 0, 35, 0, 0,
- 0, 36, 37, 0, 38, 0, 0, 0, 0, 0,
- 0, 516, 0, 0, 0, 45, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 53, 49, 52, 50, 0, 54, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 44,
- 56, 32, 0, 0, 0, 41, 0, 0, 0, 0,
- 0, 0, 46, 34, 51, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 30, 31, 0, 0, 0, 0,
- 0, 0, 0, 0, 33, 0, 0, 0, 0, 0,
- 0, 35, 0, 0, 0, 36, 37, 0, 38, 0,
- 0, 0, 0, 0, 0, 42, 0, 0, 0, 45,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 53, 49, 52,
- 50, 0, 54, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 44, 56, 32, 0, 0, 0, 41,
- 0, 0, 0, 0, 0, 0, 46, 34, 51, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 515, 0,
- 30, 31, 0, 0, 0, 0, 0, 0, 0, 0,
- 219, 0, 0, 0, 0, 0, 0, 35, 0, 0,
- 0, 36, 37, 0, 38, 0, 0, 0, 0, 0,
- 0, 516, 0, 0, 0, 45, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 53, 517, 519, 518, 0, 54, 0,
- 0, 0, 0, 227, 0, 0, 0, 0, 0, 44,
- 56, 32, 214, 0, 0, 41, 0, 0, 0, 0,
- 0, 0, 46, 34, 51, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 515, 0, 30, 31, 0, 0,
- 0, 0, 0, 0, 0, 0, 219, 0, 0, 0,
- 0, 0, 0, 35, 0, 0, 0, 36, 37, 0,
- 38, 0, 0, 0, 0, 0, 0, 516, 0, 0,
- 0, 45, 0, 0, 0, 0, 0, 0, 0, 572,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 53,
- 517, 519, 518, 0, 54, 0, 0, 0, 0, 227,
- 0, 0, 0, 0, 0, 44, 56, 32, 214, 0,
- 0, 41, 0, 0, 0, 0, 0, 0, 46, 34,
- 51, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 515, 0, 30, 31, 0, 0, 0, 0, 0, 0,
- 0, 0, 219, 0, 0, 0, 0, 0, 0, 35,
- 0, 0, 0, 36, 37, 0, 38, 0, 0, 0,
- 0, 0, 0, 516, 0, 0, 0, 45, 0, 0,
- 0, 0, 0, 0, 0, 569, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 53, 517, 519, 518, 0,
- 54, 0, 0, 0, 0, 227, 0, 0, 0, 0,
- 0, 44, 56, 32, 214, 0, 0, 41, 0, 0,
- 0, 0, 0, 0, 46, 34, 51, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 29, 30, 31, 0,
- 0, 0, 0, 0, 0, 0, 0, 33, 0, 0,
- 0, 0, 0, 0, 35, 0, 0, 0, 36, 37,
- 0, 38, 0, 0, 0, 39, 0, 40, 42, 43,
- 0, 0, 45, 0, 0, 0, 47, 0, 48, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 53, 49, 52, 50, 0, 54, 0, 55, 0, 57,
- 0, 58, 0, 0, 0, 0, 44, 56, 32, 0,
- 0, 0, 41, 0, 0, 0, 0, 0, 0, 46,
- 34, 51, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, -135, 0, 0, 0, 29, 30, 31, 0, 0,
- 0, 0, 0, 0, 0, 0, 33, 0, 0, 0,
- 0, 0, 0, 35, 0, 0, 0, 36, 37, 0,
- 38, 0, 0, 0, 39, 0, 40, 42, 43, 0,
- 0, 45, 0, 0, 0, 47, 0, 48, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 53,
- 49, 52, 50, 0, 54, 0, 55, 0, 57, 0,
- 58, 0, 0, 0, 0, 44, 56, 32, 0, 0,
- 0, 41, 0, 0, 0, 0, 0, 0, 46, 34,
- 51, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 29, 30, 31, 0, 0, 0, 0, 0, 0, 0,
- 0, 33, 0, 0, 0, 0, 0, 0, 35, 0,
- 0, 0, 36, 37, 0, 38, 0, 0, 0, 39,
- 0, 40, 42, 43, 0, 0, 45, 0, 0, 0,
- 47, 0, 48, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 53, 49, 52, 50, 0, 54,
- 0, 55, 0, 57, 282, 58, 0, 0, 0, 0,
- 44, 56, 32, 0, 0, 0, 41, 0, 0, 0,
- 0, 0, 0, 46, 34, 51, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 488, 0, 0, 29, 30,
- 31, 0, 0, 0, 0, 0, 0, 0, 0, 33,
- 0, 0, 0, 0, 0, 0, 35, 0, 0, 0,
- 36, 37, 0, 38, 0, 0, 0, 39, 0, 40,
- 42, 43, 0, 0, 45, 0, 0, 0, 47, 0,
- 48, 0, 0, 494, 0, 0, 0, 0, 0, 0,
- 0, 0, 53, 49, 52, 50, 0, 54, 0, 55,
- 0, 57, 0, 58, 0, 0, 0, 0, 44, 56,
- 32, 0, 0, 0, 41, 0, 0, 0, 0, 0,
- 0, 46, 34, 51, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 488, 0, 0, 29, 30, 31, 0,
- 0, 0, 0, 0, 0, 0, 0, 33, 0, 0,
- 0, 0, 0, 0, 35, 0, 0, 0, 36, 37,
- 0, 38, 0, 0, 0, 39, 0, 40, 42, 43,
- 0, 0, 45, 0, 0, 0, 47, 0, 48, 0,
- 0, 489, 0, 0, 0, 0, 0, 0, 0, 0,
- 53, 49, 52, 50, 0, 54, 0, 55, 0, 57,
- 0, 58, 0, 0, 0, 0, 44, 56, 32, 0,
- 0, 0, 41, 0, 0, 0, 0, 0, 0, 46,
- 34, 51, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 496, 0, 0, 29, 30, 31, 0, 0, 0,
- 0, 0, 0, 0, 0, 33, 0, 0, 0, 0,
- 0, 0, 35, 0, 0, 0, 36, 37, 0, 38,
- 0, 0, 0, 39, 0, 40, 42, 43, 0, 0,
- 45, 0, 0, 0, 47, 0, 48, 0, 0, 499,
- 0, 0, 0, 0, 0, 0, 0, 0, 53, 49,
- 52, 50, 0, 54, 0, 55, 0, 57, 0, 58,
- 0, 0, 0, 0, 44, 56, 32, 0, 0, 0,
- 41, 0, 0, 0, 0, 0, 0, 46, 34, 51,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 496,
- 0, 0, 29, 30, 31, 0, 0, 0, 0, 0,
- 0, 0, 0, 33, 0, 0, 0, 0, 0, 0,
- 35, 0, 0, 0, 36, 37, 0, 38, 0, 0,
- 0, 39, 0, 40, 42, 43, 0, 0, 45, 0,
- 0, 0, 47, 0, 48, 0, 0, 497, 0, 0,
- 0, 0, 0, 0, 0, 0, 53, 49, 52, 50,
- 0, 54, 0, 55, 0, 57, 0, 58, 0, 0,
- 0, 0, 44, 56, 32, 0, 0, 0, 41, 0,
- 0, 0, 0, 0, 0, 46, 34, 51, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 29, 30, 31,
- 0, 0, 0, 0, 0, 0, 0, 0, 33, 0,
- 0, 0, 0, 0, 0, 35, 220, 0, 0, 587,
- 633, 0, 38, 0, 0, 0, 39, 0, 40, 42,
- 43, 0, 0, 45, 0, 0, 0, 47, 0, 48,
- 0, 0, 0, 0, 0, 0, 0, 223, 0, 0,
- 0, 53, 49, 52, 50, 224, 54, 0, 55, 226,
- 57, 0, 58, 0, 229, 0, 0, 44, 56, 32,
- 0, 0, 0, 41, 0, 0, 0, 0, 0, 0,
- 46, 34, 51, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 29, 30, 31, 0, 0, 0, 0, 0,
- 0, 0, 0, 33, 0, 0, 0, 0, 0, 0,
- 35, 220, 0, 0, 221, 37, 0, 38, 0, 0,
- 0, 39, 0, 40, 42, 43, 0, 0, 45, 0,
- 0, 0, 47, 0, 48, 0, 0, 0, 0, 0,
- 0, 0, 223, 0, 0, 0, 53, 49, 52, 50,
- 224, 54, 0, 55, 226, 57, 0, 58, 0, 229,
- 0, 0, 44, 56, 32, 0, 0, 0, 41, 0,
- 0, 0, 0, 0, 0, 46, 34, 51, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 29, 30, 31,
- 0, 0, 0, 0, 0, 0, 0, 0, 33, 0,
- 0, 0, 0, 0, 0, 35, 220, 0, 0, 587,
- 37, 0, 38, 0, 0, 0, 39, 0, 40, 42,
- 43, 0, 0, 45, 0, 0, 0, 47, 0, 48,
- 0, 0, 0, 0, 0, 0, 0, 223, 0, 0,
- 0, 53, 49, 52, 50, 224, 54, 0, 55, 226,
- 57, 0, 58, 0, 229, 0, 0, 44, 56, 32,
- 0, 0, 0, 41, 0, 0, 0, 0, 0, 0,
- 46, 34, 51, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 111, 112, 113, 0, 0, 115, 117, 118,
- 0, 0, 119, 0, 120, 0, 0, 0, 122, 123,
- 124, 0, 0, 0, 0, 0, 0, 35, 125, 126,
- 127, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 128, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 131, 0, 0,
- 0, 0, 0, 0, 49, 52, 50, 132, 133, 134,
- 0, 136, 137, 138, 139, 140, 141, 0, 0, 129,
- 135, 121, 114, 116, 130, 0, 0, 0, 0, 0,
- 0, 0, 46, 34, 51, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 111, 112, 113, 0, 0, 115,
- 117, 118, 0, 0, 119, 0, 120, 0, 0, 0,
- 122, 123, 124, 0, 0, 0, 0, 0, 0, 35,
- 125, 126, 127, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 128, 0, 0, 0, 395, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 131,
- 0, 0, 0, 0, 0, 397, 49, 52, 50, 132,
- 133, 134, 0, 136, 137, 138, 139, 140, 141, 0,
- 0, 129, 135, 121, 114, 116, 130, 0, 0, 0,
- 0, 0, 0, 0, 46, 374, 380, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 111, 112, 113, 0,
- 0, 115, 117, 118, 0, 0, 119, 0, 120, 0,
- 0, 0, 122, 123, 124, 0, 0, 0, 0, 0,
- 0, 35, 125, 126, 127, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 128, 0, 0, 0, 395,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 131, 0, 0, 0, 0, 0, 397, 49, 52,
- 50, 132, 133, 134, 0, 136, 137, 138, 139, 140,
- 141, 0, 0, 129, 135, 121, 114, 116, 130, 0,
- 0, 0, 0, 0, 0, 0, 46, 34, 51, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 111, 112,
- 113, 0, 0, 115, 117, 118, 0, 0, 119, 0,
- 120, 0, 0, 0, 122, 123, 124, 0, 0, 0,
- 0, 0, 0, 35, 125, 126, 127, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 128, 0, 0,
- 0, 395, 0, 0, 0, 0, 0, 0, 0, 396,
- 0, 0, 0, 131, 0, 0, 0, 0, 0, 397,
- 49, 52, 50, 132, 133, 134, 0, 136, 137, 138,
- 139, 140, 141, 0, 0, 129, 135, 121, 114, 116,
- 130, 0, 0, 0, 0, 0, 0, 0, 46, 374,
- 380, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 213, 0, 0, 0, 0, 215, 0, 29, 30, 31,
- 217, 0, 0, 0, 0, 0, 0, 218, 33, 0,
- 0, 0, 0, 0, 0, 35, 220, 0, 0, 221,
- 37, 0, 38, 0, 0, 0, 39, 0, 40, 42,
- 43, 0, 0, 45, 0, 0, 0, 47, 0, 48,
- 0, 0, 0, 0, 0, 222, 0, 223, 0, 0,
- 0, 53, 49, 52, 50, 224, 54, 225, 55, 226,
- 57, 227, 58, 228, 229, 0, 0, 44, 56, 32,
- 214, 216, 0, 41, 0, 0, 0, 0, 0, 0,
- 46, 34, 51, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 213, 0, 0, 0, 0, 215, 0, 29,
- 30, 31, 217, 0, 0, 0, 0, 0, 0, 218,
- 219, 0, 0, 0, 0, 0, 0, 35, 220, 0,
- 0, 221, 37, 0, 38, 0, 0, 0, 39, 0,
- 40, 42, 43, 0, 0, 45, 0, 0, 0, 47,
- 0, 48, 0, 0, 0, 0, 0, 222, 0, 223,
- 0, 0, 0, 53, 49, 52, 50, 224, 54, 225,
- 55, 226, 57, 227, 58, 228, 229, 0, 0, 44,
- 56, 32, 214, 216, 0, 41, 0, 0, 0, 0,
- 0, 0, 46, 34, 51, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 591, 112, 113, 0, 0, 593,
- 117, 595, 30, 31, 596, 0, 120, 0, 0, 0,
- 122, 598, 599, 0, 0, 0, 0, 0, 0, 35,
- 600, 126, 127, 221, 37, 0, 38, 0, 0, 0,
- 39, 0, 40, 601, 43, 0, 0, 603, 0, 0,
- 0, 47, 0, 48, 0, 0, 0, 0, 0, 604,
- 0, 223, 0, 0, 0, 605, 49, 52, 50, 606,
- 607, 608, 55, 610, 611, 612, 613, 614, 615, 0,
- 0, 602, 609, 597, 592, 594, 130, 41, 0, 0,
- 0, 0, 0, 0, 46, 374, 380, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 365, 112, 113, 0,
- 0, 367, 117, 369, 30, 31, 370, 0, 120, 0,
- 0, 0, 122, 372, 373, 0, 0, 0, 0, 0,
- 0, 35, 375, 126, 127, 221, 37, 0, 38, 0,
- 0, 0, 39, 0, 40, 376, 43, 0, 0, 378,
- 0, 0, 0, 47, 0, 48, 0, -281, 0, 0,
- 0, 379, 0, 223, 0, 0, 0, 381, 49, 52,
- 50, 382, 383, 384, 55, 386, 387, 388, 389, 390,
- 391, 0, 0, 377, 385, 371, 366, 368, 130, 41,
- 0, 0, 0, 0, 0, 0, 46, 374, 380, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
+ -132, 425, 409, 424, -151, 422, -120, 403, 347, -140,
+ 428, 465, -152, -143, 417, 353, 406, -145, 452, 412,
+ 410, -148, 408, -140, 469, 271, -152, 569, 353, -132,
+ 271, -151, 248, 601, 583, -120, 583, 583, 565, 529,
+ 562, 576, 563, 598, 555, 534, 634, 539, 564, 561,
+ 558, 478, 436, 436, 436, 456, 460, 443, 644, 641,
+ 556, -148, 432, 583, 442, 583, 427, -145, 488, 458,
+ 452, 452, 485, 486, -143, 469, 452, 465, 428, 194,
+ 191, 174, 168, 248, 73, 151, 286, 145, 286, 187,
+ 310, 326, 396, 0, 168, 0, 153, 0, 244, 247,
+ 402, -121, 265, 73, 101, 691, 332, 241, 326, 469,
+ 306, 465, 193, 339, 452, 183, 306, 357, 145, 246,
+ 318, 320, 428, 248, 353, 145, 186, 271, 145, 243,
+ 580, 145, 455, 145, 176, 0, 103, 308, 145, 315,
+ 264, 101, 537, 446, 145, 559, 456, 176, 176, 308,
+ 0, 538, 145, 177, 145, 145, 0, 0, 345, 262,
+ 261, 646, 645, 494, 542, 541, 177, 177, 170, 690,
+ 689, 328, 171, 580, 103, 329, 145, 471, 654, 439,
+ 351, 181, 60, 355, 341, 262, 261, 145, 60, 66,
+ 467, 592, 560, 61, 60, 260, 259, 659, 660, 61,
+ 255, 254, 349, 648, 505, 61, 324, 267, 659, 660,
+ 537, 495, 688, 687, 420, 419, 64, 262, 261, 571,
+ 105, 581, 682, 681, 440, 685, 684, 65, 430, 583,
+ 535, 535, 574, 66, 67, 146, 87, 342, 88, 106,
+ 68, 107, 87, 545, 88, 593, 591, 567, 87, 89,
+ 88, 87, 87, 88, 88, 89, 87, 535, 88, 683,
+ 0, 89, 535, 0, 89, 89, 535, 0, 66, 89,
+ 636, 530, 87, 0, 88, 0, 532, 532, 67, 60,
+ 176, 145, 0, 145, 68, 89, 575, 573, 531, 531,
+ 61, 0, 649, 532, 0, 637, 635, 546, 544, 177,
+ 0, 178, 176, 532, 481, 531, 0, 0, 532, 87,
+ 0, 88, 532, 67, 87, 531, 88, 532, 0, 68,
+ 531, 177, 89, 415, 531, 270, 268, 89, 87, 531,
+ 88, 87, 0, 88, 239, 238, 450, 449, 87, 0,
+ 88, 89, 176, 87, 89, 88, 176, 176, 288, 289,
+ 0, 89, 288, 289, 269, 678, 89, 482, 480, 0,
+ -107, 177, 0, 178, -107, 177, 177, 178, 415, 679,
+ 677, 0, 293, 294, 0, 290, 291, 0, 0, 290,
+ 291, 295, 293, 294, 296, 0, 297, 0, 293, 294,
+ 0, 295, 293, 294, 296, 0, 297, 295, 293, 294,
+ 296, 295, 297, 676, 296, 0, 297, 295, 80, 81,
+ 296, 0, 297, 0, 0, 0, 82, 83, 80, 81,
+ 84, 35, 85, 0, 0, 35, 82, 83, 0, 0,
+ 84, 0, 85, 35, 80, 81, 35, 0, 0, 35,
+ 75, 76, 82, 83, 35, 0, 84, 35, 85, 0,
+ 6, 5, 4, 1, 3, 2, 0, 0, 49, 52,
+ 50, 0, 49, 52, 50, 0, 0, 77, 78, 0,
+ 49, 52, 50, 49, 52, 50, 49, 52, 50, 0,
+ 35, 49, 52, 50, 49, 52, 50, 35, 46, 34,
+ 51, 0, 46, 34, 51, 35, 0, 0, 35, 0,
+ 46, 34, 51, 46, 34, 51, 46, 34, 51, 0,
+ 0, 46, 34, 51, 46, 34, 51, 49, 52, 50,
+ 35, 0, 0, 0, 49, 52, 50, 0, 0, 0,
+ 80, 81, 49, 52, 50, 49, 52, 50, 82, 83,
+ 0, 0, 84, 35, 85, 0, 537, 46, 34, 51,
+ 186, 0, 0, 0, 46, 34, 51, 49, 52, 50,
+ 35, 0, 46, 34, 51, 46, 34, 51, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 537,
+ 49, 52, 50, 0, 0, 0, 537, 46, 34, 51,
+ 537, 0, 0, 35, 537, 0, 35, 49, 52, 50,
+ 35, 0, 0, 186, 35, 0, 0, 0, 35, 0,
+ 46, 34, 51, 0, 0, 35, 0, 0, 35, 0,
+ 0, 0, 0, 0, 0, 0, 0, 46, 34, 51,
+ 49, 52, 50, 49, 52, 50, 0, 49, 52, 50,
+ 0, 49, 52, 50, 0, 49, 52, 50, 0, 0,
+ 258, 257, 49, 52, 50, 49, 52, 50, 35, 0,
+ 46, 34, 51, 46, 34, 51, 0, 46, 34, 51,
+ 35, 46, 34, 51, 0, 46, 34, 51, 35, 0,
+ 0, 35, 46, 34, 51, 46, 34, 51, 0, 0,
+ 253, 252, 0, 0, 35, 49, 52, 50, 0, 0,
+ 0, 186, 253, 252, 0, 0, 0, 49, 52, 50,
+ 258, 257, 0, 258, 257, 49, 52, 50, 49, 52,
+ 50, 0, 0, 0, 0, 46, 34, 51, 0, 0,
+ 155, 49, 52, 50, 0, 0, 0, 46, 34, 51,
+ 156, 0, 0, 0, 157, 46, 34, 51, 46, 34,
+ 51, 0, 0, 158, 0, 159, 0, 0, 0, 0,
+ 0, 46, 34, 51, 0, 0, 160, 0, 161, 64,
+ 0, 0, 0, 35, 0, 0, 162, 0, 0, 163,
+ 65, 0, 0, 0, 0, 164, 0, 0, 0, 0,
+ 0, 165, 0, 0, 0, 0, 0, 0, 0, 155,
+ 0, 0, 0, 0, 0, 253, 252, 166, 0, 156,
+ 49, 52, 50, 157, 0, 0, 0, 0, 0, 0,
+ 0, 0, 158, 0, 159, 0, 0, 322, 0, 0,
+ 0, 0, 0, 0, 0, 160, 0, 161, 64, 0,
+ 46, 34, 51, 0, 0, 162, 0, 0, 163, 65,
+ 0, 0, 155, 0, 164, 0, 0, 0, 0, 0,
+ 165, 0, 156, 0, 0, 0, 157, 0, 0, 0,
+ 0, 0, 0, 0, 0, 158, 166, 159, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 160, 0,
+ 161, 64, 0, 0, 0, 0, 0, 0, 162, 0,
+ 0, 163, 65, 0, 0, 0, 0, 164, 0, 0,
+ 0, 0, 0, 165, 0, 30, 31, 0, 0, 0,
+ 0, 0, 0, 0, 0, 33, 0, 0, 0, 166,
+ 0, 0, 35, 0, 0, 0, 36, 37, 0, 38,
+ 0, 0, 0, 0, 0, 0, 521, 0, 0, 0,
+ 45, 0, 0, 0, 0, 0, 0, 30, 31, 0,
+ 0, 0, 0, 0, 0, 0, 0, 33, 53, 49,
+ 52, 50, 0, 54, 35, 0, 0, 0, 36, 37,
+ 0, 38, 0, 0, 44, 56, 32, 0, 42, 0,
+ 0, 41, 45, 0, 0, 0, 0, 0, 0, 46,
+ 34, 51, 0, 0, 0, 0, 0, 0, 0, 0,
+ 53, 49, 52, 50, 0, 54, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 44, 56, 32, 0,
+ 0, 0, 0, 41, 0, 0, 0, 0, 0, 0,
+ 0, 46, 34, 51, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 30, 31, 0, 0, 0, 0, 0,
+ 0, 0, 0, 33, 0, 0, 0, 0, 0, 0,
+ 35, 0, 0, 0, 36, 37, 0, 38, 0, 0,
+ 0, 0, 0, 0, 42, 0, 0, 0, 45, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 53, 49, 52, 50,
+ 0, 54, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 44, 56, 32, 0, 0, 0, 0, 41,
+ 0, 0, 0, 0, 0, 0, 0, 46, 34, 51,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 30,
+ 31, 0, 0, 0, 0, 0, 0, 0, 0, 33,
+ 0, 0, 0, 0, 0, 0, 35, 0, 0, 0,
+ 36, 37, 0, 38, 0, 0, 0, 0, 0, 0,
+ 521, 0, 0, 0, 45, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 53, 49, 52, 50, 0, 54, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 44, 56,
+ 32, 0, 0, 0, 0, 41, 0, 0, 0, 0,
+ 0, 0, 0, 46, 34, 51, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 519, 0, 30, 31, 0,
+ 0, 0, 0, 0, 0, 0, 0, 221, 0, 0,
+ 0, 0, 0, 0, 35, 0, 0, 0, 36, 37,
+ 0, 38, 0, 0, 0, 0, 0, 0, 521, 0,
+ 0, 0, 45, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 53, 522, 524, 523, 0, 54, 0, 0, 0, 0,
+ 230, 0, 0, 0, 0, 0, 44, 56, 32, 216,
+ 224, 0, 0, 41, 0, 0, 520, 0, 0, 0,
+ 0, 46, 34, 51, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 519, 0, 30, 31, 0, 0, 0,
+ 0, 0, 0, 0, 0, 221, 0, 0, 0, 0,
+ 0, 0, 35, 0, 0, 0, 36, 37, 0, 38,
+ 0, 0, 0, 0, 0, 0, 521, 0, 0, 0,
+ 45, 0, 0, 0, 0, 0, 0, 0, 585, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 53, 522,
+ 524, 523, 0, 54, 0, 0, 0, 0, 230, 0,
+ 0, 0, 0, 0, 44, 56, 32, 216, 224, 0,
+ 0, 41, 0, 0, 520, 0, 0, 0, 0, 46,
+ 34, 51, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 519, 0, 30, 31, 0, 0, 0, 0, 0,
+ 0, 0, 0, 221, 0, 0, 0, 0, 0, 0,
+ 35, 0, 0, 0, 36, 37, 0, 38, 0, 0,
+ 0, 0, 0, 0, 521, 0, 0, 0, 45, 0,
+ 0, 0, 0, 0, 0, 0, 588, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 53, 522, 524, 523,
+ 0, 54, 0, 0, 0, 0, 230, 0, 0, 0,
+ 0, 0, 44, 56, 32, 216, 224, 0, 0, 41,
+ 0, 0, 520, 0, 0, 0, 0, 46, 34, 51,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 29,
+ 30, 31, 0, 0, 0, 0, 0, 0, 0, 0,
+ 33, 0, 0, 0, 0, 0, 0, 35, 0, 0,
+ 0, 36, 37, 0, 38, 0, 0, 0, 39, 0,
+ 40, 42, 43, 0, 0, 45, 0, 0, 0, 47,
+ 0, 48, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 53, 49, 52, 50, 0, 54, 0,
+ 55, 0, 57, 0, 58, 0, 0, 0, 0, 44,
+ 56, 32, 0, 0, 0, 0, 41, 0, 0, 0,
+ 0, 0, 0, 0, 46, 34, 51, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, -141, 0, 0, 0,
+ 29, 30, 31, 0, 0, 0, 0, 0, 0, 0,
+ 0, 33, 0, 0, 0, 0, 0, 0, 35, 0,
+ 0, 0, 36, 37, 0, 38, 0, 0, 0, 39,
+ 0, 40, 42, 43, 0, 0, 45, 0, 0, 0,
+ 47, 0, 48, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 53, 49, 52, 50, 0, 54,
+ 0, 55, 0, 57, 0, 58, 0, 0, 0, 0,
+ 44, 56, 32, 0, 0, 0, 0, 41, 0, 0,
+ 0, 0, 0, 0, 0, 46, 34, 51, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 29, 30, 31,
+ 0, 0, 0, 0, 0, 0, 0, 0, 33, 0,
+ 0, 0, 0, 0, 0, 35, 0, 0, 0, 36,
+ 37, 0, 38, 0, 0, 0, 39, 0, 40, 42,
+ 43, 0, 0, 45, 0, 0, 0, 47, 0, 48,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 53, 49, 52, 50, 0, 54, 0, 55, 0,
+ 57, 285, 58, 0, 0, 0, 0, 44, 56, 32,
+ 0, 0, 0, 0, 41, 0, 0, 0, 0, 0,
+ 0, 0, 46, 34, 51, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 492, 0, 0, 29, 30, 31,
+ 0, 0, 0, 0, 0, 0, 0, 0, 33, 0,
+ 0, 0, 0, 0, 0, 35, 0, 0, 0, 36,
+ 37, 0, 38, 0, 0, 0, 39, 0, 40, 42,
+ 43, 0, 0, 45, 0, 0, 0, 47, 0, 48,
+ 0, 0, 493, 0, 0, 0, 0, 0, 0, 0,
+ 0, 53, 49, 52, 50, 0, 54, 0, 55, 0,
+ 57, 0, 58, 0, 0, 0, 0, 44, 56, 32,
+ 0, 0, 0, 0, 41, 0, 0, 0, 0, 0,
+ 0, 0, 46, 34, 51, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 500, 0, 0, 29, 30, 31,
+ 0, 0, 0, 0, 0, 0, 0, 0, 33, 0,
+ 0, 0, 0, 0, 0, 35, 0, 0, 0, 36,
+ 37, 0, 38, 0, 0, 0, 39, 0, 40, 42,
+ 43, 0, 0, 45, 0, 0, 0, 47, 0, 48,
+ 0, 0, 503, 0, 0, 0, 0, 0, 0, 0,
+ 0, 53, 49, 52, 50, 0, 54, 0, 55, 0,
+ 57, 0, 58, 0, 0, 0, 0, 44, 56, 32,
+ 0, 0, 0, 0, 41, 0, 0, 0, 0, 0,
+ 0, 0, 46, 34, 51, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 492, 0, 0, 29, 30, 31,
+ 0, 0, 0, 0, 0, 0, 0, 0, 33, 0,
+ 0, 0, 0, 0, 0, 35, 0, 0, 0, 36,
+ 37, 0, 38, 0, 0, 0, 39, 0, 40, 42,
+ 43, 0, 0, 45, 0, 0, 0, 47, 0, 48,
+ 0, 0, 498, 0, 0, 0, 0, 0, 0, 0,
+ 0, 53, 49, 52, 50, 0, 54, 0, 55, 0,
+ 57, 0, 58, 0, 0, 0, 0, 44, 56, 32,
+ 0, 0, 0, 0, 41, 0, 0, 0, 0, 0,
+ 0, 0, 46, 34, 51, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 500, 0, 0, 29, 30, 31,
+ 0, 0, 0, 0, 0, 0, 0, 0, 33, 0,
+ 0, 0, 0, 0, 0, 35, 0, 0, 0, 36,
+ 37, 0, 38, 0, 0, 0, 39, 0, 40, 42,
+ 43, 0, 0, 45, 0, 0, 0, 47, 0, 48,
+ 0, 0, 501, 0, 0, 0, 0, 0, 0, 0,
+ 0, 53, 49, 52, 50, 0, 54, 0, 55, 0,
+ 57, 0, 58, 0, 0, 0, 0, 44, 56, 32,
+ 0, 0, 0, 0, 41, 0, 0, 0, 0, 0,
+ 0, 0, 46, 34, 51, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 29, 30, 31, 0, 0, 0,
+ 0, 0, 0, 0, 0, 33, 0, 0, 0, 0,
+ 0, 0, 35, 222, 0, 0, 223, 37, 0, 38,
+ 0, 0, 0, 39, 0, 40, 42, 43, 0, 0,
+ 45, 0, 0, 0, 47, 0, 48, 0, 0, 0,
+ 0, 0, 0, 0, 226, 0, 0, 0, 53, 49,
+ 52, 50, 227, 54, 0, 55, 229, 57, 0, 58,
+ 0, 232, 0, 0, 44, 56, 32, 0, 0, 0,
+ 0, 41, 0, 0, 0, 0, 0, 0, 0, 46,
+ 34, 51, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 29, 30, 31, 0, 0, 0, 0, 0, 0,
+ 0, 0, 33, 0, 0, 0, 0, 0, 0, 35,
+ 222, 0, 0, 603, 650, 0, 38, 0, 0, 0,
+ 39, 0, 40, 42, 43, 0, 0, 45, 0, 0,
+ 0, 47, 0, 48, 0, 0, 0, 0, 0, 0,
+ 0, 226, 0, 0, 0, 53, 49, 52, 50, 227,
+ 54, 0, 55, 229, 57, 0, 58, 0, 232, 0,
+ 0, 44, 56, 32, 0, 0, 0, 0, 41, 0,
+ 0, 0, 0, 0, 0, 0, 46, 34, 51, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 29, 30,
+ 31, 0, 0, 0, 0, 0, 0, 0, 0, 33,
+ 0, 0, 0, 0, 0, 0, 35, 222, 0, 0,
+ 603, 37, 0, 38, 0, 0, 0, 39, 0, 40,
+ 42, 43, 0, 0, 45, 0, 0, 0, 47, 0,
+ 48, 0, 0, 0, 0, 0, 0, 0, 226, 0,
+ 0, 0, 53, 49, 52, 50, 227, 54, 0, 55,
+ 229, 57, 0, 58, 0, 232, 0, 0, 44, 56,
+ 32, 0, 0, 0, 0, 41, 0, 0, 0, 0,
+ 0, 0, 0, 46, 34, 51, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 111, 112, 113, 0, 0,
+ 115, 117, 118, 0, 0, 119, 0, 120, 0, 0,
+ 0, 123, 124, 125, 0, 0, 0, 0, 0, 0,
+ 35, 126, 127, 128, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 130, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 133, 0, 0, 0, 0, 0, 0, 49, 52, 50,
+ 134, 135, 136, 0, 138, 139, 140, 141, 142, 143,
+ 0, 0, 131, 137, 122, 114, 129, 116, 132, 0,
+ 0, 0, 121, 0, 0, 0, 0, 46, 34, 51,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 111,
+ 112, 113, 0, 0, 115, 117, 118, 0, 0, 119,
+ 0, 120, 0, 0, 0, 123, 124, 125, 0, 0,
+ 0, 0, 0, 0, 35, 126, 127, 128, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 130, 0,
+ 0, 0, 399, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 133, 0, 0, 0, 0, 0,
+ 401, 49, 52, 50, 134, 135, 136, 0, 138, 139,
+ 140, 141, 142, 143, 0, 0, 131, 137, 122, 114,
+ 129, 116, 132, 0, 0, 0, 121, 0, 0, 0,
+ 0, 46, 34, 51, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 111, 112, 113, 0, 0, 115, 117,
+ 118, 0, 0, 119, 0, 120, 0, 0, 0, 123,
+ 124, 125, 0, 0, 0, 0, 0, 0, 35, 126,
+ 127, 128, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 130, 0, 0, 0, 399, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 133, 0,
+ 0, 0, 0, 0, 401, 49, 52, 50, 134, 135,
+ 136, 0, 138, 139, 140, 141, 142, 143, 0, 0,
+ 131, 137, 122, 114, 129, 116, 132, 0, 0, 0,
+ 121, 0, 0, 0, 0, 46, 377, 384, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 111, 112, 113,
+ 0, 0, 115, 117, 118, 0, 0, 119, 0, 120,
+ 0, 0, 0, 123, 124, 125, 0, 0, 0, 0,
+ 0, 0, 35, 126, 127, 128, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 130, 0, 0, 0,
+ 399, 0, 0, 0, 0, 0, 0, 0, 400, 0,
+ 0, 0, 133, 0, 0, 0, 0, 0, 401, 49,
+ 52, 50, 134, 135, 136, 0, 138, 139, 140, 141,
+ 142, 143, 0, 0, 131, 137, 122, 114, 129, 116,
+ 132, 0, 0, 0, 121, 0, 0, 0, 0, 46,
+ 377, 384, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 215, 0, 0, 0, 0, 217, 0, 29, 30,
+ 31, 219, 0, 0, 0, 0, 0, 0, 220, 33,
+ 0, 0, 0, 0, 0, 0, 35, 222, 0, 0,
+ 223, 37, 0, 38, 0, 0, 0, 39, 0, 40,
+ 42, 43, 0, 0, 45, 0, 0, 0, 47, 0,
+ 48, 0, 0, 0, 0, 0, 225, 0, 226, 0,
+ 0, 0, 53, 49, 52, 50, 227, 54, 228, 55,
+ 229, 57, 230, 58, 231, 232, 0, 0, 44, 56,
+ 32, 216, 224, 218, 0, 41, 0, 0, 0, 0,
+ 0, 0, 0, 46, 34, 51, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 215, 0, 0, 0, 0,
+ 217, 0, 29, 30, 31, 219, 0, 0, 0, 0,
+ 0, 0, 220, 221, 0, 0, 0, 0, 0, 0,
+ 35, 222, 0, 0, 223, 37, 0, 38, 0, 0,
+ 0, 39, 0, 40, 42, 43, 0, 0, 45, 0,
+ 0, 0, 47, 0, 48, 0, 0, 0, 0, 0,
+ 225, 0, 226, 0, 0, 0, 53, 49, 52, 50,
+ 227, 54, 228, 55, 229, 57, 230, 58, 231, 232,
+ 0, 0, 44, 56, 32, 216, 224, 218, 0, 41,
+ 0, 0, 0, 0, 0, 0, 0, 46, 34, 51,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 607,
+ 112, 113, 0, 0, 609, 117, 611, 30, 31, 612,
+ 0, 120, 0, 0, 0, 123, 614, 615, 0, 0,
+ 0, 0, 0, 0, 35, 616, 127, 128, 223, 37,
+ 0, 38, 0, 0, 0, 39, 0, 40, 618, 43,
+ 0, 0, 620, 0, 0, 0, 47, 0, 48, 0,
+ 0, 0, 0, 0, 621, 0, 226, 0, 0, 0,
+ 622, 49, 52, 50, 623, 624, 625, 55, 627, 628,
+ 629, 630, 631, 632, 0, 0, 619, 626, 613, 608,
+ 617, 610, 132, 41, 0, 0, 121, 0, 0, 0,
+ 0, 46, 377, 384, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 368, 112, 113, 0, 0, 370, 117,
+ 372, 30, 31, 373, 0, 120, 0, 0, 0, 123,
+ 375, 376, 0, 0, 0, 0, 0, 0, 35, 378,
+ 127, 128, 223, 37, 0, 38, 0, 0, 0, 39,
+ 0, 40, 380, 43, 0, 0, 382, 0, 0, 0,
+ 47, 0, 48, 0, -288, 0, 0, 0, 383, 0,
+ 226, 0, 0, 0, 385, 49, 52, 50, 386, 387,
+ 388, 55, 390, 391, 392, 393, 394, 395, 0, 0,
+ 381, 389, 374, 369, 379, 371, 132, 41, 0, 0,
+ 121, 0, 0, 0, 0, 46, 377, 384, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0,
- 152, 652, 331, 669, 535, 531, 538, 142, 528, 148,
- 641, 16, 313, 393, 485, 500, 626, 630, 263, 638,
- 183, 625, 623, 206, 574, 447, 583, 320, 183, 253,
- 313, 248, 466, 145, 663, 653, 616, 584, 556, 640,
- 581, 248, 437, 253, 248, 495, 183, 178, 453, 150,
- 462, 347, 455, 550, 554, 183, 351, 447, 458, 190,
- 313, 457, 425, 188, 469, 441, 433, 253, 237, 468,
- 0, 313, 173, 171, 393, 409, 447, 498, 409, 464,
- 400, 0, 165, 206, 475, 206, 512, 511, 0, 0,
- 188, 0, 0, 206, 0, 206, 0, 62, 0, 459,
- 417, 206, 206, 206, 188, 0, 62, 0, 62, 62,
- 507, 504, 410, 148, 62, 410, 460, 62, 419, 505,
- 407, 412, 170, 62, 62, 459, 506, 444, 277, 148,
- 422, 331, 187, 281, 62, 62, 62, 180, 260, 295,
- 296, 297, 62, 62, 656, 655, 314, 298, 299, 62,
- 62, 503, 182, 62, 206, 362, 514, 393, 247, 62,
- 62, 460, 502, 62, 62, 639, 313, 167, 92, 99,
- 62, 206, 206, 514, 510, 345, 100, 260, 562, 62,
- 62, 62, 394, 493, 93, 94, 95, 492, 62, 62,
- 182, 206, 62, 206, 96, 62, 246, 97, 62, 90,
- 62, 401, 91, 206, 62, 86, 355, 340, 353, 62,
- 108, 247, 206, 349, 188, 313, 102, 206, 393, 104,
- 313, 62, 206, 182, 206, 206, 62, 362, 459, 206,
- 242, 62, 469, 460, 62, 514, 409, 63, 318, 110,
- 657, 341, 239, 590, 403, 62, 322, 206, 72, 62,
- 362, 62, 362, 69, 206, 98, 62, 62, 70, 71,
- 514, 0, 206, 62, 62, 566, 356, 0, 206, 79,
- 62, 108, 74, 410, 483, 281, 0, 309, 0, 0,
- 62, 62, 281, 304, 62, 281, 281, 62, 362, 281,
- 343, 0, 281, 284, 289, 316, 324, 327, 0, 311,
- 110, 177, 0, 309, 206, 62, 479, 0, 281, 62,
- 281, 309, 301, 309, 281, 0, 281, 309, 281, 62,
- 306, 0, 281, 62, 281, 337, 302, 0, 281, 578,
- 300, 514, 260, 328, 562, 308, 636, 570, 443, 330,
- 522, 0, 0, 0, 0, 0, 514, 0, 206, 0,
- 0, 0, 513, 523, 0, 522, 0, 485, 542, 543,
- 544, 545, 549, 546, 547, 0, 586, 513, 523, 0,
- 0, 0, 0, 0, 440, 588, 589, 542, 543, 544,
- 545, 549, 546, 547, 586, 0, 0, 0, 0, 0,
- 0, 0, 0, 634, 635, 542, 543, 544, 545, 549,
- 546, 547, 578, 0, 0, 0, 0, 0, 0, 0,
- 0, 579, 580, 542, 543, 544, 545, 549, 546, 547,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 573, 0, 0, 0, 0, 0, 0, 0, 0,
- 514, 0, 0, 0, 0, 0, 0, 0, 0, 522,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 513, 523, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0};
+ 543, 185, 640, 647, 642, 643, 504, 489, 397, 451,
+ 655, 657, 669, 670, 154, 680, 658, 448, 686, 316,
+ 185, 16, 256, 536, 251, 599, 570, 633, 572, 590,
+ 597, 144, 323, 540, 457, 150, 266, 473, 190, 441,
+ 350, 445, 251, 192, 256, 437, 429, 354, 208, 240,
+ 185, 316, 251, 256, 185, 404, 448, 448, 316, 533,
+ 566, 470, 466, 180, 451, 451, 462, 0, 62, 334,
+ 510, 516, 62, 0, 0, 325, 62, 299, 316, 0,
+ 459, 298, 397, 334, 0, 147, 461, 208, 499, 0,
+ 152, 208, 502, 167, 600, 479, 673, 672, 518, 173,
+ 175, 515, 316, 674, 208, 397, 316, 518, 316, 407,
+ 208, 0, 190, 0, 321, 208, 656, 352, 62, 249,
+ 464, 62, 62, 184, 509, 62, 62, 463, 463, 62,
+ 208, 508, 421, 208, 62, 208, 184, 356, 245, 358,
+ 405, 242, 263, 280, 62, 62, 62, 506, 284, 302,
+ 62, 301, 507, 208, 317, 208, 208, 62, 208, 62,
+ 343, 184, 300, 413, 348, 365, 62, 0, 62, 190,
+ 518, 62, 99, 62, 100, 578, 86, 90, 346, 62,
+ 208, 208, 319, 91, 344, 62, 62, 62, 413, 62,
+ 93, 94, 95, 473, 96, 468, 514, 62, 189, 62,
+ 150, 414, 97, 92, 208, 62, 472, 464, 182, 62,
+ 62, 208, 497, 62, 62, 397, 496, 250, 365, 62,
+ 104, 102, 208, 263, 208, 98, 414, 263, 169, 172,
+ 365, 208, 487, 62, 359, 511, 62, 250, 463, 208,
+ 62, 398, 464, 208, 62, 62, 606, 63, 72, 190,
+ 150, 208, 411, 62, 518, 69, 62, 208, 416, 582,
+ 365, 365, 79, 62, 62, 70, 62, 62, 483, 71,
+ 0, 284, 74, 0, 0, 62, 208, 208, 423, 307,
+ 284, 0, 62, 0, 287, 426, 108, 284, 0, 292,
+ 62, 62, 0, 0, 0, 284, 284, 303, 304, 62,
+ 312, 0, 62, 312, 284, 284, 305, 284, 284, 312,
+ 62, 0, 312, 309, 284, 284, 110, 284, 62, 312,
+ 0, 594, 333, 284, 284, 340, 578, 330, 653, 0,
+ 518, 331, 0, 327, 311, 586, 0, 589, 0, 527,
+ 0, 314, 0, 0, 518, 0, 518, 444, 447, 0,
+ 489, 517, 528, 527, 0, 527, 547, 548, 549, 550,
+ 554, 551, 552, 0, 0, 517, 528, 517, 528, 0,
+ 0, 0, 602, 0, 0, 0, 0, 0, 0, 0,
+ 108, 604, 605, 547, 548, 549, 550, 554, 551, 552,
+ 594, 0, 0, 0, 0, 0, 0, 0, 0, 595,
+ 596, 547, 548, 549, 550, 554, 551, 552, 0, 0,
+ 110, 179, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 602, 0, 0, 0, 0, 0,
+ 0, 0, 0, 651, 652, 547, 548, 549, 550, 554,
+ 551, 552, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0
+};
const short QQmlJSGrammar::action_check [] = {
- 7, 55, 48, 55, 55, 55, 36, 7, 36, 33,
- 55, 7, 7, 33, 37, 7, 7, 61, 60, 60,
- 36, 7, 33, 8, 36, 7, 16, 1, 36, 60,
- 7, 36, 2, 48, 7, 36, 5, 36, 36, 36,
- 79, 5, 36, 60, 33, 33, 55, 60, 7, 36,
- 34, 7, 33, 7, 7, 33, 36, 7, 7, 77,
- 36, 33, 8, 5, 1, 8, 33, 60, 29, 79,
- 36, 33, 17, 8, 37, 79, 33, 60, 33, 8,
- 1, 60, 2, 8, 7, 60, 33, 55, 48, 60,
- 29, 2, 7, 2, 7, 36, 36, 7, 17, 7,
- 33, 66, 7, 61, 48, 31, 36, 1, 36, 33,
- 8, 7, 60, 20, 36, 66, 33, 7, 36, 55,
- 36, 8, 60, 8, 15, -1, 40, 79, 8, 61,
- 61, 62, 10, 8, 61, 62, 40, 51, 8, 15,
- 40, 40, 8, 34, 8, 42, 6, 51, 24, 61,
- 62, 51, 51, 7, 8, 8, 53, 8, 61, 62,
- 20, 8, 8, 8, 8, 15, 61, 62, 61, 62,
- 8, 8, 15, 60, -1, 60, 56, 55, 61, 62,
- 61, 62, 61, 62, 34, 60, 56, 61, 62, 91,
- 92, 34, 56, 50, 60, 15, 29, 54, 0, 91,
- 92, 50, 61, 62, 24, 54, 25, 60, 27, 12,
- 61, 56, 29, 60, 60, 25, 60, 27, 56, 38,
- 25, 25, 27, 27, 61, 62, 12, 15, 38, 61,
- 62, 12, 29, 38, 38, 29, 7, -1, 25, 7,
- 27, 36, 75, 8, 29, 8, 34, -1, 36, 15,
- 25, 38, 27, 86, 57, 7, -1, 89, 75, 7,
- 63, -1, 33, 38, 15, 29, 61, 62, 34, 86,
- 36, 57, 29, -1, -1, -1, 57, 63, 75, -1,
- -1, 75, 63, 34, 15, 36, -1, 61, 62, 86,
- 75, -1, 86, 61, 62, -1, 61, 62, 61, 62,
- -1, 86, -1, 34, 25, 36, 27, 15, -1, 61,
- 62, 75, -1, 61, 62, 18, 19, 38, 75, 93,
- 15, -1, 86, 94, -1, 33, 34, -1, 36, 86,
- 18, 19, 18, 19, 18, 19, 47, -1, 33, 34,
- -1, 36, 45, 46, 98, 99, 100, 101, 102, 103,
- 61, 62, -1, -1, 23, 24, -1, 45, 46, 45,
- 46, 45, 46, 32, 23, 24, 35, -1, 37, -1,
- -1, -1, -1, 32, 23, 24, 35, -1, 37, -1,
- 23, 24, 93, 32, -1, 25, 35, 27, 37, 32,
- -1, -1, 35, 29, 37, 23, 24, -1, 38, -1,
- -1, -1, -1, 31, 32, 23, 24, 35, -1, 37,
- -1, -1, -1, 31, 32, 23, 24, 35, 29, 37,
- -1, -1, -1, 31, 32, 23, 24, 35, -1, 37,
- 66, 67, 68, 31, 32, 23, 24, 35, -1, 37,
- -1, -1, -1, 31, 32, -1, -1, 35, -1, 37,
- 29, -1, -1, 29, -1, 66, 67, 68, 94, 95,
- 96, 29, -1, -1, 29, -1, 23, 24, 29, -1,
- -1, 29, 15, -1, 29, 32, -1, -1, 35, -1,
- 37, 36, -1, 94, 95, 96, 29, 66, 67, 68,
- 66, 67, 68, -1, -1, -1, -1, -1, 66, 67,
- 68, 66, 67, 68, -1, 66, 67, 68, 66, 67,
- 68, 66, 67, 68, -1, 94, 95, 96, 94, 95,
- 96, -1, -1, 66, 67, 68, 94, 95, 96, 94,
- 95, 96, 15, 94, 95, 96, 94, 95, 96, 94,
- 95, 96, -1, 29, -1, -1, 29, -1, -1, 29,
- 36, 94, 95, 96, 29, -1, -1, 29, -1, -1,
- -1, 36, -1, -1, -1, 29, -1, -1, 29, -1,
- -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
- 66, 67, 68, 66, 67, 68, 66, 67, 68, 61,
- 62, 66, 67, 68, 66, 67, 68, 61, 62, -1,
- 61, 62, 66, 67, 68, 66, 67, 68, 94, 95,
- 96, 94, 95, 96, 94, 95, 96, 29, -1, 94,
- 95, 96, 94, 95, 96, 29, 15, -1, 29, -1,
- 94, 95, 96, 94, 95, 96, -1, -1, -1, -1,
- 29, -1, -1, -1, -1, -1, -1, -1, -1, 61,
- 62, -1, -1, -1, 66, 67, 68, 61, 62, -1,
- 61, 62, 66, 67, 68, 66, 67, 68, -1, -1,
- -1, -1, -1, -1, -1, 3, -1, 66, 67, 68,
- -1, -1, 94, 95, 96, 13, -1, -1, -1, 17,
- 94, 95, 96, 94, 95, 96, -1, -1, 26, -1,
- 28, -1, -1, 31, -1, 94, 95, 96, -1, -1,
- -1, 39, -1, 41, 42, -1, -1, 3, -1, -1,
- -1, 49, -1, -1, 52, 53, -1, 13, -1, -1,
- 58, 17, -1, -1, -1, -1, 64, -1, -1, -1,
- 26, -1, 28, -1, -1, -1, -1, -1, -1, -1,
- -1, -1, 80, 39, -1, 41, 42, -1, -1, -1,
- -1, -1, -1, 49, -1, -1, 52, 53, -1, -1,
- -1, -1, 58, -1, -1, -1, -1, -1, 64, -1,
- -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, 80, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
- 12, 13, -1, -1, -1, -1, -1, -1, -1, -1,
- 22, -1, -1, -1, -1, -1, -1, 29, -1, -1,
- -1, 33, 34, -1, 36, -1, -1, -1, -1, -1,
- -1, 43, -1, -1, -1, 47, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
- -1, -1, -1, 65, 66, 67, 68, -1, 70, -1,
- -1, -1, -1, -1, -1, -1, -1, -1, -1, 81,
- 82, 83, -1, -1, -1, 87, -1, -1, -1, -1,
- -1, -1, 94, 95, 96, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, 12, 13, -1, -1, -1, -1,
- -1, -1, -1, -1, 22, -1, -1, -1, -1, -1,
- -1, 29, -1, -1, -1, 33, 34, -1, 36, -1,
- -1, -1, -1, -1, -1, 43, -1, -1, -1, 47,
- -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1, -1, 65, 66, 67,
- 68, -1, 70, -1, -1, -1, -1, -1, -1, -1,
- -1, -1, -1, 81, 82, 83, -1, -1, -1, 87,
- -1, -1, -1, -1, -1, -1, 94, 95, 96, -1,
- -1, -1, -1, -1, -1, -1, -1, -1, 10, -1,
- 12, 13, -1, -1, -1, -1, -1, -1, -1, -1,
- 22, -1, -1, -1, -1, -1, -1, 29, -1, -1,
- -1, 33, 34, -1, 36, -1, -1, -1, -1, -1,
- -1, 43, -1, -1, -1, 47, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
- -1, -1, -1, 65, 66, 67, 68, -1, 70, -1,
- -1, -1, -1, 75, -1, -1, -1, -1, -1, 81,
- 82, 83, 84, -1, -1, 87, -1, -1, -1, -1,
- -1, -1, 94, 95, 96, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, 10, -1, 12, 13, -1, -1,
- -1, -1, -1, -1, -1, -1, 22, -1, -1, -1,
- -1, -1, -1, 29, -1, -1, -1, 33, 34, -1,
- 36, -1, -1, -1, -1, -1, -1, 43, -1, -1,
- -1, 47, -1, -1, -1, -1, -1, -1, -1, 55,
- -1, -1, -1, -1, -1, -1, -1, -1, -1, 65,
- 66, 67, 68, -1, 70, -1, -1, -1, -1, 75,
- -1, -1, -1, -1, -1, 81, 82, 83, 84, -1,
- -1, 87, -1, -1, -1, -1, -1, -1, 94, 95,
- 96, -1, -1, -1, -1, -1, -1, -1, -1, -1,
- 10, -1, 12, 13, -1, -1, -1, -1, -1, -1,
- -1, -1, 22, -1, -1, -1, -1, -1, -1, 29,
- -1, -1, -1, 33, 34, -1, 36, -1, -1, -1,
- -1, -1, -1, 43, -1, -1, -1, 47, -1, -1,
- -1, -1, -1, -1, -1, 55, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, 65, 66, 67, 68, -1,
- 70, -1, -1, -1, -1, 75, -1, -1, -1, -1,
- -1, 81, 82, 83, 84, -1, -1, 87, -1, -1,
- -1, -1, -1, -1, 94, 95, 96, -1, -1, -1,
- -1, -1, -1, -1, -1, -1, 11, 12, 13, -1,
- -1, -1, -1, -1, -1, -1, -1, 22, -1, -1,
- -1, -1, -1, -1, 29, -1, -1, -1, 33, 34,
- -1, 36, -1, -1, -1, 40, -1, 42, 43, 44,
- -1, -1, 47, -1, -1, -1, 51, -1, 53, -1,
- -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
- 65, 66, 67, 68, -1, 70, -1, 72, -1, 74,
- -1, 76, -1, -1, -1, -1, 81, 82, 83, -1,
- -1, -1, 87, -1, -1, -1, -1, -1, -1, 94,
- 95, 96, -1, -1, -1, -1, -1, -1, -1, -1,
- -1, 7, -1, -1, -1, 11, 12, 13, -1, -1,
- -1, -1, -1, -1, -1, -1, 22, -1, -1, -1,
- -1, -1, -1, 29, -1, -1, -1, 33, 34, -1,
- 36, -1, -1, -1, 40, -1, 42, 43, 44, -1,
- -1, 47, -1, -1, -1, 51, -1, 53, -1, -1,
- -1, -1, -1, -1, -1, -1, -1, -1, -1, 65,
- 66, 67, 68, -1, 70, -1, 72, -1, 74, -1,
- 76, -1, -1, -1, -1, 81, 82, 83, -1, -1,
- -1, 87, -1, -1, -1, -1, -1, -1, 94, 95,
- 96, -1, -1, -1, -1, -1, -1, -1, -1, -1,
- 11, 12, 13, -1, -1, -1, -1, -1, -1, -1,
- -1, 22, -1, -1, -1, -1, -1, -1, 29, -1,
- -1, -1, 33, 34, -1, 36, -1, -1, -1, 40,
- -1, 42, 43, 44, -1, -1, 47, -1, -1, -1,
- 51, -1, 53, -1, -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, 65, 66, 67, 68, -1, 70,
- -1, 72, -1, 74, 75, 76, -1, -1, -1, -1,
- 81, 82, 83, -1, -1, -1, 87, -1, -1, -1,
- -1, -1, -1, 94, 95, 96, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, 8, -1, -1, 11, 12,
- 13, -1, -1, -1, -1, -1, -1, -1, -1, 22,
- -1, -1, -1, -1, -1, -1, 29, -1, -1, -1,
- 33, 34, -1, 36, -1, -1, -1, 40, -1, 42,
- 43, 44, -1, -1, 47, -1, -1, -1, 51, -1,
- 53, -1, -1, 56, -1, -1, -1, -1, -1, -1,
- -1, -1, 65, 66, 67, 68, -1, 70, -1, 72,
- -1, 74, -1, 76, -1, -1, -1, -1, 81, 82,
- 83, -1, -1, -1, 87, -1, -1, -1, -1, -1,
- -1, 94, 95, 96, -1, -1, -1, -1, -1, -1,
- -1, -1, -1, 8, -1, -1, 11, 12, 13, -1,
- -1, -1, -1, -1, -1, -1, -1, 22, -1, -1,
- -1, -1, -1, -1, 29, -1, -1, -1, 33, 34,
- -1, 36, -1, -1, -1, 40, -1, 42, 43, 44,
- -1, -1, 47, -1, -1, -1, 51, -1, 53, -1,
- -1, 56, -1, -1, -1, -1, -1, -1, -1, -1,
- 65, 66, 67, 68, -1, 70, -1, 72, -1, 74,
- -1, 76, -1, -1, -1, -1, 81, 82, 83, -1,
- -1, -1, 87, -1, -1, -1, -1, -1, -1, 94,
- 95, 96, -1, -1, -1, -1, -1, -1, -1, -1,
- -1, 8, -1, -1, 11, 12, 13, -1, -1, -1,
- -1, -1, -1, -1, -1, 22, -1, -1, -1, -1,
- -1, -1, 29, -1, -1, -1, 33, 34, -1, 36,
- -1, -1, -1, 40, -1, 42, 43, 44, -1, -1,
- 47, -1, -1, -1, 51, -1, 53, -1, -1, 56,
- -1, -1, -1, -1, -1, -1, -1, -1, 65, 66,
- 67, 68, -1, 70, -1, 72, -1, 74, -1, 76,
- -1, -1, -1, -1, 81, 82, 83, -1, -1, -1,
- 87, -1, -1, -1, -1, -1, -1, 94, 95, 96,
- -1, -1, -1, -1, -1, -1, -1, -1, -1, 8,
- -1, -1, 11, 12, 13, -1, -1, -1, -1, -1,
- -1, -1, -1, 22, -1, -1, -1, -1, -1, -1,
- 29, -1, -1, -1, 33, 34, -1, 36, -1, -1,
- -1, 40, -1, 42, 43, 44, -1, -1, 47, -1,
- -1, -1, 51, -1, 53, -1, -1, 56, -1, -1,
- -1, -1, -1, -1, -1, -1, 65, 66, 67, 68,
- -1, 70, -1, 72, -1, 74, -1, 76, -1, -1,
- -1, -1, 81, 82, 83, -1, -1, -1, 87, -1,
- -1, -1, -1, -1, -1, 94, 95, 96, -1, -1,
- -1, -1, -1, -1, -1, -1, -1, 11, 12, 13,
- -1, -1, -1, -1, -1, -1, -1, -1, 22, -1,
- -1, -1, -1, -1, -1, 29, 30, -1, -1, 33,
- 34, -1, 36, -1, -1, -1, 40, -1, 42, 43,
- 44, -1, -1, 47, -1, -1, -1, 51, -1, 53,
- -1, -1, -1, -1, -1, -1, -1, 61, -1, -1,
- -1, 65, 66, 67, 68, 69, 70, -1, 72, 73,
- 74, -1, 76, -1, 78, -1, -1, 81, 82, 83,
- -1, -1, -1, 87, -1, -1, -1, -1, -1, -1,
- 94, 95, 96, -1, -1, -1, -1, -1, -1, -1,
- -1, -1, 11, 12, 13, -1, -1, -1, -1, -1,
- -1, -1, -1, 22, -1, -1, -1, -1, -1, -1,
- 29, 30, -1, -1, 33, 34, -1, 36, -1, -1,
- -1, 40, -1, 42, 43, 44, -1, -1, 47, -1,
- -1, -1, 51, -1, 53, -1, -1, -1, -1, -1,
- -1, -1, 61, -1, -1, -1, 65, 66, 67, 68,
- 69, 70, -1, 72, 73, 74, -1, 76, -1, 78,
- -1, -1, 81, 82, 83, -1, -1, -1, 87, -1,
- -1, -1, -1, -1, -1, 94, 95, 96, -1, -1,
- -1, -1, -1, -1, -1, -1, -1, 11, 12, 13,
- -1, -1, -1, -1, -1, -1, -1, -1, 22, -1,
- -1, -1, -1, -1, -1, 29, 30, -1, -1, 33,
- 34, -1, 36, -1, -1, -1, 40, -1, 42, 43,
- 44, -1, -1, 47, -1, -1, -1, 51, -1, 53,
- -1, -1, -1, -1, -1, -1, -1, 61, -1, -1,
- -1, 65, 66, 67, 68, 69, 70, -1, 72, 73,
- 74, -1, 76, -1, 78, -1, -1, 81, 82, 83,
- -1, -1, -1, 87, -1, -1, -1, -1, -1, -1,
- 94, 95, 96, -1, -1, -1, -1, -1, -1, -1,
- -1, -1, 4, 5, 6, -1, -1, 9, 10, 11,
- -1, -1, 14, -1, 16, -1, -1, -1, 20, 21,
- 22, -1, -1, -1, -1, -1, -1, 29, 30, 31,
- 32, -1, -1, -1, -1, -1, -1, -1, -1, -1,
- -1, 43, -1, -1, -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1, -1, 59, -1, -1,
- -1, -1, -1, -1, 66, 67, 68, 69, 70, 71,
- -1, 73, 74, 75, 76, 77, 78, -1, -1, 81,
- 82, 83, 84, 85, 86, -1, -1, -1, -1, -1,
- -1, -1, 94, 95, 96, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, 4, 5, 6, -1, -1, 9,
- 10, 11, -1, -1, 14, -1, 16, -1, -1, -1,
- 20, 21, 22, -1, -1, -1, -1, -1, -1, 29,
- 30, 31, 32, -1, -1, -1, -1, -1, -1, -1,
- -1, -1, -1, 43, -1, -1, -1, 47, -1, -1,
- -1, -1, -1, -1, -1, -1, -1, -1, -1, 59,
- -1, -1, -1, -1, -1, 65, 66, 67, 68, 69,
- 70, 71, -1, 73, 74, 75, 76, 77, 78, -1,
- -1, 81, 82, 83, 84, 85, 86, -1, -1, -1,
- -1, -1, -1, -1, 94, 95, 96, -1, -1, -1,
- -1, -1, -1, -1, -1, -1, 4, 5, 6, -1,
- -1, 9, 10, 11, -1, -1, 14, -1, 16, -1,
- -1, -1, 20, 21, 22, -1, -1, -1, -1, -1,
- -1, 29, 30, 31, 32, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, 43, -1, -1, -1, 47,
- -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
- -1, 59, -1, -1, -1, -1, -1, 65, 66, 67,
- 68, 69, 70, 71, -1, 73, 74, 75, 76, 77,
- 78, -1, -1, 81, 82, 83, 84, 85, 86, -1,
- -1, -1, -1, -1, -1, -1, 94, 95, 96, -1,
- -1, -1, -1, -1, -1, -1, -1, -1, 4, 5,
- 6, -1, -1, 9, 10, 11, -1, -1, 14, -1,
- 16, -1, -1, -1, 20, 21, 22, -1, -1, -1,
- -1, -1, -1, 29, 30, 31, 32, -1, -1, -1,
- -1, -1, -1, -1, -1, -1, -1, 43, -1, -1,
- -1, 47, -1, -1, -1, -1, -1, -1, -1, 55,
- -1, -1, -1, 59, -1, -1, -1, -1, -1, 65,
- 66, 67, 68, 69, 70, 71, -1, 73, 74, 75,
- 76, 77, 78, -1, -1, 81, 82, 83, 84, 85,
- 86, -1, -1, -1, -1, -1, -1, -1, 94, 95,
- 96, -1, -1, -1, -1, -1, -1, -1, -1, -1,
- 4, -1, -1, -1, -1, 9, -1, 11, 12, 13,
- 14, -1, -1, -1, -1, -1, -1, 21, 22, -1,
- -1, -1, -1, -1, -1, 29, 30, -1, -1, 33,
- 34, -1, 36, -1, -1, -1, 40, -1, 42, 43,
- 44, -1, -1, 47, -1, -1, -1, 51, -1, 53,
- -1, -1, -1, -1, -1, 59, -1, 61, -1, -1,
- -1, 65, 66, 67, 68, 69, 70, 71, 72, 73,
- 74, 75, 76, 77, 78, -1, -1, 81, 82, 83,
- 84, 85, -1, 87, -1, -1, -1, -1, -1, -1,
- 94, 95, 96, -1, -1, -1, -1, -1, -1, -1,
- -1, -1, 4, -1, -1, -1, -1, 9, -1, 11,
- 12, 13, 14, -1, -1, -1, -1, -1, -1, 21,
- 22, -1, -1, -1, -1, -1, -1, 29, 30, -1,
- -1, 33, 34, -1, 36, -1, -1, -1, 40, -1,
- 42, 43, 44, -1, -1, 47, -1, -1, -1, 51,
- -1, 53, -1, -1, -1, -1, -1, 59, -1, 61,
- -1, -1, -1, 65, 66, 67, 68, 69, 70, 71,
- 72, 73, 74, 75, 76, 77, 78, -1, -1, 81,
- 82, 83, 84, 85, -1, 87, -1, -1, -1, -1,
- -1, -1, 94, 95, 96, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, 4, 5, 6, -1, -1, 9,
- 10, 11, 12, 13, 14, -1, 16, -1, -1, -1,
- 20, 21, 22, -1, -1, -1, -1, -1, -1, 29,
- 30, 31, 32, 33, 34, -1, 36, -1, -1, -1,
- 40, -1, 42, 43, 44, -1, -1, 47, -1, -1,
- -1, 51, -1, 53, -1, -1, -1, -1, -1, 59,
- -1, 61, -1, -1, -1, 65, 66, 67, 68, 69,
- 70, 71, 72, 73, 74, 75, 76, 77, 78, -1,
- -1, 81, 82, 83, 84, 85, 86, 87, -1, -1,
- -1, -1, -1, -1, 94, 95, 96, -1, -1, -1,
- -1, -1, -1, -1, -1, -1, 4, 5, 6, -1,
- -1, 9, 10, 11, 12, 13, 14, -1, 16, -1,
- -1, -1, 20, 21, 22, -1, -1, -1, -1, -1,
- -1, 29, 30, 31, 32, 33, 34, -1, 36, -1,
- -1, -1, 40, -1, 42, 43, 44, -1, -1, 47,
- -1, -1, -1, 51, -1, 53, -1, 55, -1, -1,
- -1, 59, -1, 61, -1, -1, -1, 65, 66, 67,
- 68, 69, 70, 71, 72, 73, 74, 75, 76, 77,
- 78, -1, -1, 81, 82, 83, 84, 85, 86, 87,
- -1, -1, -1, -1, -1, -1, 94, 95, 96, -1,
- -1, -1, -1, -1, -1, -1, -1, -1,
+ 7, 33, 60, 60, 7, 36, 7, 7, 60, 7,
+ 36, 36, 7, 7, 60, 36, 55, 7, 33, 55,
+ 33, 7, 36, 7, 36, 36, 7, 37, 36, 7,
+ 36, 7, 7, 7, 33, 7, 33, 33, 47, 66,
+ 17, 34, 47, 66, 29, 37, 29, 29, 17, 29,
+ 29, 17, 5, 5, 5, 20, 60, 7, 60, 8,
+ 33, 7, 33, 33, 55, 33, 55, 7, 55, 36,
+ 33, 33, 60, 33, 7, 36, 33, 36, 36, 33,
+ 8, 7, 2, 7, 1, 8, 1, 8, 1, 36,
+ 8, 2, 8, -1, 2, -1, 60, -1, 33, 55,
+ 55, 7, 36, 1, 48, 0, 7, 36, 2, 36,
+ 48, 36, 60, 17, 33, 60, 48, 16, 8, 55,
+ 61, 60, 36, 7, 36, 8, 36, 36, 8, 60,
+ 8, 8, 6, 8, 15, -1, 79, 79, 8, 61,
+ 77, 48, 15, 7, 8, 8, 20, 15, 15, 79,
+ -1, 24, 8, 34, 8, 8, -1, -1, 61, 61,
+ 62, 61, 62, 8, 61, 62, 34, 34, 50, 61,
+ 62, 50, 54, 8, 79, 54, 8, 60, 56, 10,
+ 60, 56, 40, 60, 8, 61, 62, 8, 40, 12,
+ 60, 7, 55, 51, 40, 61, 62, 93, 94, 51,
+ 61, 62, 31, 7, 60, 51, 60, 60, 93, 94,
+ 15, 56, 61, 62, 61, 62, 42, 61, 62, 24,
+ 15, 56, 61, 62, 55, 61, 62, 53, 60, 33,
+ 29, 29, 7, 12, 57, 56, 25, 61, 27, 34,
+ 63, 36, 25, 7, 27, 61, 62, 29, 25, 38,
+ 27, 25, 25, 27, 27, 38, 25, 29, 27, 95,
+ -1, 38, 29, -1, 38, 38, 29, -1, 12, 38,
+ 36, 29, 25, -1, 27, -1, 75, 75, 57, 40,
+ 15, 8, -1, 8, 63, 38, 61, 62, 87, 87,
+ 51, -1, 96, 75, -1, 61, 62, 61, 62, 34,
+ -1, 36, 15, 75, 8, 87, -1, -1, 75, 25,
+ -1, 27, 75, 57, 25, 87, 27, 75, -1, 63,
+ 87, 34, 38, 36, 87, 61, 62, 38, 25, 87,
+ 27, 25, -1, 27, 61, 62, 61, 62, 25, -1,
+ 27, 38, 15, 25, 38, 27, 15, 15, 18, 19,
+ -1, 38, 18, 19, 90, 47, 38, 61, 62, -1,
+ 33, 34, -1, 36, 33, 34, 34, 36, 36, 61,
+ 62, -1, 23, 24, -1, 45, 46, -1, -1, 45,
+ 46, 32, 23, 24, 35, -1, 37, -1, 23, 24,
+ -1, 32, 23, 24, 35, -1, 37, 32, 23, 24,
+ 35, 32, 37, 95, 35, -1, 37, 32, 23, 24,
+ 35, -1, 37, -1, -1, -1, 31, 32, 23, 24,
+ 35, 29, 37, -1, -1, 29, 31, 32, -1, -1,
+ 35, -1, 37, 29, 23, 24, 29, -1, -1, 29,
+ 18, 19, 31, 32, 29, -1, 35, 29, 37, -1,
+ 100, 101, 102, 103, 104, 105, -1, -1, 66, 67,
+ 68, -1, 66, 67, 68, -1, -1, 45, 46, -1,
+ 66, 67, 68, 66, 67, 68, 66, 67, 68, -1,
+ 29, 66, 67, 68, 66, 67, 68, 29, 96, 97,
+ 98, -1, 96, 97, 98, 29, -1, -1, 29, -1,
+ 96, 97, 98, 96, 97, 98, 96, 97, 98, -1,
+ -1, 96, 97, 98, 96, 97, 98, 66, 67, 68,
+ 29, -1, -1, -1, 66, 67, 68, -1, -1, -1,
+ 23, 24, 66, 67, 68, 66, 67, 68, 31, 32,
+ -1, -1, 35, 29, 37, -1, 15, 96, 97, 98,
+ 36, -1, -1, -1, 96, 97, 98, 66, 67, 68,
+ 29, -1, 96, 97, 98, 96, 97, 98, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, 15,
+ 66, 67, 68, -1, -1, -1, 15, 96, 97, 98,
+ 15, -1, -1, 29, 15, -1, 29, 66, 67, 68,
+ 29, -1, -1, 36, 29, -1, -1, -1, 29, -1,
+ 96, 97, 98, -1, -1, 29, -1, -1, 29, -1,
+ -1, -1, -1, -1, -1, -1, -1, 96, 97, 98,
+ 66, 67, 68, 66, 67, 68, -1, 66, 67, 68,
+ -1, 66, 67, 68, -1, 66, 67, 68, -1, -1,
+ 61, 62, 66, 67, 68, 66, 67, 68, 29, -1,
+ 96, 97, 98, 96, 97, 98, -1, 96, 97, 98,
+ 29, 96, 97, 98, -1, 96, 97, 98, 29, -1,
+ -1, 29, 96, 97, 98, 96, 97, 98, -1, -1,
+ 61, 62, -1, -1, 29, 66, 67, 68, -1, -1,
+ -1, 36, 61, 62, -1, -1, -1, 66, 67, 68,
+ 61, 62, -1, 61, 62, 66, 67, 68, 66, 67,
+ 68, -1, -1, -1, -1, 96, 97, 98, -1, -1,
+ 3, 66, 67, 68, -1, -1, -1, 96, 97, 98,
+ 13, -1, -1, -1, 17, 96, 97, 98, 96, 97,
+ 98, -1, -1, 26, -1, 28, -1, -1, -1, -1,
+ -1, 96, 97, 98, -1, -1, 39, -1, 41, 42,
+ -1, -1, -1, 29, -1, -1, 49, -1, -1, 52,
+ 53, -1, -1, -1, -1, 58, -1, -1, -1, -1,
+ -1, 64, -1, -1, -1, -1, -1, -1, -1, 3,
+ -1, -1, -1, -1, -1, 61, 62, 80, -1, 13,
+ 66, 67, 68, 17, -1, -1, -1, -1, -1, -1,
+ -1, -1, 26, -1, 28, -1, -1, 31, -1, -1,
+ -1, -1, -1, -1, -1, 39, -1, 41, 42, -1,
+ 96, 97, 98, -1, -1, 49, -1, -1, 52, 53,
+ -1, -1, 3, -1, 58, -1, -1, -1, -1, -1,
+ 64, -1, 13, -1, -1, -1, 17, -1, -1, -1,
+ -1, -1, -1, -1, -1, 26, 80, 28, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, 39, -1,
+ 41, 42, -1, -1, -1, -1, -1, -1, 49, -1,
+ -1, 52, 53, -1, -1, -1, -1, 58, -1, -1,
+ -1, -1, -1, 64, -1, 12, 13, -1, -1, -1,
+ -1, -1, -1, -1, -1, 22, -1, -1, -1, 80,
+ -1, -1, 29, -1, -1, -1, 33, 34, -1, 36,
+ -1, -1, -1, -1, -1, -1, 43, -1, -1, -1,
+ 47, -1, -1, -1, -1, -1, -1, 12, 13, -1,
+ -1, -1, -1, -1, -1, -1, -1, 22, 65, 66,
+ 67, 68, -1, 70, 29, -1, -1, -1, 33, 34,
+ -1, 36, -1, -1, 81, 82, 83, -1, 43, -1,
+ -1, 88, 47, -1, -1, -1, -1, -1, -1, 96,
+ 97, 98, -1, -1, -1, -1, -1, -1, -1, -1,
+ 65, 66, 67, 68, -1, 70, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, 81, 82, 83, -1,
+ -1, -1, -1, 88, -1, -1, -1, -1, -1, -1,
+ -1, 96, 97, 98, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, 12, 13, -1, -1, -1, -1, -1,
+ -1, -1, -1, 22, -1, -1, -1, -1, -1, -1,
+ 29, -1, -1, -1, 33, 34, -1, 36, -1, -1,
+ -1, -1, -1, -1, 43, -1, -1, -1, 47, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, 65, 66, 67, 68,
+ -1, 70, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, 81, 82, 83, -1, -1, -1, -1, 88,
+ -1, -1, -1, -1, -1, -1, -1, 96, 97, 98,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, 12,
+ 13, -1, -1, -1, -1, -1, -1, -1, -1, 22,
+ -1, -1, -1, -1, -1, -1, 29, -1, -1, -1,
+ 33, 34, -1, 36, -1, -1, -1, -1, -1, -1,
+ 43, -1, -1, -1, 47, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, 65, 66, 67, 68, -1, 70, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, 81, 82,
+ 83, -1, -1, -1, -1, 88, -1, -1, -1, -1,
+ -1, -1, -1, 96, 97, 98, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, 10, -1, 12, 13, -1,
+ -1, -1, -1, -1, -1, -1, -1, 22, -1, -1,
+ -1, -1, -1, -1, 29, -1, -1, -1, 33, 34,
+ -1, 36, -1, -1, -1, -1, -1, -1, 43, -1,
+ -1, -1, 47, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ 65, 66, 67, 68, -1, 70, -1, -1, -1, -1,
+ 75, -1, -1, -1, -1, -1, 81, 82, 83, 84,
+ 85, -1, -1, 88, -1, -1, 91, -1, -1, -1,
+ -1, 96, 97, 98, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, 10, -1, 12, 13, -1, -1, -1,
+ -1, -1, -1, -1, -1, 22, -1, -1, -1, -1,
+ -1, -1, 29, -1, -1, -1, 33, 34, -1, 36,
+ -1, -1, -1, -1, -1, -1, 43, -1, -1, -1,
+ 47, -1, -1, -1, -1, -1, -1, -1, 55, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, 65, 66,
+ 67, 68, -1, 70, -1, -1, -1, -1, 75, -1,
+ -1, -1, -1, -1, 81, 82, 83, 84, 85, -1,
+ -1, 88, -1, -1, 91, -1, -1, -1, -1, 96,
+ 97, 98, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, 10, -1, 12, 13, -1, -1, -1, -1, -1,
+ -1, -1, -1, 22, -1, -1, -1, -1, -1, -1,
+ 29, -1, -1, -1, 33, 34, -1, 36, -1, -1,
+ -1, -1, -1, -1, 43, -1, -1, -1, 47, -1,
+ -1, -1, -1, -1, -1, -1, 55, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, 65, 66, 67, 68,
+ -1, 70, -1, -1, -1, -1, 75, -1, -1, -1,
+ -1, -1, 81, 82, 83, 84, 85, -1, -1, 88,
+ -1, -1, 91, -1, -1, -1, -1, 96, 97, 98,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, 11,
+ 12, 13, -1, -1, -1, -1, -1, -1, -1, -1,
+ 22, -1, -1, -1, -1, -1, -1, 29, -1, -1,
+ -1, 33, 34, -1, 36, -1, -1, -1, 40, -1,
+ 42, 43, 44, -1, -1, 47, -1, -1, -1, 51,
+ -1, 53, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, 65, 66, 67, 68, -1, 70, -1,
+ 72, -1, 74, -1, 76, -1, -1, -1, -1, 81,
+ 82, 83, -1, -1, -1, -1, 88, -1, -1, -1,
+ -1, -1, -1, -1, 96, 97, 98, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, 7, -1, -1, -1,
+ 11, 12, 13, -1, -1, -1, -1, -1, -1, -1,
+ -1, 22, -1, -1, -1, -1, -1, -1, 29, -1,
+ -1, -1, 33, 34, -1, 36, -1, -1, -1, 40,
+ -1, 42, 43, 44, -1, -1, 47, -1, -1, -1,
+ 51, -1, 53, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, 65, 66, 67, 68, -1, 70,
+ -1, 72, -1, 74, -1, 76, -1, -1, -1, -1,
+ 81, 82, 83, -1, -1, -1, -1, 88, -1, -1,
+ -1, -1, -1, -1, -1, 96, 97, 98, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, 11, 12, 13,
+ -1, -1, -1, -1, -1, -1, -1, -1, 22, -1,
+ -1, -1, -1, -1, -1, 29, -1, -1, -1, 33,
+ 34, -1, 36, -1, -1, -1, 40, -1, 42, 43,
+ 44, -1, -1, 47, -1, -1, -1, 51, -1, 53,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, 65, 66, 67, 68, -1, 70, -1, 72, -1,
+ 74, 75, 76, -1, -1, -1, -1, 81, 82, 83,
+ -1, -1, -1, -1, 88, -1, -1, -1, -1, -1,
+ -1, -1, 96, 97, 98, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, 8, -1, -1, 11, 12, 13,
+ -1, -1, -1, -1, -1, -1, -1, -1, 22, -1,
+ -1, -1, -1, -1, -1, 29, -1, -1, -1, 33,
+ 34, -1, 36, -1, -1, -1, 40, -1, 42, 43,
+ 44, -1, -1, 47, -1, -1, -1, 51, -1, 53,
+ -1, -1, 56, -1, -1, -1, -1, -1, -1, -1,
+ -1, 65, 66, 67, 68, -1, 70, -1, 72, -1,
+ 74, -1, 76, -1, -1, -1, -1, 81, 82, 83,
+ -1, -1, -1, -1, 88, -1, -1, -1, -1, -1,
+ -1, -1, 96, 97, 98, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, 8, -1, -1, 11, 12, 13,
+ -1, -1, -1, -1, -1, -1, -1, -1, 22, -1,
+ -1, -1, -1, -1, -1, 29, -1, -1, -1, 33,
+ 34, -1, 36, -1, -1, -1, 40, -1, 42, 43,
+ 44, -1, -1, 47, -1, -1, -1, 51, -1, 53,
+ -1, -1, 56, -1, -1, -1, -1, -1, -1, -1,
+ -1, 65, 66, 67, 68, -1, 70, -1, 72, -1,
+ 74, -1, 76, -1, -1, -1, -1, 81, 82, 83,
+ -1, -1, -1, -1, 88, -1, -1, -1, -1, -1,
+ -1, -1, 96, 97, 98, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, 8, -1, -1, 11, 12, 13,
+ -1, -1, -1, -1, -1, -1, -1, -1, 22, -1,
+ -1, -1, -1, -1, -1, 29, -1, -1, -1, 33,
+ 34, -1, 36, -1, -1, -1, 40, -1, 42, 43,
+ 44, -1, -1, 47, -1, -1, -1, 51, -1, 53,
+ -1, -1, 56, -1, -1, -1, -1, -1, -1, -1,
+ -1, 65, 66, 67, 68, -1, 70, -1, 72, -1,
+ 74, -1, 76, -1, -1, -1, -1, 81, 82, 83,
+ -1, -1, -1, -1, 88, -1, -1, -1, -1, -1,
+ -1, -1, 96, 97, 98, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, 8, -1, -1, 11, 12, 13,
+ -1, -1, -1, -1, -1, -1, -1, -1, 22, -1,
+ -1, -1, -1, -1, -1, 29, -1, -1, -1, 33,
+ 34, -1, 36, -1, -1, -1, 40, -1, 42, 43,
+ 44, -1, -1, 47, -1, -1, -1, 51, -1, 53,
+ -1, -1, 56, -1, -1, -1, -1, -1, -1, -1,
+ -1, 65, 66, 67, 68, -1, 70, -1, 72, -1,
+ 74, -1, 76, -1, -1, -1, -1, 81, 82, 83,
+ -1, -1, -1, -1, 88, -1, -1, -1, -1, -1,
+ -1, -1, 96, 97, 98, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, 11, 12, 13, -1, -1, -1,
+ -1, -1, -1, -1, -1, 22, -1, -1, -1, -1,
+ -1, -1, 29, 30, -1, -1, 33, 34, -1, 36,
+ -1, -1, -1, 40, -1, 42, 43, 44, -1, -1,
+ 47, -1, -1, -1, 51, -1, 53, -1, -1, -1,
+ -1, -1, -1, -1, 61, -1, -1, -1, 65, 66,
+ 67, 68, 69, 70, -1, 72, 73, 74, -1, 76,
+ -1, 78, -1, -1, 81, 82, 83, -1, -1, -1,
+ -1, 88, -1, -1, -1, -1, -1, -1, -1, 96,
+ 97, 98, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, 11, 12, 13, -1, -1, -1, -1, -1, -1,
+ -1, -1, 22, -1, -1, -1, -1, -1, -1, 29,
+ 30, -1, -1, 33, 34, -1, 36, -1, -1, -1,
+ 40, -1, 42, 43, 44, -1, -1, 47, -1, -1,
+ -1, 51, -1, 53, -1, -1, -1, -1, -1, -1,
+ -1, 61, -1, -1, -1, 65, 66, 67, 68, 69,
+ 70, -1, 72, 73, 74, -1, 76, -1, 78, -1,
+ -1, 81, 82, 83, -1, -1, -1, -1, 88, -1,
+ -1, -1, -1, -1, -1, -1, 96, 97, 98, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, 11, 12,
+ 13, -1, -1, -1, -1, -1, -1, -1, -1, 22,
+ -1, -1, -1, -1, -1, -1, 29, 30, -1, -1,
+ 33, 34, -1, 36, -1, -1, -1, 40, -1, 42,
+ 43, 44, -1, -1, 47, -1, -1, -1, 51, -1,
+ 53, -1, -1, -1, -1, -1, -1, -1, 61, -1,
+ -1, -1, 65, 66, 67, 68, 69, 70, -1, 72,
+ 73, 74, -1, 76, -1, 78, -1, -1, 81, 82,
+ 83, -1, -1, -1, -1, 88, -1, -1, -1, -1,
+ -1, -1, -1, 96, 97, 98, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, 4, 5, 6, -1, -1,
+ 9, 10, 11, -1, -1, 14, -1, 16, -1, -1,
+ -1, 20, 21, 22, -1, -1, -1, -1, -1, -1,
+ 29, 30, 31, 32, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, 43, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ 59, -1, -1, -1, -1, -1, -1, 66, 67, 68,
+ 69, 70, 71, -1, 73, 74, 75, 76, 77, 78,
+ -1, -1, 81, 82, 83, 84, 85, 86, 87, -1,
+ -1, -1, 91, -1, -1, -1, -1, 96, 97, 98,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, 4,
+ 5, 6, -1, -1, 9, 10, 11, -1, -1, 14,
+ -1, 16, -1, -1, -1, 20, 21, 22, -1, -1,
+ -1, -1, -1, -1, 29, 30, 31, 32, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, 43, -1,
+ -1, -1, 47, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, 59, -1, -1, -1, -1, -1,
+ 65, 66, 67, 68, 69, 70, 71, -1, 73, 74,
+ 75, 76, 77, 78, -1, -1, 81, 82, 83, 84,
+ 85, 86, 87, -1, -1, -1, 91, -1, -1, -1,
+ -1, 96, 97, 98, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, 4, 5, 6, -1, -1, 9, 10,
+ 11, -1, -1, 14, -1, 16, -1, -1, -1, 20,
+ 21, 22, -1, -1, -1, -1, -1, -1, 29, 30,
+ 31, 32, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, 43, -1, -1, -1, 47, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, 59, -1,
+ -1, -1, -1, -1, 65, 66, 67, 68, 69, 70,
+ 71, -1, 73, 74, 75, 76, 77, 78, -1, -1,
+ 81, 82, 83, 84, 85, 86, 87, -1, -1, -1,
+ 91, -1, -1, -1, -1, 96, 97, 98, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, 4, 5, 6,
+ -1, -1, 9, 10, 11, -1, -1, 14, -1, 16,
+ -1, -1, -1, 20, 21, 22, -1, -1, -1, -1,
+ -1, -1, 29, 30, 31, 32, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, 43, -1, -1, -1,
+ 47, -1, -1, -1, -1, -1, -1, -1, 55, -1,
+ -1, -1, 59, -1, -1, -1, -1, -1, 65, 66,
+ 67, 68, 69, 70, 71, -1, 73, 74, 75, 76,
+ 77, 78, -1, -1, 81, 82, 83, 84, 85, 86,
+ 87, -1, -1, -1, 91, -1, -1, -1, -1, 96,
+ 97, 98, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, 4, -1, -1, -1, -1, 9, -1, 11, 12,
+ 13, 14, -1, -1, -1, -1, -1, -1, 21, 22,
+ -1, -1, -1, -1, -1, -1, 29, 30, -1, -1,
+ 33, 34, -1, 36, -1, -1, -1, 40, -1, 42,
+ 43, 44, -1, -1, 47, -1, -1, -1, 51, -1,
+ 53, -1, -1, -1, -1, -1, 59, -1, 61, -1,
+ -1, -1, 65, 66, 67, 68, 69, 70, 71, 72,
+ 73, 74, 75, 76, 77, 78, -1, -1, 81, 82,
+ 83, 84, 85, 86, -1, 88, -1, -1, -1, -1,
+ -1, -1, -1, 96, 97, 98, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, 4, -1, -1, -1, -1,
+ 9, -1, 11, 12, 13, 14, -1, -1, -1, -1,
+ -1, -1, 21, 22, -1, -1, -1, -1, -1, -1,
+ 29, 30, -1, -1, 33, 34, -1, 36, -1, -1,
+ -1, 40, -1, 42, 43, 44, -1, -1, 47, -1,
+ -1, -1, 51, -1, 53, -1, -1, -1, -1, -1,
+ 59, -1, 61, -1, -1, -1, 65, 66, 67, 68,
+ 69, 70, 71, 72, 73, 74, 75, 76, 77, 78,
+ -1, -1, 81, 82, 83, 84, 85, 86, -1, 88,
+ -1, -1, -1, -1, -1, -1, -1, 96, 97, 98,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, 4,
+ 5, 6, -1, -1, 9, 10, 11, 12, 13, 14,
+ -1, 16, -1, -1, -1, 20, 21, 22, -1, -1,
+ -1, -1, -1, -1, 29, 30, 31, 32, 33, 34,
+ -1, 36, -1, -1, -1, 40, -1, 42, 43, 44,
+ -1, -1, 47, -1, -1, -1, 51, -1, 53, -1,
+ -1, -1, -1, -1, 59, -1, 61, -1, -1, -1,
+ 65, 66, 67, 68, 69, 70, 71, 72, 73, 74,
+ 75, 76, 77, 78, -1, -1, 81, 82, 83, 84,
+ 85, 86, 87, 88, -1, -1, 91, -1, -1, -1,
+ -1, 96, 97, 98, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, 4, 5, 6, -1, -1, 9, 10,
+ 11, 12, 13, 14, -1, 16, -1, -1, -1, 20,
+ 21, 22, -1, -1, -1, -1, -1, -1, 29, 30,
+ 31, 32, 33, 34, -1, 36, -1, -1, -1, 40,
+ -1, 42, 43, 44, -1, -1, 47, -1, -1, -1,
+ 51, -1, 53, -1, 55, -1, -1, -1, 59, -1,
+ 61, -1, -1, -1, 65, 66, 67, 68, 69, 70,
+ 71, 72, 73, 74, 75, 76, 77, 78, -1, -1,
+ 81, 82, 83, 84, 85, 86, 87, 88, -1, -1,
+ 91, -1, -1, -1, -1, 96, 97, 98, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1,
- 77, 14, 18, 18, 18, 32, 18, 3, 32, 42,
- 9, 3, 3, 18, 42, 3, 18, 18, 3, 22,
- 18, 32, 32, 18, 18, 25, 32, 3, 18, 18,
- 3, 18, 3, 42, 18, 14, 22, 18, 18, 22,
- 22, 18, 100, 18, 18, 42, 18, 3, 105, 42,
- 3, 3, 18, 14, 32, 18, 3, 25, 25, 18,
- 3, 25, 3, 18, 18, 3, 103, 18, 18, 2,
- -1, 3, 42, 42, 18, 14, 25, 42, 14, 2,
- 42, -1, 42, 18, 42, 18, 2, 4, -1, -1,
- 18, -1, -1, 18, -1, 18, -1, 54, -1, 56,
- 44, 18, 18, 18, 18, -1, 54, -1, 54, 54,
- 56, 56, 51, 42, 54, 51, 56, 54, 46, 56,
- 45, 50, 70, 54, 54, 56, 56, 3, 54, 42,
- 45, 18, 46, 59, 54, 54, 54, 50, 2, 59,
- 59, 59, 54, 54, 11, 12, 78, 59, 59, 54,
- 54, 56, 56, 54, 18, 2, 14, 18, 4, 54,
- 54, 56, 56, 54, 54, 23, 3, 68, 58, 60,
- 54, 18, 18, 14, 109, 2, 60, 2, 19, 54,
- 54, 54, 43, 38, 59, 59, 59, 42, 54, 54,
- 56, 18, 54, 18, 59, 54, 2, 59, 54, 58,
- 54, 2, 58, 18, 54, 59, 2, 94, 2, 54,
- 18, 4, 18, 2, 18, 3, 66, 18, 18, 64,
- 3, 54, 18, 56, 18, 18, 54, 2, 56, 18,
- 45, 54, 18, 56, 54, 14, 14, 57, 2, 47,
- 19, 78, 46, 18, 44, 54, 2, 18, 57, 54,
- 2, 54, 2, 56, 18, 60, 54, 54, 56, 56,
- 14, -1, 18, 54, 54, 19, 18, -1, 18, 60,
- 54, 18, 62, 51, 45, 59, -1, 54, -1, -1,
- 54, 54, 59, 67, 54, 59, 59, 54, 2, 59,
- 78, -1, 59, 63, 61, 78, 69, 71, -1, 76,
- 47, 48, -1, 54, 18, 54, 92, -1, 59, 54,
- 59, 54, 61, 54, 59, -1, 59, 54, 59, 54,
- 65, -1, 59, 54, 59, 76, 61, -1, 59, 14,
- 61, 14, 2, 76, 19, 76, 21, 5, 88, 76,
- 23, -1, -1, -1, -1, -1, 14, -1, 18, -1,
- -1, -1, 35, 36, -1, 23, -1, 42, 25, 26,
- 27, 28, 29, 30, 31, -1, 14, 35, 36, -1,
- -1, -1, -1, -1, 88, 23, 24, 25, 26, 27,
- 28, 29, 30, 31, 14, -1, -1, -1, -1, -1,
- -1, -1, -1, 23, 24, 25, 26, 27, 28, 29,
- 30, 31, 14, -1, -1, -1, -1, -1, -1, -1,
- -1, 23, 24, 25, 26, 27, 28, 29, 30, 31,
- -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
- -1, 5, -1, -1, -1, -1, -1, -1, -1, -1,
- 14, -1, -1, -1, -1, -1, -1, -1, -1, 23,
- -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
- -1, 35, 36, -1, -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1, -1};
+ 18, 18, 32, 18, 32, 18, 3, 43, 18, 25,
+ 22, 22, 14, 14, 78, 18, 9, 3, 18, 3,
+ 18, 3, 18, 32, 18, 32, 32, 22, 18, 18,
+ 22, 3, 3, 18, 106, 43, 3, 18, 18, 101,
+ 3, 3, 18, 18, 18, 104, 3, 3, 18, 18,
+ 18, 3, 18, 18, 18, 43, 3, 3, 3, 32,
+ 14, 3, 3, 3, 25, 25, 25, -1, 55, 18,
+ 57, 2, 55, -1, -1, 2, 55, 60, 3, -1,
+ 18, 60, 18, 18, -1, 43, 25, 18, 43, -1,
+ 43, 18, 43, 43, 18, 43, 11, 12, 14, 43,
+ 43, 4, 3, 19, 18, 18, 3, 14, 3, 45,
+ 18, -1, 18, -1, 2, 18, 23, 2, 55, 2,
+ 57, 55, 55, 57, 57, 55, 55, 57, 57, 55,
+ 18, 57, 45, 18, 55, 18, 57, 2, 46, 2,
+ 2, 47, 2, 55, 55, 55, 55, 57, 60, 60,
+ 55, 60, 57, 18, 79, 18, 18, 55, 18, 55,
+ 95, 57, 60, 14, 2, 2, 55, -1, 55, 18,
+ 14, 55, 61, 55, 61, 19, 60, 59, 79, 55,
+ 18, 18, 79, 59, 79, 55, 55, 55, 14, 55,
+ 60, 60, 60, 18, 60, 2, 110, 55, 47, 55,
+ 43, 52, 60, 59, 18, 55, 2, 57, 51, 55,
+ 55, 18, 39, 55, 55, 18, 43, 4, 2, 55,
+ 65, 67, 18, 2, 18, 61, 52, 2, 69, 71,
+ 2, 18, 46, 55, 18, 57, 55, 4, 57, 18,
+ 55, 44, 57, 18, 55, 55, 18, 58, 58, 18,
+ 43, 18, 46, 55, 14, 57, 55, 18, 51, 19,
+ 2, 2, 61, 55, 55, 57, 55, 55, 93, 57,
+ -1, 60, 63, -1, -1, 55, 18, 18, 47, 68,
+ 60, -1, 55, -1, 64, 46, 18, 60, -1, 62,
+ 55, 55, -1, -1, -1, 60, 60, 62, 62, 55,
+ 55, -1, 55, 55, 60, 60, 62, 60, 60, 55,
+ 55, -1, 55, 66, 60, 60, 48, 60, 55, 55,
+ -1, 14, 77, 60, 60, 77, 19, 72, 21, -1,
+ 14, 77, -1, 70, 77, 5, -1, 5, -1, 23,
+ -1, 77, -1, -1, 14, -1, 14, 89, 89, -1,
+ 43, 35, 36, 23, -1, 23, 25, 26, 27, 28,
+ 29, 30, 31, -1, -1, 35, 36, 35, 36, -1,
+ -1, -1, 14, -1, -1, -1, -1, -1, -1, -1,
+ 18, 23, 24, 25, 26, 27, 28, 29, 30, 31,
+ 14, -1, -1, -1, -1, -1, -1, -1, -1, 23,
+ 24, 25, 26, 27, 28, 29, 30, 31, -1, -1,
+ 48, 49, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, 14, -1, -1, -1, -1, -1,
+ -1, -1, -1, 23, 24, 25, 26, 27, 28, 29,
+ 30, 31, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1
+};
QT_END_NAMESPACE
diff --git a/src/qml/parser/qqmljsgrammar_p.h b/src/qml/parser/qqmljsgrammar_p.h
index 050ef6c288..9d028f2191 100644
--- a/src/qml/parser/qqmljsgrammar_p.h
+++ b/src/qml/parser/qqmljsgrammar_p.h
@@ -59,152 +59,154 @@ QT_BEGIN_NAMESPACE
class QQmlJSGrammar
{
public:
- enum VariousConstants {
- EOF_SYMBOL = 0,
- REDUCE_HERE = 105,
- SHIFT_THERE = 104,
- T_AND = 1,
- T_AND_AND = 2,
- T_AND_EQ = 3,
- T_AS = 93,
- T_AUTOMATIC_SEMICOLON = 62,
- T_BREAK = 4,
- T_CASE = 5,
- T_CATCH = 6,
- T_COLON = 7,
- T_COMMA = 8,
- T_COMMENT = 88,
- T_COMPATIBILITY_SEMICOLON = 89,
- T_CONST = 84,
- T_CONTINUE = 9,
- T_DEBUGGER = 85,
- T_DEFAULT = 10,
- T_DELETE = 11,
- T_DIVIDE_ = 12,
- T_DIVIDE_EQ = 13,
- T_DO = 14,
- T_DOT = 15,
- T_ELSE = 16,
- T_EQ = 17,
- T_EQ_EQ = 18,
- T_EQ_EQ_EQ = 19,
- T_ERROR = 97,
- T_FALSE = 83,
- T_FEED_JS_EXPRESSION = 101,
- T_FEED_JS_PROGRAM = 103,
- T_FEED_JS_SOURCE_ELEMENT = 102,
- T_FEED_JS_STATEMENT = 100,
- T_FEED_UI_OBJECT_MEMBER = 99,
- T_FEED_UI_PROGRAM = 98,
- T_FINALLY = 20,
- T_FOR = 21,
- T_FUNCTION = 22,
- T_GE = 23,
- T_GET = 95,
- T_GT = 24,
- T_GT_GT = 25,
- T_GT_GT_EQ = 26,
- T_GT_GT_GT = 27,
- T_GT_GT_GT_EQ = 28,
- T_IDENTIFIER = 29,
- T_IF = 30,
- T_IMPORT = 91,
- T_IN = 31,
- T_INSTANCEOF = 32,
- T_LBRACE = 33,
- T_LBRACKET = 34,
- T_LE = 35,
- T_LPAREN = 36,
- T_LT = 37,
- T_LT_LT = 38,
- T_LT_LT_EQ = 39,
- T_MINUS = 40,
- T_MINUS_EQ = 41,
- T_MINUS_MINUS = 42,
- T_MULTILINE_STRING_LITERAL = 87,
- T_NEW = 43,
- T_NOT = 44,
- T_NOT_EQ = 45,
- T_NOT_EQ_EQ = 46,
- T_NULL = 81,
- T_NUMERIC_LITERAL = 47,
- T_ON = 94,
- T_OR = 48,
- T_OR_EQ = 49,
- T_OR_OR = 50,
- T_PLUS = 51,
- T_PLUS_EQ = 52,
- T_PLUS_PLUS = 53,
- T_PRAGMA = 92,
- T_PROPERTY = 66,
- T_PUBLIC = 90,
- T_QUESTION = 54,
- T_RBRACE = 55,
- T_RBRACKET = 56,
- T_READONLY = 68,
- T_REMAINDER = 57,
- T_REMAINDER_EQ = 58,
- T_RESERVED_WORD = 86,
- T_RETURN = 59,
- T_RPAREN = 60,
- T_SEMICOLON = 61,
- T_SET = 96,
- T_SIGNAL = 67,
- T_STAR = 63,
- T_STAR_EQ = 64,
- T_STRING_LITERAL = 65,
- T_SWITCH = 69,
- T_THIS = 70,
- T_THROW = 71,
- T_TILDE = 72,
- T_TRUE = 82,
- T_TRY = 73,
- T_TYPEOF = 74,
- T_VAR = 75,
- T_VOID = 76,
- T_WHILE = 77,
- T_WITH = 78,
- T_XOR = 79,
- T_XOR_EQ = 80,
-
- ACCEPT_STATE = 674,
- RULE_COUNT = 361,
- STATE_COUNT = 675,
- TERMINAL_COUNT = 106,
- NON_TERMINAL_COUNT = 111,
-
- GOTO_INDEX_OFFSET = 675,
- GOTO_INFO_OFFSET = 3078,
- GOTO_CHECK_OFFSET = 3078
- };
-
- static const char *const spell [];
- static const short lhs [];
- static const short rhs [];
- static const short goto_default [];
- static const short action_default [];
- static const short action_index [];
- static const short action_info [];
- static const short action_check [];
-
- static inline int nt_action (int state, int nt)
- {
- const int yyn = action_index [GOTO_INDEX_OFFSET + state] + nt;
- if (yyn < 0 || action_check [GOTO_CHECK_OFFSET + yyn] != nt)
- return goto_default [nt];
-
- return action_info [GOTO_INFO_OFFSET + yyn];
- }
-
- static inline int t_action (int state, int token)
- {
- const int yyn = action_index [state] + token;
-
- if (yyn < 0 || action_check [yyn] != token)
- return - action_default [state];
-
- return action_info [yyn];
- }
+ enum VariousConstants {
+ EOF_SYMBOL = 0,
+ REDUCE_HERE = 107,
+ SHIFT_THERE = 106,
+ T_AND = 1,
+ T_AND_AND = 2,
+ T_AND_EQ = 3,
+ T_AS = 95,
+ T_AUTOMATIC_SEMICOLON = 62,
+ T_BREAK = 4,
+ T_CASE = 5,
+ T_CATCH = 6,
+ T_COLON = 7,
+ T_COMMA = 8,
+ T_COMMENT = 89,
+ T_COMPATIBILITY_SEMICOLON = 90,
+ T_CONST = 84,
+ T_CONTINUE = 9,
+ T_DEBUGGER = 86,
+ T_DEFAULT = 10,
+ T_DELETE = 11,
+ T_DIVIDE_ = 12,
+ T_DIVIDE_EQ = 13,
+ T_DO = 14,
+ T_DOT = 15,
+ T_ELSE = 16,
+ T_ENUM = 91,
+ T_EQ = 17,
+ T_EQ_EQ = 18,
+ T_EQ_EQ_EQ = 19,
+ T_ERROR = 99,
+ T_FALSE = 83,
+ T_FEED_JS_EXPRESSION = 103,
+ T_FEED_JS_PROGRAM = 105,
+ T_FEED_JS_SOURCE_ELEMENT = 104,
+ T_FEED_JS_STATEMENT = 102,
+ T_FEED_UI_OBJECT_MEMBER = 101,
+ T_FEED_UI_PROGRAM = 100,
+ T_FINALLY = 20,
+ T_FOR = 21,
+ T_FUNCTION = 22,
+ T_GE = 23,
+ T_GET = 97,
+ T_GT = 24,
+ T_GT_GT = 25,
+ T_GT_GT_EQ = 26,
+ T_GT_GT_GT = 27,
+ T_GT_GT_GT_EQ = 28,
+ T_IDENTIFIER = 29,
+ T_IF = 30,
+ T_IMPORT = 93,
+ T_IN = 31,
+ T_INSTANCEOF = 32,
+ T_LBRACE = 33,
+ T_LBRACKET = 34,
+ T_LE = 35,
+ T_LET = 85,
+ T_LPAREN = 36,
+ T_LT = 37,
+ T_LT_LT = 38,
+ T_LT_LT_EQ = 39,
+ T_MINUS = 40,
+ T_MINUS_EQ = 41,
+ T_MINUS_MINUS = 42,
+ T_MULTILINE_STRING_LITERAL = 88,
+ T_NEW = 43,
+ T_NOT = 44,
+ T_NOT_EQ = 45,
+ T_NOT_EQ_EQ = 46,
+ T_NULL = 81,
+ T_NUMERIC_LITERAL = 47,
+ T_ON = 96,
+ T_OR = 48,
+ T_OR_EQ = 49,
+ T_OR_OR = 50,
+ T_PLUS = 51,
+ T_PLUS_EQ = 52,
+ T_PLUS_PLUS = 53,
+ T_PRAGMA = 94,
+ T_PROPERTY = 66,
+ T_PUBLIC = 92,
+ T_QUESTION = 54,
+ T_RBRACE = 55,
+ T_RBRACKET = 56,
+ T_READONLY = 68,
+ T_REMAINDER = 57,
+ T_REMAINDER_EQ = 58,
+ T_RESERVED_WORD = 87,
+ T_RETURN = 59,
+ T_RPAREN = 60,
+ T_SEMICOLON = 61,
+ T_SET = 98,
+ T_SIGNAL = 67,
+ T_STAR = 63,
+ T_STAR_EQ = 64,
+ T_STRING_LITERAL = 65,
+ T_SWITCH = 69,
+ T_THIS = 70,
+ T_THROW = 71,
+ T_TILDE = 72,
+ T_TRUE = 82,
+ T_TRY = 73,
+ T_TYPEOF = 74,
+ T_VAR = 75,
+ T_VOID = 76,
+ T_WHILE = 77,
+ T_WITH = 78,
+ T_XOR = 79,
+ T_XOR_EQ = 80,
+
+ ACCEPT_STATE = 691,
+ RULE_COUNT = 369,
+ STATE_COUNT = 692,
+ TERMINAL_COUNT = 108,
+ NON_TERMINAL_COUNT = 112,
+
+ GOTO_INDEX_OFFSET = 692,
+ GOTO_INFO_OFFSET = 3357,
+ GOTO_CHECK_OFFSET = 3357
+ };
+
+ static const char *const spell[];
+ static const short lhs[];
+ static const short rhs[];
+ static const short goto_default[];
+ static const short action_default[];
+ static const short action_index[];
+ static const short action_info[];
+ static const short action_check[];
+
+ static inline int nt_action (int state, int nt)
+ {
+ const int yyn = action_index [GOTO_INDEX_OFFSET + state] + nt;
+ if (yyn < 0 || action_check [GOTO_CHECK_OFFSET + yyn] != nt)
+ return goto_default [nt];
+
+ return action_info [GOTO_INFO_OFFSET + yyn];
+ }
+
+ static inline int t_action (int state, int token)
+ {
+ const int yyn = action_index [state] + token;
+
+ if (yyn < 0 || action_check [yyn] != token)
+ return - action_default [state];
+
+ return action_info [yyn];
+ }
};
diff --git a/src/qml/parser/qqmljskeywords_p.h b/src/qml/parser/qqmljskeywords_p.h
index 84ebe5f210..20daf545a9 100644
--- a/src/qml/parser/qqmljskeywords_p.h
+++ b/src/qml/parser/qqmljskeywords_p.h
@@ -106,6 +106,13 @@ static inline int classify3(const QChar *s, bool qmlMode) {
}
}
}
+ else if (s[0].unicode() == 'l') {
+ if (s[1].unicode() == 'e') {
+ if (s[2].unicode() == 't') {
+ return int(Lexer::T_LET);
+ }
+ }
+ }
else if (s[0].unicode() == 'n') {
if (s[1].unicode() == 'e') {
if (s[2].unicode() == 'w') {
@@ -174,7 +181,7 @@ static inline int classify4(const QChar *s, bool qmlMode) {
else if (s[1].unicode() == 'n') {
if (s[2].unicode() == 'u') {
if (s[3].unicode() == 'm') {
- return Lexer::T_ENUM;
+ return qmlMode ? int(Lexer::T_ENUM) : int(Lexer::T_RESERVED_WORD);
}
}
}
@@ -278,7 +285,7 @@ static inline int classify5(const QChar *s, bool qmlMode) {
if (s[2].unicode() == 'n') {
if (s[3].unicode() == 's') {
if (s[4].unicode() == 't') {
- return qmlMode ? int(Lexer::T_CONST) : int(Lexer::T_RESERVED_WORD);
+ return int(Lexer::T_CONST);
}
}
}
diff --git a/src/qml/parser/qqmljslexer.cpp b/src/qml/parser/qqmljslexer.cpp
index 53e67fde03..78ed5e3b2c 100644
--- a/src/qml/parser/qqmljslexer.cpp
+++ b/src/qml/parser/qqmljslexer.cpp
@@ -86,6 +86,7 @@ static inline QChar convertUnicode(QChar c1, QChar c2, QChar c3, QChar c4)
Lexer::Lexer(Engine *engine)
: _engine(engine)
, _codePtr(0)
+ , _endPtr(0)
, _lastLinePtr(0)
, _tokenLinePtr(0)
, _tokenStartPtr(0)
diff --git a/src/qml/parser/qqmljslexer_p.h b/src/qml/parser/qqmljslexer_p.h
index af5597b625..11d8081713 100644
--- a/src/qml/parser/qqmljslexer_p.h
+++ b/src/qml/parser/qqmljslexer_p.h
@@ -99,7 +99,6 @@ public:
T_CHAR = T_RESERVED_WORD,
T_CLASS = T_RESERVED_WORD,
T_DOUBLE = T_RESERVED_WORD,
- T_ENUM = T_RESERVED_WORD,
T_EXPORT = T_RESERVED_WORD,
T_EXTENDS = T_RESERVED_WORD,
T_FINAL = T_RESERVED_WORD,
diff --git a/src/qml/parser/qqmljsparser.cpp b/src/qml/parser/qqmljsparser.cpp
index 50518a92ee..df16a24bcc 100644
--- a/src/qml/parser/qqmljsparser.cpp
+++ b/src/qml/parser/qqmljsparser.cpp
@@ -92,6 +92,7 @@ Parser::Parser(Engine *engine):
location_stack(0),
string_stack(0),
program(0),
+ yylval(0),
first_token(0),
last_token(0)
{
@@ -656,49 +657,87 @@ case 75: {
sym(1).Node = new (pool) AST::UiSourceElement(sym(1).Node);
} break;
-case 83: {
+case 76: {
+ AST::UiEnumDeclaration *enumDeclaration = new (pool) AST::UiEnumDeclaration(stringRef(2), sym(4).UiEnumMemberList->finish());
+ enumDeclaration->enumToken = loc(1);
+ enumDeclaration->rbraceToken = loc(5);
+ sym(1).Node = enumDeclaration;
+ break;
+}
+
+case 77: {
+ AST::UiEnumMemberList *node = new (pool) AST::UiEnumMemberList(stringRef(1));
+ node->memberToken = loc(1);
+ sym(1).Node = node;
+ break;
+}
+
+case 78: {
+ AST::UiEnumMemberList *node = new (pool) AST::UiEnumMemberList(stringRef(1), sym(3).dval);
+ node->memberToken = loc(1);
+ node->valueToken = loc(3);
+ sym(1).Node = node;
+ break;
+}
+
+case 79: {
+ AST::UiEnumMemberList *node = new (pool) AST::UiEnumMemberList(sym(1).UiEnumMemberList, stringRef(3));
+ node->memberToken = loc(3);
+ sym(1).Node = node;
+ break;
+}
+
+case 80: {
+ AST::UiEnumMemberList *node = new (pool) AST::UiEnumMemberList(sym(1).UiEnumMemberList, stringRef(3), sym(5).dval);
+ node->memberToken = loc(3);
+ node->valueToken = loc(5);
+ sym(1).Node = node;
+ break;
+}
+
+case 88: {
AST::ThisExpression *node = new (pool) AST::ThisExpression();
node->thisToken = loc(1);
sym(1).Node = node;
} break;
-case 84: {
+case 89: {
AST::IdentifierExpression *node = new (pool) AST::IdentifierExpression(stringRef(1));
node->identifierToken = loc(1);
sym(1).Node = node;
} break;
-case 85: {
+case 90: {
AST::NullExpression *node = new (pool) AST::NullExpression();
node->nullToken = loc(1);
sym(1).Node = node;
} break;
-case 86: {
+case 91: {
AST::TrueLiteral *node = new (pool) AST::TrueLiteral();
node->trueToken = loc(1);
sym(1).Node = node;
} break;
-case 87: {
+case 92: {
AST::FalseLiteral *node = new (pool) AST::FalseLiteral();
node->falseToken = loc(1);
sym(1).Node = node;
} break;
-case 88: {
+case 93: {
AST::NumericLiteral *node = new (pool) AST::NumericLiteral(sym(1).dval);
node->literalToken = loc(1);
sym(1).Node = node;
} break;
-case 89:
-case 90: {
+case 94:
+case 95: {
AST::StringLiteral *node = new (pool) AST::StringLiteral(stringRef(1));
node->literalToken = loc(1);
sym(1).Node = node;
} break;
-case 91: {
+case 96: {
bool rx = lexer->scanRegExp(Lexer::NoPrefix);
if (!rx) {
diagnostic_messages.append(DiagnosticMessage(DiagnosticMessage::Error, location(lexer), lexer->errorMessage()));
@@ -714,7 +753,7 @@ case 91: {
sym(1).Node = node;
} break;
-case 92: {
+case 97: {
bool rx = lexer->scanRegExp(Lexer::EqualPrefix);
if (!rx) {
diagnostic_messages.append(DiagnosticMessage(DiagnosticMessage::Error, location(lexer), lexer->errorMessage()));
@@ -730,28 +769,28 @@ case 92: {
sym(1).Node = node;
} break;
-case 93: {
+case 98: {
AST::ArrayLiteral *node = new (pool) AST::ArrayLiteral((AST::Elision *) 0);
node->lbracketToken = loc(1);
node->rbracketToken = loc(2);
sym(1).Node = node;
} break;
-case 94: {
+case 99: {
AST::ArrayLiteral *node = new (pool) AST::ArrayLiteral(sym(2).Elision->finish());
node->lbracketToken = loc(1);
node->rbracketToken = loc(3);
sym(1).Node = node;
} break;
-case 95: {
+case 100: {
AST::ArrayLiteral *node = new (pool) AST::ArrayLiteral(sym(2).ElementList->finish ());
node->lbracketToken = loc(1);
node->rbracketToken = loc(3);
sym(1).Node = node;
} break;
-case 96: {
+case 101: {
AST::ArrayLiteral *node = new (pool) AST::ArrayLiteral(sym(2).ElementList->finish (),
(AST::Elision *) 0);
node->lbracketToken = loc(1);
@@ -760,7 +799,7 @@ case 96: {
sym(1).Node = node;
} break;
-case 97: {
+case 102: {
AST::ArrayLiteral *node = new (pool) AST::ArrayLiteral(sym(2).ElementList->finish (),
sym(4).Elision->finish());
node->lbracketToken = loc(1);
@@ -769,7 +808,7 @@ case 97: {
sym(1).Node = node;
} break;
-case 98: {
+case 103: {
AST::ObjectLiteral *node = 0;
if (sym(2).Node)
node = new (pool) AST::ObjectLiteral(
@@ -781,7 +820,7 @@ case 98: {
sym(1).Node = node;
} break;
-case 99: {
+case 104: {
AST::ObjectLiteral *node = new (pool) AST::ObjectLiteral(
sym(2).PropertyAssignmentList->finish ());
node->lbraceToken = loc(1);
@@ -789,14 +828,14 @@ case 99: {
sym(1).Node = node;
} break;
-case 100: {
+case 105: {
AST::NestedExpression *node = new (pool) AST::NestedExpression(sym(2).Expression);
node->lparenToken = loc(1);
node->rparenToken = loc(3);
sym(1).Node = node;
} break;
-case 101: {
+case 106: {
if (AST::ArrayMemberExpression *mem = AST::cast<AST::ArrayMemberExpression *>(sym(1).Expression)) {
diagnostic_messages.append(DiagnosticMessage(DiagnosticMessage::Warning, mem->lbracketToken,
QLatin1String("Ignored annotation")));
@@ -816,48 +855,48 @@ case 101: {
}
} break;
-case 102: {
+case 107: {
sym(1).Node = new (pool) AST::ElementList((AST::Elision *) 0, sym(1).Expression);
} break;
-case 103: {
+case 108: {
sym(1).Node = new (pool) AST::ElementList(sym(1).Elision->finish(), sym(2).Expression);
} break;
-case 104: {
+case 109: {
AST::ElementList *node = new (pool) AST::ElementList(sym(1).ElementList,
(AST::Elision *) 0, sym(3).Expression);
node->commaToken = loc(2);
sym(1).Node = node;
} break;
-case 105: {
+case 110: {
AST::ElementList *node = new (pool) AST::ElementList(sym(1).ElementList, sym(3).Elision->finish(),
sym(4).Expression);
node->commaToken = loc(2);
sym(1).Node = node;
} break;
-case 106: {
+case 111: {
AST::Elision *node = new (pool) AST::Elision();
node->commaToken = loc(1);
sym(1).Node = node;
} break;
-case 107: {
+case 112: {
AST::Elision *node = new (pool) AST::Elision(sym(1).Elision);
node->commaToken = loc(2);
sym(1).Node = node;
} break;
-case 108: {
+case 113: {
AST::PropertyNameAndValue *node = new (pool) AST::PropertyNameAndValue(
sym(1).PropertyName, sym(3).Expression);
node->colonToken = loc(2);
sym(1).Node = node;
} break;
-case 109: {
+case 114: {
AST::PropertyGetterSetter *node = new (pool) AST::PropertyGetterSetter(
sym(2).PropertyName, sym(6).FunctionBody);
node->getSetToken = loc(1);
@@ -868,7 +907,7 @@ case 109: {
sym(1).Node = node;
} break;
-case 110: {
+case 115: {
AST::PropertyGetterSetter *node = new (pool) AST::PropertyGetterSetter(
sym(2).PropertyName, sym(4).FormalParameterList, sym(7).FunctionBody);
node->getSetToken = loc(1);
@@ -879,56 +918,56 @@ case 110: {
sym(1).Node = node;
} break;
-case 111: {
+case 116: {
sym(1).Node = new (pool) AST::PropertyAssignmentList(sym(1).PropertyAssignment);
} break;
-case 112: {
+case 117: {
AST::PropertyAssignmentList *node = new (pool) AST::PropertyAssignmentList(
sym(1).PropertyAssignmentList, sym(3).PropertyAssignment);
node->commaToken = loc(2);
sym(1).Node = node;
} break;
-case 113: {
+case 118: {
AST::IdentifierPropertyName *node = new (pool) AST::IdentifierPropertyName(stringRef(1));
node->propertyNameToken = loc(1);
sym(1).Node = node;
} break;
-case 114: {
+case 119: {
AST::StringLiteralPropertyName *node = new (pool) AST::StringLiteralPropertyName(stringRef(1));
node->propertyNameToken = loc(1);
sym(1).Node = node;
} break;
-case 115: {
+case 120: {
AST::NumericLiteralPropertyName *node = new (pool) AST::NumericLiteralPropertyName(sym(1).dval);
node->propertyNameToken = loc(1);
sym(1).Node = node;
} break;
-case 116: {
+case 121: {
AST::IdentifierPropertyName *node = new (pool) AST::IdentifierPropertyName(stringRef(1));
node->propertyNameToken = loc(1);
sym(1).Node = node;
} break;
-case 152: {
+case 159: {
AST::ArrayMemberExpression *node = new (pool) AST::ArrayMemberExpression(sym(1).Expression, sym(3).Expression);
node->lbracketToken = loc(2);
node->rbracketToken = loc(4);
sym(1).Node = node;
} break;
-case 153: {
+case 160: {
AST::FieldMemberExpression *node = new (pool) AST::FieldMemberExpression(sym(1).Expression, stringRef(3));
node->dotToken = loc(2);
node->identifierToken = loc(3);
sym(1).Node = node;
} break;
-case 154: {
+case 161: {
AST::NewMemberExpression *node = new (pool) AST::NewMemberExpression(sym(2).Expression, sym(4).ArgumentList);
node->newToken = loc(1);
node->lparenToken = loc(3);
@@ -936,384 +975,384 @@ case 154: {
sym(1).Node = node;
} break;
-case 156: {
+case 163: {
AST::NewExpression *node = new (pool) AST::NewExpression(sym(2).Expression);
node->newToken = loc(1);
sym(1).Node = node;
} break;
-case 157: {
+case 164: {
AST::CallExpression *node = new (pool) AST::CallExpression(sym(1).Expression, sym(3).ArgumentList);
node->lparenToken = loc(2);
node->rparenToken = loc(4);
sym(1).Node = node;
} break;
-case 158: {
+case 165: {
AST::CallExpression *node = new (pool) AST::CallExpression(sym(1).Expression, sym(3).ArgumentList);
node->lparenToken = loc(2);
node->rparenToken = loc(4);
sym(1).Node = node;
} break;
-case 159: {
+case 166: {
AST::ArrayMemberExpression *node = new (pool) AST::ArrayMemberExpression(sym(1).Expression, sym(3).Expression);
node->lbracketToken = loc(2);
node->rbracketToken = loc(4);
sym(1).Node = node;
} break;
-case 160: {
+case 167: {
AST::FieldMemberExpression *node = new (pool) AST::FieldMemberExpression(sym(1).Expression, stringRef(3));
node->dotToken = loc(2);
node->identifierToken = loc(3);
sym(1).Node = node;
} break;
-case 161: {
+case 168: {
sym(1).Node = 0;
} break;
-case 162: {
+case 169: {
sym(1).Node = sym(1).ArgumentList->finish();
} break;
-case 163: {
+case 170: {
sym(1).Node = new (pool) AST::ArgumentList(sym(1).Expression);
} break;
-case 164: {
+case 171: {
AST::ArgumentList *node = new (pool) AST::ArgumentList(sym(1).ArgumentList, sym(3).Expression);
node->commaToken = loc(2);
sym(1).Node = node;
} break;
-case 168: {
+case 175: {
AST::PostIncrementExpression *node = new (pool) AST::PostIncrementExpression(sym(1).Expression);
node->incrementToken = loc(2);
sym(1).Node = node;
} break;
-case 169: {
+case 176: {
AST::PostDecrementExpression *node = new (pool) AST::PostDecrementExpression(sym(1).Expression);
node->decrementToken = loc(2);
sym(1).Node = node;
} break;
-case 171: {
+case 178: {
AST::DeleteExpression *node = new (pool) AST::DeleteExpression(sym(2).Expression);
node->deleteToken = loc(1);
sym(1).Node = node;
} break;
-case 172: {
+case 179: {
AST::VoidExpression *node = new (pool) AST::VoidExpression(sym(2).Expression);
node->voidToken = loc(1);
sym(1).Node = node;
} break;
-case 173: {
+case 180: {
AST::TypeOfExpression *node = new (pool) AST::TypeOfExpression(sym(2).Expression);
node->typeofToken = loc(1);
sym(1).Node = node;
} break;
-case 174: {
+case 181: {
AST::PreIncrementExpression *node = new (pool) AST::PreIncrementExpression(sym(2).Expression);
node->incrementToken = loc(1);
sym(1).Node = node;
} break;
-case 175: {
+case 182: {
AST::PreDecrementExpression *node = new (pool) AST::PreDecrementExpression(sym(2).Expression);
node->decrementToken = loc(1);
sym(1).Node = node;
} break;
-case 176: {
+case 183: {
AST::UnaryPlusExpression *node = new (pool) AST::UnaryPlusExpression(sym(2).Expression);
node->plusToken = loc(1);
sym(1).Node = node;
} break;
-case 177: {
+case 184: {
AST::UnaryMinusExpression *node = new (pool) AST::UnaryMinusExpression(sym(2).Expression);
node->minusToken = loc(1);
sym(1).Node = node;
} break;
-case 178: {
+case 185: {
AST::TildeExpression *node = new (pool) AST::TildeExpression(sym(2).Expression);
node->tildeToken = loc(1);
sym(1).Node = node;
} break;
-case 179: {
+case 186: {
AST::NotExpression *node = new (pool) AST::NotExpression(sym(2).Expression);
node->notToken = loc(1);
sym(1).Node = node;
} break;
-case 181: {
+case 188: {
AST::BinaryExpression *node = new (pool) AST::BinaryExpression(sym(1).Expression,
QSOperator::Mul, sym(3).Expression);
node->operatorToken = loc(2);
sym(1).Node = node;
} break;
-case 182: {
+case 189: {
AST::BinaryExpression *node = new (pool) AST::BinaryExpression(sym(1).Expression,
QSOperator::Div, sym(3).Expression);
node->operatorToken = loc(2);
sym(1).Node = node;
} break;
-case 183: {
+case 190: {
AST::BinaryExpression *node = new (pool) AST::BinaryExpression(sym(1).Expression,
QSOperator::Mod, sym(3).Expression);
node->operatorToken = loc(2);
sym(1).Node = node;
} break;
-case 185: {
+case 192: {
AST::BinaryExpression *node = new (pool) AST::BinaryExpression(sym(1).Expression,
QSOperator::Add, sym(3).Expression);
node->operatorToken = loc(2);
sym(1).Node = node;
} break;
-case 186: {
+case 193: {
AST::BinaryExpression *node = new (pool) AST::BinaryExpression(sym(1).Expression,
QSOperator::Sub, sym(3).Expression);
node->operatorToken = loc(2);
sym(1).Node = node;
} break;
-case 188: {
+case 195: {
AST::BinaryExpression *node = new (pool) AST::BinaryExpression(sym(1).Expression,
QSOperator::LShift, sym(3).Expression);
node->operatorToken = loc(2);
sym(1).Node = node;
} break;
-case 189: {
+case 196: {
AST::BinaryExpression *node = new (pool) AST::BinaryExpression(sym(1).Expression,
QSOperator::RShift, sym(3).Expression);
node->operatorToken = loc(2);
sym(1).Node = node;
} break;
-case 190: {
+case 197: {
AST::BinaryExpression *node = new (pool) AST::BinaryExpression(sym(1).Expression,
QSOperator::URShift, sym(3).Expression);
node->operatorToken = loc(2);
sym(1).Node = node;
} break;
-case 192: {
+case 199: {
AST::BinaryExpression *node = new (pool) AST::BinaryExpression(sym(1).Expression,
QSOperator::Lt, sym(3).Expression);
node->operatorToken = loc(2);
sym(1).Node = node;
} break;
-case 193: {
+case 200: {
AST::BinaryExpression *node = new (pool) AST::BinaryExpression(sym(1).Expression,
QSOperator::Gt, sym(3).Expression);
node->operatorToken = loc(2);
sym(1).Node = node;
} break;
-case 194: {
+case 201: {
AST::BinaryExpression *node = new (pool) AST::BinaryExpression(sym(1).Expression,
QSOperator::Le, sym(3).Expression);
node->operatorToken = loc(2);
sym(1).Node = node;
} break;
-case 195: {
+case 202: {
AST::BinaryExpression *node = new (pool) AST::BinaryExpression(sym(1).Expression,
QSOperator::Ge, sym(3).Expression);
node->operatorToken = loc(2);
sym(1).Node = node;
} break;
-case 196: {
+case 203: {
AST::BinaryExpression *node = new (pool) AST::BinaryExpression(sym(1).Expression,
QSOperator::InstanceOf, sym(3).Expression);
node->operatorToken = loc(2);
sym(1).Node = node;
} break;
-case 197: {
+case 204: {
AST::BinaryExpression *node = new (pool) AST::BinaryExpression(sym(1).Expression,
QSOperator::In, sym(3).Expression);
node->operatorToken = loc(2);
sym(1).Node = node;
} break;
-case 199: {
+case 206: {
AST::BinaryExpression *node = new (pool) AST::BinaryExpression(sym(1).Expression,
QSOperator::Lt, sym(3).Expression);
node->operatorToken = loc(2);
sym(1).Node = node;
} break;
-case 200: {
+case 207: {
AST::BinaryExpression *node = new (pool) AST::BinaryExpression(sym(1).Expression,
QSOperator::Gt, sym(3).Expression);
node->operatorToken = loc(2);
sym(1).Node = node;
} break;
-case 201: {
+case 208: {
AST::BinaryExpression *node = new (pool) AST::BinaryExpression(sym(1).Expression,
QSOperator::Le, sym(3).Expression);
node->operatorToken = loc(2);
sym(1).Node = node;
} break;
-case 202: {
+case 209: {
AST::BinaryExpression *node = new (pool) AST::BinaryExpression(sym(1).Expression,
QSOperator::Ge, sym(3).Expression);
node->operatorToken = loc(2);
sym(1).Node = node;
} break;
-case 203: {
+case 210: {
AST::BinaryExpression *node = new (pool) AST::BinaryExpression(sym(1).Expression,
QSOperator::InstanceOf, sym(3).Expression);
node->operatorToken = loc(2);
sym(1).Node = node;
} break;
-case 205: {
+case 212: {
AST::BinaryExpression *node = new (pool) AST::BinaryExpression(sym(1).Expression,
QSOperator::Equal, sym(3).Expression);
node->operatorToken = loc(2);
sym(1).Node = node;
} break;
-case 206: {
+case 213: {
AST::BinaryExpression *node = new (pool) AST::BinaryExpression(sym(1).Expression,
QSOperator::NotEqual, sym(3).Expression);
node->operatorToken = loc(2);
sym(1).Node = node;
} break;
-case 207: {
+case 214: {
AST::BinaryExpression *node = new (pool) AST::BinaryExpression(sym(1).Expression,
QSOperator::StrictEqual, sym(3).Expression);
node->operatorToken = loc(2);
sym(1).Node = node;
} break;
-case 208: {
+case 215: {
AST::BinaryExpression *node = new (pool) AST::BinaryExpression(sym(1).Expression,
QSOperator::StrictNotEqual, sym(3).Expression);
node->operatorToken = loc(2);
sym(1).Node = node;
} break;
-case 210: {
+case 217: {
AST::BinaryExpression *node = new (pool) AST::BinaryExpression(sym(1).Expression,
QSOperator::Equal, sym(3).Expression);
node->operatorToken = loc(2);
sym(1).Node = node;
} break;
-case 211: {
+case 218: {
AST::BinaryExpression *node = new (pool) AST::BinaryExpression(sym(1).Expression,
QSOperator::NotEqual, sym(3).Expression);
node->operatorToken = loc(2);
sym(1).Node = node;
} break;
-case 212: {
+case 219: {
AST::BinaryExpression *node = new (pool) AST::BinaryExpression(sym(1).Expression,
QSOperator::StrictEqual, sym(3).Expression);
node->operatorToken = loc(2);
sym(1).Node = node;
} break;
-case 213: {
+case 220: {
AST::BinaryExpression *node = new (pool) AST::BinaryExpression(sym(1).Expression,
QSOperator::StrictNotEqual, sym(3).Expression);
node->operatorToken = loc(2);
sym(1).Node = node;
} break;
-case 215: {
+case 222: {
AST::BinaryExpression *node = new (pool) AST::BinaryExpression(sym(1).Expression,
QSOperator::BitAnd, sym(3).Expression);
node->operatorToken = loc(2);
sym(1).Node = node;
} break;
-case 217: {
+case 224: {
AST::BinaryExpression *node = new (pool) AST::BinaryExpression(sym(1).Expression,
QSOperator::BitAnd, sym(3).Expression);
node->operatorToken = loc(2);
sym(1).Node = node;
} break;
-case 219: {
+case 226: {
AST::BinaryExpression *node = new (pool) AST::BinaryExpression(sym(1).Expression,
QSOperator::BitXor, sym(3).Expression);
node->operatorToken = loc(2);
sym(1).Node = node;
} break;
-case 221: {
+case 228: {
AST::BinaryExpression *node = new (pool) AST::BinaryExpression(sym(1).Expression,
QSOperator::BitXor, sym(3).Expression);
node->operatorToken = loc(2);
sym(1).Node = node;
} break;
-case 223: {
+case 230: {
AST::BinaryExpression *node = new (pool) AST::BinaryExpression(sym(1).Expression,
QSOperator::BitOr, sym(3).Expression);
node->operatorToken = loc(2);
sym(1).Node = node;
} break;
-case 225: {
+case 232: {
AST::BinaryExpression *node = new (pool) AST::BinaryExpression(sym(1).Expression,
QSOperator::BitOr, sym(3).Expression);
node->operatorToken = loc(2);
sym(1).Node = node;
} break;
-case 227: {
+case 234: {
AST::BinaryExpression *node = new (pool) AST::BinaryExpression(sym(1).Expression,
QSOperator::And, sym(3).Expression);
node->operatorToken = loc(2);
sym(1).Node = node;
} break;
-case 229: {
+case 236: {
AST::BinaryExpression *node = new (pool) AST::BinaryExpression(sym(1).Expression,
QSOperator::And, sym(3).Expression);
node->operatorToken = loc(2);
sym(1).Node = node;
} break;
-case 231: {
+case 238: {
AST::BinaryExpression *node = new (pool) AST::BinaryExpression(sym(1).Expression,
QSOperator::Or, sym(3).Expression);
node->operatorToken = loc(2);
sym(1).Node = node;
} break;
-case 233: {
+case 240: {
AST::BinaryExpression *node = new (pool) AST::BinaryExpression(sym(1).Expression,
QSOperator::Or, sym(3).Expression);
node->operatorToken = loc(2);
sym(1).Node = node;
} break;
-case 235: {
+case 242: {
AST::ConditionalExpression *node = new (pool) AST::ConditionalExpression(sym(1).Expression,
sym(3).Expression, sym(5).Expression);
node->questionToken = loc(2);
@@ -1321,7 +1360,7 @@ case 235: {
sym(1).Node = node;
} break;
-case 237: {
+case 244: {
AST::ConditionalExpression *node = new (pool) AST::ConditionalExpression(sym(1).Expression,
sym(3).Expression, sym(5).Expression);
node->questionToken = loc(2);
@@ -1329,189 +1368,200 @@ case 237: {
sym(1).Node = node;
} break;
-case 239: {
+case 246: {
AST::BinaryExpression *node = new (pool) AST::BinaryExpression(sym(1).Expression,
sym(2).ival, sym(3).Expression);
node->operatorToken = loc(2);
sym(1).Node = node;
} break;
-case 241: {
+case 248: {
AST::BinaryExpression *node = new (pool) AST::BinaryExpression(sym(1).Expression,
sym(2).ival, sym(3).Expression);
node->operatorToken = loc(2);
sym(1).Node = node;
} break;
-case 242: {
+case 249: {
sym(1).ival = QSOperator::Assign;
} break;
-case 243: {
+case 250: {
sym(1).ival = QSOperator::InplaceMul;
} break;
-case 244: {
+case 251: {
sym(1).ival = QSOperator::InplaceDiv;
} break;
-case 245: {
+case 252: {
sym(1).ival = QSOperator::InplaceMod;
} break;
-case 246: {
+case 253: {
sym(1).ival = QSOperator::InplaceAdd;
} break;
-case 247: {
+case 254: {
sym(1).ival = QSOperator::InplaceSub;
} break;
-case 248: {
+case 255: {
sym(1).ival = QSOperator::InplaceLeftShift;
} break;
-case 249: {
+case 256: {
sym(1).ival = QSOperator::InplaceRightShift;
} break;
-case 250: {
+case 257: {
sym(1).ival = QSOperator::InplaceURightShift;
} break;
-case 251: {
+case 258: {
sym(1).ival = QSOperator::InplaceAnd;
} break;
-case 252: {
+case 259: {
sym(1).ival = QSOperator::InplaceXor;
} break;
-case 253: {
+case 260: {
sym(1).ival = QSOperator::InplaceOr;
} break;
-case 255: {
+case 262: {
AST::Expression *node = new (pool) AST::Expression(sym(1).Expression, sym(3).Expression);
node->commaToken = loc(2);
sym(1).Node = node;
} break;
-case 256: {
+case 263: {
sym(1).Node = 0;
} break;
-case 259: {
+case 266: {
AST::Expression *node = new (pool) AST::Expression(sym(1).Expression, sym(3).Expression);
node->commaToken = loc(2);
sym(1).Node = node;
} break;
-case 260: {
+case 267: {
sym(1).Node = 0;
} break;
-case 277: {
+case 284: {
AST::Block *node = new (pool) AST::Block(sym(2).StatementList);
node->lbraceToken = loc(1);
node->rbraceToken = loc(3);
sym(1).Node = node;
} break;
-case 278: {
+case 285: {
sym(1).Node = new (pool) AST::StatementList(sym(1).Statement);
} break;
-case 279: {
+case 286: {
sym(1).Node = new (pool) AST::StatementList(sym(1).StatementList, sym(2).Statement);
} break;
-case 280: {
+case 287: {
sym(1).Node = 0;
} break;
-case 281: {
+case 288: {
sym(1).Node = sym(1).StatementList->finish ();
} break;
-case 283: {
- AST::VariableStatement *node = new (pool) AST::VariableStatement(
- sym(2).VariableDeclarationList->finish (/*readOnly=*/sym(1).ival == T_CONST));
+case 290: {
+ AST::VariableDeclaration::VariableScope s = AST::VariableDeclaration::FunctionScope;
+ if (sym(1).ival == T_LET)
+ s = AST::VariableDeclaration::BlockScope;
+ else if (sym(1).ival == T_CONST)
+ s = AST::VariableDeclaration::ReadOnlyBlockScope;
+
+ AST::VariableStatement *node = new (pool) AST::VariableStatement(sym(2).VariableDeclarationList->finish(s));
node->declarationKindToken = loc(1);
node->semicolonToken = loc(3);
sym(1).Node = node;
} break;
-case 284: {
+case 291: {
+ sym(1).ival = T_LET;
+} break;
+
+case 292: {
sym(1).ival = T_CONST;
} break;
-case 285: {
+case 293: {
sym(1).ival = T_VAR;
} break;
-case 286: {
+case 294: {
sym(1).Node = new (pool) AST::VariableDeclarationList(sym(1).VariableDeclaration);
} break;
-case 287: {
+case 295: {
AST::VariableDeclarationList *node = new (pool) AST::VariableDeclarationList(
sym(1).VariableDeclarationList, sym(3).VariableDeclaration);
node->commaToken = loc(2);
sym(1).Node = node;
} break;
-case 288: {
+case 296: {
sym(1).Node = new (pool) AST::VariableDeclarationList(sym(1).VariableDeclaration);
} break;
-case 289: {
+case 297: {
sym(1).Node = new (pool) AST::VariableDeclarationList(sym(1).VariableDeclarationList, sym(3).VariableDeclaration);
} break;
-case 290: {
- AST::VariableDeclaration *node = new (pool) AST::VariableDeclaration(stringRef(1), sym(2).Expression);
+case 298: {
+ AST::VariableDeclaration::VariableScope s = AST::VariableDeclaration::FunctionScope;
+ AST::VariableDeclaration *node = new (pool) AST::VariableDeclaration(stringRef(1), sym(2).Expression, s);
node->identifierToken = loc(1);
sym(1).Node = node;
} break;
-case 291: {
- AST::VariableDeclaration *node = new (pool) AST::VariableDeclaration(stringRef(1), sym(2).Expression);
+case 299: {
+ AST::VariableDeclaration::VariableScope s = AST::VariableDeclaration::FunctionScope;
+ AST::VariableDeclaration *node = new (pool) AST::VariableDeclaration(stringRef(1), sym(2).Expression, s);
node->identifierToken = loc(1);
sym(1).Node = node;
} break;
-case 292: {
+case 300: {
// ### TODO: AST for initializer
sym(1) = sym(2);
} break;
-case 293: {
+case 301: {
sym(1).Node = 0;
} break;
-case 295: {
+case 303: {
// ### TODO: AST for initializer
sym(1) = sym(2);
} break;
-case 296: {
+case 304: {
sym(1).Node = 0;
} break;
-case 298: {
+case 306: {
AST::EmptyStatement *node = new (pool) AST::EmptyStatement();
node->semicolonToken = loc(1);
sym(1).Node = node;
} break;
-case 300: {
+case 308: {
AST::ExpressionStatement *node = new (pool) AST::ExpressionStatement(sym(1).Expression);
node->semicolonToken = loc(2);
sym(1).Node = node;
} break;
-case 301: {
+case 309: {
AST::IfStatement *node = new (pool) AST::IfStatement(sym(3).Expression, sym(5).Statement, sym(7).Statement);
node->ifToken = loc(1);
node->lparenToken = loc(2);
@@ -1520,7 +1570,7 @@ case 301: {
sym(1).Node = node;
} break;
-case 302: {
+case 310: {
AST::IfStatement *node = new (pool) AST::IfStatement(sym(3).Expression, sym(5).Statement);
node->ifToken = loc(1);
node->lparenToken = loc(2);
@@ -1528,7 +1578,7 @@ case 302: {
sym(1).Node = node;
} break;
-case 305: {
+case 313: {
AST::DoWhileStatement *node = new (pool) AST::DoWhileStatement(sym(2).Statement, sym(5).Expression);
node->doToken = loc(1);
node->whileToken = loc(3);
@@ -1538,7 +1588,7 @@ case 305: {
sym(1).Node = node;
} break;
-case 306: {
+case 314: {
AST::WhileStatement *node = new (pool) AST::WhileStatement(sym(3).Expression, sym(5).Statement);
node->whileToken = loc(1);
node->lparenToken = loc(2);
@@ -1546,7 +1596,7 @@ case 306: {
sym(1).Node = node;
} break;
-case 307: {
+case 315: {
AST::ForStatement *node = new (pool) AST::ForStatement(sym(3).Expression,
sym(5).Expression, sym(7).Expression, sym(9).Statement);
node->forToken = loc(1);
@@ -1557,9 +1607,10 @@ case 307: {
sym(1).Node = node;
} break;
-case 308: {
+case 316: {
+ AST::VariableDeclaration::VariableScope s = AST::VariableDeclaration::FunctionScope;
AST::LocalForStatement *node = new (pool) AST::LocalForStatement(
- sym(4).VariableDeclarationList->finish (/*readOnly=*/false), sym(6).Expression,
+ sym(4).VariableDeclarationList->finish(s), sym(6).Expression,
sym(8).Expression, sym(10).Statement);
node->forToken = loc(1);
node->lparenToken = loc(2);
@@ -1570,7 +1621,7 @@ case 308: {
sym(1).Node = node;
} break;
-case 309: {
+case 317: {
AST:: ForEachStatement *node = new (pool) AST::ForEachStatement(sym(3).Expression,
sym(5).Expression, sym(7).Statement);
node->forToken = loc(1);
@@ -1580,7 +1631,7 @@ case 309: {
sym(1).Node = node;
} break;
-case 310: {
+case 318: {
AST::LocalForEachStatement *node = new (pool) AST::LocalForEachStatement(
sym(4).VariableDeclaration, sym(6).Expression, sym(8).Statement);
node->forToken = loc(1);
@@ -1591,14 +1642,14 @@ case 310: {
sym(1).Node = node;
} break;
-case 312: {
+case 320: {
AST::ContinueStatement *node = new (pool) AST::ContinueStatement();
node->continueToken = loc(1);
node->semicolonToken = loc(2);
sym(1).Node = node;
} break;
-case 314: {
+case 322: {
AST::ContinueStatement *node = new (pool) AST::ContinueStatement(stringRef(2));
node->continueToken = loc(1);
node->identifierToken = loc(2);
@@ -1606,14 +1657,14 @@ case 314: {
sym(1).Node = node;
} break;
-case 316: {
+case 324: {
AST::BreakStatement *node = new (pool) AST::BreakStatement(QStringRef());
node->breakToken = loc(1);
node->semicolonToken = loc(2);
sym(1).Node = node;
} break;
-case 318: {
+case 326: {
AST::BreakStatement *node = new (pool) AST::BreakStatement(stringRef(2));
node->breakToken = loc(1);
node->identifierToken = loc(2);
@@ -1621,14 +1672,14 @@ case 318: {
sym(1).Node = node;
} break;
-case 320: {
+case 328: {
AST::ReturnStatement *node = new (pool) AST::ReturnStatement(sym(2).Expression);
node->returnToken = loc(1);
node->semicolonToken = loc(3);
sym(1).Node = node;
} break;
-case 321: {
+case 329: {
AST::WithStatement *node = new (pool) AST::WithStatement(sym(3).Expression, sym(5).Statement);
node->withToken = loc(1);
node->lparenToken = loc(2);
@@ -1636,7 +1687,7 @@ case 321: {
sym(1).Node = node;
} break;
-case 322: {
+case 330: {
AST::SwitchStatement *node = new (pool) AST::SwitchStatement(sym(3).Expression, sym(5).CaseBlock);
node->switchToken = loc(1);
node->lparenToken = loc(2);
@@ -1644,83 +1695,83 @@ case 322: {
sym(1).Node = node;
} break;
-case 323: {
+case 331: {
AST::CaseBlock *node = new (pool) AST::CaseBlock(sym(2).CaseClauses);
node->lbraceToken = loc(1);
node->rbraceToken = loc(3);
sym(1).Node = node;
} break;
-case 324: {
+case 332: {
AST::CaseBlock *node = new (pool) AST::CaseBlock(sym(2).CaseClauses, sym(3).DefaultClause, sym(4).CaseClauses);
node->lbraceToken = loc(1);
node->rbraceToken = loc(5);
sym(1).Node = node;
} break;
-case 325: {
+case 333: {
sym(1).Node = new (pool) AST::CaseClauses(sym(1).CaseClause);
} break;
-case 326: {
+case 334: {
sym(1).Node = new (pool) AST::CaseClauses(sym(1).CaseClauses, sym(2).CaseClause);
} break;
-case 327: {
+case 335: {
sym(1).Node = 0;
} break;
-case 328: {
+case 336: {
sym(1).Node = sym(1).CaseClauses->finish ();
} break;
-case 329: {
+case 337: {
AST::CaseClause *node = new (pool) AST::CaseClause(sym(2).Expression, sym(4).StatementList);
node->caseToken = loc(1);
node->colonToken = loc(3);
sym(1).Node = node;
} break;
-case 330: {
+case 338: {
AST::DefaultClause *node = new (pool) AST::DefaultClause(sym(3).StatementList);
node->defaultToken = loc(1);
node->colonToken = loc(2);
sym(1).Node = node;
} break;
-case 331: {
+case 339: {
AST::LabelledStatement *node = new (pool) AST::LabelledStatement(stringRef(1), sym(3).Statement);
node->identifierToken = loc(1);
node->colonToken = loc(2);
sym(1).Node = node;
} break;
-case 333: {
+case 341: {
AST::ThrowStatement *node = new (pool) AST::ThrowStatement(sym(2).Expression);
node->throwToken = loc(1);
node->semicolonToken = loc(3);
sym(1).Node = node;
} break;
-case 334: {
+case 342: {
AST::TryStatement *node = new (pool) AST::TryStatement(sym(2).Statement, sym(3).Catch);
node->tryToken = loc(1);
sym(1).Node = node;
} break;
-case 335: {
+case 343: {
AST::TryStatement *node = new (pool) AST::TryStatement(sym(2).Statement, sym(3).Finally);
node->tryToken = loc(1);
sym(1).Node = node;
} break;
-case 336: {
+case 344: {
AST::TryStatement *node = new (pool) AST::TryStatement(sym(2).Statement, sym(3).Catch, sym(4).Finally);
node->tryToken = loc(1);
sym(1).Node = node;
} break;
-case 337: {
+case 345: {
AST::Catch *node = new (pool) AST::Catch(stringRef(3), sym(5).Block);
node->catchToken = loc(1);
node->lparenToken = loc(2);
@@ -1729,20 +1780,20 @@ case 337: {
sym(1).Node = node;
} break;
-case 338: {
+case 346: {
AST::Finally *node = new (pool) AST::Finally(sym(2).Block);
node->finallyToken = loc(1);
sym(1).Node = node;
} break;
-case 340: {
+case 348: {
AST::DebuggerStatement *node = new (pool) AST::DebuggerStatement();
node->debuggerToken = loc(1);
node->semicolonToken = loc(2);
sym(1).Node = node;
} break;
-case 342: {
+case 350: {
AST::FunctionDeclaration *node = new (pool) AST::FunctionDeclaration(stringRef(2), sym(4).FormalParameterList, sym(7).FunctionBody);
node->functionToken = loc(1);
node->identifierToken = loc(2);
@@ -1753,7 +1804,7 @@ case 342: {
sym(1).Node = node;
} break;
-case 343: {
+case 351: {
AST::FunctionExpression *node = new (pool) AST::FunctionExpression(stringRef(2), sym(4).FormalParameterList, sym(7).FunctionBody);
node->functionToken = loc(1);
if (! stringRef(2).isNull())
@@ -1765,7 +1816,7 @@ case 343: {
sym(1).Node = node;
} break;
-case 344: {
+case 352: {
AST::FunctionExpression *node = new (pool) AST::FunctionExpression(QStringRef(), sym(3).FormalParameterList, sym(6).FunctionBody);
node->functionToken = loc(1);
node->lparenToken = loc(2);
@@ -1775,56 +1826,56 @@ case 344: {
sym(1).Node = node;
} break;
-case 345: {
+case 353: {
AST::FormalParameterList *node = new (pool) AST::FormalParameterList(stringRef(1));
node->identifierToken = loc(1);
sym(1).Node = node;
} break;
-case 346: {
+case 354: {
AST::FormalParameterList *node = new (pool) AST::FormalParameterList(sym(1).FormalParameterList, stringRef(3));
node->commaToken = loc(2);
node->identifierToken = loc(3);
sym(1).Node = node;
} break;
-case 347: {
+case 355: {
sym(1).Node = 0;
} break;
-case 348: {
+case 356: {
sym(1).Node = sym(1).FormalParameterList->finish ();
} break;
-case 349: {
+case 357: {
sym(1).Node = 0;
} break;
-case 351: {
+case 359: {
sym(1).Node = new (pool) AST::FunctionBody(sym(1).SourceElements->finish ());
} break;
-case 353: {
+case 361: {
sym(1).Node = new (pool) AST::Program(sym(1).SourceElements->finish ());
} break;
-case 354: {
+case 362: {
sym(1).Node = new (pool) AST::SourceElements(sym(1).SourceElement);
} break;
-case 355: {
+case 363: {
sym(1).Node = new (pool) AST::SourceElements(sym(1).SourceElements, sym(2).SourceElement);
} break;
-case 356: {
+case 364: {
sym(1).Node = new (pool) AST::StatementSourceElement(sym(1).Statement);
} break;
-case 357: {
+case 365: {
sym(1).Node = new (pool) AST::FunctionSourceElement(sym(1).FunctionDeclaration);
} break;
-case 358: {
+case 366: {
sym(1).Node = 0;
} break;
diff --git a/src/qml/parser/qqmljsparser_p.h b/src/qml/parser/qqmljsparser_p.h
index f382cd7563..9dfee70f3a 100644
--- a/src/qml/parser/qqmljsparser_p.h
+++ b/src/qml/parser/qqmljsparser_p.h
@@ -125,6 +125,7 @@ public:
AST::UiArrayMemberList *UiArrayMemberList;
AST::UiQualifiedId *UiQualifiedId;
AST::UiQualifiedPragmaId *UiQualifiedPragmaId;
+ AST::UiEnumMemberList *UiEnumMemberList;
};
public:
@@ -246,9 +247,9 @@ protected:
-#define J_SCRIPT_REGEXPLITERAL_RULE1 91
+#define J_SCRIPT_REGEXPLITERAL_RULE1 96
-#define J_SCRIPT_REGEXPLITERAL_RULE2 92
+#define J_SCRIPT_REGEXPLITERAL_RULE2 97
QT_QML_END_NAMESPACE
diff --git a/src/qml/qml.pro b/src/qml/qml.pro
index e9d7dcbd2d..efea3098af 100644
--- a/src/qml/qml.pro
+++ b/src/qml/qml.pro
@@ -6,7 +6,7 @@ qtConfig(qml-network): \
DEFINES += QT_NO_URL_CAST_FROM_STRING QT_NO_INTEGER_EVENT_COORDINATES
-win32-msvc*|win32-icc:QMAKE_LFLAGS += /BASE:0x66000000
+msvc:equals(QT_ARCH, i386): QMAKE_LFLAGS += /BASE:0x66000000
win32-msvc*:DEFINES *= _CRT_SECURE_NO_WARNINGS
win32:!winrt:LIBS += -lshell32
solaris-cc*:QMAKE_CXXFLAGS_RELEASE -= -O2
diff --git a/src/qml/qml/qqmlbinding.cpp b/src/qml/qml/qqmlbinding.cpp
index 325f752cd5..9453e6480b 100644
--- a/src/qml/qml/qqmlbinding.cpp
+++ b/src/qml/qml/qqmlbinding.cpp
@@ -54,6 +54,7 @@
#include <QVariant>
#include <QtCore/qdebug.h>
+#include <QVector>
QT_BEGIN_NAMESPACE
@@ -195,7 +196,7 @@ class QQmlNonbindingBinding: public QQmlBinding
{
protected:
void doUpdate(const DeleteWatcher &watcher,
- QQmlPropertyData::WriteFlags flags, QV4::Scope &scope) Q_DECL_OVERRIDE Q_DECL_FINAL
+ QQmlPropertyData::WriteFlags flags, QV4::Scope &scope) Q_DECL_OVERRIDE
{
auto ep = QQmlEnginePrivate::get(scope.engine);
ep->referenceScarceResources();
@@ -296,6 +297,55 @@ protected:
}
};
+class QQmlTranslationBinding : public GenericBinding<QMetaType::QString> {
+public:
+ QQmlTranslationBinding(QV4::CompiledData::CompilationUnit *compilationUnit, const QV4::CompiledData::Binding *binding)
+ {
+ setCompilationUnit(compilationUnit);
+ m_binding = binding;
+ setSourceLocation(QQmlSourceLocation(compilationUnit->fileName(), binding->valueLocation.line, binding->valueLocation.column));
+ }
+
+ void doUpdate(const DeleteWatcher &watcher,
+ QQmlPropertyData::WriteFlags flags, QV4::Scope &scope) Q_DECL_OVERRIDE Q_DECL_FINAL
+ {
+ if (watcher.wasDeleted())
+ return;
+
+ if (!isAddedToObject() || hasError())
+ return;
+
+ const QString result = m_binding->valueAsString(m_compilationUnit->data);
+
+ Q_ASSERT(targetObject());
+
+ QQmlPropertyData *pd;
+ QQmlPropertyData vpd;
+ getPropertyData(&pd, &vpd);
+ Q_ASSERT(pd);
+ if (pd->propType() == QMetaType::QString) {
+ doStore(result, pd, flags);
+ } else {
+ QV4::ScopedString value(scope, scope.engine->newString(result));
+ slowWrite(*pd, vpd, value, /*isUndefined*/false, flags);
+ }
+ }
+
+private:
+ const QV4::CompiledData::Binding *m_binding;
+};
+
+QQmlBinding *QQmlBinding::createTranslationBinding(QV4::CompiledData::CompilationUnit *unit, const QV4::CompiledData::Binding *binding, QObject *obj, QQmlContextData *ctxt)
+{
+ QQmlTranslationBinding *b = new QQmlTranslationBinding(unit, binding);
+
+ b->setNotifyOnValueChanged(true);
+ b->QQmlJavaScriptExpression::setContext(ctxt);
+ b->setScopeObject(obj);
+
+ return b;
+}
+
Q_NEVER_INLINE bool QQmlBinding::slowWrite(const QQmlPropertyData &core,
const QQmlPropertyData &valueTypeData,
const QV4::Value &result,
@@ -535,6 +585,37 @@ void QQmlBinding::getPropertyData(QQmlPropertyData **propertyData, QQmlPropertyD
}
}
+QVector<QQmlProperty> QQmlBinding::dependencies() const
+{
+ QVector<QQmlProperty> dependencies;
+ 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;
+
+ QObject *senderObject = guard->senderAsObject();
+ if (!senderObject)
+ 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())));
+ }
+ }
+ }
+ }
+
+ return dependencies;
+}
+
class QObjectPointerBinding: public QQmlNonbindingBinding
{
QQmlMetaObject targetMetaObject;
diff --git a/src/qml/qml/qqmlbinding_p.h b/src/qml/qml/qqmlbinding_p.h
index 0f2fb329f5..38d59a8919 100644
--- a/src/qml/qml/qqmlbinding_p.h
+++ b/src/qml/qml/qqmlbinding_p.h
@@ -77,6 +77,8 @@ public:
const QString &url = QString(), quint16 lineNumber = 0);
static QQmlBinding *create(const QQmlPropertyData *property, QV4::Function *function,
QObject *obj, QQmlContextData *ctxt, QV4::ExecutionContext *scope);
+ static QQmlBinding *createTranslationBinding(QV4::CompiledData::CompilationUnit *unit, const QV4::CompiledData::Binding *binding,
+ QObject *obj, QQmlContextData *ctxt);
~QQmlBinding();
void setTarget(const QQmlProperty &);
@@ -100,6 +102,15 @@ public:
QString expressionIdentifier() const override;
void expressionChanged() override;
+ /**
+ * This method returns a snapshot of the currently tracked dependencies of
+ * this binding. The dependencies can change upon reevaluation. This method is
+ * used in GammaRay to visualize binding hierarchies.
+ *
+ * Call this method from the UI thread.
+ */
+ QVector<QQmlProperty> dependencies() const;
+
protected:
virtual void doUpdate(const DeleteWatcher &watcher,
QQmlPropertyData::WriteFlags flags, QV4::Scope &scope) = 0;
diff --git a/src/qml/qml/qqmlcomponent.cpp b/src/qml/qml/qqmlcomponent.cpp
index 4da6b7958c..e895f1df1b 100644
--- a/src/qml/qml/qqmlcomponent.cpp
+++ b/src/qml/qml/qqmlcomponent.cpp
@@ -1060,20 +1060,52 @@ void QQmlComponent::create(QQmlIncubator &incubator, QQmlContext *context,
enginePriv->incubate(incubator, forContextData);
}
+/*
+ This is essentially a copy of QQmlComponent::create(); except it takes the QQmlContextData
+ arguments instead of QQmlContext which means we don't have to construct the rather weighty
+ wrapper class for every delegate item.
+
+ This is used by QQmlDelegateModel.
+*/
+void QQmlComponentPrivate::incubateObject(
+ QQmlIncubator *incubationTask,
+ QQmlComponent *component,
+ QQmlEngine *engine,
+ QQmlContextData *context,
+ QQmlContextData *forContext)
+{
+ QQmlIncubatorPrivate *incubatorPriv = QQmlIncubatorPrivate::get(incubationTask);
+ QQmlEnginePrivate *enginePriv = QQmlEnginePrivate::get(engine);
+ QQmlComponentPrivate *componentPriv = QQmlComponentPrivate::get(component);
+
+ incubatorPriv->compilationUnit = componentPriv->compilationUnit;
+ incubatorPriv->enginePriv = enginePriv;
+ incubatorPriv->creator.reset(new QQmlObjectCreator(context, componentPriv->compilationUnit, componentPriv->creationContext));
+ incubatorPriv->subComponentToCreate = componentPriv->start;
+
+ enginePriv->incubate(*incubationTask, forContext);
+}
+
+
+
class QQmlComponentIncubator;
namespace QV4 {
namespace Heap {
-struct QmlIncubatorObject : Object {
+#define QmlIncubatorObjectMembers(class, Member) \
+ Member(class, HeapValue, HeapValue, valuemap) \
+ Member(class, HeapValue, HeapValue, statusChanged) \
+ Member(class, Pointer, QmlContext *, qmlContext) \
+ Member(class, NoMark, QQmlComponentIncubator *, incubator) \
+ Member(class, NoMark, QQmlQPointer<QObject>, parent)
+
+DECLARE_HEAP_OBJECT(QmlIncubatorObject, Object) {
+ DECLARE_MARK_TABLE(QmlIncubatorObject);
+
void init(QQmlIncubator::IncubationMode = QQmlIncubator::Asynchronous);
inline void destroy();
- QQmlComponentIncubator *incubator;
- QQmlQPointer<QObject> parent;
- QV4::Value valuemap;
- QV4::Value statusChanged;
- Pointer<Heap::QmlContext> qmlContext;
};
}
@@ -1089,8 +1121,6 @@ struct QmlIncubatorObject : public QV4::Object
static void method_get_object(const BuiltinFunction *, Scope &scope, CallData *callData);
static void method_forceCompletion(const BuiltinFunction *, Scope &scope, CallData *callData);
- static void markObjects(QV4::Heap::Base *that, QV4::ExecutionEngine *e);
-
void statusChanged(QQmlIncubator::Status);
void setInitialState(QObject *);
};
@@ -1394,8 +1424,8 @@ void QQmlComponent::incubateObject(QQmlV4Function *args)
r->setPrototype(p);
if (!valuemap->isUndefined())
- r->d()->valuemap = valuemap;
- r->d()->qmlContext = v4->qmlContext();
+ r->d()->valuemap.set(scope.engine, valuemap);
+ r->d()->qmlContext.set(scope.engine, v4->qmlContext());
r->d()->parent = parent;
QQmlIncubator *incubator = r->d()->incubator;
@@ -1479,7 +1509,7 @@ void QV4::QmlIncubatorObject::method_set_statusChanged(const BuiltinFunction *,
if (!o || callData->argc < 1)
THROW_TYPE_ERROR();
- o->d()->statusChanged = callData->args[0];
+ o->d()->statusChanged.set(scope.engine, callData->args[0]);
RETURN_UNDEFINED();
}
@@ -1491,10 +1521,10 @@ QQmlComponentExtension::~QQmlComponentExtension()
void QV4::Heap::QmlIncubatorObject::init(QQmlIncubator::IncubationMode m)
{
Object::init();
- valuemap = QV4::Primitive::undefinedValue();
- statusChanged = QV4::Primitive::undefinedValue();
+ valuemap.set(internalClass->engine, QV4::Primitive::undefinedValue());
+ statusChanged.set(internalClass->engine, QV4::Primitive::undefinedValue());
parent.init();
- qmlContext = nullptr;
+ qmlContext.set(internalClass->engine, nullptr);
incubator = new QQmlComponentIncubator(this, m);
}
@@ -1517,16 +1547,6 @@ void QV4::QmlIncubatorObject::setInitialState(QObject *o)
}
}
-void QV4::QmlIncubatorObject::markObjects(QV4::Heap::Base *that, QV4::ExecutionEngine *e)
-{
- QmlIncubatorObject::Data *o = static_cast<QmlIncubatorObject::Data *>(that);
- o->valuemap.mark(e);
- o->statusChanged.mark(e);
- if (o->qmlContext)
- o->qmlContext->mark(e);
- Object::markObjects(that, e);
-}
-
void QV4::QmlIncubatorObject::statusChanged(QQmlIncubator::Status s)
{
QV4::Scope scope(engine());
diff --git a/src/qml/qml/qqmlcomponent_p.h b/src/qml/qml/qqmlcomponent_p.h
index 2a57f7b247..8a58a1ada0 100644
--- a/src/qml/qml/qqmlcomponent_p.h
+++ b/src/qml/qml/qqmlcomponent_p.h
@@ -88,6 +88,13 @@ public:
void initializeObjectWithInitialProperties(QV4::QmlContext *qmlContext, const QV4::Value &valuemap, QObject *toCreate);
static void setInitialProperties(QV4::ExecutionEngine *engine, QV4::QmlContext *qmlContext, const QV4::Value &o, const QV4::Value &v);
+ void incubateObject(
+ QQmlIncubator *incubationTask,
+ QQmlComponent *component,
+ QQmlEngine *engine,
+ QQmlContextData *context,
+ QQmlContextData *forContext);
+
QQmlTypeData *typeData;
void typeDataReady(QQmlTypeData *) override;
void typeDataProgress(QQmlTypeData *, qreal) override;
diff --git a/src/qml/qml/qqmlcustomparser.cpp b/src/qml/qml/qqmlcustomparser.cpp
index ecdaf41523..cc6e75a39c 100644
--- a/src/qml/qml/qqmlcustomparser.cpp
+++ b/src/qml/qml/qqmlcustomparser.cpp
@@ -121,13 +121,16 @@ int QQmlCustomParser::evaluateEnum(const QByteArray& script, bool *ok) const
{
Q_ASSERT_X(ok, "QQmlCustomParser::evaluateEnum", "ok must not be a null pointer");
*ok = false;
+
+ // we support one or two '.' in the enum phrase:
+ // * <TypeName>.<EnumValue>
+ // * <TypeName>.<ScopedEnumName>.<EnumValue>
+
int dot = script.indexOf('.');
- if (dot == -1)
+ if (dot == -1 || dot == script.length()-1)
return -1;
-
QString scope = QString::fromUtf8(script.left(dot));
- QByteArray enumValue = script.mid(dot+1);
if (scope != QLatin1String("Qt")) {
if (imports.isNull())
@@ -142,9 +145,20 @@ int QQmlCustomParser::evaluateEnum(const QByteArray& script, bool *ok) const
type = result.type;
}
- return type.enumValue(engine, QHashedCStringRef(enumValue.constData(), enumValue.length()), ok);
+ if (!type.isValid())
+ return -1;
+
+ int dot2 = script.indexOf('.', dot+1);
+ const bool dot2Valid = dot2 != -1 && dot2 != script.length()-1;
+ QByteArray enumValue = script.mid(dot2Valid ? dot2 + 1 : dot + 1);
+ QByteArray scopedEnumName = (dot2Valid ? script.mid(dot + 1, dot2 - dot - 1) : QByteArray());
+ if (!scopedEnumName.isEmpty())
+ return type.scopedEnumValue(engine, scopedEnumName, enumValue, ok);
+ else
+ return type.enumValue(engine, QHashedCStringRef(enumValue.constData(), enumValue.length()), ok);
}
+ QByteArray enumValue = script.mid(dot + 1);
const QMetaObject *mo = StaticQtMetaObject::get();
int i = mo->enumeratorCount();
while (i--) {
diff --git a/src/qml/qml/qqmlengine.cpp b/src/qml/qml/qqmlengine.cpp
index f4656bafd2..8e3b0a790f 100644
--- a/src/qml/qml/qqmlengine.cpp
+++ b/src/qml/qml/qqmlengine.cpp
@@ -453,6 +453,12 @@ The following functions are also on the Qt object.
\li \c "windows" - Windows
\li \c "winrt" - WinRT / UWP
\endlist
+
+ \row
+ \li \c platform.pluginName
+ \li This is the name of the platform set on the QGuiApplication instance
+ as returned by \l QGuiApplication::platformName()
+
\endtable
*/
@@ -778,7 +784,7 @@ class QQmlThreadNotifierProxyObject : public QObject
public:
QPointer<QObject> target;
- virtual int qt_metacall(QMetaObject::Call, int methodIndex, void **a) {
+ int qt_metacall(QMetaObject::Call, int methodIndex, void **a) override {
if (!target)
return -1;
@@ -1351,6 +1357,30 @@ void QQmlEngine::setOutputWarningsToStandardError(bool enabled)
}
/*!
+ Refreshes all binding expressions that use strings marked for translation.
+
+ Call this function after you have installed a new translator with
+ QCoreApplication::installTranslator, to ensure that your user-interface
+ shows up-to-date translations.
+
+ \note Due to a limitation in the implementation, this function
+ refreshes all the engine's bindings, not only those that use strings
+ marked for translation.
+ This may be optimized in a future release.
+
+ \since 5.10
+*/
+void QQmlEngine::retranslate()
+{
+ Q_D(QQmlEngine);
+ QQmlContextData *context = QQmlContextData::get(d->rootContext)->childContexts;
+ while (context) {
+ context->refreshExpressions();
+ context = context->nextChild;
+ }
+}
+
+/*!
Returns the QQmlContext for the \a object, or 0 if no
context has been set.
@@ -1470,6 +1500,9 @@ bool QQmlEngine::event(QEvent *e)
Q_D(QQmlEngine);
if (e->type() == QEvent::User)
d->doDeleteInEngineThread();
+ else if (e->type() == QEvent::LanguageChange) {
+ retranslate();
+ }
return QJSEngine::event(e);
}
@@ -1519,9 +1552,9 @@ QQmlEngine *qmlEngine(const QObject *obj)
QObject *qmlAttachedPropertiesObjectById(int id, const QObject *object, bool create)
{
- QQmlData *data = QQmlData::get(object);
+ QQmlData *data = QQmlData::get(object, create);
if (!data)
- return 0; // Attached properties are only on objects created by QML
+ return 0; // Attached properties are only on objects created by QML, unless explicitly requested (create==true)
QObject *rv = data->hasExtendedData()?data->attachedProperties()->value(id):0;
if (rv || !create)
diff --git a/src/qml/qml/qqmlengine.h b/src/qml/qml/qqmlengine.h
index 8cada954fe..2bf4c0497b 100644
--- a/src/qml/qml/qqmlengine.h
+++ b/src/qml/qml/qqmlengine.h
@@ -144,6 +144,10 @@ public:
bool outputWarningsToStandardError() const;
void setOutputWarningsToStandardError(bool);
+public Q_SLOTS:
+ void retranslate();
+
+public:
static QQmlContext *contextForObject(const QObject *);
static void setContextForObject(QObject *, QQmlContext *);
diff --git a/src/qml/qml/qqmlglobal.cpp b/src/qml/qml/qqmlglobal.cpp
index 7939656107..6418812bae 100644
--- a/src/qml/qml/qqmlglobal.cpp
+++ b/src/qml/qml/qqmlglobal.cpp
@@ -343,6 +343,8 @@ QObject *QQmlGuiProvider::styleHints()
return o;
}
+QString QQmlGuiProvider::pluginName() const { return QString(); }
+
static QQmlGuiProvider *guiProvider = 0;
Q_QML_PRIVATE_EXPORT QQmlGuiProvider *QQml_setGuiProvider(QQmlGuiProvider *newProvider)
diff --git a/src/qml/qml/qqmlglobal_p.h b/src/qml/qml/qqmlglobal_p.h
index 707814e781..5c46da0ea4 100644
--- a/src/qml/qml/qqmlglobal_p.h
+++ b/src/qml/qml/qqmlglobal_p.h
@@ -193,16 +193,6 @@ do { \
return QObjectPrivate::get(sender)->isSignalConnected(signalIdx); \
} while (0)
-struct QQmlGraphics_DerivedObject : public QObject
-{
- void setParent_noEvent(QObject *parent) {
- bool sce = d_ptr->sendChildEvents;
- d_ptr->sendChildEvents = false;
- setParent(parent);
- d_ptr->sendChildEvents = sce;
- }
-};
-
/*!
Returns true if the case of \a fileName is equivalent to the file case of
\a fileName on disk, and false otherwise.
@@ -230,7 +220,11 @@ bool QQml_isFileCaseCorrect(const QString &fileName, int length = -1);
*/
inline void QQml_setParent_noEvent(QObject *object, QObject *parent)
{
- static_cast<QQmlGraphics_DerivedObject *>(object)->setParent_noEvent(parent);
+ QObjectPrivate *d_ptr = QObjectPrivate::get(object);
+ bool sce = d_ptr->sendChildEvents;
+ d_ptr->sendChildEvents = false;
+ object->setParent(parent);
+ d_ptr->sendChildEvents = sce;
}
class Q_QML_PRIVATE_EXPORT QQmlValueTypeProvider
@@ -311,6 +305,7 @@ public:
virtual QObject *styleHints();
virtual QStringList fontFamilies();
virtual bool openUrlExternally(QUrl &);
+ virtual QString pluginName() const;
};
Q_QML_PRIVATE_EXPORT QQmlGuiProvider *QQml_setGuiProvider(QQmlGuiProvider *);
diff --git a/src/qml/qml/qqmlimport.cpp b/src/qml/qml/qqmlimport.cpp
index f43ffb4c3c..b899e80470 100644
--- a/src/qml/qml/qqmlimport.cpp
+++ b/src/qml/qml/qqmlimport.cpp
@@ -296,7 +296,9 @@ public:
bool resolveType(const QHashedStringRef &type, int *vmajor, int *vminor,
QQmlType *type_return, QList<QQmlError> *errors,
- QQmlType::RegistrationType registrationType);
+ QQmlType::RegistrationType registrationType,
+ QQmlImport::RecursionRestriction recursionRestriction
+ = QQmlImport::PreventRecursion);
QUrl baseUrl;
QString base;
@@ -634,7 +636,8 @@ QString QQmlImports::versionString(int vmaj, int vmin, ImportVersion version)
bool QQmlImports::resolveType(const QHashedStringRef &type,
QQmlType *type_return, int *vmaj, int *vmin,
QQmlImportNamespace** ns_return, QList<QQmlError> *errors,
- QQmlType::RegistrationType registrationType) const
+ QQmlType::RegistrationType registrationType,
+ QQmlImport::RecursionRestriction recursionRestriction) const
{
QQmlImportNamespace* ns = d->findQualifiedNamespace(type);
if (ns) {
@@ -643,7 +646,8 @@ bool QQmlImports::resolveType(const QHashedStringRef &type,
return true;
}
if (type_return) {
- if (d->resolveType(type, vmaj, vmin, type_return, errors, registrationType)) {
+ if (d->resolveType(type, vmaj, vmin, type_return, errors, registrationType,
+ recursionRestriction)) {
if (qmlImportTrace()) {
#define RESOLVE_TYPE_DEBUG qDebug().nospace() << "QQmlImports(" << qPrintable(baseUrl().toString()) \
<< ')' << "::resolveType: " << type.toString() << " => "
@@ -728,9 +732,10 @@ bool QQmlImports::resolveType(QQmlImportNamespace *ns, const QHashedStringRef &t
}
bool QQmlImportInstance::resolveType(QQmlTypeLoader *typeLoader, const QHashedStringRef& type,
- int *vmajor, int *vminor, QQmlType* type_return, QString *base,
+ int *vmajor, int *vminor, QQmlType *type_return, QString *base,
bool *typeRecursionDetected,
- QQmlType::RegistrationType registrationType) const
+ QQmlType::RegistrationType registrationType,
+ QQmlImport::RecursionRestriction recursionRestriction) const
{
if (majversion >= 0 && minversion >= 0) {
QQmlType t = QQmlMetaType::qmlType(type, uri, majversion, minversion);
@@ -766,6 +771,7 @@ bool QQmlImportInstance::resolveType(QQmlTypeLoader *typeLoader, const QHashedSt
// importing version -1 means import ALL versions
if ((majversion == -1) ||
+ (implicitlyImported && c.internal) || // allow the implicit import of internal types
(c.majorVersion == majversion && c.minorVersion <= minversion)) {
// Is this better than the previous candidate?
if ((candidate == end) ||
@@ -777,7 +783,7 @@ bool QQmlImportInstance::resolveType(QQmlTypeLoader *typeLoader, const QHashedSt
if (resolveLocalUrl(*base, c.fileName) != componentUrl)
continue; // failed attempt to access an internal type
}
- if (*base == componentUrl) {
+ if (recursionRestriction == QQmlImport::PreventRecursion && *base == componentUrl) {
if (typeRecursionDetected)
*typeRecursionDetected = true;
continue; // no recursion
@@ -820,7 +826,7 @@ bool QQmlImportInstance::resolveType(QQmlTypeLoader *typeLoader, const QHashedSt
}
if (exists) {
- if (base && (*base == qmlUrl)) { // no recursion
+ if (recursionRestriction == QQmlImport::PreventRecursion && base && (*base == qmlUrl)) { // no recursion
if (typeRecursionDetected)
*typeRecursionDetected = true;
} else {
@@ -838,7 +844,8 @@ bool QQmlImportInstance::resolveType(QQmlTypeLoader *typeLoader, const QHashedSt
bool QQmlImportsPrivate::resolveType(const QHashedStringRef& type, int *vmajor, int *vminor,
QQmlType *type_return, QList<QQmlError> *errors,
- QQmlType::RegistrationType registrationType)
+ QQmlType::RegistrationType registrationType,
+ QQmlImport::RecursionRestriction recursionRestriction)
{
QQmlImportNamespace *s = 0;
int dot = type.indexOf(Dot);
@@ -868,7 +875,7 @@ bool QQmlImportsPrivate::resolveType(const QHashedStringRef& type, int *vmajor,
QHashedStringRef unqualifiedtype = dot < 0 ? type : QHashedStringRef(type.constData()+dot+1, type.length()-dot-1);
if (s) {
if (s->resolveType(typeLoader, unqualifiedtype, vmajor, vminor, type_return, &base, errors,
- registrationType))
+ registrationType, recursionRestriction))
return true;
if (s->imports.count() == 1 && !s->imports.at(0)->isLibrary && type_return && s != &unqualifiedset) {
// qualified, and only 1 url
@@ -892,13 +899,14 @@ QQmlImportInstance *QQmlImportNamespace::findImport(const QString &uri) const
bool QQmlImportNamespace::resolveType(QQmlTypeLoader *typeLoader, const QHashedStringRef &type,
int *vmajor, int *vminor, QQmlType *type_return,
QString *base, QList<QQmlError> *errors,
- QQmlType::RegistrationType registrationType)
+ QQmlType::RegistrationType registrationType,
+ QQmlImport::RecursionRestriction recursionRestriction)
{
bool typeRecursionDetected = false;
for (int i=0; i<imports.count(); ++i) {
const QQmlImportInstance *import = imports.at(i);
- if (import->resolveType(typeLoader, type, vmajor, vminor, type_return,
- base, &typeRecursionDetected, registrationType)) {
+ if (import->resolveType(typeLoader, type, vmajor, vminor, type_return, base,
+ &typeRecursionDetected, registrationType, recursionRestriction)) {
if (qmlCheckTypes()) {
// check for type clashes
for (int j = i+1; j<imports.count(); ++j) {
@@ -1223,10 +1231,12 @@ QString QQmlImportsPrivate::resolvedUri(const QString &dir_arg, QQmlImportDataba
stableRelativePath.replace(Backslash, Slash);
// remove optional versioning in dot notation from uri
- int lastSlash = stableRelativePath.lastIndexOf(Slash);
- if (lastSlash >= 0) {
- int versionDot = stableRelativePath.indexOf(Dot, lastSlash);
- if (versionDot >= 0)
+ int versionDot = stableRelativePath.lastIndexOf(Dot);
+ if (versionDot >= 0) {
+ int nextSlash = stableRelativePath.indexOf(Slash, versionDot);
+ if (nextSlash >= 0)
+ stableRelativePath.remove(versionDot, nextSlash - versionDot);
+ else
stableRelativePath = stableRelativePath.left(versionDot);
}
@@ -1537,6 +1547,20 @@ bool QQmlImportsPrivate::addFileImport(const QString& uri, const QString &prefix
if (!url.endsWith(Slash) && !url.endsWith(Backslash))
url += Slash;
+ // ### For enum support, we are now adding the implicit import always (and earlier). Bail early
+ // if the implicit import has already been explicitly added, otherwise we can run into issues
+ // with duplicate imports. However remember that we attempted to add this as implicit import, to
+ // allow for the loading of internal types.
+ if (isImplicitImport) {
+ for (QList<QQmlImportInstance *>::const_iterator it = nameSpace->imports.constBegin();
+ it != nameSpace->imports.constEnd(); ++it) {
+ if ((*it)->url == url) {
+ (*it)->implicitlyImported = true;
+ return true;
+ }
+ }
+ }
+
QQmlImportInstance *inserted = addImportToNamespace(nameSpace, importUri, url, vmaj, vmin, QV4::CompiledData::Import::ImportFile, errors, isImplicitImport);
Q_ASSERT(inserted);
@@ -1738,13 +1762,13 @@ QQmlImportDatabase::QQmlImportDatabase(QQmlEngine *e)
// env import paths
if (Q_UNLIKELY(!qEnvironmentVariableIsEmpty("QML2_IMPORT_PATH"))) {
- const QByteArray envImportPath = qgetenv("QML2_IMPORT_PATH");
+ const QString envImportPath = qEnvironmentVariable("QML2_IMPORT_PATH");
#if defined(Q_OS_WIN)
QLatin1Char pathSep(';');
#else
QLatin1Char pathSep(':');
#endif
- QStringList paths = QString::fromLatin1(envImportPath).split(pathSep, QString::SkipEmptyParts);
+ QStringList paths = envImportPath.split(pathSep, QString::SkipEmptyParts);
for (int ii = paths.count() - 1; ii >= 0; --ii)
addImportPath(paths.at(ii));
}
diff --git a/src/qml/qml/qqmlimport_p.h b/src/qml/qml/qqmlimport_p.h
index 9cb5340c68..6298dd9c22 100644
--- a/src/qml/qml/qqmlimport_p.h
+++ b/src/qml/qml/qqmlimport_p.h
@@ -70,6 +70,10 @@ class QQmlImportDatabase;
class QQmlTypeLoader;
class QQmlTypeLoaderQmldirContent;
+namespace QQmlImport {
+ enum RecursionRestriction { PreventRecursion, AllowRecursion };
+}
+
struct QQmlImportInstance
{
QString uri; // e.g. QtQuick
@@ -77,6 +81,7 @@ struct QQmlImportInstance
int majversion; // the major version imported
int minversion; // the minor version imported
bool isLibrary; // true means that this is not a file import
+ bool implicitlyImported = false;
QQmlDirComponents qmlDirComponents; // a copy of the components listed in the qmldir
QQmlDirScripts qmlDirScripts; // a copy of the scripts in the qmldir
@@ -88,7 +93,8 @@ struct QQmlImportInstance
bool resolveType(QQmlTypeLoader *typeLoader, const QHashedStringRef &type,
int *vmajor, int *vminor, QQmlType* type_return,
QString *base = 0, bool *typeRecursionDetected = 0,
- QQmlType::RegistrationType = QQmlType::AnyRegistrationType) const;
+ QQmlType::RegistrationType = QQmlType::AnyRegistrationType,
+ QQmlImport::RecursionRestriction recursionRestriction = QQmlImport::PreventRecursion) const;
};
class QQmlImportNamespace
@@ -104,8 +110,8 @@ public:
bool resolveType(QQmlTypeLoader *typeLoader, const QHashedStringRef& type,
int *vmajor, int *vminor, QQmlType* type_return,
QString *base = 0, QList<QQmlError> *errors = 0,
- QQmlType::RegistrationType registrationType
- = QQmlType::AnyRegistrationType);
+ QQmlType::RegistrationType registrationType = QQmlType::AnyRegistrationType,
+ QQmlImport::RecursionRestriction recursionRestriction = QQmlImport::PreventRecursion);
// Prefix when used as a qualified import. Otherwise empty.
QHashedString prefix;
@@ -132,8 +138,9 @@ public:
int *version_major, int *version_minor,
QQmlImportNamespace **ns_return,
QList<QQmlError> *errors = 0,
- QQmlType::RegistrationType registrationType
- = QQmlType::AnyRegistrationType) const;
+ QQmlType::RegistrationType registrationType = QQmlType::AnyRegistrationType,
+ QQmlImport::RecursionRestriction recursionRestriction
+ = QQmlImport::PreventRecursion) const;
bool resolveType(QQmlImportNamespace *,
const QHashedStringRef& type,
QQmlType *type_return, int *version_major, int *version_minor,
diff --git a/src/qml/qml/qqmljavascriptexpression.cpp b/src/qml/qml/qqmljavascriptexpression.cpp
index eec5d1ae57..31c277d283 100644
--- a/src/qml/qml/qqmljavascriptexpression.cpp
+++ b/src/qml/qml/qqmljavascriptexpression.cpp
@@ -350,7 +350,7 @@ void QQmlPropertyCapture::registerQmlDependencies(const QV4::CompiledData::Funct
QV4::Scoped<QV4::QmlContext> context(scope, engine->qmlContext());
QQmlContextData *qmlContext = context->qmlContext();
- const QV4::CompiledData::LEUInt32 *idObjectDependency = compiledFunction->qmlIdObjectDependencyTable();
+ 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);
@@ -359,7 +359,7 @@ void QQmlPropertyCapture::registerQmlDependencies(const QV4::CompiledData::Funct
}
Q_ASSERT(qmlContext->contextObject);
- const QV4::CompiledData::LEUInt32 *contextPropertyDependency = compiledFunction->qmlContextPropertiesDependencyTable();
+ const quint32_le *contextPropertyDependency = compiledFunction->qmlContextPropertiesDependencyTable();
const int contextPropertyDependencyCount = compiledFunction->nDependingContextProperties;
for (int i = 0; i < contextPropertyDependencyCount; ++i) {
const int propertyIndex = *contextPropertyDependency++;
@@ -369,7 +369,7 @@ void QQmlPropertyCapture::registerQmlDependencies(const QV4::CompiledData::Funct
}
QObject *scopeObject = context->qmlScope();
- const QV4::CompiledData::LEUInt32 *scopePropertyDependency = compiledFunction->qmlScopePropertiesDependencyTable();
+ const quint32_le *scopePropertyDependency = compiledFunction->qmlScopePropertiesDependencyTable();
const int scopePropertyDependencyCount = compiledFunction->nDependingScopeProperties;
for (int i = 0; i < scopePropertyDependencyCount; ++i) {
const int propertyIndex = *scopePropertyDependency++;
@@ -461,7 +461,12 @@ void QQmlJavaScriptExpression::setupFunction(QV4::ExecutionContext *qmlContext,
return;
m_qmlScope.set(qmlContext->engine(), *qmlContext);
m_v4Function = f;
- m_compilationUnit = m_v4Function->compilationUnit;
+ setCompilationUnit(m_v4Function->compilationUnit);
+}
+
+void QQmlJavaScriptExpression::setCompilationUnit(QV4::CompiledData::CompilationUnit *compilationUnit)
+{
+ m_compilationUnit = compilationUnit;
}
void QQmlJavaScriptExpression::clearActiveGuards()
diff --git a/src/qml/qml/qqmljavascriptexpression_p.h b/src/qml/qml/qqmljavascriptexpression_p.h
index eeed272793..e9a9f4feee 100644
--- a/src/qml/qml/qqmljavascriptexpression_p.h
+++ b/src/qml/qml/qqmljavascriptexpression_p.h
@@ -160,13 +160,7 @@ protected:
}
void setupFunction(QV4::ExecutionContext *qmlContext, QV4::Function *f);
-
-private:
- friend class QQmlContextData;
- friend class QQmlPropertyCapture;
- friend void QQmlJavaScriptExpressionGuard_callback(QQmlNotifierEndpoint *, void **);
-
- QQmlDelayedError *m_error;
+ void setCompilationUnit(QV4::CompiledData::CompilationUnit *compilationUnit);
// We store some flag bits in the following flag pointers.
// activeGuards:flag1 - notifyOnValueChanged
@@ -175,6 +169,14 @@ private:
QForwardFieldList<QQmlJavaScriptExpressionGuard, &QQmlJavaScriptExpressionGuard::next> activeGuards;
QForwardFieldList<QQmlJavaScriptExpressionGuard, &QQmlJavaScriptExpressionGuard::next> permanentGuards;
+private:
+ friend class QQmlContextData;
+ friend class QQmlPropertyCapture;
+ friend void QQmlJavaScriptExpressionGuard_callback(QQmlNotifierEndpoint *, void **);
+ friend class QQmlTranslationBinding;
+
+ QQmlDelayedError *m_error;
+
QQmlContextData *m_context;
QQmlJavaScriptExpression **m_prevExpression;
QQmlJavaScriptExpression *m_nextExpression;
diff --git a/src/qml/qml/qqmllistwrapper.cpp b/src/qml/qml/qqmllistwrapper.cpp
index d94f7c56e4..43677e0d78 100644
--- a/src/qml/qml/qqmllistwrapper.cpp
+++ b/src/qml/qml/qqmllistwrapper.cpp
@@ -140,12 +140,13 @@ ReturnedValue QmlListWrapper::getIndexed(const Managed *m, uint index, bool *has
return Primitive::undefinedValue().asReturnedValue();
}
-void QmlListWrapper::put(Managed *m, String *name, const Value &value)
+bool QmlListWrapper::put(Managed *m, String *name, const Value &value)
{
// doesn't do anything. Should we throw?
Q_UNUSED(m);
Q_UNUSED(name);
Q_UNUSED(value);
+ return false;
}
void QmlListWrapper::advanceIterator(Managed *m, ObjectIterator *it, Value *name, uint *index, Property *p, PropertyAttributes *attrs)
diff --git a/src/qml/qml/qqmllistwrapper_p.h b/src/qml/qml/qqmllistwrapper_p.h
index b914c681f2..84dadba01a 100644
--- a/src/qml/qml/qqmllistwrapper_p.h
+++ b/src/qml/qml/qqmllistwrapper_p.h
@@ -95,7 +95,7 @@ struct Q_QML_EXPORT QmlListWrapper : Object
static ReturnedValue get(const Managed *m, String *name, bool *hasProperty);
static ReturnedValue getIndexed(const Managed *m, uint index, bool *hasProperty);
- static void put(Managed *m, String *name, const Value &value);
+ static bool put(Managed *m, String *name, const Value &value);
static void advanceIterator(Managed *m, ObjectIterator *it, Value *name, uint *index, Property *p, PropertyAttributes *attributes);
};
diff --git a/src/qml/qml/qqmlmetatype.cpp b/src/qml/qml/qqmlmetatype.cpp
index 89f3ced2d6..f368e6dae6 100644
--- a/src/qml/qml/qqmlmetatype.cpp
+++ b/src/qml/qml/qqmlmetatype.cpp
@@ -170,8 +170,9 @@ public:
~QQmlTypePrivate();
void init() const;
- void initEnums() const;
+ void initEnums(const QQmlPropertyCache *cache = 0) const;
void insertEnums(const QMetaObject *metaObject) const;
+ void insertEnumsFromPropertyCache(const QQmlPropertyCache *cache) const;
QAtomicInt refCount;
QQmlType::RegistrationType regType;
@@ -227,6 +228,8 @@ public:
mutable bool haveSuperType:1;
mutable QList<QQmlProxyMetaObject::ProxyData> metaObjects;
mutable QStringHash<int> enums;
+ mutable QStringHash<int> scopedEnumIndex; // maps from enum name to index in scopedEnums
+ mutable QList<QStringHash<int>*> scopedEnums;
static QHash<const QMetaObject *, int> attachedPropertyIds;
@@ -271,8 +274,10 @@ void QQmlType::SingletonInstanceInfo::init(QQmlEngine *e)
QQmlData::ensurePropertyCache(e, o);
} else if (!url.isEmpty() && !qobjectApi(e)) {
QQmlComponent component(e, url, QQmlComponent::PreferSynchronous);
- QObject *o = component.create();
+ QObject *o = component.beginCreate(e->rootContext());
setQObjectApi(e, o);
+ if (o)
+ component.completeCreate();
}
v4->popContext();
}
@@ -348,6 +353,7 @@ QQmlTypePrivate::QQmlTypePrivate(QQmlType::RegistrationType type)
QQmlTypePrivate::~QQmlTypePrivate()
{
+ qDeleteAll(scopedEnums);
switch (regType) {
case QQmlType::CppType:
delete extraData.cd->customParser;
@@ -578,14 +584,17 @@ QQmlType QQmlType::resolveCompositeBaseType(QQmlEnginePrivate *engine) const
return QQmlMetaType::qmlType(mo);
}
-int QQmlType::resolveCompositeEnumValue(QQmlEnginePrivate *engine, const QString &name, bool *ok) const
+QQmlPropertyCache *QQmlType::compositePropertyCache(QQmlEnginePrivate *engine) const
{
+ // similar logic to resolveCompositeBaseType
Q_ASSERT(isComposite());
- if (!d)
- return -1;
- *ok = false;
- QQmlType type = resolveCompositeBaseType(engine);
- return type.enumValue(engine, name, ok);
+ if (!engine)
+ return 0;
+ QQmlRefPointer<QQmlTypeData> td(engine->typeLoader.getType(sourceUrl()), QQmlRefPointer<QQmlTypeData>::Adopt);
+ if (td.isNull() || !td->isComplete())
+ return 0;
+ QV4::CompiledData::CompilationUnit *compilationUnit = td->compilationUnit();
+ return compilationUnit->rootPropertyCache();
}
static void clone(QMetaObjectBuilder &builder, const QMetaObject *mo,
@@ -754,7 +763,7 @@ void QQmlTypePrivate::init() const
lock.unlock();
}
-void QQmlTypePrivate::initEnums() const
+void QQmlTypePrivate::initEnums(const QQmlPropertyCache *cache) const
{
if (isEnumSetup) return;
@@ -763,6 +772,8 @@ void QQmlTypePrivate::initEnums() const
QMutexLocker lock(metaTypeDataLock());
if (isEnumSetup) return;
+ if (cache)
+ insertEnumsFromPropertyCache(cache);
if (baseMetaObject) // could be singleton type without metaobject
insertEnums(baseMetaObject);
@@ -783,11 +794,49 @@ void QQmlTypePrivate::insertEnums(const QMetaObject *metaObject) const
// Add any enum values defined by this class, overwriting any inherited values
for (int ii = 0; ii < metaObject->enumeratorCount(); ++ii) {
QMetaEnum e = metaObject->enumerator(ii);
- for (int jj = 0; jj < e.keyCount(); ++jj)
- enums.insert(QString::fromUtf8(e.key(jj)), e.value(jj));
+ const bool isScoped = e.isScoped();
+ QStringHash<int> *scoped = isScoped ? new QStringHash<int>() : 0;
+
+ for (int jj = 0; jj < e.keyCount(); ++jj) {
+ const QString key = QString::fromUtf8(e.key(jj));
+ const int value = e.value(jj);
+ enums.insert(key, value);
+ if (isScoped)
+ scoped->insert(key, value);
+ }
+
+ if (isScoped) {
+ scopedEnums << scoped;
+ scopedEnumIndex.insert(QString::fromUtf8(e.name()), scopedEnums.count()-1);
+ }
+ }
+}
+
+void QQmlTypePrivate::insertEnumsFromPropertyCache(const QQmlPropertyCache *cache) const
+{
+ const QMetaObject *cppMetaObject = cache->firstCppMetaObject();
+
+ while (cache && cache->metaObject() != cppMetaObject) {
+
+ int count = cache->qmlEnumCount();
+ for (int ii = 0; ii < count; ++ii) {
+ QStringHash<int> *scoped = new QStringHash<int>();
+ QQmlEnumData *enumData = cache->qmlEnum(ii);
+
+ for (int jj = 0; jj < enumData->values.count(); ++jj) {
+ const QQmlEnumValue &value = enumData->values.at(jj);
+ enums.insert(value.namedValue, value.value);
+ scoped->insert(value.namedValue, value.value);
+ }
+ scopedEnums << scoped;
+ scopedEnumIndex.insert(enumData->name, scopedEnums.count()-1);
+ }
+ cache = cache->parent();
}
+ insertEnums(cppMetaObject);
}
+
QQmlPropertyCache *QQmlTypePrivate::propertyCacheForMinorVersion(int minorVersion) const
{
for (int i = 0; i < propertyCaches.count(); ++i)
@@ -1079,11 +1128,11 @@ int QQmlType::enumValue(QQmlEnginePrivate *engine, const QHashedStringRef &name,
{
Q_ASSERT(ok);
if (d) {
- if (isComposite())
- return resolveCompositeEnumValue(engine, name.toString(), ok);
+ const QQmlPropertyCache *cache = isComposite() ? compositePropertyCache(engine) : 0;
+
*ok = true;
- d->initEnums();
+ d->initEnums(cache);
int *rv = d->enums.value(name);
if (rv)
@@ -1098,11 +1147,11 @@ int QQmlType::enumValue(QQmlEnginePrivate *engine, const QHashedCStringRef &name
{
Q_ASSERT(ok);
if (d) {
- if (isComposite())
- return resolveCompositeEnumValue(engine, name.toUtf16(), ok);
+ const QQmlPropertyCache *cache = isComposite() ? compositePropertyCache(engine) : 0;
+
*ok = true;
- d->initEnums();
+ d->initEnums(cache);
int *rv = d->enums.value(name);
if (rv)
@@ -1117,11 +1166,10 @@ int QQmlType::enumValue(QQmlEnginePrivate *engine, const QV4::String *name, bool
{
Q_ASSERT(ok);
if (d) {
- if (isComposite())
- return resolveCompositeEnumValue(engine, name->toQString(), ok);
+ const QQmlPropertyCache *cache = isComposite() ? compositePropertyCache(engine) : 0;
*ok = true;
- d->initEnums();
+ d->initEnums(cache);
int *rv = d->enums.value(name);
if (rv)
@@ -1132,6 +1180,122 @@ int QQmlType::enumValue(QQmlEnginePrivate *engine, const QV4::String *name, bool
return -1;
}
+int QQmlType::scopedEnumIndex(QQmlEnginePrivate *engine, const QV4::String *name, bool *ok) const
+{
+ Q_ASSERT(ok);
+ if (d) {
+ const QQmlPropertyCache *cache = isComposite() ? compositePropertyCache(engine) : 0;
+ *ok = true;
+
+ d->initEnums(cache);
+
+ int *rv = d->scopedEnumIndex.value(name);
+ if (rv)
+ return *rv;
+ }
+
+ *ok = false;
+ return -1;
+}
+
+int QQmlType::scopedEnumIndex(QQmlEnginePrivate *engine, const QString &name, bool *ok) const
+{
+ Q_ASSERT(ok);
+ if (d) {
+ const QQmlPropertyCache *cache = isComposite() ? compositePropertyCache(engine) : 0;
+ *ok = true;
+
+ d->initEnums(cache);
+
+ int *rv = d->scopedEnumIndex.value(name);
+ if (rv)
+ return *rv;
+ }
+
+ *ok = false;
+ return -1;
+}
+
+int QQmlType::scopedEnumValue(QQmlEnginePrivate *engine, int index, const QV4::String *name, bool *ok) const
+{
+ Q_UNUSED(engine)
+ Q_ASSERT(ok);
+ *ok = true;
+
+ if (d) {
+ Q_ASSERT(index > -1 && index < d->scopedEnums.count());
+ int *rv = d->scopedEnums.at(index)->value(name);
+ if (rv)
+ return *rv;
+ }
+
+ *ok = false;
+ return -1;
+}
+
+int QQmlType::scopedEnumValue(QQmlEnginePrivate *engine, int index, const QString &name, bool *ok) const
+{
+ Q_UNUSED(engine)
+ Q_ASSERT(ok);
+ *ok = true;
+
+ if (d) {
+ Q_ASSERT(index > -1 && index < d->scopedEnums.count());
+ int *rv = d->scopedEnums.at(index)->value(name);
+ if (rv)
+ return *rv;
+ }
+
+ *ok = false;
+ return -1;
+}
+
+int QQmlType::scopedEnumValue(QQmlEnginePrivate *engine, const QByteArray &scopedEnumName, const QByteArray &name, bool *ok) const
+{
+ Q_ASSERT(ok);
+ if (d) {
+ const QQmlPropertyCache *cache = isComposite() ? compositePropertyCache(engine) : 0;
+ *ok = true;
+
+ d->initEnums(cache);
+
+ int *rv = d->scopedEnumIndex.value(QHashedCStringRef(scopedEnumName.constData(), scopedEnumName.length()));
+ if (rv) {
+ int index = *rv;
+ Q_ASSERT(index > -1 && index < d->scopedEnums.count());
+ rv = d->scopedEnums.at(index)->value(QHashedCStringRef(name.constData(), name.length()));
+ if (rv)
+ return *rv;
+ }
+ }
+
+ *ok = false;
+ return -1;
+}
+
+int QQmlType::scopedEnumValue(QQmlEnginePrivate *engine, const QStringRef &scopedEnumName, const QStringRef &name, bool *ok) const
+{
+ Q_ASSERT(ok);
+ if (d) {
+ const QQmlPropertyCache *cache = isComposite() ? compositePropertyCache(engine) : 0;
+ *ok = true;
+
+ d->initEnums(cache);
+
+ int *rv = d->scopedEnumIndex.value(QHashedStringRef(scopedEnumName));
+ if (rv) {
+ int index = *rv;
+ Q_ASSERT(index > -1 && index < d->scopedEnums.count());
+ rv = d->scopedEnums.at(index)->value(QHashedStringRef(name));
+ if (rv)
+ return *rv;
+ }
+ }
+
+ *ok = false;
+ return -1;
+}
+
void QQmlType::refHandle(QQmlTypePrivate *priv)
{
if (priv)
diff --git a/src/qml/qml/qqmlmetatype_p.h b/src/qml/qml/qqmlmetatype_p.h
index f5b9beb905..f381b4a010 100644
--- a/src/qml/qml/qqmlmetatype_p.h
+++ b/src/qml/qml/qqmlmetatype_p.h
@@ -149,6 +149,7 @@ public:
struct QQmlMetaTypeData;
class QHashedCStringRef;
+class QQmlPropertyCache;
class Q_QML_PRIVATE_EXPORT QQmlType
{
public:
@@ -244,6 +245,13 @@ public:
int enumValue(QQmlEnginePrivate *engine, const QHashedCStringRef &, bool *ok) const;
int enumValue(QQmlEnginePrivate *engine, const QV4::String *, bool *ok) const;
+ int scopedEnumIndex(QQmlEnginePrivate *engine, const QV4::String *, bool *ok) const;
+ int scopedEnumIndex(QQmlEnginePrivate *engine, const QString &, bool *ok) const;
+ int scopedEnumValue(QQmlEnginePrivate *engine, int index, const QV4::String *, bool *ok) const;
+ int scopedEnumValue(QQmlEnginePrivate *engine, int index, const QString &, bool *ok) const;
+ int scopedEnumValue(QQmlEnginePrivate *engine, const QByteArray &, const QByteArray &, bool *ok) const;
+ int scopedEnumValue(QQmlEnginePrivate *engine, const QStringRef &, const QStringRef &, bool *ok) const;
+
QQmlTypePrivate *priv() const { return d; }
static void refHandle(QQmlTypePrivate *priv);
static void derefHandle(QQmlTypePrivate *priv);
@@ -262,6 +270,7 @@ private:
QQmlType superType() const;
QQmlType resolveCompositeBaseType(QQmlEnginePrivate *engine) const;
int resolveCompositeEnumValue(QQmlEnginePrivate *engine, const QString &name, bool *ok) const;
+ QQmlPropertyCache *compositePropertyCache(QQmlEnginePrivate *engine) const;
friend class QQmlTypePrivate;
friend QString registrationTypeString(RegistrationType);
diff --git a/src/qml/qml/qqmlnotifier_p.h b/src/qml/qml/qqmlnotifier_p.h
index 6e91369793..a99b13f155 100644
--- a/src/qml/qml/qqmlnotifier_p.h
+++ b/src/qml/qml/qqmlnotifier_p.h
@@ -109,6 +109,9 @@ public:
inline int signalIndex() const { return sourceSignal; }
+ inline QObject *senderAsObject() const;
+ inline QQmlNotifier *senderAsNotifier() const;
+
private:
friend class QQmlData;
friend class QQmlNotifier;
@@ -117,8 +120,6 @@ private:
// endpoint is connected to. While the endpoint is notifying, the
// senderPtr points to another qintptr that contains this value.
qintptr senderPtr;
- inline QObject *senderAsObject() const;
- inline QQmlNotifier *senderAsNotifier() const;
Callback callback:4;
int needsConnectNotify:1;
diff --git a/src/qml/qml/qqmlobjectcreator.cpp b/src/qml/qml/qqmlobjectcreator.cpp
index 78d732d02c..9114fbb83a 100644
--- a/src/qml/qml/qqmlobjectcreator.cpp
+++ b/src/qml/qml/qqmlobjectcreator.cpp
@@ -875,17 +875,13 @@ bool QQmlObjectCreator::setPropertyBinding(const QQmlPropertyData *property, con
&& !_valueTypeProperty)
QQmlPropertyPrivate::removeBinding(_bindingTarget, QQmlPropertyIndex(property->coreIndex()));
- if (binding->type == QV4::CompiledData::Binding::Type_Script) {
- QV4::Function *runtimeFunction = compilationUnit->runtimeFunctions.at(binding->value.compiledScriptIndex);
-
- QV4::Scope scope(v4);
- QV4::Scoped<QV4::QmlContext> qmlContext(scope, currentQmlContext());
-
+ if (binding->type == QV4::CompiledData::Binding::Type_Script || binding->containsTranslations()) {
if (binding->flags & QV4::CompiledData::Binding::IsSignalHandlerExpression) {
+ QV4::Function *runtimeFunction = compilationUnit->runtimeFunctions[binding->value.compiledScriptIndex];
int signalIndex = _propertyCache->methodIndexToSignalIndex(property->coreIndex());
QQmlBoundSignal *bs = new QQmlBoundSignal(_bindingTarget, signalIndex, _scopeObject, engine);
QQmlBoundSignalExpression *expr = new QQmlBoundSignalExpression(_bindingTarget, signalIndex,
- context, _scopeObject, runtimeFunction, qmlContext);
+ context, _scopeObject, runtimeFunction, currentQmlContext());
bs->takeExpression(expr);
} else {
@@ -901,7 +897,12 @@ bool QQmlObjectCreator::setPropertyBinding(const QQmlPropertyData *property, con
prop = _valueTypeProperty;
subprop = property;
}
- qmlBinding = QQmlBinding::create(prop, runtimeFunction, _scopeObject, context, qmlContext);
+ if (binding->containsTranslations()) {
+ qmlBinding = QQmlBinding::createTranslationBinding(compilationUnit, binding, _scopeObject, context);
+ } else {
+ QV4::Function *runtimeFunction = compilationUnit->runtimeFunctions[binding->value.compiledScriptIndex];
+ qmlBinding = QQmlBinding::create(prop, runtimeFunction, _scopeObject, context, currentQmlContext());
+ }
qmlBinding->setTarget(_bindingTarget, *prop, subprop);
sharedState->allCreatedBindings.push(QQmlAbstractBinding::Ptr(qmlBinding));
@@ -1070,7 +1071,7 @@ void QQmlObjectCreator::setupFunctions()
QV4::ScopedValue function(scope);
QV4::ScopedContext qmlContext(scope, currentQmlContext());
- const QV4::CompiledData::LEUInt32 *functionIdx = _compiledObject->functionOffsetTable();
+ const quint32_le *functionIdx = _compiledObject->functionOffsetTable();
for (quint32 i = 0; i < _compiledObject->nFunctions; ++i, ++functionIdx) {
QV4::Function *runtimeFunction = compilationUnit->runtimeFunctions[*functionIdx];
const QString name = runtimeFunction->name()->toQString();
diff --git a/src/qml/qml/qqmlobjectcreator_p.h b/src/qml/qml/qqmlobjectcreator_p.h
index 21ee30acd0..bef58b8c9a 100644
--- a/src/qml/qml/qqmlobjectcreator_p.h
+++ b/src/qml/qml/qqmlobjectcreator_p.h
@@ -123,7 +123,7 @@ private:
void registerObjectWithContextById(const QV4::CompiledData::Object *object, QObject *instance) const;
- inline QV4::Heap::QmlContext *currentQmlContext();
+ inline QV4::QmlContext *currentQmlContext();
Q_NEVER_INLINE void createQmlContext();
enum Phase {
@@ -174,12 +174,12 @@ private:
QRecursionWatcher<QQmlObjectCreatorSharedState, &QQmlObjectCreatorSharedState::recursionNode> watcher;
};
-QV4::Heap::QmlContext *QQmlObjectCreator::currentQmlContext()
+QV4::QmlContext *QQmlObjectCreator::currentQmlContext()
{
- if (Q_UNLIKELY(!_qmlContext->isManaged()))
- createQmlContext(); // less common slow path
+ if (!_qmlContext->isManaged())
+ _qmlContext->setM(QV4::QmlContext::create(v4->rootContext(), context, _scopeObject));
- return _qmlContext->d();
+ return _qmlContext;
}
QT_END_NAMESPACE
diff --git a/src/qml/qml/qqmlplatform.cpp b/src/qml/qml/qqmlplatform.cpp
index 0d6ab36066..0acf20bbb4 100644
--- a/src/qml/qml/qqmlplatform.cpp
+++ b/src/qml/qml/qqmlplatform.cpp
@@ -38,6 +38,7 @@
****************************************************************************/
#include "qqmlplatform_p.h"
+#include "qqmlglobal_p.h"
QT_BEGIN_NAMESPACE
@@ -80,6 +81,11 @@ QString QQmlPlatform::os()
#endif
}
+QString QQmlPlatform::pluginName() const
+{
+ return QQml_guiProvider()->pluginName();
+}
+
QT_END_NAMESPACE
#include "moc_qqmlplatform_p.cpp"
diff --git a/src/qml/qml/qqmlplatform_p.h b/src/qml/qml/qqmlplatform_p.h
index 6887720adb..6246ca7105 100644
--- a/src/qml/qml/qqmlplatform_p.h
+++ b/src/qml/qml/qqmlplatform_p.h
@@ -61,12 +61,14 @@ class Q_QML_PRIVATE_EXPORT QQmlPlatform : public QObject
{
Q_OBJECT
Q_PROPERTY(QString os READ os CONSTANT)
+ Q_PROPERTY(QString pluginName READ pluginName CONSTANT)
public:
explicit QQmlPlatform(QObject *parent = 0);
virtual ~QQmlPlatform();
static QString os();
+ QString pluginName() const;
private:
Q_DISABLE_COPY(QQmlPlatform)
diff --git a/src/qml/qml/qqmlpropertycache.cpp b/src/qml/qml/qqmlpropertycache.cpp
index 019fa654d1..7178dffa8b 100644
--- a/src/qml/qml/qqmlpropertycache.cpp
+++ b/src/qml/qml/qqmlpropertycache.cpp
@@ -303,12 +303,13 @@ QQmlPropertyCache *QQmlPropertyCache::copy()
}
QQmlPropertyCache *QQmlPropertyCache::copyAndReserve(int propertyCount, int methodCount,
- int signalCount)
+ int signalCount, int enumCount)
{
QQmlPropertyCache *rv = copy(propertyCount + methodCount + signalCount);
rv->propertyIndexCache.reserve(propertyCount);
rv->methodIndexCache.reserve(methodCount);
rv->signalHandlerIndexCache.reserve(signalCount);
+ rv->enumCache.reserve(enumCount);
rv->_metaObject = 0;
return rv;
@@ -403,6 +404,14 @@ void QQmlPropertyCache::appendMethod(const QString &name, QQmlPropertyData::Flag
setNamedProperty(name, methodIndex + methodOffset(), methodIndexCache.data() + methodIndex, (old != 0));
}
+void QQmlPropertyCache::appendEnum(const QString &name, const QVector<QQmlEnumValue> &values)
+{
+ QQmlEnumData data;
+ data.name = name;
+ data.values = values;
+ enumCache.append(data);
+}
+
// Returns this property cache's metaObject, creating it if necessary.
const QMetaObject *QQmlPropertyCache::createMetaObject()
{
@@ -1231,6 +1240,16 @@ void QQmlPropertyCache::toMetaObjectBuilder(QMetaObjectBuilder &builder)
method.setReturnType(returnType);
}
+ for (int ii = 0; ii < enumCache.count(); ++ii) {
+ const QQmlEnumData &enumData = enumCache.at(ii);
+ QMetaEnumBuilder enumeration = builder.addEnumerator(enumData.name.toUtf8());
+ enumeration.setIsScoped(true);
+ for (int jj = 0; jj < enumData.values.count(); ++jj) {
+ const QQmlEnumValue &value = enumData.values.at(jj);
+ enumeration.addKey(value.namedValue.toUtf8(), value.value);
+ }
+ }
+
if (!_defaultPropertyName.isEmpty()) {
QQmlPropertyData *dp = property(_defaultPropertyName, 0, 0);
if (dp && dp->coreIndex() >= propertyIndexCacheStart) {
diff --git a/src/qml/qml/qqmlpropertycache_p.h b/src/qml/qml/qqmlpropertycache_p.h
index a841570f1d..6cdb82bd46 100644
--- a/src/qml/qml/qqmlpropertycache_p.h
+++ b/src/qml/qml/qqmlpropertycache_p.h
@@ -349,6 +349,20 @@ private:
bool notFullyResolved() const { return _flags.notFullyResolved; }
};
+struct QQmlEnumValue
+{
+ QQmlEnumValue() : value(-1) {}
+ QQmlEnumValue(const QString &n, int v) : namedValue(n), value(v) {}
+ QString namedValue;
+ int value;
+};
+
+struct QQmlEnumData
+{
+ QString name;
+ QVector<QQmlEnumValue> values;
+};
+
class QQmlPropertyCacheMethodArguments;
class Q_QML_PRIVATE_EXPORT QQmlPropertyCache : public QQmlRefCount
{
@@ -374,13 +388,14 @@ public:
QQmlPropertyRawData::Flags signalFlags = QQmlPropertyData::Flags());
QQmlPropertyCache *copyAndReserve(int propertyCount,
- int methodCount, int signalCount);
+ int methodCount, int signalCount, int enumCount);
void appendProperty(const QString &, QQmlPropertyRawData::Flags flags, int coreIndex,
int propType, int notifyIndex);
void appendSignal(const QString &, QQmlPropertyRawData::Flags, int coreIndex,
const int *types = 0, const QList<QByteArray> &names = QList<QByteArray>());
void appendMethod(const QString &, QQmlPropertyData::Flags flags, int coreIndex,
const QList<QByteArray> &names = QList<QByteArray>());
+ void appendEnum(const QString &, const QVector<QQmlEnumValue> &);
const QMetaObject *metaObject() const;
const QMetaObject *createMetaObject();
@@ -395,6 +410,7 @@ public:
QQmlPropertyData *property(int) const;
QQmlPropertyData *method(int) const;
QQmlPropertyData *signal(int index) const;
+ QQmlEnumData *qmlEnum(int) const;
int methodIndexToSignalIndex(int) const;
QString defaultPropertyName() const;
@@ -434,6 +450,7 @@ public:
inline int methodOffset() const;
inline int signalCount() const;
inline int signalOffset() const;
+ inline int qmlEnumCount() const;
static bool isDynamicMetaObject(const QMetaObject *);
@@ -500,6 +517,7 @@ private:
IndexCache signalHandlerIndexCache;
StringCache stringCache;
AllowedRevisionCache allowedRevisionCache;
+ QVector<QQmlEnumData> enumCache;
bool _hasPropertyOverrides : 1;
bool _ownMetaObject : 1;
@@ -742,6 +760,14 @@ inline QQmlPropertyData *QQmlPropertyCache::signal(int index) const
return ensureResolved(rv);
}
+inline QQmlEnumData *QQmlPropertyCache::qmlEnum(int index) const
+{
+ if (index < 0 || index >= enumCache.count())
+ return 0;
+
+ return const_cast<QQmlEnumData *>(&enumCache.at(index));
+}
+
inline int QQmlPropertyCache::methodIndexToSignalIndex(int index) const
{
if (index < 0 || index >= (methodIndexCacheStart + methodIndexCache.count()))
@@ -812,6 +838,11 @@ int QQmlPropertyCache::signalOffset() const
return signalHandlerIndexCacheStart;
}
+int QQmlPropertyCache::qmlEnumCount() const
+{
+ return enumCache.count();
+}
+
bool QQmlPropertyCache::callJSFactoryMethod(QObject *object, void **args) const
{
if (_jsFactoryMethodIndex != -1) {
diff --git a/src/qml/qml/qqmltypeloader.cpp b/src/qml/qml/qqmltypeloader.cpp
index 19e57fbdba..4b6e69e617 100644
--- a/src/qml/qml/qqmltypeloader.cpp
+++ b/src/qml/qml/qqmltypeloader.cpp
@@ -2706,6 +2706,10 @@ void QQmlTypeData::resolveTypes()
m_resolvedTypes.insert(unresolvedRef.key(), ref);
}
+
+ // ### this allows enums to work without explicit import or instantiation of the type
+ if (!m_implicitImportLoaded)
+ loadImplicitImport();
}
QQmlCompileError QQmlTypeData::buildTypeResolutionCaches(
diff --git a/src/qml/qml/qqmltypenamecache.cpp b/src/qml/qml/qqmltypenamecache.cpp
index 72307c2800..32b0fa16c4 100644
--- a/src/qml/qml/qqmltypenamecache.cpp
+++ b/src/qml/qml/qqmltypenamecache.cpp
@@ -138,7 +138,7 @@ QQmlTypeNameCache::Result QQmlTypeNameCache::query(const QHashedStringRef &name,
return result;
}
-QQmlTypeNameCache::Result QQmlTypeNameCache::query(const QV4::String *name) const
+QQmlTypeNameCache::Result QQmlTypeNameCache::query(const QV4::String *name, QQmlImport::RecursionRestriction recursionRestriction) const
{
Result result = query(m_namedImports, name);
@@ -154,7 +154,8 @@ QQmlTypeNameCache::Result QQmlTypeNameCache::query(const QV4::String *name) cons
QQmlImportNamespace *typeNamespace = 0;
QList<QQmlError> errors;
QQmlType t;
- bool typeFound = m_imports.resolveType(typeName, &t, 0, 0, &typeNamespace, &errors);
+ bool typeFound = m_imports.resolveType(typeName, &t, 0, 0, &typeNamespace, &errors,
+ QQmlType::AnyRegistrationType, recursionRestriction);
if (typeFound) {
return Result(t);
}
diff --git a/src/qml/qml/qqmltypenamecache_p.h b/src/qml/qml/qqmltypenamecache_p.h
index 7e2cbec4b5..8ac25c4fbe 100644
--- a/src/qml/qml/qqmltypenamecache_p.h
+++ b/src/qml/qml/qqmltypenamecache_p.h
@@ -81,7 +81,7 @@ struct QQmlImportRef {
class QQmlType;
class QQmlEngine;
-class QQmlTypeNameCache : public QQmlRefCount
+class Q_QML_PRIVATE_EXPORT QQmlTypeNameCache : public QQmlRefCount
{
public:
QQmlTypeNameCache(const QQmlImports &imports);
@@ -107,7 +107,7 @@ public:
};
Result query(const QHashedStringRef &) const;
Result query(const QHashedStringRef &, const QQmlImportRef *importNamespace) const;
- Result query(const QV4::String *) const;
+ Result query(const QV4::String *, QQmlImport::RecursionRestriction recursionRestriction = QQmlImport::PreventRecursion) const;
Result query(const QV4::String *, const QQmlImportRef *importNamespace) const;
private:
diff --git a/src/qml/qml/qqmltypewrapper.cpp b/src/qml/qml/qqmltypewrapper.cpp
index 0fae76066d..8e067932bb 100644
--- a/src/qml/qml/qqmltypewrapper.cpp
+++ b/src/qml/qml/qqmltypewrapper.cpp
@@ -52,16 +52,17 @@ QT_BEGIN_NAMESPACE
using namespace QV4;
-DEFINE_OBJECT_VTABLE(QmlTypeWrapper);
+DEFINE_OBJECT_VTABLE(QQmlTypeWrapper);
+DEFINE_OBJECT_VTABLE(QQmlScopedEnumWrapper);
-void Heap::QmlTypeWrapper::init()
+void Heap::QQmlTypeWrapper::init()
{
Object::init();
mode = IncludeEnums;
object.init();
}
-void Heap::QmlTypeWrapper::destroy()
+void Heap::QQmlTypeWrapper::destroy()
{
QQmlType::derefHandle(typePrivate);
typePrivate = nullptr;
@@ -71,17 +72,17 @@ void Heap::QmlTypeWrapper::destroy()
Object::destroy();
}
-QQmlType Heap::QmlTypeWrapper::type() const
+QQmlType Heap::QQmlTypeWrapper::type() const
{
return QQmlType(typePrivate);
}
-bool QmlTypeWrapper::isSingleton() const
+bool QQmlTypeWrapper::isSingleton() const
{
return d()->type().isSingleton();
}
-QObject* QmlTypeWrapper::singletonObject() const
+QObject* QQmlTypeWrapper::singletonObject() const
{
if (!isSingleton())
return 0;
@@ -92,7 +93,7 @@ QObject* QmlTypeWrapper::singletonObject() const
return siinfo->qobjectApi(e);
}
-QVariant QmlTypeWrapper::toVariant() const
+QVariant QQmlTypeWrapper::toVariant() const
{
QObject *qobjectSingleton = singletonObject();
if (qobjectSingleton)
@@ -104,13 +105,13 @@ QVariant QmlTypeWrapper::toVariant() const
// Returns a type wrapper for type t on o. This allows access of enums, and attached properties.
-ReturnedValue QmlTypeWrapper::create(QV4::ExecutionEngine *engine, QObject *o, const QQmlType &t,
- Heap::QmlTypeWrapper::TypeNameMode mode)
+ReturnedValue QQmlTypeWrapper::create(QV4::ExecutionEngine *engine, QObject *o, const QQmlType &t,
+ Heap::QQmlTypeWrapper::TypeNameMode mode)
{
Q_ASSERT(t.isValid());
Scope scope(engine);
- Scoped<QmlTypeWrapper> w(scope, engine->memoryManager->allocObject<QmlTypeWrapper>());
+ Scoped<QQmlTypeWrapper> w(scope, engine->memoryManager->allocObject<QQmlTypeWrapper>());
w->d()->mode = mode; w->d()->object = o;
w->d()->typePrivate = t.priv();
QQmlType::refHandle(w->d()->typePrivate);
@@ -119,14 +120,14 @@ ReturnedValue QmlTypeWrapper::create(QV4::ExecutionEngine *engine, QObject *o, c
// Returns a type wrapper for importNamespace (of t) on o. This allows nested resolution of a type in a
// namespace.
-ReturnedValue QmlTypeWrapper::create(QV4::ExecutionEngine *engine, QObject *o, QQmlTypeNameCache *t, const QQmlImportRef *importNamespace,
- Heap::QmlTypeWrapper::TypeNameMode mode)
+ReturnedValue QQmlTypeWrapper::create(QV4::ExecutionEngine *engine, QObject *o, QQmlTypeNameCache *t, const QQmlImportRef *importNamespace,
+ Heap::QQmlTypeWrapper::TypeNameMode mode)
{
Q_ASSERT(t);
Q_ASSERT(importNamespace);
Scope scope(engine);
- Scoped<QmlTypeWrapper> w(scope, engine->memoryManager->allocObject<QmlTypeWrapper>());
+ Scoped<QQmlTypeWrapper> w(scope, engine->memoryManager->allocObject<QQmlTypeWrapper>());
w->d()->mode = mode; w->d()->object = o; w->d()->typeNamespace = t; w->d()->importNamespace = importNamespace;
t->addref();
return w.asReturnedValue();
@@ -161,14 +162,14 @@ static ReturnedValue throwLowercaseEnumError(QV4::ExecutionEngine *v4, String *n
return v4->throwTypeError(message);
}
-ReturnedValue QmlTypeWrapper::get(const Managed *m, String *name, bool *hasProperty)
+ReturnedValue QQmlTypeWrapper::get(const Managed *m, String *name, bool *hasProperty)
{
- Q_ASSERT(m->as<QmlTypeWrapper>());
+ Q_ASSERT(m->as<QQmlTypeWrapper>());
- QV4::ExecutionEngine *v4 = static_cast<const QmlTypeWrapper *>(m)->engine();
+ QV4::ExecutionEngine *v4 = static_cast<const QQmlTypeWrapper *>(m)->engine();
QV4::Scope scope(v4);
- Scoped<QmlTypeWrapper> w(scope, static_cast<const QmlTypeWrapper *>(m));
+ Scoped<QQmlTypeWrapper> w(scope, static_cast<const QQmlTypeWrapper *>(m));
if (hasProperty)
*hasProperty = true;
@@ -190,7 +191,7 @@ ReturnedValue QmlTypeWrapper::get(const Managed *m, String *name, bool *hasPrope
if (qobjectSingleton) {
// check for enum value
- const bool includeEnums = w->d()->mode == Heap::QmlTypeWrapper::IncludeEnums;
+ const bool includeEnums = w->d()->mode == Heap::QQmlTypeWrapper::IncludeEnums;
if (includeEnums && name->startsWithUpper()) {
bool ok = false;
const int value = enumForSingleton(v4, name, qobjectSingleton, type, &ok);
@@ -229,6 +230,15 @@ ReturnedValue QmlTypeWrapper::get(const Managed *m, String *name, bool *hasPrope
if (ok)
return QV4::Primitive::fromInt32(value).asReturnedValue();
+ value = type.scopedEnumIndex(QQmlEnginePrivate::get(v4->qmlEngine()), name, &ok);
+ if (ok) {
+ Scoped<QQmlScopedEnumWrapper> enumWrapper(scope, v4->memoryManager->allocObject<QQmlScopedEnumWrapper>());
+ enumWrapper->d()->typePrivate = type.priv();
+ QQmlType::refHandle(enumWrapper->d()->typePrivate);
+ enumWrapper->d()->scopeEnumIndex = value;
+ return enumWrapper.asReturnedValue();
+ }
+
// Fall through to base implementation
} else if (w->d()->object) {
@@ -285,13 +295,13 @@ ReturnedValue QmlTypeWrapper::get(const Managed *m, String *name, bool *hasPrope
}
-void QmlTypeWrapper::put(Managed *m, String *name, const Value &value)
+bool QQmlTypeWrapper::put(Managed *m, String *name, const Value &value)
{
- Q_ASSERT(m->as<QmlTypeWrapper>());
- QmlTypeWrapper *w = static_cast<QmlTypeWrapper *>(m);
+ Q_ASSERT(m->as<QQmlTypeWrapper>());
+ QQmlTypeWrapper *w = static_cast<QQmlTypeWrapper *>(m);
QV4::ExecutionEngine *v4 = w->engine();
if (v4->hasException)
- return;
+ return false;
QV4::Scope scope(v4);
QQmlContextData *context = v4->callingQmlContext();
@@ -302,7 +312,8 @@ void QmlTypeWrapper::put(Managed *m, String *name, const Value &value)
QQmlEngine *e = scope.engine->qmlEngine();
QObject *ao = qmlAttachedPropertiesObjectById(type.attachedPropertiesId(QQmlEnginePrivate::get(e)), object);
if (ao)
- QV4::QObjectWrapper::setQmlProperty(v4, context, ao, name, QV4::QObjectWrapper::IgnoreRevision, value);
+ return QV4::QObjectWrapper::setQmlProperty(v4, context, ao, name, QV4::QObjectWrapper::IgnoreRevision, value);
+ return false;
} else if (type.isSingleton()) {
QQmlEngine *e = scope.engine->qmlEngine();
QQmlType::SingletonInstanceInfo *siinfo = type.singletonInstanceInfo();
@@ -310,21 +321,23 @@ void QmlTypeWrapper::put(Managed *m, String *name, const Value &value)
QObject *qobjectSingleton = siinfo->qobjectApi(e);
if (qobjectSingleton) {
- QV4::QObjectWrapper::setQmlProperty(v4, context, qobjectSingleton, name, QV4::QObjectWrapper::IgnoreRevision, value);
+ return QV4::QObjectWrapper::setQmlProperty(v4, context, qobjectSingleton, name, QV4::QObjectWrapper::IgnoreRevision, value);
} else if (!siinfo->scriptApi(e).isUndefined()) {
QV4::ScopedObject apiprivate(scope, QJSValuePrivate::convertedToValue(v4, siinfo->scriptApi(e)));
if (!apiprivate) {
QString error = QLatin1String("Cannot assign to read-only property \"") + name->toQString() + QLatin1Char('\"');
v4->throwError(error);
- return;
+ return false;
} else {
- apiprivate->put(name, value);
+ return apiprivate->put(name, value);
}
}
}
+
+ return false;
}
-PropertyAttributes QmlTypeWrapper::query(const Managed *m, String *name)
+PropertyAttributes QQmlTypeWrapper::query(const Managed *m, String *name)
{
// ### Implement more efficiently.
bool hasProperty = false;
@@ -332,11 +345,11 @@ PropertyAttributes QmlTypeWrapper::query(const Managed *m, String *name)
return hasProperty ? Attr_Data : Attr_Invalid;
}
-bool QmlTypeWrapper::isEqualTo(Managed *a, Managed *b)
+bool QQmlTypeWrapper::isEqualTo(Managed *a, Managed *b)
{
- Q_ASSERT(a->as<QV4::QmlTypeWrapper>());
- QV4::QmlTypeWrapper *qmlTypeWrapperA = static_cast<QV4::QmlTypeWrapper *>(a);
- if (QV4::QmlTypeWrapper *qmlTypeWrapperB = b->as<QV4::QmlTypeWrapper>())
+ Q_ASSERT(a->as<QV4::QQmlTypeWrapper>());
+ QV4::QQmlTypeWrapper *qmlTypeWrapperA = static_cast<QV4::QQmlTypeWrapper *>(a);
+ if (QV4::QQmlTypeWrapper *qmlTypeWrapperB = b->as<QV4::QQmlTypeWrapper>())
return qmlTypeWrapperA->toVariant() == qmlTypeWrapperB->toVariant();
else if (QV4::QObjectWrapper *qobjectWrapper = b->as<QV4::QObjectWrapper>())
return qmlTypeWrapperA->toVariant().value<QObject*>() == qobjectWrapper->object();
@@ -344,4 +357,76 @@ bool QmlTypeWrapper::isEqualTo(Managed *a, Managed *b)
return false;
}
+ReturnedValue QQmlTypeWrapper::instanceOf(const Object *typeObject, const Value &var)
+{
+ Q_ASSERT(typeObject->as<QV4::QQmlTypeWrapper>());
+ const QV4::QQmlTypeWrapper *typeWrapper = static_cast<const QV4::QQmlTypeWrapper *>(typeObject);
+ QV4::ExecutionEngine *engine = typeObject->internalClass()->engine;
+ QQmlEnginePrivate *qenginepriv = QQmlEnginePrivate::get(engine->qmlEngine());
+
+ // can only compare a QObject* against a QML type
+ const QObjectWrapper *wrapper = var.as<QObjectWrapper>();
+ if (!wrapper)
+ return engine->throwTypeError();
+
+ // in case the wrapper outlived the QObject*
+ const QObject *wrapperObject = wrapper->object();
+ if (!wrapperObject)
+ return engine->throwTypeError();
+
+ const int myTypeId = typeWrapper->d()->type().typeId();
+ QQmlMetaObject myQmlType;
+ if (myTypeId == 0) {
+ // we're a composite type; a composite type cannot be equal to a
+ // non-composite object instance (Rectangle{} is never an instance of
+ // CustomRectangle)
+ QQmlData *theirDData = QQmlData::get(wrapperObject, /*create=*/false);
+ Q_ASSERT(theirDData); // must exist, otherwise how do we have a QObjectWrapper for it?!
+ if (!theirDData->compilationUnit)
+ return Encode(false);
+
+ QQmlTypeData *td = qenginepriv->typeLoader.getType(typeWrapper->d()->type().sourceUrl());
+ CompiledData::CompilationUnit *cu = td->compilationUnit();
+ myQmlType = qenginepriv->metaObjectForType(cu->metaTypeId);
+ } else {
+ myQmlType = qenginepriv->metaObjectForType(myTypeId);
+ }
+
+ const QMetaObject *theirType = wrapperObject->metaObject();
+
+ return QV4::Encode(QQmlMetaObject::canConvert(theirType, myQmlType));
+}
+
+void Heap::QQmlScopedEnumWrapper::destroy()
+{
+ QQmlType::derefHandle(typePrivate);
+ typePrivate = nullptr;
+ Object::destroy();
+}
+
+QQmlType Heap::QQmlScopedEnumWrapper::type() const
+{
+ return QQmlType(typePrivate);
+}
+
+ReturnedValue QQmlScopedEnumWrapper::get(const Managed *m, String *name, bool *hasProperty)
+{
+ Q_ASSERT(m->as<QQmlScopedEnumWrapper>());
+ const QQmlScopedEnumWrapper *resource = static_cast<const QQmlScopedEnumWrapper *>(m);
+ QV4::ExecutionEngine *v4 = resource->engine();
+ QV4::Scope scope(v4);
+
+ QQmlType type = resource->d()->type();
+ int index = resource->d()->scopeEnumIndex;
+
+ bool ok = false;
+ int value = type.scopedEnumValue(QQmlEnginePrivate::get(v4->qmlEngine()), index, name, &ok);
+ if (hasProperty)
+ *hasProperty = ok;
+ if (ok)
+ return QV4::Primitive::fromInt32(value).asReturnedValue();
+
+ return Encode::undefined();
+}
+
QT_END_NAMESPACE
diff --git a/src/qml/qml/qqmltypewrapper_p.h b/src/qml/qml/qqmltypewrapper_p.h
index c06c485fb8..bb65093163 100644
--- a/src/qml/qml/qqmltypewrapper_p.h
+++ b/src/qml/qml/qqmltypewrapper_p.h
@@ -65,7 +65,7 @@ namespace QV4 {
namespace Heap {
-struct QmlTypeWrapper : Object {
+struct QQmlTypeWrapper : Object {
enum TypeNameMode {
IncludeEnums,
ExcludeEnums
@@ -83,11 +83,19 @@ struct QmlTypeWrapper : Object {
const QQmlImportRef *importNamespace;
};
+struct QQmlScopedEnumWrapper : Object {
+ void init() { Object::init(); }
+ void destroy();
+ int scopeEnumIndex;
+ QQmlTypePrivate *typePrivate;
+ QQmlType type() const;
+};
+
}
-struct Q_QML_EXPORT QmlTypeWrapper : Object
+struct Q_QML_EXPORT QQmlTypeWrapper : Object
{
- V4_OBJECT2(QmlTypeWrapper, Object)
+ V4_OBJECT2(QQmlTypeWrapper, Object)
V4_NEEDS_DESTROY
bool isSingleton() const;
@@ -96,16 +104,24 @@ struct Q_QML_EXPORT QmlTypeWrapper : Object
QVariant toVariant() const;
static ReturnedValue create(ExecutionEngine *, QObject *, const QQmlType &,
- Heap::QmlTypeWrapper::TypeNameMode = Heap::QmlTypeWrapper::IncludeEnums);
+ Heap::QQmlTypeWrapper::TypeNameMode = Heap::QQmlTypeWrapper::IncludeEnums);
static ReturnedValue create(ExecutionEngine *, QObject *, QQmlTypeNameCache *, const QQmlImportRef *,
- Heap::QmlTypeWrapper::TypeNameMode = Heap::QmlTypeWrapper::IncludeEnums);
+ Heap::QQmlTypeWrapper::TypeNameMode = Heap::QQmlTypeWrapper::IncludeEnums);
static ReturnedValue get(const Managed *m, String *name, bool *hasProperty);
- static void put(Managed *m, String *name, const Value &value);
+ static bool put(Managed *m, String *name, const Value &value);
static PropertyAttributes query(const Managed *, String *name);
static bool isEqualTo(Managed *that, Managed *o);
+ static ReturnedValue instanceOf(const Object *typeObject, const Value &var);
+};
+struct Q_QML_EXPORT QQmlScopedEnumWrapper : Object
+{
+ V4_OBJECT2(QQmlScopedEnumWrapper, Object)
+ V4_NEEDS_DESTROY
+
+ static ReturnedValue get(const Managed *m, String *name, bool *hasProperty);
};
}
diff --git a/src/qml/qml/qqmlvaluetypeproxybinding.cpp b/src/qml/qml/qqmlvaluetypeproxybinding.cpp
index 4e2e7b06c7..7a3e4b2df4 100644
--- a/src/qml/qml/qqmlvaluetypeproxybinding.cpp
+++ b/src/qml/qml/qqmlvaluetypeproxybinding.cpp
@@ -72,6 +72,11 @@ bool QQmlValueTypeProxyBinding::isValueTypeProxy() const
return true;
}
+QQmlAbstractBinding *QQmlValueTypeProxyBinding::subBindings() const
+{
+ return m_bindings.data();
+}
+
QQmlAbstractBinding *QQmlValueTypeProxyBinding::binding(QQmlPropertyIndex propertyIndex) const
{
QQmlAbstractBinding *binding = m_bindings.data();
diff --git a/src/qml/qml/qqmlvaluetypeproxybinding_p.h b/src/qml/qml/qqmlvaluetypeproxybinding_p.h
index 92b5470f39..ba0d305bd9 100644
--- a/src/qml/qml/qqmlvaluetypeproxybinding_p.h
+++ b/src/qml/qml/qqmlvaluetypeproxybinding_p.h
@@ -60,6 +60,7 @@ class QQmlValueTypeProxyBinding : public QQmlAbstractBinding
public:
QQmlValueTypeProxyBinding(QObject *o, QQmlPropertyIndex coreIndex);
+ QQmlAbstractBinding *subBindings() const;
QQmlAbstractBinding *binding(QQmlPropertyIndex targetPropertyIndex) const;
void removeBindings(quint32 mask);
diff --git a/src/qml/qml/qqmlvaluetypewrapper.cpp b/src/qml/qml/qqmlvaluetypewrapper.cpp
index b2b49f7909..18c0cb8b91 100644
--- a/src/qml/qml/qqmlvaluetypewrapper.cpp
+++ b/src/qml/qml/qqmlvaluetypewrapper.cpp
@@ -51,9 +51,11 @@
#include <private/qv4alloca_p.h>
#include <private/qv4objectiterator_p.h>
#include <private/qv4qobjectwrapper_p.h>
+#include <QtCore/qloggingcategory.h>
QT_BEGIN_NAMESPACE
+Q_DECLARE_LOGGING_CATEGORY(lcBindingRemoval)
DEFINE_OBJECT_VTABLE(QV4::QQmlValueTypeWrapper);
@@ -411,13 +413,13 @@ ReturnedValue QQmlValueTypeWrapper::get(const Managed *m, String *name, bool *ha
#undef VALUE_TYPE_ACCESSOR
}
-void QQmlValueTypeWrapper::put(Managed *m, String *name, const Value &value)
+bool QQmlValueTypeWrapper::put(Managed *m, String *name, const Value &value)
{
Q_ASSERT(m->as<QQmlValueTypeWrapper>());
ExecutionEngine *v4 = static_cast<QQmlValueTypeWrapper *>(m)->engine();
Scope scope(v4);
if (scope.hasException())
- return;
+ return false;
Scoped<QQmlValueTypeWrapper> r(scope, static_cast<QQmlValueTypeWrapper *>(m));
Scoped<QQmlValueTypeReference> reference(scope, m->d());
@@ -428,7 +430,7 @@ void QQmlValueTypeWrapper::put(Managed *m, String *name, const Value &value)
QMetaProperty writebackProperty = reference->d()->object->metaObject()->property(reference->d()->property);
if (!writebackProperty.isWritable() || !reference->readReferenceValue())
- return;
+ return false;
writeBackPropertyType = writebackProperty.userType();
}
@@ -436,17 +438,20 @@ void QQmlValueTypeWrapper::put(Managed *m, String *name, const Value &value)
const QMetaObject *metaObject = r->d()->propertyCache()->metaObject();
const QQmlPropertyData *pd = r->d()->propertyCache()->property(name, 0, 0);
if (!pd)
- return;
+ return false;
if (reference) {
QV4::ScopedFunctionObject f(scope, value);
+ const QQmlQPointer<QObject> &referenceObject = reference->d()->object;
+ const int referencePropertyIndex = reference->d()->property;
+
if (f) {
if (!f->isBinding()) {
// assigning a JS function to a non-var-property is not allowed.
QString error = QStringLiteral("Cannot assign JavaScript function to value-type property");
ScopedString e(scope, v4->newString(error));
v4->throwError(e);
- return;
+ return false;
}
QQmlContextData *context = v4->callingQmlContext();
@@ -454,18 +459,31 @@ void QQmlValueTypeWrapper::put(Managed *m, String *name, const Value &value)
QQmlPropertyData cacheData;
cacheData.setWritable(true);
cacheData.setPropType(writeBackPropertyType);
- cacheData.setCoreIndex(reference->d()->property);
+ cacheData.setCoreIndex(referencePropertyIndex);
QV4::Scoped<QQmlBindingFunction> bindingFunction(scope, (const Value &)f);
QV4::ScopedContext ctx(scope, bindingFunction->scope());
- QQmlBinding *newBinding = QQmlBinding::create(&cacheData, bindingFunction->function(), reference->d()->object, context, ctx);
+ QQmlBinding *newBinding = QQmlBinding::create(&cacheData, bindingFunction->function(), referenceObject, context, ctx);
newBinding->setSourceLocation(bindingFunction->currentLocation());
- newBinding->setTarget(reference->d()->object, cacheData, pd);
+ newBinding->setTarget(referenceObject, cacheData, pd);
QQmlPropertyPrivate::setBinding(newBinding);
- return;
+ return true;
} else {
- QQmlPropertyPrivate::removeBinding(reference->d()->object, QQmlPropertyIndex(reference->d()->property, pd->coreIndex()));
+ if (Q_UNLIKELY(lcBindingRemoval().isInfoEnabled())) {
+ if (auto binding = QQmlPropertyPrivate::binding(referenceObject, QQmlPropertyIndex(referencePropertyIndex, pd->coreIndex()))) {
+ Q_ASSERT(!binding->isValueTypeProxy());
+ const auto qmlBinding = static_cast<const QQmlBinding*>(binding);
+ const auto stackFrame = v4->currentStackFrame();
+ qCInfo(lcBindingRemoval,
+ "Overwriting binding on %s::%s which was initially bound at %s by setting \"%s\" at %s:%d",
+ referenceObject->metaObject()->className(), referenceObject->metaObject()->property(referencePropertyIndex).name(),
+ qPrintable(qmlBinding->expressionIdentifier()),
+ metaObject->property(pd->coreIndex()).name(),
+ qPrintable(stackFrame.source), stackFrame.line);
+ }
+ }
+ QQmlPropertyPrivate::removeBinding(referenceObject, QQmlPropertyIndex(referencePropertyIndex, pd->coreIndex()));
}
}
@@ -497,6 +515,8 @@ void QQmlValueTypeWrapper::put(Managed *m, String *name, const Value &value)
QMetaObject::metacall(reference->d()->object, QMetaObject::WriteProperty, reference->d()->property, a);
}
}
+
+ return true;
}
QT_END_NAMESPACE
diff --git a/src/qml/qml/qqmlvaluetypewrapper_p.h b/src/qml/qml/qqmlvaluetypewrapper_p.h
index 87f9116056..c8aac719ab 100644
--- a/src/qml/qml/qqmlvaluetypewrapper_p.h
+++ b/src/qml/qml/qqmlvaluetypewrapper_p.h
@@ -106,7 +106,7 @@ public:
bool write(QObject *target, int propertyIndex) const;
static ReturnedValue get(const Managed *m, String *name, bool *hasProperty);
- static void put(Managed *m, String *name, const Value &value);
+ static bool put(Managed *m, String *name, const Value &value);
static bool isEqualTo(Managed *m, Managed *other);
static PropertyAttributes query(const Managed *, String *name);
static void advanceIterator(Managed *m, ObjectIterator *it, Value *name, uint *index, Property *p, PropertyAttributes *attributes);
diff --git a/src/qml/qml/qqmlvmemetaobject.cpp b/src/qml/qml/qqmlvmemetaobject.cpp
index 965b1fd3f2..dde8784eb1 100644
--- a/src/qml/qml/qqmlvmemetaobject.cpp
+++ b/src/qml/qml/qqmlvmemetaobject.cpp
@@ -104,8 +104,10 @@ void QQmlVMEVariantQObjectPtr::objectDestroyed(QObject *)
if (v4) {
QV4::Scope scope(v4);
QV4::Scoped<QV4::MemberData> sp(scope, m_target->propertyAndMethodStorage.value());
- if (sp)
- *(sp->data() + m_index) = QV4::Primitive::nullValue();
+ if (sp) {
+ QV4::MemberData::Index index{ sp->d(), sp->d()->values.values + m_index };
+ index.set(v4, QV4::Primitive::nullValue());
+ }
}
m_target->activate(m_target->object, m_target->methodOffset() + m_index, 0);
@@ -330,7 +332,7 @@ QQmlVMEMetaObject::QQmlVMEMetaObject(QV4::ExecutionEngine *engine,
if (size) {
QV4::Heap::MemberData *data = QV4::MemberData::allocate(engine, size);
propertyAndMethodStorage.set(engine, data);
- std::fill(data->data, data->data + data->size, QV4::Encode::undefined());
+ std::fill(data->values.values, data->values.values + data->values.size, QV4::Encode::undefined());
}
// Need JS wrapper to ensure properties/methods are marked.
@@ -365,77 +367,77 @@ void QQmlVMEMetaObject::writeProperty(int id, int v)
{
QV4::MemberData *md = propertyAndMethodStorageAsMemberData();
if (md)
- *(md->data() + id) = QV4::Primitive::fromInt32(v);
+ md->set(engine, id, QV4::Primitive::fromInt32(v));
}
void QQmlVMEMetaObject::writeProperty(int id, bool v)
{
QV4::MemberData *md = propertyAndMethodStorageAsMemberData();
if (md)
- *(md->data() + id) = QV4::Primitive::fromBoolean(v);
+ md->set(engine, id, QV4::Primitive::fromBoolean(v));
}
void QQmlVMEMetaObject::writeProperty(int id, double v)
{
QV4::MemberData *md = propertyAndMethodStorageAsMemberData();
if (md)
- *(md->data() + id) = QV4::Primitive::fromDouble(v);
+ md->set(engine, id, QV4::Primitive::fromDouble(v));
}
void QQmlVMEMetaObject::writeProperty(int id, const QString& v)
{
QV4::MemberData *md = propertyAndMethodStorageAsMemberData();
if (md)
- *(md->data() + id) = engine->newString(v);
+ md->set(engine, id, engine->newString(v));
}
void QQmlVMEMetaObject::writeProperty(int id, const QUrl& v)
{
QV4::MemberData *md = propertyAndMethodStorageAsMemberData();
if (md)
- *(md->data() + id) = engine->newVariantObject(QVariant::fromValue(v));
+ md->set(engine, id, engine->newVariantObject(QVariant::fromValue(v)));
}
void QQmlVMEMetaObject::writeProperty(int id, const QDate& v)
{
QV4::MemberData *md = propertyAndMethodStorageAsMemberData();
if (md)
- *(md->data() + id) = engine->newVariantObject(QVariant::fromValue(v));
+ md->set(engine, id, engine->newVariantObject(QVariant::fromValue(v)));
}
void QQmlVMEMetaObject::writeProperty(int id, const QDateTime& v)
{
QV4::MemberData *md = propertyAndMethodStorageAsMemberData();
if (md)
- *(md->data() + id) = engine->newVariantObject(QVariant::fromValue(v));
+ md->set(engine, id, engine->newVariantObject(QVariant::fromValue(v)));
}
void QQmlVMEMetaObject::writeProperty(int id, const QPointF& v)
{
QV4::MemberData *md = propertyAndMethodStorageAsMemberData();
if (md)
- *(md->data() + id) = engine->newVariantObject(QVariant::fromValue(v));
+ md->set(engine, id, engine->newVariantObject(QVariant::fromValue(v)));
}
void QQmlVMEMetaObject::writeProperty(int id, const QSizeF& v)
{
QV4::MemberData *md = propertyAndMethodStorageAsMemberData();
if (md)
- *(md->data() + id) = engine->newVariantObject(QVariant::fromValue(v));
+ md->set(engine, id, engine->newVariantObject(QVariant::fromValue(v)));
}
void QQmlVMEMetaObject::writeProperty(int id, const QRectF& v)
{
QV4::MemberData *md = propertyAndMethodStorageAsMemberData();
if (md)
- *(md->data() + id) = engine->newVariantObject(QVariant::fromValue(v));
+ md->set(engine, id, engine->newVariantObject(QVariant::fromValue(v)));
}
void QQmlVMEMetaObject::writeProperty(int id, QObject* v)
{
QV4::MemberData *md = propertyAndMethodStorageAsMemberData();
if (md)
- *(md->data() + id) = QV4::QObjectWrapper::wrap(engine, v);
+ md->set(engine, id, QV4::Value::fromReturnedValue(QV4::QObjectWrapper::wrap(engine, v)));
QQmlVMEVariantQObjectPtr *guard = getQObjectGuardForProperty(id);
if (v && !guard) {
@@ -593,7 +595,7 @@ QList<QObject *> *QQmlVMEMetaObject::readPropertyAsList(int id) const
if (!v || (int)v->d()->data().userType() != qMetaTypeId<QList<QObject *> >()) {
QVariant variant(qVariantFromValue(QList<QObject*>()));
v = engine->newVariantObject(variant);
- *(md->data() + id) = v;
+ md->set(engine, id, v);
}
return static_cast<QList<QObject *> *>(v->d()->data().data());
}
@@ -742,7 +744,7 @@ int QQmlVMEMetaObject::metaCall(QObject *o, QMetaObject::Call c, int _id, void *
Q_ASSERT(fallbackMetaType != QMetaType::UnknownType);
if (QV4::MemberData *md = propertyAndMethodStorageAsMemberData()) {
QVariant propertyAsVariant;
- if (QV4::VariantObject *v = (md->data() + id)->as<QV4::VariantObject>())
+ if (const QV4::VariantObject *v = (md->data() + id)->as<QV4::VariantObject>())
propertyAsVariant = v->d()->data();
QQml_valueTypeProvider()->readValueType(propertyAsVariant, a[0], fallbackMetaType);
}
@@ -815,9 +817,9 @@ int QQmlVMEMetaObject::metaCall(QObject *o, QMetaObject::Call c, int _id, void *
case QV4::CompiledData::Property::Quaternion:
Q_ASSERT(fallbackMetaType != QMetaType::UnknownType);
if (QV4::MemberData *md = propertyAndMethodStorageAsMemberData()) {
- QV4::VariantObject *v = (md->data() + id)->as<QV4::VariantObject>();
+ const QV4::VariantObject *v = (md->data() + id)->as<QV4::VariantObject>();
if (!v) {
- *(md->data() + id) = engine->newVariantObject(QVariant());
+ md->set(engine, id, engine->newVariantObject(QVariant()));
v = (md->data() + id)->as<QV4::VariantObject>();
QQml_valueTypeProvider()->initValueType(fallbackMetaType, v->d()->data());
}
@@ -1028,7 +1030,7 @@ void QQmlVMEMetaObject::writeVarProperty(int id, const QV4::Value &value)
// Importantly, if the current value is a scarce resource, we need to ensure that it
// gets automatically released by the engine if no other references to it exist.
- QV4::VariantObject *oldVariant = (md->data() + id)->as<QV4::VariantObject>();
+ const QV4::VariantObject *oldVariant = (md->data() + id)->as<QV4::VariantObject>();
if (oldVariant)
oldVariant->removeVmePropertyReference();
@@ -1054,7 +1056,7 @@ void QQmlVMEMetaObject::writeVarProperty(int id, const QV4::Value &value)
guard->setGuardedValue(valueObject, this, id);
// Write the value and emit change signal as appropriate.
- *(md->data() + id) = value;
+ md->set(engine, id, value);
activate(object, methodOffset() + id, 0);
}
@@ -1067,7 +1069,7 @@ void QQmlVMEMetaObject::writeProperty(int id, const QVariant &value)
// Importantly, if the current value is a scarce resource, we need to ensure that it
// gets automatically released by the engine if no other references to it exist.
- QV4::VariantObject *oldv = (md->data() + id)->as<QV4::VariantObject>();
+ const QV4::VariantObject *oldv = (md->data() + id)->as<QV4::VariantObject>();
if (oldv)
oldv->removeVmePropertyReference();
@@ -1081,7 +1083,7 @@ void QQmlVMEMetaObject::writeProperty(int id, const QVariant &value)
// Write the value and emit change signal as appropriate.
QVariant currentValue = readPropertyAsVariant(id);
- *(md->data() + id) = newv;
+ md->set(engine, id, newv);
if ((currentValue.userType() != value.userType() || currentValue != value))
activate(object, methodOffset() + id, 0);
} else {
@@ -1093,14 +1095,14 @@ void QQmlVMEMetaObject::writeProperty(int id, const QVariant &value)
} else {
QV4::MemberData *md = propertyAndMethodStorageAsMemberData();
if (md) {
- QV4::VariantObject *v = (md->data() + id)->as<QV4::VariantObject>();
+ const QV4::VariantObject *v = (md->data() + id)->as<QV4::VariantObject>();
needActivate = (!v ||
v->d()->data().userType() != value.userType() ||
v->d()->data() != value);
if (v)
v->removeVmePropertyReference();
- *(md->data() + id) = engine->newVariantObject(value);
- v = static_cast<QV4::VariantObject *>(md->data() + id);
+ md->set(engine, id, engine->newVariantObject(value));
+ v = static_cast<const QV4::VariantObject *>(md->data() + id);
v->addVmePropertyReference();
}
}
@@ -1139,7 +1141,7 @@ void QQmlVMEMetaObject::setVmeMethod(int index, const QV4::Value &function)
QV4::MemberData *md = propertyAndMethodStorageAsMemberData();
if (!md)
return;
- *(md->data() + methodIndex + compiledObject->nProperties) = function;
+ md->set(engine, methodIndex + compiledObject->nProperties, function);
}
QV4::ReturnedValue QQmlVMEMetaObject::vmeProperty(int index) const
@@ -1167,15 +1169,15 @@ void QQmlVMEMetaObject::ensureQObjectWrapper()
QV4::QObjectWrapper::wrap(engine, object);
}
-void QQmlVMEMetaObject::mark(QV4::ExecutionEngine *e)
+void QQmlVMEMetaObject::mark(QV4::MarkStack *markStack)
{
- if (engine != e)
+ if (engine != markStack->engine)
return;
- propertyAndMethodStorage.markOnce(e);
+ propertyAndMethodStorage.markOnce(markStack);
if (QQmlVMEMetaObject *parent = parentVMEMetaObject())
- parent->mark(e);
+ parent->mark(markStack);
}
bool QQmlVMEMetaObject::aliasTarget(int index, QObject **target, int *coreIndex, int *valueTypeIndex) const
diff --git a/src/qml/qml/qqmlvmemetaobject_p.h b/src/qml/qml/qqmlvmemetaobject_p.h
index 2dff2b7a01..891db5eb3f 100644
--- a/src/qml/qml/qqmlvmemetaobject_p.h
+++ b/src/qml/qml/qqmlvmemetaobject_p.h
@@ -206,7 +206,7 @@ public:
void ensureQObjectWrapper();
- void mark(QV4::ExecutionEngine *e);
+ void mark(QV4::MarkStack *markStack);
void connectAlias(int aliasId);
diff --git a/src/qml/qml/qqmlxmlhttprequest.cpp b/src/qml/qml/qqmlxmlhttprequest.cpp
index 58d8322675..08f3d35e46 100644
--- a/src/qml/qml/qqmlxmlhttprequest.cpp
+++ b/src/qml/qml/qqmlxmlhttprequest.cpp
@@ -1597,10 +1597,12 @@ struct QQmlXMLHttpRequestWrapper : Object {
QQmlXMLHttpRequest *request;
};
-struct QQmlXMLHttpRequestCtor : FunctionObject {
- void init(ExecutionEngine *engine);
+#define QQmlXMLHttpRequestCtorMembers(class, Member) \
+ Member(class, Pointer, Object *, proto)
- Pointer<Object> proto;
+DECLARE_HEAP_OBJECT(QQmlXMLHttpRequestCtor, FunctionObject) {
+ DECLARE_MARK_TABLE(QQmlXMLHttpRequestCtor);
+ void init(ExecutionEngine *engine);
};
}
@@ -1614,12 +1616,7 @@ struct QQmlXMLHttpRequestWrapper : public Object
struct QQmlXMLHttpRequestCtor : public FunctionObject
{
V4_OBJECT2(QQmlXMLHttpRequestCtor, FunctionObject)
- static void markObjects(Heap::Base *that, ExecutionEngine *e) {
- QQmlXMLHttpRequestCtor::Data *c = static_cast<QQmlXMLHttpRequestCtor::Data *>(that);
- if (c->proto)
- c->proto->mark(e);
- FunctionObject::markObjects(that, e);
- }
+
static void construct(const Managed *that, Scope &scope, QV4::CallData *)
{
Scoped<QQmlXMLHttpRequestCtor> ctor(scope, that->as<QQmlXMLHttpRequestCtor>());
@@ -1686,7 +1683,7 @@ void QQmlXMLHttpRequestCtor::setupProto()
ExecutionEngine *v4 = engine();
Scope scope(v4);
ScopedObject p(scope, v4->newObject());
- d()->proto = p->d();
+ d()->proto.set(scope.engine, p->d());
// Methods
p->defineDefaultProperty(QStringLiteral("open"), method_open);
@@ -1826,8 +1823,13 @@ void QQmlXMLHttpRequestCtor::method_send(const QV4::BuiltinFunction *, QV4::Scop
THROW_DOM(DOMEXCEPTION_INVALID_STATE_ERR, "Invalid state");
QByteArray data;
- if (callData->argc > 0)
- data = callData->args[0].toQStringNoThrow().toUtf8();
+ if (callData->argc > 0) {
+ if (const ArrayBuffer *buffer = callData->args[0].as<ArrayBuffer>()) {
+ data = buffer->asByteArray();
+ } else {
+ data = callData->args[0].toQStringNoThrow().toUtf8();
+ }
+ }
scope.result = r->send(w, scope.engine->callingQmlContext(), data);
}
diff --git a/src/qml/qml/v8/qqmlbuiltinfunctions.cpp b/src/qml/qml/v8/qqmlbuiltinfunctions.cpp
index 96d83b9870..1630efe081 100644
--- a/src/qml/qml/v8/qqmlbuiltinfunctions.cpp
+++ b/src/qml/qml/v8/qqmlbuiltinfunctions.cpp
@@ -851,6 +851,8 @@ In addition the following expressions can be used to specify the time:
\li use AM/PM display. \e AP will be replaced by either "AM" or "PM".
\row \li ap
\li use am/pm display. \e ap will be replaced by either "am" or "pm".
+ \row \li t
+ \li include a time-zone indicator.
\endtable
All other input characters will be ignored. Any sequence of characters that
diff --git a/src/qml/types/qqmlconnections.cpp b/src/qml/types/qqmlconnections.cpp
index 7607c19374..e218cdcfe4 100644
--- a/src/qml/types/qqmlconnections.cpp
+++ b/src/qml/types/qqmlconnections.cpp
@@ -235,14 +235,13 @@ void QQmlConnectionsParser::verifyBindings(const QV4::CompiledData::Unit *qmlUni
{
for (int ii = 0; ii < props.count(); ++ii) {
const QV4::CompiledData::Binding *binding = props.at(ii);
- QString propName = qmlUnit->stringAt(binding->propertyNameIndex);
+ const QString &propName = qmlUnit->stringAt(binding->propertyNameIndex);
- if (!propName.startsWith(QLatin1String("on")) || !propName.at(2).isUpper()) {
+ if (!propName.startsWith(QLatin1String("on")) || (propName.length() < 3 || !propName.at(2).isUpper())) {
error(props.at(ii), QQmlConnections::tr("Cannot assign to non-existent property \"%1\"").arg(propName));
return;
}
-
if (binding->type >= QV4::CompiledData::Binding::Type_Object) {
const QV4::CompiledData::Object *target = qmlUnit->objectAt(binding->value.objectIndex);
if (!qmlUnit->stringAt(target->inheritedTypeNameIndex).isEmpty())
diff --git a/src/qml/types/qqmldelegatemodel.cpp b/src/qml/types/qqmldelegatemodel.cpp
index 2badef4268..7a34bab2f5 100644
--- a/src/qml/types/qqmldelegatemodel.cpp
+++ b/src/qml/types/qqmldelegatemodel.cpp
@@ -993,7 +993,9 @@ QObject *QQmlDelegateModelPrivate::object(Compositor::Group group, int index, QQ
}
}
- cacheItem->incubateObject(
+ QQmlComponentPrivate *cp = QQmlComponentPrivate::get(m_delegate);
+ cp->incubateObject(
+ cacheItem->incubationTask,
m_delegate,
m_context->engine(),
ctxt,
@@ -1953,29 +1955,6 @@ void QQmlDelegateModelItem::Dispose()
delete this;
}
-/*
- This is essentially a copy of QQmlComponent::create(); except it takes the QQmlContextData
- arguments instead of QQmlContext which means we don't have to construct the rather weighty
- wrapper class for every delegate item.
-*/
-void QQmlDelegateModelItem::incubateObject(
- QQmlComponent *component,
- QQmlEngine *engine,
- QQmlContextData *context,
- QQmlContextData *forContext)
-{
- QQmlIncubatorPrivate *incubatorPriv = QQmlIncubatorPrivate::get(incubationTask);
- QQmlEnginePrivate *enginePriv = QQmlEnginePrivate::get(engine);
- QQmlComponentPrivate *componentPriv = QQmlComponentPrivate::get(component);
-
- incubatorPriv->compilationUnit = componentPriv->compilationUnit;
- incubatorPriv->enginePriv = enginePriv;
- incubatorPriv->creator.reset(new QQmlObjectCreator(context, componentPriv->compilationUnit, componentPriv->creationContext));
- incubatorPriv->subComponentToCreate = componentPriv->start;
-
- enginePriv->incubate(*incubationTask, forContext);
-}
-
void QQmlDelegateModelItem::destroyObject()
{
Q_ASSERT(object);
diff --git a/src/qml/types/qqmldelegatemodel_p_p.h b/src/qml/types/qqmldelegatemodel_p_p.h
index d8e61b05a1..6d061cdce4 100644
--- a/src/qml/types/qqmldelegatemodel_p_p.h
+++ b/src/qml/types/qqmldelegatemodel_p_p.h
@@ -112,11 +112,6 @@ public:
QObject *modelObject() { return this; }
- void incubateObject(
- QQmlComponent *component,
- QQmlEngine *engine,
- QQmlContextData *context,
- QQmlContextData *forContext);
void destroyObject();
static QQmlDelegateModelItem *dataForObject(QObject *object);
diff --git a/src/qml/types/qqmllistmodel.cpp b/src/qml/types/qqmllistmodel.cpp
index 2b4e906617..d72d2e9487 100644
--- a/src/qml/types/qqmllistmodel.cpp
+++ b/src/qml/types/qqmllistmodel.cpp
@@ -361,7 +361,7 @@ int ListModel::appendElement()
void ListModel::insertElement(int index)
{
newElement(index);
- updateCacheIndices();
+ updateCacheIndices(index);
}
void ListModel::move(int from, int to, int n)
@@ -383,7 +383,7 @@ void ListModel::move(int from, int to, int n)
for (int i=0 ; i < store.count() ; ++i)
elements[from+i] = store[i];
- updateCacheIndices();
+ updateCacheIndices(from, to + n);
}
void ListModel::newElement(int index)
@@ -392,9 +392,14 @@ void ListModel::newElement(int index)
elements.insert(index, e);
}
-void ListModel::updateCacheIndices()
+void ListModel::updateCacheIndices(int start, int end)
{
- for (int i=0 ; i < elements.count() ; ++i) {
+ int count = elements.count();
+
+ if (end < 0 || end > count)
+ end = count;
+
+ for (int i = start; i < end; ++i) {
ListElement *e = elements.at(i);
if (ModelNodeMetaObject *mo = e->objectCache())
mo->m_elementIndex = i;
@@ -571,7 +576,7 @@ QVector<std::function<void()>> ListModel::remove(int index, int count)
});
}
elements.remove(index, count);
- updateCacheIndices();
+ updateCacheIndices(index);
return toDestroy;
}
@@ -1332,7 +1337,7 @@ void ModelNodeMetaObject::emitDirectNotifies(const int *changedRoles, int roleCo
namespace QV4 {
-void ModelObject::put(Managed *m, String *name, const Value &value)
+bool ModelObject::put(Managed *m, String *name, const Value &value)
{
ModelObject *that = static_cast<ModelObject*>(m);
@@ -1346,6 +1351,7 @@ void ModelObject::put(Managed *m, String *name, const Value &value)
ModelNodeMetaObject *mo = ModelNodeMetaObject::get(that->object());
if (mo->initialized())
mo->emitPropertyNotification(name->toQString().toUtf8());
+ return true;
}
ReturnedValue ModelObject::get(const Managed *m, String *name, bool *hasProperty)
@@ -1984,12 +1990,12 @@ void QQmlListModel::setDynamicRoles(bool enableDynamicRoles)
if (m_mainThread && m_agent == 0) {
if (enableDynamicRoles) {
if (m_layout->roleCount())
- qmlWarning(this) << tr("unable to enable dynamic roles as this model is not empty!");
+ qmlWarning(this) << tr("unable to enable dynamic roles as this model is not empty");
else
m_dynamicRoles = true;
} else {
if (m_roles.count()) {
- qmlWarning(this) << tr("unable to enable static roles as this model is not empty!");
+ qmlWarning(this) << tr("unable to enable static roles as this model is not empty");
} else {
m_dynamicRoles = false;
}
diff --git a/src/qml/types/qqmllistmodel_p_p.h b/src/qml/types/qqmllistmodel_p_p.h
index 10916f10db..271437e680 100644
--- a/src/qml/types/qqmllistmodel_p_p.h
+++ b/src/qml/types/qqmllistmodel_p_p.h
@@ -179,7 +179,7 @@ struct ModelObject : public QObjectWrapper {
struct ModelObject : public QObjectWrapper
{
- static void put(Managed *m, String *name, const Value& value);
+ static bool put(Managed *m, String *name, const Value& value);
static ReturnedValue get(const Managed *m, String *name, bool *hasProperty);
static void advanceIterator(Managed *m, ObjectIterator *it, Value *name, uint *index, Property *p, PropertyAttributes *attributes);
@@ -396,7 +396,7 @@ private:
void newElement(int index);
- void updateCacheIndices();
+ void updateCacheIndices(int start = 0, int end = -1);
friend class ListElement;
friend class QQmlListModelWorkerAgent;
diff --git a/src/qml/types/qquickpackage.cpp b/src/qml/types/qquickpackage.cpp
index 7fb14a95f6..e0d1888f33 100644
--- a/src/qml/types/qquickpackage.cpp
+++ b/src/qml/types/qquickpackage.cpp
@@ -89,7 +89,7 @@ public:
{
DataGuard(QObject *obj, QList<DataGuard> *l) : list(l) { (QQmlGuard<QObject>&)*this = obj; }
QList<DataGuard> *list;
- void objectDestroyed(QObject *) {
+ void objectDestroyed(QObject *) override {
// we assume priv will always be destroyed after objectDestroyed calls
list->removeOne(*this);
}
diff --git a/src/qml/types/qquickworkerscript_p.h b/src/qml/types/qquickworkerscript_p.h
index dce3acc3e1..8ea630c685 100644
--- a/src/qml/types/qquickworkerscript_p.h
+++ b/src/qml/types/qquickworkerscript_p.h
@@ -51,7 +51,7 @@
// We mean it.
//
-#include "qqml.h"
+#include <qqml.h>
#include <QtQml/qqmlparserstatus.h>
#include <QtCore/qthread.h>
diff --git a/src/qml/util/qqmladaptormodel.cpp b/src/qml/util/qqmladaptormodel.cpp
index 927f740935..11fed281b7 100644
--- a/src/qml/util/qqmladaptormodel.cpp
+++ b/src/qml/util/qqmladaptormodel.cpp
@@ -102,8 +102,8 @@ public:
virtual QVariant value(int role) const = 0;
virtual void setValue(int role, const QVariant &value) = 0;
- void setValue(const QString &role, const QVariant &value);
- bool resolveIndex(const QQmlAdaptorModel &model, int idx);
+ void setValue(const QString &role, const QVariant &value) override;
+ bool resolveIndex(const QQmlAdaptorModel &model, int idx) override;
static QV4::ReturnedValue get_property(QV4::CallContext *ctx, uint propertyId);
static QV4::ReturnedValue set_property(QV4::CallContext *ctx, uint propertyId);
@@ -140,7 +140,7 @@ public:
const QList<QQmlDelegateModelItem *> &items,
int index,
int count,
- const QVector<int> &roles) const
+ const QVector<int> &roles) const override
{
bool changed = roles.isEmpty() && !watchedRoles.isEmpty();
if (!changed && !watchedRoles.isEmpty() && watchedRoleIds.isEmpty()) {
@@ -184,7 +184,7 @@ public:
void replaceWatchedRoles(
QQmlAdaptorModel &,
const QList<QByteArray> &oldRoles,
- const QList<QByteArray> &newRoles) const
+ const QList<QByteArray> &newRoles) const override
{
VDMModelDelegateDataType *dataType = const_cast<VDMModelDelegateDataType *>(this);
@@ -237,12 +237,12 @@ public:
// QAbstractDynamicMetaObject
- void objectDestroyed(QObject *)
+ void objectDestroyed(QObject *) override
{
release();
}
- int metaCall(QObject *object, QMetaObject::Call call, int id, void **arguments)
+ int metaCall(QObject *object, QMetaObject::Call call, int id, void **arguments) override
{
return static_cast<QQmlDMCachedModelData *>(object)->metaCall(call, id, arguments);
}
@@ -413,18 +413,18 @@ public:
}
}
- QVariant value(int role) const
+ QVariant value(int role) const override
{
return type->model->aim()->index(index, 0, type->model->rootIndex).data(role);
}
- void setValue(int role, const QVariant &value)
+ void setValue(int role, const QVariant &value) override
{
type->model->aim()->setData(
type->model->aim()->index(index, 0, type->model->rootIndex), value, role);
}
- QV4::ReturnedValue get()
+ QV4::ReturnedValue get() override
{
if (type->prototype.isUndefined()) {
QQmlAdaptorModelEngineData * const data = engineData(v4);
@@ -515,7 +515,7 @@ public:
QQmlDelegateModelItem *createItem(
QQmlAdaptorModel &model,
QQmlDelegateModelItemMetaType *metaType,
- int index) const Q_DECL_OVERRIDE
+ int index) const override
{
VDMAbstractItemModelDataType *dataType = const_cast<VDMAbstractItemModelDataType *>(this);
if (!metaObject)
@@ -601,7 +601,7 @@ public:
RETURN_RESULT(QV4::Encode::undefined());
}
- QV4::ReturnedValue get()
+ QV4::ReturnedValue get() override
{
QQmlAdaptorModelEngineData *data = engineData(v4);
QV4::Scope scope(v4);
@@ -612,13 +612,13 @@ public:
return o.asReturnedValue();
}
- void setValue(const QString &role, const QVariant &value)
+ void setValue(const QString &role, const QVariant &value) override
{
if (role == QLatin1String("modelData"))
cachedData = value;
}
- bool resolveIndex(const QQmlAdaptorModel &model, int idx)
+ bool resolveIndex(const QQmlAdaptorModel &model, int idx) override
{
if (index == -1) {
index = idx;
@@ -660,7 +660,7 @@ public:
QQmlDelegateModelItem *createItem(
QQmlAdaptorModel &model,
QQmlDelegateModelItemMetaType *metaType,
- int index) const Q_DECL_OVERRIDE
+ int index) const override
{
return new QQmlDMListAccessorData(
metaType,
@@ -687,7 +687,7 @@ public:
QObject *object);
QObject *modelData() const { return object; }
- QObject *proxiedObject() { return object; }
+ QObject *proxiedObject() override { return object; }
QPointer<QObject> object;
};
@@ -744,7 +744,7 @@ public:
QQmlDelegateModelItem *createItem(
QQmlAdaptorModel &model,
QQmlDelegateModelItemMetaType *metaType,
- int index) const Q_DECL_OVERRIDE
+ int index) const override
{
VDMObjectDelegateDataType *dataType = const_cast<VDMObjectDelegateDataType *>(this);
if (!metaObject)
@@ -785,7 +785,7 @@ public:
m_type->release();
}
- int metaCall(QObject *o, QMetaObject::Call call, int id, void **arguments)
+ int metaCall(QObject *o, QMetaObject::Call call, int id, void **arguments) override
{
Q_ASSERT(o == m_data);
Q_UNUSED(o);
@@ -806,7 +806,7 @@ public:
}
}
- int createProperty(const char *name, const char *)
+ int createProperty(const char *name, const char *) override
{
if (!m_data->object)
return -1;
diff --git a/src/qml/util/qqmlpropertymap.cpp b/src/qml/util/qqmlpropertymap.cpp
index 6e6554f2c3..b54e8d901a 100644
--- a/src/qml/util/qqmlpropertymap.cpp
+++ b/src/qml/util/qqmlpropertymap.cpp
@@ -186,9 +186,8 @@ int QQmlPropertyMapMetaObject::createProperty(const char *name, const char *valu
Constructs a bindable map with parent object \a parent.
*/
QQmlPropertyMap::QQmlPropertyMap(QObject *parent)
-: QObject(*allocatePrivate(), parent)
+: QQmlPropertyMap(&staticMetaObject, parent)
{
- init(metaObject());
}
/*!
@@ -339,18 +338,13 @@ QVariant QQmlPropertyMap::updateValue(const QString &key, const QVariant &input)
}
/*! \internal */
-void QQmlPropertyMap::init(const QMetaObject *staticMetaObject)
+QQmlPropertyMap::QQmlPropertyMap(const QMetaObject *staticMetaObject, QObject *parent)
+ : QObject(*(new QQmlPropertyMapPrivate), parent)
{
Q_D(QQmlPropertyMap);
d->mo = new QQmlPropertyMapMetaObject(this, d, staticMetaObject);
}
-/*! \internal */
-QObjectPrivate *QQmlPropertyMap::allocatePrivate()
-{
- return new QQmlPropertyMapPrivate;
-}
-
/*!
\fn void QQmlPropertyMap::valueChanged(const QString &key, const QVariant &value)
This signal is emitted whenever one of the values in the map is changed. \a key
diff --git a/src/qml/util/qqmlpropertymap.h b/src/qml/util/qqmlpropertymap.h
index 01048f3662..8c5ecce48e 100644
--- a/src/qml/util/qqmlpropertymap.h
+++ b/src/qml/util/qqmlpropertymap.h
@@ -80,15 +80,13 @@ protected:
template<class DerivedType>
QQmlPropertyMap(DerivedType *derived, QObject *parentObj)
- : QObject(*allocatePrivate(), parentObj)
+ : QQmlPropertyMap(&DerivedType::staticMetaObject, parentObj)
{
Q_UNUSED(derived)
- init(&DerivedType::staticMetaObject);
}
private:
- void init(const QMetaObject *staticMetaObject);
- static QObjectPrivate *allocatePrivate();
+ QQmlPropertyMap(const QMetaObject *staticMetaObject, QObject *parent);
Q_DECLARE_PRIVATE(QQmlPropertyMap)
Q_DISABLE_COPY(QQmlPropertyMap)