diff options
Diffstat (limited to 'src/qml/compiler/qv4codegen.cpp')
-rw-r--r-- | src/qml/compiler/qv4codegen.cpp | 172 |
1 files changed, 69 insertions, 103 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 = ¤tArrayEntry; - 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 = ¤tKeyValueEntry; - (*currentPtr)->expr = _block->NAME(it.key(), 0, 0); - keyValueEntryCount++; + nonArrayKey.append(name); } + } - IR::ExprList *¤t = *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; } |