aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorErik Verbruggen <[email protected]>2017-06-16 15:24:28 +0200
committerLars Knoll <[email protected]>2017-06-20 10:03:37 +0000
commit24969e19b18ea68019ae66c99982f04b2d05a9d1 (patch)
treea4939d916d301b86659d82b30e63d8b1f184ff6e /src
parentb829693623f886975a3e79c2f6804a7564449977 (diff)
Support object literals
Diffstat (limited to 'src')
-rw-r--r--src/qml/compiler/qv4codegen.cpp172
-rw-r--r--src/qml/compiler/qv4codegen_p.h15
-rw-r--r--src/qml/compiler/qv4compiler.cpp23
-rw-r--r--src/qml/compiler/qv4compiler_p.h7
-rw-r--r--src/qml/compiler/qv4isel_moth.cpp7
-rw-r--r--src/qml/compiler/qv4isel_p.h4
-rw-r--r--src/qml/jit/qv4isel_masm.cpp7
7 files changed, 110 insertions, 125 deletions
diff --git a/src/qml/compiler/qv4codegen.cpp b/src/qml/compiler/qv4codegen.cpp
index 6a0973f774..b443c5364f 100644
--- a/src/qml/compiler/qv4codegen.cpp
+++ b/src/qml/compiler/qv4codegen.cpp
@@ -2104,21 +2104,6 @@ bool Codegen::visit(NumericLiteral *ast)
return false;
}
-struct ObjectPropertyValue {
- ObjectPropertyValue()
- : value(0)
- , getter(-1)
- , setter(-1)
- {}
-
- IR::Expr *value;
- int getter; // index in _module->functions or -1 if not set
- int setter;
-
- bool hasGetter() const { return getter >= 0; }
- bool hasSetter() const { return setter >= 0; }
-};
-
bool Codegen::visit(ObjectLiteral *ast)
{
if (hasError)
@@ -2126,33 +2111,28 @@ bool Codegen::visit(ObjectLiteral *ast)
QMap<QString, ObjectPropertyValue> valueMap;
- const unsigned t = _block->newTemp();
+ auto result = Reference::fromTemp(this, _block->newTemp());
TempScope scope(_function);
for (PropertyAssignmentList *it = ast->properties; it; it = it->next) {
QString name = it->assignment->name->asString();
if (PropertyNameAndValue *nv = AST::cast<AST::PropertyNameAndValue *>(it->assignment)) {
- Result value = expression(nv->value);
+ Reference value = expression(nv->value);
if (hasError)
return false;
+
ObjectPropertyValue &v = valueMap[name];
- if (v.hasGetter() || v.hasSetter() || (_function->isStrict && v.value)) {
+ if (v.hasGetter() || v.hasSetter() || (_function->isStrict && v.rvalue.isValid())) {
throwSyntaxError(nv->lastSourceLocation(),
QStringLiteral("Illegal duplicate key '%1' in object literal").arg(name));
return false;
}
- if (IR::Const *c = (*value)->asConst()) {
- valueMap[name].value = c;
- } else {
- unsigned t = _block->newTemp();
- move(_block->TEMP(t), *value);
- valueMap[name].value = _block->TEMP(t);
- }
+ v.rvalue = value;
} else if (PropertyGetterSetter *gs = AST::cast<AST::PropertyGetterSetter *>(it->assignment)) {
const int function = defineFunction(name, gs, gs->formals, gs->functionBody ? gs->functionBody->elements : 0);
ObjectPropertyValue &v = valueMap[name];
- if (v.value ||
+ if (v.rvalue.isValid() ||
(gs->type == PropertyGetterSetter::Getter && v.hasGetter()) ||
(gs->type == PropertyGetterSetter::Setter && v.hasSetter())) {
throwSyntaxError(gs->lastSourceLocation(),
@@ -2168,96 +2148,82 @@ bool Codegen::visit(ObjectLiteral *ast)
}
}
- // The linked-list arguments to builtin_define_object_literal
- // begin with a CONST counting the number of key/value pairs, followed by the
- // key value pairs, followed by the array entries.
- IR::ExprList *args = _function->New<IR::ExprList>();
-
- IR::Const *entryCountParam = _function->New<IR::Const>();
- entryCountParam->init(IR::SInt32Type, 0);
- args->expr = entryCountParam;
- args->next = 0;
-
- IR::ExprList *keyValueEntries = 0;
- IR::ExprList *currentKeyValueEntry = 0;
- int keyValueEntryCount = 0;
- IR::ExprList *arrayEntries = 0;
+ QVector<QString> nonArrayKey, arrayKeyWithValue, arrayKeyWithGetterSetter;
+ bool needSparseArray = false; // set to true if any array index is bigger than 16
- IR::ExprList *currentArrayEntry = 0;
-
- for (QMap<QString, ObjectPropertyValue>::iterator it = valueMap.begin(); it != valueMap.end(); ) {
- IR::ExprList **currentPtr = 0;
- uint keyAsIndex = QV4::String::toArrayIndex(it.key());
- if (keyAsIndex != UINT_MAX) {
- if (!arrayEntries) {
- arrayEntries = _function->New<IR::ExprList>();
- currentArrayEntry = arrayEntries;
- } else {
- currentArrayEntry->next = _function->New<IR::ExprList>();
- currentArrayEntry = currentArrayEntry->next;
- }
- currentPtr = &currentArrayEntry;
- IR::Const *idx = _function->New<IR::Const>();
- idx->init(IR::UInt32Type, keyAsIndex);
- (*currentPtr)->expr = idx;
+ for (QMap<QString, ObjectPropertyValue>::iterator it = valueMap.begin(), eit = valueMap.end();
+ it != eit; ++it) {
+ QString name = it.key();
+ uint keyAsIndex = QV4::String::toArrayIndex(name);
+ if (keyAsIndex != std::numeric_limits<uint>::max()) {
+ it->keyAsIndex = keyAsIndex;
+ if (keyAsIndex > 16)
+ needSparseArray = true;
+ if (it->hasSetter() || it->hasGetter())
+ arrayKeyWithGetterSetter.append(name);
+ else
+ arrayKeyWithValue.append(name);
} else {
- if (!keyValueEntries) {
- keyValueEntries = _function->New<IR::ExprList>();
- currentKeyValueEntry = keyValueEntries;
- } else {
- currentKeyValueEntry->next = _function->New<IR::ExprList>();
- currentKeyValueEntry = currentKeyValueEntry->next;
- }
- currentPtr = &currentKeyValueEntry;
- (*currentPtr)->expr = _block->NAME(it.key(), 0, 0);
- keyValueEntryCount++;
+ nonArrayKey.append(name);
}
+ }
- IR::ExprList *&current = *currentPtr;
- if (it->value) {
- current->next = _function->New<IR::ExprList>();
- current = current->next;
- current->expr = _block->CONST(IR::BoolType, true);
+ int argc = 0;
+ auto push = [this, &argc](const Reference &arg) {
+ Reference::fromTemp(this, argc).store(arg);
+ argc += 1;
+ };
- current->next = _function->New<IR::ExprList>();
- current = current->next;
- current->expr = it->value;
+ auto undefined = [this](){ return Reference::fromConst(this, Encode::undefined()); };
+ QVector<QV4::Compiler::JSUnitGenerator::MemberInfo> members;
+
+ // generate the key/value pairs
+ for (const QString &key : qAsConst(nonArrayKey)) {
+ const ObjectPropertyValue &prop = valueMap[key];
+
+ if (prop.hasGetter() || prop.hasSetter()) {
+ Q_ASSERT(!prop.rvalue.isValid());
+ push(prop.hasGetter() ? Reference::fromClosure(this, prop.getter) : undefined());
+ push(prop.hasSetter() ? Reference::fromClosure(this, prop.setter) : undefined());
+ members.append({ key, true });
} else {
- current->next = _function->New<IR::ExprList>();
- current = current->next;
- current->expr = _block->CONST(IR::BoolType, false);
-
- unsigned getter = _block->newTemp();
- unsigned setter = _block->newTemp();
- move(_block->TEMP(getter), it->hasGetter() ? _block->CLOSURE(it->getter) : _block->CONST(IR::UndefinedType, 0));
- move(_block->TEMP(setter), it->hasSetter() ? _block->CLOSURE(it->setter) : _block->CONST(IR::UndefinedType, 0));
-
- current->next = _function->New<IR::ExprList>();
- current = current->next;
- current->expr = _block->TEMP(getter);
- current->next = _function->New<IR::ExprList>();
- current = current->next;
- current->expr = _block->TEMP(setter);
+ Q_ASSERT(prop.rvalue.isValid());
+ push(prop.rvalue);
+ members.append({ key, false });
}
-
- it = valueMap.erase(it);
}
- entryCountParam->value = keyValueEntryCount;
+ // generate array entries with values
+ for (const QString &key : qAsConst(arrayKeyWithValue)) {
+ const ObjectPropertyValue &prop = valueMap[key];
+ Q_ASSERT(!prop.hasGetter() && !prop.hasSetter());
+ push(Reference::fromConst(this, Encode(prop.keyAsIndex)));
+ push(prop.rvalue);
+ }
- if (keyValueEntries)
- args->next = keyValueEntries;
- if (arrayEntries) {
- if (currentKeyValueEntry)
- currentKeyValueEntry->next = arrayEntries;
- else
- args->next = arrayEntries;
+ // generate array entries with both a value and a setter
+ for (const QString &key : qAsConst(arrayKeyWithGetterSetter)) {
+ const ObjectPropertyValue &prop = valueMap[key];
+ Q_ASSERT(!prop.rvalue.isValid());
+ push(Reference::fromConst(this, Encode(prop.keyAsIndex)));
+ push(prop.hasGetter() ? Reference::fromClosure(this, prop.getter) : undefined());
+ push(prop.hasSetter() ? Reference::fromClosure(this, prop.setter) : undefined());
}
- move(_block->TEMP(t), _block->CALL(_block->NAME(IR::Name::builtin_define_object_literal,
- ast->firstSourceLocation().startLine, ast->firstSourceLocation().startColumn), args));
+ int classId = jsUnitGenerator->registerJSClass(members);
+
+ uint arrayGetterSetterCountAndFlags = arrayKeyWithGetterSetter.size();
+ arrayGetterSetterCountAndFlags |= needSparseArray << 30;
+
+ QV4::Moth::Instruction::CallBuiltinDefineObjectLiteral call;
+ call.internalClassId = classId;
+ call.arrayValueCount = arrayKeyWithValue.size();
+ call.arrayGetterSetterCountAndFlags = arrayGetterSetterCountAndFlags;
+ call.args = 0;
+ call.result = result.asLValue();
+ bytecodeGenerator->addInstruction(call);
- _expr.code = _block->TEMP(t);
+ _expr.result = result;
return false;
}
diff --git a/src/qml/compiler/qv4codegen_p.h b/src/qml/compiler/qv4codegen_p.h
index cad37c30d4..4762fff074 100644
--- a/src/qml/compiler/qv4codegen_p.h
+++ b/src/qml/compiler/qv4codegen_p.h
@@ -225,6 +225,21 @@ public:
int tempCountForScope;
};
+ struct ObjectPropertyValue {
+ ObjectPropertyValue()
+ : getter(-1)
+ , setter(-1)
+ , keyAsIndex(UINT_MAX)
+ {}
+
+ Reference rvalue;
+ int getter; // index in _module->functions or -1 if not set
+ int setter;
+ uint keyAsIndex;
+
+ bool hasGetter() const { return getter >= 0; }
+ bool hasSetter() const { return setter >= 0; }
+ };
protected:
enum Format { ex, cx, nx };
diff --git a/src/qml/compiler/qv4compiler.cpp b/src/qml/compiler/qv4compiler.cpp
index acfa2fb99a..373c7e9d87 100644
--- a/src/qml/compiler/qv4compiler.cpp
+++ b/src/qml/compiler/qv4compiler.cpp
@@ -201,33 +201,24 @@ QV4::ReturnedValue QV4::Compiler::JSUnitGenerator::constant(int idx)
return constants.at(idx);
}
-int QV4::Compiler::JSUnitGenerator::registerJSClass(int count, IR::ExprList *args)
+int QV4::Compiler::JSUnitGenerator::registerJSClass(const QVector<MemberInfo> &members)
{
// ### re-use existing class definitions.
- const int size = CompiledData::JSClass::calculateSize(count);
+ const int size = CompiledData::JSClass::calculateSize(members.size());
jsClassOffsets.append(jsClassData.size());
const int oldSize = jsClassData.size();
jsClassData.resize(jsClassData.size() + size);
memset(jsClassData.data() + oldSize, 0, size);
CompiledData::JSClass *jsClass = reinterpret_cast<CompiledData::JSClass*>(jsClassData.data() + oldSize);
- jsClass->nMembers = count;
+ jsClass->nMembers = members.size();
CompiledData::JSClassMember *member = reinterpret_cast<CompiledData::JSClassMember*>(jsClass + 1);
- IR::ExprList *it = args;
- for (int i = 0; i < count; ++i, it = it->next, ++member) {
- QV4::IR::Name *name = it->expr->asName();
- it = it->next;
-
- const bool isData = it->expr->asConst()->value;
- it = it->next;
-
- member->nameOffset = registerString(*name->id);
- member->isAccessor = !isData;
-
- if (!isData)
- it = it->next;
+ for (const MemberInfo &memberInfo : members) {
+ member->nameOffset = registerString(memberInfo.name);
+ member->isAccessor = memberInfo.isAccessor;
+ ++member;
}
return jsClassOffsets.size() - 1;
diff --git a/src/qml/compiler/qv4compiler_p.h b/src/qml/compiler/qv4compiler_p.h
index 4571268cd8..bdf39c887e 100644
--- a/src/qml/compiler/qv4compiler_p.h
+++ b/src/qml/compiler/qv4compiler_p.h
@@ -90,6 +90,11 @@ private:
};
struct Q_QML_PRIVATE_EXPORT JSUnitGenerator {
+ struct MemberInfo {
+ QString name;
+ bool isAccessor;
+ };
+
JSUnitGenerator(IR::Module *module);
int registerString(const QString &str) { return stringTable.registerString(str); }
@@ -108,7 +113,7 @@ struct Q_QML_PRIVATE_EXPORT JSUnitGenerator {
int registerConstant(ReturnedValue v);
ReturnedValue constant(int idx);
- int registerJSClass(int count, IR::ExprList *args);
+ int registerJSClass(const QVector<MemberInfo> &members);
int registerJSClass(int count, CompiledData::JSClassMember *members);
enum GeneratorOption {
diff --git a/src/qml/compiler/qv4isel_moth.cpp b/src/qml/compiler/qv4isel_moth.cpp
index 7d62d71e98..24fbe3c680 100644
--- a/src/qml/compiler/qv4isel_moth.cpp
+++ b/src/qml/compiler/qv4isel_moth.cpp
@@ -1219,15 +1219,16 @@ void InstructionSelection::callBuiltinDefineObjectLiteral(IR::Expr *result, int
{
int argLocation = outgoingArgumentTempStart();
- const int classId = registerJSClass(keyValuePairCount, keyValuePairs);
+ QVector<Compiler::JSUnitGenerator::MemberInfo> members;
// Process key/value pairs first
IR::ExprList *it = keyValuePairs;
for (int i = 0; i < keyValuePairCount; ++i, it = it->next) {
- // Skip name
+ QString key = *it->expr->asName()->id;
it = it->next;
bool isData = it->expr->asConst()->value;
+ members.append({ key, !isData });
it = it->next;
if (IR::Const *c = it->expr->asConst()) {
@@ -1254,6 +1255,8 @@ void InstructionSelection::callBuiltinDefineObjectLiteral(IR::Expr *result, int
}
}
+ const int classId = registerJSClass(members);
+
// Process array values
uint arrayValueCount = 0;
it = arrayEntries;
diff --git a/src/qml/compiler/qv4isel_p.h b/src/qml/compiler/qv4isel_p.h
index 037c02e5ea..e27bf0e284 100644
--- a/src/qml/compiler/qv4isel_p.h
+++ b/src/qml/compiler/qv4isel_p.h
@@ -87,7 +87,9 @@ public:
uint registerSetterLookup(const QString &name) { return jsGenerator->registerSetterLookup(name); }
uint registerGlobalGetterLookup(const QString &name) { return jsGenerator->registerGlobalGetterLookup(name); }
int registerRegExp(IR::RegExp *regexp) { return jsGenerator->registerRegExp(regexp); }
- int registerJSClass(int count, IR::ExprList *args) { return jsGenerator->registerJSClass(count, args); }
+ int registerJSClass(const QVector<Compiler::JSUnitGenerator::MemberInfo> &members) {
+ return jsGenerator->registerJSClass(members);
+ }
QV4::Compiler::JSUnitGenerator *jsUnitGenerator() const { return jsGenerator; }
protected:
diff --git a/src/qml/jit/qv4isel_masm.cpp b/src/qml/jit/qv4isel_masm.cpp
index 7784eb364e..e1974f5776 100644
--- a/src/qml/jit/qv4isel_masm.cpp
+++ b/src/qml/jit/qv4isel_masm.cpp
@@ -339,15 +339,16 @@ void InstructionSelection<JITAssembler>::callBuiltinDefineObjectLiteral(IR::Expr
{
Q_ASSERT(result);
+ QVector<Compiler::JSUnitGenerator::MemberInfo> members;
int argc = 0;
- const int classId = registerJSClass(keyValuePairCount, keyValuePairs);
-
IR::ExprList *it = keyValuePairs;
for (int i = 0; i < keyValuePairCount; ++i, it = it->next) {
+ QString key = *it->expr->asName()->id;
it = it->next;
bool isData = it->expr->asConst()->value;
+ members.append({ key, !isData });
it = it->next;
_as->copyValue(_as->stackLayout().argumentAddressForCall(argc++), it->expr, WriteBarrier::NoBarrier);
@@ -358,6 +359,8 @@ void InstructionSelection<JITAssembler>::callBuiltinDefineObjectLiteral(IR::Expr
}
}
+ const int classId = registerJSClass(members);
+
it = arrayEntries;
uint arrayValueCount = 0;
while (it) {