diff options
Diffstat (limited to 'src/qml')
167 files changed, 10033 insertions, 8305 deletions
diff --git a/src/qml/compiler/qqmlirbuilder.cpp b/src/qml/compiler/qqmlirbuilder.cpp index 28a4e23a37..f02e92ceb2 100644 --- a/src/qml/compiler/qqmlirbuilder.cpp +++ b/src/qml/compiler/qqmlirbuilder.cpp @@ -558,9 +558,8 @@ IRBuilder::IRBuilder(const QSet<QString> &illegalNames) { } -bool IRBuilder::generateFromQml(const QString &code, const QString &url, const QString &urlString, Document *output) +bool IRBuilder::generateFromQml(const QString &code, const QString &url, Document *output) { - this->url = url; QQmlJS::AST::UiProgram *program = 0; { QQmlJS::Lexer lexer(&output->jsParserEngine); @@ -574,7 +573,7 @@ bool IRBuilder::generateFromQml(const QString &code, const QString &url, const Q foreach (const QQmlJS::DiagnosticMessage &m, parser.diagnosticMessages()) { if (m.isWarning()) { - qWarning("%s:%d : %s", qPrintable(urlString), m.loc.startLine, qPrintable(m.message)); + qWarning("%s:%d : %s", qPrintable(url), m.loc.startLine, qPrintable(m.message)); continue; } diff --git a/src/qml/compiler/qqmlirbuilder_p.h b/src/qml/compiler/qqmlirbuilder_p.h index 3438af425c..1aac878776 100644 --- a/src/qml/compiler/qqmlirbuilder_p.h +++ b/src/qml/compiler/qqmlirbuilder_p.h @@ -343,7 +343,7 @@ struct Q_QML_PRIVATE_EXPORT IRBuilder : public QQmlJS::AST::Visitor Q_DECLARE_TR_FUNCTIONS(QQmlCodeGenerator) public: IRBuilder(const QSet<QString> &illegalNames); - bool generateFromQml(const QString &code, const QString &url, const QString &urlString, Document *output); + bool generateFromQml(const QString &code, const QString &url, Document *output); static bool isSignalPropertyName(const QString &name); @@ -420,7 +420,6 @@ public: QQmlJS::MemoryPool *pool; QString sourceCode; - QString url; QV4::Compiler::JSUnitGenerator *jsGenerator; }; diff --git a/src/qml/compiler/qqmltypecompiler.cpp b/src/qml/compiler/qqmltypecompiler.cpp index 60a0829b9b..e2636a57c3 100644 --- a/src/qml/compiler/qqmltypecompiler.cpp +++ b/src/qml/compiler/qqmltypecompiler.cpp @@ -298,7 +298,7 @@ bool QQmlTypeCompiler::compile() void QQmlTypeCompiler::recordError(const QQmlError &error) { QQmlError e = error; - e.setUrl(compiledData->url); + e.setUrl(url()); errors << e; } @@ -378,9 +378,9 @@ QHash<int, QHash<int, int> > *QQmlTypeCompiler::objectIndexToIdPerComponent() return &compiledData->objectIndexToIdPerComponent; } -QHash<int, QQmlCompiledData::CustomParserData> *QQmlTypeCompiler::customParserData() +QHash<int, QBitArray> *QQmlTypeCompiler::customParserBindings() { - return &compiledData->customParserData; + return &compiledData->customParserBindings; } QQmlJS::MemoryPool *QQmlTypeCompiler::memoryPool() @@ -398,11 +398,6 @@ const QV4::Compiler::StringTableGenerator *QQmlTypeCompiler::stringPool() const return &document->jsGenerator.stringTable; } -void QQmlTypeCompiler::setCustomParserBindings(const QVector<int> &bindings) -{ - compiledData->customParserBindings = bindings; -} - void QQmlTypeCompiler::setDeferredBindingsPerObject(const QHash<int, QBitArray> &deferredBindingsPerObject) { compiledData->deferredBindingsPerObject = deferredBindingsPerObject; @@ -1720,7 +1715,7 @@ QQmlPropertyValidator::QQmlPropertyValidator(QQmlTypeCompiler *typeCompiler) , customParsers(typeCompiler->customParserCache()) , propertyCaches(typeCompiler->propertyCaches()) , objectIndexToIdPerComponent(*typeCompiler->objectIndexToIdPerComponent()) - , customParserData(typeCompiler->customParserData()) + , customParserBindingsPerObject(typeCompiler->customParserBindings()) , _seenObjectWithId(false) { } @@ -1729,7 +1724,6 @@ bool QQmlPropertyValidator::validate() { if (!validateObject(qmlUnit->indexOfRootObject, /*instantiatingBinding*/0)) return false; - compiler->setCustomParserBindings(customParserBindings); compiler->setDeferredBindingsPerObject(deferredBindingsPerObject); return true; } @@ -1739,13 +1733,6 @@ const QQmlImports &QQmlPropertyValidator::imports() const return *compiler->imports(); } -QQmlBinding::Identifier QQmlPropertyValidator::bindingIdentifier(const QV4::CompiledData::Binding *binding, QQmlCustomParser *) -{ - const int id = customParserBindings.count(); - customParserBindings.append(binding->value.compiledScriptIndex); - return id; -} - QString QQmlPropertyValidator::bindingAsString(int objectIndex, const QV4::CompiledData::Binding *binding) const { const QmlIR::Object *object = compiler->qmlObjects()->value(objectIndex); @@ -2016,11 +2003,11 @@ bool QQmlPropertyValidator::validateObject(int objectIndex, const QV4::CompiledD if (customParser && !customBindings.isEmpty()) { customParser->clearErrors(); customParser->compiler = this; - QQmlCompiledData::CustomParserData data; - data.bindings = customParserBindings; - data.compilationArtifact = customParser->compile(qmlUnit, customBindings); + customParser->imports = compiler->imports(); + customParser->verifyBindings(qmlUnit, customBindings); customParser->compiler = 0; - customParserData->insert(objectIndex, data); + customParser->imports = (QQmlImports*)0; + customParserBindingsPerObject->insert(objectIndex, customParserBindings); const QList<QQmlError> parserErrors = customParser->errors(); if (!parserErrors.isEmpty()) { foreach (QQmlError error, parserErrors) @@ -2166,7 +2153,7 @@ bool QQmlPropertyValidator::validateLiteralBinding(QQmlPropertyCache *propertyCa #endif // QT_NO_DATESTRING case QVariant::Point: { bool ok = false; - QQmlStringConverters::pointFFromString(binding->valueAsString(&qmlUnit->header), &ok).toPoint(); + QQmlStringConverters::pointFFromString(binding->valueAsString(&qmlUnit->header), &ok); if (!ok) { recordError(binding->valueLocation, tr("Invalid property assignment: point expected")); return false; @@ -2184,7 +2171,7 @@ bool QQmlPropertyValidator::validateLiteralBinding(QQmlPropertyCache *propertyCa break; case QVariant::Size: { bool ok = false; - QQmlStringConverters::sizeFFromString(binding->valueAsString(&qmlUnit->header), &ok).toSize(); + QQmlStringConverters::sizeFFromString(binding->valueAsString(&qmlUnit->header), &ok); if (!ok) { recordError(binding->valueLocation, tr("Invalid property assignment: size expected")); return false; @@ -2202,7 +2189,7 @@ bool QQmlPropertyValidator::validateLiteralBinding(QQmlPropertyCache *propertyCa break; case QVariant::Rect: { bool ok = false; - QQmlStringConverters::rectFFromString(binding->valueAsString(&qmlUnit->header), &ok).toRect(); + QQmlStringConverters::rectFFromString(binding->valueAsString(&qmlUnit->header), &ok); if (!ok) { recordError(binding->valueLocation, tr("Invalid property assignment: rect expected")); return false; @@ -2257,7 +2244,7 @@ bool QQmlPropertyValidator::validateLiteralBinding(QQmlPropertyCache *propertyCa // generate single literal value assignment to a list property if required if (property->propType == qMetaTypeId<QList<qreal> >()) { if (binding->type != QV4::CompiledData::Binding::Type_Number) { - recordError(binding->valueLocation, tr("Invalid property assignment: real or array of reals expected")); + recordError(binding->valueLocation, tr("Invalid property assignment: number or array of numbers expected")); return false; } break; diff --git a/src/qml/compiler/qqmltypecompiler_p.h b/src/qml/compiler/qqmltypecompiler_p.h index fb8ac94fcd..caf1f93923 100644 --- a/src/qml/compiler/qqmltypecompiler_p.h +++ b/src/qml/compiler/qqmltypecompiler_p.h @@ -84,7 +84,7 @@ public: const QV4::CompiledData::QmlUnit *qmlUnit() const; - QUrl url() const { return compiledData->url; } + QUrl url() const { return typeData->finalUrl(); } QQmlEnginePrivate *enginePrivate() const { return engine; } const QQmlImports *imports() const; QHash<int, QQmlCompiledData::TypeReference *> *resolvedTypes(); @@ -96,11 +96,10 @@ public: QVector<QByteArray> *vmeMetaObjects() const; QHash<int, int> *objectIndexToIdForRoot(); QHash<int, QHash<int, int> > *objectIndexToIdPerComponent(); - QHash<int, QQmlCompiledData::CustomParserData> *customParserData(); + QHash<int, QBitArray> *customParserBindings(); QQmlJS::MemoryPool *memoryPool(); QStringRef newStringRef(const QString &string); const QV4::Compiler::StringTableGenerator *stringPool() const; - void setCustomParserBindings(const QVector<int> &bindings); void setDeferredBindingsPerObject(const QHash<int, QBitArray> &deferredBindingsPerObject); const QHash<int, QQmlCustomParser*> &customParserCache() const { return customParsers; } @@ -282,7 +281,6 @@ public: // Re-implemented for QQmlCustomParser virtual const QQmlImports &imports() const; - virtual QQmlBinding::Identifier bindingIdentifier(const QV4::CompiledData::Binding *binding, QQmlCustomParser *parser); virtual QString bindingAsString(int objectIndex, const QV4::CompiledData::Binding *binding) const; private: @@ -300,8 +298,7 @@ private: const QHash<int, QQmlCustomParser*> &customParsers; const QVector<QQmlPropertyCache *> &propertyCaches; const QHash<int, QHash<int, int> > objectIndexToIdPerComponent; - QHash<int, QQmlCompiledData::CustomParserData> *customParserData; - QVector<int> customParserBindings; + QHash<int, QBitArray> *customParserBindingsPerObject; QHash<int, QBitArray> deferredBindingsPerObject; bool _seenObjectWithId; @@ -394,6 +391,7 @@ private: virtual void visitClosure(QV4::IR::Closure *closure); virtual void visitTemp(QV4::IR::Temp *) {} + virtual void visitArgLocal(QV4::IR::ArgLocal *) {} virtual void visitMove(QV4::IR::Move *s) { s->source->accept(this); diff --git a/src/qml/compiler/qv4codegen.cpp b/src/qml/compiler/qv4codegen.cpp index fdc4d5c9f2..2d45543305 100644 --- a/src/qml/compiler/qv4codegen.cpp +++ b/src/qml/compiler/qv4codegen.cpp @@ -487,11 +487,9 @@ void Codegen::leaveEnvironment() _env = _env->parent; } -void Codegen::enterLoop(Statement *node, IR::BasicBlock *startBlock, IR::BasicBlock *breakBlock, IR::BasicBlock *continueBlock) +void Codegen::enterLoop(Statement *node, IR::BasicBlock *breakBlock, IR::BasicBlock *continueBlock) { - if (startBlock) - startBlock->markAsGroupStart(); - _loop = new Loop(node, startBlock, breakBlock, continueBlock, _loop); + _loop = new Loop(node, breakBlock, continueBlock, _loop); _loop->labelledStatement = _labelledStatement; // consume the enclosing labelled statement _loop->scopeAndFinally = _scopeAndFinally; _labelledStatement = 0; @@ -509,8 +507,8 @@ IR::Expr *Codegen::member(IR::Expr *base, const QString *name) if (hasError) return 0; - if (base->asTemp() /*|| base->asName()*/) - return _block->MEMBER(base->asTemp(), name); + if (base->asTemp() || base->asArgLocal()) + return _block->MEMBER(base, name); else { const unsigned t = _block->newTemp(); move(_block->TEMP(t), base); @@ -523,25 +521,26 @@ IR::Expr *Codegen::subscript(IR::Expr *base, IR::Expr *index) if (hasError) return 0; - if (! base->asTemp()) { + if (! base->asTemp() || base->asArgLocal()) { const unsigned t = _block->newTemp(); move(_block->TEMP(t), base); base = _block->TEMP(t); } - if (! index->asTemp()) { + if (! index->asTemp() || index->asArgLocal()) { const unsigned t = _block->newTemp(); move(_block->TEMP(t), index); index = _block->TEMP(t); } - Q_ASSERT(base->asTemp() && index->asTemp()); + Q_ASSERT(base->asTemp() || base->asArgLocal()); + Q_ASSERT(index->asTemp() || index->asArgLocal()); return _block->SUBSCRIPT(base->asTemp(), index->asTemp()); } IR::Expr *Codegen::argument(IR::Expr *expr) { - if (expr && ! expr->asTemp()) { + if (expr && !expr->asTemp() && !expr->asArgLocal()) { const unsigned t = _block->newTemp(); move(_block->TEMP(t), expr); expr = _block->TEMP(t); @@ -555,7 +554,7 @@ IR::Expr *Codegen::reference(IR::Expr *expr) if (hasError) return 0; - if (expr && !expr->asTemp() && !expr->asName() && !expr->asMember() && !expr->asSubscript()) { + if (expr && !expr->asTemp() && !expr->asArgLocal() && !expr->asName() && !expr->asMember() && !expr->asSubscript()) { const unsigned t = _block->newTemp(); move(_block->TEMP(t), expr); expr = _block->TEMP(t); @@ -591,13 +590,13 @@ IR::Expr *Codegen::unop(IR::AluOp op, IR::Expr *expr) } } } - if (! expr->asTemp()) { + if (!expr->asTemp() && !expr->asArgLocal()) { const unsigned t = _block->newTemp(); move(_block->TEMP(t), expr); expr = _block->TEMP(t); } - Q_ASSERT(expr->asTemp()); - return _block->UNOP(op, expr->asTemp()); + Q_ASSERT(expr->asTemp() || expr->asArgLocal()); + return _block->UNOP(op, expr); } IR::Expr *Codegen::binop(IR::AluOp op, IR::Expr *left, IR::Expr *right) @@ -655,20 +654,20 @@ IR::Expr *Codegen::binop(IR::AluOp op, IR::Expr *left, IR::Expr *right) } } - if (!left->asTemp()) { + if (!left->asTemp() && !left->asArgLocal()) { const unsigned t = _block->newTemp(); move(_block->TEMP(t), left); left = _block->TEMP(t); } - if (!right->asTemp()) { + if (!right->asTemp() && !right->asArgLocal()) { const unsigned t = _block->newTemp(); move(_block->TEMP(t), right); right = _block->TEMP(t); } - Q_ASSERT(left->asTemp()); - Q_ASSERT(right->asTemp()); + Q_ASSERT(left->asTemp() || left->asArgLocal()); + Q_ASSERT(right->asTemp() || right->asArgLocal()); return _block->BINOP(op, left, right); } @@ -693,12 +692,12 @@ void Codegen::move(IR::Expr *target, IR::Expr *source, IR::AluOp op) return; } - if (!source->asTemp() && !source->asConst() && !target->asTemp()) { + if (!source->asTemp() && !source->asConst() && !target->asTemp() && !source->asArgLocal() && !target->asArgLocal()) { unsigned t = _block->newTemp(); _block->MOVE(_block->TEMP(t), source); source = _block->TEMP(t); } - if (source->asConst() && !target->asTemp()) { + if (source->asConst() && !target->asTemp() && !target->asArgLocal()) { unsigned t = _block->newTemp(); _block->MOVE(_block->TEMP(t), source); source = _block->TEMP(t); @@ -749,7 +748,7 @@ void Codegen::statement(ExpressionNode *ast) if (r.format == ex) { if (r->asCall()) { _block->EXP(*r); // the nest nx representation for calls is EXP(CALL(c..)) - } else if (r->asTemp()) { + } else if (r->asTemp() || r->asArgLocal()) { // there is nothing to do } else { unsigned t = _block->newTemp(); @@ -1065,7 +1064,7 @@ bool Codegen::visit(ArrayLiteral *ast) current = arg; IR::Expr *exp = *expr; - if (exp->asTemp() || exp->asConst()) { + if (exp->asTemp() || expr->asArgLocal() || exp->asConst()) { current->expr = exp; } else { unsigned value = _block->newTemp(); @@ -1126,13 +1125,13 @@ bool Codegen::visit(BinaryExpression *ast) if (ast->op == QSOperator::And) { if (_expr.accept(cx)) { - IR::BasicBlock *iftrue = _function->newBasicBlock(groupStartBlock(), exceptionHandler()); + IR::BasicBlock *iftrue = _function->newBasicBlock(exceptionHandler()); condition(ast->left, iftrue, _expr.iffalse); _block = iftrue; condition(ast->right, _expr.iftrue, _expr.iffalse); } else { - IR::BasicBlock *iftrue = _function->newBasicBlock(groupStartBlock(), exceptionHandler()); - IR::BasicBlock *endif = _function->newBasicBlock(groupStartBlock(), exceptionHandler()); + IR::BasicBlock *iftrue = _function->newBasicBlock(exceptionHandler()); + IR::BasicBlock *endif = _function->newBasicBlock(exceptionHandler()); const unsigned r = _block->newTemp(); @@ -1148,13 +1147,13 @@ bool Codegen::visit(BinaryExpression *ast) return false; } else if (ast->op == QSOperator::Or) { if (_expr.accept(cx)) { - IR::BasicBlock *iffalse = _function->newBasicBlock(groupStartBlock(), exceptionHandler()); + IR::BasicBlock *iffalse = _function->newBasicBlock(exceptionHandler()); condition(ast->left, _expr.iftrue, iffalse); _block = iffalse; condition(ast->right, _expr.iftrue, _expr.iffalse); } else { - IR::BasicBlock *iffalse = _function->newBasicBlock(groupStartBlock(), exceptionHandler()); - IR::BasicBlock *endif = _function->newBasicBlock(groupStartBlock(), exceptionHandler()); + IR::BasicBlock *iffalse = _function->newBasicBlock(exceptionHandler()); + IR::BasicBlock *endif = _function->newBasicBlock(exceptionHandler()); const unsigned r = _block->newTemp(); move(_block->TEMP(r), *expression(ast->left)); @@ -1236,7 +1235,7 @@ bool Codegen::visit(BinaryExpression *ast) case QSOperator::Lt: case QSOperator::StrictEqual: case QSOperator::StrictNotEqual: { - if (!left->asTemp() && !left->asConst()) { + if (!left->asTemp() && !left->asArgLocal() && !left->asConst()) { const unsigned t = _block->newTemp(); move(_block->TEMP(t), left); left = _block->TEMP(t); @@ -1270,7 +1269,7 @@ bool Codegen::visit(BinaryExpression *ast) case QSOperator::RShift: case QSOperator::Sub: case QSOperator::URShift: { - if (!left->asTemp() && !left->asConst()) { + if (!left->asTemp() && !left->asArgLocal() && !left->asConst()) { const unsigned t = _block->newTemp(); move(_block->TEMP(t), left); left = _block->TEMP(t); @@ -1317,9 +1316,9 @@ bool Codegen::visit(ConditionalExpression *ast) if (hasError) return true; - IR::BasicBlock *iftrue = _function->newBasicBlock(groupStartBlock(), exceptionHandler()); - IR::BasicBlock *iffalse = _function->newBasicBlock(groupStartBlock(), exceptionHandler()); - IR::BasicBlock *endif = _function->newBasicBlock(groupStartBlock(), exceptionHandler()); + IR::BasicBlock *iftrue = _function->newBasicBlock(exceptionHandler()); + IR::BasicBlock *iffalse = _function->newBasicBlock(exceptionHandler()); + IR::BasicBlock *endif = _function->newBasicBlock(exceptionHandler()); const unsigned t = _block->newTemp(); @@ -1347,8 +1346,8 @@ bool Codegen::visit(DeleteExpression *ast) IR::Expr* expr = *expression(ast->expression); // Temporaries cannot be deleted - IR::Temp *t = expr->asTemp(); - if (t && t->index < static_cast<unsigned>(_env->members.size())) { + IR::ArgLocal *al = expr->asArgLocal(); + if (al && al->index < static_cast<unsigned>(_env->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.")); @@ -1375,7 +1374,9 @@ bool Codegen::visit(DeleteExpression *ast) _expr.code = _block->CONST(IR::BoolType, 1); return false; } - if (expr->asTemp() && expr->asTemp()->index >= static_cast<unsigned>(_env->members.size())) { + if (expr->asTemp() || + (expr->asArgLocal() && + expr->asArgLocal()->index >= static_cast<unsigned>(_env->members.size()))) { _expr.code = _block->CONST(IR::BoolType, 1); return false; } @@ -1435,10 +1436,10 @@ IR::Expr *Codegen::identifier(const QString &name, int line, int col) int index = e->findMember(name); Q_ASSERT (index < e->members.size()); if (index != -1) { - IR::Temp *t = _block->LOCAL(index, scope); + IR::ArgLocal *al = _block->LOCAL(index, scope); if (name == QStringLiteral("arguments") || name == QStringLiteral("eval")) - t->isArgumentsOrEval = true; - return t; + al->isArgumentsOrEval = true; + return al; } const int argIdx = f->indexOfArgument(&name); if (argIdx != -1) @@ -1497,7 +1498,7 @@ bool Codegen::visit(NewExpression *ast) Result base = expression(ast->expression); IR::Expr *expr = *base; - if (expr && !expr->asTemp() && !expr->asName() && !expr->asMember()) { + if (expr && !expr->asTemp() && !expr->asArgLocal() && !expr->asName() && !expr->asMember()) { const unsigned t = _block->newTemp(); move(_block->TEMP(t), expr); expr = _block->TEMP(t); @@ -1513,7 +1514,7 @@ bool Codegen::visit(NewMemberExpression *ast) Result base = expression(ast->base); IR::Expr *expr = *base; - if (expr && !expr->asTemp() && !expr->asName() && !expr->asMember()) { + if (expr && !expr->asTemp() && !expr->asArgLocal() && !expr->asName() && !expr->asMember()) { const unsigned t = _block->newTemp(); move(_block->TEMP(t), expr); expr = _block->TEMP(t); @@ -1947,8 +1948,8 @@ int Codegen::defineFunction(const QString &name, AST::Node *ast, IR::Function *function = _module->newFunction(name, _function); int functionIndex = _module->functions.count() - 1; - IR::BasicBlock *entryBlock = function->newBasicBlock(groupStartBlock(), 0); - IR::BasicBlock *exitBlock = function->newBasicBlock(groupStartBlock(), 0, IR::Function::DontInsertBlock); + IR::BasicBlock *entryBlock = function->newBasicBlock(0); + IR::BasicBlock *exitBlock = function->newBasicBlock(0, IR::Function::DontInsertBlock); function->hasDirectEval = _env->hasDirectEval || _env->compilationMode == EvalCode; function->usesArgumentsObject = _env->parent && (_env->usesArgumentsObject == Environment::ArgumentsObjectUsed); function->usesThis = _env->usesThis; @@ -2162,11 +2163,11 @@ bool Codegen::visit(DoWhileStatement *ast) if (hasError) return true; - IR::BasicBlock *loopbody = _function->newBasicBlock(groupStartBlock(), exceptionHandler()); - IR::BasicBlock *loopcond = _function->newBasicBlock(loopbody, exceptionHandler()); - IR::BasicBlock *loopend = _function->newBasicBlock(groupStartBlock(), exceptionHandler()); + IR::BasicBlock *loopbody = _function->newBasicBlock(exceptionHandler()); + IR::BasicBlock *loopcond = _function->newBasicBlock(exceptionHandler()); + IR::BasicBlock *loopend = _function->newBasicBlock(exceptionHandler()); - enterLoop(ast, loopbody, loopend, loopcond); + enterLoop(ast, loopend, loopcond); _block->JUMP(loopbody); @@ -2212,9 +2213,9 @@ bool Codegen::visit(ForEachStatement *ast) if (hasError) return true; - IR::BasicBlock *foreachin = _function->newBasicBlock(groupStartBlock(), exceptionHandler()); - IR::BasicBlock *foreachbody = _function->newBasicBlock(foreachin, exceptionHandler()); - IR::BasicBlock *foreachend = _function->newBasicBlock(groupStartBlock(), exceptionHandler()); + IR::BasicBlock *foreachin = _function->newBasicBlock(exceptionHandler()); + IR::BasicBlock *foreachbody = _function->newBasicBlock(exceptionHandler()); + IR::BasicBlock *foreachend = _function->newBasicBlock(exceptionHandler()); int objectToIterateOn = _block->newTemp(); move(_block->TEMP(objectToIterateOn), *expression(ast->expression)); @@ -2224,7 +2225,7 @@ bool Codegen::visit(ForEachStatement *ast) int iterator = _block->newTemp(); move(_block->TEMP(iterator), _block->CALL(_block->NAME(IR::Name::builtin_foreach_iterator_object, 0, 0), args)); - enterLoop(ast, foreachin, foreachend, foreachin); + enterLoop(ast, foreachend, foreachin); _block->JUMP(foreachin); _block = foreachbody; @@ -2252,15 +2253,15 @@ bool Codegen::visit(ForStatement *ast) if (hasError) return true; - IR::BasicBlock *forcond = _function->newBasicBlock(groupStartBlock(), exceptionHandler()); - IR::BasicBlock *forbody = _function->newBasicBlock(forcond, exceptionHandler()); - IR::BasicBlock *forstep = _function->newBasicBlock(forcond, exceptionHandler()); - IR::BasicBlock *forend = _function->newBasicBlock(groupStartBlock(), exceptionHandler()); + IR::BasicBlock *forcond = _function->newBasicBlock(exceptionHandler()); + IR::BasicBlock *forbody = _function->newBasicBlock(exceptionHandler()); + IR::BasicBlock *forstep = _function->newBasicBlock(exceptionHandler()); + IR::BasicBlock *forend = _function->newBasicBlock(exceptionHandler()); statement(ast->initialiser); _block->JUMP(forcond); - enterLoop(ast, forcond, forend, forstep); + enterLoop(ast, forend, forstep); _block = forcond; if (ast->condition) @@ -2288,9 +2289,9 @@ bool Codegen::visit(IfStatement *ast) if (hasError) return true; - IR::BasicBlock *iftrue = _function->newBasicBlock(groupStartBlock(), exceptionHandler()); - IR::BasicBlock *iffalse = ast->ko ? _function->newBasicBlock(groupStartBlock(), exceptionHandler()) : 0; - IR::BasicBlock *endif = _function->newBasicBlock(groupStartBlock(), exceptionHandler()); + IR::BasicBlock *iftrue = _function->newBasicBlock(exceptionHandler()); + IR::BasicBlock *iffalse = ast->ko ? _function->newBasicBlock(exceptionHandler()) : 0; + IR::BasicBlock *endif = _function->newBasicBlock(exceptionHandler()); condition(ast->expression, iftrue, ast->ko ? iffalse : endif); @@ -2335,8 +2336,8 @@ bool Codegen::visit(LabelledStatement *ast) AST::cast<AST::LocalForEachStatement *>(ast->statement)) { statement(ast->statement); // labelledStatement will be associated with the ast->statement's loop. } else { - IR::BasicBlock *breakBlock = _function->newBasicBlock(groupStartBlock(), exceptionHandler()); - enterLoop(ast->statement, 0, breakBlock, /*continueBlock*/ 0); + IR::BasicBlock *breakBlock = _function->newBasicBlock(exceptionHandler()); + enterLoop(ast->statement, breakBlock, /*continueBlock*/ 0); statement(ast->statement); _block->JUMP(breakBlock); _block = breakBlock; @@ -2351,9 +2352,9 @@ bool Codegen::visit(LocalForEachStatement *ast) if (hasError) return true; - IR::BasicBlock *foreachin = _function->newBasicBlock(groupStartBlock(), exceptionHandler()); - IR::BasicBlock *foreachbody = _function->newBasicBlock(foreachin, exceptionHandler()); - IR::BasicBlock *foreachend = _function->newBasicBlock(groupStartBlock(), exceptionHandler()); + IR::BasicBlock *foreachin = _function->newBasicBlock(exceptionHandler()); + IR::BasicBlock *foreachbody = _function->newBasicBlock(exceptionHandler()); + IR::BasicBlock *foreachend = _function->newBasicBlock(exceptionHandler()); variableDeclaration(ast->declaration); @@ -2364,7 +2365,7 @@ bool Codegen::visit(LocalForEachStatement *ast) move(_block->TEMP(iterator), _block->CALL(_block->NAME(IR::Name::builtin_foreach_iterator_object, 0, 0), args)); _block->JUMP(foreachin); - enterLoop(ast, foreachin, foreachend, foreachin); + enterLoop(ast, foreachend, foreachin); _block = foreachbody; int temp = _block->newTemp(); @@ -2391,15 +2392,15 @@ bool Codegen::visit(LocalForStatement *ast) if (hasError) return true; - IR::BasicBlock *forcond = _function->newBasicBlock(groupStartBlock(), exceptionHandler()); - IR::BasicBlock *forbody = _function->newBasicBlock(forcond, exceptionHandler()); - IR::BasicBlock *forstep = _function->newBasicBlock(forcond, exceptionHandler()); - IR::BasicBlock *forend = _function->newBasicBlock(groupStartBlock(), exceptionHandler()); + IR::BasicBlock *forcond = _function->newBasicBlock(exceptionHandler()); + IR::BasicBlock *forbody = _function->newBasicBlock(exceptionHandler()); + IR::BasicBlock *forstep = _function->newBasicBlock(exceptionHandler()); + IR::BasicBlock *forend = _function->newBasicBlock(exceptionHandler()); variableDeclarationList(ast->declarations); _block->JUMP(forcond); - enterLoop(ast, forcond, forend, forstep); + enterLoop(ast, forend, forstep); _block = forcond; if (ast->condition) @@ -2446,22 +2447,22 @@ bool Codegen::visit(SwitchStatement *ast) if (hasError) return true; - IR::BasicBlock *switchend = _function->newBasicBlock(groupStartBlock(), exceptionHandler()); + IR::BasicBlock *switchend = _function->newBasicBlock(exceptionHandler()); if (ast->block) { Result lhs = expression(ast->expression); - IR::BasicBlock *switchcond = _function->newBasicBlock(groupStartBlock(), exceptionHandler()); + IR::BasicBlock *switchcond = _function->newBasicBlock(exceptionHandler()); _block->JUMP(switchcond); IR::BasicBlock *previousBlock = 0; QHash<Node *, IR::BasicBlock *> blockMap; - enterLoop(ast, 0, switchend, 0); + enterLoop(ast, switchend, 0); for (CaseClauses *it = ast->block->clauses; it; it = it->next) { CaseClause *clause = it->clause; - _block = _function->newBasicBlock(groupStartBlock(), exceptionHandler()); + _block = _function->newBasicBlock(exceptionHandler()); blockMap[clause] = _block; if (previousBlock && !previousBlock->isTerminated()) @@ -2474,7 +2475,7 @@ bool Codegen::visit(SwitchStatement *ast) } if (ast->block->defaultClause) { - _block = _function->newBasicBlock(groupStartBlock(), exceptionHandler()); + _block = _function->newBasicBlock(exceptionHandler()); blockMap[ast->block->defaultClause] = _block; if (previousBlock && !previousBlock->isTerminated()) @@ -2489,7 +2490,7 @@ bool Codegen::visit(SwitchStatement *ast) for (CaseClauses *it = ast->block->moreClauses; it; it = it->next) { CaseClause *clause = it->clause; - _block = _function->newBasicBlock(groupStartBlock(), exceptionHandler()); + _block = _function->newBasicBlock(exceptionHandler()); blockMap[clause] = _block; if (previousBlock && !previousBlock->isTerminated()) @@ -2510,7 +2511,7 @@ bool Codegen::visit(SwitchStatement *ast) CaseClause *clause = it->clause; Result rhs = expression(clause->expression); IR::BasicBlock *iftrue = blockMap[clause]; - IR::BasicBlock *iffalse = _function->newBasicBlock(groupStartBlock(), exceptionHandler()); + IR::BasicBlock *iffalse = _function->newBasicBlock(exceptionHandler()); cjump(binop(IR::OpStrictEqual, *lhs, *rhs), iftrue, iffalse); _block = iffalse; } @@ -2519,7 +2520,7 @@ bool Codegen::visit(SwitchStatement *ast) CaseClause *clause = it->clause; Result rhs = expression(clause->expression); IR::BasicBlock *iftrue = blockMap[clause]; - IR::BasicBlock *iffalse = _function->newBasicBlock(groupStartBlock(), exceptionHandler()); + IR::BasicBlock *iffalse = _function->newBasicBlock(exceptionHandler()); cjump(binop(IR::OpStrictEqual, *lhs, *rhs), iftrue, iffalse); _block = iffalse; } @@ -2568,16 +2569,16 @@ bool Codegen::visit(TryStatement *ast) IR::BasicBlock *finallyBody = 0; IR::BasicBlock *catchBody = 0; IR::BasicBlock *catchExceptionHandler = 0; - IR::BasicBlock *end = _function->newBasicBlock(groupStartBlock(), surroundingExceptionHandler, IR::Function::DontInsertBlock); + IR::BasicBlock *end = _function->newBasicBlock(surroundingExceptionHandler, IR::Function::DontInsertBlock); if (ast->finallyExpression) - finallyBody = _function->newBasicBlock(groupStartBlock(), surroundingExceptionHandler, IR::Function::DontInsertBlock); + finallyBody = _function->newBasicBlock(surroundingExceptionHandler, IR::Function::DontInsertBlock); if (ast->catchExpression) { // exception handler for the catch body - catchExceptionHandler = _function->newBasicBlock(groupStartBlock(), 0, IR::Function::DontInsertBlock); + catchExceptionHandler = _function->newBasicBlock(0, IR::Function::DontInsertBlock); pushExceptionHandler(catchExceptionHandler); - catchBody = _function->newBasicBlock(groupStartBlock(), catchExceptionHandler, IR::Function::DontInsertBlock); + catchBody = _function->newBasicBlock(catchExceptionHandler, IR::Function::DontInsertBlock); popExceptionHandler(); pushExceptionHandler(catchBody); } else { @@ -2585,7 +2586,7 @@ bool Codegen::visit(TryStatement *ast) pushExceptionHandler(finallyBody); } - IR::BasicBlock *tryBody = _function->newBasicBlock(groupStartBlock(), exceptionHandler()); + IR::BasicBlock *tryBody = _function->newBasicBlock(exceptionHandler()); _block->JUMP(tryBody); ScopeAndFinally tcf(_scopeAndFinally, ast->finallyExpression); @@ -2690,11 +2691,11 @@ bool Codegen::visit(WhileStatement *ast) if (hasError) return true; - IR::BasicBlock *whilecond = _function->newBasicBlock(groupStartBlock(), exceptionHandler()); - IR::BasicBlock *whilebody = _function->newBasicBlock(whilecond, exceptionHandler()); - IR::BasicBlock *whileend = _function->newBasicBlock(groupStartBlock(), exceptionHandler()); + IR::BasicBlock *whilecond = _function->newBasicBlock(exceptionHandler()); + IR::BasicBlock *whilebody = _function->newBasicBlock(exceptionHandler()); + IR::BasicBlock *whileend = _function->newBasicBlock(exceptionHandler()); - enterLoop(ast, whilecond, whileend, whilecond); + enterLoop(ast, whileend, whilecond); _block->JUMP(whilecond); _block = whilecond; @@ -2718,7 +2719,7 @@ bool Codegen::visit(WithStatement *ast) _function->hasWith = true; // need an exception handler for with to cleanup the with scope - IR::BasicBlock *withExceptionHandler = _function->newBasicBlock(groupStartBlock(), exceptionHandler()); + IR::BasicBlock *withExceptionHandler = _function->newBasicBlock(exceptionHandler()); withExceptionHandler->EXP(withExceptionHandler->CALL(withExceptionHandler->NAME(IR::Name::builtin_pop_scope, 0, 0), 0)); if (!exceptionHandler()) withExceptionHandler->EXP(withExceptionHandler->CALL(withExceptionHandler->NAME(IR::Name::builtin_rethrow, 0, 0), 0)); @@ -2727,7 +2728,7 @@ bool Codegen::visit(WithStatement *ast) pushExceptionHandler(withExceptionHandler); - IR::BasicBlock *withBlock = _function->newBasicBlock(groupStartBlock(), exceptionHandler()); + IR::BasicBlock *withBlock = _function->newBasicBlock(exceptionHandler()); _block->JUMP(withBlock); _block = withBlock; @@ -2748,7 +2749,7 @@ bool Codegen::visit(WithStatement *ast) _block->EXP(_block->CALL(_block->NAME(IR::Name::builtin_pop_scope, 0, 0), 0)); popExceptionHandler(); - IR::BasicBlock *next = _function->newBasicBlock(groupStartBlock(), exceptionHandler()); + IR::BasicBlock *next = _function->newBasicBlock(exceptionHandler()); _block->JUMP(next); _block = next; @@ -2798,8 +2799,8 @@ bool Codegen::throwSyntaxErrorOnEvalOrArgumentsInStrictMode(IR::Expr *expr, cons if (IR::Name *n = expr->asName()) { if (*n->id != QLatin1String("eval") && *n->id != QLatin1String("arguments")) return false; - } else if (IR::Temp *t = expr->asTemp()) { - if (!t->isArgumentsOrEval) + } else if (IR::ArgLocal *al = expr->asArgLocal()) { + if (!al->isArgumentsOrEval) return false; } else { return false; diff --git a/src/qml/compiler/qv4codegen_p.h b/src/qml/compiler/qv4codegen_p.h index 0d52fb83fa..cbe8301c09 100644 --- a/src/qml/compiler/qv4codegen_p.h +++ b/src/qml/compiler/qv4codegen_p.h @@ -256,28 +256,20 @@ protected: struct Loop { AST::LabelledStatement *labelledStatement; AST::Statement *node; - QV4::IR::BasicBlock *groupStartBlock; QV4::IR::BasicBlock *breakBlock; QV4::IR::BasicBlock *continueBlock; Loop *parent; ScopeAndFinally *scopeAndFinally; - Loop(AST::Statement *node, QV4::IR::BasicBlock *groupStartBlock, QV4::IR::BasicBlock *breakBlock, QV4::IR::BasicBlock *continueBlock, Loop *parent) - : labelledStatement(0), node(node), groupStartBlock(groupStartBlock), breakBlock(breakBlock), continueBlock(continueBlock), parent(parent) {} + Loop(AST::Statement *node, QV4::IR::BasicBlock *breakBlock, QV4::IR::BasicBlock *continueBlock, Loop *parent) + : labelledStatement(0), node(node), breakBlock(breakBlock), continueBlock(continueBlock), parent(parent) {} }; void enterEnvironment(AST::Node *node); void leaveEnvironment(); - void enterLoop(AST::Statement *node, QV4::IR::BasicBlock *startBlock, QV4::IR::BasicBlock *breakBlock, QV4::IR::BasicBlock *continueBlock); + void enterLoop(AST::Statement *node, QV4::IR::BasicBlock *breakBlock, QV4::IR::BasicBlock *continueBlock); void leaveLoop(); - QV4::IR::BasicBlock *groupStartBlock() const - { - for (Loop *it = _loop; it; it = it->parent) - if (it->groupStartBlock) - return it->groupStartBlock; - return 0; - } QV4::IR::BasicBlock *exceptionHandler() const { if (_exceptionHandlers.isEmpty()) diff --git a/src/qml/compiler/qv4isel_moth.cpp b/src/qml/compiler/qv4isel_moth.cpp index 9288008632..7c67ae2301 100644 --- a/src/qml/compiler/qv4isel_moth.cpp +++ b/src/qml/compiler/qv4isel_moth.cpp @@ -168,22 +168,30 @@ inline bool isBoolType(IR::Expr *e) */ class AllocateStackSlots: protected ConvertTemps { - const QVector<IR::LifeTimeInterval> _intervals; - QVector<const IR::LifeTimeInterval *> _unhandled; - QVector<const IR::LifeTimeInterval *> _live; + IR::LifeTimeIntervals::Ptr _intervals; + QVector<IR::LifeTimeInterval *> _unhandled; + QVector<IR::LifeTimeInterval *> _live; QBitArray _slotIsInUse; IR::Function *_function; + int defPosition(IR::Stmt *s) const + { + return usePosition(s) + 1; + } + + int usePosition(IR::Stmt *s) const + { + return _intervals->positionForStatement(s); + } + public: - AllocateStackSlots(const QVector<IR::LifeTimeInterval> &intervals) + AllocateStackSlots(const IR::LifeTimeIntervals::Ptr &intervals) : _intervals(intervals) - , _slotIsInUse(intervals.size(), false) + , _slotIsInUse(intervals->size(), false) , _function(0) { _live.reserve(8); - _unhandled.reserve(_intervals.size()); - for (int i = _intervals.size() - 1; i >= 0; --i) - _unhandled.append(&_intervals.at(i)); + _unhandled = _intervals->intervals(); } void forFunction(IR::Function *function) @@ -219,8 +227,6 @@ protected: virtual void process(IR::Stmt *s) { - Q_ASSERT(s->id > 0); - // qDebug("L%d statement %d:", _currentBasicBlock->index, s->id); if (IR::Phi *phi = s->asPhi()) { @@ -229,7 +235,7 @@ protected: // purge ranges no longer alive: for (int i = 0; i < _live.size(); ) { const IR::LifeTimeInterval *lti = _live.at(i); - if (lti->end() < s->id) { + if (lti->end() < usePosition(s)) { // qDebug() << "\t - moving temp" << lti->temp().index << "to handled, freeing slot" << _stackSlotForTemp[lti->temp().index]; _live.remove(i); Q_ASSERT(_slotIsInUse[_stackSlotForTemp[lti->temp().index]]); @@ -242,8 +248,8 @@ protected: // active new ranges: while (!_unhandled.isEmpty()) { - const IR::LifeTimeInterval *lti = _unhandled.last(); - if (lti->start() > s->id) + IR::LifeTimeInterval *lti = _unhandled.last(); + if (lti->start() > defPosition(s)) break; // we're done Q_ASSERT(!_stackSlotForTemp.contains(lti->temp().index)); _stackSlotForTemp[lti->temp().index] = allocateFreeSlot(); @@ -286,7 +292,7 @@ protected: int i = _unhandled.size() - 1; for (; i >= 0; --i) { - const IR::LifeTimeInterval *lti = _unhandled[i]; + IR::LifeTimeInterval *lti = _unhandled[i]; if (lti->temp() == t) { _live.append(lti); _unhandled.remove(i); @@ -322,9 +328,8 @@ InstructionSelection::InstructionSelection(QQmlEnginePrivate *qmlEngine, QV4::Ex , _codeNext(0) , _codeEnd(0) , _currentStatement(0) -{ - compilationUnit = new CompilationUnit; -} + , compilationUnit(new CompilationUnit) +{} InstructionSelection::~InstructionSelection() { @@ -453,10 +458,10 @@ QV4::CompiledData::CompilationUnit *InstructionSelection::backendCompileStep() int i = 0; foreach (IR::Function *irFunction, irModule->functions) compilationUnit->codeRefs[i++] = codeRefs[irFunction]; - return compilationUnit; + return compilationUnit.take(); } -void InstructionSelection::callValue(IR::Temp *value, IR::ExprList *args, IR::Temp *result) +void InstructionSelection::callValue(IR::Expr *value, IR::ExprList *args, IR::Expr *result) { Instruction::CallValue call; prepareCallArgs(args, call.argc); @@ -467,7 +472,7 @@ void InstructionSelection::callValue(IR::Temp *value, IR::ExprList *args, IR::Te } void InstructionSelection::callProperty(IR::Expr *base, const QString &name, IR::ExprList *args, - IR::Temp *result) + IR::Expr *result) { if (useFastLookups) { Instruction::CallPropertyLookup call; @@ -490,7 +495,7 @@ void InstructionSelection::callProperty(IR::Expr *base, const QString &name, IR: } void InstructionSelection::callSubscript(IR::Expr *base, IR::Expr *index, IR::ExprList *args, - IR::Temp *result) + IR::Expr *result) { // call the property on the loaded base Instruction::CallElement call; @@ -502,7 +507,7 @@ void InstructionSelection::callSubscript(IR::Expr *base, IR::Expr *index, IR::Ex addInstruction(call); } -void InstructionSelection::convertType(IR::Temp *source, IR::Temp *target) +void InstructionSelection::convertType(IR::Expr *source, IR::Expr *target) { // FIXME: do something more useful with this info if (target->type & IR::NumberType && !(source->type & IR::NumberType)) @@ -513,14 +518,14 @@ void InstructionSelection::convertType(IR::Temp *source, IR::Temp *target) void InstructionSelection::constructActivationProperty(IR::Name *func, IR::ExprList *args, - IR::Temp *result) + IR::Expr *target) { if (useFastLookups && func->global) { Instruction::ConstructGlobalLookup call; call.index = registerGlobalGetterLookup(*func->id); prepareCallArgs(args, call.argc); call.callData = callDataStart(); - call.result = getResultParam(result); + call.result = getResultParam(target); addInstruction(call); return; } @@ -528,11 +533,11 @@ void InstructionSelection::constructActivationProperty(IR::Name *func, create.name = registerString(*func->id); prepareCallArgs(args, create.argc); create.callData = callDataStart(); - create.result = getResultParam(result); + create.result = getResultParam(target); addInstruction(create); } -void InstructionSelection::constructProperty(IR::Temp *base, const QString &name, IR::ExprList *args, IR::Temp *result) +void InstructionSelection::constructProperty(IR::Expr *base, const QString &name, IR::ExprList *args, IR::Expr *target) { if (useFastLookups) { Instruction::ConstructPropertyLookup call; @@ -540,7 +545,7 @@ void InstructionSelection::constructProperty(IR::Temp *base, const QString &name call.index = registerGetterLookup(name); prepareCallArgs(args, call.argc); call.callData = callDataStart(); - call.result = getResultParam(result); + call.result = getResultParam(target); addInstruction(call); return; } @@ -549,101 +554,101 @@ void InstructionSelection::constructProperty(IR::Temp *base, const QString &name create.name = registerString(name); prepareCallArgs(args, create.argc); create.callData = callDataStart(); - create.result = getResultParam(result); + create.result = getResultParam(target); addInstruction(create); } -void InstructionSelection::constructValue(IR::Temp *value, IR::ExprList *args, IR::Temp *result) +void InstructionSelection::constructValue(IR::Expr *value, IR::ExprList *args, IR::Expr *target) { Instruction::CreateValue create; create.func = getParam(value); prepareCallArgs(args, create.argc); create.callData = callDataStart(); - create.result = getResultParam(result); + create.result = getResultParam(target); addInstruction(create); } -void InstructionSelection::loadThisObject(IR::Temp *temp) +void InstructionSelection::loadThisObject(IR::Expr *e) { Instruction::LoadThis load; - load.result = getResultParam(temp); + load.result = getResultParam(e); addInstruction(load); } -void InstructionSelection::loadQmlIdArray(IR::Temp *temp) +void InstructionSelection::loadQmlIdArray(IR::Expr *e) { Instruction::LoadQmlIdArray load; - load.result = getResultParam(temp); + load.result = getResultParam(e); addInstruction(load); } -void InstructionSelection::loadQmlImportedScripts(IR::Temp *temp) +void InstructionSelection::loadQmlImportedScripts(IR::Expr *e) { Instruction::LoadQmlImportedScripts load; - load.result = getResultParam(temp); + load.result = getResultParam(e); addInstruction(load); } -void InstructionSelection::loadQmlContextObject(IR::Temp *temp) +void InstructionSelection::loadQmlContextObject(IR::Expr *e) { Instruction::LoadQmlContextObject load; - load.result = getResultParam(temp); + load.result = getResultParam(e); addInstruction(load); } -void InstructionSelection::loadQmlScopeObject(IR::Temp *temp) +void InstructionSelection::loadQmlScopeObject(IR::Expr *e) { Instruction::LoadQmlScopeObject load; - load.result = getResultParam(temp); + load.result = getResultParam(e); addInstruction(load); } -void InstructionSelection::loadQmlSingleton(const QString &name, IR::Temp *temp) +void InstructionSelection::loadQmlSingleton(const QString &name, IR::Expr *e) { Instruction::LoadQmlSingleton load; - load.result = getResultParam(temp); + load.result = getResultParam(e); load.name = registerString(name); addInstruction(load); } -void InstructionSelection::loadConst(IR::Const *sourceConst, IR::Temp *targetTemp) +void InstructionSelection::loadConst(IR::Const *sourceConst, IR::Expr *e) { Q_ASSERT(sourceConst); Instruction::MoveConst move; move.source = convertToValue(sourceConst).asReturnedValue(); - move.result = getResultParam(targetTemp); + move.result = getResultParam(e); addInstruction(move); } -void InstructionSelection::loadString(const QString &str, IR::Temp *targetTemp) +void InstructionSelection::loadString(const QString &str, IR::Expr *target) { Instruction::LoadRuntimeString load; load.stringId = registerString(str); - load.result = getResultParam(targetTemp); + load.result = getResultParam(target); addInstruction(load); } -void InstructionSelection::loadRegexp(IR::RegExp *sourceRegexp, IR::Temp *targetTemp) +void InstructionSelection::loadRegexp(IR::RegExp *sourceRegexp, IR::Expr *target) { Instruction::LoadRegExp load; load.regExpId = registerRegExp(sourceRegexp); - load.result = getResultParam(targetTemp); + load.result = getResultParam(target); addInstruction(load); } -void InstructionSelection::getActivationProperty(const IR::Name *name, IR::Temp *temp) +void InstructionSelection::getActivationProperty(const IR::Name *name, IR::Expr *target) { if (useFastLookups && name->global) { Instruction::GetGlobalLookup load; load.index = registerGlobalGetterLookup(*name->id); - load.result = getResultParam(temp); + load.result = getResultParam(target); addInstruction(load); return; } Instruction::LoadName load; load.name = registerString(*name->id); - load.result = getResultParam(temp); + load.result = getResultParam(target); addInstruction(load); } @@ -655,7 +660,7 @@ void InstructionSelection::setActivationProperty(IR::Expr *source, const QString addInstruction(store); } -void InstructionSelection::initClosure(IR::Closure *closure, IR::Temp *target) +void InstructionSelection::initClosure(IR::Closure *closure, IR::Expr *target) { int id = closure->value; Instruction::LoadClosure load; @@ -664,7 +669,7 @@ void InstructionSelection::initClosure(IR::Closure *closure, IR::Temp *target) addInstruction(load); } -void InstructionSelection::getProperty(IR::Expr *base, const QString &name, IR::Temp *target) +void InstructionSelection::getProperty(IR::Expr *base, const QString &name, IR::Expr *target) { if (useFastLookups) { Instruction::GetLookup load; @@ -708,7 +713,7 @@ void InstructionSelection::setQObjectProperty(IR::Expr *source, IR::Expr *target addInstruction(store); } -void InstructionSelection::getQObjectProperty(IR::Expr *base, int propertyIndex, bool captureRequired, int attachedPropertiesId, IR::Temp *target) +void InstructionSelection::getQObjectProperty(IR::Expr *base, int propertyIndex, bool captureRequired, int attachedPropertiesId, IR::Expr *target) { if (attachedPropertiesId != 0) { Instruction::LoadAttachedQObjectProperty load; @@ -726,7 +731,7 @@ void InstructionSelection::getQObjectProperty(IR::Expr *base, int propertyIndex, } } -void InstructionSelection::getElement(IR::Expr *base, IR::Expr *index, IR::Temp *target) +void InstructionSelection::getElement(IR::Expr *base, IR::Expr *index, IR::Expr *target) { if (useFastLookups) { Instruction::LoadElementLookup load; @@ -763,92 +768,92 @@ void InstructionSelection::setElement(IR::Expr *source, IR::Expr *targetBase, addInstruction(store); } -void InstructionSelection::copyValue(IR::Temp *sourceTemp, IR::Temp *targetTemp) +void InstructionSelection::copyValue(IR::Expr *source, IR::Expr *target) { Instruction::Move move; - move.source = getParam(sourceTemp); - move.result = getResultParam(targetTemp); + move.source = getParam(source); + move.result = getResultParam(target); if (move.source != move.result) addInstruction(move); } -void InstructionSelection::swapValues(IR::Temp *sourceTemp, IR::Temp *targetTemp) +void InstructionSelection::swapValues(IR::Expr *source, IR::Expr *target) { Instruction::SwapTemps swap; - swap.left = getParam(sourceTemp); - swap.right = getParam(targetTemp); + swap.left = getParam(source); + swap.right = getParam(target); addInstruction(swap); } -void InstructionSelection::unop(IR::AluOp oper, IR::Temp *sourceTemp, IR::Temp *targetTemp) +void InstructionSelection::unop(IR::AluOp oper, IR::Expr *source, IR::Expr *target) { switch (oper) { case IR::OpIfTrue: Q_ASSERT(!"unreachable"); break; case IR::OpNot: { // ### enabling this fails in some cases, where apparently the value is not a bool at runtime - if (0 && isBoolType(sourceTemp)) { + if (0 && isBoolType(source)) { Instruction::UNotBool unot; - unot.source = getParam(sourceTemp); - unot.result = getResultParam(targetTemp); + unot.source = getParam(source); + unot.result = getResultParam(target); addInstruction(unot); return; } Instruction::UNot unot; - unot.source = getParam(sourceTemp); - unot.result = getResultParam(targetTemp); + unot.source = getParam(source); + unot.result = getResultParam(target); addInstruction(unot); return; } case IR::OpUMinus: { Instruction::UMinus uminus; - uminus.source = getParam(sourceTemp); - uminus.result = getResultParam(targetTemp); + uminus.source = getParam(source); + uminus.result = getResultParam(target); addInstruction(uminus); return; } case IR::OpUPlus: { - if (isNumberType(sourceTemp)) { + if (isNumberType(source)) { // use a move Instruction::Move move; - move.source = getParam(sourceTemp); - move.result = getResultParam(targetTemp); + move.source = getParam(source); + move.result = getResultParam(target); if (move.source != move.result) addInstruction(move); return; } Instruction::UPlus uplus; - uplus.source = getParam(sourceTemp); - uplus.result = getResultParam(targetTemp); + uplus.source = getParam(source); + uplus.result = getResultParam(target); addInstruction(uplus); return; } case IR::OpCompl: { // ### enabling this fails in some cases, where apparently the value is not a int at runtime - if (0 && isIntegerType(sourceTemp)) { + if (0 && isIntegerType(source)) { Instruction::UComplInt unot; - unot.source = getParam(sourceTemp); - unot.result = getResultParam(targetTemp); + unot.source = getParam(source); + unot.result = getResultParam(target); addInstruction(unot); return; } Instruction::UCompl ucompl; - ucompl.source = getParam(sourceTemp); - ucompl.result = getResultParam(targetTemp); + ucompl.source = getParam(source); + ucompl.result = getResultParam(target); addInstruction(ucompl); return; } case IR::OpIncrement: { Instruction::Increment inc; - inc.source = getParam(sourceTemp); - inc.result = getResultParam(targetTemp); + inc.source = getParam(source); + inc.result = getResultParam(target); addInstruction(inc); return; } case IR::OpDecrement: { Instruction::Decrement dec; - dec.source = getParam(sourceTemp); - dec.result = getResultParam(targetTemp); + dec.source = getParam(source); + dec.result = getResultParam(target); addInstruction(dec); return; } @@ -858,12 +863,12 @@ void InstructionSelection::unop(IR::AluOp oper, IR::Temp *sourceTemp, IR::Temp * Q_ASSERT(!"unreachable"); } -void InstructionSelection::binop(IR::AluOp oper, IR::Expr *leftSource, IR::Expr *rightSource, IR::Temp *target) +void InstructionSelection::binop(IR::AluOp oper, IR::Expr *leftSource, IR::Expr *rightSource, IR::Expr *target) { binopHelper(oper, leftSource, rightSource, target); } -Param InstructionSelection::binopHelper(IR::AluOp oper, IR::Expr *leftSource, IR::Expr *rightSource, IR::Temp *target) +Param InstructionSelection::binopHelper(IR::AluOp oper, IR::Expr *leftSource, IR::Expr *rightSource, IR::Expr *target) { if (oper == IR::OpAdd) { Instruction::Add add; @@ -1103,7 +1108,7 @@ void InstructionSelection::visitRet(IR::Ret *s) addInstruction(ret); } -void InstructionSelection::callBuiltinInvalid(IR::Name *func, IR::ExprList *args, IR::Temp *result) +void InstructionSelection::callBuiltinInvalid(IR::Name *func, IR::ExprList *args, IR::Expr *result) { if (useFastLookups && func->global) { Instruction::CallGlobalLookup call; @@ -1123,7 +1128,7 @@ void InstructionSelection::callBuiltinInvalid(IR::Name *func, IR::ExprList *args } void InstructionSelection::callBuiltinTypeofMember(IR::Expr *base, const QString &name, - IR::Temp *result) + IR::Expr *result) { Instruction::CallBuiltinTypeofMember call; call.base = getParam(base); @@ -1133,7 +1138,7 @@ void InstructionSelection::callBuiltinTypeofMember(IR::Expr *base, const QString } void InstructionSelection::callBuiltinTypeofSubscript(IR::Expr *base, IR::Expr *index, - IR::Temp *result) + IR::Expr *result) { Instruction::CallBuiltinTypeofSubscript call; call.base = getParam(base); @@ -1142,7 +1147,7 @@ void InstructionSelection::callBuiltinTypeofSubscript(IR::Expr *base, IR::Expr * addInstruction(call); } -void InstructionSelection::callBuiltinTypeofName(const QString &name, IR::Temp *result) +void InstructionSelection::callBuiltinTypeofName(const QString &name, IR::Expr *result) { Instruction::CallBuiltinTypeofName call; call.name = registerString(name); @@ -1150,7 +1155,7 @@ void InstructionSelection::callBuiltinTypeofName(const QString &name, IR::Temp * addInstruction(call); } -void InstructionSelection::callBuiltinTypeofValue(IR::Expr *value, IR::Temp *result) +void InstructionSelection::callBuiltinTypeofValue(IR::Expr *value, IR::Expr *result) { Instruction::CallBuiltinTypeofValue call; call.value = getParam(value); @@ -1158,7 +1163,7 @@ void InstructionSelection::callBuiltinTypeofValue(IR::Expr *value, IR::Temp *res addInstruction(call); } -void InstructionSelection::callBuiltinDeleteMember(IR::Temp *base, const QString &name, IR::Temp *result) +void InstructionSelection::callBuiltinDeleteMember(IR::Expr *base, const QString &name, IR::Expr *result) { Instruction::CallBuiltinDeleteMember call; call.base = getParam(base); @@ -1167,8 +1172,8 @@ void InstructionSelection::callBuiltinDeleteMember(IR::Temp *base, const QString addInstruction(call); } -void InstructionSelection::callBuiltinDeleteSubscript(IR::Temp *base, IR::Expr *index, - IR::Temp *result) +void InstructionSelection::callBuiltinDeleteSubscript(IR::Expr *base, IR::Expr *index, + IR::Expr *result) { Instruction::CallBuiltinDeleteSubscript call; call.base = getParam(base); @@ -1177,7 +1182,7 @@ void InstructionSelection::callBuiltinDeleteSubscript(IR::Temp *base, IR::Expr * addInstruction(call); } -void InstructionSelection::callBuiltinDeleteName(const QString &name, IR::Temp *result) +void InstructionSelection::callBuiltinDeleteName(const QString &name, IR::Expr *result) { Instruction::CallBuiltinDeleteName call; call.name = registerString(name); @@ -1185,7 +1190,7 @@ void InstructionSelection::callBuiltinDeleteName(const QString &name, IR::Temp * addInstruction(call); } -void InstructionSelection::callBuiltinDeleteValue(IR::Temp *result) +void InstructionSelection::callBuiltinDeleteValue(IR::Expr *result) { Instruction::MoveConst move; move.source = QV4::Encode(false); @@ -1217,7 +1222,7 @@ void InstructionSelection::callBuiltinReThrow() } } -void InstructionSelection::callBuiltinUnwindException(IR::Temp *result) +void InstructionSelection::callBuiltinUnwindException(IR::Expr *result) { Instruction::CallBuiltinUnwindException call; call.result = getResultParam(result); @@ -1232,7 +1237,7 @@ void InstructionSelection::callBuiltinPushCatchScope(const QString &exceptionNam addInstruction(call); } -void InstructionSelection::callBuiltinForeachIteratorObject(IR::Expr *arg, IR::Temp *result) +void InstructionSelection::callBuiltinForeachIteratorObject(IR::Expr *arg, IR::Expr *result) { Instruction::CallBuiltinForeachIteratorObject call; call.arg = getParam(arg); @@ -1240,7 +1245,7 @@ void InstructionSelection::callBuiltinForeachIteratorObject(IR::Expr *arg, IR::T addInstruction(call); } -void InstructionSelection::callBuiltinForeachNextPropertyname(IR::Temp *arg, IR::Temp *result) +void InstructionSelection::callBuiltinForeachNextPropertyname(IR::Expr *arg, IR::Expr *result) { Instruction::CallBuiltinForeachNextPropertyName call; call.arg = getParam(arg); @@ -1248,7 +1253,7 @@ void InstructionSelection::callBuiltinForeachNextPropertyname(IR::Temp *arg, IR: addInstruction(call); } -void InstructionSelection::callBuiltinPushWithScope(IR::Temp *arg) +void InstructionSelection::callBuiltinPushWithScope(IR::Expr *arg) { Instruction::CallBuiltinPushScope call; call.arg = getParam(arg); @@ -1269,7 +1274,7 @@ void InstructionSelection::callBuiltinDeclareVar(bool deletable, const QString & addInstruction(call); } -void InstructionSelection::callBuiltinDefineArray(IR::Temp *result, IR::ExprList *args) +void InstructionSelection::callBuiltinDefineArray(IR::Expr *result, IR::ExprList *args) { Instruction::CallBuiltinDefineArray call; prepareCallArgs(args, call.argc, &call.args); @@ -1277,7 +1282,7 @@ void InstructionSelection::callBuiltinDefineArray(IR::Temp *result, IR::ExprList addInstruction(call); } -void InstructionSelection::callBuiltinDefineObjectLiteral(IR::Temp *result, int keyValuePairCount, IR::ExprList *keyValuePairs, IR::ExprList *arrayEntries, bool needSparseArray) +void InstructionSelection::callBuiltinDefineObjectLiteral(IR::Expr *result, int keyValuePairCount, IR::ExprList *keyValuePairs, IR::ExprList *arrayEntries, bool needSparseArray) { int argLocation = outgoingArgumentTempStart(); @@ -1397,7 +1402,7 @@ void InstructionSelection::callBuiltinDefineObjectLiteral(IR::Temp *result, int addInstruction(call); } -void InstructionSelection::callBuiltinSetupArgumentObject(IR::Temp *result) +void InstructionSelection::callBuiltinSetupArgumentObject(IR::Expr *result) { Instruction::CallBuiltinSetupArgumentsObject call; call.result = getResultParam(result); @@ -1475,16 +1480,22 @@ Param InstructionSelection::getParam(IR::Expr *e) { return Param::createConstant(idx); } else if (IR::Temp *t = e->asTemp()) { switch (t->kind) { - case IR::Temp::Formal: - case IR::Temp::ScopedFormal: return Param::createArgument(t->index, t->scope); - case IR::Temp::Local: return Param::createLocal(t->index); - case IR::Temp::ScopedLocal: return Param::createScopedLocal(t->index, t->scope); case IR::Temp::StackSlot: return Param::createTemp(t->index); default: Q_UNREACHABLE(); return Param(); } + } else if (IR::ArgLocal *al = e->asArgLocal()) { + switch (al->kind) { + case IR::ArgLocal::Formal: + case IR::ArgLocal::ScopedFormal: return Param::createArgument(al->index, al->scope); + case IR::ArgLocal::Local: return Param::createLocal(al->index); + case IR::ArgLocal::ScopedLocal: return Param::createScopedLocal(al->index, al->scope); + default: + Q_UNREACHABLE(); + return Param(); + } } else { Q_UNIMPLEMENTED(); return Param(); diff --git a/src/qml/compiler/qv4isel_moth_p.h b/src/qml/compiler/qv4isel_moth_p.h index 0aa1972fb4..2fdb7c007c 100644 --- a/src/qml/compiler/qv4isel_moth_p.h +++ b/src/qml/compiler/qv4isel_moth_p.h @@ -80,60 +80,60 @@ protected: virtual void visitCJump(IR::CJump *); virtual void visitRet(IR::Ret *); - virtual void callBuiltinInvalid(IR::Name *func, IR::ExprList *args, IR::Temp *result); - virtual void callBuiltinTypeofMember(IR::Expr *base, const QString &name, IR::Temp *result); - virtual void callBuiltinTypeofSubscript(IR::Expr *base, IR::Expr *index, IR::Temp *result); - virtual void callBuiltinTypeofName(const QString &name, IR::Temp *result); - virtual void callBuiltinTypeofValue(IR::Expr *value, IR::Temp *result); - virtual void callBuiltinDeleteMember(IR::Temp *base, const QString &name, IR::Temp *result); - virtual void callBuiltinDeleteSubscript(IR::Temp *base, IR::Expr *index, IR::Temp *result); - virtual void callBuiltinDeleteName(const QString &name, IR::Temp *result); - virtual void callBuiltinDeleteValue(IR::Temp *result); + virtual void callBuiltinInvalid(IR::Name *func, IR::ExprList *args, IR::Expr *result); + virtual void callBuiltinTypeofMember(IR::Expr *base, const QString &name, IR::Expr *result); + virtual void callBuiltinTypeofSubscript(IR::Expr *base, IR::Expr *index, IR::Expr *result); + virtual void callBuiltinTypeofName(const QString &name, IR::Expr *result); + virtual void callBuiltinTypeofValue(IR::Expr *value, IR::Expr *result); + virtual void callBuiltinDeleteMember(IR::Expr *base, const QString &name, IR::Expr *result); + virtual void callBuiltinDeleteSubscript(IR::Expr *base, IR::Expr *index, IR::Expr *result); + virtual void callBuiltinDeleteName(const QString &name, IR::Expr *result); + virtual void callBuiltinDeleteValue(IR::Expr *result); virtual void callBuiltinThrow(IR::Expr *arg); virtual void callBuiltinReThrow(); - virtual void callBuiltinUnwindException(IR::Temp *); + virtual void callBuiltinUnwindException(IR::Expr *); virtual void callBuiltinPushCatchScope(const QString &exceptionName); - virtual void callBuiltinForeachIteratorObject(IR::Expr *arg, IR::Temp *result); - virtual void callBuiltinForeachNextPropertyname(IR::Temp *arg, IR::Temp *result); - virtual void callBuiltinPushWithScope(IR::Temp *arg); + virtual void callBuiltinForeachIteratorObject(IR::Expr *arg, IR::Expr *result); + virtual void callBuiltinForeachNextPropertyname(IR::Expr *arg, IR::Expr *result); + virtual void callBuiltinPushWithScope(IR::Expr *arg); virtual void callBuiltinPopScope(); virtual void callBuiltinDeclareVar(bool deletable, const QString &name); - virtual void callBuiltinDefineArray(IR::Temp *result, IR::ExprList *args); - virtual void callBuiltinDefineObjectLiteral(IR::Temp *result, int keyValuePairCount, IR::ExprList *keyValuePairs, IR::ExprList *arrayEntries, bool needSparseArray); - virtual void callBuiltinSetupArgumentObject(IR::Temp *result); + virtual void callBuiltinDefineArray(IR::Expr *result, IR::ExprList *args); + virtual void callBuiltinDefineObjectLiteral(IR::Expr *result, int keyValuePairCount, IR::ExprList *keyValuePairs, IR::ExprList *arrayEntries, bool needSparseArray); + virtual void callBuiltinSetupArgumentObject(IR::Expr *result); virtual void callBuiltinConvertThisToObject(); - virtual void callValue(IR::Temp *value, IR::ExprList *args, IR::Temp *result); - virtual void callProperty(IR::Expr *base, const QString &name, IR::ExprList *args, IR::Temp *result); - virtual void callSubscript(IR::Expr *base, IR::Expr *index, IR::ExprList *args, IR::Temp *result); - virtual void convertType(IR::Temp *source, IR::Temp *target); - virtual void constructActivationProperty(IR::Name *func, IR::ExprList *args, IR::Temp *result); - virtual void constructProperty(IR::Temp *base, const QString &name, IR::ExprList *args, IR::Temp *result); - virtual void constructValue(IR::Temp *value, IR::ExprList *args, IR::Temp *result); - virtual void loadThisObject(IR::Temp *temp); - virtual void loadQmlIdArray(IR::Temp *temp); - virtual void loadQmlImportedScripts(IR::Temp *temp); - virtual void loadQmlContextObject(IR::Temp *temp); - virtual void loadQmlScopeObject(IR::Temp *temp); - virtual void loadQmlSingleton(const QString &name, IR::Temp *temp); - virtual void loadConst(IR::Const *sourceConst, IR::Temp *targetTemp); - virtual void loadString(const QString &str, IR::Temp *targetTemp); - virtual void loadRegexp(IR::RegExp *sourceRegexp, IR::Temp *targetTemp); - virtual void getActivationProperty(const IR::Name *name, IR::Temp *temp); + virtual void callValue(IR::Expr *value, IR::ExprList *args, IR::Expr *result); + virtual void callProperty(IR::Expr *base, const QString &name, IR::ExprList *args, IR::Expr *result); + virtual void callSubscript(IR::Expr *base, IR::Expr *index, IR::ExprList *args, IR::Expr *result); + virtual void convertType(IR::Expr *source, IR::Expr *target); + virtual void constructActivationProperty(IR::Name *func, IR::ExprList *args, IR::Expr *result); + virtual void constructProperty(IR::Expr *base, const QString &name, IR::ExprList *args, IR::Expr *result); + virtual void constructValue(IR::Expr *value, IR::ExprList *args, IR::Expr *result); + virtual void loadThisObject(IR::Expr *e); + virtual void loadQmlIdArray(IR::Expr *e); + virtual void loadQmlImportedScripts(IR::Expr *e); + virtual void loadQmlContextObject(IR::Expr *e); + virtual void loadQmlScopeObject(IR::Expr *e); + virtual void loadQmlSingleton(const QString &name, IR::Expr *e); + virtual void loadConst(IR::Const *sourceConst, IR::Expr *e); + virtual void loadString(const QString &str, IR::Expr *target); + virtual void loadRegexp(IR::RegExp *sourceRegexp, IR::Expr *target); + virtual void getActivationProperty(const IR::Name *name, IR::Expr *target); virtual void setActivationProperty(IR::Expr *source, const QString &targetName); - virtual void initClosure(IR::Closure *closure, IR::Temp *target); - virtual void getProperty(IR::Expr *base, const QString &name, IR::Temp *target); + virtual void initClosure(IR::Closure *closure, IR::Expr *target); + virtual void getProperty(IR::Expr *base, const QString &name, IR::Expr *target); virtual void setProperty(IR::Expr *source, IR::Expr *targetBase, const QString &targetName); virtual void setQObjectProperty(IR::Expr *source, IR::Expr *targetBase, int propertyIndex); - virtual void getQObjectProperty(IR::Expr *base, int propertyIndex, bool captureRequired, int attachedPropertiesId, IR::Temp *target); - virtual void getElement(IR::Expr *base, IR::Expr *index, IR::Temp *target); + virtual void getQObjectProperty(IR::Expr *base, int propertyIndex, bool captureRequired, int attachedPropertiesId, IR::Expr *target); + virtual void getElement(IR::Expr *base, IR::Expr *index, IR::Expr *target); virtual void setElement(IR::Expr *source, IR::Expr *targetBase, IR::Expr *targetIndex); - virtual void copyValue(IR::Temp *sourceTemp, IR::Temp *targetTemp); - virtual void swapValues(IR::Temp *sourceTemp, IR::Temp *targetTemp); - virtual void unop(IR::AluOp oper, IR::Temp *sourceTemp, IR::Temp *targetTemp); - virtual void binop(IR::AluOp oper, IR::Expr *leftSource, IR::Expr *rightSource, IR::Temp *target); + virtual void copyValue(IR::Expr *source, IR::Expr *target); + virtual void swapValues(IR::Expr *source, IR::Expr *target); + virtual void unop(IR::AluOp oper, IR::Expr *source, IR::Expr *target); + virtual void binop(IR::AluOp oper, IR::Expr *leftSource, IR::Expr *rightSource, IR::Expr *target); private: - Param binopHelper(IR::AluOp oper, IR::Expr *leftSource, IR::Expr *rightSource, IR::Temp *target); + Param binopHelper(IR::AluOp oper, IR::Expr *leftSource, IR::Expr *rightSource, IR::Expr *target); struct Instruction { #define MOTH_INSTR_DATA_TYPEDEF(I, FMT) typedef InstrData<Instr::I> I; @@ -145,7 +145,7 @@ private: Param getParam(IR::Expr *e); - Param getResultParam(IR::Temp *result) + Param getResultParam(IR::Expr *result) { if (result) return getParam(result); @@ -184,7 +184,7 @@ private: QSet<IR::Jump *> _removableJumps; IR::Stmt *_currentStatement; - CompilationUnit *compilationUnit; + QScopedPointer<CompilationUnit> compilationUnit; QHash<IR::Function *, QByteArray> codeRefs; }; diff --git a/src/qml/compiler/qv4isel_p.cpp b/src/qml/compiler/qv4isel_p.cpp index 429688090c..1aa0c4dad8 100644 --- a/src/qml/compiler/qv4isel_p.cpp +++ b/src/qml/compiler/qv4isel_p.cpp @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). +** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies). ** Contact: http://www.qt-project.org/legal ** ** This file is part of the QtQml module of the Qt Toolkit. @@ -93,54 +93,54 @@ QV4::CompiledData::CompilationUnit *EvalInstructionSelection::compile(bool gener void IRDecoder::visitMove(IR::Move *s) { if (IR::Name *n = s->target->asName()) { - if (s->source->asTemp() || s->source->asConst()) { + if (s->source->asTemp() || s->source->asConst() || s->source->asArgLocal()) { setActivationProperty(s->source, *n->id); return; } - } else if (IR::Temp *t = s->target->asTemp()) { + } else if (s->target->asTemp() || s->target->asArgLocal()) { if (IR::Name *n = s->source->asName()) { if (n->id && *n->id == QStringLiteral("this")) // TODO: `this' should be a builtin. - loadThisObject(t); + loadThisObject(s->target); else if (n->builtin == IR::Name::builtin_qml_id_array) - loadQmlIdArray(t); + loadQmlIdArray(s->target); else if (n->builtin == IR::Name::builtin_qml_context_object) - loadQmlContextObject(t); + loadQmlContextObject(s->target); else if (n->builtin == IR::Name::builtin_qml_scope_object) - loadQmlScopeObject(t); + loadQmlScopeObject(s->target); else if (n->builtin == IR::Name::builtin_qml_imported_scripts_object) - loadQmlImportedScripts(t); + loadQmlImportedScripts(s->target); else if (n->qmlSingleton) - loadQmlSingleton(*n->id, t); + loadQmlSingleton(*n->id, s->target); else - getActivationProperty(n, t); + getActivationProperty(n, s->target); return; } else if (IR::Const *c = s->source->asConst()) { - loadConst(c, t); + loadConst(c, s->target); return; - } else if (IR::Temp *t2 = s->source->asTemp()) { + } else if (s->source->asTemp() || s->source->asArgLocal()) { if (s->swap) - swapValues(t2, t); + swapValues(s->source, s->target); else - copyValue(t2, t); + copyValue(s->source, s->target); return; } else if (IR::String *str = s->source->asString()) { - loadString(*str->value, t); + loadString(*str->value, s->target); return; } else if (IR::RegExp *re = s->source->asRegExp()) { - loadRegexp(re, t); + loadRegexp(re, s->target); return; } else if (IR::Closure *clos = s->source->asClosure()) { - initClosure(clos, t); + initClosure(clos, s->target); return; } else if (IR::New *ctor = s->source->asNew()) { if (Name *func = ctor->base->asName()) { - constructActivationProperty(func, ctor->args, t); + constructActivationProperty(func, ctor->args, s->target); return; } else if (IR::Member *member = ctor->base->asMember()) { - constructProperty(member->base->asTemp(), *member->name, ctor->args, t); + constructProperty(member->base, *member->name, ctor->args, s->target); return; - } else if (IR::Temp *value = ctor->base->asTemp()) { - constructValue(value, ctor->args, t); + } else if (ctor->base->asTemp() || ctor->base->asArgLocal()) { + constructValue(ctor->base, ctor->args, s->target); return; } } else if (IR::Member *m = s->source->asMember()) { @@ -162,46 +162,44 @@ void IRDecoder::visitMove(IR::Move *s) captureRequired = false; } } - getQObjectProperty(m->base, m->property->coreIndex, captureRequired, attachedPropertiesId, t); + getQObjectProperty(m->base, m->property->coreIndex, captureRequired, attachedPropertiesId, s->target); #endif // V4_BOOTSTRAP return; - } else if (m->base->asTemp() || m->base->asConst()) { - getProperty(m->base, *m->name, t); + } else if (m->base->asTemp() || m->base->asConst() || m->base->asArgLocal()) { + getProperty(m->base, *m->name, s->target); return; } } else if (IR::Subscript *ss = s->source->asSubscript()) { - getElement(ss->base, ss->index, t); + getElement(ss->base, ss->index, s->target); return; } else if (IR::Unop *u = s->source->asUnop()) { - if (IR::Temp *e = u->expr->asTemp()) { - unop(u->op, e, t); - return; - } + unop(u->op, u->expr, s->target); + return; } else if (IR::Binop *b = s->source->asBinop()) { - binop(b->op, b->left, b->right, t); + binop(b->op, b->left, b->right, s->target); return; } else if (IR::Call *c = s->source->asCall()) { if (c->base->asName()) { - callBuiltin(c, t); + callBuiltin(c, s->target); return; } else if (Member *member = c->base->asMember()) { - callProperty(member->base, *member->name, c->args, t); + callProperty(member->base, *member->name, c->args, s->target); return; } else if (Subscript *ss = c->base->asSubscript()) { - callSubscript(ss->base, ss->index, c->args, t); + callSubscript(ss->base, ss->index, c->args, s->target); return; - } else if (IR::Temp *value = c->base->asTemp()) { - callValue(value, c->args, t); + } else if (c->base->asTemp() || c->base->asArgLocal()) { + callValue(c->base, c->args, s->target); return; } } else if (IR::Convert *c = s->source->asConvert()) { - Q_ASSERT(c->expr->asTemp()); - convertType(c->expr->asTemp(), t); + Q_ASSERT(c->expr->asTemp() || c->expr->asArgLocal()); + convertType(c->expr, s->target); return; } } else if (IR::Member *m = s->target->asMember()) { - if (m->base->asTemp() || m->base->asConst()) { - if (s->source->asTemp() || s->source->asConst()) { + if (m->base->asTemp() || m->base->asConst() || m->base->asArgLocal()) { + if (s->source->asTemp() || s->source->asConst() || s->source->asArgLocal()) { Q_ASSERT(m->kind != IR::Member::MemberOfEnum); const int attachedPropertiesId = m->attachedPropertiesIdOrEnumValue; if (m->property && attachedPropertiesId == 0) { @@ -218,7 +216,7 @@ void IRDecoder::visitMove(IR::Move *s) } } } else if (IR::Subscript *ss = s->target->asSubscript()) { - if (s->source->asTemp() || s->source->asConst()) { + if (s->source->asTemp() || s->source->asConst() || s->source->asArgLocal()) { setElement(s->source, ss->base, ss->index); return; } @@ -226,7 +224,7 @@ void IRDecoder::visitMove(IR::Move *s) // For anything else...: Q_UNIMPLEMENTED(); - s->dump(qout, IR::Stmt::MIR); + IRPrinter(&qout).print(s); qout << endl; Q_ASSERT(!"TODO"); } @@ -241,22 +239,22 @@ void IRDecoder::visitExp(IR::Exp *s) // These are calls where the result is ignored. if (c->base->asName()) { callBuiltin(c, 0); - } else if (Temp *value = c->base->asTemp()) { - callValue(value, c->args, 0); + } else if (c->base->asTemp() || c->base->asArgLocal() || c->base->asConst()) { + callValue(c->base, c->args, 0); } else if (Member *member = c->base->asMember()) { - Q_ASSERT(member->base->asTemp()); - callProperty(member->base->asTemp(), *member->name, c->args, 0); + Q_ASSERT(member->base->asTemp() || member->base->asArgLocal()); + callProperty(member->base, *member->name, c->args, 0); } else if (Subscript *s = c->base->asSubscript()) { callSubscript(s->base, s->index, c->args, 0); } else { - Q_UNIMPLEMENTED(); + Q_UNREACHABLE(); } } else { - Q_UNIMPLEMENTED(); + Q_UNREACHABLE(); } } -void IRDecoder::callBuiltin(IR::Call *call, IR::Temp *result) +void IRDecoder::callBuiltin(IR::Call *call, Expr *result) { IR::Name *baseName = call->base->asName(); Q_ASSERT(baseName != 0); @@ -276,7 +274,9 @@ void IRDecoder::callBuiltin(IR::Call *call, IR::Temp *result) } else if (IR::Name *n = call->args->expr->asName()) { callBuiltinTypeofName(*n->id, result); return; - } else if (call->args->expr->asTemp() || call->args->expr->asConst()){ + } else if (call->args->expr->asTemp() || + call->args->expr->asConst() || + call->args->expr->asArgLocal()) { callBuiltinTypeofValue(call->args->expr, result); return; } @@ -284,15 +284,16 @@ void IRDecoder::callBuiltin(IR::Call *call, IR::Temp *result) case IR::Name::builtin_delete: { if (IR::Member *m = call->args->expr->asMember()) { - callBuiltinDeleteMember(m->base->asTemp(), *m->name, result); + callBuiltinDeleteMember(m->base, *m->name, result); return; } else if (IR::Subscript *ss = call->args->expr->asSubscript()) { - callBuiltinDeleteSubscript(ss->base->asTemp(), ss->index, result); + callBuiltinDeleteSubscript(ss->base, ss->index, result); return; } else if (IR::Name *n = call->args->expr->asName()) { callBuiltinDeleteName(*n->id, result); return; - } else if (call->args->expr->asTemp()){ + } else if (call->args->expr->asTemp() || + call->args->expr->asArgLocal()) { // TODO: should throw in strict mode callBuiltinDeleteValue(result); return; @@ -301,7 +302,7 @@ void IRDecoder::callBuiltin(IR::Call *call, IR::Temp *result) case IR::Name::builtin_throw: { IR::Expr *arg = call->args->expr; - Q_ASSERT(arg->asTemp() || arg->asConst()); + Q_ASSERT(arg->asTemp() || arg->asConst() || arg->asArgLocal()); callBuiltinThrow(arg); } return; @@ -326,14 +327,15 @@ void IRDecoder::callBuiltin(IR::Call *call, IR::Temp *result) } return; case IR::Name::builtin_foreach_next_property_name: { - IR::Temp *arg = call->args->expr->asTemp(); + IR::Expr *arg = call->args->expr; Q_ASSERT(arg != 0); callBuiltinForeachNextPropertyname(arg, result); } return; case IR::Name::builtin_push_with_scope: { - IR::Temp *arg = call->args->expr->asTemp(); - Q_ASSERT(arg != 0); - callBuiltinPushWithScope(arg); + if (call->args->expr->asTemp() || call->args->expr->asArgLocal()) + callBuiltinPushWithScope(call->args->expr); + else + Q_UNIMPLEMENTED(); } return; case IR::Name::builtin_pop_scope: @@ -402,7 +404,7 @@ void IRDecoder::callBuiltin(IR::Call *call, IR::Temp *result) } Q_UNIMPLEMENTED(); - call->dump(qout); qout << endl; + IRPrinter(&qout).print(call); qout << endl; Q_ASSERT(!"TODO!"); Q_UNREACHABLE(); } diff --git a/src/qml/compiler/qv4isel_p.h b/src/qml/compiler/qv4isel_p.h index 74e6ba8200..cbfc21c211 100644 --- a/src/qml/compiler/qv4isel_p.h +++ b/src/qml/compiler/qv4isel_p.h @@ -112,60 +112,60 @@ public: // visitor methods for StmtVisitor: virtual void visitExp(IR::Exp *s); public: // to implement by subclasses: - virtual void callBuiltinInvalid(IR::Name *func, IR::ExprList *args, IR::Temp *result) = 0; - virtual void callBuiltinTypeofMember(IR::Expr *base, const QString &name, IR::Temp *result) = 0; - virtual void callBuiltinTypeofSubscript(IR::Expr *base, IR::Expr *index, IR::Temp *result) = 0; - virtual void callBuiltinTypeofName(const QString &name, IR::Temp *result) = 0; - virtual void callBuiltinTypeofValue(IR::Expr *value, IR::Temp *result) = 0; - virtual void callBuiltinDeleteMember(IR::Temp *base, const QString &name, IR::Temp *result) = 0; - virtual void callBuiltinDeleteSubscript(IR::Temp *base, IR::Expr *index, IR::Temp *result) = 0; - virtual void callBuiltinDeleteName(const QString &name, IR::Temp *result) = 0; - virtual void callBuiltinDeleteValue(IR::Temp *result) = 0; + virtual void callBuiltinInvalid(IR::Name *func, IR::ExprList *args, IR::Expr *result) = 0; + virtual void callBuiltinTypeofMember(IR::Expr *base, const QString &name, IR::Expr *result) = 0; + virtual void callBuiltinTypeofSubscript(IR::Expr *base, IR::Expr *index, IR::Expr *result) = 0; + virtual void callBuiltinTypeofName(const QString &name, IR::Expr *result) = 0; + virtual void callBuiltinTypeofValue(IR::Expr *value, IR::Expr *result) = 0; + virtual void callBuiltinDeleteMember(IR::Expr *base, const QString &name, IR::Expr *result) = 0; + virtual void callBuiltinDeleteSubscript(IR::Expr *base, IR::Expr *index, IR::Expr *result) = 0; + virtual void callBuiltinDeleteName(const QString &name, IR::Expr *result) = 0; + virtual void callBuiltinDeleteValue(IR::Expr *result) = 0; virtual void callBuiltinThrow(IR::Expr *arg) = 0; virtual void callBuiltinReThrow() = 0; - virtual void callBuiltinUnwindException(IR::Temp *) = 0; + virtual void callBuiltinUnwindException(IR::Expr *) = 0; virtual void callBuiltinPushCatchScope(const QString &exceptionName) = 0; - virtual void callBuiltinForeachIteratorObject(IR::Expr *arg, IR::Temp *result) = 0; - virtual void callBuiltinForeachNextPropertyname(IR::Temp *arg, IR::Temp *result) = 0; - virtual void callBuiltinPushWithScope(IR::Temp *arg) = 0; + virtual void callBuiltinForeachIteratorObject(IR::Expr *arg, IR::Expr *result) = 0; + virtual void callBuiltinForeachNextPropertyname(IR::Expr *arg, IR::Expr *result) = 0; + virtual void callBuiltinPushWithScope(IR::Expr *arg) = 0; virtual void callBuiltinPopScope() = 0; virtual void callBuiltinDeclareVar(bool deletable, const QString &name) = 0; - virtual void callBuiltinDefineArray(IR::Temp *result, IR::ExprList *args) = 0; - virtual void callBuiltinDefineObjectLiteral(IR::Temp *result, int keyValuePairCount, IR::ExprList *keyValuePairs, IR::ExprList *arrayEntries, bool needSparseArray) = 0; - virtual void callBuiltinSetupArgumentObject(IR::Temp *result) = 0; + virtual void callBuiltinDefineArray(IR::Expr *result, IR::ExprList *args) = 0; + virtual void callBuiltinDefineObjectLiteral(IR::Expr *result, int keyValuePairCount, IR::ExprList *keyValuePairs, IR::ExprList *arrayEntries, bool needSparseArray) = 0; + virtual void callBuiltinSetupArgumentObject(IR::Expr *result) = 0; virtual void callBuiltinConvertThisToObject() = 0; - virtual void callValue(IR::Temp *value, IR::ExprList *args, IR::Temp *result) = 0; - virtual void callProperty(IR::Expr *base, const QString &name, IR::ExprList *args, IR::Temp *result) = 0; - virtual void callSubscript(IR::Expr *base, IR::Expr *index, IR::ExprList *args, IR::Temp *result) = 0; - virtual void convertType(IR::Temp *source, IR::Temp *target) = 0; - virtual void constructActivationProperty(IR::Name *func, IR::ExprList *args, IR::Temp *result) = 0; - virtual void constructProperty(IR::Temp *base, const QString &name, IR::ExprList *args, IR::Temp *result) = 0; - virtual void constructValue(IR::Temp *value, IR::ExprList *args, IR::Temp *result) = 0; - virtual void loadThisObject(IR::Temp *temp) = 0; - virtual void loadQmlIdArray(IR::Temp *temp) = 0; - virtual void loadQmlImportedScripts(IR::Temp *temp) = 0; - virtual void loadQmlContextObject(IR::Temp *temp) = 0; - virtual void loadQmlScopeObject(IR::Temp *temp) = 0; - virtual void loadQmlSingleton(const QString &name, IR::Temp *temp) = 0; - virtual void loadConst(IR::Const *sourceConst, IR::Temp *targetTemp) = 0; - virtual void loadString(const QString &str, IR::Temp *targetTemp) = 0; - virtual void loadRegexp(IR::RegExp *sourceRegexp, IR::Temp *targetTemp) = 0; - virtual void getActivationProperty(const IR::Name *name, IR::Temp *temp) = 0; + virtual void callValue(IR::Expr *value, IR::ExprList *args, IR::Expr *result) = 0; + virtual void callProperty(IR::Expr *base, const QString &name, IR::ExprList *args, IR::Expr *result) = 0; + virtual void callSubscript(IR::Expr *base, IR::Expr *index, IR::ExprList *args, IR::Expr *result) = 0; + virtual void convertType(IR::Expr *source, IR::Expr *target) = 0; + virtual void constructActivationProperty(IR::Name *func, IR::ExprList *args, IR::Expr *result) = 0; + virtual void constructProperty(IR::Expr *base, const QString &name, IR::ExprList *args, IR::Expr *result) = 0; + virtual void constructValue(IR::Expr *value, IR::ExprList *args, IR::Expr *result) = 0; + virtual void loadThisObject(IR::Expr *target) = 0; + virtual void loadQmlIdArray(IR::Expr *target) = 0; + virtual void loadQmlImportedScripts(IR::Expr *target) = 0; + virtual void loadQmlContextObject(IR::Expr *target) = 0; + virtual void loadQmlScopeObject(IR::Expr *target) = 0; + virtual void loadQmlSingleton(const QString &name, IR::Expr *target) = 0; + virtual void loadConst(IR::Const *sourceConst, IR::Expr *target) = 0; + virtual void loadString(const QString &str, IR::Expr *target) = 0; + virtual void loadRegexp(IR::RegExp *sourceRegexp, IR::Expr *target) = 0; + virtual void getActivationProperty(const IR::Name *name, IR::Expr *target) = 0; virtual void setActivationProperty(IR::Expr *source, const QString &targetName) = 0; - virtual void initClosure(IR::Closure *closure, IR::Temp *target) = 0; - virtual void getProperty(IR::Expr *base, const QString &name, IR::Temp *target) = 0; - virtual void getQObjectProperty(IR::Expr *base, int propertyIndex, bool captureRequired, int attachedPropertiesId, IR::Temp *targetTemp) = 0; + virtual void initClosure(IR::Closure *closure, IR::Expr *target) = 0; + virtual void getProperty(IR::Expr *base, const QString &name, IR::Expr *target) = 0; + virtual void getQObjectProperty(IR::Expr *base, int propertyIndex, bool captureRequired, int attachedPropertiesId, IR::Expr *target) = 0; virtual void setProperty(IR::Expr *source, IR::Expr *targetBase, const QString &targetName) = 0; virtual void setQObjectProperty(IR::Expr *source, IR::Expr *targetBase, int propertyIndex) = 0; - virtual void getElement(IR::Expr *base, IR::Expr *index, IR::Temp *target) = 0; + virtual void getElement(IR::Expr *base, IR::Expr *index, IR::Expr *target) = 0; virtual void setElement(IR::Expr *source, IR::Expr *targetBase, IR::Expr *targetIndex) = 0; - virtual void copyValue(IR::Temp *sourceTemp, IR::Temp *targetTemp) = 0; - virtual void swapValues(IR::Temp *sourceTemp, IR::Temp *targetTemp) = 0; - virtual void unop(IR::AluOp oper, IR::Temp *sourceTemp, IR::Temp *targetTemp) = 0; - virtual void binop(IR::AluOp oper, IR::Expr *leftSource, IR::Expr *rightSource, IR::Temp *target) = 0; + virtual void copyValue(IR::Expr *source, IR::Expr *target) = 0; + virtual void swapValues(IR::Expr *source, IR::Expr *target) = 0; + virtual void unop(IR::AluOp oper, IR::Expr *source, IR::Expr *target) = 0; + virtual void binop(IR::AluOp oper, IR::Expr *leftSource, IR::Expr *rightSource, IR::Expr *target) = 0; protected: - virtual void callBuiltin(IR::Call *c, IR::Temp *result); + virtual void callBuiltin(IR::Call *c, IR::Expr *result); IR::Function *_function; // subclass needs to set }; diff --git a/src/qml/compiler/qv4isel_util_p.h b/src/qml/compiler/qv4isel_util_p.h index 09b98a18d1..483e0eb8b4 100644 --- a/src/qml/compiler/qv4isel_util_p.h +++ b/src/qml/compiler/qv4isel_util_p.h @@ -153,6 +153,7 @@ protected: virtual void visitRegExp(IR::RegExp *) {} virtual void visitName(IR::Name *) {} virtual void visitTemp(IR::Temp *e) { renumber(e); } + virtual void visitArgLocal(IR::ArgLocal *) {} virtual void visitClosure(IR::Closure *) {} virtual void visitConvert(IR::Convert *e) { e->expr->accept(this); } virtual void visitUnop(IR::Unop *e) { e->expr->accept(this); } diff --git a/src/qml/compiler/qv4jsir.cpp b/src/qml/compiler/qv4jsir.cpp index f81985c07d..4b26ff20b7 100644 --- a/src/qml/compiler/qv4jsir.cpp +++ b/src/qml/compiler/qv4jsir.cpp @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). +** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies). ** Contact: http://www.qt-project.org/legal ** ** This file is part of the QtQml module of the Qt Toolkit. @@ -45,6 +45,8 @@ #ifndef V4_BOOTSTRAP #include <private/qqmlpropertycache_p.h> #endif + +#include <QtCore/QBuffer> #include <QtCore/qtextstream.h> #include <QtCore/qdebug.h> #include <QtCore/qset.h> @@ -231,6 +233,7 @@ struct RemoveSharedExpressions: IR::StmtVisitor, IR::ExprVisitor virtual void visitRegExp(RegExp *) {} virtual void visitName(Name *) {} virtual void visitTemp(Temp *) {} + virtual void visitArgLocal(ArgLocal *) {} virtual void visitClosure(Closure *) {} virtual void visitConvert(Convert *e) @@ -275,104 +278,6 @@ struct RemoveSharedExpressions: IR::StmtVisitor, IR::ExprVisitor } }; -static QString dumpStart(const Expr *e) { - if (e->type == UnknownType) -// return QStringLiteral("**UNKNOWN**"); - return QString(); - - QString result = typeName(e->type); -#ifndef V4_BOOTSTRAP - const Temp *temp = const_cast<Expr*>(e)->asTemp(); - if (e->type == QObjectType && temp && temp->memberResolver.isQObjectResolver) { - result += QLatin1Char('<'); - result += QString::fromUtf8(static_cast<QQmlPropertyCache*>(temp->memberResolver.data)->className()); - result += QLatin1Char('>'); - } -#endif - result += QLatin1Char('{'); - return result; -} - -static const char *dumpEnd(const Expr *e) { - if (e->type == UnknownType) - return ""; - else - return "}"; -} - -void Const::dump(QTextStream &out) const -{ - if (type != UndefinedType && type != NullType) - out << dumpStart(this); - switch (type) { - case QV4::IR::UndefinedType: - out << "undefined"; - break; - case QV4::IR::NullType: - out << "null"; - break; - case QV4::IR::BoolType: - out << (value ? "true" : "false"); - break; - case QV4::IR::MissingType: - out << "missing"; - break; - default: - if (int(value) == 0 && int(value) == value) { - if (isNegative(value)) - out << "-0"; - else - out << "0"; - } else { - out << QString::number(value, 'g', 16); - } - break; - } - if (type != UndefinedType && type != NullType) - out << dumpEnd(this); -} - -void String::dump(QTextStream &out) const -{ - out << '"' << escape(*value) << '"'; -} - -QString String::escape(const QString &s) -{ - QString r; - for (int i = 0; i < s.length(); ++i) { - const QChar ch = s.at(i); - if (ch == QLatin1Char('\n')) - r += QStringLiteral("\\n"); - else if (ch == QLatin1Char('\r')) - r += QStringLiteral("\\r"); - else if (ch == QLatin1Char('\\')) - r += QStringLiteral("\\\\"); - else if (ch == QLatin1Char('"')) - r += QStringLiteral("\\\""); - else if (ch == QLatin1Char('\'')) - r += QStringLiteral("\\'"); - else - r += ch; - } - return r; -} - -void RegExp::dump(QTextStream &out) const -{ - char f[3]; - int i = 0; - if (flags & RegExp_Global) - f[i++] = 'g'; - if (flags & RegExp_IgnoreCase) - f[i++] = 'i'; - if (flags & RegExp_Multiline) - f[i++] = 'm'; - f[i] = 0; - - out << '/' << *value << '/' << f; -} - void Name::initGlobal(const QString *id, quint32 line, quint32 column) { this->id = id; @@ -453,185 +358,11 @@ static const char *builtin_to_string(Name::Builtin b) return "builtin_(###FIXME)"; }; -void Name::dump(QTextStream &out) const -{ - if (id) - out << *id; - else - out << builtin_to_string(builtin); -} - -void Temp::dump(QTextStream &out) const -{ - out << dumpStart(this); - switch (kind) { - case Formal: out << '#' << index; break; - case ScopedFormal: out << '#' << index - << '@' << scope; break; - case Local: out << '$' << index; break; - case ScopedLocal: out << '$' << index - << '@' << scope; break; - case VirtualRegister: out << '%' << index; break; - case PhysicalRegister: out << (type == DoubleType ? "fp" : "r") - << index; break; - case StackSlot: out << '&' << index; break; - default: out << "INVALID"; - } - out << dumpEnd(this); -} - bool operator<(const Temp &t1, const Temp &t2) Q_DECL_NOTHROW { if (t1.kind < t2.kind) return true; if (t1.kind > t2.kind) return false; - if (t1.index < t2.index) return true; - if (t1.index > t2.index) return false; - return t1.scope < t2.scope; -} - -void Closure::dump(QTextStream &out) const -{ - QString name = functionName ? *functionName : QString(); - if (name.isEmpty()) - name.sprintf("%x", value); - out << "closure(" << name << ')'; -} - -void Convert::dump(QTextStream &out) const -{ - out << dumpStart(this); - out << "convert("; - expr->dump(out); - out << ')' << dumpEnd(this); -} - -void Unop::dump(QTextStream &out) const -{ - out << dumpStart(this) << opname(op); - expr->dump(out); - out << dumpEnd(this); -} - -void Binop::dump(QTextStream &out) const -{ - out << dumpStart(this); - left->dump(out); - out << ' ' << opname(op) << ' '; - right->dump(out); - out << dumpEnd(this); -} - -void Call::dump(QTextStream &out) const -{ - base->dump(out); - out << '('; - for (ExprList *it = args; it; it = it->next) { - if (it != args) - out << ", "; - it->expr->dump(out); - } - out << ')'; -} - -void New::dump(QTextStream &out) const -{ - out << "new "; - base->dump(out); - out << '('; - for (ExprList *it = args; it; it = it->next) { - if (it != args) - out << ", "; - it->expr->dump(out); - } - out << ')'; -} - -void Subscript::dump(QTextStream &out) const -{ - base->dump(out); - out << '['; - index->dump(out); - out << ']'; -} - -void Member::dump(QTextStream &out) const -{ - if (kind != MemberOfEnum && attachedPropertiesIdOrEnumValue != 0 && !base->asTemp()) - out << "[[attached property from " << attachedPropertiesIdOrEnumValue << "]]"; - else - base->dump(out); - out << '.' << *name; -#ifndef V4_BOOTSTRAP - if (property) - out << " (meta-property " << property->coreIndex << " <" << QMetaType::typeName(property->propType) << ">)"; -#endif -} - -void Exp::dump(QTextStream &out, Mode) -{ - out << "(void) "; - expr->dump(out); - out << ';'; -} - -void Move::dump(QTextStream &out, Mode mode) -{ - Q_UNUSED(mode); - - target->dump(out); - out << ' '; - if (swap) - out << "<=> "; - else - out << "= "; -// if (source->type != target->type) -// out << typeName(source->type) << "_to_" << typeName(target->type) << '('; - source->dump(out); -// if (source->type != target->type) -// out << ')'; - out << ';'; -} - -void Jump::dump(QTextStream &out, Mode mode) -{ - Q_UNUSED(mode); - out << "goto " << 'L' << target->index() << ';'; -} - -void CJump::dump(QTextStream &out, Mode mode) -{ - Q_UNUSED(mode); - out << "if ("; - cond->dump(out); - if (mode == HIR) - out << ") goto " << 'L' << iftrue->index() << "; else goto " << 'L' << iffalse->index() << ';'; - else - out << ") goto " << 'L' << iftrue->index() << ";"; -} - -void Ret::dump(QTextStream &out, Mode) -{ - out << "return"; - if (expr) { - out << ' '; - expr->dump(out); - } - out << ';'; -} - -void Phi::dump(QTextStream &out, Stmt::Mode mode) -{ - Q_UNUSED(mode); - - targetTemp->dump(out); - out << " = phi("; - for (int i = 0, ei = d->incoming.size(); i < ei; ++i) { - if (i > 0) - out << ", "; - if (d->incoming[i]) - d->incoming[i]->dump(out); - } - out << ");"; + return t1.index < t2.index; } Function *Module::newFunction(const QString &name, Function *outer) @@ -680,6 +411,7 @@ Function::Function(Module *module, Function *outer, const QString &name) , line(-1) , column(-1) , _allBasicBlocks(0) + , _statementCount(0) { this->name = newString(name); _basicBlocks.reserve(8); @@ -704,9 +436,9 @@ const QString *Function::newString(const QString &text) return &*strings.insert(text); } -BasicBlock *Function::newBasicBlock(BasicBlock *containingLoop, BasicBlock *catchBlock, BasicBlockInsertMode mode) +BasicBlock *Function::newBasicBlock(BasicBlock *catchBlock, BasicBlockInsertMode mode) { - BasicBlock *block = new BasicBlock(this, containingLoop, catchBlock); + BasicBlock *block = new BasicBlock(this, catchBlock); return mode == InsertBlock ? addBasicBlock(block) : block; } @@ -734,21 +466,6 @@ int Function::liveBasicBlocksCount() const return count; } -void Function::dump(QTextStream &out, Stmt::Mode mode) -{ - QString n = name ? *name : QString(); - if (n.isEmpty()) - n.sprintf("%p", this); - out << "function " << n << "() {" << endl; - foreach (const QString *formal, formals) - out << "\treceive " << *formal << ';' << endl; - foreach (const QString *local, locals) - out << "\tlocal " << *local << ';' << endl; - foreach (BasicBlock *bb, basicBlocks()) - bb->dump(out, mode); - out << '}' << endl; -} - void Function::removeSharedExpressions() { RemoveSharedExpressions removeSharedExpressions; @@ -793,23 +510,23 @@ Temp *BasicBlock::TEMP(unsigned index) { Q_ASSERT(!isRemoved()); Temp *e = function->New<Temp>(); - e->init(Temp::VirtualRegister, index, 0); + e->init(Temp::VirtualRegister, index); return e; } -Temp *BasicBlock::ARG(unsigned index, unsigned scope) +ArgLocal *BasicBlock::ARG(unsigned index, unsigned scope) { Q_ASSERT(!isRemoved()); - Temp *e = function->New<Temp>(); - e->init(scope ? Temp::ScopedFormal : Temp::Formal, index, scope); + ArgLocal *e = function->New<ArgLocal>(); + e->init(scope ? ArgLocal::ScopedFormal : ArgLocal::Formal, index, scope); return e; } -Temp *BasicBlock::LOCAL(unsigned index, unsigned scope) +ArgLocal *BasicBlock::LOCAL(unsigned index, unsigned scope) { Q_ASSERT(!isRemoved()); - Temp *e = function->New<Temp>(); - e->init(scope ? Temp::ScopedLocal : Temp::Local, index, scope); + ArgLocal *e = function->New<ArgLocal>(); + e->init(scope ? ArgLocal::ScopedLocal : ArgLocal::Local, index, scope); return e; } @@ -949,7 +666,7 @@ Stmt *BasicBlock::EXP(Expr *expr) if (isTerminated()) return 0; - Exp *s = function->New<Exp>(); + Exp *s = function->NewStmt<Exp>(); s->init(expr); appendStatement(s); return s; @@ -961,7 +678,7 @@ Stmt *BasicBlock::MOVE(Expr *target, Expr *source) if (isTerminated()) return 0; - Move *s = function->New<Move>(); + Move *s = function->NewStmt<Move>(); s->init(target, source); appendStatement(s); return s; @@ -973,7 +690,7 @@ Stmt *BasicBlock::JUMP(BasicBlock *target) if (isTerminated()) return 0; - Jump *s = function->New<Jump>(); + Jump *s = function->NewStmt<Jump>(); s->init(target); appendStatement(s); @@ -997,7 +714,7 @@ Stmt *BasicBlock::CJUMP(Expr *cond, BasicBlock *iftrue, BasicBlock *iffalse) return JUMP(iftrue); } - CJump *s = function->New<CJump>(); + CJump *s = function->NewStmt<CJump>(); s->init(cond, iftrue, iffalse); appendStatement(s); @@ -1022,29 +739,12 @@ Stmt *BasicBlock::RET(Temp *expr) if (isTerminated()) return 0; - Ret *s = function->New<Ret>(); + Ret *s = function->NewStmt<Ret>(); s->init(expr); appendStatement(s); return s; } -void BasicBlock::dump(QTextStream &out, Stmt::Mode mode) -{ - out << 'L' << index() << ':'; - if (catchBlock) - out << " (catchBlock L" << catchBlock->index() << ")"; - out << endl; - foreach (Stmt *s, statements()) { - out << '\t'; - s->dump(out, mode); - - if (s->location.isValid()) - out << " // line: " << s->location.startLine << " ; column: " << s->location.startColumn; - - out << endl; - } -} - void BasicBlock::setStatements(const QVector<Stmt *> &newStatements) { Q_ASSERT(!isRemoved()); @@ -1071,6 +771,14 @@ void BasicBlock::prependStatement(Stmt *stmt) _statements.prepend(stmt); } +void BasicBlock::prependStatements(const QVector<Stmt *> &stmts) +{ + Q_ASSERT(!isRemoved()); + QVector<Stmt *> newStmts = stmts; + newStmts += _statements; + _statements = newStmts; +} + void BasicBlock::insertStatementBefore(Stmt *before, Stmt *newStmt) { int idx = _statements.indexOf(before); @@ -1156,6 +864,11 @@ void CloneExpr::visitTemp(Temp *e) cloned = cloneTemp(e, block->function); } +void CloneExpr::visitArgLocal(ArgLocal *e) +{ + cloned = cloneArgLocal(e, block->function); +} + void CloneExpr::visitClosure(Closure *e) { cloned = block->CLOSURE(e->value); @@ -1197,6 +910,401 @@ void CloneExpr::visitMember(Member *e) cloned = block->MEMBER(clonedBase, e->name, e->property, e->kind, e->attachedPropertiesIdOrEnumValue); } +IRPrinter::IRPrinter(QTextStream *out) + : out(out) + , printElse(true) +{ +} + +IRPrinter::~IRPrinter() +{ +} + +void IRPrinter::print(Stmt *s) +{ + s->accept(this); +} + +void IRPrinter::print(const Expr &e) +{ + const_cast<Expr *>(&e)->accept(this); +} + +void IRPrinter::print(Expr *e) +{ + e->accept(this); +} + +void IRPrinter::print(Function *f) +{ + QString n = f->name ? *f->name : QString(); + if (n.isEmpty()) + n.sprintf("%p", f); + *out << "function " << n << '('; + + for (int i = 0; i < f->formals.size(); ++i) { + if (i != 0) + *out << ", "; + *out << *f->formals.at(i); + } + *out << ')' << endl + << '{' << endl; + + foreach (const QString *local, f->locals) + *out << " var " << *local << ';' << endl; + + foreach (BasicBlock *bb, f->basicBlocks()) + if (!bb->isRemoved()) + print(bb); + *out << '}' << endl; +} + +void IRPrinter::print(BasicBlock *bb) +{ + bool prevPrintElse = false; + std::swap(printElse, prevPrintElse); + printBlockStart(bb); + + foreach (Stmt *s, bb->statements()) { + QByteArray str; + QBuffer buf(&str); + buf.open(QIODevice::WriteOnly); + QTextStream os(&buf); + QTextStream *prevOut = &os; + std::swap(out, prevOut); + addStmtNr(s); + s->accept(this); + if (s->location.isValid()) { + out->flush(); + for (int i = 58 - str.length(); i > 0; --i) + *out << ' '; + *out << " // line: " << s->location.startLine << " column: " << s->location.startColumn; + } + + out->flush(); + std::swap(out, prevOut); + + *out << " " << str; + *out << endl; + + if (s->asCJump()) { + *out << " else goto L" << s->asCJump()->iffalse->index() << ";" << endl; + } + } + + std::swap(printElse, prevPrintElse); +} + +void IRPrinter::visitExp(Exp *s) +{ + *out << "(void) "; + s->expr->accept(this); + *out << ';'; +} + +void IRPrinter::visitMove(Move *s) +{ + s->target->accept(this); + *out << ' '; + if (s->swap) + *out << "<=> "; + else + *out << "= "; + s->source->accept(this); + *out << ';'; +} + +void IRPrinter::visitJump(Jump *s) +{ + *out << "goto L" << s->target->index() << ';'; +} + +void IRPrinter::visitCJump(CJump *s) +{ + *out << "if ("; + s->cond->accept(this); + *out << ") goto L" << s->iftrue->index() << ';'; + if (printElse) + *out << " else goto L" << s->iffalse->index() << ';'; +} + +void IRPrinter::visitRet(Ret *s) +{ + *out << "return"; + if (s->expr) { + *out << ' '; + s->expr->accept(this); + } + *out << ';'; +} + +void IRPrinter::visitPhi(Phi *s) +{ + s->targetTemp->accept(this); + *out << " = phi("; + for (int i = 0, ei = s->d->incoming.size(); i < ei; ++i) { + if (i > 0) + *out << ", "; + if (s->d->incoming[i]) + s->d->incoming[i]->accept(this); + } + *out << ");"; +} + +void IRPrinter::visitConst(Const *e) +{ + if (e->type != UndefinedType && e->type != NullType) + *out << dumpStart(e); + switch (e->type) { + case QV4::IR::UndefinedType: + *out << "undefined"; + break; + case QV4::IR::NullType: + *out << "null"; + break; + case QV4::IR::BoolType: + *out << (e->value ? "true" : "false"); + break; + case QV4::IR::MissingType: + *out << "missing"; + break; + default: + if (int(e->value) == 0 && int(e->value) == e->value) { + if (isNegative(e->value)) + *out << "-0"; + else + *out << "0"; + } else { + *out << QString::number(e->value, 'g', 16); + } + break; + } + if (e->type != UndefinedType && e->type != NullType) + *out << dumpEnd(e); +} + +void IRPrinter::visitString(String *e) +{ + *out << '"' << escape(*e->value) << '"'; +} + +void IRPrinter::visitRegExp(RegExp *e) +{ + char f[3]; + int i = 0; + if (e->flags & RegExp::RegExp_Global) + f[i++] = 'g'; + if (e->flags & RegExp::RegExp_IgnoreCase) + f[i++] = 'i'; + if (e->flags & RegExp::RegExp_Multiline) + f[i++] = 'm'; + f[i] = 0; + + *out << '/' << *e->value << '/' << f; +} + +void IRPrinter::visitName(Name *e) +{ + if (e->id) + *out << *e->id; + else + *out << builtin_to_string(e->builtin); +} + +void IRPrinter::visitTemp(Temp *e) +{ + *out << dumpStart(e); + switch (e->kind) { + case Temp::VirtualRegister: *out << '%' << e->index; break; + case Temp::PhysicalRegister: *out << (e->type == DoubleType ? "fp" : "r") + << e->index; break; + case Temp::StackSlot: *out << '&' << e->index; break; + default: *out << "INVALID"; + } + *out << dumpEnd(e); +} + +void IRPrinter::visitArgLocal(ArgLocal *e) +{ + *out << dumpStart(e); + switch (e->kind) { + case ArgLocal::Formal: *out << '#' << e->index; break; + case ArgLocal::ScopedFormal: *out << '#' << e->index + << '@' << e->scope; break; + case ArgLocal::Local: *out << '$' << e->index; break; + case ArgLocal::ScopedLocal: *out << '$' << e->index + << '@' << e->scope; break; + default: *out << "INVALID"; + } + *out << dumpEnd(e); +} + +void IRPrinter::visitClosure(Closure *e) +{ + QString name = e->functionName ? *e->functionName : QString(); + if (name.isEmpty()) + name.sprintf("%x", e->value); + *out << "closure(" << name << ')'; +} + +void IRPrinter::visitConvert(Convert *e) +{ + *out << dumpStart(e); + *out << "convert("; + e->expr->accept(this); + *out << ')' << dumpEnd(e); +} + +void IRPrinter::visitUnop(Unop *e) +{ + *out << dumpStart(e) << opname(e->op); + e->expr->accept(this); + *out << dumpEnd(e); +} + +void IRPrinter::visitBinop(Binop *e) +{ + *out << dumpStart(e); + e->left->accept(this); + *out << ' ' << opname(e->op) << ' '; + e->right->accept(this); + *out << dumpEnd(e); +} + +void IRPrinter::visitCall(Call *e) +{ + e->base->accept(this); + *out << '('; + for (ExprList *it = e->args; it; it = it->next) { + if (it != e->args) + *out << ", "; + it->expr->accept(this); + } + *out << ')'; +} + +void IRPrinter::visitNew(New *e) +{ + *out << "new "; + e->base->accept(this); + *out << '('; + for (ExprList *it = e->args; it; it = it->next) { + if (it != e->args) + *out << ", "; + it->expr->accept(this); + } + *out << ')'; +} + +void IRPrinter::visitSubscript(Subscript *e) +{ + e->base->accept(this); + *out << '['; + e->index->accept(this); + *out << ']'; +} + +void IRPrinter::visitMember(Member *e) +{ + if (e->kind != Member::MemberOfEnum + && e->attachedPropertiesIdOrEnumValue != 0 && !e->base->asTemp()) + *out << "[[attached property from " << e->attachedPropertiesIdOrEnumValue << "]]"; + else + e->base->accept(this); + *out << '.' << *e->name; +#ifndef V4_BOOTSTRAP + if (e->property) + *out << " (meta-property " << e->property->coreIndex + << " <" << QMetaType::typeName(e->property->propType) + << ">)"; +#endif +} + +QString IRPrinter::escape(const QString &s) +{ + QString r; + for (int i = 0; i < s.length(); ++i) { + const QChar ch = s.at(i); + if (ch == QLatin1Char('\n')) + r += QStringLiteral("\\n"); + else if (ch == QLatin1Char('\r')) + r += QStringLiteral("\\r"); + else if (ch == QLatin1Char('\\')) + r += QStringLiteral("\\\\"); + else if (ch == QLatin1Char('"')) + r += QStringLiteral("\\\""); + else if (ch == QLatin1Char('\'')) + r += QStringLiteral("\\'"); + else + r += ch; + } + return r; +} + +void IRPrinter::addStmtNr(Stmt *s) +{ + if (s->id() >= 0) + *out << s->id() << ": "; +} + +QString IRPrinter::dumpStart(const Expr *e) +{ + if (e->type == UnknownType) + return QString(); + + QString result = typeName(e->type); +#ifndef V4_BOOTSTRAP + const Temp *temp = const_cast<Expr*>(e)->asTemp(); + if (e->type == QObjectType && temp && temp->memberResolver.isQObjectResolver) { + result += QLatin1Char('<'); + result += QString::fromUtf8(static_cast<QQmlPropertyCache*>(temp->memberResolver.data)->className()); + result += QLatin1Char('>'); + } +#endif + result += QLatin1Char('{'); + return result; +} + +const char *IRPrinter::dumpEnd(const Expr *e) +{ + if (e->type == UnknownType) + return ""; + else + return "}"; +} + +void IRPrinter::printBlockStart(BasicBlock *bb) +{ + if (bb->isRemoved()) { + *out << "(block has been removed)"; + return; + } + + QByteArray str; + str.append('L'); + str.append(QByteArray::number(bb->index())); + str.append(':'); + if (bb->catchBlock) { + str.append(" (exception handler L"); + str.append(QByteArray::number(bb->catchBlock->index())); + str.append(')'); + } + for (int i = 66 - str.length(); i; --i) + str.append(' '); + *out << str; + + *out << "// predecessor blocks:"; + foreach (BasicBlock *in, bb->in) + *out << " L" << in->index(); + if (bb->in.isEmpty()) + *out << " (none)"; + if (BasicBlock *container = bb->containingGroup()) + *out << "; container block: L" << container->index(); + if (bb->isGroupStart()) + *out << "; group start"; + *out << endl; +} + } // end of namespace IR } // end of namespace QV4 diff --git a/src/qml/compiler/qv4jsir_p.h b/src/qml/compiler/qv4jsir_p.h index 9eff90dd30..606313d0c1 100644 --- a/src/qml/compiler/qv4jsir_p.h +++ b/src/qml/compiler/qv4jsir_p.h @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). +** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies). ** Contact: http://www.qt-project.org/legal ** ** This file is part of the QtQml module of the Qt Toolkit. @@ -108,6 +108,7 @@ struct String; struct RegExp; struct Name; struct Temp; +struct ArgLocal; struct Closure; struct Convert; struct Unop; @@ -210,6 +211,7 @@ struct ExprVisitor { virtual void visitRegExp(RegExp *) = 0; virtual void visitName(Name *) = 0; virtual void visitTemp(Temp *) = 0; + virtual void visitArgLocal(ArgLocal *) = 0; virtual void visitClosure(Closure *) = 0; virtual void visitConvert(Convert *) = 0; virtual void visitUnop(Unop *) = 0; @@ -260,6 +262,7 @@ struct Q_AUTOTEST_EXPORT Expr { virtual RegExp *asRegExp() { return 0; } virtual Name *asName() { return 0; } virtual Temp *asTemp() { return 0; } + virtual ArgLocal *asArgLocal() { return 0; } virtual Closure *asClosure() { return 0; } virtual Convert *asConvert() { return 0; } virtual Unop *asUnop() { return 0; } @@ -268,7 +271,6 @@ struct Q_AUTOTEST_EXPORT Expr { virtual New *asNew() { return 0; } virtual Subscript *asSubscript() { return 0; } virtual Member *asMember() { return 0; } - virtual void dump(QTextStream &out) const = 0; }; struct ExprList { @@ -295,8 +297,6 @@ struct Const: Expr { virtual void accept(ExprVisitor *v) { v->visitConst(this); } virtual Const *asConst() { return this; } - - virtual void dump(QTextStream &out) const; }; struct String: Expr { @@ -309,9 +309,6 @@ struct String: Expr { virtual void accept(ExprVisitor *v) { v->visitString(this); } virtual String *asString() { return this; } - - virtual void dump(QTextStream &out) const; - static QString escape(const QString &s); }; struct RegExp: Expr { @@ -333,8 +330,6 @@ struct RegExp: Expr { virtual void accept(ExprVisitor *v) { v->visitRegExp(this); } virtual RegExp *asRegExp() { return this; } - - virtual void dump(QTextStream &out) const; }; struct Name: Expr { @@ -376,60 +371,85 @@ struct Name: Expr { virtual void accept(ExprVisitor *v) { v->visitName(this); } virtual bool isLValue() { return true; } virtual Name *asName() { return this; } - - virtual void dump(QTextStream &out) const; }; struct Q_AUTOTEST_EXPORT Temp: Expr { enum Kind { - Formal = 0, - ScopedFormal, - Local, - ScopedLocal, + Invalid = 0, VirtualRegister, PhysicalRegister, StackSlot }; - unsigned index; - unsigned scope : 27; // how many scopes outside the current one? - unsigned kind : 3; - unsigned isArgumentsOrEval : 1; - unsigned isReadOnly : 1; + unsigned index : 28; + unsigned kind : 3; + unsigned isReadOnly : 1; // Used when temp is used as base in member expression MemberExpressionResolver memberResolver; - void init(unsigned kind, unsigned index, unsigned scope) - { - Q_ASSERT((kind == ScopedLocal && scope != 0) || - (kind == ScopedFormal && scope != 0) || - (scope == 0)); + Temp() + : index((1 << 28) - 1) + , kind(Invalid) + , isReadOnly(0) + {} + void init(unsigned kind, unsigned index) + { this->kind = kind; this->index = index; - this->scope = scope; - this->isArgumentsOrEval = false; this->isReadOnly = false; } + bool isInvalid() const { return kind == Invalid; } virtual void accept(ExprVisitor *v) { v->visitTemp(this); } virtual bool isLValue() { return !isReadOnly; } virtual Temp *asTemp() { return this; } - - virtual void dump(QTextStream &out) const; }; inline bool operator==(const Temp &t1, const Temp &t2) Q_DECL_NOTHROW -{ return t1.index == t2.index && t1.scope == t2.scope && t1.kind == t2.kind && t1.type == t2.type; } +{ return t1.index == t2.index && t1.kind == t2.kind && t1.type == t2.type; } inline bool operator!=(const Temp &t1, const Temp &t2) Q_DECL_NOTHROW { return !(t1 == t2); } inline uint qHash(const Temp &t, uint seed = 0) Q_DECL_NOTHROW -{ return t.index ^ (t.kind | (t.scope << 3)) ^ seed; } +{ return t.index ^ t.kind ^ seed; } bool operator<(const Temp &t1, const Temp &t2) Q_DECL_NOTHROW; +struct Q_AUTOTEST_EXPORT ArgLocal: Expr { + enum Kind { + Formal = 0, + ScopedFormal, + Local, + ScopedLocal + }; + + unsigned index; + unsigned scope : 29; // how many scopes outside the current one? + unsigned kind : 2; + unsigned isArgumentsOrEval : 1; + + void init(unsigned kind, unsigned index, unsigned scope) + { + Q_ASSERT((kind == ScopedLocal && scope != 0) || + (kind == ScopedFormal && scope != 0) || + (scope == 0)); + + this->kind = kind; + this->index = index; + this->scope = scope; + this->isArgumentsOrEval = false; + } + + virtual void accept(ExprVisitor *v) { v->visitArgLocal(this); } + virtual bool isLValue() { return true; } + virtual ArgLocal *asArgLocal() { return this; } + + bool operator==(const ArgLocal &other) const + { return index == other.index && scope == other.scope && kind == other.kind; } +}; + struct Closure: Expr { int value; // index in _module->functions const QString *functionName; @@ -442,8 +462,6 @@ struct Closure: Expr { virtual void accept(ExprVisitor *v) { v->visitClosure(this); } virtual Closure *asClosure() { return this; } - - virtual void dump(QTextStream &out) const; }; struct Convert: Expr { @@ -457,8 +475,6 @@ struct Convert: Expr { virtual void accept(ExprVisitor *v) { v->visitConvert(this); } virtual Convert *asConvert() { return this; } - - virtual void dump(QTextStream &out) const; }; struct Unop: Expr { @@ -473,8 +489,6 @@ struct Unop: Expr { virtual void accept(ExprVisitor *v) { v->visitUnop(this); } virtual Unop *asUnop() { return this; } - - virtual void dump(QTextStream &out) const; }; struct Binop: Expr { @@ -491,8 +505,6 @@ struct Binop: Expr { virtual void accept(ExprVisitor *v) { v->visitBinop(this); } virtual Binop *asBinop() { return this; } - - virtual void dump(QTextStream &out) const; }; struct Call: Expr { @@ -513,8 +525,6 @@ struct Call: Expr { virtual void accept(ExprVisitor *v) { v->visitCall(this); } virtual Call *asCall() { return this; } - - virtual void dump(QTextStream &out) const; }; struct New: Expr { @@ -535,8 +545,6 @@ struct New: Expr { virtual void accept(ExprVisitor *v) { v->visitNew(this); } virtual New *asNew() { return this; } - - virtual void dump(QTextStream &out) const; }; struct Subscript: Expr { @@ -552,8 +560,6 @@ struct Subscript: Expr { virtual void accept(ExprVisitor *v) { v->visitSubscript(this); } virtual bool isLValue() { return true; } virtual Subscript *asSubscript() { return this; } - - virtual void dump(QTextStream &out) const; }; struct Member: Expr { @@ -605,25 +611,20 @@ struct Member: Expr { virtual void accept(ExprVisitor *v) { v->visitMember(this); } virtual bool isLValue() { return true; } virtual Member *asMember() { return this; } - - virtual void dump(QTextStream &out) const; }; struct Stmt { - enum Mode { - HIR, - MIR - }; - struct Data { QVector<Expr *> incoming; // used by Phi nodes }; + enum { InvalidId = -1 }; + Data *d; - int id; QQmlJS::AST::SourceLocation location; - Stmt(): d(0), id(-1) {} + explicit Stmt(int id): d(0), _id(id) {} + virtual ~Stmt() { #ifdef Q_CC_MSVC @@ -641,7 +642,8 @@ struct Stmt { virtual CJump *asCJump() { return 0; } virtual Ret *asRet() { return 0; } virtual Phi *asPhi() { return 0; } - virtual void dump(QTextStream &out, Mode mode = HIR) = 0; + + int id() const { return _id; } private: // For memory management in BasicBlock friend struct BasicBlock; @@ -649,11 +651,17 @@ private: // For memory management in BasicBlock delete d; d = 0; } + +private: + friend struct Function; + int _id; }; struct Exp: Stmt { Expr *expr; + Exp(int id): Stmt(id) {} + void init(Expr *expr) { this->expr = expr; @@ -662,7 +670,6 @@ struct Exp: Stmt { virtual void accept(StmtVisitor *v) { v->visitExp(this); } virtual Exp *asExp() { return this; } - virtual void dump(QTextStream &out, Mode); }; struct Move: Stmt { @@ -670,6 +677,8 @@ struct Move: Stmt { Expr *source; bool swap; + Move(int id): Stmt(id) {} + void init(Expr *target, Expr *source) { this->target = target; @@ -680,12 +689,13 @@ struct Move: Stmt { virtual void accept(StmtVisitor *v) { v->visitMove(this); } virtual Move *asMove() { return this; } - virtual void dump(QTextStream &out, Mode mode = HIR); }; struct Jump: Stmt { BasicBlock *target; + Jump(int id): Stmt(id) {} + void init(BasicBlock *target) { this->target = target; @@ -695,8 +705,6 @@ struct Jump: Stmt { virtual void accept(StmtVisitor *v) { v->visitJump(this); } virtual Jump *asJump() { return this; } - - virtual void dump(QTextStream &out, Mode mode); }; struct CJump: Stmt { @@ -704,6 +712,8 @@ struct CJump: Stmt { BasicBlock *iftrue; BasicBlock *iffalse; + CJump(int id): Stmt(id) {} + void init(Expr *cond, BasicBlock *iftrue, BasicBlock *iffalse) { this->cond = cond; @@ -715,13 +725,13 @@ struct CJump: Stmt { virtual void accept(StmtVisitor *v) { v->visitCJump(this); } virtual CJump *asCJump() { return this; } - - virtual void dump(QTextStream &out, Mode mode); }; struct Ret: Stmt { Expr *expr; + Ret(int id): Stmt(id) {} + void init(Expr *expr) { this->expr = expr; @@ -731,17 +741,15 @@ struct Ret: Stmt { virtual void accept(StmtVisitor *v) { v->visitRet(this); } virtual Ret *asRet() { return this; } - - virtual void dump(QTextStream &out, Mode); }; struct Phi: Stmt { Temp *targetTemp; + Phi(int id): Stmt(id) {} + virtual void accept(StmtVisitor *v) { v->visitPhi(this); } virtual Phi *asPhi() { return this; } - - virtual void dump(QTextStream &out, Mode mode); }; struct Q_QML_PRIVATE_EXPORT Module { @@ -775,10 +783,10 @@ public: QVector<BasicBlock *> out; QQmlJS::AST::SourceLocation nextLocation; - BasicBlock(Function *function, BasicBlock *containingLoop, BasicBlock *catcher) + BasicBlock(Function *function, BasicBlock *catcher) : function(function) , catchBlock(catcher) - , _containingGroup(containingLoop) + , _containingGroup(0) , _index(-1) , _isExceptionHandler(false) , _groupStart(false) @@ -812,6 +820,7 @@ public: void appendStatement(Stmt *statement); void prependStatement(Stmt *stmt); + void prependStatements(const QVector<Stmt *> &stmts); void insertStatementBefore(Stmt *before, Stmt *newStmt); void insertStatementBefore(int index, Stmt *newStmt); void insertStatementBeforeTerminator(Stmt *stmt); @@ -841,8 +850,8 @@ public: unsigned newTemp(); Temp *TEMP(unsigned kind); - Temp *ARG(unsigned index, unsigned scope); - Temp *LOCAL(unsigned index, unsigned scope); + ArgLocal *ARG(unsigned index, unsigned scope); + ArgLocal *LOCAL(unsigned index, unsigned scope); Expr *CONST(Type type, double value); Expr *STRING(const QString *value); @@ -871,8 +880,6 @@ public: Stmt *CJUMP(Expr *cond, BasicBlock *iftrue, BasicBlock *iffalse); Stmt *RET(Temp *expr); - void dump(QTextStream &out, Stmt::Mode mode = Stmt::HIR); - BasicBlock *containingGroup() const { Q_ASSERT(!isRemoved()); @@ -994,7 +1001,10 @@ struct Function { PropertyDependencyMap contextObjectPropertyDependencies; PropertyDependencyMap scopeObjectPropertyDependencies; - template <typename _Tp> _Tp *New() { return new (pool->allocate(sizeof(_Tp))) _Tp(); } + template <typename T> T *New() { return new (pool->allocate(sizeof(T))) T(); } + template <typename T> T *NewStmt() { + return new (pool->allocate(sizeof(T))) T(getNewStatementId()); + } Function(Module *module, Function *outer, const QString &name); ~Function(); @@ -1004,7 +1014,7 @@ struct Function { DontInsertBlock }; - BasicBlock *newBasicBlock(BasicBlock *containingLoop, BasicBlock *catchBlock, BasicBlockInsertMode mode = InsertBlock); + BasicBlock *newBasicBlock(BasicBlock *catchBlock, BasicBlockInsertMode mode = InsertBlock); const QString *newString(const QString &text); void RECEIVE(const QString &name) { formals.append(newString(name)); } @@ -1024,8 +1034,6 @@ struct Function { int liveBasicBlocksCount() const; - void dump(QTextStream &out, Stmt::Mode mode = Stmt::HIR); - void removeSharedExpressions(); int indexOfArgument(const QStringRef &string) const; @@ -1036,9 +1044,13 @@ struct Function { void setScheduledBlocks(const QVector<BasicBlock *> &scheduled); void renumberBasicBlocks(); + unsigned getNewStatementId() { return _statementCount++; } + unsigned statementCount() const { return _statementCount; } + private: QVector<BasicBlock *> _basicBlocks; QVector<BasicBlock *> *_allBasicBlocks; + unsigned _statementCount; }; class CloneExpr: protected IR::ExprVisitor @@ -1088,12 +1100,20 @@ public: static Temp *cloneTemp(Temp *t, Function *f) { Temp *newTemp = f->New<Temp>(); - newTemp->init(t->kind, t->index, t->scope); + newTemp->init(t->kind, t->index); newTemp->type = t->type; newTemp->memberResolver = t->memberResolver; return newTemp; } + static ArgLocal *cloneArgLocal(ArgLocal *argLocal, Function *f) + { + ArgLocal *newArgLocal = f->New<ArgLocal>(); + newArgLocal->init(argLocal->kind, argLocal->index, argLocal->scope); + newArgLocal->type = argLocal->type; + return newArgLocal; + } + protected: IR::ExprList *clone(IR::ExprList *list); @@ -1102,6 +1122,7 @@ protected: virtual void visitRegExp(RegExp *); virtual void visitName(Name *); virtual void visitTemp(Temp *); + virtual void visitArgLocal(ArgLocal *); virtual void visitClosure(Closure *); virtual void visitConvert(Convert *); virtual void visitUnop(Unop *); @@ -1116,6 +1137,54 @@ private: IR::Expr *cloned; }; +class IRPrinter: public StmtVisitor, public ExprVisitor +{ +public: + IRPrinter(QTextStream *out); + virtual ~IRPrinter(); + + void print(Stmt *s); + void print(Expr *e); + void print(const Expr &e); + + virtual void print(Function *f); + virtual void print(BasicBlock *bb); + + virtual void visitExp(Exp *s); + virtual void visitMove(Move *s); + virtual void visitJump(Jump *s); + virtual void visitCJump(CJump *s); + virtual void visitRet(Ret *s); + virtual void visitPhi(Phi *s); + + virtual void visitConst(Const *e); + virtual void visitString(String *e); + virtual void visitRegExp(RegExp *e); + virtual void visitName(Name *e); + virtual void visitTemp(Temp *e); + virtual void visitArgLocal(ArgLocal *e); + virtual void visitClosure(Closure *e); + virtual void visitConvert(Convert *e); + virtual void visitUnop(Unop *e); + virtual void visitBinop(Binop *e); + virtual void visitCall(Call *e); + virtual void visitNew(New *e); + virtual void visitSubscript(Subscript *e); + virtual void visitMember(Member *e); + + static QString escape(const QString &s); + +protected: + virtual void addStmtNr(Stmt *s); + QString dumpStart(const Expr *e); + const char *dumpEnd(const Expr *e); + void printBlockStart(BasicBlock *bb); + +protected: + QTextStream *out; + bool printElse; +}; + } // end of namespace IR } // end of namespace QV4 diff --git a/src/qml/compiler/qv4ssa.cpp b/src/qml/compiler/qv4ssa.cpp index d7dbfac50b..8488d6eb2b 100644 --- a/src/qml/compiler/qv4ssa.cpp +++ b/src/qml/compiler/qv4ssa.cpp @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). +** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies). ** Contact: http://www.qt-project.org/legal ** ** This file is part of the QtQml module of the Qt Toolkit. @@ -39,9 +39,10 @@ ** ****************************************************************************/ -#ifndef QT_NO_DEBUG -# define _LIBCPP_DEBUG2 0 -#endif // QT_NO_DEBUG +// When building with debug code, the macro below will enable debug helpers when using libc++. +// For example, the std::vector<T>::operator[] will use _LIBCPP_ASSERT to check if the index is +// within the array bounds. Note that this only works reliably with OSX 10.9 or later. +//#define _LIBCPP_DEBUG2 2 #include "qv4ssa_p.h" #include "qv4isel_util_p.h" @@ -50,7 +51,6 @@ #include <QtCore/QCoreApplication> #include <QtCore/QStringList> #include <QtCore/QSet> -#include <QtCore/QBuffer> #include <QtCore/QLinkedList> #include <QtCore/QStack> #include <qv4runtime_p.h> @@ -69,102 +69,20 @@ using namespace IR; namespace { +#ifdef QT_NO_DEBUG +enum { DoVerification = 0 }; +#else +enum { DoVerification = 1 }; +#endif + Q_GLOBAL_STATIC_WITH_ARGS(QTextStream, qout, (stderr, QIODevice::WriteOnly)); #define qout *qout() void showMeTheCode(IR::Function *function) { static bool showCode = !qgetenv("QV4_SHOW_IR").isNull(); - if (showCode) { - QVector<Stmt *> code; - QHash<Stmt *, BasicBlock *> leader; - - foreach (BasicBlock *block, function->basicBlocks()) { - if (block->isRemoved() || block->isEmpty()) - continue; - leader.insert(block->statements().first(), block); - foreach (Stmt *s, block->statements()) { - code.append(s); - } - } - - QString name; - if (function->name && !function->name->isEmpty()) - name = *function->name; - else - name.sprintf("%p", function); - - qout << "function " << name << "("; - for (int i = 0; i < function->formals.size(); ++i) { - if (i != 0) - qout << ", "; - qout << *function->formals.at(i); - } - qout << ")" << endl - << "{" << endl; - - foreach (const QString *local, function->locals) { - qout << " var " << *local << ';' << endl; - } - - for (int i = 0; i < code.size(); ++i) { - Stmt *s = code.at(i); - Q_ASSERT(s); - - if (BasicBlock *bb = leader.value(s)) { - qout << endl; - QByteArray str; - str.append('L'); - str.append(QByteArray::number(bb->index())); - str.append(':'); - if (bb->catchBlock) { - str.append(" (exception handler L"); - str.append(QByteArray::number(bb->catchBlock->index())); - str.append(')'); - } - for (int i = 66 - str.length(); i; --i) - str.append(' '); - qout << str; - qout << "// predecessor blocks:"; - foreach (BasicBlock *in, bb->in) - qout << " L" << in->index(); - if (bb->in.isEmpty()) - qout << "(none)"; - if (BasicBlock *container = bb->containingGroup()) - qout << "; container block: L" << container->index(); - if (bb->isGroupStart()) - qout << "; group start"; - qout << endl; - } - Stmt *n = (i + 1) < code.size() ? code.at(i + 1) : 0; - - QByteArray str; - QBuffer buf(&str); - buf.open(QIODevice::WriteOnly); - QTextStream out(&buf); - if (s->id > 0) - out << s->id << ": "; - s->dump(out, Stmt::MIR); - if (s->location.isValid()) { - out.flush(); - for (int i = 58 - str.length(); i > 0; --i) - out << ' '; - out << " // line: " << s->location.startLine << " column: " << s->location.startColumn; - } - - out.flush(); - - qout << " " << str; - qout << endl; - - if (n && s->asCJump()) { - qout << " else goto L" << s->asCJump()->iffalse->index() << ";" << endl; - } - } - - qout << "}" << endl - << endl; - } + if (showCode) + IRPrinter(&qout).print(function); } class ProcessedBlocks @@ -190,29 +108,6 @@ public: } }; -inline bool unescapableTemp(Temp *t, IR::Function *f) -{ - switch (t->kind) { - case Temp::Formal: - case Temp::ScopedFormal: - case Temp::ScopedLocal: - return false; - case Temp::Local: - return !f->variablesCanEscape(); - default: - return true; - } -} - -inline Temp *unescapableTemp(Expr *e, IR::Function *f) -{ - Temp *t = e->asTemp(); - if (!t) - return 0; - - return unescapableTemp(t, f) ? t : 0; -} - class BasicBlockSet { typedef std::vector<int> Numbers; @@ -237,7 +132,7 @@ public: const_iterator(const BasicBlockSet &set, bool end) : set(set) { - if (end) { + if (end || !set.function) { if (set.blockNumbers) numberIt = set.blockNumbers->end(); else @@ -274,10 +169,11 @@ public: public: BasicBlock *operator*() const { + if (set.blockNumbers) { return set.function->basicBlock(*numberIt); } else { - Q_ASSERT(flagIt <= INT_MAX); + Q_ASSERT(flagIt <= static_cast<size_t>(set.function->basicBlockCount())); return set.function->basicBlock(static_cast<int>(flagIt)); } } @@ -332,6 +228,8 @@ public: void insert(BasicBlock *bb) { + Q_ASSERT(function); + if (blockFlags) { (*blockFlags)[bb->index()] = true; return; @@ -358,31 +256,42 @@ public: const_iterator begin() const { return const_iterator(*this, false); } const_iterator end() const { return const_iterator(*this, true); } - QList<BasicBlock *> values() const + void collectValues(std::vector<BasicBlock *> &bbs) const { - QList<BasicBlock *> result; + Q_ASSERT(function); for (const_iterator it = begin(), eit = end(); it != eit; ++it) - result.append(*it); - - return result; + bbs.push_back(*it); } }; -class DominatorTree { +class DominatorTree +{ + enum { + DebugDominatorFrontiers = 0, + DebugImmediateDominators = 0 + }; + typedef int BasicBlockIndex; enum { InvalidBasicBlockIndex = -1 }; + struct Data + { + int N; + std::vector<int> dfnum; // BasicBlock index -> dfnum + std::vector<int> vertex; + std::vector<BasicBlockIndex> parent; // BasicBlock index -> parent BasicBlock index + std::vector<BasicBlockIndex> ancestor; // BasicBlock index -> ancestor BasicBlock index + std::vector<BasicBlockIndex> best; // BasicBlock index -> best BasicBlock index + std::vector<BasicBlockIndex> semi; // BasicBlock index -> semi dominator BasicBlock index + std::vector<BasicBlockIndex> samedom; // BasicBlock index -> same dominator BasicBlock index + + Data(): N(0) {} + }; + IR::Function *function; - int N; - std::vector<int> dfnum; // BasicBlock index -> dfnum - std::vector<int> vertex; - std::vector<BasicBlockIndex> parent; // BasicBlock index -> parent BasicBlock index - std::vector<BasicBlockIndex> ancestor; // BasicBlock index -> ancestor BasicBlock index - std::vector<BasicBlockIndex> best; // BasicBlock index -> best BasicBlock index - std::vector<BasicBlockIndex> semi; // BasicBlock index -> semi dominator BasicBlock index + QScopedPointer<Data> d; std::vector<BasicBlockIndex> idom; // BasicBlock index -> immediate dominator BasicBlock index - std::vector<BasicBlockIndex> samedom; // BasicBlock index -> same dominator BasicBlock index std::vector<BasicBlockSet> DF; // BasicBlock index -> dominator frontier struct DFSTodo { @@ -401,17 +310,17 @@ class DominatorTree { void DFS(BasicBlockIndex node) { std::vector<DFSTodo> worklist; - worklist.reserve(vertex.capacity() / 2); + worklist.reserve(d->vertex.capacity() / 2); DFSTodo todo(node, InvalidBasicBlockIndex); while (true) { BasicBlockIndex n = todo.node; - if (dfnum[n] == 0) { - dfnum[n] = N; - vertex[N] = n; - parent[n] = todo.parent; - ++N; + if (d->dfnum[n] == 0) { + d->dfnum[n] = d->N; + d->vertex[d->N] = n; + d->parent[n] = todo.parent; + ++d->N; const QVector<BasicBlock *> &out = function->basicBlock(n)->out; for (int i = out.size() - 1; i > 0; --i) worklist.push_back(DFSTodo(out[i]->index(), n)); @@ -438,20 +347,20 @@ class DominatorTree { BasicBlockIndex ancestorWithLowestSemi(BasicBlockIndex v, std::vector<BasicBlockIndex> &worklist) { worklist.clear(); - for (BasicBlockIndex it = v; it != InvalidBasicBlockIndex; it = ancestor[it]) + for (BasicBlockIndex it = v; it != InvalidBasicBlockIndex; it = d->ancestor[it]) worklist.push_back(it); if (worklist.size() < 2) - return best[v]; + return d->best[v]; BasicBlockIndex b = InvalidBasicBlockIndex; BasicBlockIndex last = worklist.back(); Q_ASSERT(worklist.size() <= INT_MAX); for (int it = static_cast<int>(worklist.size()) - 2; it >= 0; --it) { BasicBlockIndex bbIt = worklist[it]; - ancestor[bbIt] = last; - BasicBlockIndex &best_it = best[bbIt]; - if (b != InvalidBasicBlockIndex && dfnum[semi[b]] < dfnum[semi[best_it]]) + d->ancestor[bbIt] = last; + BasicBlockIndex &best_it = d->best[bbIt]; + if (b != InvalidBasicBlockIndex && d->dfnum[d->semi[b]] < d->dfnum[d->semi[best_it]]) best_it = b; else b = best_it; @@ -460,57 +369,57 @@ class DominatorTree { } void link(BasicBlockIndex p, BasicBlockIndex n) { - ancestor[n] = p; - best[n] = n; + d->ancestor[n] = p; + d->best[n] = n; } void calculateIDoms() { Q_ASSERT(function->basicBlock(0)->in.isEmpty()); const int bbCount = function->basicBlockCount(); - vertex = std::vector<int>(bbCount, InvalidBasicBlockIndex); - parent = std::vector<int>(bbCount, InvalidBasicBlockIndex); - dfnum = std::vector<int>(bbCount, 0); - semi = std::vector<BasicBlockIndex>(bbCount, InvalidBasicBlockIndex); - ancestor = std::vector<BasicBlockIndex>(bbCount, InvalidBasicBlockIndex); + d->vertex = std::vector<int>(bbCount, InvalidBasicBlockIndex); + d->parent = std::vector<int>(bbCount, InvalidBasicBlockIndex); + d->dfnum = std::vector<int>(bbCount, 0); + d->semi = std::vector<BasicBlockIndex>(bbCount, InvalidBasicBlockIndex); + d->ancestor = std::vector<BasicBlockIndex>(bbCount, InvalidBasicBlockIndex); idom = std::vector<BasicBlockIndex>(bbCount, InvalidBasicBlockIndex); - samedom = std::vector<BasicBlockIndex>(bbCount, InvalidBasicBlockIndex); - best = std::vector<BasicBlockIndex>(bbCount, InvalidBasicBlockIndex); + d->samedom = std::vector<BasicBlockIndex>(bbCount, InvalidBasicBlockIndex); + d->best = std::vector<BasicBlockIndex>(bbCount, InvalidBasicBlockIndex); QHash<BasicBlockIndex, std::vector<BasicBlockIndex> > bucket; bucket.reserve(bbCount); DFS(function->basicBlock(0)->index()); - Q_ASSERT(N == function->liveBasicBlocksCount()); + Q_ASSERT(d->N == function->liveBasicBlocksCount()); std::vector<BasicBlockIndex> worklist; - worklist.reserve(vertex.capacity() / 2); + worklist.reserve(d->vertex.capacity() / 2); - for (int i = N - 1; i > 0; --i) { - BasicBlockIndex n = vertex[i]; - BasicBlockIndex p = parent[n]; + for (int i = d->N - 1; i > 0; --i) { + BasicBlockIndex n = d->vertex[i]; + BasicBlockIndex p = d->parent[n]; BasicBlockIndex s = p; foreach (BasicBlock *v, function->basicBlock(n)->in) { BasicBlockIndex ss = InvalidBasicBlockIndex; - if (dfnum[v->index()] <= dfnum[n]) + if (d->dfnum[v->index()] <= d->dfnum[n]) ss = v->index(); else - ss = semi[ancestorWithLowestSemi(v->index(), worklist)]; - if (dfnum[ss] < dfnum[s]) + ss = d->semi[ancestorWithLowestSemi(v->index(), worklist)]; + if (d->dfnum[ss] < d->dfnum[s]) s = ss; } - semi[n] = s; + d->semi[n] = s; bucket[s].push_back(n); link(p, n); if (bucket.contains(p)) { foreach (BasicBlockIndex v, bucket[p]) { BasicBlockIndex y = ancestorWithLowestSemi(v, worklist); - BasicBlockIndex semi_v = semi[v]; - if (semi[y] == semi_v) + BasicBlockIndex semi_v = d->semi[v]; + if (d->semi[y] == semi_v) idom[v] = semi_v; else - samedom[v] = y; + d->samedom[v] = y; } bucket.remove(p); } @@ -521,31 +430,19 @@ class DominatorTree { qDebug("\tL%d: ancestor = %d, semi = %d, samedom = %d", i, ancestor[i], semi[i], samedom[i]); #endif // SHOW_SSA - for (int i = 1; i < N; ++i) { - BasicBlockIndex n = vertex[i]; + for (int i = 1; i < d->N; ++i) { + BasicBlockIndex n = d->vertex[i]; Q_ASSERT(n != InvalidBasicBlockIndex); Q_ASSERT(!bucket.contains(n)); - Q_ASSERT(ancestor[n] != InvalidBasicBlockIndex - && ((semi[n] != InvalidBasicBlockIndex - && dfnum[ancestor[n]] <= dfnum[semi[n]]) || semi[n] == n)); - BasicBlockIndex sdn = samedom[n]; + Q_ASSERT(d->ancestor[n] != InvalidBasicBlockIndex + && ((d->semi[n] != InvalidBasicBlockIndex + && d->dfnum[d->ancestor[n]] <= d->dfnum[d->semi[n]]) || d->semi[n] == n)); + BasicBlockIndex sdn = d->samedom[n]; if (sdn != InvalidBasicBlockIndex) idom[n] = idom[sdn]; } -#if defined(SHOW_SSA) - qout << "Immediate dominators:" << endl; - foreach (BasicBlock *to, nodes) { - qout << '\t'; - BasicBlockIndex from = idom.at(to->index); - if (from != InvalidBasicBlockIndex) - qout << from; - else - qout << "(none)"; - qout << " -> " << to->index << endl; - } - qout << "N = " << N << endl; -#endif // SHOW_SSA + dumpImmediateDominators(); } struct NodeProgress { @@ -553,7 +450,18 @@ class DominatorTree { std::vector<BasicBlockIndex> todo; }; +public: + DominatorTree(IR::Function *function) + : function(function) + , d(new Data) + { + calculateIDoms(); + d.reset(); + } + void computeDF() { + DF.resize(function->basicBlockCount()); + // compute children of each node in the dominator tree std::vector<std::vector<BasicBlockIndex> > children; // BasicBlock index -> children children.resize(function->basicBlockCount()); @@ -569,10 +477,10 @@ class DominatorTree { } // Fill the worklist and initialize the node status for each basic-block - QHash<BasicBlockIndex, NodeProgress> nodeStatus; - nodeStatus.reserve(function->basicBlockCount()); + std::vector<NodeProgress> nodeStatus; + nodeStatus.resize(function->basicBlockCount()); std::vector<BasicBlockIndex> worklist; - worklist.reserve(function->basicBlockCount() * 2); + worklist.reserve(function->basicBlockCount()); foreach (BasicBlock *bb, function->basicBlocks()) { if (bb->isRemoved()) continue; @@ -624,19 +532,23 @@ class DominatorTree { } } -#if defined(SHOW_SSA) - qout << "Dominator Frontiers:" << endl; - foreach (BasicBlock *n, nodes) { - qout << "\tDF[" << n->index << "]: {"; - QList<BasicBlock *> SList = DF[n->index].values(); - for (int i = 0; i < SList.size(); ++i) { - if (i > 0) - qout << ", "; - qout << SList[i]->index; + if (DebugDominatorFrontiers) { + qout << "Dominator Frontiers:" << endl; + foreach (BasicBlock *n, function->basicBlocks()) { + if (n->isRemoved()) + continue; + + qout << "\tDF[" << n->index() << "]: {"; + const BasicBlockSet &SList = DF[n->index()]; + for (BasicBlockSet::const_iterator i = SList.begin(), ei = SList.end(); i != ei; ++i) { + if (i != SList.begin()) + qout << ", "; + qout << (*i)->index(); + } + qout << "}" << endl; } - qout << "}" << endl; } -#endif // SHOW_SSA + #if !defined(QT_NO_DEBUG) && defined(CAN_TAKE_LOSTS_OF_TIME) foreach (BasicBlock *n, nodes) { const BasicBlockSet &fBlocks = DF[n->index]; @@ -659,37 +571,40 @@ class DominatorTree { #endif // !QT_NO_DEBUG } -public: - DominatorTree(IR::Function *function) - : function(function) - , N(0) - { - DF.resize(function->basicBlockCount()); - calculateIDoms(); - computeDF(); - } - const BasicBlockSet &dominatorFrontier(BasicBlock *n) const { return DF[n->index()]; } BasicBlock *immediateDominator(BasicBlock *bb) const { - return function->basicBlock(idom[bb->index()]); + const BasicBlockIndex idx = idom[bb->index()]; + if (idx == -1) + return 0; + return function->basicBlock(idx); } void dumpImmediateDominators() const { - qDebug() << "Immediate dominators for" << idom.size() << "nodes:"; - for (size_t i = 0, ei = idom.size(); i != ei; ++i) - if (idom[i] == InvalidBasicBlockIndex) - qDebug("\tnone -> L%d", int(i)); - else - qDebug("\tL%d -> L%d", idom[i], int(i)); + if (DebugImmediateDominators) { + qout << "Immediate dominators:" << endl; + foreach (BasicBlock *to, function->basicBlocks()) { + if (to->isRemoved()) + continue; + + qout << '\t'; + BasicBlockIndex from = idom.at(to->index()); + if (from != InvalidBasicBlockIndex) + qout << from; + else + qout << "(none)"; + qout << " -> " << to->index() << endl; + } + } } void updateImmediateDominator(BasicBlock *bb, BasicBlock *newDominator) { Q_ASSERT(bb->index() >= 0); + Q_ASSERT(!newDominator || newDominator->index() >= 0); if (static_cast<std::vector<BasicBlockIndex>::size_type>(bb->index()) >= idom.size()) { // This is a new block, probably introduced by edge splitting. So, we'll have to grow @@ -697,13 +612,60 @@ public: idom.resize(function->basicBlockCount(), InvalidBasicBlockIndex); } - idom[bb->index()] = newDominator->index(); + idom[bb->index()] = newDominator ? newDominator->index() : 0; } bool dominates(BasicBlock *dominator, BasicBlock *dominated) const { return dominates(dominator->index(), dominated->index()); } + // Calculate a depth-first iteration order on the nodes of the dominator tree. + // + // The order of the nodes in the vector is not the same as one where a recursive depth-first + // iteration is done on a tree. Rather, the nodes are (reverse) sorted on tree depth. + // So for the: + // 1 dominates 2 + // 2 dominates 3 + // 3 dominates 4 + // 2 dominates 5 + // the order will be: + // 4, 3, 5, 2, 1 + // or: + // 4, 5, 3, 2, 1 + // So the order of nodes on the same depth is undefined, but it will be after the nodes + // they dominate, and before the nodes that dominate them. + // + // The reason for this order is that a proper DFS pre-/post-order would require inverting + // the idom vector by either building a real tree datastructure or by searching the idoms + // for siblings and children. Both have a higher time complexity than sorting by depth. + QVector<BasicBlock *> calculateDFNodeIterOrder() const + { + std::vector<int> depths = calculateNodeDepths(); + struct Cmp { + std::vector<int> *nodeDepths; + Cmp(std::vector<int> *nodeDepths) + : nodeDepths(nodeDepths) + { Q_ASSERT(nodeDepths); } + bool operator()(BasicBlock *one, BasicBlock *two) const + { + if (one->isRemoved()) + return false; + if (two->isRemoved()) + return true; + return nodeDepths->at(one->index()) > nodeDepths->at(two->index()); + } + }; + QVector<BasicBlock *> order = function->basicBlocks(); + std::sort(order.begin(), order.end(), Cmp(&depths)); + for (int i = 0; i < order.size(); ) { + if (order[i]->isRemoved()) + order.remove(i); + else + ++i; + } + return order; + } + private: bool dominates(BasicBlockIndex dominator, BasicBlockIndex dominated) const { // dominator can be Invalid when the dominated block has no dominator (i.e. the start node) @@ -719,28 +681,95 @@ private: return false; } + + // Algorithm: + // - for each node: + // - get the depth of a node. If it's unknown (-1): + // - get the depth of the immediate dominator. + // - if that's unknown too, calculate it by calling calculateNodeDepth + // - set the current node's depth to that of immediate dominator + 1 + std::vector<int> calculateNodeDepths() const + { + std::vector<int> nodeDepths(function->basicBlockCount(), -1); + nodeDepths[0] = 0; + foreach (BasicBlock *bb, function->basicBlocks()) { + if (bb->isRemoved()) + continue; + + int &bbDepth = nodeDepths[bb->index()]; + if (bbDepth == -1) { + const int immDom = idom[bb->index()]; + int immDomDepth = nodeDepths[immDom]; + if (immDomDepth == -1) + immDomDepth = calculateNodeDepth(immDom, nodeDepths); + bbDepth = immDomDepth + 1; + } + } + return nodeDepths; + } + + // Algorithm: + // - search for the first dominator of a node that has a known depth. As all nodes are + // reachable from the start node, and that node's depth is 0, this is finite. + // - while doing that search, put all unknown nodes in the worklist + // - pop all nodes from the worklist, and set their depth to the previous' (== dominating) + // node's depth + 1 + // This way every node's depth is calculated once, and the complexity is O(n). + int calculateNodeDepth(int nodeIdx, std::vector<int> &nodeDepths) const + { + std::vector<int> worklist; + worklist.reserve(8); + int depth = -1; + + do { + worklist.push_back(nodeIdx); + nodeIdx = idom[nodeIdx]; + depth = nodeDepths[nodeIdx]; + } while (depth == -1); + + for (std::vector<int>::const_reverse_iterator it = worklist.rbegin(), eit = worklist.rend(); it != eit; ++it) + nodeDepths[*it] = ++depth; + + return depth; + } }; class VariableCollector: public StmtVisitor, ExprVisitor { - typedef QHash<Temp, QSet<BasicBlock *> > DefSites; - DefSites _defsites; - QVector<QSet<Temp> > A_orig; - QSet<Temp> nonLocals; - QSet<Temp> killed; + std::vector<Temp> _allTemps; + std::vector<BasicBlockSet> _defsites; + std::vector<std::vector<int> > A_orig; + std::vector<bool> nonLocals; + std::vector<bool> killed; BasicBlock *currentBB; - IR::Function *function; bool isCollectable(Temp *t) const { + Q_UNUSED(t); Q_ASSERT(t->kind != Temp::PhysicalRegister && t->kind != Temp::StackSlot); - return unescapableTemp(t, function); + return true; + } + + void addDefInCurrentBlock(Temp *t) + { + std::vector<int> &temps = A_orig[currentBB->index()]; + if (std::find(temps.begin(), temps.end(), t->index) == temps.end()) + temps.push_back(t->index); + } + + void addTemp(Temp *t) + { + if (_allTemps[t->index].kind == Temp::Invalid) + _allTemps[t->index] = *t; } public: VariableCollector(IR::Function *function) - : function(function) { - _defsites.reserve(function->tempCount); + _allTemps.resize(function->tempCount); + _defsites.resize(function->tempCount); + for (int i = 0; i < function->tempCount; ++i) + _defsites[i].init(function); + nonLocals.resize(function->tempCount); A_orig.resize(function->basicBlockCount()); for (int i = 0, ei = A_orig.size(); i != ei; ++i) A_orig[i].reserve(8); @@ -754,11 +783,9 @@ public: continue; currentBB = bb; - killed.clear(); - killed.reserve(bb->statements().size() / 2); - foreach (Stmt *s, bb->statements()) { + killed.assign(function->tempCount, false); + foreach (Stmt *s, bb->statements()) s->accept(this); - } } #if defined(SHOW_SSA) @@ -773,28 +800,36 @@ public: #endif // SHOW_SSA } - QList<Temp> vars() const { - return _defsites.keys(); - } + const std::vector<Temp> &allTemps() const + { return _allTemps; } - QSet<BasicBlock *> defsite(const Temp &n) const { - return _defsites[n]; + void collectDefSites(const Temp &n, std::vector<BasicBlock *> &bbs) const { + Q_ASSERT(!n.isInvalid()); + Q_ASSERT(n.index < _defsites.size()); + _defsites[n.index].collectValues(bbs); } - QSet<Temp> inBlock(BasicBlock *n) const { + const std::vector<int> &inBlock(BasicBlock *n) const + { return A_orig.at(n->index()); } - bool isNonLocal(const Temp &var) const { return nonLocals.contains(var); } + bool isNonLocal(const Temp &var) const + { + Q_ASSERT(!var.isInvalid()); + Q_ASSERT(var.index < nonLocals.size()); + return nonLocals[var.index]; + } protected: - virtual void visitPhi(Phi *) {}; - virtual void visitConvert(Convert *e) { e->expr->accept(this); }; + virtual void visitPhi(Phi *) {} + virtual void visitConvert(Convert *e) { e->expr->accept(this); } virtual void visitConst(Const *) {} virtual void visitString(IR::String *) {} virtual void visitRegExp(IR::RegExp *) {} virtual void visitName(Name *) {} + virtual void visitArgLocal(ArgLocal *) {} virtual void visitClosure(Closure *) {} virtual void visitUnop(Unop *e) { e->expr->accept(this); } virtual void visitBinop(Binop *e) { e->left->accept(this); e->right->accept(this); } @@ -821,6 +856,8 @@ protected: s->source->accept(this); if (Temp *t = s->target->asTemp()) { + addTemp(t); + if (isCollectable(t)) { #if defined(SHOW_SSA) qout << '\t'; @@ -828,18 +865,11 @@ protected: qout << " -> L" << currentBB->index << endl; #endif // SHOW_SSA - DefSites::iterator defsitesIt = _defsites.find(*t); - if (defsitesIt == _defsites.end()) { - QSet<BasicBlock *> bbs; - bbs.reserve(4); - defsitesIt = _defsites.insert(*t, bbs); - } - defsitesIt->insert(currentBB); - - A_orig[currentBB->index()].insert(*t); + _defsites[t->index].insert(currentBB); + addDefInCurrentBlock(t); // For semi-pruned SSA: - killed.insert(*t); + killed[t->index] = true; } } else { s->target->accept(this); @@ -848,9 +878,243 @@ protected: virtual void visitTemp(Temp *t) { + addTemp(t); + if (isCollectable(t)) - if (!killed.contains(*t)) - nonLocals.insert(*t); + if (!killed[t->index]) + nonLocals[t->index] = true; + } +}; + +struct UntypedTemp { + Temp temp; + UntypedTemp() {} + UntypedTemp(const Temp &t): temp(t) {} +}; +inline bool operator==(const UntypedTemp &t1, const UntypedTemp &t2) Q_DECL_NOTHROW +{ return t1.temp.index == t2.temp.index && t1.temp.kind == t2.temp.kind; } +inline bool operator!=(const UntypedTemp &t1, const UntypedTemp &t2) Q_DECL_NOTHROW +{ return !(t1 == t2); } + +class DefUses +{ +public: + struct DefUse { + DefUse() + : defStmt(0) + , blockOfStatement(0) + { uses.reserve(8); } + Temp temp; + Stmt *defStmt; + BasicBlock *blockOfStatement; + QVector<Stmt *> uses; + + bool isValid() const + { return temp.kind != Temp::Invalid; } + + void clear() + { defStmt = 0; blockOfStatement = 0; uses.clear(); } + }; + +private: + std::vector<DefUse> _defUses; + class Temps: public QVector<Temp> { + public: + Temps() { reserve(4); } + }; + std::vector<Temps> _usesPerStatement; + + void ensure(Temp *newTemp) + { + if (_defUses.size() <= newTemp->index) { + _defUses.reserve(newTemp->index + _defUses.size() / 3 + 1); + _defUses.resize(newTemp->index + 1); + } + } + + void ensure(Stmt *s) + { + Q_ASSERT(s->id() >= 0); + if (static_cast<unsigned>(s->id()) >= _usesPerStatement.size()) { + _usesPerStatement.reserve(s->id() + _usesPerStatement.size() / 3 + 1); + _usesPerStatement.resize(s->id() + 1); + } + } + + void addUseForStatement(Stmt *s, const Temp &var) + { + ensure(s); + _usesPerStatement[s->id()].push_back(var); + } + +public: + DefUses(IR::Function *function) + { + _usesPerStatement.resize(function->statementCount()); + _defUses.resize(function->tempCount); + } + + void cleanup() + { + for (size_t i = 0, ei = _defUses.size(); i != ei; ++i) { + DefUse &defUse = _defUses[i]; + if (defUse.isValid() && !defUse.defStmt) + defUse.clear(); + } + } + + unsigned statementCount() const + { return _usesPerStatement.size(); } + + unsigned tempCount() const + { return _defUses.size(); } + + const Temp &temp(int idx) const + { return _defUses[idx].temp; } + + void addDef(Temp *newTemp, Stmt *defStmt, BasicBlock *defBlock) + { + ensure(newTemp); + DefUse &defUse = _defUses[newTemp->index]; + Q_ASSERT(!defUse.isValid()); + defUse.temp = *newTemp; + defUse.defStmt = defStmt; + defUse.blockOfStatement = defBlock; + } + + QList<UntypedTemp> defsUntyped() const + { + QList<UntypedTemp> res; + foreach (const DefUse &du, _defUses) + if (du.isValid()) + res.append(UntypedTemp(du.temp)); + return res; + } + + std::vector<const Temp *> defs() const { + std::vector<const Temp *> res; + res.reserve(_defUses.size()); + for (unsigned i = 0, ei = _defUses.size(); i != ei; ++i) { + const DefUse &du = _defUses.at(i); + if (du.isValid()) + res.push_back(&du.temp); + } + return res; + } + + void removeDef(const Temp &variable) { + Q_ASSERT(static_cast<unsigned>(variable.index) < _defUses.size()); + _defUses[variable.index].clear(); + } + + void addUses(const Temp &variable, const QVector<Stmt *> &newUses) + { + Q_ASSERT(static_cast<unsigned>(variable.index) < _defUses.size()); + QVector<Stmt *> &uses = _defUses[variable.index].uses; + foreach (Stmt *stmt, newUses) + if (std::find(uses.begin(), uses.end(), stmt) == uses.end()) + uses.push_back(stmt); + } + + void addUse(const Temp &variable, Stmt *newUse) + { + if (_defUses.size() <= variable.index) { + _defUses.resize(variable.index + 1); + DefUse &du = _defUses[variable.index]; + du.temp = variable; + du.uses.push_back(newUse); + addUseForStatement(newUse, variable); + return; + } + + QVector<Stmt *> &uses = _defUses[variable.index].uses; + if (std::find(uses.begin(), uses.end(), newUse) == uses.end()) + uses.push_back(newUse); + addUseForStatement(newUse, variable); + } + + int useCount(const Temp &variable) const + { + Q_ASSERT(static_cast<unsigned>(variable.index) < _defUses.size()); + return _defUses[variable.index].uses.size(); + } + + Stmt *defStmt(const Temp &variable) const + { + Q_ASSERT(static_cast<unsigned>(variable.index) < _defUses.size()); + return _defUses[variable.index].defStmt; + } + + BasicBlock *defStmtBlock(const Temp &variable) const + { + Q_ASSERT(static_cast<unsigned>(variable.index) < _defUses.size()); + return _defUses[variable.index].blockOfStatement; + } + + void removeUse(Stmt *usingStmt, const Temp &var) + { + Q_ASSERT(static_cast<unsigned>(var.index) < _defUses.size()); + QVector<Stmt *> &uses = _defUses[var.index].uses; + uses.erase(std::remove(uses.begin(), uses.end(), usingStmt), uses.end()); + } + + void registerNewStatement(Stmt *s) + { + ensure(s); + } + + const QVector<Temp> &usedVars(Stmt *s) const + { + Q_ASSERT(s->id() >= 0); + Q_ASSERT(static_cast<unsigned>(s->id()) < _usesPerStatement.size()); + return _usesPerStatement[s->id()]; + } + + const QVector<Stmt *> &uses(const Temp &var) const + { + return _defUses[var.index].uses; + } + + QVector<Stmt*> removeDefUses(Stmt *s) + { + QVector<Stmt*> defStmts; + foreach (const Temp &usedVar, usedVars(s)) { + if (Stmt *ds = defStmt(usedVar)) + defStmts += ds; + removeUse(s, usedVar); + } + if (Move *m = s->asMove()) { + if (Temp *t = m->target->asTemp()) + removeDef(*t); + } else if (Phi *p = s->asPhi()) { + removeDef(*p->targetTemp); + } + + return defStmts; + } + + void dump() const + { + qout << "Defines and uses:" << endl; + foreach (const DefUse &du, _defUses) { + if (!du.isValid()) + continue; + qout << '%' << du.temp.index; + qout << " -> defined in block " << du.blockOfStatement->index() + << ", statement: " << du.defStmt->id() + << endl; + qout << " uses:"; + foreach (Stmt *s, du.uses) + qout << ' ' << s->id(); + qout << endl; + } + qout << "Uses per statement:" << endl; + for (unsigned i = 0, ei = _usesPerStatement.size(); i != ei; ++i) { + qout << " " << i << ":"; + foreach (const Temp &t, _usesPerStatement[i]) + qout << ' ' << t.index; + qout << endl; + } } }; @@ -861,16 +1125,16 @@ void insertPhiNode(const Temp &a, BasicBlock *y, IR::Function *f) { qout << " in block " << y->index << endl; #endif - Phi *phiNode = f->New<Phi>(); + Phi *phiNode = f->NewStmt<Phi>(); phiNode->d = new Stmt::Data; phiNode->targetTemp = f->New<Temp>(); - phiNode->targetTemp->init(a.kind, a.index, 0); + phiNode->targetTemp->init(a.kind, a.index); y->prependStatement(phiNode); phiNode->d->incoming.resize(y->in.size()); for (int i = 0, ei = y->in.size(); i < ei; ++i) { Temp *t = f->New<Temp>(); - t->init(a.kind, a.index, 0); + t->init(a.kind, a.index); phiNode->d->incoming[i] = t; } } @@ -945,23 +1209,22 @@ void insertPhiNode(const Temp &a, BasicBlock *y, IR::Function *f) { // mapping[t] = c class VariableRenamer: public StmtVisitor, public ExprVisitor { + Q_DISABLE_COPY(VariableRenamer) + IR::Function *function; + DefUses &defUses; unsigned tempCount; - typedef QHash<unsigned, int> Mapping; // maps from existing/old temp number to the new and unique temp number. + typedef std::vector<int> Mapping; // maps from existing/old temp number to the new and unique temp number. enum { Absent = -1 }; - Mapping localMapping; Mapping vregMapping; ProcessedBlocks processed; - bool isRenamable(Temp *t) const - { - Q_ASSERT(t->kind != Temp::PhysicalRegister && t->kind != Temp::StackSlot); - return unescapableTemp(t, function); - } + BasicBlock *currentBB; + Stmt *currentStmt; struct TodoAction { - enum { RestoreLocal, RestoreVReg, Rename } action; + enum { RestoreVReg, Rename } action; union { struct { unsigned temp; @@ -982,9 +1245,9 @@ class VariableRenamer: public StmtVisitor, public ExprVisitor TodoAction(const Temp &t, int prev) { - Q_ASSERT(t.kind == Temp::Local || t.kind == Temp::VirtualRegister); + Q_ASSERT(t.kind == Temp::VirtualRegister); - action = t.kind == Temp::Local ? RestoreLocal : RestoreVReg; + action = RestoreVReg; restoreData.temp = t.index; restoreData.previous = prev; } @@ -1001,13 +1264,13 @@ class VariableRenamer: public StmtVisitor, public ExprVisitor QVector<TodoAction> todo; public: - VariableRenamer(IR::Function *f) + VariableRenamer(IR::Function *f, DefUses &defUses) : function(f) + , defUses(defUses) , tempCount(0) , processed(f) { - localMapping.reserve(f->tempCount); - vregMapping.reserve(f->tempCount); + vregMapping.assign(f->tempCount, Absent); todo.reserve(f->basicBlockCount()); } @@ -1023,9 +1286,6 @@ public: case TodoAction::Rename: rename(todoAction.renameData.basicBlock); break; - case TodoAction::RestoreLocal: - restore(localMapping, todoAction.restoreData.temp, todoAction.restoreData.previous); - break; case TodoAction::RestoreVReg: restore(vregMapping, todoAction.restoreData.temp, todoAction.restoreData.previous); break; @@ -1038,12 +1298,9 @@ public: } private: - static inline void restore(Mapping &mapping, unsigned temp, int previous) + static inline void restore(Mapping &mapping, int temp, int previous) { - if (previous == Absent) - mapping.remove(temp); - else - mapping[temp] = previous; + mapping[temp] = previous; } void rename(BasicBlock *bb) @@ -1067,8 +1324,12 @@ private: void renameStatementsAndPhis(BasicBlock *bb) { - foreach (Stmt *s, bb->statements()) + currentBB = bb; + + foreach (Stmt *s, bb->statements()) { + currentStmt = s; s->accept(this); + } foreach (BasicBlock *Y, bb->out) { const int j = Y->in.indexOf(bb); @@ -1080,6 +1341,7 @@ private: // qDebug()<<"I: replacing phi use"<<a<<"with"<<newTmp<<"in L"<<Y->index; t->index = newTmp; t->kind = Temp::VirtualRegister; + defUses.addUse(*t, phi); } else { break; } @@ -1091,11 +1353,8 @@ private: { int nr = Absent; switch (t.kind) { - case Temp::Local: - nr = localMapping.value(t.index, Absent); - break; case Temp::VirtualRegister: - nr = vregMapping.value(t.index, Absent); + nr = vregMapping[t.index]; break; default: Q_UNREACHABLE(); @@ -1122,13 +1381,9 @@ private: int oldIndex = Absent; switch (t.kind) { - case Temp::Local: - oldIndex = localMapping.value(t.index, Absent); - localMapping.insert(t.index, newIndex); - break; case Temp::VirtualRegister: - oldIndex = vregMapping.value(t.index, Absent); - vregMapping.insert(t.index, newIndex); + oldIndex = vregMapping[t.index]; + vregMapping[t.index] = newIndex; break; default: Q_UNREACHABLE(); @@ -1141,11 +1396,10 @@ private: protected: virtual void visitTemp(Temp *e) { // only called for uses, not defs - if (isRenamable(e)) { -// qDebug()<<"I: replacing use of"<<e->index<<"with"<<stack[e->index].top(); - e->index = currentNumber(*e); - e->kind = Temp::VirtualRegister; - } +// qDebug()<<"I: replacing use of"<<e->index<<"with"<<stack[e->index].top(); + e->index = currentNumber(*e); + e->kind = Temp::VirtualRegister; + defUses.addUse(*e, currentStmt); } virtual void visitMove(Move *s) { @@ -1159,13 +1413,12 @@ protected: s->target->accept(this); } - void renameTemp(Temp *t) { - if (isRenamable(t)) { - const int newIdx = nextFreeTemp(*t); -// qDebug()<<"I: replacing def of"<<a<<"with"<<newIdx; - t->kind = Temp::VirtualRegister; - t->index = newIdx; - } + void renameTemp(Temp *t) { // only called for defs, not uses + const int newIdx = nextFreeTemp(*t); +// qDebug()<<"I: replacing def of"<<a<<"with"<<newIdx; + t->kind = Temp::VirtualRegister; + t->index = newIdx; + defUses.addDef(t, currentStmt, currentBB); } virtual void visitConvert(Convert *e) { e->expr->accept(this); } @@ -1181,6 +1434,7 @@ protected: virtual void visitString(IR::String *) {} virtual void visitRegExp(IR::RegExp *) {} virtual void visitName(Name *) {} + virtual void visitArgLocal(ArgLocal *) {} virtual void visitClosure(Closure *) {} virtual void visitUnop(Unop *e) { e->expr->accept(this); } virtual void visitBinop(Binop *e) { e->left->accept(this); e->right->accept(this); } @@ -1206,7 +1460,9 @@ protected: } }; -void convertToSSA(IR::Function *function, const DominatorTree &df) +// This function converts the IR to semi-pruned SSA form. For details about SSA and the algorightm, +// see [Appel]. For the changes needed for semi-pruned SSA form, and for its advantages, see [Briggs]. +void convertToSSA(IR::Function *function, const DominatorTree &df, DefUses &defUses) { #if defined(SHOW_SSA) qout << "Converting function "; @@ -1221,376 +1477,214 @@ void convertToSSA(IR::Function *function, const DominatorTree &df) VariableCollector variables(function); // Prepare for phi node insertion: - QVector<QSet<Temp> > A_phi; + std::vector<std::vector<bool> > A_phi; A_phi.resize(function->basicBlockCount()); - for (int i = 0, ei = A_phi.size(); i != ei; ++i) { - QSet<Temp> temps; - temps.reserve(4); - A_phi[i] = temps; - } + for (int i = 0, ei = A_phi.size(); i != ei; ++i) + A_phi[i].assign(function->tempCount, false); + + std::vector<BasicBlock *> W; + W.reserve(8); // Place phi functions: - foreach (Temp a, variables.vars()) { + foreach (const Temp &a, variables.allTemps()) { + if (a.isInvalid()) + continue; if (!variables.isNonLocal(a)) continue; // for semi-pruned SSA - QList<BasicBlock *> W = QList<BasicBlock *>::fromSet(variables.defsite(a)); - while (!W.isEmpty()) { - BasicBlock *n = W.first(); - W.removeFirst(); + W.clear(); + variables.collectDefSites(a, W); + while (!W.empty()) { + BasicBlock *n = W.back(); + W.pop_back(); const BasicBlockSet &dominatorFrontierForN = df.dominatorFrontier(n); for (BasicBlockSet::const_iterator it = dominatorFrontierForN.begin(), eit = dominatorFrontierForN.end(); it != eit; ++it) { BasicBlock *y = *it; - if (!A_phi.at(y->index()).contains(a)) { + if (!A_phi.at(y->index()).at(a.index)) { insertPhiNode(a, y, function); - A_phi[y->index()].insert(a); - if (!variables.inBlock(y).contains(a)) - W.append(y); + A_phi[y->index()].at(a.index) = true; + const std::vector<int> &varsInBlockY = variables.inBlock(y); + if (std::find(varsInBlockY.begin(), varsInBlockY.end(), a.index) == varsInBlockY.end()) + W.push_back(y); } } } } // Rename variables: - VariableRenamer(function).run(); + VariableRenamer(function, defUses).run(); } -struct UntypedTemp { - Temp temp; - UntypedTemp() {} - UntypedTemp(const Temp &t): temp(t) {} -}; -inline uint qHash(const UntypedTemp &t, uint seed = 0) Q_DECL_NOTHROW -{ return t.temp.index ^ (t.temp.kind | (t.temp.scope << 3)) ^ seed; } -inline bool operator==(const UntypedTemp &t1, const UntypedTemp &t2) Q_DECL_NOTHROW -{ return t1.temp.index == t2.temp.index && t1.temp.scope == t2.temp.scope && t1.temp.kind == t2.temp.kind; } -inline bool operator!=(const UntypedTemp &t1, const UntypedTemp &t2) Q_DECL_NOTHROW -{ return !(t1 == t2); } - -class DefUsesCalculator: public StmtVisitor, public ExprVisitor { -public: - struct DefUse { - DefUse() - : defStmt(0) - , blockOfStatement(0) - {} - Stmt *defStmt; - BasicBlock *blockOfStatement; - QList<Stmt *> uses; - }; - -private: - IR::Function *function; - typedef QHash<UntypedTemp, DefUse> DefUses; - DefUses _defUses; - QHash<Stmt *, QList<Temp> > _usesPerStatement; - - BasicBlock *_block; - Stmt *_stmt; - - bool isCollectible(Temp *t) const { - Q_ASSERT(t->kind != Temp::PhysicalRegister && t->kind != Temp::StackSlot); - return unescapableTemp(t, function); - } - - void addUse(Temp *t) { - Q_ASSERT(t); - if (!isCollectible(t)) - return; - - _defUses[*t].uses.append(_stmt); - _usesPerStatement[_stmt].append(*t); - } - - void addDef(Temp *t) { - if (!isCollectible(t)) - return; - - Q_ASSERT(!_defUses.contains(*t) || _defUses.value(*t).defStmt == 0 || _defUses.value(*t).defStmt == _stmt); - - DefUse &defUse = _defUses[*t]; - defUse.defStmt = _stmt; - defUse.blockOfStatement = _block; - } - -public: - DefUsesCalculator(IR::Function *function) - : function(function) - { - foreach (BasicBlock *bb, function->basicBlocks()) { - if (bb->isRemoved()) - continue; - - _block = bb; - foreach (Stmt *stmt, bb->statements()) { - _stmt = stmt; - stmt->accept(this); - } - } - - QMutableHashIterator<UntypedTemp, DefUse> it(_defUses); - while (it.hasNext()) { - it.next(); - if (!it.value().defStmt) - it.remove(); - } - } - - void addTemp(Temp *newTemp, Stmt *defStmt, BasicBlock *defBlock) - { - DefUse &defUse = _defUses[*newTemp]; - defUse.defStmt = defStmt; - defUse.blockOfStatement = defBlock; - } - - QList<UntypedTemp> defsUntyped() const { return _defUses.keys(); } - - QList<Temp> defs() const { - QList<Temp> res; - res.reserve(_defUses.size()); - foreach (const UntypedTemp &t, _defUses.keys()) - res.append(t.temp); - return res; - } - - void removeDef(const Temp &var) { - _defUses.remove(var); - } - - void addUses(const Temp &variable, const QList<Stmt *> &newUses) - { _defUses[variable].uses.append(newUses); } - - void addUse(const Temp &variable, Stmt * newUse) - { _defUses[variable].uses.append(newUse); } - - int useCount(const UntypedTemp &variable) const - { return _defUses[variable].uses.size(); } - - Stmt *defStmt(const UntypedTemp &variable) const - { return _defUses[variable].defStmt; } - - BasicBlock *defStmtBlock(const Temp &variable) const - { return _defUses[variable].blockOfStatement; } - - void removeUse(Stmt *usingStmt, const Temp &var) - { _defUses[var].uses.removeAll(usingStmt); } - - QList<Temp> usedVars(Stmt *s) const - { return _usesPerStatement[s]; } - - const QList<Stmt *> &uses(const UntypedTemp &var) const - { - static const QList<Stmt *> noUses; - - DefUses::const_iterator it = _defUses.find(var); - if (it == _defUses.end()) - return noUses; - else - return it->uses; - } - - QVector<Stmt*> removeDefUses(Stmt *s) - { - QVector<Stmt*> defStmts; - foreach (const Temp &usedVar, usedVars(s)) { - if (Stmt *ds = defStmt(usedVar)) - defStmts += ds; - removeUse(s, usedVar); - } - if (Move *m = s->asMove()) { - if (Temp *t = m->target->asTemp()) - removeDef(*t); - } else if (Phi *p = s->asPhi()) { - removeDef(*p->targetTemp); - } - - return defStmts; - } - - void dump() const - { - foreach (const UntypedTemp &var, _defUses.keys()) { - const DefUse &du = _defUses[var]; - var.temp.dump(qout); - qout<<" -> defined in block "<<du.blockOfStatement->index()<<", statement: "; - du.defStmt->dump(qout); - qout<<endl<<" uses:"<<endl; - foreach (Stmt *s, du.uses) { - qout<<" ";s->dump(qout);qout<<endl; - } - } - } - -protected: - virtual void visitExp(Exp *s) { s->expr->accept(this); } - virtual void visitJump(Jump *) {} - virtual void visitCJump(CJump *s) { s->cond->accept(this); } - virtual void visitRet(Ret *s) { s->expr->accept(this); } - - virtual void visitPhi(Phi *s) { - addDef(s->targetTemp); - foreach (Expr *e, s->d->incoming) - addUse(e->asTemp()); - } - - virtual void visitMove(Move *s) { - if (Temp *t = s->target->asTemp()) - addDef(t); - else - s->target->accept(this); - - s->source->accept(this); - } - - virtual void visitTemp(Temp *e) { addUse(e); } +/// Calculate if a phi node result is used only by other phi nodes, and if those uses are +/// in turn also used by other phi nodes. +bool hasPhiOnlyUses(Phi *phi, const DefUses &defUses, QBitArray &collectedPhis) +{ + collectedPhis.setBit(phi->id()); - virtual void visitConst(Const *) {} - virtual void visitString(IR::String *) {} - virtual void visitRegExp(IR::RegExp *) {} - virtual void visitName(Name *) {} - virtual void visitClosure(Closure *) {} - virtual void visitConvert(Convert *e) { e->expr->accept(this); } - virtual void visitUnop(Unop *e) { e->expr->accept(this); } - virtual void visitBinop(Binop *e) { e->left->accept(this); e->right->accept(this); } - virtual void visitSubscript(Subscript *e) { e->base->accept(this); e->index->accept(this); } - virtual void visitMember(Member *e) { e->base->accept(this); } - virtual void visitCall(Call *e) { - e->base->accept(this); - for (ExprList *it = e->args; it; it = it->next) - it->expr->accept(this); - } + foreach (Stmt *use, defUses.uses(*phi->targetTemp)) { + Phi *dependentPhi = use->asPhi(); + if (!dependentPhi) + return false; // there is a use by a non-phi node - virtual void visitNew(New *e) { - e->base->accept(this); - for (ExprList *it = e->args; it; it = it->next) - it->expr->accept(this); - } -}; + if (collectedPhis.at(dependentPhi->id())) + continue; // we already found this node -bool hasPhiOnlyUses(Phi *phi, const DefUsesCalculator &defUses, QSet<Phi *> &collectedPhis) -{ - collectedPhis.insert(phi); - foreach (Stmt *use, defUses.uses(*phi->targetTemp)) { - if (Phi *dependentPhi = use->asPhi()) { - if (!collectedPhis.contains(dependentPhi)) { - if (!hasPhiOnlyUses(dependentPhi, defUses, collectedPhis)) - return false; - } - } else { + if (!hasPhiOnlyUses(dependentPhi, defUses, collectedPhis)) return false; - } } + return true; } -void cleanupPhis(DefUsesCalculator &defUses) +void cleanupPhis(DefUses &defUses) { - QLinkedList<Phi *> phis; - foreach (const Temp &def, defUses.defs()) - if (Phi *phi = defUses.defStmt(def)->asPhi()) - phis.append(phi); - - QSet<Phi *> toRemove; - while (!phis.isEmpty()) { - Phi *phi = phis.first(); - phis.removeFirst(); - if (toRemove.contains(phi)) + QBitArray toRemove(defUses.statementCount()); + QBitArray collectedPhis(defUses.statementCount()); + std::vector<Phi *> allPhis; + allPhis.reserve(32); + + foreach (const Temp *def, defUses.defs()) { + Stmt *defStmt = defUses.defStmt(*def); + if (!defStmt) + continue; + + Phi *phi = defStmt->asPhi(); + if (!phi) + continue; + allPhis.push_back(phi); + if (toRemove.at(phi->id())) continue; - QSet<Phi *> collectedPhis; + + collectedPhis.fill(false); if (hasPhiOnlyUses(phi, defUses, collectedPhis)) - toRemove.unite(collectedPhis); + toRemove |= collectedPhis; } - foreach (Phi *phi, toRemove) { - Temp targetVar = *phi->targetTemp; + foreach (Phi *phi, allPhis) { + if (!toRemove.at(phi->id())) + continue; + const Temp &targetVar = *phi->targetTemp; defUses.defStmtBlock(targetVar)->removeStatement(phi); foreach (const Temp &usedVar, defUses.usedVars(phi)) defUses.removeUse(phi, usedVar); defUses.removeDef(targetVar); } + + defUses.cleanup(); } class StatementWorklist { - QVector<Stmt *> worklist; - QBitArray inWorklist; - QSet<Stmt *> removed; - QHash<Stmt*,Stmt*> replaced; + IR::Function *theFunction; + std::vector<Stmt *> stmts; + std::vector<bool> worklist; + unsigned worklistSize; + std::vector<int> replaced; + std::vector<bool> removed; Q_DISABLE_COPY(StatementWorklist) public: StatementWorklist(IR::Function *function) + : theFunction(function) + , stmts(function->statementCount(), 0) + , worklist(function->statementCount(), false) + , worklistSize(0) + , replaced(function->statementCount(), Stmt::InvalidId) + , removed(function->statementCount()) { - QVector<Stmt *> w; - int stmtCount = 0; + grow(); - // Put in all statements, and number them on the fly. The numbering is used to index the - // bit array. foreach (BasicBlock *bb, function->basicBlocks()) { if (bb->isRemoved()) continue; foreach (Stmt *s, bb->statements()) { - s->id = stmtCount++; - w.append(s); + if (!s) + continue; + + stmts[s->id()] = s; + worklist[s->id()] = true; + ++worklistSize; } } + } - // For QVector efficiency reasons, we process statements from the back. However, it is more - // effective to process the statements in ascending order. So we need to invert the - // order. - worklist.reserve(w.size()); - for (int i = w.size() - 1; i >= 0; --i) - worklist.append(w.at(i)); + void reset() + { + foreach (Stmt *s, stmts) { + if (!s) + continue; - inWorklist = QBitArray(stmtCount, true); + worklist[s->id()] = true; + ++worklistSize; + } + + replaced.assign(replaced.size(), Stmt::InvalidId); + removed.assign(removed.size(), false); } - // This will clear the entry for the statement in the basic block. After processing all - // statements, the cleanup method needs to be run to remove all null-pointers. - void clear(Stmt *stmt) + void remove(Stmt *stmt) { - Q_ASSERT(!inWorklist.at(stmt->id)); - removed.insert(stmt); + replaced[stmt->id()] = Stmt::InvalidId; + removed[stmt->id()] = true; + std::vector<bool>::reference inWorklist = worklist[stmt->id()]; + if (inWorklist) { + inWorklist = false; + Q_ASSERT(worklistSize > 0); + --worklistSize; + } } void replace(Stmt *oldStmt, Stmt *newStmt) { Q_ASSERT(oldStmt); + Q_ASSERT(replaced[oldStmt->id()] == Stmt::InvalidId); + Q_ASSERT(removed[oldStmt->id()] == false); + Q_ASSERT(newStmt); - Q_ASSERT(!removed.contains(oldStmt)); + registerNewStatement(newStmt); + Q_ASSERT(replaced[newStmt->id()] == Stmt::InvalidId); + Q_ASSERT(removed[newStmt->id()] == false); - if (newStmt->id == -1) - newStmt->id = oldStmt->id; - QHash<Stmt *, Stmt *>::const_iterator it = replaced.find(oldStmt); - if (it != replaced.end()) - oldStmt = it.key(); - replaced[oldStmt] = newStmt; + replaced[oldStmt->id()] = newStmt->id(); + worklist[oldStmt->id()] = false; } - void cleanup(IR::Function *function) + void applyToFunction() { - foreach (BasicBlock *bb, function->basicBlocks()) { + foreach (BasicBlock *bb, theFunction->basicBlocks()) { if (bb->isRemoved()) continue; for (int i = 0; i < bb->statementCount();) { - Stmt *stmt = bb->statements()[i]; - QHash<Stmt *, Stmt *>::const_iterator it = replaced.find(stmt); - if (it != replaced.end() && !removed.contains(it.value())) { - bb->replaceStatement(i, it.value()); - } else if (removed.contains(stmt)) { + Stmt *stmt = bb->statements().at(i); + + int id = stmt->id(); + Q_ASSERT(id != Stmt::InvalidId); + Q_ASSERT(static_cast<unsigned>(stmt->id()) < stmts.size()); + + for (int replacementId = replaced[id]; replacementId != Stmt::InvalidId; replacementId = replaced[replacementId]) + id = replacementId; + Q_ASSERT(id != Stmt::InvalidId); + Q_ASSERT(static_cast<unsigned>(stmt->id()) < stmts.size()); + + if (removed[id]) { bb->removeStatement(i); - continue; - } + } else { + if (id != stmt->id()) + bb->replaceStatement(i, stmts[id]); - ++i; + ++i; + } } } + + replaced.assign(replaced.size(), Stmt::InvalidId); + removed.assign(removed.size(), false); } StatementWorklist &operator+=(const QVector<Stmt *> &stmts) @@ -1601,18 +1695,17 @@ public: return *this; } - StatementWorklist &operator+=(Stmt *s) { if (!s) return *this; - Q_ASSERT(s->id >= 0); - Q_ASSERT(s->id < inWorklist.size()); + Q_ASSERT(s->id() >= 0); + Q_ASSERT(static_cast<unsigned>(s->id()) < worklist.size()); - if (!inWorklist.at(s->id)) { - worklist.append(s); - inWorklist.setBit(s->id); + if (!worklist[s->id()]) { + worklist[s->id()] = true; + ++worklistSize; } return *this; @@ -1620,12 +1713,14 @@ public: StatementWorklist &operator-=(Stmt *s) { - Q_ASSERT(s->id >= 0); - Q_ASSERT(s->id < inWorklist.size()); - - if (inWorklist.at(s->id)) { - worklist.remove(worklist.indexOf(s)); - inWorklist.clearBit(s->id); + Q_ASSERT(s->id() >= 0); + Q_ASSERT(static_cast<unsigned>(s->id()) < worklist.size()); + + std::vector<bool>::reference inWorklist = worklist[s->id()]; + if (inWorklist) { + inWorklist = false; + Q_ASSERT(worklistSize > 0); + --worklistSize; } return *this; @@ -1633,34 +1728,78 @@ public: bool isEmpty() const { - return worklist.isEmpty(); + return worklistSize == 0; } - Stmt *takeOne() + Stmt *takeNext(Stmt *last) { if (isEmpty()) return 0; - Stmt *s = worklist.last(); - Q_ASSERT(s->id < inWorklist.size()); - worklist.removeLast(); - inWorklist.clearBit(s->id); + const int startAt = last ? last->id() + 1 : 0; + Q_ASSERT(startAt >= 0); + Q_ASSERT(static_cast<unsigned>(startAt) <= worklist.size()); + + Q_ASSERT(worklist.size() == stmts.size()); + + // Do not compare the result of find with the end iterator, because some libc++ versions + // have a bug where the result of the ++operator is past-the-end of the vector, but unequal + // to end(). + size_t pos = std::find(worklist.begin() + startAt, worklist.end(), true) - worklist.begin(); + if (pos >= worklist.size()) + pos = std::find(worklist.begin(), worklist.begin() + startAt, true) - worklist.begin(); + + worklist[pos] = false; + Q_ASSERT(worklistSize > 0); + --worklistSize; + Stmt *s = stmts.at(pos); + Q_ASSERT(s); return s; } + + IR::Function *function() const + { + return theFunction; + } + + void registerNewStatement(Stmt *s) + { + Q_ASSERT(s->id() >= 0); + if (static_cast<unsigned>(s->id()) >= stmts.size()) { + if (static_cast<unsigned>(s->id()) >= stmts.capacity()) + grow(); + + int newSize = s->id() + 1; + stmts.resize(newSize, 0); + worklist.resize(newSize, false); + replaced.resize(newSize, Stmt::InvalidId); + removed.resize(newSize, false); + } + + stmts[s->id()] = s; + } + +private: + void grow() + { + size_t newCapacity = ((stmts.capacity() + 1) * 3) / 2; + stmts.reserve(newCapacity); + worklist.reserve(newCapacity); + replaced.reserve(newCapacity); + removed.reserve(newCapacity); + } }; class EliminateDeadCode: public ExprVisitor { - DefUsesCalculator &_defUses; + DefUses &_defUses; StatementWorklist &_worklist; - IR::Function *function; bool _sideEffect; QVector<Temp *> _collectedTemps; public: - EliminateDeadCode(DefUsesCalculator &defUses, StatementWorklist &worklist, IR::Function *function) + EliminateDeadCode(DefUses &defUses, StatementWorklist &worklist) : _defUses(defUses) , _worklist(worklist) - , function(function) { _collectedTemps.reserve(8); } @@ -1691,11 +1830,6 @@ private: _collectedTemps.clear(); } - bool isCollectable(Temp *t) const - { - return unescapableTemp(t, function); - } - protected: virtual void visitConst(Const *) {} virtual void visitString(IR::String *) {} @@ -1713,10 +1847,11 @@ protected: virtual void visitTemp(Temp *e) { - if (isCollectable(e)) - _collectedTemps.append(e); + _collectedTemps.append(e); } + virtual void visitArgLocal(ArgLocal *) {} + virtual void visitClosure(Closure *) { markAsSideEffect(); @@ -1814,12 +1949,12 @@ struct DiscoveredType { class PropagateTempTypes: public StmtVisitor, ExprVisitor { - const DefUsesCalculator &defUses; + const DefUses &defUses; UntypedTemp theTemp; DiscoveredType newType; public: - PropagateTempTypes(const DefUsesCalculator &defUses) + PropagateTempTypes(const DefUses &defUses) : defUses(defUses) {} @@ -1827,9 +1962,9 @@ public: { newType = type; theTemp = temp; - if (Stmt *defStmt = defUses.defStmt(temp)) + if (Stmt *defStmt = defUses.defStmt(temp.temp)) defStmt->accept(this); - foreach (Stmt *use, defUses.uses(temp)) + foreach (Stmt *use, defUses.uses(temp.temp)) use->accept(this); } @@ -1844,6 +1979,7 @@ protected: e->memberResolver = newType.memberResolver; } } + virtual void visitArgLocal(ArgLocal *) {} virtual void visitClosure(Closure *) {} virtual void visitConvert(Convert *e) { e->expr->accept(this); } virtual void visitUnop(Unop *e) { e->expr->accept(this); } @@ -1884,71 +2020,81 @@ protected: } }; -class TypeInference: public StmtVisitor, public ExprVisitor { +class TypeInference: public StmtVisitor, public ExprVisitor +{ + enum { DebugTypeInference = 0 }; + QQmlEnginePrivate *qmlEngine; - IR::Function *function; - const DefUsesCalculator &_defUses; - typedef QHash<Temp, DiscoveredType> TempTypes; + const DefUses &_defUses; + typedef std::vector<DiscoveredType> TempTypes; TempTypes _tempTypes; - QList<Stmt *> _worklist; + StatementWorklist *_worklist; struct TypingResult { DiscoveredType type; bool fullyTyped; - TypingResult(const DiscoveredType &type = DiscoveredType()) : type(type), fullyTyped(type.type != UnknownType) {} - explicit TypingResult(MemberExpressionResolver memberResolver): type(memberResolver), fullyTyped(true) {} + TypingResult(const DiscoveredType &type = DiscoveredType()) + : type(type) + , fullyTyped(type.type != UnknownType) + {} + explicit TypingResult(MemberExpressionResolver memberResolver) + : type(memberResolver) + , fullyTyped(true) + {} }; TypingResult _ty; public: - TypeInference(QQmlEnginePrivate *qmlEngine, const DefUsesCalculator &defUses) + TypeInference(QQmlEnginePrivate *qmlEngine, const DefUses &defUses) : qmlEngine(qmlEngine) , _defUses(defUses) + , _tempTypes(_defUses.tempCount()) + , _worklist(0) , _ty(UnknownType) {} - void run(IR::Function *f) { - function = f; + void run(StatementWorklist &w) { + _worklist = &w; - // TODO: the worklist handling looks a bit inefficient... check if there is something better - _worklist.clear(); - for (int i = 0, ei = function->basicBlockCount(); i != ei; ++i) { - BasicBlock *bb = function->basicBlock(i); - if (bb->isRemoved()) + Stmt *s = 0; + while ((s = _worklist->takeNext(s))) { + if (s->asJump()) continue; - if (i == 0 || !bb->in.isEmpty()) - _worklist += bb->statements().toList(); - } - - while (!_worklist.isEmpty()) { - QList<Stmt *> worklist = QSet<Stmt *>::fromList(_worklist).toList(); - _worklist.clear(); - while (!worklist.isEmpty()) { - Stmt *s = worklist.first(); - worklist.removeFirst(); - if (s->asJump()) - continue; -#if defined(SHOW_SSA) - qout<<"Typing stmt ";s->dump(qout);qout<<endl; -#endif + if (DebugTypeInference) { + qout<<"Typing stmt "; + IRPrinter(&qout).print(s); + qout<<endl; + } - if (!run(s)) { - _worklist += s; -#if defined(SHOW_SSA) + if (!run(s)) { + *_worklist += s; + if (DebugTypeInference) { qout<<"Pushing back stmt: "; - s->dump(qout);qout<<endl; - } else { + IRPrinter(&qout).print(s); + qout<<endl; + } + } else { + if (DebugTypeInference) { qout<<"Finished: "; - s->dump(qout);qout<<endl; -#endif + IRPrinter(&qout).print(s); + qout<<endl; } } } PropagateTempTypes propagator(_defUses); - for (QHash<Temp, DiscoveredType>::const_iterator i = _tempTypes.begin(), ei = _tempTypes.end(); i != ei; ++i) - propagator.run(i.key(), i.value()); + for (unsigned i = 0, ei = _tempTypes.size(); i != ei; ++i) { + const Temp &temp = _defUses.temp(i); + if (temp.kind == Temp::Invalid) + continue; + const DiscoveredType &tempType = _tempTypes[i]; + if (tempType.type == UnknownType) + continue; + propagator.run(temp, tempType); + } + + _worklist = 0; } private: @@ -1971,35 +2117,26 @@ private: return ty; } - bool isAlwaysVar(Temp *t) { - if (unescapableTemp(t, function)) - return false; - t->type = VarType; - return true; - } - void setType(Expr *e, DiscoveredType ty) { if (Temp *t = e->asTemp()) { -#if defined(SHOW_SSA) - qout<<"Setting type for "<< (t->scope?"scoped temp ":"temp ") <<t->index<< " to "<<typeName(Type(ty)) << " (" << ty << ")" << endl; -#endif - if (isAlwaysVar(t)) - ty = DiscoveredType(VarType); - TempTypes::iterator it = _tempTypes.find(*t); - if (it == _tempTypes.end()) - it = _tempTypes.insert(*t, DiscoveredType()); - if (it.value() != ty) { - it.value() = ty; - -#if defined(SHOW_SSA) - foreach (Stmt *s, _defUses.uses(*t)) { - qout << "Pushing back dependent stmt: "; - s->dump(qout); - qout << endl; + if (DebugTypeInference) + qout << "Setting type for temp " << t->index + << " to " << typeName(Type(ty.type)) << " (" << ty.type << ")" + << endl; + + DiscoveredType &it = _tempTypes[t->index]; + if (it != ty) { + it = ty; + + if (DebugTypeInference) { + foreach (Stmt *s, _defUses.uses(*t)) { + qout << "Pushing back dependent stmt: "; + IRPrinter(&qout).print(s); + qout<<endl; + } } -#endif - _worklist += _defUses.uses(*t); + *_worklist += _defUses.uses(*t); } } else { e->type = (Type) ty.type; @@ -2022,14 +2159,17 @@ protected: virtual void visitRegExp(IR::RegExp *) { _ty = TypingResult(VarType); } virtual void visitName(Name *) { _ty = TypingResult(VarType); } virtual void visitTemp(Temp *e) { - if (isAlwaysVar(e)) - _ty = TypingResult(VarType); - else if (e->memberResolver.isValid()) + if (e->memberResolver.isValid()) _ty = TypingResult(e->memberResolver); else - _ty = TypingResult(_tempTypes.value(*e)); + _ty = TypingResult(_tempTypes[e->index]); + setType(e, _ty.type); + } + virtual void visitArgLocal(ArgLocal *e) { + _ty = TypingResult(VarType); setType(e, _ty.type); } + virtual void visitClosure(Closure *) { _ty = TypingResult(VarType); } virtual void visitConvert(Convert *e) { _ty = TypingResult(e->type); @@ -2201,15 +2341,17 @@ protected: class ReverseInference { - const DefUsesCalculator &_defUses; + const DefUses &_defUses; public: - ReverseInference(const DefUsesCalculator &defUses) + ReverseInference(const DefUses &defUses) : _defUses(defUses) {} void run(IR::Function *f) { + Q_UNUSED(f); + QVector<UntypedTemp> knownOk; QList<UntypedTemp> candidates = _defUses.defsUntyped(); while (!candidates.isEmpty()) { @@ -2222,7 +2364,7 @@ public: if (!isUsedAsInt32(temp, knownOk)) continue; - Stmt *s = _defUses.defStmt(temp); + Stmt *s = _defUses.defStmt(temp.temp); Move *m = s->asMove(); if (!m) continue; @@ -2252,13 +2394,13 @@ public: default: continue; } - if (Temp *lt = unescapableTemp(b->left, f)) + if (Temp *lt = b->left->asTemp()) candidates.append(*lt); - if (Temp *rt = unescapableTemp(b->right, f)) + if (Temp *rt = b->right->asTemp()) candidates.append(*rt); } else if (Unop *u = m->source->asUnop()) { if (u->op == OpCompl || u->op == OpUPlus) { - if (Temp *t = unescapableTemp(u->expr, f)) + if (Temp *t = u->expr->asTemp()) candidates.append(*t); } } else { @@ -2271,7 +2413,7 @@ public: PropagateTempTypes propagator(_defUses); foreach (const UntypedTemp &t, knownOk) { propagator.run(t, SInt32Type); - if (Stmt *defStmt = _defUses.defStmt(t)) { + if (Stmt *defStmt = _defUses.defStmt(t.temp)) { if (Move *m = defStmt->asMove()) { if (Convert *c = m->source->asConvert()) { c->type = SInt32Type; @@ -2289,7 +2431,7 @@ public: private: bool isUsedAsInt32(const UntypedTemp &t, const QVector<UntypedTemp> &knownOk) const { - const QList<Stmt *> &uses = _defUses.uses(t); + const QVector<Stmt *> &uses = _defUses.uses(t.temp); if (uses.isEmpty()) return false; @@ -2364,7 +2506,7 @@ void convertConst(Const *c, Type targetType) } class TypePropagation: public StmtVisitor, public ExprVisitor { - DefUsesCalculator &_defUses; + DefUses &_defUses; Type _ty; IR::Function *_f; @@ -2415,9 +2557,9 @@ class TypePropagation: public StmtVisitor, public ExprVisitor { } public: - TypePropagation(DefUsesCalculator &defUses) : _defUses(defUses), _ty(UnknownType) {} + TypePropagation(DefUses &defUses) : _defUses(defUses), _ty(UnknownType) {} - void run(IR::Function *f) { + void run(IR::Function *f, StatementWorklist &worklist) { _f = f; foreach (BasicBlock *bb, f->basicBlocks()) { if (bb->isRemoved()) @@ -2438,13 +2580,35 @@ public: *conversion.expr = bb->CONVERT(*conversion.expr, conversion.targetType); } else if (Const *c = (*conversion.expr)->asConst()) { convertConst(c, conversion.targetType); + } else if (ArgLocal *al = (*conversion.expr)->asArgLocal()) { + Temp *target = bb->TEMP(bb->newTemp()); + target->type = conversion.targetType; + Expr *convert = bb->CONVERT(al, conversion.targetType); + Move *convCall = f->NewStmt<Move>(); + worklist.registerNewStatement(convCall); + convCall->init(target, convert); + _defUses.addDef(target, convCall, bb); + + Temp *source = bb->TEMP(target->index); + source->type = conversion.targetType; + _defUses.addUse(*source, conversion.stmt); + + if (conversion.stmt->asPhi()) { + // Only temps can be used as arguments to phi nodes, so this is a sanity check...: + Q_UNREACHABLE(); + } else { + bb->insertStatementBefore(conversion.stmt, convCall); + } + + *conversion.expr = source; } else if (Temp *t = (*conversion.expr)->asTemp()) { Temp *target = bb->TEMP(bb->newTemp()); target->type = conversion.targetType; Expr *convert = bb->CONVERT(t, conversion.targetType); - Move *convCall = f->New<Move>(); + Move *convCall = f->NewStmt<Move>(); + worklist.registerNewStatement(convCall); convCall->init(target, convert); - _defUses.addTemp(target, convCall, bb); + _defUses.addDef(target, convCall, bb); _defUses.addUse(*t, convCall); Temp *source = bb->TEMP(target->index); @@ -2469,9 +2633,10 @@ public: // int32{%2} = int32{convert(double{%3})}; Temp *tmp = bb->TEMP(bb->newTemp()); tmp->type = u->type; - Move *extraMove = f->New<Move>(); + Move *extraMove = f->NewStmt<Move>(); + worklist.registerNewStatement(extraMove); extraMove->init(tmp, u); - _defUses.addTemp(tmp, extraMove, bb); + _defUses.addDef(tmp, extraMove, bb); if (Temp *unopOperand = u->expr->asTemp()) { _defUses.addUse(*unopOperand, extraMove); @@ -2480,7 +2645,7 @@ public: bb->insertStatementBefore(conversion.stmt, extraMove); - *conversion.expr = bb->CONVERT(tmp, conversion.targetType); + *conversion.expr = bb->CONVERT(CloneExpr::cloneTemp(tmp, f), conversion.targetType); _defUses.addUse(*tmp, move); } else { Q_UNREACHABLE(); @@ -2504,6 +2669,7 @@ protected: virtual void visitRegExp(IR::RegExp *) {} virtual void visitName(Name *) {} virtual void visitTemp(Temp *) {} + virtual void visitArgLocal(ArgLocal *) {} virtual void visitClosure(Closure *) {} virtual void visitConvert(Convert *e) { run(e->expr, e->type); } virtual void visitUnop(Unop *e) { run(e->expr, e->type); } @@ -2608,7 +2774,7 @@ protected: } }; -void splitCriticalEdges(IR::Function *f, DominatorTree &df) +void splitCriticalEdges(IR::Function *f, DominatorTree &df, StatementWorklist &worklist, DefUses &defUses) { foreach (BasicBlock *bb, f->basicBlocks()) { if (bb->isRemoved()) @@ -2622,11 +2788,11 @@ void splitCriticalEdges(IR::Function *f, DominatorTree &df) continue; // We found a critical edge. - BasicBlock *containingGroup = inBB->isGroupStart() ? inBB : inBB->containingGroup(); - // create the basic block: - BasicBlock *newBB = f->newBasicBlock(containingGroup, bb->catchBlock); - Jump *s = f->New<Jump>(); + BasicBlock *newBB = f->newBasicBlock(bb->catchBlock); + Jump *s = f->NewStmt<Jump>(); + worklist.registerNewStatement(s); + defUses.registerNewStatement(s); s->init(bb); newBB->appendStatement(s); @@ -2663,6 +2829,231 @@ void splitCriticalEdges(IR::Function *f, DominatorTree &df) } } +// Detect all (sub-)loops in a function. +// +// Doing loop detection on the CFG is better than relying on the statement information in +// order to mark loops. Although JavaScript only has natural loops, it can still be the case +// that something is not a loop even though a loop-like-statement is in the source. For +// example: +// while (true) { +// if (i > 0) +// break; +// else +// break; +// } +// +// Algorithm: +// - do a DFS on the dominator tree, where for each node: +// - collect all back-edges +// - if there are back-edges, the node is a loop-header for a new loop, so: +// - walk the CFG is reverse-direction, and for every node: +// - if the node already belongs to a loop, we've found a nested loop: +// - get the loop-header for the (outermost) nested loop +// - add that loop-header to the current loop +// - continue by walking all incoming edges that do not yet belong to the current loop +// - if the node does not belong to a loop yet, add it to the current loop, and +// go on with all incoming edges +// +// Loop-header detection by checking for back-edges is very straight forward: a back-edge is +// an incoming edge where the other node is dominated by the current node. Meaning: all +// execution paths that reach that other node have to go through the current node, that other +// node ends with a (conditional) jump back to the loop header. +// +// The exact order of the DFS on the dominator tree is not important. The only property has to +// be that a node is only visited when all the nodes it dominates have been visited before. +// The reason for the DFS is that for nested loops, the inner loop's loop-header is dominated +// by the outer loop's header. So, by visiting depth-first, sub-loops are identified before +// their containing loops, which makes nested-loop identification free. An added benefit is +// that the nodes for those sub-loops are only processed once. +// +// Note: independent loops that share the same header are merged together. For example, in +// the code snippet below, there are 2 back-edges into the loop-header, but only one single +// loop will be detected. +// while (a) { +// if (b) +// continue; +// else +// continue; +// } +class LoopDetection +{ + enum { DebugLoopDetection = 0 }; + + Q_DISABLE_COPY(LoopDetection) + +public: + struct LoopInfo + { + BasicBlock *loopHeader; + QVector<BasicBlock *> loopBody; + QVector<LoopInfo *> nestedLoops; + LoopInfo *parentLoop; + + LoopInfo(BasicBlock *loopHeader = 0) + : loopHeader(loopHeader) + , parentLoop(0) + {} + + bool isValid() const + { return loopHeader != 0; } + + void addNestedLoop(LoopInfo *nested) + { + Q_ASSERT(nested); + Q_ASSERT(!nestedLoops.contains(nested)); + Q_ASSERT(nested->parentLoop == 0); + nested->parentLoop = this; + nestedLoops.append(nested); + } + }; + +public: + LoopDetection(const DominatorTree &dt) + : dt(dt) + {} + + ~LoopDetection() + { + qDeleteAll(loopInfos); + } + + void run(IR::Function *function) + { + std::vector<BasicBlock *> backedges; + backedges.reserve(4); + + foreach (BasicBlock *bb, dt.calculateDFNodeIterOrder()) { + Q_ASSERT(!bb->isRemoved()); + + backedges.clear(); + + foreach (BasicBlock *in, bb->in) + if (dt.dominates(bb, in)) + backedges.push_back(in); + + if (!backedges.empty()) { + subLoop(bb, backedges); + } + } + + createLoopInfos(function); + dumpLoopInfo(); + } + + void dumpLoopInfo() const + { + if (!DebugLoopDetection) + return; + + foreach (LoopInfo *info, loopInfos) { + qDebug() << "Loop header:" << info->loopHeader->index() + << "for loop" << quint64(info); + foreach (BasicBlock *bb, info->loopBody) + qDebug() << " " << bb->index(); + foreach (LoopInfo *nested, info->nestedLoops) + qDebug() << " sub loop:" << quint64(nested); + qDebug() << " parent loop:" << quint64(info->parentLoop); + } + } + + QVector<LoopInfo *> allLoops() const + { return loopInfos; } + + // returns all loop headers for loops that have no nested loops. + QVector<LoopInfo *> innermostLoops() const + { + QVector<LoopInfo *> inner(loopInfos); + + for (int i = 0; i < inner.size(); ) { + if (inner.at(i)->nestedLoops.isEmpty()) + ++i; + else + inner.remove(i); + } + + return inner; + } + +private: + void subLoop(BasicBlock *loopHead, const std::vector<BasicBlock *> &backedges) + { + loopHead->markAsGroupStart(); + + std::vector<BasicBlock *> worklist; + worklist.reserve(backedges.size() + 8); + worklist.insert(worklist.end(), backedges.begin(), backedges.end()); + while (!worklist.empty()) { + BasicBlock *predIt = worklist.back(); + worklist.pop_back(); + + BasicBlock *subloop = predIt->containingGroup(); + if (subloop) { + // This is a discovered block. Find its outermost discovered loop. + while (BasicBlock *parentLoop = subloop->containingGroup()) + subloop = parentLoop; + + // If it is already discovered to be a subloop of this loop, continue. + if (subloop == loopHead) + continue; + + // Yay, it's a subloop of this loop. + subloop->setContainingGroup(loopHead); + predIt = subloop; + + // Add all predecessors of the subloop header to the worklist, as long as + // those predecessors are not in the current subloop. It might be the case + // that they are in other loops, which we will then add as a subloop to the + // current loop. + foreach (BasicBlock *predIn, predIt->in) + if (predIn->containingGroup() != subloop) + worklist.push_back(predIn); + } else { + if (predIt == loopHead) + continue; + + // This is an undiscovered block. Map it to the current loop. + predIt->setContainingGroup(loopHead); + + // Add all incoming edges to the worklist. + foreach (BasicBlock *bb, predIt->in) + worklist.push_back(bb); + } + } + } + +private: + const DominatorTree &dt; + QVector<LoopInfo *> loopInfos; + + void createLoopInfos(IR::Function *function) + { + foreach (BasicBlock *bb, function->basicBlocks()) { + if (bb->isRemoved()) + continue; + if (BasicBlock *loopHeader = bb->containingGroup()) + findLoop(loopHeader)->loopBody.append(bb); + } + + foreach (LoopInfo *info, loopInfos) { + if (BasicBlock *containingLoopHeader = info->loopHeader->containingGroup()) + findLoop(containingLoopHeader)->addNestedLoop(info); + } + } + + LoopInfo *findLoop(BasicBlock *loopHeader) + { + foreach (LoopInfo *info, loopInfos) { + if (info->loopHeader == loopHeader) + return info; + } + + LoopInfo *info = new LoopInfo; + info->loopHeader = loopHeader; + loopInfos.append(info); + return info; + } +}; + // High-level algorithm: // 0. start with the first node (the start node) of a function // 1. emit the node @@ -2931,20 +3322,20 @@ static Expr *clone(Expr *e, IR::Function *function) { class ExprReplacer: public StmtVisitor, public ExprVisitor { - DefUsesCalculator &_defUses; + DefUses &_defUses; IR::Function* _function; Temp *_toReplace; Expr *_replacement; public: - ExprReplacer(DefUsesCalculator &defUses, IR::Function *function) + ExprReplacer(DefUses &defUses, IR::Function *function) : _defUses(defUses) , _function(function) , _toReplace(0) , _replacement(0) {} - void operator()(Temp *toReplace, Expr *replacement, StatementWorklist &W, QList<Stmt *> *newUses = 0) + void operator()(Temp *toReplace, Expr *replacement, StatementWorklist &W, QVector<Stmt *> *newUses = 0) { Q_ASSERT(replacement->asTemp() || replacement->asConst() || replacement->asName()); @@ -2953,7 +3344,7 @@ public: qSwap(_toReplace, toReplace); qSwap(_replacement, replacement); - const QList<Stmt *> &uses = _defUses.uses(*_toReplace); + const QVector<Stmt *> &uses = _defUses.uses(*_toReplace); if (newUses) newUses->reserve(uses.size()); @@ -2964,7 +3355,7 @@ public: // qout<<" -> ";use->dump(qout);qout<<"\n"; W += use; if (newUses) - newUses->append(use); + newUses->push_back(use); } qSwap(_replacement, replacement); @@ -2977,6 +3368,7 @@ protected: virtual void visitRegExp(IR::RegExp *) {} virtual void visitName(Name *) {} virtual void visitTemp(Temp *) {} + virtual void visitArgLocal(ArgLocal *) {} virtual void visitClosure(Closure *) {} virtual void visitConvert(Convert *e) { check(e->expr); } virtual void visitUnop(Unop *e) { check(e->expr); } @@ -3047,7 +3439,7 @@ namespace { /// and removes unreachable staements from the worklist, so that optimiseSSA won't consider them /// anymore. /// Important: this assumes that there are no critical edges in the control-flow graph! -void purgeBB(BasicBlock *bb, IR::Function *func, DefUsesCalculator &defUses, StatementWorklist &W, +void purgeBB(BasicBlock *bb, IR::Function *func, DefUses &defUses, StatementWorklist &W, DominatorTree &df) { // TODO: after the change above: if we keep on detaching the block from predecessors or @@ -3085,8 +3477,10 @@ void purgeBB(BasicBlock *bb, IR::Function *func, DefUsesCalculator &defUses, Sta if (!outStmt) continue; if (Phi *phi = outStmt->asPhi()) { - if (Temp *t = phi->d->incoming[idx]->asTemp()) + if (Temp *t = phi->d->incoming[idx]->asTemp()) { defUses.removeUse(phi, *t); + W += defUses.defStmt(*t); + } phi->d->incoming.remove(idx); W += phi; } else @@ -3180,24 +3574,79 @@ bool tryOptimizingComparison(Expr *&expr) return false; } + +void cfg2dot(IR::Function *f, const QVector<LoopDetection::LoopInfo *> &loops = QVector<LoopDetection::LoopInfo *>()) +{ + static bool showCode = !qgetenv("QV4_SHOW_IR").isNull(); + if (!showCode) + return; + + struct Util { + static void genLoop(LoopDetection::LoopInfo *loop) + { + qout << " subgraph \"cluster" << quint64(loop) << "\" {\n"; + qout << " L" << loop->loopHeader->index() << ";\n"; + foreach (BasicBlock *bb, loop->loopBody) + qout << " L" << bb->index() << ";\n"; + foreach (LoopDetection::LoopInfo *nested, loop->nestedLoops) + genLoop(nested); + qout << " }\n"; + } + }; + + QString name; + if (f->name) name = *f->name; + else name = QString::fromLatin1("%1").arg((unsigned long long)f); + qout << "digraph \"" << name << "\" { ordering=out;\n"; + + foreach (LoopDetection::LoopInfo *l, loops) { + if (l->parentLoop == 0) + Util::genLoop(l); + } + + foreach (BasicBlock *bb, f->basicBlocks()) { + if (bb->isRemoved()) + continue; + + int idx = bb->index(); + qout << " L" << idx << " [label=\"L" << idx << "\""; + if (idx == 0 || bb->terminator()->asRet()) + qout << ", shape=doublecircle"; + else + qout << ", shape=circle"; + qout << "];\n"; + foreach (BasicBlock *out, bb->out) + qout << " L" << idx << " -> L" << out->index() << "\n"; + } + + qout << "}\n" << flush; +} + } // anonymous namespace -void optimizeSSA(IR::Function *function, DefUsesCalculator &defUses, DominatorTree &df) +void optimizeSSA(StatementWorklist &W, DefUses &defUses, DominatorTree &df) { - StatementWorklist W(function); + IR::Function *function = W.function(); ExprReplacer replaceUses(defUses, function); + Stmt *s = 0; while (!W.isEmpty()) { - Stmt *s = W.takeOne(); - if (!s) - continue; + s = W.takeNext(s); + Q_ASSERT(s); if (Phi *phi = s->asPhi()) { + // dead code elimination: + if (defUses.useCount(*phi->targetTemp) == 0) { + W += defUses.removeDefUses(phi); + W.remove(s); + continue; + } + // constant propagation: if (Const *c = isConstPhi(phi)) { replaceUses(phi->targetTemp, c, W); defUses.removeDef(*phi->targetTemp); - W.clear(s); + W.remove(s); continue; } @@ -3206,26 +3655,15 @@ void optimizeSSA(IR::Function *function, DefUsesCalculator &defUses, DominatorTr Temp *t = phi->targetTemp; Expr *e = phi->d->incoming.first(); - QList<Stmt *> newT2Uses; + QVector<Stmt *> newT2Uses; replaceUses(t, e, W, &newT2Uses); if (Temp *t2 = e->asTemp()) { defUses.removeUse(s, *t2); defUses.addUses(*t2, newT2Uses); + W += defUses.defStmt(*t2); } defUses.removeDef(*t); - W.clear(s); - continue; - } - - // dead code elimination: - if (defUses.useCount(*phi->targetTemp) == 0) { - foreach (Expr *in, phi->d->incoming) { - if (Temp *t = in->asTemp()) - W += defUses.defStmt(*t); - } - - defUses.removeDef(*phi->targetTemp); - W.clear(s); + W.remove(s); continue; } } else if (Move *m = s->asMove()) { @@ -3244,12 +3682,12 @@ void optimizeSSA(IR::Function *function, DefUsesCalculator &defUses, DominatorTr } } - if (Temp *targetTemp = unescapableTemp(m->target, function)) { + if (Temp *targetTemp = m->target->asTemp()) { // dead code elimination: if (defUses.useCount(*targetTemp) == 0) { - EliminateDeadCode(defUses, W, function).run(m->source, s); + EliminateDeadCode(defUses, W).run(m->source, s); if (!m->source) - W.clear(s); + W.remove(s); continue; } @@ -3257,7 +3695,7 @@ void optimizeSSA(IR::Function *function, DefUsesCalculator &defUses, DominatorTr if (Const *sourceConst = m->source->asConst()) { replaceUses(targetTemp, sourceConst, W); defUses.removeDef(*targetTemp); - W.clear(s); + W.remove(s); continue; } if (Member *member = m->source->asMember()) { @@ -3267,7 +3705,7 @@ void optimizeSSA(IR::Function *function, DefUsesCalculator &defUses, DominatorTr c->init(SInt32Type, enumValue); replaceUses(targetTemp, c, W); defUses.removeDef(*targetTemp); - W.clear(s); + W.remove(s); defUses.removeUse(s, *member->base->asTemp()); continue; } else if (member->attachedPropertiesIdOrEnumValue != 0 && member->property && member->base->asTemp()) { @@ -3282,13 +3720,13 @@ void optimizeSSA(IR::Function *function, DefUsesCalculator &defUses, DominatorTr } // copy propagation: - if (Temp *sourceTemp = unescapableTemp(m->source, function)) { - QList<Stmt *> newT2Uses; + if (Temp *sourceTemp = m->source->asTemp()) { + QVector<Stmt *> newT2Uses; replaceUses(targetTemp, sourceTemp, W, &newT2Uses); defUses.removeUse(s, *sourceTemp); defUses.addUses(*sourceTemp, newT2Uses); defUses.removeDef(*targetTemp); - W.clear(s); + W.remove(s); continue; } @@ -3451,7 +3889,8 @@ void optimizeSSA(IR::Function *function, DefUsesCalculator &defUses, DominatorTr if (Const *constantCondition = cjump->cond->asConst()) { // Note: this assumes that there are no critical edges! Meaning, we can safely purge // any basic blocks that are found to be unreachable. - Jump *jump = function->New<Jump>(); + Jump *jump = function->NewStmt<Jump>(); + W.registerNewStatement(jump); if (convertToValue(constantCondition).toBoolean()) { jump->target = cjump->iftrue; purgeBB(cjump->iffalse, function, defUses, W, df); @@ -3473,21 +3912,27 @@ void optimizeSSA(IR::Function *function, DefUsesCalculator &defUses, DominatorTr } } - W.cleanup(function); + W.applyToFunction(); } +//### TODO: use DefUses from the optimizer, because it already has all this information class InputOutputCollector: protected StmtVisitor, protected ExprVisitor { - IR::Function *function; + void setOutput(Temp *out) + { + Q_ASSERT(!output); + output = out; + } public: - QList<Temp> inputs; - QList<Temp> outputs; + std::vector<Temp *> inputs; + Temp *output; - InputOutputCollector(IR::Function *f): function(f) {} + InputOutputCollector() + { inputs.reserve(4); } void collect(Stmt *s) { - inputs.clear(); - outputs.clear(); + inputs.resize(0); + output = 0; s->accept(this); } @@ -3497,9 +3942,9 @@ protected: virtual void visitRegExp(IR::RegExp *) {} virtual void visitName(Name *) {} virtual void visitTemp(Temp *e) { - if (unescapableTemp(e, function)) - inputs.append(*e); + inputs.push_back(e); } + virtual void visitArgLocal(ArgLocal *) {} virtual void visitClosure(Closure *) {} virtual void visitConvert(Convert *e) { e->expr->accept(this); } virtual void visitUnop(Unop *e) { e->expr->accept(this); } @@ -3520,10 +3965,7 @@ protected: virtual void visitMove(Move *s) { s->source->accept(this); if (Temp *t = s->target->asTemp()) { - if (unescapableTemp(t, function)) - outputs.append(*t); - else - s->target->accept(this); + setOutput(t); } else { s->target->accept(this); } @@ -3542,74 +3984,88 @@ protected: * Linear Scan Register Allocation on SSA Form * Christian Wimmer & Michael Franz, CGO'10, April 24-28, 2010 * - * There is one slight difference w.r.t. the phi-nodes: in the artice, the phi nodes are attached - * to the basic-blocks. Therefore, in the algorithm in the article, the ranges for input parameters - * for phi nodes run from their definition upto the branch instruction into the block with the phi - * node. In our representation, phi nodes are mostly treaded as normal instructions, so we have to - * enlarge the range to cover the phi node itself. + * See LifeTimeIntervals::renumber for details on the numbering. */ class LifeRanges { typedef QSet<Temp> LiveRegs; - QVector<LiveRegs> _liveIn; - QHash<Temp, LifeTimeInterval> _intervals; - typedef QVector<LifeTimeInterval> LifeTimeIntervals; - LifeTimeIntervals _sortedIntervals; + std::vector<LiveRegs> _liveIn; + std::vector<LifeTimeInterval *> _intervals; + LifeTimeIntervals::Ptr _sortedIntervals; + + LifeTimeInterval &interval(const Temp *temp) + { + LifeTimeInterval *<i = _intervals[temp->index]; + if (Q_UNLIKELY(!lti)) { + lti = new LifeTimeInterval; + lti->setTemp(*temp); + } + return *lti; + } + + int defPosition(IR::Stmt *s) const + { + return usePosition(s) + 1; + } + + int usePosition(IR::Stmt *s) const + { + return _sortedIntervals->positionForStatement(s); + } + + int start(IR::BasicBlock *bb) const + { + return _sortedIntervals->startPosition(bb); + } + + int end(IR::BasicBlock *bb) const + { + return _sortedIntervals->endPosition(bb); + } public: LifeRanges(IR::Function *function, const QHash<BasicBlock *, BasicBlock *> &startEndLoops) + : _intervals(function->tempCount) { + _sortedIntervals = LifeTimeIntervals::create(function); _liveIn.resize(function->basicBlockCount()); - int id = 0; - foreach (BasicBlock *bb, function->basicBlocks()) { - foreach (Stmt *s, bb->statements()) { - if (s->asPhi()) - s->id = id + 1; - else - s->id = ++id; - } - } - for (int i = function->basicBlockCount() - 1; i >= 0; --i) { BasicBlock *bb = function->basicBlock(i); - buildIntervals(bb, startEndLoops.value(bb, 0), function); + buildIntervals(bb, startEndLoops.value(bb, 0)); } - _sortedIntervals.reserve(_intervals.size()); - for (QHash<Temp, LifeTimeInterval>::const_iterator i = _intervals.begin(), ei = _intervals.end(); i != ei; ++i) { - LifeTimeIntervals::iterator lti = _sortedIntervals.insert(_sortedIntervals.end(), i.value()); - lti->setTemp(i.key()); - } - std::sort(_sortedIntervals.begin(), _sortedIntervals.end(), LifeTimeInterval::lessThan); _intervals.clear(); } - QVector<LifeTimeInterval> intervals() const { return _sortedIntervals; } + LifeTimeIntervals::Ptr intervals() const { return _sortedIntervals; } void dump() const { qout << "Life ranges:" << endl; qout << "Intervals:" << endl; - foreach (const LifeTimeInterval &range, _sortedIntervals) { - range.dump(qout); + foreach (const LifeTimeInterval *range, _sortedIntervals->intervals()) { + range->dump(qout); qout << endl; } + IRPrinter printer(&qout); for (int i = 0, ei = _liveIn.size(); i != ei; ++i) { qout << "L" << i <<" live-in: "; QList<Temp> live = QList<Temp>::fromSet(_liveIn.at(i)); + if (live.isEmpty()) + qout << "(none)"; std::sort(live.begin(), live.end()); for (int i = 0; i < live.size(); ++i) { if (i > 0) qout << ", "; - live[i].dump(qout); + printer.print(&live[i]); } qout << endl; } } private: - void buildIntervals(BasicBlock *bb, BasicBlock *loopEnd, IR::Function *function) + void buildIntervals(BasicBlock *bb, BasicBlock *loopEnd) { LiveRegs live; foreach (BasicBlock *successor, bb->out) { @@ -3630,35 +4086,41 @@ private: QVector<Stmt *> statements = bb->statements(); foreach (const Temp &opd, live) - _intervals[opd].addRange(statements.first()->id, statements.last()->id); + interval(&opd).addRange(start(bb), end(bb)); - InputOutputCollector collector(function); + InputOutputCollector collector; for (int i = statements.size() - 1; i >= 0; --i) { - Stmt *s = statements[i]; + Stmt *s = statements.at(i); if (Phi *phi = s->asPhi()) { LiveRegs::iterator it = live.find(*phi->targetTemp); if (it == live.end()) { // a phi node target that is only defined, but never used - _intervals[*phi->targetTemp].setFrom(s); + interval(phi->targetTemp).setFrom(start(bb)); } else { live.erase(it); } + _sortedIntervals->add(&interval(phi->targetTemp)); continue; } collector.collect(s); - foreach (const Temp &opd, collector.outputs) { - _intervals[opd].setFrom(s); - live.remove(opd); + //### TODO: use DefUses from the optimizer, because it already has all this information + if (Temp *opd = collector.output) { + LifeTimeInterval <i = interval(opd); + lti.setFrom(defPosition(s)); + live.remove(lti.temp()); + _sortedIntervals->add(<i); } - foreach (const Temp &opd, collector.inputs) { - _intervals[opd].addRange(statements.first()->id, s->id); - live.insert(opd); + //### TODO: use DefUses from the optimizer, because it already has all this information + for (unsigned i = 0, ei = collector.inputs.size(); i != ei; ++i) { + Temp *opd = collector.inputs[i]; + interval(opd).addRange(start(bb), usePosition(s)); + live.insert(*opd); } } if (loopEnd) { // Meaning: bb is a loop header, because loopEnd is set to non-null. foreach (const Temp &opd, live) - _intervals[opd].addRange(statements.first()->id, loopEnd->terminator()->id); + interval(&opd).addRange(start(bb), usePosition(loopEnd->terminator())); } _liveIn[bb->index()] = live; @@ -3675,17 +4137,280 @@ void removeUnreachleBlocks(IR::Function *function) function->setScheduledBlocks(newSchedule); function->renumberBasicBlocks(); } + +class ConvertArgLocals: protected StmtVisitor, protected ExprVisitor +{ +public: + ConvertArgLocals(IR::Function *function) + : function(function) + , convertArgs(!function->usesArgumentsObject) + { + tempForFormal.resize(function->formals.size(), -1); + tempForLocal.resize(function->locals.size(), -1); + } + + void toTemps() + { + if (function->variablesCanEscape()) + return; + + QVector<Stmt *> extraMoves; + if (convertArgs) { + const int formalCount = function->formals.size(); + extraMoves.reserve(formalCount + function->basicBlock(0)->statementCount()); + extraMoves.resize(formalCount); + + for (int i = 0; i != formalCount; ++i) { + const int newTemp = function->tempCount++; + tempForFormal[i] = newTemp; + + ArgLocal *source = function->New<ArgLocal>(); + source->init(ArgLocal::Formal, i, 0); + + Temp *target = function->New<Temp>(); + target->init(Temp::VirtualRegister, newTemp); + + Move *m = function->NewStmt<Move>(); + m->init(target, source); + extraMoves[i] = m; + } + } + + foreach (BasicBlock *bb, function->basicBlocks()) + if (!bb->isRemoved()) + foreach (Stmt *s, bb->statements()) + s->accept(this); + + if (convertArgs && function->formals.size() > 0) + function->basicBlock(0)->prependStatements(extraMoves); + + function->locals.clear(); + } + +protected: + virtual void visitConst(Const *) {} + virtual void visitString(IR::String *) {} + virtual void visitRegExp(IR::RegExp *) {} + virtual void visitName(Name *) {} + virtual void visitTemp(Temp *) {} + virtual void visitArgLocal(ArgLocal *) {} + virtual void visitClosure(Closure *) {} + virtual void visitConvert(Convert *e) { check(e->expr); } + virtual void visitUnop(Unop *e) { check(e->expr); } + virtual void visitBinop(Binop *e) { check(e->left); check(e->right); } + virtual void visitCall(Call *e) { + check(e->base); + for (ExprList *it = e->args; it; it = it->next) + check(it->expr); + } + virtual void visitNew(New *e) { + check(e->base); + for (ExprList *it = e->args; it; it = it->next) + check(it->expr); + } + virtual void visitSubscript(Subscript *e) { check(e->base); check(e->index); } + virtual void visitMember(Member *e) { check(e->base); } + virtual void visitExp(Exp *s) { check(s->expr); } + virtual void visitMove(Move *s) { check(s->target); check(s->source); } + virtual void visitJump(Jump *) {} + virtual void visitCJump(CJump *s) { check(s->cond); } + virtual void visitRet(Ret *s) { check(s->expr); } + virtual void visitPhi(Phi *) { + Q_UNREACHABLE(); + } + +private: + void check(Expr *&e) { + if (ArgLocal *al = e->asArgLocal()) { + if (al->kind == ArgLocal::Local) { + Temp *t = function->New<Temp>(); + t->init(Temp::VirtualRegister, fetchTempForLocal(al->index)); + e = t; + } else if (convertArgs && al->kind == ArgLocal::Formal) { + Temp *t = function->New<Temp>(); + t->init(Temp::VirtualRegister, fetchTempForFormal(al->index)); + e = t; + } + } else { + e->accept(this); + } + } + + int fetchTempForLocal(int local) + { + int &ref = tempForLocal[local]; + if (ref == -1) + ref = function->tempCount++; + return ref; + } + + int fetchTempForFormal(int formal) + { + return tempForFormal[formal]; + } + + IR::Function *function; + bool convertArgs; + std::vector<int> tempForFormal; + std::vector<int> tempForLocal; +}; + +static void verifyCFG(IR::Function *function) +{ + if (!DoVerification) + return; + + foreach (BasicBlock *bb, function->basicBlocks()) { + if (bb->isRemoved()) { + Q_ASSERT(bb->in.isEmpty()); + Q_ASSERT(bb->out.isEmpty()); + continue; + } + + Q_ASSERT(function->basicBlock(bb->index()) == bb); + + // Check the terminators: + if (Jump *jump = bb->terminator()->asJump()) { + Q_UNUSED(jump); + Q_ASSERT(jump->target); + Q_ASSERT(!jump->target->isRemoved()); + Q_ASSERT(bb->out.size() == 1); + Q_ASSERT(bb->out.first() == jump->target); + } else if (CJump *cjump = bb->terminator()->asCJump()) { + Q_UNUSED(cjump); + Q_ASSERT(bb->out.size() == 2); + Q_ASSERT(cjump->iftrue); + Q_ASSERT(!cjump->iftrue->isRemoved()); + Q_ASSERT(cjump->iftrue == bb->out[0]); + Q_ASSERT(cjump->iffalse); + Q_ASSERT(!cjump->iffalse->isRemoved()); + Q_ASSERT(cjump->iffalse == bb->out[1]); + } else if (bb->terminator()->asRet()) { + Q_ASSERT(bb->out.size() == 0); + } else { + Q_UNREACHABLE(); + } + + // Check the outgoing edges: + foreach (BasicBlock *out, bb->out) { + Q_UNUSED(out); + Q_ASSERT(!out->isRemoved()); + Q_ASSERT(out->in.contains(bb)); + } + + // Check the incoming edges: + foreach (BasicBlock *in, bb->in) { + Q_UNUSED(in); + Q_ASSERT(!in->isRemoved()); + Q_ASSERT(in->out.contains(bb)); + } + } +} + +static void verifyImmediateDominators(const DominatorTree &dt, IR::Function *function) +{ + if (!DoVerification) + return; + + cfg2dot(function); + dt.dumpImmediateDominators(); + DominatorTree referenceTree(function); + + foreach (BasicBlock *bb, function->basicBlocks()) { + if (bb->isRemoved()) + continue; + + BasicBlock *idom = dt.immediateDominator(bb); + BasicBlock *referenceIdom = referenceTree.immediateDominator(bb); + Q_UNUSED(idom); + Q_UNUSED(referenceIdom); + Q_ASSERT(idom == referenceIdom); + } +} + +static void verifyNoPointerSharing(IR::Function *function) +{ + if (!DoVerification) + return; + + class : public StmtVisitor, public ExprVisitor { + public: + void operator()(IR::Function *f) + { + foreach (BasicBlock *bb, f->basicBlocks()) { + if (bb->isRemoved()) + continue; + + foreach (Stmt *s, bb->statements()) + s->accept(this); + } + } + + protected: + virtual void visitExp(Exp *s) { check(s); s->expr->accept(this); } + virtual void visitMove(Move *s) { check(s); s->target->accept(this); s->source->accept(this); } + virtual void visitJump(Jump *s) { check(s); } + virtual void visitCJump(CJump *s) { check(s); s->cond->accept(this); } + virtual void visitRet(Ret *s) { check(s); s->expr->accept(this); } + virtual void visitPhi(Phi *s) + { + check(s); + s->targetTemp->accept(this); + foreach (Expr *e, s->d->incoming) + e->accept(this); + } + + virtual void visitConst(Const *e) { check(e); } + virtual void visitString(IR::String *e) { check(e); } + virtual void visitRegExp(IR::RegExp *e) { check(e); } + virtual void visitName(Name *e) { check(e); } + virtual void visitTemp(Temp *e) { check(e); } + virtual void visitArgLocal(ArgLocal *e) { check(e); } + virtual void visitClosure(Closure *e) { check(e); } + virtual void visitConvert(Convert *e) { check(e); e->expr->accept(this); } + virtual void visitUnop(Unop *e) { check(e); e->expr->accept(this); } + virtual void visitBinop(Binop *e) { check(e); e->left->accept(this); e->right->accept(this); } + virtual void visitCall(Call *e) { check(e); e->base->accept(this); check(e->args); } + virtual void visitNew(New *e) { check(e); e->base->accept(this); check(e->args); } + virtual void visitSubscript(Subscript *e) { check(e); e->base->accept(this); e->index->accept(this); } + virtual void visitMember(Member *e) { check(e); e->base->accept(this); } + + void check(ExprList *l) + { + for (ExprList *it = l; it; it = it->next) + check(it->expr); + } + + private: + void check(Stmt *s) + { + Q_ASSERT(!stmts.contains(s)); + stmts.insert(s); + } + + void check(Expr *e) + { + Q_ASSERT(!exprs.contains(e)); + exprs.insert(e); + } + + QSet<Stmt *> stmts; + QSet<Expr *> exprs; + } V; + V(function); +} + } // anonymous namespace -void LifeTimeInterval::setFrom(Stmt *from) { - Q_ASSERT(from && from->id > 0); +void LifeTimeInterval::setFrom(int from) { + Q_ASSERT(from > 0); if (_ranges.isEmpty()) { // this is the case where there is no use, only a define - _ranges.push_front(Range(from->id, from->id)); - if (_end == Invalid) - _end = from->id; + _ranges.push_front(Range(from, from)); + if (_end == InvalidPosition) + _end = from; } else { - _ranges.first().start = from->id; + _ranges.first().start = from; } } @@ -3705,7 +4430,7 @@ void LifeTimeInterval::addRange(int from, int to) { p->start = qMin(p->start, from); p->end = qMax(p->end, to); while (_ranges.count() > 1) { - Range *p1 = &_ranges[1]; + Range *p1 = p + 1; if (p->end + 1 < p1->start || p1->end + 1 < p->start) break; p1->start = qMin(p->start, p1->start); @@ -3727,7 +4452,7 @@ void LifeTimeInterval::addRange(int from, int to) { LifeTimeInterval LifeTimeInterval::split(int atPosition, int newStart) { - Q_ASSERT(atPosition < newStart || newStart == Invalid); + Q_ASSERT(atPosition < newStart || newStart == InvalidPosition); if (_ranges.isEmpty() || atPosition < _ranges.first().start) return LifeTimeInterval(); @@ -3756,7 +4481,7 @@ LifeTimeInterval LifeTimeInterval::split(int atPosition, int newStart) if (newInterval._ranges.first().end == atPosition) newInterval._ranges.removeFirst(); - if (newStart == Invalid) { + if (newStart == InvalidPosition) { // the temp stays inactive for the rest of its lifetime newInterval = LifeTimeInterval(); } else { @@ -3793,7 +4518,7 @@ LifeTimeInterval LifeTimeInterval::split(int atPosition, int newStart) } void LifeTimeInterval::dump(QTextStream &out) const { - _temp.dump(out); + IRPrinter(&out).print(const_cast<Temp *>(&_temp)); out << ": ends at " << _end << " with ranges "; if (_ranges.isEmpty()) out << "(none)"; @@ -3801,23 +4526,87 @@ void LifeTimeInterval::dump(QTextStream &out) const { if (i > 0) out << ", "; out << _ranges[i].start << " - " << _ranges[i].end; } - if (_reg != Invalid) + if (_reg != InvalidRegister) out << " (register " << _reg << ")"; } -bool LifeTimeInterval::lessThan(const LifeTimeInterval &r1, const LifeTimeInterval &r2) { - if (r1._ranges.first().start == r2._ranges.first().start) { - if (r1.isSplitFromInterval() == r2.isSplitFromInterval()) - return r1._ranges.last().end < r2._ranges.last().end; +bool LifeTimeInterval::lessThan(const LifeTimeInterval *r1, const LifeTimeInterval *r2) { + if (r1->_ranges.first().start == r2->_ranges.first().start) { + if (r1->isSplitFromInterval() == r2->isSplitFromInterval()) + return r1->_ranges.last().end < r2->_ranges.last().end; else - return r1.isSplitFromInterval(); + return r1->isSplitFromInterval(); } else - return r1._ranges.first().start < r2._ranges.first().start; + return r1->_ranges.first().start < r2->_ranges.first().start; +} + +bool LifeTimeInterval::lessThanForTemp(const LifeTimeInterval *r1, const LifeTimeInterval *r2) +{ + return r1->temp() < r2->temp(); +} + +LifeTimeIntervals::LifeTimeIntervals(IR::Function *function) + : _basicBlockPosition(function->basicBlockCount()) + , _positionForStatement(function->statementCount(), IR::Stmt::InvalidId) + , _lastPosition(0) +{ + _intervals.reserve(function->tempCount + 32); // we reserve a bit more space for intervals, because the register allocator will add intervals with fixed ranges for each register. + renumber(function); } -bool LifeTimeInterval::lessThanForTemp(const LifeTimeInterval &r1, const LifeTimeInterval &r2) +// Renumbering works as follows: +// - phi statements are not numbered +// - statement numbers start at 0 (zero) and increment get an even number (lastPosition + 2) +// - basic blocks start at firstStatementNumber - 1, or rephrased: lastPosition + 1 +// - basic blocks end at the number of the last statement +// And during life-time calculation the next rule is used: +// - any temporary starts its life-time at definingStatementPosition + 1 +// +// This numbering simulates half-open intervals. For example: +// 0: %1 = 1 +// 2: %2 = 2 +// 4: %3 = %1 + %2 +// 6: print(%3) +// Here the half-open life-time intervals would be: +// %1: (0-4] +// %2: (2-4] +// %3: (4-6] +// Instead, we use the even statement positions for uses of temporaries, and the odd positions for +// their definitions: +// %1: [1-4] +// %2: [3-4] +// %3: [5-6] +// This has the nice advantage that placing %3 (for example) is really easy: the start will +// never overlap with the end of the uses of the operands used in the defining statement. +// +// The reason to start a basic-block at firstStatementPosition - 1 is to have correct start +// positions for target temporaries of phi-nodes. Those temporaries will now start before the +// first statement. This also means that any moves that get generated when transforming out of SSA +// form, will not interfere with (read: overlap) any defining statements in the preceding +// basic-block. +void LifeTimeIntervals::renumber(IR::Function *function) { - return r1.temp() < r2.temp(); + foreach (BasicBlock *bb, function->basicBlocks()) { + if (bb->isRemoved()) + continue; + + _basicBlockPosition[bb->index()].start = _lastPosition + 1; + + foreach (Stmt *s, bb->statements()) { + if (s->asPhi()) + continue; + + _lastPosition += 2; + _positionForStatement[s->id()] = _lastPosition; + } + + _basicBlockPosition[bb->index()].end = _lastPosition; + } +} + +LifeTimeIntervals::~LifeTimeIntervals() +{ + qDeleteAll(_intervals); } Optimizer::Optimizer(IR::Function *function) @@ -3845,22 +4634,31 @@ void Optimizer::run(QQmlEnginePrivate *qmlEngine) if (!function->hasTry && !function->hasWith && !function->module->debugMode && doSSA) { // qout << "SSA for " << (function->name ? qPrintable(*function->name) : "<anonymous>") << endl; + ConvertArgLocals(function).toTemps(); + showMeTheCode(function); + // Calculate the dominator tree: DominatorTree df(function); + df.computeDF(); + + verifyCFG(function); + verifyImmediateDominators(df, function); + + DefUses defUses(function); // qout << "Converting to SSA..." << endl; - convertToSSA(function, df); + convertToSSA(function, df, defUses); // showMeTheCode(function); - -// qout << "Starting def/uses calculation..." << endl; - DefUsesCalculator defUses(function); +// defUses.dump(); // qout << "Cleaning up phi nodes..." << endl; cleanupPhis(defUses); // showMeTheCode(function); + StatementWorklist worklist(function); + // qout << "Running type inference..." << endl; - TypeInference(qmlEngine, defUses).run(function); + TypeInference(qmlEngine, defUses).run(worklist); // showMeTheCode(function); // qout << "Doing reverse inference..." << endl; @@ -3868,18 +4666,20 @@ void Optimizer::run(QQmlEnginePrivate *qmlEngine) // showMeTheCode(function); // qout << "Doing type propagation..." << endl; - TypePropagation(defUses).run(function); + TypePropagation(defUses).run(function, worklist); // showMeTheCode(function); + verifyNoPointerSharing(function); // Transform the CFG into edge-split SSA. // qout << "Starting edge splitting..." << endl; - splitCriticalEdges(function, df); + splitCriticalEdges(function, df, worklist, defUses); // showMeTheCode(function); static bool doOpt = qgetenv("QV4_NO_OPT").isEmpty(); if (doOpt) { // qout << "Running SSA optimization..." << endl; - optimizeSSA(function, defUses, df); + worklist.reset(); + optimizeSSA(worklist, defUses, df); // showMeTheCode(function); } @@ -3894,6 +4694,9 @@ void Optimizer::run(QQmlEnginePrivate *qmlEngine) cleanupBasicBlocks(function); // showMeTheCode(function); + LoopDetection(df).run(function); + showMeTheCode(function); + // qout << "Doing block scheduling..." << endl; // df.dumpImmediateDominators(); startEndLoops = BlockScheduler(function, df).go(); @@ -3960,7 +4763,7 @@ void Optimizer::convertOutOfSSA() { } } -QVector<LifeTimeInterval> Optimizer::lifeTimeIntervals() const +LifeTimeIntervals::Ptr Optimizer::lifeTimeIntervals() const { Q_ASSERT(isInSSA()); @@ -4021,8 +4824,6 @@ static inline bool overlappingStorage(const Temp &t1, const Temp &t2) // This is the same as the operator==, but for one detail: memory locations are not sensitive // to types, and neither are general-purpose registers. - if (t1.scope != t2.scope) - return false; if (t1.index != t2.index) return false; // different position, where-ever that may (physically) be. if (t1.kind != t2.kind) @@ -4103,7 +4904,7 @@ QList<IR::Move *> MoveMapping::insertMoves(BasicBlock *bb, IR::Function *functio int insertionPoint = atEnd ? bb->statements().size() - 1 : 0; foreach (const Move &m, _moves) { - IR::Move *move = function->New<IR::Move>(); + IR::Move *move = function->NewStmt<IR::Move>(); move->init(clone(m.to, function), clone(m.from, function)); move->swap = m.needsSwap; bb->insertStatementBefore(insertionPoint++, move); diff --git a/src/qml/compiler/qv4ssa_p.h b/src/qml/compiler/qv4ssa_p.h index 372fe5cdeb..8a2241641e 100644 --- a/src/qml/compiler/qv4ssa_p.h +++ b/src/qml/compiler/qv4ssa_p.h @@ -43,6 +43,7 @@ #define QV4SSA_P_H #include "qv4jsir_p.h" +#include <QtCore/QSharedPointer> QT_BEGIN_NAMESPACE class QTextStream; @@ -57,7 +58,7 @@ public: int start; int end; - Range(int start = Invalid, int end = Invalid) + Range(int start = InvalidPosition, int end = InvalidPosition) : start(start) , end(end) {} @@ -75,22 +76,23 @@ private: unsigned _isSplitFromInterval : 1; public: - enum { Invalid = -1 }; + enum { InvalidPosition = -1 }; + enum { InvalidRegister = -1 }; explicit LifeTimeInterval(int rangeCapacity = 2) - : _end(Invalid) - , _reg(Invalid) + : _end(InvalidPosition) + , _reg(InvalidRegister) , _isFixedInterval(0) , _isSplitFromInterval(0) { _ranges.reserve(rangeCapacity); } - bool isValid() const { return _end != Invalid; } + bool isValid() const { return _end != InvalidRegister; } void setTemp(const Temp &temp) { this->_temp = temp; } Temp temp() const { return _temp; } bool isFP() const { return _temp.type == IR::DoubleType; } - void setFrom(Stmt *from); + void setFrom(int from); void addRange(int from, int to); const Ranges &ranges() const { return _ranges; } @@ -98,15 +100,13 @@ public: int end() const { return _end; } bool covers(int position) const { - foreach (const Range &r, _ranges) { - if (r.covers(position)) + for (int i = 0, ei = _ranges.size(); i != ei; ++i) { + if (_ranges.at(i).covers(position)) return true; } return false; } - int firstPossibleUsePosition(bool isPhiTarget) const { return start() + (isSplitFromInterval() || isPhiTarget ? 0 : 1); } - int reg() const { return _reg; } void setReg(int reg) { Q_ASSERT(!_isFixedInterval); _reg = reg; } @@ -118,13 +118,13 @@ public: void setSplitFromInterval(bool isSplitFromInterval) { _isSplitFromInterval = isSplitFromInterval; } void dump(QTextStream &out) const; - static bool lessThan(const LifeTimeInterval &r1, const LifeTimeInterval &r2); - static bool lessThanForTemp(const LifeTimeInterval &r1, const LifeTimeInterval &r2); + static bool lessThan(const LifeTimeInterval *r1, const LifeTimeInterval *r2); + static bool lessThanForTemp(const LifeTimeInterval *r1, const LifeTimeInterval *r2); void validate() const { #if !defined(QT_NO_DEBUG) // Validate the new range - if (_end != Invalid) { + if (_end != InvalidPosition) { Q_ASSERT(!_ranges.isEmpty()); foreach (const Range &range, _ranges) { Q_ASSERT(range.start >= 0); @@ -136,6 +136,78 @@ public: } }; +class LifeTimeIntervals +{ + Q_DISABLE_COPY(LifeTimeIntervals) + + LifeTimeIntervals(IR::Function *function); + void renumber(IR::Function *function); + +public: + typedef QSharedPointer<LifeTimeIntervals> Ptr; + static Ptr create(IR::Function *function) + { return Ptr(new LifeTimeIntervals(function)); } + + ~LifeTimeIntervals(); + + // takes ownership of the pointer + void add(LifeTimeInterval *interval) + { _intervals.append(interval); } + + // After calling Optimizer::lifeTimeIntervals() the result will have all intervals in descending order of start position. + QVector<LifeTimeInterval *> intervals() const + { return _intervals; } + + int size() const + { return _intervals.size(); } + + int positionForStatement(Stmt *stmt) const + { + Q_ASSERT(stmt->id() >= 0); + if (static_cast<unsigned>(stmt->id()) < _positionForStatement.size()) + return _positionForStatement[stmt->id()]; + + return Stmt::InvalidId; + } + + int startPosition(BasicBlock *bb) const + { + Q_ASSERT(bb->index() >= 0); + Q_ASSERT(static_cast<unsigned>(bb->index()) < _basicBlockPosition.size()); + + return _basicBlockPosition.at(bb->index()).start; + } + + int endPosition(BasicBlock *bb) const + { + Q_ASSERT(bb->index() >= 0); + Q_ASSERT(static_cast<unsigned>(bb->index()) < _basicBlockPosition.size()); + + return _basicBlockPosition.at(bb->index()).end; + } + + int lastPosition() const + { + return _lastPosition; + } + +private: + struct BasicBlockPositions { + int start; + int end; + + BasicBlockPositions() + : start(IR::Stmt::InvalidId) + , end(IR::Stmt::InvalidId) + {} + }; + + std::vector<BasicBlockPositions> _basicBlockPosition; + std::vector<int> _positionForStatement; + QVector<LifeTimeInterval *> _intervals; + int _lastPosition; +}; + class Q_QML_PRIVATE_EXPORT Optimizer { Q_DISABLE_COPY(Optimizer) @@ -151,7 +223,7 @@ public: QHash<BasicBlock *, BasicBlock *> loopStartEndBlocks() const { return startEndLoops; } - QVector<LifeTimeInterval> lifeTimeIntervals() const; + LifeTimeIntervals::Ptr lifeTimeIntervals() const; QSet<IR::Jump *> calculateOptionalJumps(); diff --git a/src/qml/debugger/qqmlprofilerdefinitions_p.h b/src/qml/debugger/qqmlprofilerdefinitions_p.h index 9452260ce4..689a06a0d1 100644 --- a/src/qml/debugger/qqmlprofilerdefinitions_p.h +++ b/src/qml/debugger/qqmlprofilerdefinitions_p.h @@ -67,6 +67,7 @@ struct QQmlProfilerDefinitions { Complete, // end of transmission PixmapCacheEvent, SceneGraphFrame, + MemoryAllocation, MaximumMessage }; @@ -122,7 +123,7 @@ struct QQmlProfilerDefinitions { SceneGraphPolishAndSync, SceneGraphWindowsRenderShow, SceneGraphWindowsAnimations, - SceneGraphWindowsPolishFrame, + SceneGraphPolishFrame, MaximumSceneGraphFrameType }; diff --git a/src/qml/debugger/qv4profileradapter.cpp b/src/qml/debugger/qv4profileradapter.cpp index e7b82566d6..cdceb0e533 100644 --- a/src/qml/debugger/qv4profileradapter.cpp +++ b/src/qml/debugger/qv4profileradapter.cpp @@ -58,26 +58,47 @@ QV4ProfilerAdapter::QV4ProfilerAdapter(QQmlProfilerService *service, QV4::Execut connect(this, SIGNAL(dataRequested()), engine->profiler, SLOT(reportData())); connect(this, SIGNAL(referenceTimeKnown(QElapsedTimer)), engine->profiler, SLOT(setTimer(QElapsedTimer))); - connect(engine->profiler, SIGNAL(dataReady(QList<QV4::Profiling::FunctionCallProperties>)), - this, SLOT(receiveData(QList<QV4::Profiling::FunctionCallProperties>))); + connect(engine->profiler, SIGNAL(dataReady(QList<QV4::Profiling::FunctionCallProperties>, + QList<QV4::Profiling::MemoryAllocationProperties>)), + this, SLOT(receiveData(QList<QV4::Profiling::FunctionCallProperties>, + QList<QV4::Profiling::MemoryAllocationProperties>))); } +qint64 QV4ProfilerAdapter::appendMemoryEvents(qint64 until, QList<QByteArray> &messages) +{ + QByteArray message; + while (!memory_data.empty() && memory_data.front().timestamp <= until) { + QQmlDebugStream d(&message, QIODevice::WriteOnly); + QV4::Profiling::MemoryAllocationProperties &props = memory_data.front(); + d << props.timestamp << MemoryAllocation << props.type << props.size; + memory_data.pop_front(); + messages.append(message); + } + return memory_data.empty() ? -1 : memory_data.front().timestamp; +} qint64 QV4ProfilerAdapter::sendMessages(qint64 until, QList<QByteArray> &messages) { QByteArray message; while (true) { while (!stack.empty() && (data.empty() || stack.top() <= data.front().start)) { - if (stack.top() > until) - return stack.top(); + if (stack.top() > until) { + qint64 memory_next = appendMemoryEvents(until, messages); + return memory_next == -1 ? stack.top() : qMin(stack.top(), memory_next); + } + appendMemoryEvents(stack.top(), messages); QQmlDebugStream d(&message, QIODevice::WriteOnly); d << stack.pop() << RangeEnd << Javascript; messages.append(message); } while (!data.empty() && (stack.empty() || data.front().start < stack.top())) { - if (data.front().start > until) - return data.front().start; const QV4::Profiling::FunctionCallProperties &props = data.front(); + if (props.start > until) { + qint64 memory_next = appendMemoryEvents(until, messages); + return memory_next == -1 ? props.start : qMin(props.start, memory_next); + } + appendMemoryEvents(props.start, messages); + QQmlDebugStream d_start(&message, QIODevice::WriteOnly); d_start << props.start << RangeStart << Javascript; messages.push_back(message); @@ -95,13 +116,15 @@ qint64 QV4ProfilerAdapter::sendMessages(qint64 until, QList<QByteArray> &message data.pop_front(); } if (stack.empty() && data.empty()) - return -1; + return appendMemoryEvents(until, messages); } } -void QV4ProfilerAdapter::receiveData(const QList<QV4::Profiling::FunctionCallProperties> &new_data) +void QV4ProfilerAdapter::receiveData(const QList<QV4::Profiling::FunctionCallProperties> &new_data, + const QList<QV4::Profiling::MemoryAllocationProperties> &new_memory_data) { data = new_data; + memory_data = new_memory_data; stack.clear(); service->dataReady(this); } diff --git a/src/qml/debugger/qv4profileradapter_p.h b/src/qml/debugger/qv4profileradapter_p.h index 922aedd828..29bdd606ef 100644 --- a/src/qml/debugger/qv4profileradapter_p.h +++ b/src/qml/debugger/qv4profileradapter_p.h @@ -71,11 +71,14 @@ public: virtual qint64 sendMessages(qint64 until, QList<QByteArray> &messages); public slots: - void receiveData(const QList<QV4::Profiling::FunctionCallProperties> &); + void receiveData(const QList<QV4::Profiling::FunctionCallProperties> &, + const QList<QV4::Profiling::MemoryAllocationProperties> &); private: QList<QV4::Profiling::FunctionCallProperties> data; + QList<QV4::Profiling::MemoryAllocationProperties> memory_data; QStack<qint64> stack; + qint64 appendMemoryEvents(qint64 until, QList<QByteArray> &messages); }; QT_END_NAMESPACE diff --git a/src/qml/doc/qtqml.qdocconf b/src/qml/doc/qtqml.qdocconf index d691dbfd8a..418a330d2c 100644 --- a/src/qml/doc/qtqml.qdocconf +++ b/src/qml/doc/qtqml.qdocconf @@ -28,7 +28,7 @@ qhp.QtQml.subprojects.examples.indexTitle = Qt Quick Examples and Tutorials qhp.QtQml.subprojects.examples.selectors = fake:example qhp.QtQml.subprojects.qmltypes.title = QML Types qhp.QtQml.subprojects.qmltypes.indexTitle = Qt QML QML Types -qhp.QtQml.subprojects.qmltypes.selectors = fake:qmlclass +qhp.QtQml.subprojects.qmltypes.selectors = qmlclass qhp.QtQml.subprojects.qmltypes.sortPages = true diff --git a/src/qml/doc/src/qmlfunctions.qdoc b/src/qml/doc/src/qmlfunctions.qdoc index d3d3174193..e95784dc5c 100644 --- a/src/qml/doc/src/qmlfunctions.qdoc +++ b/src/qml/doc/src/qmlfunctions.qdoc @@ -157,6 +157,44 @@ */ /*! + \fn int qmlRegisterExtendedUncreatableType(const char *uri, int versionMajor, int versionMinor, const char *qmlName, const QString& message) + \relates QQmlEgine + + This template function registers the C++ type and its extension + in the QML system with the name \a qmlName in the library imported + from \a uri having version number composed from \a versionMajor and + \a versionMinor. + + While the type has a name and a type, it cannot be created, and the + given error \a message will result if creation is attempted. + + This is useful where the type is only intended for providing attached + properties, enum values or an abstract base class with its extension. + + Returns the QML type id. + + #include <QtQml> to use this function. + + \sa qmlRegisterUncreatableType() +*/ + +/*! + \fn int qmlRegisterCustomExtendedType(const char *uri, int versionMajor, int versionMinor, const char *qmlName, QQmlCustomParser *parser) + \relates QQmlEgine + + This template function registers the C++ type and its extension + in the QML system with the name \a qmlName in the library imported + from \a uri having version number composed from \a versionMajor and + \a versionMinor. Properties from the C++ type or its extension that + cannot be resolved directly by the QML system will be resolved using + the \a parser provided. + + Returns the QML type id. + + #include <QtQml> to use this function. +*/ + +/*! \fn int qmlRegisterTypeNotAvailable(const char *uri, int versionMajor, int versionMinor, const char *qmlName, const QString& message) \relates QQmlEngine diff --git a/src/qml/jit/jit.pri b/src/qml/jit/jit.pri index 151ff32df9..7ea4e951d5 100644 --- a/src/qml/jit/jit.pri +++ b/src/qml/jit/jit.pri @@ -6,9 +6,11 @@ INCLUDEPATH += $$OUT_PWD HEADERS += \ $$PWD/qv4assembler_p.h \ $$PWD/qv4regalloc_p.h \ + $$PWD/qv4targetplatform_p.h \ $$PWD/qv4isel_masm_p.h \ $$PWD/qv4binop_p.h \ $$PWD/qv4unop_p.h \ + $$PWD/qv4registerinfo_p.h SOURCES += \ $$PWD/qv4assembler.cpp \ diff --git a/src/qml/jit/qv4assembler.cpp b/src/qml/jit/qv4assembler.cpp index cd44b537df..cb2279b336 100644 --- a/src/qml/jit/qv4assembler.cpp +++ b/src/qml/jit/qv4assembler.cpp @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). +** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies). ** Contact: http://www.qt-project.org/legal ** ** This file is part of the QtQml module of the Qt Toolkit. @@ -91,58 +91,6 @@ QV4::ExecutableAllocator::ChunkOfPages *CompilationUnit::chunkForFunction(int fu return handle->chunk(); } - - -/* Platform/Calling convention/Architecture specific section */ - -#if CPU(X86_64) -# if OS(LINUX) || OS(MAC_OS_X) -static const Assembler::RegisterID calleeSavedRegisters[] = { - JSC::X86Registers::ebx, - JSC::X86Registers::r12, // LocalsRegister - JSC::X86Registers::r13, - JSC::X86Registers::r14, // ContextRegister - JSC::X86Registers::r15 -}; -# elif OS(WINDOWS) -static const Assembler::RegisterID calleeSavedRegisters[] = { - JSC::X86Registers::ebx, - JSC::X86Registers::esi, - JSC::X86Registers::edi, - JSC::X86Registers::r12, // LocalsRegister - JSC::X86Registers::r13, - JSC::X86Registers::r14, // ContextRegister - JSC::X86Registers::r15 -}; -# endif -#endif - -#if CPU(X86) -static const Assembler::RegisterID calleeSavedRegisters[] = { - JSC::X86Registers::ebx, // temporary register - JSC::X86Registers::esi, // ContextRegister - JSC::X86Registers::edi // LocalsRegister -}; -#endif - -#if CPU(ARM) -static const Assembler::RegisterID calleeSavedRegisters[] = { - JSC::ARMRegisters::r11, - JSC::ARMRegisters::r10, - JSC::ARMRegisters::r9, - JSC::ARMRegisters::r8, - JSC::ARMRegisters::r7, - JSC::ARMRegisters::r6, - JSC::ARMRegisters::r5, - JSC::ARMRegisters::r4 -}; -#endif - -const int Assembler::calleeSavedRegisterCount = sizeof(calleeSavedRegisters) / sizeof(calleeSavedRegisters[0]); - -/* End of platform/calling convention/architecture specific section */ - - const Assembler::VoidType Assembler::Void; Assembler::Assembler(InstructionSelection *isel, IR::Function* function, QV4::ExecutableAllocator *executableAllocator, @@ -223,33 +171,47 @@ void Assembler::generateCJumpOnCompare(RelationalCondition cond, RegisterID left } } -Assembler::Pointer Assembler::loadTempAddress(RegisterID baseReg, IR::Temp *t) +Assembler::Pointer Assembler::loadAddress(RegisterID tmp, IR::Expr *e) +{ + IR::Temp *t = e->asTemp(); + if (t) + return loadTempAddress(t); + else + return loadArgLocalAddress(tmp, e->asArgLocal()); +} + +Assembler::Pointer Assembler::loadTempAddress(IR::Temp *t) +{ + if (t->kind == IR::Temp::StackSlot) + return stackSlotPointer(t); + else + Q_UNREACHABLE(); +} + +Assembler::Pointer Assembler::loadArgLocalAddress(RegisterID baseReg, IR::ArgLocal *al) { int32_t offset = 0; - int scope = t->scope; + int scope = al->scope; RegisterID context = ContextRegister; if (scope) { - loadPtr(Address(ContextRegister, qOffsetOf(ExecutionContext, outer)), baseReg); + loadPtr(Address(ContextRegister, qOffsetOf(ExecutionContext::Data, outer)), baseReg); --scope; context = baseReg; while (scope) { - loadPtr(Address(context, qOffsetOf(ExecutionContext, outer)), context); + loadPtr(Address(context, qOffsetOf(ExecutionContext::Data, outer)), context); --scope; } } - switch (t->kind) { - case IR::Temp::Formal: - case IR::Temp::ScopedFormal: { - loadPtr(Address(context, qOffsetOf(ExecutionContext, callData)), baseReg); - offset = sizeof(CallData) + (t->index - 1) * sizeof(Value); + switch (al->kind) { + case IR::ArgLocal::Formal: + case IR::ArgLocal::ScopedFormal: { + loadPtr(Address(context, qOffsetOf(ExecutionContext::Data, callData)), baseReg); + offset = sizeof(CallData) + (al->index - 1) * sizeof(Value); } break; - case IR::Temp::Local: - case IR::Temp::ScopedLocal: { - loadPtr(Address(context, qOffsetOf(CallContext, locals)), baseReg); - offset = t->index * sizeof(Value); - } break; - case IR::Temp::StackSlot: { - return stackSlotPointer(t); + case IR::ArgLocal::Local: + case IR::ArgLocal::ScopedLocal: { + loadPtr(Address(context, qOffsetOf(CallContext::Data, locals)), baseReg); + offset = al->index * sizeof(Value); } break; default: Q_UNREACHABLE(); @@ -259,7 +221,7 @@ Assembler::Pointer Assembler::loadTempAddress(RegisterID baseReg, IR::Temp *t) Assembler::Pointer Assembler::loadStringAddress(RegisterID reg, const QString &string) { - loadPtr(Address(Assembler::ContextRegister, qOffsetOf(QV4::ExecutionContext, compilationUnit)), Assembler::ScratchRegister); + loadPtr(Address(Assembler::ContextRegister, qOffsetOf(QV4::ExecutionContext::Data, compilationUnit)), Assembler::ScratchRegister); loadPtr(Address(Assembler::ScratchRegister, qOffsetOf(QV4::CompiledData::CompilationUnit, runtimeStrings)), reg); const int id = _isel->registerString(string); return Pointer(reg, id * sizeof(QV4::StringValue)); @@ -267,21 +229,21 @@ Assembler::Pointer Assembler::loadStringAddress(RegisterID reg, const QString &s void Assembler::loadStringRef(RegisterID reg, const QString &string) { - loadPtr(Address(Assembler::ContextRegister, qOffsetOf(QV4::ExecutionContext, compilationUnit)), reg); + loadPtr(Address(Assembler::ContextRegister, qOffsetOf(QV4::ExecutionContext::Data, compilationUnit)), reg); loadPtr(Address(reg, qOffsetOf(QV4::CompiledData::CompilationUnit, runtimeStrings)), reg); const int id = _isel->registerString(string); - addPtr(TrustedImmPtr(id * sizeof(QV4::StringValue)), reg); + loadPtr(Address(reg, id * sizeof(QV4::StringValue)), reg); } -void Assembler::storeValue(QV4::Primitive value, IR::Temp* destination) +void Assembler::storeValue(QV4::Primitive value, IR::Expr *destination) { - Address addr = loadTempAddress(ScratchRegister, destination); + Address addr = loadAddress(ScratchRegister, destination); storeValue(value, addr); } void Assembler::enterStandardStackFrame() { - platformEnterStandardStackFrame(); + platformEnterStandardStackFrame(this); // ### FIXME: Handle through calleeSavedRegisters mechanism // or eliminate StackFrameRegister altogether. @@ -292,16 +254,18 @@ void Assembler::enterStandardStackFrame() subPtr(TrustedImm32(frameSize), StackPointerRegister); - for (int i = 0; i < calleeSavedRegisterCount; ++i) - storePtr(calleeSavedRegisters[i], Address(StackFrameRegister, -(i + 1) * sizeof(void*))); + const RegisterInformation &calleeSavedRegisters = getCalleeSavedRegisters(); + for (int i = 0; i < calleeSavedRegisterCount(); ++i) + storePtr(calleeSavedRegisters[i].reg<RegisterID>(), Address(StackFrameRegister, -(i + 1) * sizeof(void*))); } void Assembler::leaveStandardStackFrame() { // restore the callee saved registers - for (int i = calleeSavedRegisterCount - 1; i >= 0; --i) - loadPtr(Address(StackFrameRegister, -(i + 1) * sizeof(void*)), calleeSavedRegisters[i]); + const RegisterInformation &calleeSavedRegisters = getCalleeSavedRegisters(); + for (int i = calleeSavedRegisterCount() - 1; i >= 0; --i) + loadPtr(Address(StackFrameRegister, -(i + 1) * sizeof(void*)), calleeSavedRegisters[i].reg<RegisterID>()); int frameSize = _stackLayout.calculateStackFrameSize(); // Work around bug in ARMv7Assembler.h where add32(imm, sp, sp) doesn't @@ -314,7 +278,7 @@ void Assembler::leaveStandardStackFrame() #endif pop(StackFrameRegister); - platformLeaveStandardStackFrame(); + platformLeaveStandardStackFrame(this); } @@ -347,13 +311,12 @@ Assembler::Jump Assembler::genTryDoubleConversion(IR::Expr *src, Assembler::FPRe break; } - IR::Temp *sourceTemp = src->asTemp(); - Q_ASSERT(sourceTemp); + Q_ASSERT(src->asTemp() || src->asArgLocal()); // It's not a number type, so it cannot be in a register. - Q_ASSERT(sourceTemp->kind != IR::Temp::PhysicalRegister || sourceTemp->type == IR::BoolType); + Q_ASSERT(src->asArgLocal() || src->asTemp()->kind != IR::Temp::PhysicalRegister || src->type == IR::BoolType); - Assembler::Pointer tagAddr = loadTempAddress(Assembler::ScratchRegister, sourceTemp); + Assembler::Pointer tagAddr = loadAddress(Assembler::ScratchRegister, src); tagAddr.offset += 4; load32(tagAddr, Assembler::ScratchRegister); diff --git a/src/qml/jit/qv4assembler_p.h b/src/qml/jit/qv4assembler_p.h index 6fde517e1f..5e1f162f39 100644 --- a/src/qml/jit/qv4assembler_p.h +++ b/src/qml/jit/qv4assembler_p.h @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). +** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies). ** Contact: http://www.qt-project.org/legal ** ** This file is part of the QtQml module of the Qt Toolkit. @@ -47,6 +47,7 @@ #include "private/qv4isel_util_p.h" #include "private/qv4value_p.h" #include "private/qv4lookup_p.h" +#include "qv4targetplatform_p.h" #include <QtCore/QHash> #include <QtCore/QStack> @@ -123,158 +124,12 @@ struct ExceptionCheck<void (*)(QV4::NoThrowContext *, A, B, C)> { enum { NeedsCheck = 0 }; }; -class Assembler : public JSC::MacroAssembler +class Assembler : public JSC::MacroAssembler, public TargetPlatform { public: Assembler(InstructionSelection *isel, IR::Function* function, QV4::ExecutableAllocator *executableAllocator, int maxArgCountForBuiltins); -#if CPU(X86) - -#undef VALUE_FITS_IN_REGISTER -#undef ARGUMENTS_IN_REGISTERS - -#define HAVE_ALU_OPS_WITH_MEM_OPERAND 1 - - static const RegisterID StackFrameRegister = JSC::X86Registers::ebp; - static const RegisterID StackPointerRegister = JSC::X86Registers::esp; - static const RegisterID LocalsRegister = JSC::X86Registers::edi; - static const RegisterID ContextRegister = JSC::X86Registers::esi; - static const RegisterID ReturnValueRegister = JSC::X86Registers::eax; - static const RegisterID ScratchRegister = JSC::X86Registers::ecx; - static const FPRegisterID FPGpr0 = JSC::X86Registers::xmm0; - static const FPRegisterID FPGpr1 = JSC::X86Registers::xmm1; - - static const int RegisterSize = 4; - - static const int RegisterArgumentCount = 0; - static RegisterID registerForArgument(int) - { - Q_ASSERT(false); - // Not reached. - return JSC::X86Registers::eax; - } - - // Return address is pushed onto stack by the CPU. - static const int StackSpaceAllocatedUponFunctionEntry = RegisterSize; - static const int StackShadowSpace = 0; - inline void platformEnterStandardStackFrame() {} - inline void platformLeaveStandardStackFrame() {} -#elif CPU(X86_64) - -#define VALUE_FITS_IN_REGISTER -#define ARGUMENTS_IN_REGISTERS -#define HAVE_ALU_OPS_WITH_MEM_OPERAND 1 - - static const RegisterID StackFrameRegister = JSC::X86Registers::ebp; - static const RegisterID StackPointerRegister = JSC::X86Registers::esp; - static const RegisterID LocalsRegister = JSC::X86Registers::r12; - static const RegisterID ContextRegister = JSC::X86Registers::r14; - static const RegisterID ReturnValueRegister = JSC::X86Registers::eax; - static const RegisterID ScratchRegister = JSC::X86Registers::r10; - static const FPRegisterID FPGpr0 = JSC::X86Registers::xmm0; - static const FPRegisterID FPGpr1 = JSC::X86Registers::xmm1; - - static const int RegisterSize = 8; - -#if OS(WINDOWS) - static const int RegisterArgumentCount = 4; - static RegisterID registerForArgument(int index) - { - static RegisterID regs[RegisterArgumentCount] = { - JSC::X86Registers::ecx, - JSC::X86Registers::edx, - JSC::X86Registers::r8, - JSC::X86Registers::r9 - }; - Q_ASSERT(index >= 0 && index < RegisterArgumentCount); - return regs[index]; - }; - static const int StackShadowSpace = 32; -#else // Unix - static const int RegisterArgumentCount = 6; - static RegisterID registerForArgument(int index) - { - static RegisterID regs[RegisterArgumentCount] = { - JSC::X86Registers::edi, - JSC::X86Registers::esi, - JSC::X86Registers::edx, - JSC::X86Registers::ecx, - JSC::X86Registers::r8, - JSC::X86Registers::r9 - }; - Q_ASSERT(index >= 0 && index < RegisterArgumentCount); - return regs[index]; - }; - static const int StackShadowSpace = 0; -#endif - - // Return address is pushed onto stack by the CPU. - static const int StackSpaceAllocatedUponFunctionEntry = RegisterSize; - inline void platformEnterStandardStackFrame() {} - inline void platformLeaveStandardStackFrame() {} -#elif CPU(ARM) - -#undef VALUE_FITS_IN_REGISTER -#define ARGUMENTS_IN_REGISTERS -#undef HAVE_ALU_OPS_WITH_MEM_OPERAND - - static const RegisterID StackPointerRegister = JSC::ARMRegisters::sp; // r13 - static const RegisterID StackFrameRegister = JSC::ARMRegisters::fp; // r11 - static const RegisterID LocalsRegister = JSC::ARMRegisters::r7; - static const RegisterID ScratchRegister = JSC::ARMRegisters::r6; - static const RegisterID ContextRegister = JSC::ARMRegisters::r5; - static const RegisterID ReturnValueRegister = JSC::ARMRegisters::r0; - static const FPRegisterID FPGpr0 = JSC::ARMRegisters::d0; - static const FPRegisterID FPGpr1 = JSC::ARMRegisters::d1; - - static const int RegisterSize = 4; - - static const RegisterID RegisterArgument1 = JSC::ARMRegisters::r0; - static const RegisterID RegisterArgument2 = JSC::ARMRegisters::r1; - static const RegisterID RegisterArgument3 = JSC::ARMRegisters::r2; - static const RegisterID RegisterArgument4 = JSC::ARMRegisters::r3; - - static const int RegisterArgumentCount = 4; - static RegisterID registerForArgument(int index) - { - Q_ASSERT(index >= 0 && index < RegisterArgumentCount); - return static_cast<RegisterID>(JSC::ARMRegisters::r0 + index); - }; - - // Registers saved in platformEnterStandardStackFrame below. - static const int StackSpaceAllocatedUponFunctionEntry = 5 * RegisterSize; - static const int StackShadowSpace = 0; - inline void platformEnterStandardStackFrame() - { - // Move the register arguments onto the stack as if they were - // pushed by the caller, just like on ia32. This gives us consistent - // access to the parameters if we need to. - push(JSC::ARMRegisters::r3); - push(JSC::ARMRegisters::r2); - push(JSC::ARMRegisters::r1); - push(JSC::ARMRegisters::r0); - push(JSC::ARMRegisters::lr); - } - inline void platformLeaveStandardStackFrame() - { - pop(JSC::ARMRegisters::lr); - addPtr(TrustedImm32(4 * RegisterSize), StackPointerRegister); - } -#else -#error The JIT needs to be ported to this platform. -#endif - static const int calleeSavedRegisterCount; - -#if CPU(X86) || CPU(X86_64) - static const int StackAlignment = 16; -#elif CPU(ARM) - // Per AAPCS - static const int StackAlignment = 8; -#else -#error Stack alignment unknown for this platform. -#endif - // Explicit type to allow distinguishing between // pushing an address itself or the value it points // to onto the stack when calling functions. @@ -318,7 +173,7 @@ public: { public: StackLayout(IR::Function *function, int maxArgCountForBuiltins) - : calleeSavedRegCount(Assembler::calleeSavedRegisterCount + 1) + : calleeSavedRegCount(Assembler::calleeSavedRegisterCount() + 1) , maxOutgoingArgumentCount(function->maxNumberOfArguments) , localCount(function->tempCount) , savedRegCount(maxArgCountForBuiltins) @@ -351,7 +206,7 @@ public: + RegisterSize; // saved StackFrameRegister // space for the callee saved registers - int frameSize = RegisterSize * calleeSavedRegisterCount; + int frameSize = RegisterSize * calleeSavedRegisterCount(); frameSize += savedRegCount * sizeof(QV4::Value); // these get written out as Values, not as native registers Q_ASSERT(frameSize + stackSpaceAllocatedOtherwise < INT_MAX); @@ -460,8 +315,10 @@ public: QString string; }; struct Reference { - Reference(IR::Temp *value) : value(value) {} - IR::Temp *value; + Reference(IR::Expr *value) : value(value) { + Q_ASSERT(value->asTemp() || value->asArgLocal()); + } + IR::Expr *value; }; struct ReentryBlock { @@ -504,13 +361,14 @@ public: Jump genTryDoubleConversion(IR::Expr *src, Assembler::FPRegisterID dest); Assembler::Jump branchDouble(bool invertCondition, IR::AluOp op, IR::Expr *left, IR::Expr *right); - Pointer loadTempAddress(RegisterID baseReg, IR::Temp *t); + Pointer loadAddress(RegisterID tmp, IR::Expr *t); + Pointer loadTempAddress(IR::Temp *t); + Pointer loadArgLocalAddress(RegisterID baseReg, IR::ArgLocal *al); Pointer loadStringAddress(RegisterID reg, const QString &string); void loadStringRef(RegisterID reg, const QString &string); Pointer stackSlotPointer(IR::Temp *t) const { Q_ASSERT(t->kind == IR::Temp::StackSlot); - Q_ASSERT(t->scope == 0); return Pointer(_stackLayout.stackSlotPointer(t->index)); } @@ -585,7 +443,7 @@ public: void loadArgumentInRegister(Reference temp, RegisterID dest, int argumentNumber) { Q_ASSERT(temp.value); - Pointer addr = loadTempAddress(dest, temp.value); + Pointer addr = loadAddress(dest, temp.value); loadArgumentInRegister(addr, dest, argumentNumber); } @@ -603,12 +461,25 @@ public: { Q_UNUSED(argumentNumber); - if (!temp) { + if (temp) { + Pointer addr = loadTempAddress(temp); + load64(addr, dest); + } else { QV4::Value undefined = QV4::Primitive::undefinedValue(); move(TrustedImm64(undefined.val), dest); - } else { - Pointer addr = loadTempAddress(dest, temp); + } + } + + void loadArgumentInRegister(IR::ArgLocal* al, RegisterID dest, int argumentNumber) + { + Q_UNUSED(argumentNumber); + + if (al) { + Pointer addr = loadArgLocalAddress(dest, al); load64(addr, dest); + } else { + QV4::Value undefined = QV4::Primitive::undefinedValue(); + move(TrustedImm64(undefined.val), dest); } } @@ -627,10 +498,12 @@ public: if (!expr) { QV4::Value undefined = QV4::Primitive::undefinedValue(); move(TrustedImm64(undefined.val), dest); - } else if (expr->asTemp()){ - loadArgumentInRegister(expr->asTemp(), dest, argumentNumber); - } else if (expr->asConst()) { - loadArgumentInRegister(expr->asConst(), dest, argumentNumber); + } else if (IR::Temp *t = expr->asTemp()){ + loadArgumentInRegister(t, dest, argumentNumber); + } else if (IR::ArgLocal *al = expr->asArgLocal()) { + loadArgumentInRegister(al, dest, argumentNumber); + } else if (IR::Const *c = expr->asConst()) { + loadArgumentInRegister(c, dest, argumentNumber); } else { Q_ASSERT(!"unimplemented expression type in loadArgument"); } @@ -704,20 +577,26 @@ public: } #endif - void storeReturnValue(IR::Temp *temp) + void storeReturnValue(IR::Expr *target) { - if (!temp) + if (!target) return; - 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); - } else { - Pointer addr = loadTempAddress(ScratchRegister, temp); + 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); } } @@ -775,7 +654,7 @@ public: { Q_ASSERT (temp.value); - Pointer ptr = loadTempAddress(ScratchRegister, temp.value); + Pointer ptr = loadAddress(ScratchRegister, temp.value); loadArgumentOnStack<StackSlot>(ptr, argumentNumber); } @@ -807,30 +686,32 @@ public: poke(TrustedImmPtr(name), StackSlot); } - void loadDouble(IR::Temp* temp, FPRegisterID dest) + void loadDouble(IR::Expr *source, FPRegisterID dest) { - if (temp->kind == IR::Temp::PhysicalRegister) { - moveDouble((FPRegisterID) temp->index, dest); + IR::Temp *sourceTemp = source->asTemp(); + if (sourceTemp && sourceTemp->kind == IR::Temp::PhysicalRegister) { + moveDouble((FPRegisterID) sourceTemp->index, dest); return; } - Pointer ptr = loadTempAddress(ScratchRegister, temp); + Pointer ptr = loadAddress(ScratchRegister, source); loadDouble(ptr, dest); } - void storeDouble(FPRegisterID source, IR::Temp* temp) + void storeDouble(FPRegisterID source, IR::Expr* target) { - if (temp->kind == IR::Temp::PhysicalRegister) { - moveDouble(source, (FPRegisterID) temp->index); + IR::Temp *targetTemp = target->asTemp(); + if (targetTemp && targetTemp->kind == IR::Temp::PhysicalRegister) { + moveDouble(source, (FPRegisterID) targetTemp->index); return; } #if QT_POINTER_SIZE == 8 moveDoubleTo64(source, ReturnValueRegister); move(TrustedImm64(QV4::Value::NaNEncodeMask), ScratchRegister); xor64(ScratchRegister, ReturnValueRegister); - Pointer ptr = loadTempAddress(ScratchRegister, temp); + Pointer ptr = loadAddress(ScratchRegister, target); store64(ReturnValueRegister, ptr); #else - Pointer ptr = loadTempAddress(ScratchRegister, temp); + Pointer ptr = loadAddress(ScratchRegister, target); storeDouble(source, ptr); #endif } @@ -862,11 +743,11 @@ public: void copyValue(Result result, IR::Expr* source); // The scratch register is used to calculate the temp address for the source. - void memcopyValue(Pointer target, IR::Temp *sourceTemp, RegisterID scratchRegister) + void memcopyValue(Pointer target, IR::Expr *source, RegisterID scratchRegister) { - Q_ASSERT(sourceTemp->kind != IR::Temp::PhysicalRegister); + Q_ASSERT(!source->asTemp() || source->asTemp()->kind != IR::Temp::PhysicalRegister); Q_ASSERT(target.base != scratchRegister); - JSC::MacroAssembler::loadDouble(loadTempAddress(scratchRegister, sourceTemp), FPGpr0); + JSC::MacroAssembler::loadDouble(loadAddress(scratchRegister, source), FPGpr0); JSC::MacroAssembler::storeDouble(FPGpr0, target); } @@ -888,13 +769,13 @@ public: #endif } - void storeValue(QV4::Primitive value, IR::Temp* temp); + void storeValue(QV4::Primitive value, IR::Expr* temp); void enterStandardStackFrame(); void leaveStandardStackFrame(); void checkException() { - loadPtr(Address(ContextRegister, qOffsetOf(QV4::ExecutionContext, engine)), ScratchRegister); + loadPtr(Address(ContextRegister, qOffsetOf(QV4::ExecutionContext::Data, engine)), ScratchRegister); load32(Address(ScratchRegister, qOffsetOf(QV4::ExecutionEngine, hasException)), ScratchRegister); Jump exceptionThrown = branch32(NotEqual, ScratchRegister, TrustedImm32(0)); if (catchBlock) @@ -988,10 +869,8 @@ public: prepareRelativeCall(function, this); loadArgumentOnStackOrRegister<0>(arg1); -#if (OS(LINUX) && CPU(X86) && (defined(__PIC__) || defined(__PIE__))) || \ - (OS(WINDOWS) && CPU(X86)) - load32(Address(StackFrameRegister, -int(sizeof(void*))), - JSC::X86Registers::ebx); // restore the GOT ptr +#ifdef RESTORE_EBX_ON_CALL + load32(ebxAddressOnStack(), JSC::X86Registers::ebx); // restore the GOT ptr #endif callAbsolute(functionName, function); @@ -1050,13 +929,11 @@ public: return Pointer(addr); } - IR::Temp *t = e->asTemp(); - Q_ASSERT(t); - if (t->kind != IR::Temp::PhysicalRegister) - return loadTempAddress(tmpReg, t); - + if (IR::Temp *t = e->asTemp()) + if (t->kind == IR::Temp::PhysicalRegister) + return Pointer(_stackLayout.savedRegPointer(offset)); - return Pointer(_stackLayout.savedRegPointer(offset)); + return loadAddress(tmpReg, e); } void storeBool(RegisterID reg, Pointer addr) @@ -1071,24 +948,31 @@ public: move(src, dest); } - void storeBool(RegisterID reg, IR::Temp *target) + void storeBool(RegisterID reg, IR::Expr *target) { - if (target->kind == IR::Temp::PhysicalRegister) { - move(reg, (RegisterID) target->index); - } else { - Pointer addr = loadTempAddress(ScratchRegister, target); - storeBool(reg, addr); + if (IR::Temp *targetTemp = target->asTemp()) { + if (targetTemp->kind == IR::Temp::PhysicalRegister) { + move(reg, (RegisterID) targetTemp->index); + return; + } } + + Pointer addr = loadAddress(ScratchRegister, target); + storeBool(reg, addr); } - void storeBool(bool value, IR::Temp *target) { + void storeBool(bool value, IR::Expr *target) { TrustedImm32 trustedValue(value ? 1 : 0); - if (target->kind == IR::Temp::PhysicalRegister) { - move(trustedValue, (RegisterID) target->index); - } else { - move(trustedValue, ScratchRegister); - storeBool(ScratchRegister, target); + + if (IR::Temp *targetTemp = target->asTemp()) { + if (targetTemp->kind == IR::Temp::PhysicalRegister) { + move(trustedValue, (RegisterID) targetTemp->index); + return; + } } + + move(trustedValue, ScratchRegister); + storeBool(ScratchRegister, target); } void storeInt32(RegisterID src, RegisterID dest) @@ -1103,12 +987,17 @@ public: store32(TrustedImm32(QV4::Primitive::fromInt32(0).tag), addr); } - void storeInt32(RegisterID reg, IR::Temp *target) + void storeInt32(RegisterID reg, IR::Expr *target) { - if (target->kind == IR::Temp::PhysicalRegister) { - move(reg, (RegisterID) target->index); - } else { - Pointer addr = loadTempAddress(ScratchRegister, 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); } } @@ -1130,12 +1019,13 @@ public: done.link(this); } - void storeUInt32(RegisterID reg, IR::Temp *target) + void storeUInt32(RegisterID reg, IR::Expr *target) { - if (target->kind == IR::Temp::PhysicalRegister) { - move(reg, (RegisterID) target->index); + IR::Temp *targetTemp = target->asTemp(); + if (targetTemp && targetTemp->kind == IR::Temp::PhysicalRegister) { + move(reg, (RegisterID) targetTemp->index); } else { - Pointer addr = loadTempAddress(ScratchRegister, target); + Pointer addr = loadAddress(ScratchRegister, target); storeUInt32(reg, addr); } } @@ -1157,12 +1047,11 @@ public: return target; } - IR::Temp *t = e->asTemp(); - Q_ASSERT(t); - if (t->kind == IR::Temp::PhysicalRegister) - return (FPRegisterID) t->index; + if (IR::Temp *t = e->asTemp()) + if (t->kind == IR::Temp::PhysicalRegister) + return (FPRegisterID) t->index; - loadDouble(t, target); + loadDouble(e, target); return target; } @@ -1178,12 +1067,11 @@ public: return scratchReg; } - IR::Temp *t = e->asTemp(); - Q_ASSERT(t); - if (t->kind == IR::Temp::PhysicalRegister) - return (RegisterID) t->index; + if (IR::Temp *t = e->asTemp()) + if (t->kind == IR::Temp::PhysicalRegister) + return (RegisterID) t->index; - return toInt32Register(loadTempAddress(scratchReg, t), scratchReg); + return toInt32Register(loadAddress(scratchReg, e), scratchReg); } RegisterID toInt32Register(Pointer addr, RegisterID scratchReg) @@ -1199,12 +1087,11 @@ public: return scratchReg; } - IR::Temp *t = e->asTemp(); - Q_ASSERT(t); - if (t->kind == IR::Temp::PhysicalRegister) - return (RegisterID) t->index; + if (IR::Temp *t = e->asTemp()) + if (t->kind == IR::Temp::PhysicalRegister) + return (RegisterID) t->index; - return toUInt32Register(loadTempAddress(scratchReg, t), scratchReg); + return toUInt32Register(loadAddress(scratchReg, e), scratchReg); } RegisterID toUInt32Register(Pointer addr, RegisterID scratchReg) @@ -1291,17 +1178,15 @@ void Assembler::copyValue(Result result, IR::Expr* source) storeUInt32(reg, result); } else if (source->type == IR::DoubleType) { storeDouble(toDoubleRegister(source), result); - } else if (IR::Temp *temp = source->asTemp()) { + } else if (source->asTemp() || source->asArgLocal()) { #ifdef VALUE_FITS_IN_REGISTER - Q_UNUSED(temp); - - // Use ReturnValueRegister as "scratch" register because loadArgument - // and storeArgument are functions that may need a scratch register themselves. - loadArgumentInRegister(source, ReturnValueRegister, 0); - storeReturnValue(result); + // Use ReturnValueRegister as "scratch" register because loadArgument + // and storeArgument are functions that may need a scratch register themselves. + loadArgumentInRegister(source, ReturnValueRegister, 0); + storeReturnValue(result); #else - loadDouble(temp, FPGpr0); - storeDouble(FPGpr0, result); + loadDouble(source, FPGpr0); + storeDouble(FPGpr0, result); #endif } else if (IR::Const *c = source->asConst()) { QV4::Primitive v = convertToValue(c); @@ -1316,7 +1201,7 @@ void Assembler::copyValue(Result result, IR::Expr* source) template <typename T> inline void prepareRelativeCall(const T &, Assembler *){} template <> inline void prepareRelativeCall(const RelativeCall &relativeCall, Assembler *as) { - as->loadPtr(Assembler::Address(Assembler::ContextRegister, qOffsetOf(QV4::ExecutionContext, lookups)), + as->loadPtr(Assembler::Address(Assembler::ContextRegister, qOffsetOf(QV4::ExecutionContext::Data, lookups)), relativeCall.addr.base); } diff --git a/src/qml/jit/qv4binop.cpp b/src/qml/jit/qv4binop.cpp index 344bbf56e0..a19072f52e 100644 --- a/src/qml/jit/qv4binop.cpp +++ b/src/qml/jit/qv4binop.cpp @@ -112,7 +112,7 @@ const Binop::OpInfo Binop::operations[IR::LastAluOp + 1] = { -void Binop::generate(IR::Expr *lhs, IR::Expr *rhs, IR::Temp *target) +void Binop::generate(IR::Expr *lhs, IR::Expr *rhs, IR::Expr *target) { if (op != IR::OpMod && lhs->type == IR::DoubleType && rhs->type == IR::DoubleType @@ -156,14 +156,15 @@ void Binop::generate(IR::Expr *lhs, IR::Expr *rhs, IR::Temp *target) } -void Binop::doubleBinop(IR::Expr *lhs, IR::Expr *rhs, IR::Temp *target) +void Binop::doubleBinop(IR::Expr *lhs, IR::Expr *rhs, IR::Expr *target) { Q_ASSERT(lhs->asConst() == 0 || rhs->asConst() == 0); Q_ASSERT(isPregOrConst(lhs)); Q_ASSERT(isPregOrConst(rhs)); + IR::Temp *targetTemp = target->asTemp(); Assembler::FPRegisterID targetReg; - if (target->kind == IR::Temp::PhysicalRegister) - targetReg = (Assembler::FPRegisterID) target->index; + if (targetTemp && targetTemp->kind == IR::Temp::PhysicalRegister) + targetReg = (Assembler::FPRegisterID) targetTemp->index; else targetReg = Assembler::FPGpr0; @@ -232,31 +233,33 @@ void Binop::doubleBinop(IR::Expr *lhs, IR::Expr *rhs, IR::Temp *target) } return; } - if (target->kind != IR::Temp::PhysicalRegister) + if (!targetTemp || targetTemp->kind != IR::Temp::PhysicalRegister) as->storeDouble(Assembler::FPGpr0, target); } -bool Binop::int32Binop(IR::Expr *leftSource, IR::Expr *rightSource, IR::Temp *target) +bool Binop::int32Binop(IR::Expr *leftSource, IR::Expr *rightSource, IR::Expr *target) { Q_ASSERT(leftSource->type == IR::SInt32Type); + IR::Temp *targetTemp = target->asTemp(); Assembler::RegisterID targetReg = Assembler::ReturnValueRegister; - if (target->kind == IR::Temp::PhysicalRegister) { + if (targetTemp && targetTemp->kind == IR::Temp::PhysicalRegister) { // We try to load leftSource into the target's register, but we can't do that if // the target register is the same as rightSource. IR::Temp *rhs = rightSource->asTemp(); - if (!rhs || rhs->kind != IR::Temp::PhysicalRegister || rhs->index != target->index) - targetReg = (Assembler::RegisterID) target->index; + if (!rhs || rhs->kind != IR::Temp::PhysicalRegister || rhs->index != targetTemp->index) + targetReg = (Assembler::RegisterID) targetTemp->index; } switch (op) { case IR::OpBitAnd: { Q_ASSERT(rightSource->type == IR::SInt32Type); if (rightSource->asTemp() && rightSource->asTemp()->kind == IR::Temp::PhysicalRegister - && target->kind == IR::Temp::PhysicalRegister - && target->index == rightSource->asTemp()->index) { + && targetTemp + && targetTemp->kind == IR::Temp::PhysicalRegister + && targetTemp->index == rightSource->asTemp()->index) { as->and32(as->toInt32Register(leftSource, Assembler::ScratchRegister), - (Assembler::RegisterID) target->index); + (Assembler::RegisterID) targetTemp->index); return true; } @@ -268,10 +271,11 @@ bool Binop::int32Binop(IR::Expr *leftSource, IR::Expr *rightSource, IR::Temp *ta case IR::OpBitOr: { Q_ASSERT(rightSource->type == IR::SInt32Type); if (rightSource->asTemp() && rightSource->asTemp()->kind == IR::Temp::PhysicalRegister - && target->kind == IR::Temp::PhysicalRegister - && target->index == rightSource->asTemp()->index) { + && targetTemp + && targetTemp->kind == IR::Temp::PhysicalRegister + && targetTemp->index == rightSource->asTemp()->index) { as->or32(as->toInt32Register(leftSource, Assembler::ScratchRegister), - (Assembler::RegisterID) target->index); + (Assembler::RegisterID) targetTemp->index); return true; } @@ -283,10 +287,11 @@ bool Binop::int32Binop(IR::Expr *leftSource, IR::Expr *rightSource, IR::Temp *ta case IR::OpBitXor: { Q_ASSERT(rightSource->type == IR::SInt32Type); if (rightSource->asTemp() && rightSource->asTemp()->kind == IR::Temp::PhysicalRegister - && target->kind == IR::Temp::PhysicalRegister - && target->index == rightSource->asTemp()->index) { + && targetTemp + && targetTemp->kind == IR::Temp::PhysicalRegister + && targetTemp->index == rightSource->asTemp()->index) { as->xor32(as->toInt32Register(leftSource, Assembler::ScratchRegister), - (Assembler::RegisterID) target->index); + (Assembler::RegisterID) targetTemp->index); return true; } @@ -370,9 +375,10 @@ bool Binop::int32Binop(IR::Expr *leftSource, IR::Expr *rightSource, IR::Temp *ta Q_ASSERT(rightSource->type == IR::SInt32Type); if (rightSource->asTemp() && rightSource->asTemp()->kind == IR::Temp::PhysicalRegister - && target->kind == IR::Temp::PhysicalRegister - && target->index == rightSource->asTemp()->index) { - Assembler::RegisterID targetReg = (Assembler::RegisterID) target->index; + && targetTemp + && targetTemp->kind == IR::Temp::PhysicalRegister + && targetTemp->index == rightSource->asTemp()->index) { + Assembler::RegisterID targetReg = (Assembler::RegisterID) targetTemp->index; as->move(targetReg, Assembler::ScratchRegister); as->move(as->toInt32Register(leftSource, targetReg), targetReg); as->sub32(Assembler::ScratchRegister, targetReg); @@ -407,7 +413,7 @@ static inline Assembler::FPRegisterID getFreeFPReg(IR::Expr *shouldNotOverlap, u return Assembler::FPRegisterID(hint); } -Assembler::Jump Binop::genInlineBinop(IR::Expr *leftSource, IR::Expr *rightSource, IR::Temp *target) +Assembler::Jump Binop::genInlineBinop(IR::Expr *leftSource, IR::Expr *rightSource, IR::Expr *target) { Assembler::Jump done; diff --git a/src/qml/jit/qv4binop_p.h b/src/qml/jit/qv4binop_p.h index a6292e6fb5..8c7fa4337a 100644 --- a/src/qml/jit/qv4binop_p.h +++ b/src/qml/jit/qv4binop_p.h @@ -58,10 +58,10 @@ struct Binop { , op(operation) {} - void generate(IR::Expr *lhs, IR::Expr *rhs, IR::Temp *target); - void doubleBinop(IR::Expr *lhs, IR::Expr *rhs, IR::Temp *target); - bool int32Binop(IR::Expr *leftSource, IR::Expr *rightSource, IR::Temp *target); - Assembler::Jump genInlineBinop(IR::Expr *leftSource, IR::Expr *rightSource, IR::Temp *target); + void generate(IR::Expr *lhs, IR::Expr *rhs, IR::Expr *target); + void doubleBinop(IR::Expr *lhs, IR::Expr *rhs, IR::Expr *target); + bool int32Binop(IR::Expr *leftSource, IR::Expr *rightSource, IR::Expr *target); + Assembler::Jump genInlineBinop(IR::Expr *leftSource, IR::Expr *rightSource, IR::Expr *target); typedef Assembler::Jump (Binop::*MemRegOp)(Assembler::Address, Assembler::RegisterID); typedef Assembler::Jump (Binop::*ImmRegOp)(Assembler::TrustedImm32, Assembler::RegisterID); diff --git a/src/qml/jit/qv4isel_masm.cpp b/src/qml/jit/qv4isel_masm.cpp index 17e2730669..353a29425d 100644 --- a/src/qml/jit/qv4isel_masm.cpp +++ b/src/qml/jit/qv4isel_masm.cpp @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). +** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies). ** Contact: http://www.qt-project.org/legal ** ** This file is part of the QtQml module of the Qt Toolkit. @@ -203,9 +203,9 @@ InstructionSelection::InstructionSelection(QQmlEnginePrivate *qmlEngine, QV4::Ex : EvalInstructionSelection(execAllocator, module, jsGenerator) , _block(0) , _as(0) + , compilationUnit(new CompilationUnit) , qmlEngine(qmlEngine) { - compilationUnit = new CompilationUnit; compilationUnit->codeRefs.resize(module->functions.size()); } @@ -214,90 +214,6 @@ InstructionSelection::~InstructionSelection() delete _as; } -#if (CPU(X86_64) && (OS(MAC_OS_X) || OS(LINUX))) || (CPU(X86) && OS(LINUX)) -# define REGALLOC_IS_SUPPORTED -static QVector<int> getIntRegisters() -{ -# if CPU(X86) && OS(LINUX) // x86 with linux - static const QVector<int> intRegisters = QVector<int>() - << JSC::X86Registers::edx - << JSC::X86Registers::ebx; -# else // x86_64 with linux or with macos - static const QVector<int> intRegisters = QVector<int>() - << JSC::X86Registers::ebx - << JSC::X86Registers::edi - << JSC::X86Registers::esi - << JSC::X86Registers::edx - << JSC::X86Registers::r9 - << JSC::X86Registers::r8 - << JSC::X86Registers::r13 - << JSC::X86Registers::r15; -# endif - return intRegisters; -} - -static QVector<int> getFpRegisters() -{ -// linux/x86_64, linux/x86, and macos/x86_64: - static const QVector<int> fpRegisters = QVector<int>() - << JSC::X86Registers::xmm2 - << JSC::X86Registers::xmm3 - << JSC::X86Registers::xmm4 - << JSC::X86Registers::xmm5 - << JSC::X86Registers::xmm6 - << JSC::X86Registers::xmm7; - return fpRegisters; -} - -#elif CPU(ARM) && OS(LINUX) - // Note: this is not generic for all ARM platforms. Specifically, r9 is platform dependent - // (e.g. iOS reserves it). See the ARM GNU Linux abi for details. -# define REGALLOC_IS_SUPPORTED -static QVector<int> getIntRegisters() -{ - static const QVector<int> intRegisters = QVector<int>() - << JSC::ARMRegisters::r1 - << JSC::ARMRegisters::r2 - << JSC::ARMRegisters::r3 - << JSC::ARMRegisters::r4 - << JSC::ARMRegisters::r8 - << JSC::ARMRegisters::r9; - return intRegisters; -} - -static QVector<int> getFpRegisters() -{ - static const QVector<int> fpRegisters = QVector<int>() - << JSC::ARMRegisters::d2 - << JSC::ARMRegisters::d3 - << JSC::ARMRegisters::d4 - << JSC::ARMRegisters::d5 - << JSC::ARMRegisters::d6; - return fpRegisters; -} -#elif CPU(X86) && OS(WINDOWS) -# define REGALLOC_IS_SUPPORTED -static QVector<int> getIntRegisters() -{ - static const QVector<int> intRegisters = QVector<int>() - << JSC::X86Registers::edx - << JSC::X86Registers::ebx; - return intRegisters; -} - -static QVector<int> getFpRegisters() -{ - static const QVector<int> fpRegisters = QVector<int>() - << JSC::X86Registers::xmm2 - << JSC::X86Registers::xmm3 - << JSC::X86Registers::xmm4 - << JSC::X86Registers::xmm5 - << JSC::X86Registers::xmm6 - << JSC::X86Registers::xmm7; - return fpRegisters; -} -#endif - void InstructionSelection::run(int functionIndex) { IR::Function *function = irModule->functions[functionIndex]; @@ -307,19 +223,16 @@ void InstructionSelection::run(int functionIndex) IR::Optimizer opt(_function); opt.run(qmlEngine); -#ifdef REGALLOC_IS_SUPPORTED static const bool withRegisterAllocator = qgetenv("QV4_NO_REGALLOC").isEmpty(); - if (opt.isInSSA() && withRegisterAllocator) { - RegisterAllocator(getIntRegisters(), getFpRegisters()).run(_function, opt); - } else -#endif // REGALLOC_IS_SUPPORTED - { + if (Assembler::RegAllocIsSupported && opt.isInSSA() && withRegisterAllocator) { + RegisterAllocator(Assembler::getRegisterInfo()).run(_function, opt); + } else { if (opt.isInSSA()) // No register allocator available for this platform, or env. var was set, so: opt.convertOutOfSSA(); ConvertTemps().toStackSlots(_function); + IR::Optimizer::showMeTheCode(_function); } - IR::Optimizer::showMeTheCode(_function); QSet<IR::Jump *> removableJumps = opt.calculateOptionalJumps(); qSwap(_removableJumps, removableJumps); @@ -335,7 +248,7 @@ void InstructionSelection::run(int functionIndex) #endif const int locals = _as->stackLayout().calculateJSStackFrameSize(); - _as->loadPtr(Address(Assembler::ContextRegister, qOffsetOf(ExecutionContext, engine)), Assembler::ScratchRegister); + _as->loadPtr(Address(Assembler::ContextRegister, qOffsetOf(ExecutionContext::Data, engine)), Assembler::ScratchRegister); _as->loadPtr(Address(Assembler::ScratchRegister, qOffsetOf(ExecutionEngine, jsStackTop)), Assembler::LocalsRegister); _as->addPtr(Assembler::TrustedImm32(sizeof(QV4::Value)*locals), Assembler::LocalsRegister); _as->storePtr(Assembler::LocalsRegister, Address(Assembler::ScratchRegister, qOffsetOf(ExecutionEngine, jsStackTop))); @@ -351,7 +264,7 @@ void InstructionSelection::run(int functionIndex) foreach (IR::Stmt *s, _block->statements()) { if (s->location.isValid()) { if (int(s->location.startLine) != lastLine) { - Assembler::Address lineAddr(Assembler::ContextRegister, qOffsetOf(QV4::ExecutionContext, lineNumber)); + Assembler::Address lineAddr(Assembler::ContextRegister, qOffsetOf(QV4::ExecutionContext::Data, lineNumber)); _as->store32(Assembler::TrustedImm32(s->location.startLine), lineAddr); lastLine = s->location.startLine; } @@ -385,10 +298,10 @@ const void *InstructionSelection::addConstantTable(QVector<Primitive> *values) QV4::CompiledData::CompilationUnit *InstructionSelection::backendCompileStep() { - return compilationUnit; + return compilationUnit.take(); } -void InstructionSelection::callBuiltinInvalid(IR::Name *func, IR::ExprList *args, IR::Temp *result) +void InstructionSelection::callBuiltinInvalid(IR::Name *func, IR::ExprList *args, IR::Expr *result) { prepareCallData(args, 0); @@ -407,52 +320,52 @@ void InstructionSelection::callBuiltinInvalid(IR::Name *func, IR::ExprList *args } void InstructionSelection::callBuiltinTypeofMember(IR::Expr *base, const QString &name, - IR::Temp *result) + IR::Expr *result) { generateFunctionCall(result, Runtime::typeofMember, Assembler::ContextRegister, Assembler::PointerToValue(base), Assembler::PointerToString(name)); } void InstructionSelection::callBuiltinTypeofSubscript(IR::Expr *base, IR::Expr *index, - IR::Temp *result) + IR::Expr *result) { generateFunctionCall(result, Runtime::typeofElement, Assembler::ContextRegister, Assembler::PointerToValue(base), Assembler::PointerToValue(index)); } -void InstructionSelection::callBuiltinTypeofName(const QString &name, IR::Temp *result) +void InstructionSelection::callBuiltinTypeofName(const QString &name, IR::Expr *result) { generateFunctionCall(result, Runtime::typeofName, Assembler::ContextRegister, Assembler::PointerToString(name)); } -void InstructionSelection::callBuiltinTypeofValue(IR::Expr *value, IR::Temp *result) +void InstructionSelection::callBuiltinTypeofValue(IR::Expr *value, IR::Expr *result) { generateFunctionCall(result, Runtime::typeofValue, Assembler::ContextRegister, Assembler::PointerToValue(value)); } -void InstructionSelection::callBuiltinDeleteMember(IR::Temp *base, const QString &name, IR::Temp *result) +void InstructionSelection::callBuiltinDeleteMember(IR::Expr *base, const QString &name, IR::Expr *result) { generateFunctionCall(result, Runtime::deleteMember, Assembler::ContextRegister, Assembler::Reference(base), Assembler::PointerToString(name)); } -void InstructionSelection::callBuiltinDeleteSubscript(IR::Temp *base, IR::Expr *index, - IR::Temp *result) +void InstructionSelection::callBuiltinDeleteSubscript(IR::Expr *base, IR::Expr *index, + IR::Expr *result) { generateFunctionCall(result, Runtime::deleteElement, Assembler::ContextRegister, Assembler::Reference(base), Assembler::PointerToValue(index)); } -void InstructionSelection::callBuiltinDeleteName(const QString &name, IR::Temp *result) +void InstructionSelection::callBuiltinDeleteName(const QString &name, IR::Expr *result) { generateFunctionCall(result, Runtime::deleteName, Assembler::ContextRegister, Assembler::PointerToString(name)); } -void InstructionSelection::callBuiltinDeleteValue(IR::Temp *result) +void InstructionSelection::callBuiltinDeleteValue(IR::Expr *result) { _as->storeValue(Primitive::fromBoolean(false), result); } @@ -468,7 +381,7 @@ void InstructionSelection::callBuiltinReThrow() _as->jumpToExceptionHandler(); } -void InstructionSelection::callBuiltinUnwindException(IR::Temp *result) +void InstructionSelection::callBuiltinUnwindException(IR::Expr *result) { generateFunctionCall(result, Runtime::unwindException, Assembler::ContextRegister); @@ -476,11 +389,10 @@ void InstructionSelection::callBuiltinUnwindException(IR::Temp *result) void InstructionSelection::callBuiltinPushCatchScope(const QString &exceptionName) { - Assembler::Pointer s = _as->loadStringAddress(Assembler::ScratchRegister, exceptionName); - generateFunctionCall(Assembler::ContextRegister, Runtime::pushCatchScope, Assembler::ContextRegister, s); + generateFunctionCall(Assembler::ContextRegister, Runtime::pushCatchScope, Assembler::ContextRegister, Assembler::PointerToString(exceptionName)); } -void InstructionSelection::callBuiltinForeachIteratorObject(IR::Expr *arg, IR::Temp *result) +void InstructionSelection::callBuiltinForeachIteratorObject(IR::Expr *arg, IR::Expr *result) { Q_ASSERT(arg); Q_ASSERT(result); @@ -488,7 +400,7 @@ void InstructionSelection::callBuiltinForeachIteratorObject(IR::Expr *arg, IR::T generateFunctionCall(result, Runtime::foreachIterator, Assembler::ContextRegister, Assembler::PointerToValue(arg)); } -void InstructionSelection::callBuiltinForeachNextPropertyname(IR::Temp *arg, IR::Temp *result) +void InstructionSelection::callBuiltinForeachNextPropertyname(IR::Expr *arg, IR::Expr *result) { Q_ASSERT(arg); Q_ASSERT(result); @@ -496,7 +408,7 @@ void InstructionSelection::callBuiltinForeachNextPropertyname(IR::Temp *arg, IR: generateFunctionCall(result, Runtime::foreachNextPropertyName, Assembler::Reference(arg)); } -void InstructionSelection::callBuiltinPushWithScope(IR::Temp *arg) +void InstructionSelection::callBuiltinPushWithScope(IR::Expr *arg) { Q_ASSERT(arg); @@ -514,7 +426,7 @@ void InstructionSelection::callBuiltinDeclareVar(bool deletable, const QString & Assembler::TrustedImm32(deletable), Assembler::PointerToString(name)); } -void InstructionSelection::callBuiltinDefineArray(IR::Temp *result, IR::ExprList *args) +void InstructionSelection::callBuiltinDefineArray(IR::Expr *result, IR::ExprList *args) { Q_ASSERT(result); @@ -523,7 +435,7 @@ void InstructionSelection::callBuiltinDefineArray(IR::Temp *result, IR::ExprList baseAddressForCallArguments(), Assembler::TrustedImm32(length)); } -void InstructionSelection::callBuiltinDefineObjectLiteral(IR::Temp *result, int keyValuePairCount, IR::ExprList *keyValuePairs, IR::ExprList *arrayEntries, bool needSparseArray) +void InstructionSelection::callBuiltinDefineObjectLiteral(IR::Expr *result, int keyValuePairCount, IR::ExprList *keyValuePairs, IR::ExprList *arrayEntries, bool needSparseArray) { Q_ASSERT(result); @@ -604,7 +516,7 @@ void InstructionSelection::callBuiltinDefineObjectLiteral(IR::Temp *result, int Assembler::TrustedImm32(arrayValueCount), Assembler::TrustedImm32(arrayGetterSetterCount | (needSparseArray << 30))); } -void InstructionSelection::callBuiltinSetupArgumentObject(IR::Temp *result) +void InstructionSelection::callBuiltinSetupArgumentObject(IR::Expr *result) { generateFunctionCall(result, Runtime::setupArgumentsObject, Assembler::ContextRegister); } @@ -614,19 +526,24 @@ void InstructionSelection::callBuiltinConvertThisToObject() generateFunctionCall(Assembler::Void, Runtime::convertThisToObject, Assembler::ContextRegister); } -void InstructionSelection::callValue(IR::Temp *value, IR::ExprList *args, IR::Temp *result) +void InstructionSelection::callValue(IR::Expr *value, IR::ExprList *args, IR::Expr *result) { Q_ASSERT(value); prepareCallData(args, 0); - generateFunctionCall(result, Runtime::callValue, Assembler::ContextRegister, - Assembler::Reference(value), - baseAddressForCallData()); + if (value->asConst()) + generateFunctionCall(result, Runtime::callValue, Assembler::ContextRegister, + Assembler::PointerToValue(value), + baseAddressForCallData()); + else + generateFunctionCall(result, Runtime::callValue, Assembler::ContextRegister, + Assembler::Reference(value), + baseAddressForCallData()); } -void InstructionSelection::loadThisObject(IR::Temp *temp) +void InstructionSelection::loadThisObject(IR::Expr *temp) { - _as->loadPtr(Address(Assembler::ContextRegister, qOffsetOf(ExecutionContext, callData)), Assembler::ScratchRegister); + _as->loadPtr(Address(Assembler::ContextRegister, qOffsetOf(ExecutionContext::Data, callData)), Assembler::ScratchRegister); #if defined(VALUE_FITS_IN_REGISTER) _as->load64(Pointer(Assembler::ScratchRegister, qOffsetOf(CallData, thisObject)), Assembler::ReturnValueRegister); @@ -636,60 +553,63 @@ void InstructionSelection::loadThisObject(IR::Temp *temp) #endif } -void InstructionSelection::loadQmlIdArray(IR::Temp *temp) +void InstructionSelection::loadQmlIdArray(IR::Expr *temp) { generateFunctionCall(temp, Runtime::getQmlIdArray, Assembler::ContextRegister); } -void InstructionSelection::loadQmlImportedScripts(IR::Temp *temp) +void InstructionSelection::loadQmlImportedScripts(IR::Expr *temp) { generateFunctionCall(temp, Runtime::getQmlImportedScripts, Assembler::ContextRegister); } -void InstructionSelection::loadQmlContextObject(IR::Temp *temp) +void InstructionSelection::loadQmlContextObject(IR::Expr *temp) { generateFunctionCall(temp, Runtime::getQmlContextObject, Assembler::ContextRegister); } -void InstructionSelection::loadQmlScopeObject(IR::Temp *temp) +void InstructionSelection::loadQmlScopeObject(IR::Expr *temp) { generateFunctionCall(temp, Runtime::getQmlScopeObject, Assembler::ContextRegister); } -void InstructionSelection::loadQmlSingleton(const QString &name, IR::Temp *temp) +void InstructionSelection::loadQmlSingleton(const QString &name, IR::Expr *temp) { generateFunctionCall(temp, Runtime::getQmlSingleton, Assembler::ContextRegister, Assembler::PointerToString(name)); } -void InstructionSelection::loadConst(IR::Const *sourceConst, IR::Temp *targetTemp) -{ - if (targetTemp->kind == IR::Temp::PhysicalRegister) { - if (targetTemp->type == IR::DoubleType) { - Q_ASSERT(sourceConst->type == IR::DoubleType); - _as->toDoubleRegister(sourceConst, (Assembler::FPRegisterID) targetTemp->index); - } else if (targetTemp->type == IR::SInt32Type) { - Q_ASSERT(sourceConst->type == IR::SInt32Type); - _as->toInt32Register(sourceConst, (Assembler::RegisterID) targetTemp->index); - } else if (targetTemp->type == IR::UInt32Type) { - Q_ASSERT(sourceConst->type == IR::UInt32Type); - _as->toUInt32Register(sourceConst, (Assembler::RegisterID) targetTemp->index); - } else if (targetTemp->type == IR::BoolType) { - Q_ASSERT(sourceConst->type == IR::BoolType); - _as->move(Assembler::TrustedImm32(convertToValue(sourceConst).int_32), - (Assembler::RegisterID) targetTemp->index); - } else { - Q_UNREACHABLE(); +void InstructionSelection::loadConst(IR::Const *sourceConst, IR::Expr *target) +{ + if (IR::Temp *targetTemp = target->asTemp()) { + if (targetTemp->kind == IR::Temp::PhysicalRegister) { + if (targetTemp->type == IR::DoubleType) { + Q_ASSERT(sourceConst->type == IR::DoubleType); + _as->toDoubleRegister(sourceConst, (Assembler::FPRegisterID) targetTemp->index); + } else if (targetTemp->type == IR::SInt32Type) { + Q_ASSERT(sourceConst->type == IR::SInt32Type); + _as->toInt32Register(sourceConst, (Assembler::RegisterID) targetTemp->index); + } else if (targetTemp->type == IR::UInt32Type) { + Q_ASSERT(sourceConst->type == IR::UInt32Type); + _as->toUInt32Register(sourceConst, (Assembler::RegisterID) targetTemp->index); + } else if (targetTemp->type == IR::BoolType) { + Q_ASSERT(sourceConst->type == IR::BoolType); + _as->move(Assembler::TrustedImm32(convertToValue(sourceConst).int_32), + (Assembler::RegisterID) targetTemp->index); + } else { + Q_UNREACHABLE(); + } + return; } - } else { - _as->storeValue(convertToValue(sourceConst), targetTemp); } + + _as->storeValue(convertToValue(sourceConst), target); } -void InstructionSelection::loadString(const QString &str, IR::Temp *targetTemp) +void InstructionSelection::loadString(const QString &str, IR::Expr *target) { Pointer srcAddr = _as->loadStringAddress(Assembler::ReturnValueRegister, str); _as->loadPtr(srcAddr, Assembler::ReturnValueRegister); - Pointer destAddr = _as->loadTempAddress(Assembler::ScratchRegister, targetTemp); + Pointer destAddr = _as->loadAddress(Assembler::ScratchRegister, target); #if QT_POINTER_SIZE == 8 _as->store64(Assembler::ReturnValueRegister, destAddr); #else @@ -699,20 +619,20 @@ void InstructionSelection::loadString(const QString &str, IR::Temp *targetTemp) #endif } -void InstructionSelection::loadRegexp(IR::RegExp *sourceRegexp, IR::Temp *targetTemp) +void InstructionSelection::loadRegexp(IR::RegExp *sourceRegexp, IR::Expr *target) { int id = registerRegExp(sourceRegexp); - generateFunctionCall(targetTemp, Runtime::regexpLiteral, Assembler::ContextRegister, Assembler::TrustedImm32(id)); + generateFunctionCall(target, Runtime::regexpLiteral, Assembler::ContextRegister, Assembler::TrustedImm32(id)); } -void InstructionSelection::getActivationProperty(const IR::Name *name, IR::Temp *temp) +void InstructionSelection::getActivationProperty(const IR::Name *name, IR::Expr *target) { if (useFastLookups && name->global) { uint index = registerGlobalGetterLookup(*name->id); - generateLookupCall(temp, index, qOffsetOf(QV4::Lookup, globalGetter), Assembler::ContextRegister, Assembler::Void); + generateLookupCall(target, index, qOffsetOf(QV4::Lookup, globalGetter), Assembler::ContextRegister, Assembler::Void); return; } - generateFunctionCall(temp, Runtime::getActivationProperty, Assembler::ContextRegister, Assembler::PointerToString(*name->id)); + generateFunctionCall(target, Runtime::getActivationProperty, Assembler::ContextRegister, Assembler::PointerToString(*name->id)); } void InstructionSelection::setActivationProperty(IR::Expr *source, const QString &targetName) @@ -722,13 +642,13 @@ void InstructionSelection::setActivationProperty(IR::Expr *source, const QString Assembler::ContextRegister, Assembler::PointerToString(targetName), Assembler::PointerToValue(source)); } -void InstructionSelection::initClosure(IR::Closure *closure, IR::Temp *target) +void InstructionSelection::initClosure(IR::Closure *closure, IR::Expr *target) { int id = closure->value; generateFunctionCall(target, Runtime::closure, Assembler::ContextRegister, Assembler::TrustedImm32(id)); } -void InstructionSelection::getProperty(IR::Expr *base, const QString &name, IR::Temp *target) +void InstructionSelection::getProperty(IR::Expr *base, const QString &name, IR::Expr *target) { if (useFastLookups) { uint index = registerGetterLookup(name); @@ -739,7 +659,7 @@ void InstructionSelection::getProperty(IR::Expr *base, const QString &name, IR:: } } -void InstructionSelection::getQObjectProperty(IR::Expr *base, int propertyIndex, bool captureRequired, int attachedPropertiesId, IR::Temp *target) +void InstructionSelection::getQObjectProperty(IR::Expr *base, int propertyIndex, bool captureRequired, int attachedPropertiesId, IR::Expr *target) { if (attachedPropertiesId != 0) generateFunctionCall(target, Runtime::getQmlAttachedProperty, Assembler::ContextRegister, Assembler::TrustedImm32(attachedPropertiesId), Assembler::TrustedImm32(propertyIndex)); @@ -769,7 +689,7 @@ void InstructionSelection::setQObjectProperty(IR::Expr *source, IR::Expr *target Assembler::TrustedImm32(propertyIndex), Assembler::PointerToValue(source)); } -void InstructionSelection::getElement(IR::Expr *base, IR::Expr *index, IR::Temp *target) +void InstructionSelection::getElement(IR::Expr *base, IR::Expr *index, IR::Expr *target) { if (useFastLookups) { uint lookup = registerIndexedGetterLookup(); @@ -797,13 +717,20 @@ void InstructionSelection::setElement(IR::Expr *source, IR::Expr *targetBase, IR Assembler::PointerToValue(source)); } -void InstructionSelection::copyValue(IR::Temp *sourceTemp, IR::Temp *targetTemp) +void InstructionSelection::copyValue(IR::Expr *source, IR::Expr *target) { - if (*sourceTemp == *targetTemp) + IR::Temp *sourceTemp = source->asTemp(); + IR::Temp *targetTemp = target->asTemp(); + + if (sourceTemp && targetTemp && *sourceTemp == *targetTemp) return; + if (IR::ArgLocal *sal = source->asArgLocal()) + if (IR::ArgLocal *tal = target->asArgLocal()) + if (*sal == *tal) + return; - if (sourceTemp->kind == IR::Temp::PhysicalRegister) { - if (targetTemp->kind == IR::Temp::PhysicalRegister) { + if (sourceTemp && sourceTemp->kind == IR::Temp::PhysicalRegister) { + if (targetTemp && targetTemp->kind == IR::Temp::PhysicalRegister) { if (sourceTemp->type == IR::DoubleType) _as->moveDouble((Assembler::FPRegisterID) sourceTemp->index, (Assembler::FPRegisterID) targetTemp->index); @@ -814,16 +741,16 @@ void InstructionSelection::copyValue(IR::Temp *sourceTemp, IR::Temp *targetTemp) } else { switch (sourceTemp->type) { case IR::DoubleType: - _as->storeDouble((Assembler::FPRegisterID) sourceTemp->index, targetTemp); + _as->storeDouble((Assembler::FPRegisterID) sourceTemp->index, target); break; case IR::SInt32Type: - _as->storeInt32((Assembler::RegisterID) sourceTemp->index, targetTemp); + _as->storeInt32((Assembler::RegisterID) sourceTemp->index, target); break; case IR::UInt32Type: - _as->storeUInt32((Assembler::RegisterID) sourceTemp->index, targetTemp); + _as->storeUInt32((Assembler::RegisterID) sourceTemp->index, target); break; case IR::BoolType: - _as->storeBool((Assembler::RegisterID) sourceTemp->index, targetTemp); + _as->storeBool((Assembler::RegisterID) sourceTemp->index, target); break; default: Q_ASSERT(!"Unreachable"); @@ -831,23 +758,23 @@ void InstructionSelection::copyValue(IR::Temp *sourceTemp, IR::Temp *targetTemp) } return; } - } else if (targetTemp->kind == IR::Temp::PhysicalRegister) { + } else if (targetTemp && targetTemp->kind == IR::Temp::PhysicalRegister) { switch (targetTemp->type) { case IR::DoubleType: - Q_ASSERT(sourceTemp->type == IR::DoubleType); - _as->toDoubleRegister(sourceTemp, (Assembler::FPRegisterID) targetTemp->index); + Q_ASSERT(source->type == IR::DoubleType); + _as->toDoubleRegister(source, (Assembler::FPRegisterID) targetTemp->index); return; case IR::BoolType: - Q_ASSERT(sourceTemp->type == IR::BoolType); - _as->toInt32Register(sourceTemp, (Assembler::RegisterID) targetTemp->index); + Q_ASSERT(source->type == IR::BoolType); + _as->toInt32Register(source, (Assembler::RegisterID) targetTemp->index); return; case IR::SInt32Type: - Q_ASSERT(sourceTemp->type == IR::SInt32Type); - _as->toInt32Register(sourceTemp, (Assembler::RegisterID) targetTemp->index); + Q_ASSERT(source->type == IR::SInt32Type); + _as->toInt32Register(source, (Assembler::RegisterID) targetTemp->index); return; case IR::UInt32Type: - Q_ASSERT(sourceTemp->type == IR::UInt32Type); - _as->toUInt32Register(sourceTemp, (Assembler::RegisterID) targetTemp->index); + Q_ASSERT(source->type == IR::UInt32Type); + _as->toUInt32Register(source, (Assembler::RegisterID) targetTemp->index); return; default: Q_ASSERT(!"Unreachable"); @@ -856,14 +783,16 @@ void InstructionSelection::copyValue(IR::Temp *sourceTemp, IR::Temp *targetTemp) } // The target is not a physical register, nor is the source. So we can do a memory-to-memory copy: - _as->memcopyValue(_as->loadTempAddress(Assembler::ReturnValueRegister, targetTemp), sourceTemp, - Assembler::ScratchRegister); + _as->memcopyValue(_as->loadAddress(Assembler::ReturnValueRegister, target), source, Assembler::ScratchRegister); } -void InstructionSelection::swapValues(IR::Temp *sourceTemp, IR::Temp *targetTemp) +void InstructionSelection::swapValues(IR::Expr *source, IR::Expr *target) { - if (sourceTemp->kind == IR::Temp::PhysicalRegister) { - if (targetTemp->kind == IR::Temp::PhysicalRegister) { + IR::Temp *sourceTemp = source->asTemp(); + IR::Temp *targetTemp = target->asTemp(); + + if (sourceTemp && sourceTemp->kind == IR::Temp::PhysicalRegister) { + if (targetTemp && targetTemp->kind == IR::Temp::PhysicalRegister) { Q_ASSERT(sourceTemp->type == targetTemp->type); if (sourceTemp->type == IR::DoubleType) { @@ -877,11 +806,11 @@ void InstructionSelection::swapValues(IR::Temp *sourceTemp, IR::Temp *targetTemp } return; } - } else if (sourceTemp->kind == IR::Temp::StackSlot) { - if (targetTemp->kind == IR::Temp::StackSlot) { + } 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. - Assembler::Pointer sAddr = _as->stackSlotPointer(sourceTemp); - Assembler::Pointer tAddr = _as->stackSlotPointer(targetTemp); + Assembler::Pointer sAddr = _as->loadAddress(Assembler::ScratchRegister, source); + Assembler::Pointer tAddr = _as->loadAddress(Assembler::ReturnValueRegister, target); // use the implementation in JSC::MacroAssembler, as it doesn't do bit swizzling _as->JSC::MacroAssembler::loadDouble(sAddr, Assembler::FPGpr0); _as->JSC::MacroAssembler::loadDouble(tAddr, Assembler::FPGpr1); @@ -891,25 +820,28 @@ void InstructionSelection::swapValues(IR::Temp *sourceTemp, IR::Temp *targetTemp } } - IR::Temp *stackTemp = sourceTemp->kind == IR::Temp::StackSlot ? sourceTemp : targetTemp; - IR::Temp *registerTemp = sourceTemp->kind == IR::Temp::PhysicalRegister ? sourceTemp - : targetTemp; - Assembler::Pointer addr = _as->stackSlotPointer(stackTemp); - if (registerTemp->type == IR::DoubleType) { + IR::Expr *memExpr = !sourceTemp || sourceTemp->kind == IR::Temp::StackSlot ? source : target; + IR::Temp *regTemp = sourceTemp && sourceTemp->kind == IR::Temp::PhysicalRegister ? sourceTemp + : targetTemp; + Q_ASSERT(memExpr); + Q_ASSERT(regTemp); + + Assembler::Pointer addr = _as->loadAddress(Assembler::ReturnValueRegister, memExpr); + if (regTemp->type == IR::DoubleType) { _as->loadDouble(addr, Assembler::FPGpr0); - _as->storeDouble((Assembler::FPRegisterID) registerTemp->index, addr); - _as->moveDouble(Assembler::FPGpr0, (Assembler::FPRegisterID) registerTemp->index); - } else if (registerTemp->type == IR::UInt32Type) { + _as->storeDouble((Assembler::FPRegisterID) regTemp->index, addr); + _as->moveDouble(Assembler::FPGpr0, (Assembler::FPRegisterID) regTemp->index); + } else if (regTemp->type == IR::UInt32Type) { _as->toUInt32Register(addr, Assembler::ScratchRegister); - _as->storeUInt32((Assembler::RegisterID) registerTemp->index, addr); - _as->move(Assembler::ScratchRegister, (Assembler::RegisterID) registerTemp->index); + _as->storeUInt32((Assembler::RegisterID) regTemp->index, addr); + _as->move(Assembler::ScratchRegister, (Assembler::RegisterID) regTemp->index); } else { _as->load32(addr, Assembler::ScratchRegister); - _as->store32((Assembler::RegisterID) registerTemp->index, addr); - if (registerTemp->type != stackTemp->type) { + _as->store32((Assembler::RegisterID) regTemp->index, addr); + if (regTemp->type != memExpr->type) { addr.offset += 4; quint32 tag; - switch (registerTemp->type) { + switch (regTemp->type) { case IR::BoolType: tag = QV4::Value::_Boolean_Type; break; @@ -922,7 +854,7 @@ void InstructionSelection::swapValues(IR::Temp *sourceTemp, IR::Temp *targetTemp } _as->store32(Assembler::TrustedImm32(tag), addr); } - _as->move(Assembler::ScratchRegister, (Assembler::RegisterID) registerTemp->index); + _as->move(Assembler::ScratchRegister, (Assembler::RegisterID) regTemp->index); } } @@ -931,21 +863,21 @@ void InstructionSelection::swapValues(IR::Temp *sourceTemp, IR::Temp *targetTemp #define setOpContext(op, opName, operation) \ do { opContext = operation; opName = isel_stringIfy(operation); } while (0) -void InstructionSelection::unop(IR::AluOp oper, IR::Temp *sourceTemp, IR::Temp *targetTemp) +void InstructionSelection::unop(IR::AluOp oper, IR::Expr *source, IR::Expr *target) { QV4::JIT::Unop unop(_as, oper); - unop.generate(sourceTemp, targetTemp); + unop.generate(source, target); } -void InstructionSelection::binop(IR::AluOp oper, IR::Expr *leftSource, IR::Expr *rightSource, IR::Temp *target) +void InstructionSelection::binop(IR::AluOp oper, IR::Expr *leftSource, IR::Expr *rightSource, IR::Expr *target) { QV4::JIT::Binop binop(_as, oper); binop.generate(leftSource, rightSource, target); } void InstructionSelection::callProperty(IR::Expr *base, const QString &name, IR::ExprList *args, - IR::Temp *result) + IR::Expr *result) { Q_ASSERT(base != 0); @@ -965,7 +897,7 @@ void InstructionSelection::callProperty(IR::Expr *base, const QString &name, IR: } void InstructionSelection::callSubscript(IR::Expr *base, IR::Expr *index, IR::ExprList *args, - IR::Temp *result) + IR::Expr *result) { Q_ASSERT(base != 0); @@ -975,7 +907,7 @@ void InstructionSelection::callSubscript(IR::Expr *base, IR::Expr *index, IR::Ex baseAddressForCallData()); } -void InstructionSelection::convertType(IR::Temp *source, IR::Temp *target) +void InstructionSelection::convertType(IR::Expr *source, IR::Expr *target) { switch (target->type) { case IR::DoubleType: @@ -996,7 +928,7 @@ void InstructionSelection::convertType(IR::Temp *source, IR::Temp *target) } } -void InstructionSelection::convertTypeSlowPath(IR::Temp *source, IR::Temp *target) +void InstructionSelection::convertTypeSlowPath(IR::Expr *source, IR::Expr *target) { Q_ASSERT(target->type != IR::BoolType); @@ -1006,7 +938,7 @@ void InstructionSelection::convertTypeSlowPath(IR::Temp *source, IR::Temp *targe copyValue(source, target); } -void InstructionSelection::convertTypeToDouble(IR::Temp *source, IR::Temp *target) +void InstructionSelection::convertTypeToDouble(IR::Expr *source, IR::Expr *target) { switch (source->type) { case IR::SInt32Type: @@ -1018,13 +950,13 @@ void InstructionSelection::convertTypeToDouble(IR::Temp *source, IR::Temp *targe convertUIntToDouble(source, target); break; case IR::UndefinedType: - _as->loadDouble(_as->loadTempAddress(Assembler::ScratchRegister, source), Assembler::FPGpr0); + _as->loadDouble(_as->loadAddress(Assembler::ScratchRegister, source), Assembler::FPGpr0); _as->storeDouble(Assembler::FPGpr0, target); break; case IR::StringType: case IR::VarType: { // load the tag: - Assembler::Pointer tagAddr = _as->loadTempAddress(Assembler::ScratchRegister, source); + Assembler::Pointer tagAddr = _as->loadAddress(Assembler::ScratchRegister, source); tagAddr.offset += 4; _as->load32(tagAddr, Assembler::ScratchRegister); @@ -1051,17 +983,18 @@ void InstructionSelection::convertTypeToDouble(IR::Temp *source, IR::Temp *targe // it is a double: isDbl.link(_as); - Assembler::Pointer addr2 = _as->loadTempAddress(Assembler::ScratchRegister, source); - if (target->kind == IR::Temp::StackSlot) { + Assembler::Pointer addr2 = _as->loadAddress(Assembler::ScratchRegister, source); + IR::Temp *targetTemp = target->asTemp(); + if (!targetTemp || targetTemp->kind == IR::Temp::StackSlot) { #if QT_POINTER_SIZE == 8 _as->load64(addr2, Assembler::ScratchRegister); - _as->store64(Assembler::ScratchRegister, _as->stackSlotPointer(target)); + _as->store64(Assembler::ScratchRegister, _as->loadAddress(Assembler::ReturnValueRegister, target)); #else _as->loadDouble(addr2, Assembler::FPGpr0); - _as->storeDouble(Assembler::FPGpr0, _as->stackSlotPointer(target)); + _as->storeDouble(Assembler::FPGpr0, _as->loadAddress(Assembler::ReturnValueRegister, target)); #endif } else { - _as->loadDouble(addr2, (Assembler::FPRegisterID) target->index); + _as->loadDouble(addr2, (Assembler::FPRegisterID) targetTemp->index); } noDoubleDone.link(_as); @@ -1073,8 +1006,9 @@ void InstructionSelection::convertTypeToDouble(IR::Temp *source, IR::Temp *targe } } -void InstructionSelection::convertTypeToBool(IR::Temp *source, IR::Temp *target) +void InstructionSelection::convertTypeToBool(IR::Expr *source, IR::Expr *target) { + IR::Temp *sourceTemp = source->asTemp(); switch (source->type) { case IR::SInt32Type: case IR::UInt32Type: @@ -1085,8 +1019,8 @@ void InstructionSelection::convertTypeToBool(IR::Temp *source, IR::Temp *target) // allocator was not used, then that means that we can use any register for to // load the double into. Assembler::FPRegisterID reg; - if (source->kind == IR::Temp::PhysicalRegister) - reg = (Assembler::FPRegisterID) source->index; + if (sourceTemp && sourceTemp->kind == IR::Temp::PhysicalRegister) + reg = (Assembler::FPRegisterID) sourceTemp->index; else reg = _as->toDoubleRegister(source, (Assembler::FPRegisterID) 1); Assembler::Jump nonZero = _as->branchDoubleNonZero(reg, Assembler::FPGpr0); @@ -1116,13 +1050,13 @@ void InstructionSelection::convertTypeToBool(IR::Temp *source, IR::Temp *target) } } -void InstructionSelection::convertTypeToSInt32(IR::Temp *source, IR::Temp *target) +void InstructionSelection::convertTypeToSInt32(IR::Expr *source, IR::Expr *target) { switch (source->type) { case IR::VarType: { #if QT_POINTER_SIZE == 8 - Assembler::Pointer addr = _as->loadTempAddress(Assembler::ScratchRegister, source); + Assembler::Pointer addr = _as->loadAddress(Assembler::ScratchRegister, source); _as->load64(addr, Assembler::ScratchRegister); _as->move(Assembler::ScratchRegister, Assembler::ReturnValueRegister); @@ -1142,12 +1076,13 @@ void InstructionSelection::convertTypeToSInt32(IR::Temp *source, IR::Temp *targe // not an int: fallback.link(_as); generateFunctionCall(Assembler::ReturnValueRegister, Runtime::toInt, - _as->loadTempAddress(Assembler::ScratchRegister, source)); + _as->loadAddress(Assembler::ScratchRegister, source)); isInt.link(_as); success.link(_as); - if (target->kind == IR::Temp::StackSlot) { - Assembler::Pointer targetAddr = _as->stackSlotPointer(target); + IR::Temp *targetTemp = target->asTemp(); + if (!targetTemp || targetTemp->kind == IR::Temp::StackSlot) { + Assembler::Pointer targetAddr = _as->loadAddress(Assembler::ScratchRegister, target); _as->store32(Assembler::ReturnValueRegister, targetAddr); targetAddr.offset += 4; _as->store32(Assembler::TrustedImm32(Value::_Integer_Type), targetAddr); @@ -1156,7 +1091,7 @@ void InstructionSelection::convertTypeToSInt32(IR::Temp *source, IR::Temp *targe } #else // load the tag: - Assembler::Pointer addr = _as->loadTempAddress(Assembler::ScratchRegister, source); + Assembler::Pointer addr = _as->loadAddress(Assembler::ScratchRegister, source); Assembler::Pointer tagAddr = addr; tagAddr.offset += 4; _as->load32(tagAddr, Assembler::ReturnValueRegister); @@ -1164,21 +1099,22 @@ void InstructionSelection::convertTypeToSInt32(IR::Temp *source, IR::Temp *targe // check if it's an int32: Assembler::Jump fallback = _as->branch32(Assembler::NotEqual, Assembler::ReturnValueRegister, Assembler::TrustedImm32(Value::_Integer_Type)); - if (target->kind == IR::Temp::StackSlot) { - _as->load32(addr, Assembler::ScratchRegister); - Assembler::Pointer targetAddr = _as->stackSlotPointer(target); - _as->store32(Assembler::ScratchRegister, targetAddr); + IR::Temp *targetTemp = target->asTemp(); + if (!targetTemp || targetTemp->kind == IR::Temp::StackSlot) { + _as->load32(addr, Assembler::ReturnValueRegister); + Assembler::Pointer targetAddr = _as->loadAddress(Assembler::ScratchRegister, target); + _as->store32(Assembler::ReturnValueRegister, targetAddr); targetAddr.offset += 4; _as->store32(Assembler::TrustedImm32(Value::_Integer_Type), targetAddr); } else { - _as->load32(addr, (Assembler::RegisterID) target->index); + _as->load32(addr, (Assembler::RegisterID) targetTemp->index); } Assembler::Jump intDone = _as->jump(); // not an int: fallback.link(_as); generateFunctionCall(Assembler::ReturnValueRegister, Runtime::toInt, - _as->loadTempAddress(Assembler::ScratchRegister, source)); + _as->loadAddress(Assembler::ScratchRegister, source)); _as->storeInt32(Assembler::ReturnValueRegister, target); intDone.link(_as); @@ -1209,32 +1145,32 @@ void InstructionSelection::convertTypeToSInt32(IR::Temp *source, IR::Temp *targe case IR::StringType: default: generateFunctionCall(Assembler::ReturnValueRegister, Runtime::toInt, - _as->loadTempAddress(Assembler::ScratchRegister, source)); + _as->loadAddress(Assembler::ScratchRegister, source)); _as->storeInt32(Assembler::ReturnValueRegister, target); break; } // switch (source->type) } -void InstructionSelection::convertTypeToUInt32(IR::Temp *source, IR::Temp *target) +void InstructionSelection::convertTypeToUInt32(IR::Expr *source, IR::Expr *target) { switch (source->type) { case IR::VarType: { // load the tag: - Assembler::Pointer tagAddr = _as->loadTempAddress(Assembler::ScratchRegister, source); + Assembler::Pointer tagAddr = _as->loadAddress(Assembler::ScratchRegister, source); tagAddr.offset += 4; _as->load32(tagAddr, Assembler::ScratchRegister); // check if it's an int32: Assembler::Jump isNoInt = _as->branch32(Assembler::NotEqual, Assembler::ScratchRegister, Assembler::TrustedImm32(Value::_Integer_Type)); - Assembler::Pointer addr = _as->loadTempAddress(Assembler::ScratchRegister, source); + Assembler::Pointer addr = _as->loadAddress(Assembler::ScratchRegister, source); _as->storeUInt32(_as->toInt32Register(addr, Assembler::ScratchRegister), target); Assembler::Jump intDone = _as->jump(); // not an int: isNoInt.link(_as); generateFunctionCall(Assembler::ReturnValueRegister, Runtime::toUInt, - _as->loadTempAddress(Assembler::ScratchRegister, source)); + _as->loadAddress(Assembler::ScratchRegister, source)); _as->storeInt32(Assembler::ReturnValueRegister, target); intDone.link(_as); @@ -1268,7 +1204,7 @@ void InstructionSelection::convertTypeToUInt32(IR::Temp *source, IR::Temp *targe } // switch (source->type) } -void InstructionSelection::constructActivationProperty(IR::Name *func, IR::ExprList *args, IR::Temp *result) +void InstructionSelection::constructActivationProperty(IR::Name *func, IR::ExprList *args, IR::Expr *result) { Q_ASSERT(func != 0); prepareCallData(args, 0); @@ -1288,7 +1224,7 @@ void InstructionSelection::constructActivationProperty(IR::Name *func, IR::ExprL } -void InstructionSelection::constructProperty(IR::Temp *base, const QString &name, IR::ExprList *args, IR::Temp *result) +void InstructionSelection::constructProperty(IR::Expr *base, const QString &name, IR::ExprList *args, IR::Expr *result) { prepareCallData(args, base); if (useFastLookups) { @@ -1305,7 +1241,7 @@ void InstructionSelection::constructProperty(IR::Temp *base, const QString &name baseAddressForCallData()); } -void InstructionSelection::constructValue(IR::Temp *value, IR::ExprList *args, IR::Temp *result) +void InstructionSelection::constructValue(IR::Expr *value, IR::ExprList *args, IR::Expr *result) { Q_ASSERT(value != 0); @@ -1324,16 +1260,17 @@ void InstructionSelection::visitJump(IR::Jump *s) void InstructionSelection::visitCJump(IR::CJump *s) { - if (IR::Temp *t = s->cond->asTemp()) { + IR::Temp *t = s->cond->asTemp(); + if (t || s->cond->asArgLocal()) { Assembler::RegisterID reg; - if (t->kind == IR::Temp::PhysicalRegister) { + if (t && t->kind == IR::Temp::PhysicalRegister) { Q_ASSERT(t->type == IR::BoolType); reg = (Assembler::RegisterID) t->index; - } else if (t->kind == IR::Temp::StackSlot && t->type == IR::BoolType) { + } else if (t && t->kind == IR::Temp::StackSlot && t->type == IR::BoolType) { reg = Assembler::ReturnValueRegister; _as->toInt32Register(t, reg); } else { - Address temp = _as->loadTempAddress(Assembler::ScratchRegister, t); + Address temp = _as->loadAddress(Assembler::ScratchRegister, s->cond); Address tag = temp; tag.offset += qOffsetOf(QV4::Value, tag); Assembler::Jump booleanConversion = _as->branch32(Assembler::NotEqual, tag, Assembler::TrustedImm32(QV4::Value::Boolean_Type)); @@ -1345,7 +1282,7 @@ void InstructionSelection::visitCJump(IR::CJump *s) booleanConversion.link(_as); reg = Assembler::ReturnValueRegister; - generateFunctionCall(reg, Runtime::toBoolean, Assembler::Reference(t)); + generateFunctionCall(reg, Runtime::toBoolean, Assembler::Reference(s->cond)); testBoolean.link(_as); } @@ -1455,7 +1392,7 @@ void InstructionSelection::visitRet(IR::Ret *s) Q_UNREACHABLE(); } } else { - Pointer addr = _as->loadTempAddress(Assembler::ScratchRegister, t); + Pointer addr = _as->loadAddress(Assembler::ScratchRegister, t); _as->load32(addr, lowReg); addr.offset += 4; _as->load32(addr, highReg); @@ -1523,7 +1460,7 @@ void InstructionSelection::visitRet(IR::Ret *s) const int locals = _as->stackLayout().calculateJSStackFrameSize(); _as->subPtr(Assembler::TrustedImm32(sizeof(QV4::Value)*locals), Assembler::LocalsRegister); - _as->loadPtr(Address(Assembler::ContextRegister, qOffsetOf(ExecutionContext, engine)), Assembler::ScratchRegister); + _as->loadPtr(Address(Assembler::ContextRegister, qOffsetOf(ExecutionContext::Data, engine)), Assembler::ScratchRegister); _as->storePtr(Assembler::LocalsRegister, Address(Assembler::ScratchRegister, qOffsetOf(ExecutionEngine, jsStackTop))); _as->leaveStandardStackFrame(); @@ -1692,10 +1629,7 @@ bool InstructionSelection::visitCJumpStrictNullUndefined(IR::Type nullOrUndef, I return true; } - IR::Temp *t = varSrc->asTemp(); - Q_ASSERT(t); - - Assembler::Pointer tagAddr = _as->loadTempAddress(Assembler::ScratchRegister, t); + Assembler::Pointer tagAddr = _as->loadAddress(Assembler::ScratchRegister, varSrc); tagAddr.offset += 4; const Assembler::RegisterID tagReg = Assembler::ScratchRegister; _as->load32(tagAddr, tagReg); @@ -1738,11 +1672,7 @@ bool InstructionSelection::visitCJumpStrictBool(IR::Binop *binop, IR::BasicBlock return true; } - IR::Temp *otherTemp = otherSrc->asTemp(); - Q_ASSERT(otherTemp); // constants cannot have "var" type - Q_ASSERT(otherTemp->kind != IR::Temp::PhysicalRegister); - - Assembler::Pointer otherAddr = _as->loadTempAddress(Assembler::ReturnValueRegister, otherTemp); + Assembler::Pointer otherAddr = _as->loadAddress(Assembler::ReturnValueRegister, otherSrc); otherAddr.offset += 4; // tag address // check if the tag of the var operand is indicates 'boolean' @@ -1790,10 +1720,7 @@ bool InstructionSelection::visitCJumpNullUndefined(IR::Type nullOrUndef, IR::Bin return true; } - IR::Temp *t = varSrc->asTemp(); - Q_ASSERT(t); - - Assembler::Pointer tagAddr = _as->loadTempAddress(Assembler::ScratchRegister, t); + Assembler::Pointer tagAddr = _as->loadAddress(Assembler::ScratchRegister, varSrc); tagAddr.offset += 4; const Assembler::RegisterID tagReg = Assembler::ScratchRegister; _as->load32(tagAddr, tagReg); diff --git a/src/qml/jit/qv4isel_masm_p.h b/src/qml/jit/qv4isel_masm_p.h index d589223d7e..9c0bc73a65 100644 --- a/src/qml/jit/qv4isel_masm_p.h +++ b/src/qml/jit/qv4isel_masm_p.h @@ -76,54 +76,54 @@ public: protected: virtual QV4::CompiledData::CompilationUnit *backendCompileStep(); - virtual void callBuiltinInvalid(IR::Name *func, IR::ExprList *args, IR::Temp *result); - virtual void callBuiltinTypeofMember(IR::Expr *base, const QString &name, IR::Temp *result); - virtual void callBuiltinTypeofSubscript(IR::Expr *base, IR::Expr *index, IR::Temp *result); - virtual void callBuiltinTypeofName(const QString &name, IR::Temp *result); - virtual void callBuiltinTypeofValue(IR::Expr *value, IR::Temp *result); - virtual void callBuiltinDeleteMember(IR::Temp *base, const QString &name, IR::Temp *result); - virtual void callBuiltinDeleteSubscript(IR::Temp *base, IR::Expr *index, IR::Temp *result); - virtual void callBuiltinDeleteName(const QString &name, IR::Temp *result); - virtual void callBuiltinDeleteValue(IR::Temp *result); + virtual void callBuiltinInvalid(IR::Name *func, IR::ExprList *args, IR::Expr *result); + virtual void callBuiltinTypeofMember(IR::Expr *base, const QString &name, IR::Expr *result); + virtual void callBuiltinTypeofSubscript(IR::Expr *base, IR::Expr *index, IR::Expr *result); + virtual void callBuiltinTypeofName(const QString &name, IR::Expr *result); + virtual void callBuiltinTypeofValue(IR::Expr *value, IR::Expr *result); + virtual void callBuiltinDeleteMember(IR::Expr *base, const QString &name, IR::Expr *result); + virtual void callBuiltinDeleteSubscript(IR::Expr *base, IR::Expr *index, IR::Expr *result); + virtual void callBuiltinDeleteName(const QString &name, IR::Expr *result); + virtual void callBuiltinDeleteValue(IR::Expr *result); virtual void callBuiltinThrow(IR::Expr *arg); virtual void callBuiltinReThrow(); - virtual void callBuiltinUnwindException(IR::Temp *); + virtual void callBuiltinUnwindException(IR::Expr *); virtual void callBuiltinPushCatchScope(const QString &exceptionName); - virtual void callBuiltinForeachIteratorObject(IR::Expr *arg, IR::Temp *result); - virtual void callBuiltinForeachNextPropertyname(IR::Temp *arg, IR::Temp *result); - virtual void callBuiltinPushWithScope(IR::Temp *arg); + virtual void callBuiltinForeachIteratorObject(IR::Expr *arg, IR::Expr *result); + virtual void callBuiltinForeachNextPropertyname(IR::Expr *arg, IR::Expr *result); + virtual void callBuiltinPushWithScope(IR::Expr *arg); virtual void callBuiltinPopScope(); virtual void callBuiltinDeclareVar(bool deletable, const QString &name); - virtual void callBuiltinDefineArray(IR::Temp *result, IR::ExprList *args); - virtual void callBuiltinDefineObjectLiteral(IR::Temp *result, int keyValuePairCount, IR::ExprList *keyValuePairs, IR::ExprList *arrayEntries, bool needSparseArray); - virtual void callBuiltinSetupArgumentObject(IR::Temp *result); + virtual void callBuiltinDefineArray(IR::Expr *result, IR::ExprList *args); + virtual void callBuiltinDefineObjectLiteral(IR::Expr *result, int keyValuePairCount, IR::ExprList *keyValuePairs, IR::ExprList *arrayEntries, bool needSparseArray); + virtual void callBuiltinSetupArgumentObject(IR::Expr *result); virtual void callBuiltinConvertThisToObject(); - virtual void callValue(IR::Temp *value, IR::ExprList *args, IR::Temp *result); - virtual void callProperty(IR::Expr *base, const QString &name, IR::ExprList *args, IR::Temp *result); - virtual void callSubscript(IR::Expr *base, IR::Expr *index, IR::ExprList *args, IR::Temp *result); - virtual void convertType(IR::Temp *source, IR::Temp *target); - virtual void loadThisObject(IR::Temp *temp); - virtual void loadQmlIdArray(IR::Temp *temp); - virtual void loadQmlImportedScripts(IR::Temp *temp); - virtual void loadQmlContextObject(IR::Temp *temp); - virtual void loadQmlScopeObject(IR::Temp *temp); - virtual void loadQmlSingleton(const QString &name, IR::Temp *temp); - virtual void loadConst(IR::Const *sourceConst, IR::Temp *targetTemp); - virtual void loadString(const QString &str, IR::Temp *targetTemp); - virtual void loadRegexp(IR::RegExp *sourceRegexp, IR::Temp *targetTemp); - virtual void getActivationProperty(const IR::Name *name, IR::Temp *temp); + virtual void callValue(IR::Expr *value, IR::ExprList *args, IR::Expr *result); + virtual void callProperty(IR::Expr *base, const QString &name, IR::ExprList *args, IR::Expr *result); + virtual void callSubscript(IR::Expr *base, IR::Expr *index, IR::ExprList *args, IR::Expr *result); + virtual void convertType(IR::Expr *source, IR::Expr *target); + virtual void loadThisObject(IR::Expr *temp); + virtual void loadQmlIdArray(IR::Expr *target); + virtual void loadQmlImportedScripts(IR::Expr *target); + virtual void loadQmlContextObject(IR::Expr *target); + virtual void loadQmlScopeObject(IR::Expr *target); + virtual void loadQmlSingleton(const QString &name, IR::Expr *target); + virtual void loadConst(IR::Const *sourceConst, IR::Expr *target); + virtual void loadString(const QString &str, IR::Expr *target); + virtual void loadRegexp(IR::RegExp *sourceRegexp, IR::Expr *target); + virtual void getActivationProperty(const IR::Name *name, IR::Expr *target); virtual void setActivationProperty(IR::Expr *source, const QString &targetName); - virtual void initClosure(IR::Closure *closure, IR::Temp *target); - virtual void getProperty(IR::Expr *base, const QString &name, IR::Temp *target); + virtual void initClosure(IR::Closure *closure, IR::Expr *target); + virtual void getProperty(IR::Expr *base, const QString &name, IR::Expr *target); + virtual void getQObjectProperty(IR::Expr *base, int propertyIndex, bool captureRequired, int attachedPropertiesId, IR::Expr *target); virtual void setProperty(IR::Expr *source, IR::Expr *targetBase, const QString &targetName); virtual void setQObjectProperty(IR::Expr *source, IR::Expr *targetBase, int propertyIndex); - virtual void getQObjectProperty(IR::Expr *base, int propertyIndex, bool captureRequired, int attachedPropertiesId, IR::Temp *target); - virtual void getElement(IR::Expr *base, IR::Expr *index, IR::Temp *target); + virtual void getElement(IR::Expr *base, IR::Expr *index, IR::Expr *target); virtual void setElement(IR::Expr *source, IR::Expr *targetBase, IR::Expr *targetIndex); - virtual void copyValue(IR::Temp *sourceTemp, IR::Temp *targetTemp); - virtual void swapValues(IR::Temp *sourceTemp, IR::Temp *targetTemp); - virtual void unop(IR::AluOp oper, IR::Temp *sourceTemp, IR::Temp *targetTemp); - virtual void binop(IR::AluOp oper, IR::Expr *leftSource, IR::Expr *rightSource, IR::Temp *target); + virtual void copyValue(IR::Expr *source, IR::Expr *target); + virtual void swapValues(IR::Expr *source, IR::Expr *target); + virtual void unop(IR::AluOp oper, IR::Expr *sourceTemp, IR::Expr *target); + virtual void binop(IR::AluOp oper, IR::Expr *leftSource, IR::Expr *rightSource, IR::Expr *target); typedef Assembler::Address Address; typedef Assembler::Pointer Pointer; @@ -148,9 +148,9 @@ protected: return _as->stackLayout().callDataAddress(); } - virtual void constructActivationProperty(IR::Name *func, IR::ExprList *args, IR::Temp *result); - virtual void constructProperty(IR::Temp *base, const QString &name, IR::ExprList *args, IR::Temp *result); - virtual void constructValue(IR::Temp *value, IR::ExprList *args, IR::Temp *result); + virtual void constructActivationProperty(IR::Name *func, IR::ExprList *args, IR::Expr *result); + virtual void constructProperty(IR::Expr *base, const QString &name, IR::ExprList *args, IR::Expr*result); + virtual void constructValue(IR::Expr *value, IR::ExprList *args, IR::Expr *result); virtual void visitJump(IR::Jump *); virtual void visitCJump(IR::CJump *); @@ -167,44 +167,51 @@ protected: void visitCJumpEqual(IR::Binop *binop, IR::BasicBlock *trueBlock, IR::BasicBlock *falseBlock); private: - void convertTypeSlowPath(IR::Temp *source, IR::Temp *target); - void convertTypeToDouble(IR::Temp *source, IR::Temp *target); - void convertTypeToBool(IR::Temp *source, IR::Temp *target); - void convertTypeToSInt32(IR::Temp *source, IR::Temp *target); - void convertTypeToUInt32(IR::Temp *source, IR::Temp *target); + void convertTypeSlowPath(IR::Expr *source, IR::Expr *target); + void convertTypeToDouble(IR::Expr *source, IR::Expr *target); + void convertTypeToBool(IR::Expr *source, IR::Expr *target); + void convertTypeToSInt32(IR::Expr *source, IR::Expr *target); + void convertTypeToUInt32(IR::Expr *source, IR::Expr *target); - void convertIntToDouble(IR::Temp *source, IR::Temp *target) + void convertIntToDouble(IR::Expr *source, IR::Expr *target) { - if (target->kind == IR::Temp::PhysicalRegister) { - _as->convertInt32ToDouble(_as->toInt32Register(source, Assembler::ScratchRegister), - (Assembler::FPRegisterID) target->index); - } else { - _as->convertInt32ToDouble(_as->toInt32Register(source, Assembler::ScratchRegister), - Assembler::FPGpr0); - _as->storeDouble(Assembler::FPGpr0, _as->stackSlotPointer(target)); + if (IR::Temp *targetTemp = target->asTemp()) { + if (targetTemp->kind == IR::Temp::PhysicalRegister) { + _as->convertInt32ToDouble(_as->toInt32Register(source, Assembler::ScratchRegister), + (Assembler::FPRegisterID) targetTemp->index); + return; + } } + + _as->convertInt32ToDouble(_as->toInt32Register(source, Assembler::ScratchRegister), + Assembler::FPGpr0); + _as->storeDouble(Assembler::FPGpr0, _as->loadAddress(Assembler::ScratchRegister, target)); } - void convertUIntToDouble(IR::Temp *source, IR::Temp *target) + void convertUIntToDouble(IR::Expr *source, IR::Expr *target) { Assembler::RegisterID tmpReg = Assembler::ScratchRegister; Assembler::RegisterID reg = _as->toInt32Register(source, tmpReg); - if (target->kind == IR::Temp::PhysicalRegister) { - _as->convertUInt32ToDouble(reg, (Assembler::FPRegisterID) target->index, tmpReg); - } else { - _as->convertUInt32ToDouble(_as->toUInt32Register(source, tmpReg), - Assembler::FPGpr0, tmpReg); - _as->storeDouble(Assembler::FPGpr0, _as->stackSlotPointer(target)); + if (IR::Temp *targetTemp = target->asTemp()) { + if (targetTemp->kind == IR::Temp::PhysicalRegister) { + _as->convertUInt32ToDouble(reg, (Assembler::FPRegisterID) targetTemp->index, tmpReg); + return; + } } + + _as->convertUInt32ToDouble(_as->toUInt32Register(source, tmpReg), + Assembler::FPGpr0, tmpReg); + _as->storeDouble(Assembler::FPGpr0, _as->loadAddress(tmpReg, target)); } - void convertIntToBool(IR::Temp *source, IR::Temp *target) + void convertIntToBool(IR::Expr *source, IR::Expr *target) { - Assembler::RegisterID reg = target->kind == IR::Temp::PhysicalRegister - ? (Assembler::RegisterID) target->index - : Assembler::ScratchRegister; + Assembler::RegisterID reg = Assembler::ScratchRegister; + if (IR::Temp *targetTemp = target->asTemp()) + if (targetTemp->kind == IR::Temp::PhysicalRegister) + reg = (Assembler::RegisterID) targetTemp->index; _as->move(_as->toInt32Register(source, reg), reg); _as->compare32(Assembler::NotEqual, reg, Assembler::TrustedImm32(0), reg); _as->storeBool(reg, target); @@ -247,7 +254,7 @@ private: QSet<IR::Jump *> _removableJumps; Assembler* _as; - CompilationUnit *compilationUnit; + QScopedPointer<CompilationUnit> compilationUnit; QQmlEnginePrivate *qmlEngine; }; diff --git a/src/qml/jit/qv4regalloc.cpp b/src/qml/jit/qv4regalloc.cpp index b5765cd589..52c2936352 100644 --- a/src/qml/jit/qv4regalloc.cpp +++ b/src/qml/jit/qv4regalloc.cpp @@ -44,9 +44,9 @@ #include <algorithm> -//#define DEBUG_REGALLOC - namespace { +enum { DebugRegAlloc = 0 }; + struct Use { enum RegisterFlag { MustHaveRegister = 0, CouldHaveRegister = 1 }; unsigned flag : 1; @@ -68,45 +68,135 @@ using namespace QV4::IR; namespace QV4 { namespace JIT { +namespace { +class IRPrinterWithPositions: public IRPrinter +{ + LifeTimeIntervals::Ptr intervals; + const int positionSize; + +public: + IRPrinterWithPositions(QTextStream *out, const LifeTimeIntervals::Ptr &intervals) + : IRPrinter(out) + , intervals(intervals) + , positionSize(QString::number(intervals->lastPosition()).size()) + {} + +protected: + void addStmtNr(Stmt *s) + { + QString posStr; + int pos = intervals->positionForStatement(s); + if (pos != Stmt::InvalidId) + posStr = QString::number(pos); + *out << posStr.rightJustified(positionSize); + if (pos == Stmt::InvalidId) + *out << " "; + else + *out << ": "; + } +}; + +class IRPrinterWithRegisters: public IRPrinterWithPositions +{ + const RegisterInformation &_registerInformation; + QHash<int, const RegisterInfo *> _infoForRegularRegister; + QHash<int, const RegisterInfo *> _infoForFPRegister; + +public: + IRPrinterWithRegisters(QTextStream *out, const LifeTimeIntervals::Ptr &intervals, + const RegisterInformation ®isterInformation) + : IRPrinterWithPositions(out, intervals) + , _registerInformation(registerInformation) + { + for (int i = 0, ei = _registerInformation.size(); i != ei; ++i) + if (_registerInformation.at(i).isRegularRegister()) + _infoForRegularRegister.insert(_registerInformation.at(i).reg<int>(), + &_registerInformation.at(i)); + else + _infoForFPRegister.insert(_registerInformation.at(i).reg<int>(), + &_registerInformation.at(i)); + } + +protected: + void visitTemp(Temp *e) + { + switch (e->kind) { + case Temp::PhysicalRegister: { + const RegisterInfo *ri = e->type == DoubleType ? _infoForFPRegister.value(e->index, 0) + : _infoForRegularRegister.value(e->index, 0); + if (ri) { + *out << dumpStart(e); + *out << ri->prettyName(); + *out << dumpEnd(e); + break; + } + } + default: + IRPrinterWithPositions::visitTemp(e); + } + } +}; +} + class RegAllocInfo: public IRDecoder { struct Def { - unsigned defStmt : 30; + unsigned valid : 1; unsigned canHaveReg : 1; unsigned isPhiTarget : 1; - Def(): defStmt(0), canHaveReg(0), isPhiTarget(0) {} - Def(int defStmt, bool canHaveReg, bool isPhiTarget) - : defStmt(defStmt), canHaveReg(canHaveReg), isPhiTarget(isPhiTarget) + Def(): valid(0), canHaveReg(0), isPhiTarget(0) {} + Def(bool canHaveReg, bool isPhiTarget) + : valid(1), canHaveReg(canHaveReg), isPhiTarget(isPhiTarget) { - Q_ASSERT(defStmt > 0); - Q_ASSERT(defStmt < (1 << 30)); } - bool isValid() const { return defStmt != 0; } // 0 is invalid, as stmt numbers start at 1. + bool isValid() const { return valid != 0; } }; + IR::LifeTimeIntervals::Ptr _lifeTimeIntervals; + BasicBlock *_currentBB; Stmt *_currentStmt; - QHash<Temp, Def> _defs; - QHash<Temp, QList<Use> > _uses; - QList<int> _calls; - QHash<Temp, QList<Temp> > _hints; + std::vector<Def> _defs; + std::vector<std::vector<Use> > _uses; + std::vector<int> _calls; + std::vector<QList<Temp> > _hints; + + int defPosition(Stmt *s) const + { + return usePosition(s) + 1; + } + + int usePosition(Stmt *s) const + { + return _lifeTimeIntervals->positionForStatement(s); + } public: - RegAllocInfo(): _currentStmt(0) {} + RegAllocInfo(): _currentBB(0), _currentStmt(0) {} - void collect(IR::Function *function) + void collect(IR::Function *function, const IR::LifeTimeIntervals::Ptr &lifeTimeIntervals) { + _lifeTimeIntervals = lifeTimeIntervals; + _defs.resize(function->tempCount); + _uses.resize(function->tempCount); + _calls.reserve(function->statementCount() / 3); + _hints.resize(function->tempCount); + foreach (BasicBlock *bb, function->basicBlocks()) { + _currentBB = bb; foreach (Stmt *s, bb->statements()) { - Q_ASSERT(s->id > 0); _currentStmt = s; s->accept(this); } } } - QList<Use> uses(const Temp &t) const { return _uses[t]; } + const std::vector<Use> &uses(const Temp &t) const + { + return _uses[t.index]; + } + bool useMustHaveReg(const Temp &t, int position) { foreach (const Use &use, uses(t)) if (use.pos == position) @@ -121,45 +211,52 @@ public: return false; } - int def(const Temp &t) const { - Q_ASSERT(_defs[t].isValid()); - return _defs[t].defStmt; - } bool canHaveRegister(const Temp &t) const { - Q_ASSERT(_defs[t].isValid()); - return _defs[t].canHaveReg; + Q_ASSERT(_defs[t.index].isValid()); + return _defs[t.index].canHaveReg; } bool isPhiTarget(const Temp &t) const { - Q_ASSERT(_defs[t].isValid()); - return _defs[t].isPhiTarget; + Q_ASSERT(_defs[t.index].isValid()); + return _defs[t.index].isPhiTarget; } - const QList<int> &calls() const { return _calls; } - QList<Temp> hints(const Temp &t) const { return _hints[t]; } + const std::vector<int> &calls() const { return _calls; } + const QList<Temp> &hints(const Temp &t) const { return _hints[t.index]; } void addHint(const Temp &t, int physicalRegister) + { addHint(t, Temp::PhysicalRegister, physicalRegister); } + + void addHint(const Temp &t, Temp::Kind kind, int hintedIndex) { + QList<Temp> &hints = _hints[t.index]; + foreach (const Temp &hint, hints) + if (hint.index == hintedIndex) + return; + Temp hint; - hint.init(Temp::PhysicalRegister, physicalRegister, 0); - _hints[t].append(hint); + hint.init(kind, hintedIndex); + hints.append(hint); } -#ifdef DEBUG_REGALLOC void dump() const { + if (!DebugRegAlloc) + return; + QTextStream qout(stdout, QIODevice::WriteOnly); + IRPrinterWithPositions printer(&qout, _lifeTimeIntervals); qout << "RegAllocInfo:" << endl << "Defs/uses:" << endl; - QList<Temp> temps = _defs.keys(); - std::sort(temps.begin(), temps.end()); - foreach (const Temp &t, temps) { - t.dump(qout); - qout << " def at " << _defs[t].defStmt << " (" + for (unsigned t = 0; t < _defs.size(); ++t) { + const std::vector<Use> &uses = _uses[t]; + if (uses.empty()) + continue; + qout << "%" << t <<": " + << " (" << (_defs[t].canHaveReg ? "can" : "can NOT") << " have a register, and " - << (isPhiTarget(t) ? "is" : "is NOT") + << (_defs[t].isPhiTarget ? "is" : "is NOT") << " defined by a phi node), uses at: "; - const QList<Use> &uses = _uses[t]; - for (int i = 0; i < uses.size(); ++i) { + for (unsigned i = 0; i < uses.size(); ++i) { if (i > 0) qout << ", "; qout << uses[i].pos; if (uses[i].mustHaveRegister()) qout << "(R)"; else qout << "(S)"; @@ -168,66 +265,62 @@ public: } qout << "Calls at: "; - for (int i = 0; i < _calls.size(); ++i) { + for (unsigned i = 0; i < _calls.size(); ++i) { if (i > 0) qout << ", "; qout << _calls[i]; } qout << endl; qout << "Hints:" << endl; - QList<Temp> hinted = _hints.keys(); - if (hinted.isEmpty()) - qout << "\t(none)" << endl; - std::sort(hinted.begin(), hinted.end()); - foreach (const Temp &t, hinted) { - qout << "\t"; - t.dump(qout); - qout << ": "; + for (unsigned t = 0; t < _hints.size(); ++t) { + if (_uses[t].empty()) + continue; + qout << "\t%" << t << ": "; QList<Temp> hints = _hints[t]; for (int i = 0; i < hints.size(); ++i) { if (i > 0) qout << ", "; - hints[i].dump(qout); + printer.print(hints[i]); } qout << endl; } } -#endif // DEBUG_REGALLOC protected: // IRDecoder - virtual void callBuiltinInvalid(IR::Name *, IR::ExprList *, IR::Temp *) {} - virtual void callBuiltinTypeofMember(IR::Expr *, const QString &, IR::Temp *) {} - virtual void callBuiltinTypeofSubscript(IR::Expr *, IR::Expr *, IR::Temp *) {} - virtual void callBuiltinTypeofName(const QString &, IR::Temp *) {} - virtual void callBuiltinTypeofValue(IR::Expr *, IR::Temp *) {} - virtual void callBuiltinDeleteMember(IR::Temp *, const QString &, IR::Temp *) {} - virtual void callBuiltinDeleteSubscript(IR::Temp *, IR::Expr *, IR::Temp *) {} - virtual void callBuiltinDeleteName(const QString &, IR::Temp *) {} - virtual void callBuiltinDeleteValue(IR::Temp *) {} + virtual void callBuiltinInvalid(IR::Name *, IR::ExprList *, IR::Expr *) {} + virtual void callBuiltinTypeofMember(IR::Expr *, const QString &, IR::Expr *) {} + virtual void callBuiltinTypeofSubscript(IR::Expr *, IR::Expr *, IR::Expr *) {} + virtual void callBuiltinTypeofName(const QString &, IR::Expr *) {} + virtual void callBuiltinTypeofValue(IR::Expr *, IR::Expr *) {} + virtual void callBuiltinDeleteMember(IR::Expr *, const QString &, IR::Expr *) {} + virtual void callBuiltinDeleteSubscript(IR::Expr *, IR::Expr *, IR::Expr *) {} + virtual void callBuiltinDeleteName(const QString &, IR::Expr *) {} + virtual void callBuiltinDeleteValue(IR::Expr *) {} virtual void callBuiltinThrow(IR::Expr *) {} virtual void callBuiltinReThrow() {} - virtual void callBuiltinUnwindException(IR::Temp *) {} + virtual void callBuiltinUnwindException(IR::Expr *) {} virtual void callBuiltinPushCatchScope(const QString &) {}; - virtual void callBuiltinForeachIteratorObject(IR::Expr *, IR::Temp *) {} + virtual void callBuiltinForeachIteratorObject(IR::Expr *, IR::Expr *) {} virtual void callBuiltinForeachNextProperty(IR::Temp *, IR::Temp *) {} - virtual void callBuiltinForeachNextPropertyname(IR::Temp *, IR::Temp *) {} - virtual void callBuiltinPushWithScope(IR::Temp *) {} + virtual void callBuiltinForeachNextPropertyname(IR::Expr *, IR::Expr *) {} + virtual void callBuiltinPushWithScope(IR::Expr *) {} virtual void callBuiltinPopScope() {} virtual void callBuiltinDeclareVar(bool , const QString &) {} - virtual void callBuiltinDefineArray(IR::Temp *, IR::ExprList *) {} - virtual void callBuiltinDefineObjectLiteral(IR::Temp *, int, IR::ExprList *, IR::ExprList *, bool) {} - virtual void callBuiltinSetupArgumentObject(IR::Temp *) {} + virtual void callBuiltinDefineArray(IR::Expr *, IR::ExprList *) {} + virtual void callBuiltinDefineObjectLiteral(IR::Expr *, int, IR::ExprList *, IR::ExprList *, bool) {} + virtual void callBuiltinSetupArgumentObject(IR::Expr *) {} virtual void callBuiltinConvertThisToObject() {} - virtual void callValue(IR::Temp *value, IR::ExprList *args, IR::Temp *result) + virtual void callValue(IR::Expr *value, IR::ExprList *args, IR::Expr *result) { addDef(result); - addUses(value, Use::CouldHaveRegister); + if (IR::Temp *tempValue = value->asTemp()) + addUses(tempValue, Use::CouldHaveRegister); addUses(args, Use::CouldHaveRegister); addCall(); } virtual void callProperty(IR::Expr *base, const QString &name, IR::ExprList *args, - IR::Temp *result) + IR::Expr *result) { Q_UNUSED(name) @@ -238,7 +331,7 @@ protected: // IRDecoder } virtual void callSubscript(IR::Expr *base, IR::Expr *index, IR::ExprList *args, - IR::Temp *result) + IR::Expr *result) { addDef(result); addUses(base->asTemp(), Use::CouldHaveRegister); @@ -247,7 +340,7 @@ protected: // IRDecoder addCall(); } - virtual void convertType(IR::Temp *source, IR::Temp *target) + virtual void convertType(IR::Expr *source, IR::Expr *target) { addDef(target); @@ -310,22 +403,24 @@ protected: // IRDecoder break; } - addUses(source, sourceReg); + Temp *sourceTemp = source->asTemp(); + if (sourceTemp) + addUses(sourceTemp, sourceReg); if (needsCall) addCall(); - else - addHint(target, source); + else if (target->asTemp()) + addHint(target->asTemp(), sourceTemp); } - virtual void constructActivationProperty(IR::Name *, IR::ExprList *args, IR::Temp *result) + virtual void constructActivationProperty(IR::Name *, IR::ExprList *args, IR::Expr *result) { addDef(result); addUses(args, Use::CouldHaveRegister); addCall(); } - virtual void constructProperty(IR::Temp *base, const QString &, IR::ExprList *args, IR::Temp *result) + virtual void constructProperty(IR::Expr *base, const QString &, IR::ExprList *args, IR::Expr *result) { addDef(result); addUses(base, Use::CouldHaveRegister); @@ -333,7 +428,7 @@ protected: // IRDecoder addCall(); } - virtual void constructValue(IR::Temp *value, IR::ExprList *args, IR::Temp *result) + virtual void constructValue(IR::Expr *value, IR::ExprList *args, IR::Expr *result) { addDef(result); addUses(value, Use::CouldHaveRegister); @@ -341,30 +436,30 @@ protected: // IRDecoder addCall(); } - virtual void loadThisObject(IR::Temp *temp) + virtual void loadThisObject(IR::Expr *temp) { addDef(temp); } - virtual void loadQmlIdArray(IR::Temp *temp) + virtual void loadQmlIdArray(IR::Expr *temp) { addDef(temp); addCall(); } - virtual void loadQmlImportedScripts(IR::Temp *temp) + virtual void loadQmlImportedScripts(IR::Expr *temp) { addDef(temp); addCall(); } - virtual void loadQmlContextObject(Temp *temp) + virtual void loadQmlContextObject(Expr *temp) { addDef(temp); addCall(); } - virtual void loadQmlScopeObject(Temp *temp) + virtual void loadQmlScopeObject(Expr *temp) { Q_UNUSED(temp); @@ -372,7 +467,7 @@ protected: // IRDecoder addCall(); } - virtual void loadQmlSingleton(const QString &/*name*/, Temp *temp) + virtual void loadQmlSingleton(const QString &/*name*/, Expr *temp) { Q_UNUSED(temp); @@ -380,21 +475,21 @@ protected: // IRDecoder addCall(); } - virtual void loadConst(IR::Const *sourceConst, IR::Temp *targetTemp) + virtual void loadConst(IR::Const *sourceConst, Expr *targetTemp) { Q_UNUSED(sourceConst); addDef(targetTemp); } - virtual void loadString(const QString &str, IR::Temp *targetTemp) + virtual void loadString(const QString &str, Expr *targetTemp) { Q_UNUSED(str); addDef(targetTemp); } - virtual void loadRegexp(IR::RegExp *sourceRegexp, IR::Temp *targetTemp) + virtual void loadRegexp(IR::RegExp *sourceRegexp, Expr *targetTemp) { Q_UNUSED(sourceRegexp); @@ -402,7 +497,7 @@ protected: // IRDecoder addCall(); } - virtual void getActivationProperty(const IR::Name *, IR::Temp *temp) + virtual void getActivationProperty(const IR::Name *, Expr *temp) { addDef(temp); addCall(); @@ -414,7 +509,7 @@ protected: // IRDecoder addCall(); } - virtual void initClosure(IR::Closure *closure, IR::Temp *target) + virtual void initClosure(IR::Closure *closure, Expr *target) { Q_UNUSED(closure); @@ -422,7 +517,7 @@ protected: // IRDecoder addCall(); } - virtual void getProperty(IR::Expr *base, const QString &, IR::Temp *target) + virtual void getProperty(IR::Expr *base, const QString &, Expr *target) { addDef(target); addUses(base->asTemp(), Use::CouldHaveRegister); @@ -443,14 +538,14 @@ protected: // IRDecoder addCall(); } - virtual void getQObjectProperty(IR::Expr *base, int /*propertyIndex*/, bool /*captureRequired*/, int /*attachedPropertiesId*/, IR::Temp *target) + virtual void getQObjectProperty(IR::Expr *base, int /*propertyIndex*/, bool /*captureRequired*/, int /*attachedPropertiesId*/, IR::Expr *target) { addDef(target); addUses(base->asTemp(), Use::CouldHaveRegister); addCall(); } - virtual void getElement(IR::Expr *base, IR::Expr *index, IR::Temp *target) + virtual void getElement(IR::Expr *base, IR::Expr *index, Expr *target) { addDef(target); addUses(base->asTemp(), Use::CouldHaveRegister); @@ -466,25 +561,30 @@ protected: // IRDecoder addCall(); } - virtual void copyValue(IR::Temp *sourceTemp, IR::Temp *targetTemp) + virtual void copyValue(Expr *source, Expr *target) { - addDef(targetTemp); + addDef(target); + Temp *sourceTemp = source->asTemp(); + if (!sourceTemp) + return; addUses(sourceTemp, Use::CouldHaveRegister); - addHint(targetTemp, sourceTemp); + Temp *targetTemp = target->asTemp(); + if (targetTemp) + addHint(targetTemp, sourceTemp); } - virtual void swapValues(IR::Temp *, IR::Temp *) + virtual void swapValues(Expr *, Expr *) { // Inserted by the register allocator, so it cannot occur here. Q_UNREACHABLE(); } - virtual void unop(AluOp oper, Temp *sourceTemp, Temp *targetTemp) + virtual void unop(AluOp oper, Expr *source, Expr *target) { - addDef(targetTemp); + addDef(target); bool needsCall = true; - if (oper == OpNot && sourceTemp->type == IR::BoolType && targetTemp->type == IR::BoolType) + if (oper == OpNot && source->type == IR::BoolType && target->type == IR::BoolType) needsCall = false; #if 0 // TODO: change masm to generate code @@ -504,15 +604,18 @@ protected: // IRDecoder } #endif + IR::Temp *sourceTemp = source->asTemp(); if (needsCall) { - addUses(sourceTemp, Use::CouldHaveRegister); + if (sourceTemp) + addUses(sourceTemp, Use::CouldHaveRegister); addCall(); } else { - addUses(sourceTemp, Use::MustHaveRegister); + if (sourceTemp) + addUses(sourceTemp, Use::MustHaveRegister); } } - virtual void binop(AluOp oper, Expr *leftSource, Expr *rightSource, Temp *target) + virtual void binop(AluOp oper, Expr *leftSource, Expr *rightSource, Expr *target) { bool needsCall = true; @@ -590,25 +693,31 @@ protected: // IRDecoder if (Temp *t = e->asTemp()) { addUses(t, Use::CouldHaveRegister); addHint(s->targetTemp, t); + addHint(t, s->targetTemp); } } } protected: - virtual void callBuiltin(IR::Call *c, IR::Temp *result) + virtual void callBuiltin(IR::Call *c, IR::Expr *result) { addDef(result); - addUses(c->base->asTemp(), Use::CouldHaveRegister); + addUses(c->base, Use::CouldHaveRegister); addUses(c->args, Use::CouldHaveRegister); addCall(); } private: - void addDef(Temp *t, bool isPhiTarget = false) + void addDef(Expr *e, bool isPhiTarget = false) { + if (!e) + return; + Temp *t = e->asTemp(); + if (!t) + return; if (!t || t->kind != Temp::VirtualRegister) return; - Q_ASSERT(!_defs.contains(*t)); + Q_ASSERT(!_defs[t->index].isValid()); bool canHaveReg = true; switch (t->type) { case QObjectType: @@ -622,25 +731,40 @@ private: break; } - _defs[*t] = Def(_currentStmt->id, canHaveReg, isPhiTarget); + _defs[t->index] = Def(canHaveReg, isPhiTarget); } - void addUses(Temp *t, Use::RegisterFlag flag) + void addUses(Expr *e, Use::RegisterFlag flag) { - Q_ASSERT(_currentStmt->id > 0); + int usePos = usePosition(_currentStmt); + if (usePos == Stmt::InvalidId) + usePos = _lifeTimeIntervals->startPosition(_currentBB); + Q_ASSERT(usePos > 0); + if (!e) + return; + Temp *t = e->asTemp(); + if (!t) + return; if (t && t->kind == Temp::VirtualRegister) - _uses[*t].append(Use(_currentStmt->id, flag)); + _uses[t->index].push_back(Use(usePosition(_currentStmt), flag)); } void addUses(ExprList *l, Use::RegisterFlag flag) { for (ExprList *it = l; it; it = it->next) - addUses(it->expr->asTemp(), flag); + addUses(it->expr, flag); } void addCall() { - _calls.append(_currentStmt->id); + _calls.push_back(usePosition(_currentStmt)); + } + + void addHint(Expr *hinted, Temp *hint1, Temp *hint2 = 0) + { + if (hinted) + if (Temp *hintedTemp = hinted->asTemp()) + addHint(hintedTemp, hint1, hint2); } void addHint(Temp *hinted, Temp *hint1, Temp *hint2 = 0) @@ -648,9 +772,9 @@ private: if (!hinted || hinted->kind != Temp::VirtualRegister) return; if (hint1 && hint1->kind == Temp::VirtualRegister && hinted->type == hint1->type) - _hints[*hinted].append(*hint1); + addHint(*hinted, Temp::VirtualRegister, hint1->index); if (hint2 && hint2->kind == Temp::VirtualRegister && hinted->type == hint2->type) - _hints[*hinted].append(*hint2); + addHint(*hinted, Temp::VirtualRegister, hint2->index); } }; @@ -666,16 +790,15 @@ using namespace QT_PREPEND_NAMESPACE(QV4); namespace { class ResolutionPhase: protected StmtVisitor, protected ExprVisitor { - const QVector<LifeTimeInterval> &_intervals; - QVector<const LifeTimeInterval *> _unprocessed; + Q_DISABLE_COPY(ResolutionPhase) + + LifeTimeIntervals::Ptr _intervals; + QVector<LifeTimeInterval *> _unprocessed; IR::Function *_function; -#if !defined(QT_NO_DEBUG) - RegAllocInfo *_info; -#endif - const QHash<IR::Temp, int> &_assignedSpillSlots; + const std::vector<int> &_assignedSpillSlots; QHash<IR::Temp, const LifeTimeInterval *> _intervalForTemp; - const QVector<int> &_intRegs; - const QVector<int> &_fpRegs; + const QVector<const RegisterInfo *> &_intRegs; + const QVector<const RegisterInfo *> &_fpRegs; Stmt *_currentStmt; QVector<Move *> _loads; @@ -685,54 +808,64 @@ class ResolutionPhase: protected StmtVisitor, protected ExprVisitor { QHash<BasicBlock *, QList<const LifeTimeInterval *> > _liveAtEnd; public: - ResolutionPhase(const QVector<LifeTimeInterval> &intervals, IR::Function *function, RegAllocInfo *info, - const QHash<IR::Temp, int> &assignedSpillSlots, - const QVector<int> &intRegs, const QVector<int> &fpRegs) + ResolutionPhase(const QVector<LifeTimeInterval *> &unprocessed, + const LifeTimeIntervals::Ptr &intervals, + IR::Function *function, + const std::vector<int> &assignedSpillSlots, + const QVector<const RegisterInfo *> &intRegs, + const QVector<const RegisterInfo *> &fpRegs) : _intervals(intervals) , _function(function) -#if !defined(QT_NO_DEBUG) - , _info(info) -#endif , _assignedSpillSlots(assignedSpillSlots) , _intRegs(intRegs) , _fpRegs(fpRegs) { -#if defined(QT_NO_DEBUG) - Q_UNUSED(info) -#endif - - _unprocessed.resize(_intervals.size()); - for (int i = 0, ei = _intervals.size(); i != ei; ++i) - _unprocessed[i] = &_intervals[i]; - + _unprocessed = unprocessed; _liveAtStart.reserve(function->basicBlockCount()); _liveAtEnd.reserve(function->basicBlockCount()); } void run() { renumber(); - Optimizer::showMeTheCode(_function); + if (DebugRegAlloc) { + QTextStream qout(stdout, QIODevice::WriteOnly); + IRPrinterWithPositions(&qout, _intervals).print(_function); + } resolve(); } private: + int defPosition(Stmt *s) const + { + return usePosition(s) + 1; + } + + int usePosition(Stmt *s) const + { + return _intervals->positionForStatement(s); + } + void renumber() { foreach (BasicBlock *bb, _function->basicBlocks()) { + _currentStmt = 0; + QVector<Stmt *> statements = bb->statements(); QVector<Stmt *> newStatements; newStatements.reserve(bb->statements().size() + 7); - bool seenFirstNonPhiStmt = false; + cleanOldIntervals(_intervals->startPosition(bb)); + addNewIntervals(_intervals->startPosition(bb)); + _liveAtStart[bb] = _intervalForTemp.values(); + for (int i = 0, ei = statements.size(); i != ei; ++i) { - _currentStmt = statements[i]; + _currentStmt = statements.at(i); _loads.clear(); _stores.clear(); - addNewIntervals(); - if (!seenFirstNonPhiStmt && !_currentStmt->asPhi()) { - seenFirstNonPhiStmt = true; - _liveAtStart[bb] = _intervalForTemp.values(); - } + if (_currentStmt->asTerminator()) + addNewIntervals(usePosition(_currentStmt)); + else + addNewIntervals(defPosition(_currentStmt)); _currentStmt->accept(this); foreach (Move *load, _loads) newStatements.append(load); @@ -744,90 +877,71 @@ private: newStatements.append(store); } - cleanOldIntervals(); + cleanOldIntervals(_intervals->endPosition(bb)); _liveAtEnd[bb] = _intervalForTemp.values(); -#ifdef DEBUG_REGALLOC - QTextStream os(stdout, QIODevice::WriteOnly); - os << "Intervals live at the start of L" << bb->index << ":" << endl; - if (_liveAtStart[bb].isEmpty()) - os << "\t(none)" << endl; - foreach (const LifeTimeInterval *i, _liveAtStart[bb]) { - os << "\t"; - i->dump(os); - os << endl; - } - os << "Intervals live at the end of L" << bb->index << ":" << endl; - if (_liveAtEnd[bb].isEmpty()) - os << "\t(none)" << endl; - foreach (const LifeTimeInterval *i, _liveAtEnd[bb]) { - os << "\t"; - i->dump(os); - os << endl; + if (DebugRegAlloc) { + QTextStream os(stdout, QIODevice::WriteOnly); + os << "Intervals live at the start of L" << bb->index() << ":" << endl; + if (_liveAtStart[bb].isEmpty()) + os << "\t(none)" << endl; + foreach (const LifeTimeInterval *i, _liveAtStart[bb]) { + os << "\t"; + i->dump(os); + os << endl; + } + os << "Intervals live at the end of L" << bb->index() << ":" << endl; + if (_liveAtEnd[bb].isEmpty()) + os << "\t(none)" << endl; + foreach (const LifeTimeInterval *i, _liveAtEnd[bb]) { + os << "\t"; + i->dump(os); + os << endl; + } } -#endif bb->setStatements(newStatements); } } - void activate(const LifeTimeInterval *i) + void maybeGenerateSpill(Temp *t) { - Q_ASSERT(!i->isFixedInterval()); - _intervalForTemp[i->temp()] = i; + const LifeTimeInterval *i = _intervalForTemp[*t]; + if (i->reg() == LifeTimeInterval::InvalidRegister) + return; - if (i->reg() != LifeTimeInterval::Invalid) { - // check if we need to generate spill/unspill instructions - if (i->start() == _currentStmt->id) { - if (i->isSplitFromInterval()) { - int pReg = platformRegister(*i); - _loads.append(generateUnspill(i->temp(), pReg)); - } else { - int pReg = platformRegister(*i); - int spillSlot = _assignedSpillSlots.value(i->temp(), -1); - if (spillSlot != -1) - _stores.append(generateSpill(spillSlot, i->temp().type, pReg)); - } - } - } + const RegisterInfo *pReg = platformRegister(*i); + Q_ASSERT(pReg); + int spillSlot = _assignedSpillSlots[i->temp().index]; + if (spillSlot != RegisterAllocator::InvalidSpillSlot) + _stores.append(generateSpill(spillSlot, i->temp().type, pReg->reg<int>())); } - void addNewIntervals() + void addNewIntervals(int position) { - if (Phi *phi = _currentStmt->asPhi()) { - // for phi nodes, only activate the range belonging to that node - for (int it = 0, eit = _unprocessed.size(); it != eit; ++it) { - const LifeTimeInterval *i = _unprocessed.at(it); - if (i->start() > _currentStmt->id) - break; - if (i->temp() == *phi->targetTemp) { - activate(i); - _unprocessed.remove(it); - break; - } - } + if (position == Stmt::InvalidId) return; - } while (!_unprocessed.isEmpty()) { const LifeTimeInterval *i = _unprocessed.first(); - if (i->start() > _currentStmt->id) + if (i->start() > position) break; - activate(i); + Q_ASSERT(!i->isFixedInterval()); + _intervalForTemp[i->temp()] = i; +// qDebug() << "-- Activating interval for temp" << i->temp().index; _unprocessed.removeFirst(); } } - void cleanOldIntervals() + void cleanOldIntervals(int position) { - const int id = _currentStmt->id; QMutableHashIterator<Temp, const LifeTimeInterval *> it(_intervalForTemp); while (it.hasNext()) { const LifeTimeInterval *i = it.next().value(); - if (i->end() < id || i->isFixedInterval()) + if (i->end() < position || i->isFixedInterval()) it.remove(); } } @@ -840,77 +954,75 @@ private: } } - void resolveEdge(BasicBlock *predecessor, BasicBlock *successor) + Phi *findDefPhi(const Temp &t, BasicBlock *bb) const { -#ifdef DEBUG_REGALLOC - Optimizer::showMeTheCode(_function); - qDebug() << "Resolving edge" << predecessor->index << "->" << successor->index; -#endif // DEBUG_REGALLOC + foreach (Stmt *s, bb->statements()) { + Phi *phi = s->asPhi(); + if (!phi) + return 0; - MoveMapping mapping; + if (*phi->targetTemp == t) + return phi; + } - const int predecessorEnd = predecessor->terminator()->id; // the terminator is always last and always has an id set... - Q_ASSERT(predecessorEnd > 0); // ... but we verify it anyway for good measure. + Q_UNREACHABLE(); + } - int successorStart = -1; - foreach (Stmt *s, successor->statements()) { - if (s && s->id > 0) { - successorStart = s->id; - break; - } + void resolveEdge(BasicBlock *predecessor, BasicBlock *successor) + { + if (DebugRegAlloc) { + qDebug() << "Resolving edge" << predecessor->index() << "->" << successor->index(); + QTextStream qout(stdout, QIODevice::WriteOnly); + IRPrinterWithPositions printer(&qout, _intervals); + printer.print(predecessor); + printer.print(successor); + qout.flush(); } + MoveMapping mapping; + + const int predecessorEnd = _intervals->endPosition(predecessor); + Q_ASSERT(predecessorEnd > 0); + + int successorStart = _intervals->startPosition(successor); Q_ASSERT(successorStart > 0); foreach (const LifeTimeInterval *it, _liveAtStart[successor]) { - if (it->end() < successorStart) - continue; - bool isPhiTarget = false; Expr *moveFrom = 0; if (it->start() == successorStart) { - foreach (Stmt *s, successor->statements()) { - if (!s || s->id < 1) - continue; - if (Phi *phi = s->asPhi()) { - if (*phi->targetTemp == it->temp()) { - isPhiTarget = true; - Expr *opd = phi->d->incoming[successor->in.indexOf(predecessor)]; - if (opd->asConst()) { - moveFrom = opd; - } else { - Temp *t = opd->asTemp(); - Q_ASSERT(t); - - foreach (const LifeTimeInterval *it2, _liveAtEnd[predecessor]) { - if (it2->temp() == *t - && it2->reg() != LifeTimeInterval::Invalid - && it2->covers(predecessorEnd)) { - moveFrom = createTemp(Temp::PhysicalRegister, - platformRegister(*it2), t->type); - break; - } - } - if (!moveFrom) - moveFrom = createTemp(Temp::StackSlot, - _assignedSpillSlots.value(*t, -1), - t->type); + if (Phi *phi = findDefPhi(it->temp(), successor)) { + isPhiTarget = true; + Expr *opd = phi->d->incoming[successor->in.indexOf(predecessor)]; + if (opd->asConst()) { + moveFrom = opd; + } else { + Temp *t = opd->asTemp(); + Q_ASSERT(t); + + foreach (const LifeTimeInterval *it2, _liveAtEnd[predecessor]) { + if (it2->temp() == *t + && it2->reg() != LifeTimeInterval::InvalidRegister + && it2->covers(predecessorEnd)) { + moveFrom = createPhysicalRegister(it2, t->type); + break; } } - } else { - break; + if (!moveFrom) + moveFrom = createTemp(Temp::StackSlot, + _assignedSpillSlots[t->index], + t->type); } } } else { foreach (const LifeTimeInterval *predIt, _liveAtEnd[predecessor]) { if (predIt->temp() == it->temp()) { - if (predIt->reg() != LifeTimeInterval::Invalid + if (predIt->reg() != LifeTimeInterval::InvalidRegister && predIt->covers(predecessorEnd)) { - moveFrom = createTemp(Temp::PhysicalRegister, platformRegister(*predIt), - predIt->temp().type); + moveFrom = createPhysicalRegister(predIt, predIt->temp().type); } else { - int spillSlot = _assignedSpillSlots.value(predIt->temp(), -1); + int spillSlot = _assignedSpillSlots[predIt->temp().index]; if (spillSlot != -1) moveFrom = createTemp(Temp::StackSlot, spillSlot, predIt->temp().type); } @@ -919,14 +1031,14 @@ private: } } if (!moveFrom) { -#if !defined(QT_NO_DEBUG) +#if !defined(QT_NO_DEBUG) && 0 bool lifeTimeHole = false; if (it->ranges().first().start <= successorStart && it->ranges().last().end >= successorStart) lifeTimeHole = !it->covers(successorStart); Q_ASSERT(!_info->isPhiTarget(it->temp()) || it->isSplitFromInterval() || lifeTimeHole); if (_info->def(it->temp()) != successorStart && !it->isSplitFromInterval()) { - const int successorEnd = successor->terminator()->id; + const int successorEnd = successor->terminator()->id(); const int idx = successor->in.indexOf(predecessor); foreach (const Use &use, _info->uses(it->temp())) { if (use.pos == static_cast<unsigned>(successorStart)) { @@ -956,15 +1068,15 @@ private: } Temp *moveTo; - if (it->reg() == LifeTimeInterval::Invalid || !it->covers(successorStart)) { + if (it->reg() == LifeTimeInterval::InvalidRegister || !it->covers(successorStart)) { if (!isPhiTarget) // if it->temp() is a phi target, skip it. continue; - const int spillSlot = _assignedSpillSlots.value(it->temp(), -1); - if (spillSlot == -1) + const int spillSlot = _assignedSpillSlots[it->temp().index]; + if (spillSlot == RegisterAllocator::InvalidSpillSlot) continue; // it has a life-time hole here. moveTo = createTemp(Temp::StackSlot, spillSlot, it->temp().type); } else { - moveTo = createTemp(Temp::PhysicalRegister, platformRegister(*it), it->temp().type); + moveTo = createPhysicalRegister(it, it->temp().type); } // add move to mapping @@ -972,37 +1084,52 @@ private: } mapping.order(); -#ifdef DEBUG_REGALLOC - mapping.dump(); -#endif // DEBUG_REGALLOC + if (DebugRegAlloc) + mapping.dump(); bool insertIntoPredecessor = successor->in.size() > 1; mapping.insertMoves(insertIntoPredecessor ? predecessor : successor, _function, insertIntoPredecessor); + + if (DebugRegAlloc) { + qDebug() << ".. done, result:"; + QTextStream qout(stdout, QIODevice::WriteOnly); + IRPrinterWithPositions printer(&qout, _intervals); + printer.print(predecessor); + printer.print(successor); + qout.flush(); + } } Temp *createTemp(Temp::Kind kind, int index, Type type) const { Q_ASSERT(index >= 0); Temp *t = _function->New<Temp>(); - t->init(kind, index, 0); + t->init(kind, index); t->type = type; return t; } - int platformRegister(const LifeTimeInterval &i) const + Temp *createPhysicalRegister(const LifeTimeInterval *i, Type type) const + { + const RegisterInfo *ri = platformRegister(*i); + Q_ASSERT(ri); + return createTemp(Temp::PhysicalRegister, ri->reg<int>(), type); + } + + const RegisterInfo *platformRegister(const LifeTimeInterval &i) const { if (i.isFP()) - return _fpRegs.value(i.reg(), -1); + return _fpRegs.value(i.reg(), 0); else - return _intRegs.value(i.reg(), -1); + return _intRegs.value(i.reg(), 0); } Move *generateSpill(int spillSlot, Type type, int pReg) const { Q_ASSERT(spillSlot >= 0); - Move *store = _function->New<Move>(); + Move *store = _function->NewStmt<Move>(); store->init(createTemp(Temp::StackSlot, spillSlot, type), createTemp(Temp::PhysicalRegister, pReg, type)); return store; @@ -1011,9 +1138,9 @@ private: Move *generateUnspill(const Temp &t, int pReg) const { Q_ASSERT(pReg >= 0); - int spillSlot = _assignedSpillSlots.value(t, -1); + int spillSlot = _assignedSpillSlots[t.index]; Q_ASSERT(spillSlot != -1); - Move *load = _function->New<Move>(); + Move *load = _function->NewStmt<Move>(); load->init(createTemp(Temp::PhysicalRegister, pReg, t.type), createTemp(Temp::StackSlot, spillSlot, t.type)); return load; @@ -1027,18 +1154,30 @@ protected: const LifeTimeInterval *i = _intervalForTemp[*t]; Q_ASSERT(i->isValid()); - if (i->reg() != LifeTimeInterval::Invalid && i->covers(_currentStmt->id)) { - int pReg = platformRegister(*i); + + if (_currentStmt != 0 && i->start() == usePosition(_currentStmt)) { + Q_ASSERT(i->isSplitFromInterval()); + const RegisterInfo *pReg = platformRegister(*i); + Q_ASSERT(pReg); + _loads.append(generateUnspill(i->temp(), pReg->reg<int>())); + } + + if (i->reg() != LifeTimeInterval::InvalidRegister && + (i->covers(defPosition(_currentStmt)) || + i->covers(usePosition(_currentStmt)))) { + const RegisterInfo *pReg = platformRegister(*i); + Q_ASSERT(pReg); t->kind = Temp::PhysicalRegister; - t->index = pReg; + t->index = pReg->reg<unsigned>(); } else { - int stackSlot = _assignedSpillSlots.value(*t, -1); + int stackSlot = _assignedSpillSlots[t->index]; Q_ASSERT(stackSlot >= 0); t->kind = Temp::StackSlot; t->index = stackSlot; } } + virtual void visitArgLocal(ArgLocal *) {} virtual void visitConst(Const *) {} virtual void visitString(IR::String *) {} virtual void visitRegExp(IR::RegExp *) {} @@ -1063,21 +1202,41 @@ protected: } virtual void visitExp(Exp *s) { s->expr->accept(this); } - virtual void visitMove(Move *s) { s->source->accept(this); s->target->accept(this); } + + virtual void visitMove(Move *s) + { + if (Temp *t = s->target->asTemp()) + maybeGenerateSpill(t); + + s->source->accept(this); + s->target->accept(this); + } + virtual void visitJump(Jump *) {} virtual void visitCJump(CJump *s) { s->cond->accept(this); } virtual void visitRet(Ret *s) { s->expr->accept(this); } - virtual void visitPhi(Phi *) {} + virtual void visitPhi(Phi *s) + { + maybeGenerateSpill(s->targetTemp); + } }; } // anonymous namespace -RegisterAllocator::RegisterAllocator(const QVector<int> &normalRegisters, const QVector<int> &fpRegisters) - : _normalRegisters(normalRegisters) - , _fpRegisters(fpRegisters) +RegisterAllocator::RegisterAllocator(const QV4::JIT::RegisterInformation ®isterInformation) + : _registerInformation(registerInformation) { - Q_ASSERT(normalRegisters.size() >= 2); - Q_ASSERT(fpRegisters.size() >= 2); - _active.reserve((normalRegisters.size() + fpRegisters.size()) * 2); + for (int i = 0, ei = registerInformation.size(); i != ei; ++i) { + const RegisterInfo ®Info = registerInformation.at(i); + if (regInfo.useForRegAlloc()) { + if (regInfo.isRegularRegister()) + _normalRegisters.append(®Info); + else + _fpRegisters.append(®Info); + } + } + Q_ASSERT(_normalRegisters.size() >= 2); + Q_ASSERT(_fpRegisters.size() >= 2); + _active.reserve((_normalRegisters.size() + _fpRegisters.size()) * 2); _inactive.reserve(_active.size()); } @@ -1087,54 +1246,58 @@ RegisterAllocator::~RegisterAllocator() void RegisterAllocator::run(IR::Function *function, const Optimizer &opt) { - _lastAssignedRegister.reserve(function->tempCount); - _assignedSpillSlots.reserve(function->tempCount); + _lastAssignedRegister.assign(function->tempCount, LifeTimeInterval::InvalidRegister); + _assignedSpillSlots.assign(function->tempCount, InvalidSpillSlot); _activeSpillSlots.resize(function->tempCount); -#ifdef DEBUG_REGALLOC - qDebug() << "*** Running regalloc for function" << (function->name ? qPrintable(*function->name) : "NO NAME") << "***"; -#endif // DEBUG_REGALLOC + if (DebugRegAlloc) + qDebug() << "*** Running regalloc for function" << (function->name ? qPrintable(*function->name) : "NO NAME") << "***"; + + _lifeTimeIntervals = opt.lifeTimeIntervals(); - _unhandled = opt.lifeTimeIntervals(); + _unhandled = _lifeTimeIntervals->intervals(); _handled.reserve(_unhandled.size()); _info.reset(new RegAllocInfo); - _info->collect(function); + _info->collect(function, _lifeTimeIntervals); -#ifdef DEBUG_REGALLOC - { + if (DebugRegAlloc) { QTextStream qout(stdout, QIODevice::WriteOnly); qout << "Ranges:" << endl; - QVector<LifeTimeInterval> intervals = _unhandled; - std::sort(intervals.begin(), intervals.end(), LifeTimeInterval::lessThanForTemp); - foreach (const LifeTimeInterval &r, intervals) { - r.dump(qout); + QVector<LifeTimeInterval *> intervals = _unhandled; + std::reverse(intervals.begin(), intervals.end()); + foreach (const LifeTimeInterval *r, intervals) { + r->dump(qout); qout << endl; } + _info->dump(); } - _info->dump(); -#endif // DEBUG_REGALLOC + if (DebugRegAlloc) { + qDebug() << "*** Before register allocation:"; + QTextStream qout(stdout, QIODevice::WriteOnly); + IRPrinterWithPositions(&qout, _lifeTimeIntervals).print(function); + } prepareRanges(); - Optimizer::showMeTheCode(function); - linearScan(); -#ifdef DEBUG_REGALLOC - dump(); -#endif // DEBUG_REGALLOC + if (DebugRegAlloc) + dump(function); std::sort(_handled.begin(), _handled.end(), LifeTimeInterval::lessThan); - ResolutionPhase(_handled, function, _info.data(), _assignedSpillSlots, _normalRegisters, _fpRegisters).run(); + ResolutionPhase(_handled, _lifeTimeIntervals, function, _assignedSpillSlots, _normalRegisters, _fpRegisters).run(); - function->tempCount = QSet<int>::fromList(_assignedSpillSlots.values()).size(); + function->tempCount = *std::max_element(_assignedSpillSlots.begin(), _assignedSpillSlots.end()) + 1; - Optimizer::showMeTheCode(function); + if (DebugRegAlloc) + qDebug() << "*** Finished regalloc , result:"; -#ifdef DEBUG_REGALLOC - qDebug() << "*** Finished regalloc for function" << (function->name ? qPrintable(*function->name) : "NO NAME") << "***"; -#endif // DEBUG_REGALLOC + static bool showCode = !qgetenv("QV4_SHOW_IR").isNull(); + if (showCode) { + QTextStream qout(stdout, QIODevice::WriteOnly); + IRPrinterWithRegisters(&qout, _lifeTimeIntervals, _registerInformation).print(function); + } } static inline LifeTimeInterval createFixedInterval(int rangeCount) @@ -1143,26 +1306,30 @@ static inline LifeTimeInterval createFixedInterval(int rangeCount) i.setReg(0); Temp t; - t.init(Temp::PhysicalRegister, 0, 0); + t.init(Temp::PhysicalRegister, 0); t.type = IR::SInt32Type; i.setTemp(t); return i; } -static inline LifeTimeInterval cloneFixedInterval(int reg, bool isFP, LifeTimeInterval lti) +LifeTimeInterval *RegisterAllocator::cloneFixedInterval(int reg, bool isFP, const LifeTimeInterval &original) { - lti.setReg(reg); - lti.setFixedInterval(true); + LifeTimeInterval *lti = new LifeTimeInterval(original); + _lifeTimeIntervals->add(lti); + lti->setReg(reg); + lti->setFixedInterval(true); Temp t; - t.init(Temp::PhysicalRegister, reg, 0); + t.init(Temp::PhysicalRegister, reg); t.type = isFP ? IR::DoubleType : IR::SInt32Type; - lti.setTemp(t); + lti->setTemp(t); return lti; } +// Creates the intervals with fixed ranges. See [Wimmer2]. Note that this only applies to callee- +// saved registers. void RegisterAllocator::prepareRanges() { LifeTimeInterval ltiWithCalls = createFixedInterval(_info->calls().size()); @@ -1172,37 +1339,41 @@ void RegisterAllocator::prepareRanges() const int regCount = _normalRegisters.size(); _fixedRegisterRanges.reserve(regCount); for (int reg = 0; reg < regCount; ++reg) { - LifeTimeInterval lti = cloneFixedInterval(reg, false, ltiWithCalls); - _fixedRegisterRanges.append(lti); - if (lti.isValid()) - _active.append(lti); + if (_normalRegisters.at(reg)->isCallerSaved()) { + LifeTimeInterval *lti = cloneFixedInterval(reg, false, ltiWithCalls); + _fixedRegisterRanges.append(lti); + if (lti->isValid()) + _active.append(lti); + } } const int fpRegCount = _fpRegisters.size(); _fixedFPRegisterRanges.reserve(fpRegCount); for (int fpReg = 0; fpReg < fpRegCount; ++fpReg) { - LifeTimeInterval lti = cloneFixedInterval(fpReg, true, ltiWithCalls); - _fixedFPRegisterRanges.append(lti); - if (lti.isValid()) - _active.append(lti); + if (_fpRegisters.at(fpReg)->isCallerSaved()) { + LifeTimeInterval *lti = cloneFixedInterval(fpReg, true, ltiWithCalls); + _fixedFPRegisterRanges.append(lti); + if (lti->isValid()) + _active.append(lti); + } } } void RegisterAllocator::linearScan() { while (!_unhandled.isEmpty()) { - LifeTimeInterval current = _unhandled.first(); - _unhandled.removeFirst(); - int position = current.start(); + LifeTimeInterval *current = _unhandled.back(); + _unhandled.pop_back(); + const int position = current->start(); // check for intervals in active that are handled or inactive for (int i = 0; i < _active.size(); ) { - const LifeTimeInterval &it = _active.at(i); - if (it.end() < position) { - if (!it.isFixedInterval()) + LifeTimeInterval *it = _active.at(i); + if (it->end() < position) { + if (!it->isFixedInterval()) _handled += it; _active.remove(i); - } else if (!it.covers(position)) { + } else if (!it->covers(position)) { _inactive += it; _active.remove(i); } else { @@ -1212,13 +1383,13 @@ void RegisterAllocator::linearScan() // check for intervals in inactive that are handled or active for (int i = 0; i < _inactive.size(); ) { - const LifeTimeInterval &it = _inactive.at(i); - if (it.end() < position) { - if (!it.isFixedInterval()) + LifeTimeInterval *it = _inactive.at(i); + if (it->end() < position) { + if (!it->isFixedInterval()) _handled += it; _inactive.remove(i); - } else if (it.covers(position)) { - if (it.reg() != LifeTimeInterval::Invalid) { + } else if (it->covers(position)) { + if (it->reg() != LifeTimeInterval::InvalidRegister) { _active += it; _inactive.remove(i); } else { @@ -1231,34 +1402,33 @@ void RegisterAllocator::linearScan() } } - Q_ASSERT(!current.isFixedInterval()); + Q_ASSERT(!current->isFixedInterval()); #ifdef DEBUG_REGALLOC qDebug() << "** Position" << position; #endif // DEBUG_REGALLOC - if (_info->canHaveRegister(current.temp())) { - tryAllocateFreeReg(current, position); - if (current.reg() == LifeTimeInterval::Invalid) - allocateBlockedReg(current, position); - if (current.reg() != LifeTimeInterval::Invalid) + if (_info->canHaveRegister(current->temp())) { + tryAllocateFreeReg(*current); + if (current->reg() == LifeTimeInterval::InvalidRegister) + allocateBlockedReg(*current); + if (current->reg() != LifeTimeInterval::InvalidRegister) _active += current; } else { - assignSpillSlot(current.temp(), current.start(), current.end()); + assignSpillSlot(current->temp(), current->start(), current->end()); _inactive += current; -#ifdef DEBUG_REGALLOC - qDebug() << "*** allocating stack slot" << _assignedSpillSlots[current.temp()] - << "for %" << current.temp().index << "as it cannot be loaded in a register"; -#endif // DEBUG_REGALLOC + if (DebugRegAlloc) + qDebug() << "*** allocating stack slot" << _assignedSpillSlots[current->temp().index] + << "for %" << current->temp().index << "as it cannot be loaded in a register"; } } - foreach (const LifeTimeInterval &r, _active) - if (!r.isFixedInterval()) + foreach (LifeTimeInterval *r, _active) + if (!r->isFixedInterval()) _handled.append(r); _active.clear(); - foreach (const LifeTimeInterval &r, _inactive) - if (!r.isFixedInterval()) + foreach (LifeTimeInterval *r, _inactive) + if (!r->isFixedInterval()) _handled.append(r); _inactive.clear(); } @@ -1284,45 +1454,75 @@ static inline int intersectionPosition(const LifeTimeInterval::Range &one, const static inline bool isFP(const Temp &t) { return t.type == DoubleType; } -void RegisterAllocator::tryAllocateFreeReg(LifeTimeInterval ¤t, const int position) +static inline bool candidateIsBetterFit(int bestSizeSoFar, int idealSize, int candidateSize) { - Q_ASSERT(!current.isFixedInterval()); - Q_ASSERT(current.reg() == LifeTimeInterval::Invalid); + // If the candidateSize is larger than the current we take it only if the current size does not + // yet fit for the whole interval. + if (bestSizeSoFar < candidateSize && bestSizeSoFar < idealSize) + return true; - const bool needsFPReg = isFP(current.temp()); - QVector<int> freeUntilPos(needsFPReg ? _fpRegisters.size() : _normalRegisters.size(), INT_MAX); - Q_ASSERT(freeUntilPos.size() > 0); + // If the candidateSize is smaller we only take it if it still fits the whole interval. + if (bestSizeSoFar > candidateSize && candidateSize >= idealSize) + return true; - const bool isPhiTarget = _info->isPhiTarget(current.temp()); - foreach (const LifeTimeInterval &it, _active) { - if (it.isFP() == needsFPReg) { - if (!isPhiTarget && it.isFixedInterval() && !current.isSplitFromInterval()) { - const int idx = indexOfRangeCoveringPosition(it.ranges(), position); - if (it.ranges().at(idx).end == current.start()) { - if (it.ranges().size() > idx + 1) - freeUntilPos[it.reg()] = it.ranges().at(idx + 1).start; - continue; - } - } + // Other wise: no luck. + return false; +} - if (isPhiTarget || it.end() >= current.firstPossibleUsePosition(isPhiTarget)) - freeUntilPos[it.reg()] = 0; // mark register as unavailable +// Out of all available registers (with their next-uses), choose the one that fits the requested +// duration best. This can return a register that is not free for the whole interval, but that's +// fine: we just have to split the current interval. +static void longestAvailableReg(int *nextUses, int nextUseCount, int ®, int &freeUntilPos_reg, int lastUse) +{ + reg = LifeTimeInterval::InvalidRegister; + freeUntilPos_reg = 0; + + for (int candidate = 0, candidateEnd = nextUseCount; candidate != candidateEnd; ++candidate) { + int fp = nextUses[candidate]; + if (candidateIsBetterFit(freeUntilPos_reg, lastUse, fp)) { + reg = candidate; + freeUntilPos_reg = fp; } } +} - foreach (const LifeTimeInterval &it, _inactive) { - if (current.isSplitFromInterval() || it.isFixedInterval()) { - if (it.isFP() == needsFPReg && it.reg() != LifeTimeInterval::Invalid) { - const int intersectionPos = nextIntersection(current, it, position); - if (!isPhiTarget && it.isFixedInterval() && current.end() == intersectionPos) - freeUntilPos[it.reg()] = qMin(freeUntilPos[it.reg()], intersectionPos + 1); - else if (intersectionPos != -1) - freeUntilPos[it.reg()] = qMin(freeUntilPos[it.reg()], intersectionPos); - } +#define CALLOC_ON_STACK(ty, ptr, sz, val) \ + Q_ASSERT(sz > 0); \ + ty *ptr = reinterpret_cast<ty *>(alloca(sizeof(ty) * (sz))); \ + for (ty *it = ptr, *eit = ptr + (sz); it != eit; ++it) \ + *it = val; + +// Try to allocate a register that's currently free. +void RegisterAllocator::tryAllocateFreeReg(LifeTimeInterval ¤t) +{ + Q_ASSERT(!current.isFixedInterval()); + Q_ASSERT(current.reg() == LifeTimeInterval::InvalidRegister); + + const bool needsFPReg = isFP(current.temp()); + const int freeUntilPosCount = needsFPReg ? _fpRegisters.size() : _normalRegisters.size(); + CALLOC_ON_STACK(int, freeUntilPos, freeUntilPosCount, INT_MAX); + + for (Intervals::const_iterator i = _active.constBegin(), ei = _active.constEnd(); i != ei; ++i) { + const LifeTimeInterval *it = *i; + if (it->isFP() == needsFPReg) + freeUntilPos[it->reg()] = 0; // mark register as unavailable + } + + for (Intervals::const_iterator i = _inactive.constBegin(), ei = _inactive.constEnd(); i != ei; ++i) { + const LifeTimeInterval *it = *i; + if (it->isFP() != needsFPReg) + continue; // different register type, so not applicable. + if (it->reg() == LifeTimeInterval::InvalidRegister) + continue; // this range does not block a register from being used, as it has no register assigned + + if (current.isSplitFromInterval() || it->isFixedInterval()) { + const int intersectionPos = nextIntersection(current, *it); + if (intersectionPos != -1) + freeUntilPos[it->reg()] = qMin(freeUntilPos[it->reg()], intersectionPos); } } - int reg = LifeTimeInterval::Invalid; + int reg = LifeTimeInterval::InvalidRegister; int freeUntilPos_reg = 0; foreach (const Temp &hint, _info->hints(current.temp())) { @@ -1330,173 +1530,165 @@ void RegisterAllocator::tryAllocateFreeReg(LifeTimeInterval ¤t, const int if (hint.kind == Temp::PhysicalRegister) candidate = hint.index; else - candidate = _lastAssignedRegister.value(hint, LifeTimeInterval::Invalid); + candidate = _lastAssignedRegister[hint.index]; const int end = current.end(); - if (candidate != LifeTimeInterval::Invalid) { - if (current.isFP() == (hint.type == DoubleType)) { - int fp = freeUntilPos[candidate]; - if ((freeUntilPos_reg < end && fp > freeUntilPos_reg) - || (freeUntilPos_reg >= end && fp >= end && freeUntilPos_reg > fp)) { - reg = candidate; - freeUntilPos_reg = fp; - } - } + if (candidate == LifeTimeInterval::InvalidRegister) + continue; // the candidate has no register assigned, so it cannot be (re-)used + if (current.isFP() != isFP(hint)) + continue; // different register type, so not applicable. + + const int fp = freeUntilPos[candidate]; + if (candidateIsBetterFit(freeUntilPos_reg, end, fp)) { + reg = candidate; + freeUntilPos_reg = fp; } } - if (reg == LifeTimeInterval::Invalid) - longestAvailableReg(freeUntilPos, reg, freeUntilPos_reg, current.end()); + // None of the hinted registers could fit the interval, so try all registers next. + if (reg == LifeTimeInterval::InvalidRegister) + longestAvailableReg(freeUntilPos, freeUntilPosCount, reg, freeUntilPos_reg, current.end()); if (freeUntilPos_reg == 0) { // no register available without spilling -#ifdef DEBUG_REGALLOC - qDebug() << "*** no register available for %" << current.temp().index; -#endif // DEBUG_REGALLOC + if (DebugRegAlloc) + qDebug() << "*** no register available for %" << current.temp().index; return; } else if (current.end() < freeUntilPos_reg) { // register available for the whole interval -#ifdef DEBUG_REGALLOC - qDebug() << "*** allocating register" << reg << "for the whole interval of %" << current.temp().index; -#endif // DEBUG_REGALLOC + if (DebugRegAlloc) + qDebug() << "*** allocating register" << reg << "for the whole interval of %" << current.temp().index; current.setReg(reg); - _lastAssignedRegister.insert(current.temp(), reg); + _lastAssignedRegister[current.temp().index] = reg; } else { // register available for the first part of the interval + + // TODO: this is slightly inefficient in the following case: + // %1 = something + // some_call(%1) + // %2 = %1 + 1 + // Now %1 will get a register assigned, and will be spilled to the stack immediately. It + // would be better to check if there are actually uses in the range before the split. + current.setReg(reg); - _lastAssignedRegister.insert(current.temp(), reg); -#ifdef DEBUG_REGALLOC - qDebug() << "*** allocating register" << reg << "for the first part of interval of %" << current.temp().index; -#endif // DEBUG_REGALLOC + _lastAssignedRegister[current.temp().index] = reg; + if (DebugRegAlloc) + qDebug() << "*** allocating register" << reg << "for the first part of interval of %" << current.temp().index; split(current, freeUntilPos_reg, true); } } -void RegisterAllocator::allocateBlockedReg(LifeTimeInterval ¤t, const int position) +// This gets called when all registers are currently in use. +void RegisterAllocator::allocateBlockedReg(LifeTimeInterval ¤t) { Q_ASSERT(!current.isFixedInterval()); - Q_ASSERT(current.reg() == LifeTimeInterval::Invalid); + Q_ASSERT(current.reg() == LifeTimeInterval::InvalidRegister); + const int position = current.start(); const bool isPhiTarget = _info->isPhiTarget(current.temp()); if (isPhiTarget && !current.isSplitFromInterval()) { + // Special case: storing to a phi-node's target will result in a single move. So, if we + // would spill another interval to the stack (that's 1 store), and then do the move for the + // phi target (at least 1 move or a load), that would result in 2 instructions. Instead, we + // force the phi-node's target to go to the stack immediately, which is always a single + // store. split(current, position + 1, true); - _inactive.append(current); + _inactive.append(¤t); return; } const bool needsFPReg = isFP(current.temp()); - QVector<int> nextUsePos(needsFPReg ? _fpRegisters.size() : _normalRegisters.size(), INT_MAX); - QVector<LifeTimeInterval *> nextUseRangeForReg(nextUsePos.size(), 0); - Q_ASSERT(nextUsePos.size() > 0); - - const bool definedAtCurrentPosition = !current.isSplitFromInterval() && current.start() == position; - - for (int i = 0, ei = _active.size(); i != ei; ++i) { - LifeTimeInterval &it = _active[i]; - if (it.isFP() == needsFPReg) { - int nu = it.isFixedInterval() ? 0 : nextUse(it.temp(), current.firstPossibleUsePosition(isPhiTarget)); - if (nu == position && !definedAtCurrentPosition) { - nextUsePos[it.reg()] = 0; - } else if (nu != -1 && nu < nextUsePos[it.reg()]) { - nextUsePos[it.reg()] = nu; - nextUseRangeForReg[it.reg()] = ⁢ - } else if (nu == -1 && nextUsePos[it.reg()] == INT_MAX) { - // in a loop, the range can be active, but only used before the current position (e.g. in a loop header or phi node) - nextUseRangeForReg[it.reg()] = ⁢ - } + const int nextUsePosCount = needsFPReg ? _fpRegisters.size() : _normalRegisters.size(); + CALLOC_ON_STACK(int, nextUsePos, nextUsePosCount, INT_MAX); + QVector<LifeTimeInterval *> nextUseRangeForReg(nextUsePosCount, 0); + + for (Intervals::const_iterator i = _active.constBegin(), ei = _active.constEnd(); i != ei; ++i) { + LifeTimeInterval &it = **i; + if (it.isFP() != needsFPReg) + continue; // different register type, so not applicable. + + const int nu = it.isFixedInterval() ? 0 : nextUse(it.temp(), current.start()); + if (nu == position) { + nextUsePos[it.reg()] = 0; + } else if (nu != -1 && nu < nextUsePos[it.reg()]) { + nextUsePos[it.reg()] = nu; + nextUseRangeForReg[it.reg()] = ⁢ + } else if (nu == -1 && nextUsePos[it.reg()] == INT_MAX) { + // in a loop, the range can be active, but the result might only be used before the + // current position (e.g. the induction variable being used in the phi node in the loop + // header). So, we can use this register, but we need to remember to split the interval + // in order to have the edge-resolving generate a load at the edge going back to the + // loop header. + nextUseRangeForReg[it.reg()] = ⁢ } } - for (int i = 0, ei = _inactive.size(); i != ei; ++i) { - LifeTimeInterval &it = _inactive[i]; + for (Intervals::const_iterator i = _inactive.constBegin(), ei = _inactive.constEnd(); i != ei; ++i) { + LifeTimeInterval &it = **i; + if (it.isFP() != needsFPReg) + continue; // different register type, so not applicable. + if (it.reg() == LifeTimeInterval::InvalidRegister) + continue; // this range does not block a register from being used, as it has no register assigned + if (current.isSplitFromInterval() || it.isFixedInterval()) { - if (it.isFP() == needsFPReg && it.reg() != LifeTimeInterval::Invalid) { - if (nextIntersection(current, it, position) != -1) { - int nu = nextUse(it.temp(), current.firstPossibleUsePosition(isPhiTarget)); - if (nu != -1 && nu < nextUsePos[it.reg()]) { - nextUsePos[it.reg()] = nu; - nextUseRangeForReg[it.reg()] = ⁢ - } + if (nextIntersection(current, it) != -1) { + const int nu = nextUse(it.temp(), current.start()); + if (nu != -1 && nu < nextUsePos[it.reg()]) { + nextUsePos[it.reg()] = nu; + nextUseRangeForReg[it.reg()] = ⁢ } } } } int reg, nextUsePos_reg; - longestAvailableReg(nextUsePos, reg, nextUsePos_reg, current.end()); + longestAvailableReg(nextUsePos, nextUsePosCount, reg, nextUsePos_reg, current.end()); - if (current.start() > nextUsePos_reg) { - // all other intervals are used before current, so it is best to spill current itself -#ifdef DEBUG_REGALLOC - QTextStream out(stderr, QIODevice::WriteOnly); - out << "*** splitting current for range ";current.dump(out);out<<endl; -#endif // DEBUG_REGALLOC - Q_ASSERT(!_info->useMustHaveReg(current.temp(), position)); - split(current, position + 1, true); - _inactive.append(current); - } else { - // spill intervals that currently block reg -#ifdef DEBUG_REGALLOC - QTextStream out(stderr, QIODevice::WriteOnly); - out << "*** spilling intervals that block reg "<<reg<<" for interval ";current.dump(out);out<<endl; -#endif // DEBUG_REGALLOC - current.setReg(reg); - _lastAssignedRegister.insert(current.temp(), reg); - LifeTimeInterval *nextUse = nextUseRangeForReg[reg]; - Q_ASSERT(nextUse); - Q_ASSERT(!nextUse->isFixedInterval()); - - if (_info->isUsedAt(nextUse->temp(), position)) { - Q_ASSERT(!_info->isUsedAt(current.temp(), position)); - // the register is used (as an incoming parameter) at the current position, so split - // the interval immediately after the (use at the) current position - split(*nextUse, position + 1); - } else { - // the register was used before the current position - split(*nextUse, position); - } + Q_ASSERT(current.start() <= nextUsePos_reg); - splitInactiveAtEndOfLifetimeHole(reg, needsFPReg, position); - - // make sure that current does not intersect with the fixed interval for reg - const LifeTimeInterval &fixedRegRange = needsFPReg ? _fixedFPRegisterRanges.at(reg) - : _fixedRegisterRanges.at(reg); - int ni = nextIntersection(current, fixedRegRange, position); - if (ni != -1) { -#ifdef DEBUG_REGALLOC - out << "***-- current range intersects with a fixed reg use at "<<ni<<", so splitting it."<<endl; -#endif // DEBUG_REGALLOC - split(current, ni, true); - } - } -} - -void RegisterAllocator::longestAvailableReg(const QVector<int> &nextUses, int ®, - int &freeUntilPos_reg, int lastUse) const -{ - reg = LifeTimeInterval::Invalid; - freeUntilPos_reg = 0; - - for (int candidate = 0, candidateEnd = nextUses.size(); candidate != candidateEnd; ++candidate) { - int fp = nextUses[candidate]; - if ((freeUntilPos_reg < lastUse && fp > freeUntilPos_reg) - || (freeUntilPos_reg >= lastUse && fp >= lastUse && freeUntilPos_reg > fp)) { - reg = candidate; - freeUntilPos_reg = fp; + // spill interval that currently block reg + if (DebugRegAlloc) { + QTextStream out(stderr, QIODevice::WriteOnly); + out << "*** spilling intervals that block reg " <<reg<< " for interval "; + current.dump(out); + out << endl; + } + current.setReg(reg); + _lastAssignedRegister[current.temp().index] = reg; + LifeTimeInterval *nextUse = nextUseRangeForReg[reg]; + Q_ASSERT(nextUse); + Q_ASSERT(!nextUse->isFixedInterval()); + + split(*nextUse, position); + + // We might have chosen a register that is used by a range that has a hole in its life time. + // If that's the case, check if the current interval completely fits in the hole. Or rephrased: + // check if the current interval will use the register after that hole ends (so that range, and + // if so, split that interval so that it gets a new register assigned when it needs one. + splitInactiveAtEndOfLifetimeHole(reg, needsFPReg, position); + + // make sure that current does not intersect with the fixed interval for reg + const LifeTimeInterval &fixedRegRange = needsFPReg ? *_fixedFPRegisterRanges.at(reg) + : *_fixedRegisterRanges.at(reg); + int ni = nextIntersection(current, fixedRegRange); + if (ni != -1) { + if (DebugRegAlloc) { + QTextStream out(stderr, QIODevice::WriteOnly); + out << "***-- current range intersects with a fixed reg use at " << ni << ", so splitting it." << endl; } + // current does overlap with a fixed interval, so split current before that intersection. + split(current, ni, true); } } int RegisterAllocator::nextIntersection(const LifeTimeInterval ¤t, - const LifeTimeInterval &another, const int position) const + const LifeTimeInterval &another) const { - LifeTimeInterval::Ranges currentRanges = current.ranges(); - int currentIt = indexOfRangeCoveringPosition(currentRanges, position); - if (currentIt == -1) - return -1; + const LifeTimeInterval::Ranges ¤tRanges = current.ranges(); + int currentIt = 0; - LifeTimeInterval::Ranges anotherRanges = another.ranges(); - const int anotherItStart = indexOfRangeCoveringPosition(anotherRanges, position); + const LifeTimeInterval::Ranges &anotherRanges = another.ranges(); + const int anotherItStart = indexOfRangeCoveringPosition(anotherRanges, current.start()); if (anotherItStart == -1) return -1; @@ -1515,11 +1707,12 @@ int RegisterAllocator::nextIntersection(const LifeTimeInterval ¤t, return -1; } +/// Find the first use after the start position for the given temp. int RegisterAllocator::nextUse(const Temp &t, int startPosition) const { - QList<Use> usePositions = _info->uses(t); - for (int i = 0, ei = usePositions.size(); i != ei; ++i) { - int usePos = usePositions[i].pos; + const std::vector<Use> &usePositions = _info->uses(t); + for (int i = 0, ei = usePositions.size(); i != ei; ++i) { //### FIXME: use an iterator + const int usePos = usePositions.at(i).pos; if (usePos >= startPosition) return usePos; } @@ -1527,16 +1720,16 @@ int RegisterAllocator::nextUse(const Temp &t, int startPosition) const return -1; } -static inline void insertSorted(QVector<LifeTimeInterval> &intervals, const LifeTimeInterval &newInterval) +static inline void insertReverseSorted(QVector<LifeTimeInterval *> &intervals, LifeTimeInterval *newInterval) { - newInterval.validate(); - for (int i = 0, ei = intervals.size(); i != ei; ++i) { - if (LifeTimeInterval::lessThan(newInterval, intervals.at(i))) { - intervals.insert(i, newInterval); + newInterval->validate(); + for (int i = intervals.size(); i > 0;) { + if (LifeTimeInterval::lessThan(newInterval, intervals.at(--i))) { + intervals.insert(i + 1, newInterval); return; } } - intervals.append(newInterval); + intervals.insert(0, newInterval); } void RegisterAllocator::split(LifeTimeInterval ¤t, int beforePosition, @@ -1544,28 +1737,21 @@ void RegisterAllocator::split(LifeTimeInterval ¤t, int beforePosition, { // TODO: check if we can always skip the optional register uses Q_ASSERT(!current.isFixedInterval()); -#ifdef DEBUG_REGALLOC - QTextStream out(stderr, QIODevice::WriteOnly); - out << "***** split request for range ";current.dump(out);out<<" before position "<<beforePosition<<" and skipOptionalRegisterUses = "<<skipOptionalRegisterUses<<endl; -#endif // DEBUG_REGALLOC + if (DebugRegAlloc) { + QTextStream out(stderr, QIODevice::WriteOnly); + out << "***** split request for range ";current.dump(out);out<<" before position "<<beforePosition<<" and skipOptionalRegisterUses = "<<skipOptionalRegisterUses<<endl; + } assignSpillSlot(current.temp(), current.start(), current.end()); - const int defPosition = _info->def(current.temp()); - if (beforePosition < defPosition) { -#ifdef DEBUG_REGALLOC - out << "***** split before position is before or at definition, so not splitting."<<endl; -#endif // DEBUG_REGALLOC - return; - } + const int firstPosition = current.start(); + Q_ASSERT(beforePosition > firstPosition && "split before start"); - int lastUse = -1; - if (defPosition < beforePosition) - lastUse = defPosition; + int lastUse = firstPosition; int nextUse = -1; - QList<Use> usePositions = _info->uses(current.temp()); + const std::vector<Use> &usePositions = _info->uses(current.temp()); for (int i = 0, ei = usePositions.size(); i != ei; ++i) { - const Use &usePosition = usePositions[i]; + const Use &usePosition = usePositions.at(i); const int usePos = usePosition.pos; if (lastUse < usePos && usePos < beforePosition) { lastUse = usePos; @@ -1576,31 +1762,30 @@ void RegisterAllocator::split(LifeTimeInterval ¤t, int beforePosition, } } } - if (lastUse == -1) - lastUse = beforePosition - 1; - + Q_ASSERT(lastUse != -1); Q_ASSERT(lastUse < beforePosition); -#ifdef DEBUG_REGALLOC - out << "***** last use = "<<lastUse<<", nextUse = " << nextUse<<endl; -#endif // DEBUG_REGALLOC LifeTimeInterval newInterval = current.split(lastUse, nextUse); -#ifdef DEBUG_REGALLOC - out << "***** new interval: "; newInterval.dump(out); out << endl; - out << "***** preceding interval: "; current.dump(out); out << endl; -#endif // DEBUG_REGALLOC + if (DebugRegAlloc) { + QTextStream out(stderr, QIODevice::WriteOnly); + out << "***** last use = "<<lastUse<<", nextUse = " << nextUse<<endl; + out << "***** new interval: "; newInterval.dump(out); out << endl; + out << "***** preceding interval: "; current.dump(out); out << endl; + } if (newInterval.isValid()) { - if (current.reg() != LifeTimeInterval::Invalid) + if (current.reg() != LifeTimeInterval::InvalidRegister) _info->addHint(current.temp(), current.reg()); - newInterval.setReg(LifeTimeInterval::Invalid); - insertSorted(_unhandled, newInterval); + newInterval.setReg(LifeTimeInterval::InvalidRegister); + LifeTimeInterval *newIntervalPtr = new LifeTimeInterval(newInterval); + _lifeTimeIntervals->add(newIntervalPtr); + insertReverseSorted(_unhandled, newIntervalPtr); } } void RegisterAllocator::splitInactiveAtEndOfLifetimeHole(int reg, bool isFPReg, int position) { for (int i = 0, ei = _inactive.size(); i != ei; ++i) { - LifeTimeInterval &interval = _inactive[i]; + LifeTimeInterval &interval = *_inactive[i]; if (interval.isFixedInterval()) continue; if (isFPReg == interval.isFP() && interval.reg() == reg) { @@ -1618,13 +1803,13 @@ void RegisterAllocator::splitInactiveAtEndOfLifetimeHole(int reg, bool isFPReg, void RegisterAllocator::assignSpillSlot(const Temp &t, int startPos, int endPos) { - if (_assignedSpillSlots.contains(t)) + if (_assignedSpillSlots[t.index] != InvalidSpillSlot) return; for (int i = 0, ei = _activeSpillSlots.size(); i != ei; ++i) { if (_activeSpillSlots.at(i) < startPos) { _activeSpillSlots[i] = endPos; - _assignedSpillSlots.insert(t, i); + _assignedSpillSlots[t.index] = i; return; } } @@ -1632,32 +1817,33 @@ void RegisterAllocator::assignSpillSlot(const Temp &t, int startPos, int endPos) Q_UNREACHABLE(); } -void RegisterAllocator::dump() const +void RegisterAllocator::dump(IR::Function *function) const { -#ifdef DEBUG_REGALLOC QTextStream qout(stdout, QIODevice::WriteOnly); + IRPrinterWithPositions printer(&qout, _lifeTimeIntervals); - { - qout << "Ranges:" << endl; - QVector<LifeTimeInterval> handled = _handled; - std::sort(handled.begin(), handled.end(), LifeTimeInterval::lessThanForTemp); - foreach (const LifeTimeInterval &r, handled) { - r.dump(qout); - qout << endl; - } + qout << "Ranges:" << endl; + QVector<LifeTimeInterval *> handled = _handled; + std::sort(handled.begin(), handled.end(), LifeTimeInterval::lessThanForTemp); + foreach (const LifeTimeInterval *r, handled) { + r->dump(qout); + qout << endl; } - { - qout << "Spill slots:" << endl; - QList<Temp> temps = _assignedSpillSlots.keys(); - if (temps.isEmpty()) - qout << "\t(none)" << endl; - std::sort(temps.begin(), temps.end()); - foreach (const Temp &t, temps) { - qout << "\t"; - t.dump(qout); - qout << " -> " << _assignedSpillSlots[t] << endl; - } - } -#endif // DEBUG_REGALLOC + qout << "Spill slots:" << endl; + for (unsigned i = 0; i < _assignedSpillSlots.size(); ++i) + if (_assignedSpillSlots[i] != InvalidSpillSlot) + qout << "\t%" << i << " -> " << _assignedSpillSlots[i] << endl; + + printer.print(function); } + +// References: +// [Wimmer1] C. Wimmer and M. Franz. Linear Scan Register Allocation on SSA Form. In Proceedings of +// CGO’10, ACM Press, 2010 +// [Wimmer2] C. Wimmer and H. Mossenbock. Optimized Interval Splitting in a Linear Scan Register +// Allocator. In Proceedings of the ACM/USENIX International Conference on Virtual +// Execution Environments, pages 132–141. ACM Press, 2005. +// [Traub] Omri Traub, Glenn Holloway, and Michael D. Smith. Quality and Speed in Linear-scan +// Register Allocation. In Proceedings of the ACM SIGPLAN 1998 Conference on Programming +// Language Design and Implementation, pages 142–151, June 1998. diff --git a/src/qml/jit/qv4regalloc_p.h b/src/qml/jit/qv4regalloc_p.h index 030fb4bf50..34ae19dfec 100644 --- a/src/qml/jit/qv4regalloc_p.h +++ b/src/qml/jit/qv4regalloc_p.h @@ -44,6 +44,7 @@ #include "qv4global_p.h" #include "qv4isel_p.h" #include "qv4ssa_p.h" +#include "qv4registerinfo_p.h" #include <config.h> @@ -54,46 +55,68 @@ namespace JIT { class RegAllocInfo; +// This class implements a linear-scan register allocator, with a couple of tweaks: +// - Second-chance allocation is used when an interval becomes active after a spill, which results +// in fewer differences between edges, and hence fewer moves before jumps. +// - Use positions are flagged with either "must have" register or "could have" register. This is +// used to decide whether a register is really needed when a temporary is used after a spill +// occurred. +// - Fixed intervals are used to denotate IR positions where certain registers are needed in order +// to implement the operation, and cannot be used by a temporary on that position. An example is +// caller saved registers, where the call will use/clobber those registers. +// - Hints are used to indicate which registers could be used to generate more compact code. An +// example is an addition, where one (or both) operands' life-time ends at that instruction. In +// this case, re-using an operand register for the result will result in an in-place add. +// - SSA form properties are used: +// - to simplify life-times (two temporaries will never interfere as long as their intervals +// are not split), resulting in a slightly faster algorithm; +// - when a temporary needs to be spilled, it is done directly after calculating it, so that +// 1 store is generated even if multiple spills/splits happen. +// - phi-node elimination (SSA form deconstruction) is done when resolving differences between +// CFG edges class RegisterAllocator { typedef IR::LifeTimeInterval LifeTimeInterval; - QVector<int> _normalRegisters; - QVector<int> _fpRegisters; + const RegisterInformation &_registerInformation; + QVector<const RegisterInfo *> _normalRegisters; + QVector<const RegisterInfo *> _fpRegisters; QScopedPointer<RegAllocInfo> _info; - QVector<LifeTimeInterval> _fixedRegisterRanges, _fixedFPRegisterRanges; + QVector<LifeTimeInterval *> _fixedRegisterRanges, _fixedFPRegisterRanges; - QVector<LifeTimeInterval> _unhandled, _active, _inactive, _handled; + IR::LifeTimeIntervals::Ptr _lifeTimeIntervals; + typedef QVector<LifeTimeInterval *> Intervals; + Intervals _unhandled, _active, _inactive, _handled; - QHash<IR::Temp, int> _lastAssignedRegister; - QHash<IR::Temp, int> _assignedSpillSlots; + std::vector<int> _lastAssignedRegister; + std::vector<int> _assignedSpillSlots; QVector<int> _activeSpillSlots; Q_DISABLE_COPY(RegisterAllocator) public: - RegisterAllocator(const QVector<int> &normalRegisters, const QVector<int> &fpRegisters); + enum { InvalidSpillSlot = -1 }; + + RegisterAllocator(const RegisterInformation ®isterInformation); ~RegisterAllocator(); void run(IR::Function *function, const IR::Optimizer &opt); private: + LifeTimeInterval *cloneFixedInterval(int reg, bool isFP, const LifeTimeInterval &original); void prepareRanges(); void linearScan(); - void tryAllocateFreeReg(LifeTimeInterval ¤t, const int position); - void allocateBlockedReg(LifeTimeInterval ¤t, const int position); - void longestAvailableReg(const QVector<int> &nextUses, int ®, int &nextUsePos_reg, - int lastUse) const; - int nextIntersection(const LifeTimeInterval ¤t, const LifeTimeInterval &another, - const int position) const; + void tryAllocateFreeReg(LifeTimeInterval ¤t); + void allocateBlockedReg(LifeTimeInterval ¤t); + int nextIntersection(const LifeTimeInterval ¤t, const LifeTimeInterval &another) const; int nextUse(const IR::Temp &t, int startPosition) const; void split(LifeTimeInterval ¤t, int beforePosition, bool skipOptionalRegisterUses =false); void splitInactiveAtEndOfLifetimeHole(int reg, bool isFPReg, int position); void assignSpillSlot(const IR::Temp &t, int startPos, int endPos); void resolve(IR::Function *function, const IR::Optimizer &opt); - void dump() const; + void dump(IR::Function *function) const; }; } // end of namespace JIT diff --git a/src/qml/jit/qv4registerinfo_p.h b/src/qml/jit/qv4registerinfo_p.h new file mode 100644 index 0000000000..b8701d72f4 --- /dev/null +++ b/src/qml/jit/qv4registerinfo_p.h @@ -0,0 +1,99 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** 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 Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/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 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QV4REGISTERINFO_P_H +#define QV4REGISTERINFO_P_H + +#include <QtCore/QString> + +QT_BEGIN_NAMESPACE + +namespace QV4 { +namespace JIT { + +class RegisterInfo +{ +public: + enum { InvalidRegister = -1 }; + enum SavedBy { CallerSaved, CalleeSaved }; + enum RegisterType { RegularRegister, FloatingPointRegister }; + enum Usage { Predefined, RegAlloc }; + +public: + RegisterInfo() + : _reg(InvalidRegister) + , _type(RegularRegister) + , _savedBy(CallerSaved) + , _usage(Predefined) + {} + + RegisterInfo(int reg, const QString &prettyName, RegisterType type, SavedBy savedBy, Usage usage) + : _reg(reg) + , _prettyName(prettyName) + , _type(type) + , _savedBy(savedBy) + , _usage(usage) + {} + + bool isValid() const { return _reg != InvalidRegister; } + template <typename T> T reg() const { return static_cast<T>(_reg); } + QString prettyName() const { return _prettyName; } + bool isCallerSaved() const { return _savedBy == CallerSaved; } + bool isCalleeSaved() const { return _savedBy == CalleeSaved; } + bool isFloatingPoint() const { return _type == FloatingPointRegister; } + bool isRegularRegister() const { return _type == RegularRegister; } + bool useForRegAlloc() const { return _usage == RegAlloc; } + +private: + int _reg; + QString _prettyName; + RegisterType _type; + SavedBy _savedBy; + Usage _usage; +}; +typedef QVector<RegisterInfo> RegisterInformation; + +} // JIT namespace +} // QV4 namespace + +QT_END_NAMESPACE + +#endif // QV4REGISTERINFO_P_H diff --git a/src/qml/jit/qv4targetplatform_p.h b/src/qml/jit/qv4targetplatform_p.h new file mode 100644 index 0000000000..4b384d2fe9 --- /dev/null +++ b/src/qml/jit/qv4targetplatform_p.h @@ -0,0 +1,390 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** 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 Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/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 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QV4TARGETPLATFORM_P_H +#define QV4TARGETPLATFORM_P_H + +#include <config.h> + +#if ENABLE(ASSEMBLER) + +#include "qv4registerinfo_p.h" +#include <assembler/MacroAssembler.h> + +QT_BEGIN_NAMESPACE + +namespace QV4 { +namespace JIT { + +// The TargetPlatform class describes how the stack and the registers work on a CPU+ABI combination. +// +// All combinations have a separate definition, guarded by #ifdefs. The exceptions are: +// - Linux/x86 and win32, which are the same, except that linux non-PIC/PIE code does not need to +// restore ebx (which holds the GOT ptr) before a call +// - All (supported) ARM platforms, where the only variety is the platform specific usage of r9, +// and the frame-pointer in Thumb/Thumb2 v.s. ARM mode. +// +// Specific handling of ebx when it holds the GOT: +// In this case we can use it, but it needs to be restored when doing a call. So, the handling is as +// follows: it is marked as caller saved, meaning the value in it won't survive a call. When +// calculating the list of callee saved registers in getCalleeSavedRegisters (which is used to +// generate push/pop instructions in the prelude/postlude), we add ebx too. Then when synthesizing +// a call, we add a load it right before emitting the call instruction. +// +// NOTE: When adding new architecture, do not forget to whitelist it in qv4global_p.h! +class TargetPlatform +{ +public: +#if CPU(X86) && (OS(LINUX) || OS(WINDOWS) || OS(QNX) || OS(FREEBSD)) + enum { RegAllocIsSupported = 1 }; + + static const JSC::MacroAssembler::RegisterID StackFrameRegister = JSC::X86Registers::ebp; + static const JSC::MacroAssembler::RegisterID StackPointerRegister = JSC::X86Registers::esp; + static const JSC::MacroAssembler::RegisterID LocalsRegister = JSC::X86Registers::edi; + static const JSC::MacroAssembler::RegisterID ContextRegister = JSC::X86Registers::esi; + static const JSC::MacroAssembler::RegisterID ReturnValueRegister = JSC::X86Registers::eax; + static const JSC::MacroAssembler::RegisterID ScratchRegister = JSC::X86Registers::ecx; + static const JSC::MacroAssembler::FPRegisterID FPGpr0 = JSC::X86Registers::xmm0; + static const JSC::MacroAssembler::FPRegisterID FPGpr1 = JSC::X86Registers::xmm1; + + static RegisterInformation getPlatformRegisterInfo() + { + typedef RegisterInfo RI; + return RegisterInformation() + << RI(JSC::X86Registers::edx, QStringLiteral("edx"), RI::RegularRegister, RI::CallerSaved, RI::RegAlloc) + << RI(JSC::X86Registers::ebx, QStringLiteral("ebx"), RI::RegularRegister, RI::CallerSaved, RI::RegAlloc) + << RI(JSC::X86Registers::edi, QStringLiteral("edi"), RI::RegularRegister, RI::CalleeSaved, RI::Predefined) + << RI(JSC::X86Registers::esi, QStringLiteral("esi"), RI::RegularRegister, RI::CalleeSaved, RI::Predefined) + << RI(JSC::X86Registers::xmm2, QStringLiteral("xmm2"), RI::FloatingPointRegister, RI::CallerSaved, RI::RegAlloc) + << RI(JSC::X86Registers::xmm3, QStringLiteral("xmm3"), RI::FloatingPointRegister, RI::CallerSaved, RI::RegAlloc) + << RI(JSC::X86Registers::xmm4, QStringLiteral("xmm4"), RI::FloatingPointRegister, RI::CallerSaved, RI::RegAlloc) + << RI(JSC::X86Registers::xmm5, QStringLiteral("xmm5"), RI::FloatingPointRegister, RI::CallerSaved, RI::RegAlloc) + << RI(JSC::X86Registers::xmm6, QStringLiteral("xmm6"), RI::FloatingPointRegister, RI::CallerSaved, RI::RegAlloc) + << RI(JSC::X86Registers::xmm7, QStringLiteral("xmm7"), RI::FloatingPointRegister, RI::CallerSaved, RI::RegAlloc) + ; + } + +# define HAVE_ALU_OPS_WITH_MEM_OPERAND 1 +# undef VALUE_FITS_IN_REGISTER + static const int RegisterSize = 4; + +# undef ARGUMENTS_IN_REGISTERS + static const int RegisterArgumentCount = 0; + static JSC::MacroAssembler::RegisterID registerForArgument(int) { Q_UNREACHABLE(); } + + static const int StackAlignment = 16; + static const int StackShadowSpace = 0; + static const int StackSpaceAllocatedUponFunctionEntry = RegisterSize; // Return address is pushed onto stack by the CPU. + static void platformEnterStandardStackFrame(JSC::MacroAssembler *as) { Q_UNUSED(as); } + static void platformLeaveStandardStackFrame(JSC::MacroAssembler *as) { Q_UNUSED(as); } + +#if OS(WINDOWS) || OS(QNX) || \ + ((OS(LINUX) || OS(FREEBSD)) && (defined(__PIC__) || defined(__PIE__))) + +#define RESTORE_EBX_ON_CALL + static JSC::MacroAssembler::Address ebxAddressOnStack() + { + static int ebxIdx = -1; + if (ebxIdx == -1) { + int calleeSaves = 0; + foreach (const RegisterInfo &info, getRegisterInfo()) { + if (info.reg<JSC::X86Registers::RegisterID>() == JSC::X86Registers::ebx) { + ebxIdx = calleeSaves; + break; + } else if (info.isCalleeSaved()) { + ++calleeSaves; + } + } + Q_ASSERT(ebxIdx >= 0); + ebxIdx += 1; + } + return JSC::MacroAssembler::Address(StackFrameRegister, ebxIdx * -int(sizeof(void*))); + } +#endif + +#endif // Windows on x86 + +#if CPU(X86_64) && (OS(LINUX) || OS(MAC_OS_X) || OS(FREEBSD)) + enum { RegAllocIsSupported = 1 }; + + static const JSC::MacroAssembler::RegisterID StackFrameRegister = JSC::X86Registers::ebp; + static const JSC::MacroAssembler::RegisterID StackPointerRegister = JSC::X86Registers::esp; + static const JSC::MacroAssembler::RegisterID LocalsRegister = JSC::X86Registers::r12; + static const JSC::MacroAssembler::RegisterID ContextRegister = JSC::X86Registers::r14; + static const JSC::MacroAssembler::RegisterID ReturnValueRegister = JSC::X86Registers::eax; + static const JSC::MacroAssembler::RegisterID ScratchRegister = JSC::X86Registers::r10; + static const JSC::MacroAssembler::FPRegisterID FPGpr0 = JSC::X86Registers::xmm0; + static const JSC::MacroAssembler::FPRegisterID FPGpr1 = JSC::X86Registers::xmm1; + + static RegisterInformation getPlatformRegisterInfo() + { + typedef RegisterInfo RI; + return RegisterInformation() + << RI(JSC::X86Registers::ebx, QStringLiteral("rbx"), RI::RegularRegister, RI::CalleeSaved, RI::RegAlloc) + << RI(JSC::X86Registers::edi, QStringLiteral("rdi"), RI::RegularRegister, RI::CallerSaved, RI::RegAlloc) + << RI(JSC::X86Registers::esi, QStringLiteral("rsi"), RI::RegularRegister, RI::CallerSaved, RI::RegAlloc) + << RI(JSC::X86Registers::edx, QStringLiteral("rdx"), RI::RegularRegister, RI::CallerSaved, RI::RegAlloc) + << RI(JSC::X86Registers::r9, QStringLiteral("r9"), RI::RegularRegister, RI::CallerSaved, RI::RegAlloc) + << RI(JSC::X86Registers::r8, QStringLiteral("r8"), RI::RegularRegister, RI::CallerSaved, RI::RegAlloc) + << RI(JSC::X86Registers::r12, QStringLiteral("r12"), RI::RegularRegister, RI::CalleeSaved, RI::Predefined) + << RI(JSC::X86Registers::r13, QStringLiteral("r13"), RI::RegularRegister, RI::CalleeSaved, RI::RegAlloc) + << RI(JSC::X86Registers::r14, QStringLiteral("r14"), RI::RegularRegister, RI::CalleeSaved, RI::Predefined) + << RI(JSC::X86Registers::r15, QStringLiteral("r15"), RI::RegularRegister, RI::CalleeSaved, RI::RegAlloc) + << RI(JSC::X86Registers::xmm2, QStringLiteral("xmm2"), RI::FloatingPointRegister, RI::CallerSaved, RI::RegAlloc) + << RI(JSC::X86Registers::xmm3, QStringLiteral("xmm3"), RI::FloatingPointRegister, RI::CallerSaved, RI::RegAlloc) + << RI(JSC::X86Registers::xmm4, QStringLiteral("xmm4"), RI::FloatingPointRegister, RI::CallerSaved, RI::RegAlloc) + << RI(JSC::X86Registers::xmm5, QStringLiteral("xmm5"), RI::FloatingPointRegister, RI::CallerSaved, RI::RegAlloc) + << RI(JSC::X86Registers::xmm6, QStringLiteral("xmm6"), RI::FloatingPointRegister, RI::CallerSaved, RI::RegAlloc) + << RI(JSC::X86Registers::xmm7, QStringLiteral("xmm7"), RI::FloatingPointRegister, RI::CallerSaved, RI::RegAlloc) + ; + } + +#define HAVE_ALU_OPS_WITH_MEM_OPERAND 1 +#define VALUE_FITS_IN_REGISTER + static const int RegisterSize = 8; + +#define ARGUMENTS_IN_REGISTERS + static const int RegisterArgumentCount = 6; + static JSC::MacroAssembler::RegisterID registerForArgument(int index) + { + static JSC::MacroAssembler::RegisterID regs[RegisterArgumentCount] = { + JSC::X86Registers::edi, + JSC::X86Registers::esi, + JSC::X86Registers::edx, + JSC::X86Registers::ecx, + JSC::X86Registers::r8, + JSC::X86Registers::r9 + }; + Q_ASSERT(index >= 0 && index < RegisterArgumentCount); + return regs[index]; + }; + + static const int StackAlignment = 16; + static const int StackShadowSpace = 0; + static const int StackSpaceAllocatedUponFunctionEntry = RegisterSize; // Return address is pushed onto stack by the CPU. + static void platformEnterStandardStackFrame(JSC::MacroAssembler *as) { Q_UNUSED(as); } + static void platformLeaveStandardStackFrame(JSC::MacroAssembler *as) { Q_UNUSED(as); } +#endif // Linux/MacOS on x86_64 + +#if CPU(X86_64) && OS(WINDOWS) + // Register allocation is not (yet) supported on win64, because the ABI related stack handling + // is not completely implemented. Specifically, the saving of xmm registers, and the saving of + // incoming function parameters to the shadow space is missing. + enum { RegAllocIsSupported = 0 }; + + static const JSC::MacroAssembler::RegisterID StackFrameRegister = JSC::X86Registers::ebp; + static const JSC::MacroAssembler::RegisterID StackPointerRegister = JSC::X86Registers::esp; + static const JSC::MacroAssembler::RegisterID LocalsRegister = JSC::X86Registers::r12; + static const JSC::MacroAssembler::RegisterID ContextRegister = JSC::X86Registers::r14; + static const JSC::MacroAssembler::RegisterID ReturnValueRegister = JSC::X86Registers::eax; + static const JSC::MacroAssembler::RegisterID ScratchRegister = JSC::X86Registers::r10; + static const JSC::MacroAssembler::FPRegisterID FPGpr0 = JSC::X86Registers::xmm0; + static const JSC::MacroAssembler::FPRegisterID FPGpr1 = JSC::X86Registers::xmm1; + + static RegisterInformation getPlatformRegisterInfo() + { + typedef RegisterInfo RI; + return RegisterInformation() + << RI(JSC::X86Registers::ebx, QStringLiteral("rbx"), RI::RegularRegister, RI::CalleeSaved, RI::Predefined) + << RI(JSC::X86Registers::edi, QStringLiteral("rdi"), RI::RegularRegister, RI::CalleeSaved, RI::Predefined) + << RI(JSC::X86Registers::esi, QStringLiteral("rsi"), RI::RegularRegister, RI::CalleeSaved, RI::Predefined) + << RI(JSC::X86Registers::edx, QStringLiteral("rdx"), RI::RegularRegister, RI::CallerSaved, RI::Predefined) + << RI(JSC::X86Registers::r9, QStringLiteral("r9"), RI::RegularRegister, RI::CallerSaved, RI::Predefined) + << RI(JSC::X86Registers::r8, QStringLiteral("r8"), RI::RegularRegister, RI::CallerSaved, RI::Predefined) + << RI(JSC::X86Registers::r12, QStringLiteral("r12"), RI::RegularRegister, RI::CalleeSaved, RI::Predefined) + << RI(JSC::X86Registers::r13, QStringLiteral("r13"), RI::RegularRegister, RI::CalleeSaved, RI::Predefined) + << RI(JSC::X86Registers::r14, QStringLiteral("r14"), RI::RegularRegister, RI::CalleeSaved, RI::Predefined) + << RI(JSC::X86Registers::r15, QStringLiteral("r15"), RI::RegularRegister, RI::CalleeSaved, RI::Predefined) + ; + } + +#define HAVE_ALU_OPS_WITH_MEM_OPERAND 1 +#define VALUE_FITS_IN_REGISTER + static const int RegisterSize = 8; + +#define ARGUMENTS_IN_REGISTERS + static const int RegisterArgumentCount = 4; + static JSC::MacroAssembler::RegisterID registerForArgument(int index) + { + static JSC::MacroAssembler::RegisterID regs[RegisterArgumentCount] = { + JSC::X86Registers::ecx, + JSC::X86Registers::edx, + JSC::X86Registers::r8, + JSC::X86Registers::r9 + }; + Q_ASSERT(index >= 0 && index < RegisterArgumentCount); + return regs[index]; + }; + + static const int StackAlignment = 16; + static const int StackShadowSpace = 32; + static const int StackSpaceAllocatedUponFunctionEntry = RegisterSize; // Return address is pushed onto stack by the CPU. + static void platformEnterStandardStackFrame(JSC::MacroAssembler *as) { Q_UNUSED(as); } + static void platformLeaveStandardStackFrame(JSC::MacroAssembler *as) { Q_UNUSED(as); } +#endif // Windows on x86_64 + +#if CPU(ARM) + enum { RegAllocIsSupported = 1 }; + + // The AAPCS specifies that the platform ABI has to define the usage of r9. Known are: + // - The GNU/Linux ABI defines it as an additional callee-saved variable register (v6). + // - iOS (for which we cannot JIT, but still...) defines it as having a special use, so we do + // not touch it, nor use it. + // - Any other platform has not been verified, so we conservatively assume we cannot use it. +#if OS(LINUX) +#define CAN_USE_R9 +#endif + + // There are two designated frame-pointer registers on ARM, depending on which instruction set + // is used for the subroutine: r7 for Thumb or Thumb2, and r11 for ARM. We assign the constants + // accordingly, and assign the locals-register to the "other" register. +#if CPU(ARM_THUMB2) + static const JSC::MacroAssembler::RegisterID StackFrameRegister = JSC::ARMRegisters::r7; + static const JSC::MacroAssembler::RegisterID LocalsRegister = JSC::ARMRegisters::r11; +#else // Thumbs down + static const JSC::MacroAssembler::RegisterID StackFrameRegister = JSC::ARMRegisters::r11; + static const JSC::MacroAssembler::RegisterID LocalsRegister = JSC::ARMRegisters::r7; +#endif + static const JSC::MacroAssembler::RegisterID StackPointerRegister = JSC::ARMRegisters::r13; + static const JSC::MacroAssembler::RegisterID ScratchRegister = JSC::ARMRegisters::r6; + static const JSC::MacroAssembler::RegisterID ContextRegister = JSC::ARMRegisters::r5; + static const JSC::MacroAssembler::RegisterID ReturnValueRegister = JSC::ARMRegisters::r0; + static const JSC::MacroAssembler::FPRegisterID FPGpr0 = JSC::ARMRegisters::d0; + static const JSC::MacroAssembler::FPRegisterID FPGpr1 = JSC::ARMRegisters::d1; + + static RegisterInformation getPlatformRegisterInfo() + { + typedef RegisterInfo RI; + return RegisterInformation() + << RI(JSC::ARMRegisters::r0, QStringLiteral("r0"), RI::RegularRegister, RI::CallerSaved, RI::Predefined) + << RI(JSC::ARMRegisters::r1, QStringLiteral("r1"), RI::RegularRegister, RI::CallerSaved, RI::RegAlloc) + << RI(JSC::ARMRegisters::r2, QStringLiteral("r2"), RI::RegularRegister, RI::CallerSaved, RI::RegAlloc) + << RI(JSC::ARMRegisters::r3, QStringLiteral("r3"), RI::RegularRegister, RI::CallerSaved, RI::RegAlloc) + << RI(JSC::ARMRegisters::r4, QStringLiteral("r4"), RI::RegularRegister, RI::CalleeSaved, RI::RegAlloc) + << RI(JSC::ARMRegisters::r5, QStringLiteral("r5"), RI::RegularRegister, RI::CalleeSaved, RI::Predefined) + << RI(JSC::ARMRegisters::r6, QStringLiteral("r6"), RI::RegularRegister, RI::CalleeSaved, RI::Predefined) +#if !CPU(ARM_THUMB2) + << RI(JSC::ARMRegisters::r7, QStringLiteral("r7"), RI::RegularRegister, RI::CalleeSaved, RI::Predefined) +#endif + << RI(JSC::ARMRegisters::r8, QStringLiteral("r8"), RI::RegularRegister, RI::CalleeSaved, RI::RegAlloc) +#ifdef CAN_USE_R9 + << RI(JSC::ARMRegisters::r9, QStringLiteral("r9"), RI::RegularRegister, RI::CalleeSaved, RI::RegAlloc) +#endif + << RI(JSC::ARMRegisters::r10, QStringLiteral("r10"), RI::RegularRegister, RI::CalleeSaved, RI::Predefined) +#if CPU(ARM_THUMB2) + << RI(JSC::ARMRegisters::r11, QStringLiteral("r11"), RI::RegularRegister, RI::CalleeSaved, RI::Predefined) +#endif + << RI(JSC::ARMRegisters::d2, QStringLiteral("d2"), RI::FloatingPointRegister, RI::CallerSaved, RI::RegAlloc) + << RI(JSC::ARMRegisters::d3, QStringLiteral("d3"), RI::FloatingPointRegister, RI::CallerSaved, RI::RegAlloc) + << RI(JSC::ARMRegisters::d4, QStringLiteral("d4"), RI::FloatingPointRegister, RI::CallerSaved, RI::RegAlloc) + << RI(JSC::ARMRegisters::d5, QStringLiteral("d5"), RI::FloatingPointRegister, RI::CallerSaved, RI::RegAlloc) + << RI(JSC::ARMRegisters::d6, QStringLiteral("d6"), RI::FloatingPointRegister, RI::CallerSaved, RI::RegAlloc) + ; + // TODO: someone should check what's up with d8-d15: are they alway available, and are they caller or callee saved? + } + +#undef HAVE_ALU_OPS_WITH_MEM_OPERAND +#undef VALUE_FITS_IN_REGISTER + static const int RegisterSize = 4; + +#define ARGUMENTS_IN_REGISTERS + static const int RegisterArgumentCount = 4; + static JSC::MacroAssembler::RegisterID registerForArgument(int index) + { + static JSC::MacroAssembler::RegisterID regs[RegisterArgumentCount] = { + JSC::ARMRegisters::r0, + JSC::ARMRegisters::r1, + JSC::ARMRegisters::r2, + JSC::ARMRegisters::r3 + }; + + Q_ASSERT(index >= 0 && index < RegisterArgumentCount); + return regs[index]; + }; + + static const int StackAlignment = 8; // Per AAPCS + static const int StackShadowSpace = 0; + static const int StackSpaceAllocatedUponFunctionEntry = 1 * RegisterSize; // Registers saved in platformEnterStandardStackFrame below. + static void platformEnterStandardStackFrame(JSC::MacroAssembler *as) { as->push(JSC::ARMRegisters::lr); } + static void platformLeaveStandardStackFrame(JSC::MacroAssembler *as) { as->pop(JSC::ARMRegisters::lr); } +#endif // Linux on ARM (32 bit) + +public: // utility functions + static RegisterInformation getRegisterInfo() + { + static const RegisterInformation info = getPlatformRegisterInfo(); + + return info; + } + + static RegisterInformation &getCalleeSavedRegisters() + { + static RegisterInformation regs; + if (regs.isEmpty()) { + foreach (const RegisterInfo &info, getRegisterInfo()) { +#if defined(RESTORE_EBX_ON_CALL) + if (info.reg<JSC::X86Registers::RegisterID>() == JSC::X86Registers::ebx) { + regs.append(info); + continue; + } +#endif // RESTORE_EBX_ON_CALL + if (info.isCalleeSaved()) + regs.append(info); + } + } + + return regs; + } + + static int calleeSavedRegisterCount() + { + return getCalleeSavedRegisters().size(); + } +}; + +} // JIT namespace +} // QV4 namespace + +QT_END_NAMESPACE + +#endif // ENABLE(ASSEMBLER) + +#endif // QV4TARGETPLATFORM_P_H diff --git a/src/qml/jit/qv4unop.cpp b/src/qml/jit/qv4unop.cpp index 40f86f91b5..d92b5797cd 100644 --- a/src/qml/jit/qv4unop.cpp +++ b/src/qml/jit/qv4unop.cpp @@ -51,7 +51,7 @@ using namespace JIT; #define setOp(operation) \ do { call = operation; name = stringIfy(operation); } while (0) -void Unop::generate(IR::Temp *source, IR::Temp *target) +void Unop::generate(IR::Expr *source, IR::Expr *target) { Runtime::UnaryOperation call = 0; const char *name = 0; @@ -77,16 +77,17 @@ void Unop::generate(IR::Temp *source, IR::Temp *target) } } -void Unop::generateUMinus(IR::Temp *source, IR::Temp *target) +void Unop::generateUMinus(IR::Expr *source, IR::Expr *target) { + IR::Temp *targetTemp = target->asTemp(); if (source->type == IR::SInt32Type) { Assembler::RegisterID tReg = Assembler::ScratchRegister; - if (target->kind == IR::Temp::PhysicalRegister) - tReg = (Assembler::RegisterID) target->index; + if (targetTemp && targetTemp->kind == IR::Temp::PhysicalRegister) + tReg = (Assembler::RegisterID) targetTemp->index; Assembler::RegisterID sReg = as->toInt32Register(source, tReg); as->move(sReg, tReg); as->neg32(tReg); - if (target->kind != IR::Temp::PhysicalRegister) + if (!targetTemp || targetTemp->kind != IR::Temp::PhysicalRegister) as->storeInt32(tReg, target); return; } @@ -94,24 +95,25 @@ void Unop::generateUMinus(IR::Temp *source, IR::Temp *target) as->generateFunctionCallImp(target, "Runtime::uMinus", Runtime::uMinus, Assembler::PointerToValue(source)); } -void Unop::generateNot(IR::Temp *source, IR::Temp *target) +void Unop::generateNot(IR::Expr *source, IR::Expr *target) { + IR::Temp *targetTemp = target->asTemp(); if (source->type == IR::BoolType) { Assembler::RegisterID tReg = Assembler::ScratchRegister; - if (target->kind == IR::Temp::PhysicalRegister) - tReg = (Assembler::RegisterID) target->index; + if (targetTemp && targetTemp->kind == IR::Temp::PhysicalRegister) + tReg = (Assembler::RegisterID) targetTemp->index; as->xor32(Assembler::TrustedImm32(0x1), as->toInt32Register(source, tReg), tReg); - if (target->kind != IR::Temp::PhysicalRegister) + if (!targetTemp || targetTemp->kind != IR::Temp::PhysicalRegister) as->storeBool(tReg, target); return; } else if (source->type == IR::SInt32Type) { Assembler::RegisterID tReg = Assembler::ScratchRegister; - if (target->kind == IR::Temp::PhysicalRegister) - tReg = (Assembler::RegisterID) target->index; + if (targetTemp && targetTemp->kind == IR::Temp::PhysicalRegister) + tReg = (Assembler::RegisterID) targetTemp->index; as->compare32(Assembler::Equal, as->toInt32Register(source, Assembler::ScratchRegister), Assembler::TrustedImm32(0), tReg); - if (target->kind != IR::Temp::PhysicalRegister) + if (!targetTemp || targetTemp->kind != IR::Temp::PhysicalRegister) as->storeBool(tReg, target); return; } else if (source->type == IR::DoubleType) { @@ -122,14 +124,15 @@ void Unop::generateNot(IR::Temp *source, IR::Temp *target) as->generateFunctionCallImp(target, "Runtime::uNot", Runtime::uNot, Assembler::PointerToValue(source)); } -void Unop::generateCompl(IR::Temp *source, IR::Temp *target) +void Unop::generateCompl(IR::Expr *source, IR::Expr *target) { + IR::Temp *targetTemp = target->asTemp(); if (source->type == IR::SInt32Type) { Assembler::RegisterID tReg = Assembler::ScratchRegister; - if (target->kind == IR::Temp::PhysicalRegister) - tReg = (Assembler::RegisterID) target->index; + if (targetTemp && targetTemp->kind == IR::Temp::PhysicalRegister) + tReg = (Assembler::RegisterID) targetTemp->index; as->xor32(Assembler::TrustedImm32(0xffffffff), as->toInt32Register(source, tReg), tReg); - if (target->kind != IR::Temp::PhysicalRegister) + if (!targetTemp || targetTemp->kind != IR::Temp::PhysicalRegister) as->storeInt32(tReg, target); return; } diff --git a/src/qml/jit/qv4unop_p.h b/src/qml/jit/qv4unop_p.h index a8c62182ad..07fb6e5ad6 100644 --- a/src/qml/jit/qv4unop_p.h +++ b/src/qml/jit/qv4unop_p.h @@ -59,11 +59,11 @@ struct Unop { , op(operation) {} - void generate(IR::Temp *source, IR::Temp *target); + void generate(IR::Expr *source, IR::Expr *target); - void generateUMinus(IR::Temp *source, IR::Temp *target); - void generateNot(IR::Temp *source, IR::Temp *target); - void generateCompl(IR::Temp *source, IR::Temp *target); + void generateUMinus(IR::Expr *source, IR::Expr *target); + void generateNot(IR::Expr *source, IR::Expr *target); + void generateCompl(IR::Expr *source, IR::Expr *target); Assembler *as; IR::AluOp op; diff --git a/src/qml/jsapi/qjsengine.cpp b/src/qml/jsapi/qjsengine.cpp index 9cb727dd63..929361bf72 100644 --- a/src/qml/jsapi/qjsengine.cpp +++ b/src/qml/jsapi/qjsengine.cpp @@ -50,6 +50,7 @@ #include "private/qv4globalobject_p.h" #include "private/qv4script_p.h" #include "private/qv4runtime_p.h" +#include <private/qqmlbuiltinfunctions_p.h> #include <QtCore/qdatetime.h> #include <QtCore/qmetaobject.h> @@ -232,6 +233,45 @@ void QJSEngine::collectGarbage() } /*! + \since 5.4 + + Installs translator functions on the given \a object, or on the Global + Object if no object is specified. + + The relation between script translator functions and C++ translator + functions is described in the following table: + + \table + \header \li Script Function \li Corresponding C++ Function + \row \li qsTr() \li QObject::tr() + \row \li QT_TR_NOOP() \li QT_TR_NOOP() + \row \li qsTranslate() \li QCoreApplication::translate() + \row \li QT_TRANSLATE_NOOP() \li QT_TRANSLATE_NOOP() + \row \li qsTrId() \li qtTrId() + \row \li QT_TRID_NOOP() \li QT_TRID_NOOP() + \endtable + + \sa {Internationalization with Qt} +*/ +void QJSEngine::installTranslatorFunctions(const QJSValue &object) +{ + QV4::ExecutionEngine *v4 = d->m_v4Engine; + QV4::Scope scope(v4); + QJSValuePrivate *vp = QJSValuePrivate::get(object); + QV4::ScopedObject obj(scope, vp->getValue(v4)); + if (!obj) + obj = v4->globalObject; +#ifndef QT_NO_TRANSLATION + obj->defineDefaultProperty(QStringLiteral("qsTranslate"), QV4::GlobalExtensions::method_qsTranslate); + obj->defineDefaultProperty(QStringLiteral("QT_TRANSLATE_NOOP"), QV4::GlobalExtensions::method_qsTranslateNoOp); + obj->defineDefaultProperty(QStringLiteral("qsTr"), QV4::GlobalExtensions::method_qsTr); + obj->defineDefaultProperty(QStringLiteral("QT_TR_NOOP"), QV4::GlobalExtensions::method_qsTrNoOp); + obj->defineDefaultProperty(QStringLiteral("qsTrId"), QV4::GlobalExtensions::method_qsTrId); + obj->defineDefaultProperty(QStringLiteral("QT_TRID_NOOP"), QV4::GlobalExtensions::method_qsTrIdNoOp); +#endif +} + +/*! Evaluates \a program, using \a lineNumber as the base line number, and returns the result of the evaluation. @@ -269,7 +309,7 @@ QJSValue QJSEngine::evaluate(const QString& program, const QString& fileName, in QV4::ScopedValue result(scope); QV4::Script script(ctx, program, fileName, lineNumber); - script.strictMode = ctx->strictMode; + script.strictMode = ctx->d()->strictMode; script.inheritContext = true; script.parse(); if (!scope.engine->hasException) diff --git a/src/qml/jsapi/qjsengine.h b/src/qml/jsapi/qjsengine.h index 0a575f84e9..9d810a85d1 100644 --- a/src/qml/jsapi/qjsengine.h +++ b/src/qml/jsapi/qjsengine.h @@ -89,6 +89,8 @@ public: void collectGarbage(); + void installTranslatorFunctions(const QJSValue &object = QJSValue()); + QV8Engine *handle() const { return d; } private: diff --git a/src/qml/jsapi/qjsvalue.cpp b/src/qml/jsapi/qjsvalue.cpp index b17ac17752..ec45ce9374 100644 --- a/src/qml/jsapi/qjsvalue.cpp +++ b/src/qml/jsapi/qjsvalue.cpp @@ -385,7 +385,7 @@ double QJSValue::toNumber() const QV4::ExecutionContext *ctx = d->engine ? d->engine->currentContext() : 0; double dbl = d->value.toNumber(); - if (ctx && ctx->engine->hasException) { + if (ctx && ctx->d()->engine->hasException) { ctx->catchException(); return 0; } @@ -411,7 +411,7 @@ bool QJSValue::toBool() const QV4::ExecutionContext *ctx = d->engine ? d->engine->currentContext() : 0; bool b = d->value.toBoolean(); - if (ctx && ctx->engine->hasException) { + if (ctx && ctx->d()->engine->hasException) { ctx->catchException(); return false; } @@ -437,7 +437,7 @@ qint32 QJSValue::toInt() const QV4::ExecutionContext *ctx = d->engine ? d->engine->currentContext() : 0; qint32 i = d->value.toInt32(); - if (ctx && ctx->engine->hasException) { + if (ctx && ctx->d()->engine->hasException) { ctx->catchException(); return 0; } @@ -463,7 +463,7 @@ quint32 QJSValue::toUInt() const QV4::ExecutionContext *ctx = d->engine ? d->engine->currentContext() : 0; quint32 u = d->value.toUInt32(); - if (ctx && ctx->engine->hasException) { + if (ctx && ctx->d()->engine->hasException) { ctx->catchException(); return 0; } @@ -682,7 +682,7 @@ QJSValue QJSValue::prototype() const Scoped<Object> p(scope, o->prototype()); if (!p) return QJSValue(NullValue); - return new QJSValuePrivate(o->internalClass->engine, p); + return new QJSValuePrivate(o->internalClass()->engine, p); } /*! @@ -861,7 +861,7 @@ QJSValue QJSValue::property(const QString& name) const s->makeIdentifier(); QV4::ExecutionContext *ctx = engine->currentContext(); QV4::ScopedValue result(scope); - result = o->get(s); + result = o->get(s.getPointer()); if (scope.hasException()) result = ctx->catchException(); @@ -893,7 +893,7 @@ QJSValue QJSValue::property(quint32 arrayIndex) const QV4::ExecutionContext *ctx = engine->currentContext(); QV4::ScopedValue result(scope); - result = arrayIndex == UINT_MAX ? o->get(engine->id_uintMax) : o->getIndexed(arrayIndex); + result = arrayIndex == UINT_MAX ? o->get(engine->id_uintMax.getPointer()) : o->getIndexed(arrayIndex); if (scope.hasException()) result = ctx->catchException(); return new QJSValuePrivate(engine, result); @@ -936,7 +936,7 @@ void QJSValue::setProperty(const QString& name, const QJSValue& value) QV4::ExecutionContext *ctx = engine->currentContext(); s->makeIdentifier(); QV4::ScopedValue v(scope, value.d->getValue(engine)); - o->put(s, v); + o->put(s.getPointer(), v); if (scope.hasException()) ctx->catchException(); } @@ -969,7 +969,7 @@ void QJSValue::setProperty(quint32 arrayIndex, const QJSValue& value) if (arrayIndex != UINT_MAX) o->putIndexed(arrayIndex, v); else - o->put(engine->id_uintMax, v); + o->put(engine->id_uintMax.getPointer(), v); if (scope.hasException()) ctx->catchException(); } @@ -1004,7 +1004,7 @@ bool QJSValue::deleteProperty(const QString &name) return false; ScopedString s(scope, engine->newString(name)); - bool b = o->deleteProperty(s); + bool b = o->deleteProperty(s.getPointer()); if (scope.hasException()) ctx->catchException(); return b; @@ -1028,7 +1028,7 @@ bool QJSValue::hasProperty(const QString &name) const return false; ScopedString s(scope, engine->newIdentifier(name)); - return o->hasProperty(s); + return o->hasProperty(s.getPointer()); } /*! @@ -1049,7 +1049,7 @@ bool QJSValue::hasOwnProperty(const QString &name) const return false; ScopedString s(scope, engine->newIdentifier(name)); - return o->hasOwnProperty(s); + return o->hasOwnProperty(s.getPointer()); } /*! diff --git a/src/qml/jsapi/qjsvalueiterator.cpp b/src/qml/jsapi/qjsvalueiterator.cpp index 6dcfafaa27..449fb8235a 100644 --- a/src/qml/jsapi/qjsvalueiterator.cpp +++ b/src/qml/jsapi/qjsvalueiterator.cpp @@ -108,8 +108,10 @@ QJSValueIterator::QJSValueIterator(const QJSValue& object) return; QV4::Scope scope(v4); QV4::Scoped<QV4::ForEachIteratorObject> it(scope, d_ptr->iterator.value()); - it->it.flags = QV4::ObjectIterator::NoFlags; - it->it.next(d_ptr->nextName, &d_ptr->nextIndex, &d_ptr->nextProperty, &d_ptr->nextAttributes); + it->d()->it.flags = QV4::ObjectIterator::NoFlags; + QV4::String *nm = 0; + it->d()->it.next(nm, &d_ptr->nextIndex, &d_ptr->nextProperty, &d_ptr->nextAttributes); + d_ptr->nextName = nm; } /*! @@ -155,7 +157,9 @@ bool QJSValueIterator::next() return false; QV4::Scope scope(v4); QV4::Scoped<QV4::ForEachIteratorObject> it(scope, d_ptr->iterator.value()); - it->it.next(d_ptr->nextName, &d_ptr->nextIndex, &d_ptr->nextProperty, &d_ptr->nextAttributes); + QV4::String *nm = 0; + it->d()->it.next(nm, &d_ptr->nextIndex, &d_ptr->nextProperty, &d_ptr->nextAttributes); + d_ptr->nextName = nm; return !!d_ptr->currentName || d_ptr->currentIndex != UINT_MAX; } @@ -229,8 +233,10 @@ QJSValueIterator& QJSValueIterator::operator=(QJSValue& object) QV4::ScopedObject o(scope, jsp->value); d_ptr->iterator = v4->newForEachIteratorObject(v4->currentContext(), o)->asReturnedValue(); QV4::Scoped<QV4::ForEachIteratorObject> it(scope, d_ptr->iterator.value()); - it->it.flags = QV4::ObjectIterator::NoFlags; - it->it.next(d_ptr->nextName, &d_ptr->nextIndex, &d_ptr->nextProperty, &d_ptr->nextAttributes); + it->d()->it.flags = QV4::ObjectIterator::NoFlags; + QV4::String *nm = 0; + it->d()->it.next(nm, &d_ptr->nextIndex, &d_ptr->nextProperty, &d_ptr->nextAttributes); + d_ptr->nextName = nm; return *this; } diff --git a/src/qml/jsruntime/jsruntime.pri b/src/qml/jsruntime/jsruntime.pri index 72010d3fa8..c27aaa90d8 100644 --- a/src/qml/jsruntime/jsruntime.pri +++ b/src/qml/jsruntime/jsruntime.pri @@ -105,13 +105,6 @@ SOURCES += \ $$PWD/qv4string.cpp \ $$PWD/qv4value.cpp -# Use SSE2 floating point math on 32 bit instead of the default -# 387 to make test results pass on 32 and on 64 bit builds. -linux-g++*:isEqual(QT_ARCH,i386) { - QMAKE_CFLAGS += -march=pentium4 -msse2 -mfpmath=sse - QMAKE_CXXFLAGS += -march=pentium4 -msse2 -mfpmath=sse -} - valgrind { DEFINES += V4_USE_VALGRIND } diff --git a/src/qml/jsruntime/qv4argumentsobject.cpp b/src/qml/jsruntime/qv4argumentsobject.cpp index 987b228209..71563b7b0d 100644 --- a/src/qml/jsruntime/qv4argumentsobject.cpp +++ b/src/qml/jsruntime/qv4argumentsobject.cpp @@ -46,63 +46,58 @@ using namespace QV4; DEFINE_OBJECT_VTABLE(ArgumentsObject); -ArgumentsObject::ArgumentsObject(CallContext *context) - : Object(context->strictMode ? context->engine->strictArgumentsObjectClass : context->engine->argumentsObjectClass) +ArgumentsObject::Data::Data(CallContext *context) + : Object::Data(context->d()->strictMode ? context->d()->engine->strictArgumentsObjectClass : context->d()->engine->argumentsObjectClass) , context(context) , fullyCreated(false) { - ExecutionEngine *v4 = context->engine; + Q_ASSERT(internalClass->vtable == staticVTable()); + + ExecutionEngine *v4 = context->d()->engine; Scope scope(v4); - ScopedObject protectThis(scope, this); + Scoped<ArgumentsObject> args(scope, this); - setArrayType(ArrayData::Complex); + args->setArrayType(ArrayData::Complex); - if (context->strictMode) { - Q_ASSERT(CalleePropertyIndex == internalClass->find(context->engine->id_callee)); - Q_ASSERT(CallerPropertyIndex == internalClass->find(context->engine->id_caller)); - propertyAt(CalleePropertyIndex)->value = v4->thrower; - propertyAt(CalleePropertyIndex)->set = v4->thrower; - propertyAt(CallerPropertyIndex)->value = v4->thrower; - propertyAt(CallerPropertyIndex)->set = v4->thrower; + if (context->d()->strictMode) { + Q_ASSERT(CalleePropertyIndex == args->internalClass()->find(context->d()->engine->id_callee)); + Q_ASSERT(CallerPropertyIndex == args->internalClass()->find(context->d()->engine->id_caller)); + args->propertyAt(CalleePropertyIndex)->value = v4->thrower; + args->propertyAt(CalleePropertyIndex)->set = v4->thrower; + args->propertyAt(CallerPropertyIndex)->value = v4->thrower; + args->propertyAt(CallerPropertyIndex)->set = v4->thrower; - arrayReserve(context->callData->argc); - arrayPut(0, context->callData->args, context->callData->argc); - fullyCreated = true; + args->arrayReserve(context->d()->callData->argc); + args->arrayPut(0, context->d()->callData->args, context->d()->callData->argc); + args->d()->fullyCreated = true; } else { - hasAccessorProperty = 1; - Q_ASSERT(CalleePropertyIndex == internalClass->find(context->engine->id_callee)); - memberData[CalleePropertyIndex] = context->function->asReturnedValue(); + args->setHasAccessorProperty(); + Q_ASSERT(CalleePropertyIndex == args->internalClass()->find(context->d()->engine->id_callee)); + args->memberData()[CalleePropertyIndex] = context->d()->function->asReturnedValue(); } - Q_ASSERT(LengthPropertyIndex == internalClass->find(context->engine->id_length)); - memberData[LengthPropertyIndex] = Primitive::fromInt32(context->realArgumentCount); - - Q_ASSERT(internalClass->vtable == staticVTable()); -} - -void ArgumentsObject::destroy(Managed *that) -{ - static_cast<ArgumentsObject *>(that)->~ArgumentsObject(); + Q_ASSERT(LengthPropertyIndex == args->internalClass()->find(context->d()->engine->id_length)); + args->memberData()[LengthPropertyIndex] = Primitive::fromInt32(context->d()->realArgumentCount); } void ArgumentsObject::fullyCreate() { - if (fullyCreated) + if (fullyCreated()) return; - uint numAccessors = qMin((int)context->function->formalParameterCount(), context->realArgumentCount); - uint argCount = qMin(context->realArgumentCount, context->callData->argc); + uint numAccessors = qMin((int)context()->d()->function->formalParameterCount(), context()->d()->realArgumentCount); + uint argCount = qMin(context()->d()->realArgumentCount, context()->d()->callData->argc); ArrayData::realloc(this, ArrayData::Sparse, 0, argCount, true); - context->engine->requireArgumentsAccessors(numAccessors); - mappedArguments.ensureIndex(engine(), numAccessors); + context()->d()->engine->requireArgumentsAccessors(numAccessors); + mappedArguments().ensureIndex(engine(), numAccessors); for (uint i = 0; i < (uint)numAccessors; ++i) { - mappedArguments[i] = context->callData->args[i]; - arraySet(i, context->engine->argumentsAccessors[i], Attr_Accessor); + mappedArguments()[i] = context()->d()->callData->args[i]; + arraySet(i, context()->d()->engine->argumentsAccessors[i], Attr_Accessor); } - arrayPut(numAccessors, context->callData->args + numAccessors, argCount - numAccessors); + arrayPut(numAccessors, context()->d()->callData->args + numAccessors, argCount - numAccessors); for (uint i = numAccessors; i < argCount; ++i) setArrayAttributes(i, Attr_Data); - fullyCreated = true; + d()->fullyCreated = true; } bool ArgumentsObject::defineOwnProperty(ExecutionContext *ctx, uint index, const Property &desc, PropertyAttributes attrs) @@ -110,26 +105,26 @@ bool ArgumentsObject::defineOwnProperty(ExecutionContext *ctx, uint index, const fullyCreate(); Scope scope(ctx); - Property *pd = arrayData->getProperty(index); + Property *pd = arrayData()->getProperty(index); Property map; PropertyAttributes mapAttrs; bool isMapped = false; - uint numAccessors = qMin((int)context->function->formalParameterCount(), context->realArgumentCount); + uint numAccessors = qMin((int)context()->d()->function->formalParameterCount(), context()->d()->realArgumentCount); if (pd && index < (uint)numAccessors) - isMapped = arrayData->attributes(index).isAccessor() && pd->getter() == context->engine->argumentsAccessors[index].getter(); + isMapped = arrayData()->attributes(index).isAccessor() && pd->getter() == context()->d()->engine->argumentsAccessors[index].getter(); if (isMapped) { - mapAttrs = arrayData->attributes(index); + mapAttrs = arrayData()->attributes(index); map.copy(*pd, mapAttrs); setArrayAttributes(index, Attr_Data); - pd = arrayData->getProperty(index); - pd->value = mappedArguments[index]; + pd = arrayData()->getProperty(index); + pd->value = mappedArguments()[index]; } - bool strict = ctx->strictMode; - ctx->strictMode = false; + bool strict = ctx->d()->strictMode; + ctx->d()->strictMode = false; bool result = Object::defineOwnProperty2(ctx, index, desc, attrs); - ctx->strictMode = strict; + ctx->d()->strictMode = strict; if (isMapped && attrs.isData()) { ScopedCallData callData(scope, 1); @@ -139,12 +134,12 @@ bool ArgumentsObject::defineOwnProperty(ExecutionContext *ctx, uint index, const if (attrs.isWritable()) { setArrayAttributes(index, mapAttrs); - pd = arrayData->getProperty(index); + pd = arrayData()->getProperty(index); pd->copy(map, mapAttrs); } } - if (ctx->strictMode && !result) + if (ctx->d()->strictMode && !result) return ctx->throwTypeError(); return result; } @@ -152,13 +147,13 @@ bool ArgumentsObject::defineOwnProperty(ExecutionContext *ctx, uint index, const ReturnedValue ArgumentsObject::getIndexed(Managed *m, uint index, bool *hasProperty) { ArgumentsObject *args = static_cast<ArgumentsObject *>(m); - if (args->fullyCreated) + if (args->fullyCreated()) return Object::getIndexed(m, index, hasProperty); - if (index < static_cast<uint>(args->context->callData->argc)) { + if (index < static_cast<uint>(args->context()->d()->callData->argc)) { if (hasProperty) *hasProperty = true; - return args->context->callData->args[index].asReturnedValue(); + return args->context()->d()->callData->args[index].asReturnedValue(); } if (hasProperty) *hasProperty = false; @@ -168,21 +163,21 @@ ReturnedValue ArgumentsObject::getIndexed(Managed *m, uint index, bool *hasPrope void ArgumentsObject::putIndexed(Managed *m, uint index, const ValueRef value) { ArgumentsObject *args = static_cast<ArgumentsObject *>(m); - if (!args->fullyCreated && index >= static_cast<uint>(args->context->callData->argc)) + if (!args->fullyCreated() && index >= static_cast<uint>(args->context()->d()->callData->argc)) args->fullyCreate(); - if (args->fullyCreated) { + if (args->fullyCreated()) { Object::putIndexed(m, index, value); return; } - args->context->callData->args[index] = value; + args->context()->d()->callData->args[index] = value; } bool ArgumentsObject::deleteIndexedProperty(Managed *m, uint index) { ArgumentsObject *args = static_cast<ArgumentsObject *>(m); - if (!args->fullyCreated) + if (!args->fullyCreated()) args->fullyCreate(); return Object::deleteIndexedProperty(m, index); } @@ -190,11 +185,11 @@ bool ArgumentsObject::deleteIndexedProperty(Managed *m, uint index) PropertyAttributes ArgumentsObject::queryIndexed(const Managed *m, uint index) { const ArgumentsObject *args = static_cast<const ArgumentsObject *>(m); - if (args->fullyCreated) + if (args->fullyCreated()) return Object::queryIndexed(m, index); - uint numAccessors = qMin((int)args->context->function->formalParameterCount(), args->context->realArgumentCount); - uint argCount = qMin(args->context->realArgumentCount, args->context->callData->argc); + uint numAccessors = qMin((int)args->context()->d()->function->formalParameterCount(), args->context()->d()->realArgumentCount); + uint argCount = qMin(args->context()->d()->realArgumentCount, args->context()->d()->callData->argc); if (index >= argCount) return PropertyAttributes(); if (index >= numAccessors) @@ -213,8 +208,8 @@ ReturnedValue ArgumentsGetterFunction::call(Managed *getter, CallData *callData) if (!o) return v4->currentContext()->throwTypeError(); - Q_ASSERT(g->index < static_cast<unsigned>(o->context->callData->argc)); - return o->context->argument(g->index); + Q_ASSERT(g->index() < static_cast<unsigned>(o->context()->d()->callData->argc)); + return o->context()->argument(g->index()); } DEFINE_OBJECT_VTABLE(ArgumentsSetterFunction); @@ -228,17 +223,17 @@ ReturnedValue ArgumentsSetterFunction::call(Managed *setter, CallData *callData) if (!o) return v4->currentContext()->throwTypeError(); - Q_ASSERT(s->index < static_cast<unsigned>(o->context->callData->argc)); - o->context->callData->args[s->index] = callData->argc ? callData->args[0].asReturnedValue() : Encode::undefined(); + Q_ASSERT(s->index() < static_cast<unsigned>(o->context()->d()->callData->argc)); + o->context()->d()->callData->args[s->index()] = callData->argc ? callData->args[0].asReturnedValue() : Encode::undefined(); return Encode::undefined(); } void ArgumentsObject::markObjects(Managed *that, ExecutionEngine *e) { ArgumentsObject *o = static_cast<ArgumentsObject *>(that); - if (o->context) - o->context->mark(e); - o->mappedArguments.mark(e); + if (o->context()) + o->context()->mark(e); + o->mappedArguments().mark(e); Object::markObjects(that, e); } diff --git a/src/qml/jsruntime/qv4argumentsobject_p.h b/src/qml/jsruntime/qv4argumentsobject_p.h index 80c2a70501..59ab9f020e 100644 --- a/src/qml/jsruntime/qv4argumentsobject_p.h +++ b/src/qml/jsruntime/qv4argumentsobject_p.h @@ -50,43 +50,58 @@ namespace QV4 { struct ArgumentsGetterFunction: FunctionObject { - V4_OBJECT - uint index; + struct Data : FunctionObject::Data { + Data(ExecutionContext *scope, uint index) + : FunctionObject::Data(scope) + , index(index) + { + setVTable(staticVTable()); + } + uint index; + }; + V4_OBJECT(FunctionObject) - ArgumentsGetterFunction(ExecutionContext *scope, uint index) - : FunctionObject(scope), index(index) { - setVTable(staticVTable()); - } + uint index() const { return d()->index; } static ReturnedValue call(Managed *that, CallData *d); }; struct ArgumentsSetterFunction: FunctionObject { - V4_OBJECT - uint index; + struct Data : FunctionObject::Data { + Data(ExecutionContext *scope, uint index) + : FunctionObject::Data(scope) + , index(index) + { + setVTable(staticVTable()); + } + uint index; + }; + V4_OBJECT(FunctionObject) - ArgumentsSetterFunction(ExecutionContext *scope, uint index) - : FunctionObject(scope), index(index) { - setVTable(staticVTable()); - } + uint index() const { return d()->index; } static ReturnedValue call(Managed *that, CallData *callData); }; struct ArgumentsObject: Object { - V4_OBJECT + struct Data : Object::Data { + Data(CallContext *context); + CallContext *context; + bool fullyCreated; + Members mappedArguments; + }; + V4_OBJECT(Object) Q_MANAGED_TYPE(ArgumentsObject) - CallContext *context; - bool fullyCreated; - Members mappedArguments; - ArgumentsObject(CallContext *context); - ~ArgumentsObject() {} + + CallContext *context() const { return d()->context; } + bool fullyCreated() const { return d()->fullyCreated; } + Members &mappedArguments() { return d()->mappedArguments; } static bool isNonStrictArgumentsObject(Managed *m) { - return m->internalClass->vtable->type == Type_ArgumentsObject && - !static_cast<ArgumentsObject *>(m)->context->strictMode; + return m->internalClass()->vtable->type == Type_ArgumentsObject && + !static_cast<ArgumentsObject *>(m)->context()->d()->strictMode; } enum { @@ -100,7 +115,6 @@ struct ArgumentsObject: Object { static bool deleteIndexedProperty(Managed *m, uint index); static PropertyAttributes queryIndexed(const Managed *m, uint index); static void markObjects(Managed *that, ExecutionEngine *e); - static void destroy(Managed *); void fullyCreate(); }; diff --git a/src/qml/jsruntime/qv4arraydata.cpp b/src/qml/jsruntime/qv4arraydata.cpp index ed2122fb89..f56c31b177 100644 --- a/src/qml/jsruntime/qv4arraydata.cpp +++ b/src/qml/jsruntime/qv4arraydata.cpp @@ -45,9 +45,25 @@ using namespace QV4; +const QV4::ManagedVTable QV4::ArrayData::static_vtbl = { + 0, + QV4::ArrayData::IsExecutionContext, + QV4::ArrayData::IsString, + QV4::ArrayData::IsObject, + QV4::ArrayData::IsFunctionObject, + QV4::ArrayData::IsErrorObject, + QV4::ArrayData::IsArrayData, + 0, + QV4::ArrayData::MyType, + "ArrayData", + Q_VTABLE_FUNCTION(QV4::ArrayData, destroy), + 0, + isEqualTo +}; + const ArrayVTable SimpleArrayData::static_vtbl = { - DEFINE_MANAGED_VTABLE_INT(SimpleArrayData), + DEFINE_MANAGED_VTABLE_INT(SimpleArrayData, 0), SimpleArrayData::Simple, SimpleArrayData::reallocate, SimpleArrayData::get, @@ -64,7 +80,7 @@ const ArrayVTable SimpleArrayData::static_vtbl = const ArrayVTable SparseArrayData::static_vtbl = { - DEFINE_MANAGED_VTABLE_INT(SparseArrayData), + DEFINE_MANAGED_VTABLE_INT(SparseArrayData, 0), ArrayData::Sparse, SparseArrayData::reallocate, SparseArrayData::get, @@ -82,7 +98,7 @@ const ArrayVTable SparseArrayData::static_vtbl = void ArrayData::realloc(Object *o, Type newType, uint offset, uint alloc, bool enforceAttributes) { - ArrayData *d = o->arrayData; + ArrayData *d = o->arrayData(); uint oldAlloc = 0; uint toCopy = 0; @@ -90,19 +106,19 @@ void ArrayData::realloc(Object *o, Type newType, uint offset, uint alloc, bool e alloc = 8; if (d) { - bool hasAttrs = d->attrs; + bool hasAttrs = d->attrs(); enforceAttributes |= hasAttrs; - if (!offset && alloc <= d->alloc && newType == d->type && hasAttrs == enforceAttributes) + if (!offset && alloc <= d->alloc() && newType == d->type() && hasAttrs == enforceAttributes) return; - oldAlloc = d->alloc; - if (d->type < Sparse) { - offset = qMax(offset, static_cast<SimpleArrayData *>(d)->offset); - toCopy = static_cast<SimpleArrayData *>(d)->len; + oldAlloc = d->alloc(); + if (d->type() < Sparse) { + offset = qMax(offset, static_cast<SimpleArrayData *>(d)->offset()); + toCopy = static_cast<SimpleArrayData *>(d)->len(); } else { Q_ASSERT(!offset); - toCopy = d->alloc; + toCopy = d->alloc(); newType = Sparse; } } @@ -115,69 +131,69 @@ void ArrayData::realloc(Object *o, Type newType, uint offset, uint alloc, bool e size += alloc*sizeof(PropertyAttributes); if (newType < Sparse) { - size += sizeof(SimpleArrayData); + size += sizeof(SimpleArrayData::Data); SimpleArrayData *newData = static_cast<SimpleArrayData *>(o->engine()->memoryManager->allocManaged(size)); - new (newData) SimpleArrayData(o->engine()); - newData->alloc = alloc - offset; - newData->type = newType; - newData->data = reinterpret_cast<Value *>(newData + 1) + offset; - newData->attrs = enforceAttributes ? reinterpret_cast<PropertyAttributes *>(newData->data + alloc) + offset : 0; - newData->offset = offset; - newData->len = d ? static_cast<SimpleArrayData *>(d)->len : 0; - o->arrayData = newData; + new (newData->d()) SimpleArrayData::Data(o->engine()); + newData->setAlloc(alloc - offset); + newData->setType(newType); + newData->setArrayData(reinterpret_cast<Value *>(newData->d() + 1) + offset); + newData->setAttrs(enforceAttributes ? reinterpret_cast<PropertyAttributes *>(newData->arrayData() + alloc) + offset : 0); + newData->offset() = offset; + newData->len() = d ? static_cast<SimpleArrayData *>(d)->len() : 0; + o->setArrayData(newData); } else { - size += sizeof(SparseArrayData); + size += sizeof(SparseArrayData::Data); SparseArrayData *newData = static_cast<SparseArrayData *>(o->engine()->memoryManager->allocManaged(size)); - new (newData) SparseArrayData(o->engine()); - newData->alloc = alloc; - newData->type = newType; - newData->data = reinterpret_cast<Value *>(newData + 1); - newData->attrs = enforceAttributes ? reinterpret_cast<PropertyAttributes *>(newData->data + alloc) : 0; - o->arrayData = newData; + new (newData->d()) SparseArrayData::Data(o->engine()); + newData->setAlloc(alloc); + newData->setType(newType); + newData->setArrayData(reinterpret_cast<Value *>(newData->d() + 1)); + newData->setAttrs(enforceAttributes ? reinterpret_cast<PropertyAttributes *>(newData->arrayData() + alloc) : 0); + o->setArrayData(newData); } if (d) { - memcpy(o->arrayData->data, d->data, sizeof(Value)*toCopy); + memcpy(o->arrayData()->arrayData(), d->arrayData(), sizeof(Value)*toCopy); if (enforceAttributes) { - if (d->attrs) - memcpy(o->arrayData->attrs, d->attrs, sizeof(PropertyAttributes)*toCopy); + if (d->attrs()) + memcpy(o->arrayData()->attrs(), d->attrs(), sizeof(PropertyAttributes)*toCopy); else for (uint i = 0; i < toCopy; ++i) - o->arrayData->attrs[i] = Attr_Data; + o->arrayData()->attrs()[i] = Attr_Data; } } if (newType != Sparse) return; - SparseArrayData *newData = static_cast<SparseArrayData *>(o->arrayData); - if (d && d->type == Sparse) { + SparseArrayData *newData = static_cast<SparseArrayData *>(o->arrayData()); + if (d && d->type() == Sparse) { SparseArrayData *old = static_cast<SparseArrayData *>(d); - newData->sparse = old->sparse; - old->sparse = 0; - newData->freeList = old->freeList; + newData->setSparse(old->sparse()); + old->setSparse(0); + newData->freeList() = old->freeList(); } else { - newData->sparse = new SparseArray; - uint *lastFree = &newData->freeList; + newData->setSparse(new SparseArray); + uint *lastFree = &newData->freeList(); for (uint i = 0; i < toCopy; ++i) { - if (!newData->data[i].isEmpty()) { - SparseArrayNode *n = newData->sparse->insert(i); + if (!newData->arrayData()[i].isEmpty()) { + SparseArrayNode *n = newData->sparse()->insert(i); n->value = i; } else { *lastFree = i; - newData->data[i].tag = Value::Empty_Type; - lastFree = &newData->data[i].uint_32; + newData->arrayData()[i].tag = Value::Empty_Type; + lastFree = &newData->arrayData()[i].uint_32; } } } - uint *lastFree = &newData->freeList; - for (uint i = toCopy; i < newData->alloc; ++i) { + uint *lastFree = &newData->freeList(); + for (uint i = toCopy; i < newData->alloc(); ++i) { *lastFree = i; - newData->data[i].tag = Value::Empty_Type; - lastFree = &newData->data[i].uint_32; + newData->arrayData()[i].tag = Value::Empty_Type; + lastFree = &newData->arrayData()[i].uint_32; } - *lastFree = newData->alloc; + *lastFree = newData->alloc(); // ### Could explicitly free the old data } @@ -185,248 +201,244 @@ void ArrayData::realloc(Object *o, Type newType, uint offset, uint alloc, bool e void SimpleArrayData::getHeadRoom(Object *o) { - SimpleArrayData *dd = static_cast<SimpleArrayData *>(o->arrayData); + SimpleArrayData *dd = static_cast<SimpleArrayData *>(o->arrayData()); Q_ASSERT(dd); - Q_ASSERT(!dd->offset); - uint offset = qMax(dd->len >> 2, (uint)16); + Q_ASSERT(!dd->offset()); + uint offset = qMax(dd->len() >> 2, (uint)16); realloc(o, Simple, offset, 0, false); } ArrayData *SimpleArrayData::reallocate(Object *o, uint n, bool enforceAttributes) { realloc(o, Simple, 0, n, enforceAttributes); - return o->arrayData; + return o->arrayData(); } void ArrayData::ensureAttributes(Object *o) { - if (o->arrayData && o->arrayData->attrs) + if (o->arrayData() && o->arrayData()->attrs()) return; ArrayData::realloc(o, Simple, 0, 0, true); } -void SimpleArrayData::destroy(Managed *) -{ -} - void SimpleArrayData::markObjects(Managed *d, ExecutionEngine *e) { SimpleArrayData *dd = static_cast<SimpleArrayData *>(d); - uint l = dd->len; + uint l = dd->len(); for (uint i = 0; i < l; ++i) - dd->data[i].mark(e); + dd->arrayData()[i].mark(e); } ReturnedValue SimpleArrayData::get(const ArrayData *d, uint index) { const SimpleArrayData *dd = static_cast<const SimpleArrayData *>(d); - if (index >= dd->len) + if (index >= dd->len()) return Primitive::emptyValue().asReturnedValue(); - return dd->data[index].asReturnedValue(); + return dd->arrayData()[index].asReturnedValue(); } bool SimpleArrayData::put(Object *o, uint index, ValueRef value) { - SimpleArrayData *dd = static_cast<SimpleArrayData *>(o->arrayData); - Q_ASSERT(index >= dd->len || !dd->attrs || !dd->attrs[index].isAccessor()); + SimpleArrayData *dd = static_cast<SimpleArrayData *>(o->arrayData()); + Q_ASSERT(index >= dd->len() || !dd->attrs() || !dd->attrs()[index].isAccessor()); // ### honour attributes - dd->data[index] = value; - if (index >= dd->len) { - if (dd->attrs) - dd->attrs[index] = Attr_Data; - dd->len = index + 1; + dd->arrayData()[index] = value; + if (index >= dd->len()) { + if (dd->attrs()) + dd->attrs()[index] = Attr_Data; + dd->len() = index + 1; } return true; } bool SimpleArrayData::del(Object *o, uint index) { - SimpleArrayData *dd = static_cast<SimpleArrayData *>(o->arrayData); - if (index >= dd->len) + SimpleArrayData *dd = static_cast<SimpleArrayData *>(o->arrayData()); + if (index >= dd->len()) return true; - if (!dd->attrs || dd->attrs[index].isConfigurable()) { - dd->data[index] = Primitive::emptyValue(); - if (dd->attrs) - dd->attrs[index] = Attr_Data; + if (!dd->attrs() || dd->attrs()[index].isConfigurable()) { + dd->arrayData()[index] = Primitive::emptyValue(); + if (dd->attrs()) + dd->attrs()[index] = Attr_Data; return true; } - if (dd->data[index].isEmpty()) + if (dd->arrayData()[index].isEmpty()) return true; return false; } void SimpleArrayData::setAttribute(Object *o, uint index, PropertyAttributes attrs) { - o->arrayData->attrs[index] = attrs; + o->arrayData()->attrs()[index] = attrs; } PropertyAttributes SimpleArrayData::attribute(const ArrayData *d, uint index) { - return d->attrs[index]; + return d->attrs()[index]; } void SimpleArrayData::push_front(Object *o, Value *values, uint n) { - SimpleArrayData *dd = static_cast<SimpleArrayData *>(o->arrayData); - Q_ASSERT(!dd->attrs); + SimpleArrayData *dd = static_cast<SimpleArrayData *>(o->arrayData()); + Q_ASSERT(!dd->attrs()); for (int i = n - 1; i >= 0; --i) { - if (!dd->offset) { + if (!dd->offset()) { getHeadRoom(o); - dd = static_cast<SimpleArrayData *>(o->arrayData); + dd = static_cast<SimpleArrayData *>(o->arrayData()); } - --dd->offset; - --dd->data; - ++dd->len; - ++dd->alloc; - *dd->data = values[i].asReturnedValue(); + --dd->offset(); + --dd->arrayData(); + ++dd->len(); + ++dd->alloc(); + *dd->arrayData() = values[i].asReturnedValue(); } } ReturnedValue SimpleArrayData::pop_front(Object *o) { - SimpleArrayData *dd = static_cast<SimpleArrayData *>(o->arrayData); - Q_ASSERT(!dd->attrs); - if (!dd->len) + SimpleArrayData *dd = static_cast<SimpleArrayData *>(o->arrayData()); + Q_ASSERT(!dd->attrs()); + if (!dd->len()) return Encode::undefined(); - ReturnedValue v = dd->data[0].isEmpty() ? Encode::undefined() : dd->data[0].asReturnedValue(); - ++dd->offset; - ++dd->data; - --dd->len; - --dd->alloc; + ReturnedValue v = dd->arrayData()[0].isEmpty() ? Encode::undefined() : dd->arrayData()[0].asReturnedValue(); + ++dd->offset(); + ++dd->arrayData(); + --dd->len(); + --dd->alloc(); return v; } uint SimpleArrayData::truncate(Object *o, uint newLen) { - SimpleArrayData *dd = static_cast<SimpleArrayData *>(o->arrayData); - if (dd->len < newLen) + SimpleArrayData *dd = static_cast<SimpleArrayData *>(o->arrayData()); + if (dd->len() < newLen) return newLen; - if (dd->attrs) { - Value *it = dd->data + dd->len; - const Value *begin = dd->data + newLen; + if (dd->attrs()) { + Value *it = dd->arrayData() + dd->len(); + const Value *begin = dd->arrayData() + newLen; while (--it >= begin) { - if (!it->isEmpty() && !dd->attrs[it - dd->data].isConfigurable()) { - newLen = it - dd->data + 1; + if (!it->isEmpty() && !dd->attrs()[it - dd->arrayData()].isConfigurable()) { + newLen = it - dd->arrayData() + 1; break; } *it = Primitive::emptyValue(); } } - dd->len = newLen; + dd->len() = newLen; return newLen; } uint SimpleArrayData::length(const ArrayData *d) { - return static_cast<const SimpleArrayData *>(d)->len; + return static_cast<const SimpleArrayData *>(d)->len(); } bool SimpleArrayData::putArray(Object *o, uint index, Value *values, uint n) { - SimpleArrayData *dd = static_cast<SimpleArrayData *>(o->arrayData); - if (index + n > dd->alloc) { + SimpleArrayData *dd = static_cast<SimpleArrayData *>(o->arrayData()); + if (index + n > dd->alloc()) { reallocate(o, index + n + 1, false); - dd = static_cast<SimpleArrayData *>(o->arrayData); + dd = static_cast<SimpleArrayData *>(o->arrayData()); } - for (uint i = dd->len; i < index; ++i) - dd->data[i] = Primitive::emptyValue(); + for (uint i = dd->len(); i < index; ++i) + dd->arrayData()[i] = Primitive::emptyValue(); for (uint i = 0; i < n; ++i) - dd->data[index + i] = values[i]; - dd->len = qMax(dd->len, index + n); + dd->arrayData()[index + i] = values[i]; + dd->len() = qMax(dd->len(), index + n); return true; } void SparseArrayData::free(ArrayData *d, uint idx) { - Q_ASSERT(d && d->type == ArrayData::Sparse); + Q_ASSERT(d && d->type() == ArrayData::Sparse); SparseArrayData *dd = static_cast<SparseArrayData *>(d); - Value *v = dd->data + idx; - if (dd->attrs && dd->attrs[idx].isAccessor()) { + Value *v = dd->arrayData() + idx; + if (dd->attrs() && dd->attrs()[idx].isAccessor()) { // double slot, free both. Order is important, so we have a double slot for allocation again afterwards. v[1].tag = Value::Empty_Type; - v[1].uint_32 = dd->freeList; + v[1].uint_32 = dd->freeList(); v[0].tag = Value::Empty_Type; v[0].uint_32 = idx + 1; } else { v->tag = Value::Empty_Type; - v->uint_32 = dd->freeList; + v->uint_32 = dd->freeList(); } - dd->freeList = idx; - if (dd->attrs) - dd->attrs[idx].clear(); + dd->freeList() = idx; + if (dd->attrs()) + dd->attrs()[idx].clear(); } void SparseArrayData::destroy(Managed *d) { SparseArrayData *dd = static_cast<SparseArrayData *>(d); - delete dd->sparse; + delete dd->sparse(); } void SparseArrayData::markObjects(Managed *d, ExecutionEngine *e) { SparseArrayData *dd = static_cast<SparseArrayData *>(d); - uint l = dd->alloc; + uint l = dd->alloc(); for (uint i = 0; i < l; ++i) - dd->data[i].mark(e); + dd->arrayData()[i].mark(e); } ArrayData *SparseArrayData::reallocate(Object *o, uint n, bool enforceAttributes) { realloc(o, Sparse, 0, n, enforceAttributes); - return o->arrayData; + return o->arrayData(); } // double slots are required for accessor properties uint SparseArrayData::allocate(Object *o, bool doubleSlot) { - Q_ASSERT(o->arrayData->type == ArrayData::Sparse); - SparseArrayData *dd = static_cast<SparseArrayData *>(o->arrayData); + Q_ASSERT(o->arrayData()->type() == ArrayData::Sparse); + SparseArrayData *dd = static_cast<SparseArrayData *>(o->arrayData()); if (doubleSlot) { - uint *last = &dd->freeList; + uint *last = &dd->freeList(); while (1) { - if (*last + 1 >= dd->alloc) { - reallocate(o, o->arrayData->alloc + 2, true); - dd = static_cast<SparseArrayData *>(o->arrayData); - last = &dd->freeList; + if (*last + 1 >= dd->alloc()) { + reallocate(o, o->arrayData()->alloc() + 2, true); + dd = static_cast<SparseArrayData *>(o->arrayData()); + last = &dd->freeList(); } - if (dd->data[*last].uint_32 == (*last + 1)) { + if (dd->arrayData()[*last].uint_32 == (*last + 1)) { // found two slots in a row uint idx = *last; - *last = dd->data[*last + 1].uint_32; - o->arrayData->attrs[idx] = Attr_Accessor; + *last = dd->arrayData()[*last + 1].uint_32; + o->arrayData()->attrs()[idx] = Attr_Accessor; return idx; } - last = &dd->data[*last].uint_32; + last = &dd->arrayData()[*last].uint_32; } } else { - if (dd->alloc == dd->freeList) { - reallocate(o, o->arrayData->alloc + 2, false); - dd = static_cast<SparseArrayData *>(o->arrayData); + if (dd->alloc() == dd->freeList()) { + reallocate(o, o->arrayData()->alloc() + 2, false); + dd = static_cast<SparseArrayData *>(o->arrayData()); } - uint idx = dd->freeList; - dd->freeList = dd->data[idx].uint_32; - if (dd->attrs) - dd->attrs[idx] = Attr_Data; + uint idx = dd->freeList(); + dd->freeList() = dd->arrayData()[idx].uint_32; + if (dd->attrs()) + dd->attrs()[idx] = Attr_Data; return idx; } } ReturnedValue SparseArrayData::get(const ArrayData *d, uint index) { - SparseArrayNode *n = static_cast<const SparseArrayData *>(d)->sparse->findNode(index); + SparseArrayNode *n = static_cast<const SparseArrayData *>(d)->sparse()->findNode(index); if (!n) return Primitive::emptyValue().asReturnedValue(); - return d->data[n->value].asReturnedValue(); + return d->arrayData()[n->value].asReturnedValue(); } bool SparseArrayData::put(Object *o, uint index, ValueRef value) @@ -434,93 +446,93 @@ bool SparseArrayData::put(Object *o, uint index, ValueRef value) if (value->isEmpty()) return true; - SparseArrayNode *n = static_cast<SparseArrayData *>(o->arrayData)->sparse->insert(index); - Q_ASSERT(n->value == UINT_MAX || !o->arrayData->attrs || !o->arrayData->attrs[n->value].isAccessor()); + SparseArrayNode *n = static_cast<SparseArrayData *>(o->arrayData())->sparse()->insert(index); + Q_ASSERT(n->value == UINT_MAX || !o->arrayData()->attrs() || !o->arrayData()->attrs()[n->value].isAccessor()); if (n->value == UINT_MAX) n->value = allocate(o); - o->arrayData->data[n->value] = value; - if (o->arrayData->attrs) - o->arrayData->attrs[n->value] = Attr_Data; + o->arrayData()->arrayData()[n->value] = value; + if (o->arrayData()->attrs()) + o->arrayData()->attrs()[n->value] = Attr_Data; return true; } bool SparseArrayData::del(Object *o, uint index) { - SparseArrayData *dd = static_cast<SparseArrayData *>(o->arrayData); - SparseArrayNode *n = dd->sparse->findNode(index); + SparseArrayData *dd = static_cast<SparseArrayData *>(o->arrayData()); + SparseArrayNode *n = dd->sparse()->findNode(index); if (!n) return true; uint pidx = n->value; - Q_ASSERT(!dd->data[pidx].isEmpty()); + Q_ASSERT(!dd->arrayData()[pidx].isEmpty()); bool isAccessor = false; - if (dd->attrs) { - if (!dd->attrs[pidx].isConfigurable()) + if (dd->attrs()) { + if (!dd->attrs()[pidx].isConfigurable()) return false; - isAccessor = dd->attrs[pidx].isAccessor(); - dd->attrs[pidx] = Attr_Data; + isAccessor = dd->attrs()[pidx].isAccessor(); + dd->attrs()[pidx] = Attr_Data; } if (isAccessor) { // free up both indices - dd->data[pidx + 1].tag = Value::Undefined_Type; - dd->data[pidx + 1].uint_32 = static_cast<SparseArrayData *>(dd)->freeList; - dd->data[pidx].tag = Value::Undefined_Type; - dd->data[pidx].uint_32 = pidx + 1; + dd->arrayData()[pidx + 1].tag = Value::Undefined_Type; + dd->arrayData()[pidx + 1].uint_32 = static_cast<SparseArrayData *>(dd)->freeList(); + dd->arrayData()[pidx].tag = Value::Undefined_Type; + dd->arrayData()[pidx].uint_32 = pidx + 1; } else { - dd->data[pidx].tag = Value::Undefined_Type; - dd->data[pidx].uint_32 = static_cast<SparseArrayData *>(dd)->freeList; + dd->arrayData()[pidx].tag = Value::Undefined_Type; + dd->arrayData()[pidx].uint_32 = static_cast<SparseArrayData *>(dd)->freeList(); } - dd->freeList = pidx; - dd->sparse->erase(n); + dd->freeList() = pidx; + dd->sparse()->erase(n); return true; } void SparseArrayData::setAttribute(Object *o, uint index, PropertyAttributes attrs) { - SparseArrayData *d = static_cast<SparseArrayData *>(o->arrayData); - SparseArrayNode *n = d->sparse->insert(index); + SparseArrayData *d = static_cast<SparseArrayData *>(o->arrayData()); + SparseArrayNode *n = d->sparse()->insert(index); if (n->value == UINT_MAX) { n->value = allocate(o, attrs.isAccessor()); - d = static_cast<SparseArrayData *>(o->arrayData); + d = static_cast<SparseArrayData *>(o->arrayData()); } - else if (attrs.isAccessor() != d->attrs[n->value].isAccessor()) { + else if (attrs.isAccessor() != d->attrs()[n->value].isAccessor()) { // need to convert the slot free(d, n->value); n->value = allocate(o, attrs.isAccessor()); } - o->arrayData->attrs[n->value] = attrs; + o->arrayData()->attrs()[n->value] = attrs; } PropertyAttributes SparseArrayData::attribute(const ArrayData *d, uint index) { - SparseArrayNode *n = static_cast<const SparseArrayData *>(d)->sparse->insert(index); + SparseArrayNode *n = static_cast<const SparseArrayData *>(d)->sparse()->insert(index); if (!n) return PropertyAttributes(); - return d->attrs[n->value]; + return d->attrs()[n->value]; } void SparseArrayData::push_front(Object *o, Value *values, uint n) { - Q_ASSERT(!o->arrayData->attrs); + Q_ASSERT(!o->arrayData()->attrs()); for (int i = n - 1; i >= 0; --i) { uint idx = allocate(o); - o->arrayData->data[idx] = values[i]; - static_cast<SparseArrayData *>(o->arrayData)->sparse->push_front(idx); + o->arrayData()->arrayData()[idx] = values[i]; + static_cast<SparseArrayData *>(o->arrayData())->sparse()->push_front(idx); } } ReturnedValue SparseArrayData::pop_front(Object *o) { - Q_ASSERT(!o->arrayData->attrs); - uint idx = static_cast<SparseArrayData *>(o->arrayData)->sparse->pop_front(); + Q_ASSERT(!o->arrayData()->attrs()); + uint idx = static_cast<SparseArrayData *>(o->arrayData())->sparse()->pop_front(); ReturnedValue v; if (idx != UINT_MAX) { - v = o->arrayData->data[idx].asReturnedValue(); - free(o->arrayData, idx); + v = o->arrayData()->arrayData()[idx].asReturnedValue(); + free(o->arrayData(), idx); } else { v = Encode::undefined(); } @@ -529,13 +541,13 @@ ReturnedValue SparseArrayData::pop_front(Object *o) uint SparseArrayData::truncate(Object *o, uint newLen) { - SparseArrayData *d = static_cast<SparseArrayData *>(o->arrayData); - SparseArrayNode *begin = d->sparse->lowerBound(newLen); - if (begin != d->sparse->end()) { - SparseArrayNode *it = d->sparse->end()->previousNode(); + SparseArrayData *d = static_cast<SparseArrayData *>(o->arrayData()); + SparseArrayNode *begin = d->sparse()->lowerBound(newLen); + if (begin != d->sparse()->end()) { + SparseArrayNode *it = d->sparse()->end()->previousNode(); while (1) { - if (d->attrs) { - if (!d->attrs[it->value].isConfigurable()) { + if (d->attrs()) { + if (!d->attrs()[it->value].isConfigurable()) { newLen = it->key() + 1; break; } @@ -543,7 +555,7 @@ uint SparseArrayData::truncate(Object *o, uint newLen) free(d, it->value); bool brk = (it == begin); SparseArrayNode *prev = it->previousNode(); - static_cast<SparseArrayData *>(d)->sparse->erase(it); + static_cast<SparseArrayData *>(d)->sparse()->erase(it); if (brk) break; it = prev; @@ -555,9 +567,9 @@ uint SparseArrayData::truncate(Object *o, uint newLen) uint SparseArrayData::length(const ArrayData *d) { const SparseArrayData *dd = static_cast<const SparseArrayData *>(d); - if (!dd->sparse) + if (!dd->sparse()) return 0; - SparseArrayNode *n = dd->sparse->end(); + SparseArrayNode *n = dd->sparse()->end(); n = n->previousNode(); return n ? n->key() + 1 : 0; } @@ -572,12 +584,12 @@ bool SparseArrayData::putArray(Object *o, uint index, Value *values, uint n) uint ArrayData::append(Object *obj, const ArrayObject *otherObj, uint n) { - Q_ASSERT(!obj->arrayData->hasAttributes()); + Q_ASSERT(!obj->arrayData()->hasAttributes()); if (!n) return obj->getLength(); - const ArrayData *other = otherObj->arrayData; + const ArrayData *other = otherObj->arrayData(); if (other->isSparse()) obj->initSparseArray(); @@ -587,21 +599,21 @@ uint ArrayData::append(Object *obj, const ArrayObject *otherObj, uint n) uint oldSize = obj->getLength(); if (other->isSparse()) { - if (otherObj->hasAccessorProperty && other->hasAttributes()) { + if (otherObj->hasAccessorProperty() && other->hasAttributes()) { Scope scope(obj->engine()); ScopedValue v(scope); - for (const SparseArrayNode *it = static_cast<const SparseArrayData *>(other)->sparse->begin(); - it != static_cast<const SparseArrayData *>(other)->sparse->end(); it = it->nextNode()) { - v = otherObj->getValue(reinterpret_cast<Property *>(other->data + it->value), other->attrs[it->value]); + for (const SparseArrayNode *it = static_cast<const SparseArrayData *>(other)->sparse()->begin(); + it != static_cast<const SparseArrayData *>(other)->sparse()->end(); it = it->nextNode()) { + v = otherObj->getValue(reinterpret_cast<Property *>(other->arrayData() + it->value), other->attrs()[it->value]); obj->arraySet(oldSize + it->key(), v); } } else { - for (const SparseArrayNode *it = static_cast<const SparseArrayData *>(other)->sparse->begin(); - it != static_cast<const SparseArrayData *>(other)->sparse->end(); it = it->nextNode()) - obj->arraySet(oldSize + it->key(), ValueRef(other->data[it->value])); + for (const SparseArrayNode *it = static_cast<const SparseArrayData *>(other)->sparse()->begin(); + it != static_cast<const SparseArrayData *>(other)->sparse()->end(); it = it->nextNode()) + obj->arraySet(oldSize + it->key(), ValueRef(other->arrayData()[it->value])); } } else { - obj->arrayPut(oldSize, other->data, n); + obj->arrayPut(oldSize, other->arrayData(), n); } return oldSize + n; @@ -609,42 +621,42 @@ uint ArrayData::append(Object *obj, const ArrayObject *otherObj, uint n) Property *ArrayData::insert(Object *o, uint index, bool isAccessor) { - if (!isAccessor && o->arrayData->type != ArrayData::Sparse) { - SimpleArrayData *d = static_cast<SimpleArrayData *>(o->arrayData); - if (index < 0x1000 || index < d->len + (d->len >> 2)) { - if (index >= o->arrayData->alloc) { + if (!isAccessor && o->arrayData()->type() != ArrayData::Sparse) { + SimpleArrayData *d = static_cast<SimpleArrayData *>(o->arrayData()); + if (index < 0x1000 || index < d->len() + (d->len() >> 2)) { + if (index >= o->arrayData()->alloc()) { o->arrayReserve(index + 1); - d = static_cast<SimpleArrayData *>(o->arrayData); + d = static_cast<SimpleArrayData *>(o->arrayData()); } - if (index >= d->len) { + if (index >= d->len()) { // 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->len(); i < index; ++i) + d->arrayData()[i] = Primitive::emptyValue(); + d->len() = index + 1; } - return reinterpret_cast<Property *>(o->arrayData->data + index); + return reinterpret_cast<Property *>(o->arrayData()->arrayData() + index); } } o->initSparseArray(); - SparseArrayNode *n = static_cast<SparseArrayData *>(o->arrayData)->sparse->insert(index); + SparseArrayNode *n = static_cast<SparseArrayData *>(o->arrayData())->sparse()->insert(index); if (n->value == UINT_MAX) n->value = SparseArrayData::allocate(o, isAccessor); - return reinterpret_cast<Property *>(o->arrayData->data + n->value); + return reinterpret_cast<Property *>(o->arrayData()->arrayData() + n->value); } class ArrayElementLessThan { public: - inline ArrayElementLessThan(ExecutionContext *context, ObjectRef thisObject, const ValueRef comparefn) + inline ArrayElementLessThan(ExecutionContext *context, Object *thisObject, const ValueRef comparefn) : m_context(context), thisObject(thisObject), m_comparefn(comparefn) {} bool operator()(const Value &v1, const Value &v2) const; private: ExecutionContext *m_context; - ObjectRef thisObject; + Object *thisObject; const ValueRef m_comparefn; }; @@ -674,12 +686,12 @@ bool ArrayElementLessThan::operator()(const Value &v1, const Value &v2) const return p1s->toQString() < p2s->toQString(); } -void ArrayData::sort(ExecutionContext *context, ObjectRef thisObject, const ValueRef comparefn, uint len) +void ArrayData::sort(ExecutionContext *context, Object *thisObject, const ValueRef comparefn, uint len) { if (!len) return; - if (!thisObject->arrayData->length()) + if (!thisObject->arrayData()->length()) return; if (!(comparefn->isUndefined() || comparefn->asObject())) { @@ -690,50 +702,50 @@ void ArrayData::sort(ExecutionContext *context, ObjectRef thisObject, const Valu // The spec says the sorting goes through a series of get,put and delete operations. // this implies that the attributes don't get sorted around. - if (thisObject->arrayData->type == ArrayData::Sparse) { + if (thisObject->arrayData()->type() == ArrayData::Sparse) { // since we sort anyway, we can simply iterate over the entries in the sparse // array and append them one by one to a regular one. - SparseArrayData *sparse = static_cast<SparseArrayData *>(thisObject->arrayData); + SparseArrayData *sparse = static_cast<SparseArrayData *>(thisObject->arrayData()); - if (!sparse->sparse->nEntries()) + if (!sparse->sparse()->nEntries()) return; - thisObject->arrayData = 0; - ArrayData::realloc(thisObject, ArrayData::Simple, 0, sparse->sparse->nEntries(), sparse->attrs ? true : false); - SimpleArrayData *d = static_cast<SimpleArrayData *>(thisObject->arrayData); + thisObject->setArrayData(0); + ArrayData::realloc(thisObject, ArrayData::Simple, 0, sparse->sparse()->nEntries(), sparse->attrs() ? true : false); + SimpleArrayData *d = static_cast<SimpleArrayData *>(thisObject->arrayData()); - SparseArrayNode *n = sparse->sparse->begin(); + SparseArrayNode *n = sparse->sparse()->begin(); uint i = 0; - if (sparse->attrs) { - while (n != sparse->sparse->end()) { + if (sparse->attrs()) { + while (n != sparse->sparse()->end()) { if (n->value >= len) break; - PropertyAttributes a = sparse->attrs ? sparse->attrs[n->value] : Attr_Data; - d->data[i] = thisObject->getValue(reinterpret_cast<Property *>(sparse->data + n->value), a); - d->attrs[i] = a.isAccessor() ? Attr_Data : a; + PropertyAttributes a = sparse->attrs() ? sparse->attrs()[n->value] : Attr_Data; + d->arrayData()[i] = thisObject->getValue(reinterpret_cast<Property *>(sparse->arrayData() + n->value), a); + d->attrs()[i] = a.isAccessor() ? Attr_Data : a; n = n->nextNode(); ++i; } } else { - while (n != sparse->sparse->end()) { + while (n != sparse->sparse()->end()) { if (n->value >= len) break; - d->data[i] = sparse->data[n->value]; + d->arrayData()[i] = sparse->arrayData()[n->value]; n = n->nextNode(); ++i; } } - d->len = i; + d->len() = i; if (len > i) len = i; - if (n != sparse->sparse->end()) { + if (n != sparse->sparse()->end()) { // have some entries outside the sort range that we need to ignore when sorting 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->data + n->value), a); + 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); n = n->nextNode(); } @@ -741,19 +753,19 @@ void ArrayData::sort(ExecutionContext *context, ObjectRef thisObject, const Valu } // ### explicitly delete sparse } else { - SimpleArrayData *d = static_cast<SimpleArrayData *>(thisObject->arrayData); - if (len > d->len) - len = d->len; + SimpleArrayData *d = static_cast<SimpleArrayData *>(thisObject->arrayData()); + if (len > d->len()) + len = d->len(); // sort empty values to the end for (uint i = 0; i < len; i++) { - if (thisObject->arrayData->data[i].isEmpty()) { + if (thisObject->arrayData()->arrayData()[i].isEmpty()) { while (--len > i) - if (!thisObject->arrayData->data[len].isEmpty()) + if (!thisObject->arrayData()->arrayData()[len].isEmpty()) break; - Q_ASSERT(!thisObject->arrayData->attrs || !thisObject->arrayData->attrs[len].isAccessor()); - thisObject->arrayData->data[i] = thisObject->arrayData->data[len]; - thisObject->arrayData->data[len] = Primitive::emptyValue(); + Q_ASSERT(!thisObject->arrayData()->attrs() || !thisObject->arrayData()->attrs()[len].isAccessor()); + thisObject->arrayData()->arrayData()[i] = thisObject->arrayData()->arrayData()[len]; + thisObject->arrayData()->arrayData()[len] = Primitive::emptyValue(); } } @@ -764,7 +776,7 @@ void ArrayData::sort(ExecutionContext *context, ObjectRef thisObject, const Valu ArrayElementLessThan lessThan(context, thisObject, comparefn); - Value *begin = thisObject->arrayData->data; + Value *begin = thisObject->arrayData()->arrayData(); std::sort(begin, begin + len, lessThan); #ifdef CHECK_SPARSE_ARRAYS diff --git a/src/qml/jsruntime/qv4arraydata_p.h b/src/qml/jsruntime/qv4arraydata_p.h index 50b7b8a947..aab9157ced 100644 --- a/src/qml/jsruntime/qv4arraydata_p.h +++ b/src/qml/jsruntime/qv4arraydata_p.h @@ -57,6 +57,10 @@ namespace QV4 { static inline const QV4::ManagedVTable *staticVTable() { return &static_vtbl.managedVTable; } \ template <typename T> \ QV4::Returned<T> *asReturned() { return QV4::Returned<T>::create(this); } \ + V4_MANAGED_SIZE_TEST \ + const Data *d() const { return &static_cast<const Data &>(Managed::data); } \ + Data *d() { return &static_cast<Data &>(Managed::data); } + struct ArrayData; @@ -80,11 +84,6 @@ struct ArrayVTable struct Q_QML_EXPORT ArrayData : public Managed { - ArrayData(InternalClass *ic) - : Managed(ic) - { - } - enum Type { Simple = 0, Complex = 1, @@ -92,13 +91,30 @@ struct Q_QML_EXPORT ArrayData : public Managed Custom = 3 }; - uint alloc; - Type type; - PropertyAttributes *attrs; - Value *data; - - const ArrayVTable *vtable() const { return reinterpret_cast<const ArrayVTable *>(internalClass->vtable); } - bool isSparse() const { return this && type == Sparse; } + struct Data : public Managed::Data { + Data(InternalClass *ic) + : Managed::Data(ic) + {} + uint alloc; + Type type; + PropertyAttributes *attrs; + Value *arrayData; + }; + V4_MANAGED(Managed) + + uint alloc() const { return d()->alloc; } + uint &alloc() { return d()->alloc; } + void setAlloc(uint a) { d()->alloc = a; } + Type type() const { return d()->type; } + void setType(Type t) { d()->type = t; } + PropertyAttributes *attrs() const { return d()->attrs; } + void setAttrs(PropertyAttributes *a) { d()->attrs = a; } + Value *arrayData() const { return d()->arrayData; } + Value *&arrayData() { return d()->arrayData; } + void setArrayData(Value *v) { d()->arrayData = v; } + + const ArrayVTable *vtable() const { return reinterpret_cast<const ArrayVTable *>(internalClass()->vtable); } + bool isSparse() const { return this && type() == Sparse; } uint length() const { if (!this) @@ -107,11 +123,11 @@ struct Q_QML_EXPORT ArrayData : public Managed } bool hasAttributes() const { - return this && attrs; + return this && attrs(); } PropertyAttributes attributes(int i) const { Q_ASSERT(this); - return attrs ? vtable()->attribute(this, i) : Attr_Data; + return attrs() ? vtable()->attribute(this, i) : Attr_Data; } bool isEmpty(uint i) const { @@ -130,26 +146,31 @@ struct Q_QML_EXPORT ArrayData : public Managed static void ensureAttributes(Object *o); static void realloc(Object *o, Type newType, uint offset, uint alloc, bool enforceAttributes); - static void sort(ExecutionContext *context, ObjectRef thisObject, const ValueRef comparefn, uint dataLen); + static void sort(ExecutionContext *context, Object *thisObject, const ValueRef comparefn, uint dataLen); static uint append(Object *obj, const ArrayObject *otherObj, uint n); static Property *insert(Object *o, uint index, bool isAccessor = false); }; struct Q_QML_EXPORT SimpleArrayData : public ArrayData { - V4_ARRAYDATA - SimpleArrayData(ExecutionEngine *engine) - : ArrayData(engine->simpleArrayDataClass) - {} + struct Data : public ArrayData::Data { + Data(ExecutionEngine *engine) + : ArrayData::Data(engine->simpleArrayDataClass) + {} + uint len; + uint offset; + }; + V4_ARRAYDATA - uint len; - uint offset; + uint &len() { return d()->len; } + uint len() const { return d()->len; } + uint &offset() { return d()->offset; } + uint offset() const { return d()->offset; } static void getHeadRoom(Object *o); static ArrayData *reallocate(Object *o, uint n, bool enforceAttributes); - static void destroy(Managed *d); static void markObjects(Managed *d, ExecutionEngine *e); static ReturnedValue get(const ArrayData *d, uint index); @@ -166,14 +187,20 @@ struct Q_QML_EXPORT SimpleArrayData : public ArrayData struct Q_QML_EXPORT SparseArrayData : public ArrayData { - V4_ARRAYDATA + struct Data : public ArrayData::Data { + Data(ExecutionEngine *engine) + : ArrayData::Data(engine->emptyClass) + { setVTable(staticVTable()); } - SparseArrayData(ExecutionEngine *engine) - : ArrayData(engine->emptyClass) - { setVTable(staticVTable()); } + uint freeList; + SparseArray *sparse; + }; + V4_ARRAYDATA - uint freeList; - SparseArray *sparse; + uint &freeList() { return d()->freeList; } + uint freeList() const { return d()->freeList; } + SparseArray *sparse() const { return d()->sparse; } + void setSparse(SparseArray *s) { d()->sparse = s; } static uint allocate(Object *o, bool doubleSlot = false); static void free(ArrayData *d, uint idx); @@ -199,16 +226,16 @@ inline Property *ArrayData::getProperty(uint index) const { if (!this) return 0; - if (type != Sparse) { + if (type() != Sparse) { const SimpleArrayData *that = static_cast<const SimpleArrayData *>(this); - if (index >= that->len || data[index].isEmpty()) + if (index >= that->len() || arrayData()[index].isEmpty()) return 0; - return reinterpret_cast<Property *>(data + index); + return reinterpret_cast<Property *>(arrayData() + index); } else { - SparseArrayNode *n = static_cast<const SparseArrayData *>(this)->sparse->findNode(index); + SparseArrayNode *n = static_cast<const SparseArrayData *>(this)->sparse()->findNode(index); if (!n) return 0; - return reinterpret_cast<Property *>(data + n->value); + return reinterpret_cast<Property *>(arrayData() + n->value); } } diff --git a/src/qml/jsruntime/qv4arrayobject.cpp b/src/qml/jsruntime/qv4arrayobject.cpp index fbd757a829..abe8a44065 100644 --- a/src/qml/jsruntime/qv4arrayobject.cpp +++ b/src/qml/jsruntime/qv4arrayobject.cpp @@ -48,8 +48,8 @@ using namespace QV4; DEFINE_OBJECT_VTABLE(ArrayCtor); -ArrayCtor::ArrayCtor(ExecutionContext *scope) - : FunctionObject(scope, QStringLiteral("Array")) +ArrayCtor::Data::Data(ExecutionContext *scope) + : FunctionObject::Data(scope, QStringLiteral("Array")) { setVTable(staticVTable()); } @@ -84,12 +84,7 @@ ReturnedValue ArrayCtor::call(Managed *that, CallData *callData) return construct(that, callData); } -ArrayPrototype::ArrayPrototype(InternalClass *ic) - : ArrayObject(ic) -{ -} - -void ArrayPrototype::init(ExecutionEngine *engine, ObjectRef ctor) +void ArrayPrototype::init(ExecutionEngine *engine, Object *ctor) { Scope scope(engine); ScopedObject o(scope); @@ -122,21 +117,21 @@ void ArrayPrototype::init(ExecutionEngine *engine, ObjectRef ctor) ReturnedValue ArrayPrototype::method_isArray(CallContext *ctx) { - bool isArray = ctx->callData->argc && ctx->callData->args[0].asArrayObject(); + bool isArray = ctx->d()->callData->argc && ctx->d()->callData->args[0].asArrayObject(); return Encode(isArray); } ReturnedValue ArrayPrototype::method_toString(CallContext *ctx) { Scope scope(ctx); - ScopedObject o(scope, ctx->callData->thisObject, ScopedObject::Convert); - if (ctx->engine->hasException) + ScopedObject o(scope, ctx->d()->callData->thisObject, ScopedObject::Convert); + if (ctx->d()->engine->hasException) return Encode::undefined(); - ScopedString s(scope, ctx->engine->newString(QStringLiteral("join"))); - ScopedFunctionObject f(scope, o->get(s)); + ScopedString s(scope, ctx->d()->engine->newString(QStringLiteral("join"))); + ScopedFunctionObject f(scope, o->get(s.getPointer())); if (!!f) { ScopedCallData d(scope, 0); - d->thisObject = ctx->callData->thisObject; + d->thisObject = ctx->d()->callData->thisObject; return f->call(d); } return ObjectPrototype::method_toString(ctx); @@ -150,9 +145,9 @@ ReturnedValue ArrayPrototype::method_toLocaleString(CallContext *ctx) ReturnedValue ArrayPrototype::method_concat(CallContext *ctx) { Scope scope(ctx); - ScopedObject result(scope, ctx->engine->newArrayObject()); + ScopedObject result(scope, ctx->d()->engine->newArrayObject()); - ScopedObject thisObject(scope, ctx->callData->thisObject.toObject(ctx)); + ScopedObject thisObject(scope, ctx->d()->callData->thisObject.toObject(ctx)); if (!thisObject) return Encode::undefined(); ScopedArrayObject instance(scope, thisObject); @@ -165,9 +160,9 @@ ReturnedValue ArrayPrototype::method_concat(CallContext *ctx) ScopedArrayObject elt(scope); ScopedObject eltAsObj(scope); ScopedValue entry(scope); - for (int i = 0; i < ctx->callData->argc; ++i) { - eltAsObj = ctx->callData->args[i]; - elt = ctx->callData->args[i]; + for (int i = 0; i < ctx->d()->callData->argc; ++i) { + eltAsObj = ctx->d()->callData->args[i]; + elt = ctx->d()->callData->args[i]; if (elt) { uint n = elt->getLength(); uint newLen = ArrayData::append(result.getPointer(), elt.getPointer(), n); @@ -179,7 +174,7 @@ ReturnedValue ArrayPrototype::method_concat(CallContext *ctx) result->putIndexed(startIndex + i, entry); } } else { - result->arraySet(result->getLength(), ValueRef(ctx->callData->args[i])); + result->arraySet(result->getLength(), ValueRef(ctx->d()->callData->args[i])); } } @@ -197,12 +192,12 @@ ReturnedValue ArrayPrototype::method_join(CallContext *ctx) else r4 = arg->toQString(); - ScopedObject self(scope, ctx->callData->thisObject); - ScopedValue length(scope, self->get(ctx->engine->id_length)); + ScopedObject self(scope, ctx->d()->callData->thisObject); + ScopedValue length(scope, self->get(ctx->d()->engine->id_length)); const quint32 r2 = length->isUndefined() ? 0 : length->toUInt32(); if (!r2) - return ctx->engine->newString(QString())->asReturnedValue(); + return ctx->d()->engine->newString(QString())->asReturnedValue(); QString R; @@ -223,8 +218,8 @@ ReturnedValue ArrayPrototype::method_join(CallContext *ctx) // // crazy! // - ScopedString name(scope, ctx->engine->newString(QStringLiteral("0"))); - ScopedValue r6(scope, self->get(name)); + ScopedString name(scope, ctx->d()->engine->newString(QStringLiteral("0"))); + ScopedValue r6(scope, self->get(name.getPointer())); if (!r6->isNullOrUndefined()) R = r6->toString(ctx)->toQString(); @@ -233,7 +228,7 @@ ReturnedValue ArrayPrototype::method_join(CallContext *ctx) R += r4; name = Primitive::fromDouble(k).toString(ctx); - r12 = self->get(name); + r12 = self->get(name.getPointer()); if (scope.hasException()) return Encode::undefined(); @@ -242,20 +237,20 @@ ReturnedValue ArrayPrototype::method_join(CallContext *ctx) } } - return ctx->engine->newString(R)->asReturnedValue(); + return ctx->d()->engine->newString(R)->asReturnedValue(); } ReturnedValue ArrayPrototype::method_pop(CallContext *ctx) { Scope scope(ctx); - ScopedObject instance(scope, ctx->callData->thisObject.toObject(ctx)); + ScopedObject instance(scope, ctx->d()->callData->thisObject.toObject(ctx)); if (!instance) return Encode::undefined(); uint len = instance->getLength(); if (!len) { if (!instance->isArrayObject()) - instance->put(ctx->engine->id_length, ScopedValue(scope, Primitive::fromInt32(0))); + instance->put(ctx->d()->engine->id_length, ScopedValue(scope, Primitive::fromInt32(0))); return Encode::undefined(); } @@ -269,14 +264,14 @@ ReturnedValue ArrayPrototype::method_pop(CallContext *ctx) if (instance->isArrayObject()) instance->setArrayLength(len - 1); else - instance->put(ctx->engine->id_length, ScopedValue(scope, Primitive::fromDouble(len - 1))); + instance->put(ctx->d()->engine->id_length, ScopedValue(scope, Primitive::fromDouble(len - 1))); return result.asReturnedValue(); } ReturnedValue ArrayPrototype::method_push(CallContext *ctx) { Scope scope(ctx); - ScopedObject instance(scope, ctx->callData->thisObject.toObject(ctx)); + ScopedObject instance(scope, ctx->d()->callData->thisObject.toObject(ctx)); if (!instance) return Encode::undefined(); @@ -284,38 +279,38 @@ ReturnedValue ArrayPrototype::method_push(CallContext *ctx) uint len = instance->getLength(); - if (len + ctx->callData->argc < len) { + if (len + ctx->d()->callData->argc < len) { // ughh... double l = len; ScopedString s(scope); - for (int i = 0; i < ctx->callData->argc; ++i) { + for (int i = 0; i < ctx->d()->callData->argc; ++i) { s = Primitive::fromDouble(l + i).toString(ctx); - instance->put(s, ctx->callData->args[i]); + instance->put(s.getPointer(), ctx->d()->callData->args[i]); } - double newLen = l + ctx->callData->argc; + double newLen = l + ctx->d()->callData->argc; if (!instance->isArrayObject()) - instance->put(ctx->engine->id_length, ScopedValue(scope, Primitive::fromDouble(newLen))); + instance->put(ctx->d()->engine->id_length, ScopedValue(scope, Primitive::fromDouble(newLen))); else { - ScopedString str(scope, ctx->engine->newString(QStringLiteral("Array.prototype.push: Overflow"))); + ScopedString str(scope, ctx->d()->engine->newString(QStringLiteral("Array.prototype.push: Overflow"))); return ctx->throwRangeError(str); } return Encode(newLen); } - if (!ctx->callData->argc) { + if (!ctx->d()->callData->argc) { ; - } else if (!instance->protoHasArray() && instance->arrayData->length() <= len && instance->arrayType() == ArrayData::Simple) { - instance->arrayData->vtable()->putArray(instance.getPointer(), len, ctx->callData->args, ctx->callData->argc); - len = instance->arrayData->length(); + } else if (!instance->protoHasArray() && instance->arrayData()->length() <= len && instance->arrayType() == ArrayData::Simple) { + instance->arrayData()->vtable()->putArray(instance.getPointer(), len, ctx->d()->callData->args, ctx->d()->callData->argc); + len = instance->arrayData()->length(); } else { - for (int i = 0; i < ctx->callData->argc; ++i) - instance->putIndexed(len + i, ctx->callData->args[i]); - len += ctx->callData->argc; + for (int i = 0; i < ctx->d()->callData->argc; ++i) + instance->putIndexed(len + i, ctx->d()->callData->args[i]); + len += ctx->d()->callData->argc; } if (instance->isArrayObject()) instance->setArrayLengthUnchecked(len); else - instance->put(ctx->engine->id_length, ScopedValue(scope, Primitive::fromDouble(len))); + instance->put(ctx->d()->engine->id_length, ScopedValue(scope, Primitive::fromDouble(len))); return Encode(len); } @@ -323,7 +318,7 @@ ReturnedValue ArrayPrototype::method_push(CallContext *ctx) ReturnedValue ArrayPrototype::method_reverse(CallContext *ctx) { Scope scope(ctx); - ScopedObject instance(scope, ctx->callData->thisObject.toObject(ctx)); + ScopedObject instance(scope, ctx->d()->callData->thisObject.toObject(ctx)); if (!instance) return Encode::undefined(); uint length = instance->getLength(); @@ -355,7 +350,7 @@ ReturnedValue ArrayPrototype::method_reverse(CallContext *ctx) ReturnedValue ArrayPrototype::method_shift(CallContext *ctx) { Scope scope(ctx); - ScopedObject instance(scope, ctx->callData->thisObject.toObject(ctx)); + ScopedObject instance(scope, ctx->d()->callData->thisObject.toObject(ctx)); if (!instance) return Encode::undefined(); @@ -365,14 +360,14 @@ ReturnedValue ArrayPrototype::method_shift(CallContext *ctx) if (!len) { if (!instance->isArrayObject()) - instance->put(ctx->engine->id_length, ScopedValue(scope, Primitive::fromInt32(0))); + instance->put(ctx->d()->engine->id_length, ScopedValue(scope, Primitive::fromInt32(0))); return Encode::undefined(); } ScopedValue result(scope); - if (!instance->protoHasArray() && !instance->arrayData->hasAttributes() && instance->arrayData->length() <= len && instance->arrayData->type != ArrayData::Custom) { - result = instance->arrayData->vtable()->pop_front(instance.getPointer()); + if (!instance->protoHasArray() && !instance->arrayData()->hasAttributes() && instance->arrayData()->length() <= len && instance->arrayData()->type() != ArrayData::Custom) { + result = instance->arrayData()->vtable()->pop_front(instance.getPointer()); } else { result = instance->getIndexed(0); if (scope.hasException()) @@ -399,18 +394,18 @@ ReturnedValue ArrayPrototype::method_shift(CallContext *ctx) if (instance->isArrayObject()) instance->setArrayLengthUnchecked(len - 1); else - instance->put(ctx->engine->id_length, ScopedValue(scope, Primitive::fromDouble(len - 1))); + instance->put(ctx->d()->engine->id_length, ScopedValue(scope, Primitive::fromDouble(len - 1))); return result.asReturnedValue(); } ReturnedValue ArrayPrototype::method_slice(CallContext *ctx) { Scope scope(ctx); - ScopedObject o(scope, ctx->callData->thisObject.toObject(ctx)); + ScopedObject o(scope, ctx->d()->callData->thisObject.toObject(ctx)); if (!o) return Encode::undefined(); - Scoped<ArrayObject> result(scope, ctx->engine->newArrayObject()); + Scoped<ArrayObject> result(scope, ctx->d()->engine->newArrayObject()); uint len = o->getLength(); double s = ScopedValue(scope, ctx->argument(0))->toInteger(); uint start; @@ -421,8 +416,8 @@ ReturnedValue ArrayPrototype::method_slice(CallContext *ctx) else start = (uint) s; uint end = len; - if (ctx->callData->argc > 1 && !ctx->callData->args[1].isUndefined()) { - double e = ctx->callData->args[1].toInteger(); + if (ctx->d()->callData->argc > 1 && !ctx->d()->callData->args[1].isUndefined()) { + double e = ctx->d()->callData->args[1].toInteger(); if (e < 0) end = (uint)qMax(len + e, 0.); else if (e > len) @@ -448,7 +443,7 @@ ReturnedValue ArrayPrototype::method_slice(CallContext *ctx) ReturnedValue ArrayPrototype::method_sort(CallContext *ctx) { Scope scope(ctx); - Scoped<Object> instance(scope, ctx->callData->thisObject.toObject(ctx)); + Scoped<Object> instance(scope, ctx->d()->callData->thisObject.toObject(ctx)); if (!instance) return Encode::undefined(); @@ -456,18 +451,18 @@ ReturnedValue ArrayPrototype::method_sort(CallContext *ctx) ScopedValue comparefn(scope, ctx->argument(0)); ArrayData::sort(ctx, instance, comparefn, len); - return ctx->callData->thisObject.asReturnedValue(); + return ctx->d()->callData->thisObject.asReturnedValue(); } ReturnedValue ArrayPrototype::method_splice(CallContext *ctx) { Scope scope(ctx); - ScopedObject instance(scope, ctx->callData->thisObject.toObject(ctx)); + ScopedObject instance(scope, ctx->d()->callData->thisObject.toObject(ctx)); if (!instance) return Encode::undefined(); uint len = instance->getLength(); - Scoped<ArrayObject> newArray(scope, ctx->engine->newArrayObject()); + Scoped<ArrayObject> newArray(scope, ctx->d()->engine->newArrayObject()); double rs = ScopedValue(scope, ctx->argument(0))->toInteger(); uint start; @@ -490,7 +485,7 @@ ReturnedValue ArrayPrototype::method_splice(CallContext *ctx) } newArray->setArrayLengthUnchecked(deleteCount); - uint itemCount = ctx->callData->argc < 2 ? 0 : ctx->callData->argc - 2; + uint itemCount = ctx->d()->callData->argc < 2 ? 0 : ctx->d()->callData->argc - 2; if (itemCount < deleteCount) { for (uint k = start; k < len - deleteCount; ++k) { @@ -528,13 +523,13 @@ ReturnedValue ArrayPrototype::method_splice(CallContext *ctx) } for (uint i = 0; i < itemCount; ++i) { - instance->putIndexed(start + i, ctx->callData->args[i + 2]); + instance->putIndexed(start + i, ctx->d()->callData->args[i + 2]); if (scope.hasException()) return Encode::undefined(); } - ctx->strictMode = true; - instance->put(ctx->engine->id_length, ScopedValue(scope, Primitive::fromDouble(len - deleteCount + itemCount))); + ctx->d()->strictMode = true; + instance->put(ctx->d()->engine->id_length, ScopedValue(scope, Primitive::fromDouble(len - deleteCount + itemCount))); return newArray.asReturnedValue(); } @@ -542,7 +537,7 @@ ReturnedValue ArrayPrototype::method_splice(CallContext *ctx) ReturnedValue ArrayPrototype::method_unshift(CallContext *ctx) { Scope scope(ctx); - ScopedObject instance(scope, ctx->callData->thisObject.toObject(ctx)); + ScopedObject instance(scope, ctx->d()->callData->thisObject.toObject(ctx)); if (!instance) return Encode::undefined(); @@ -550,27 +545,27 @@ ReturnedValue ArrayPrototype::method_unshift(CallContext *ctx) uint len = instance->getLength(); - if (!instance->protoHasArray() && !instance->arrayData->hasAttributes() && instance->arrayData->length() <= len && instance->arrayData->type != ArrayData::Custom) { - instance->arrayData->vtable()->push_front(instance.getPointer(), ctx->callData->args, ctx->callData->argc); + if (!instance->protoHasArray() && !instance->arrayData()->hasAttributes() && instance->arrayData()->length() <= len && instance->arrayData()->type() != ArrayData::Custom) { + instance->arrayData()->vtable()->push_front(instance.getPointer(), ctx->d()->callData->args, ctx->d()->callData->argc); } else { ScopedValue v(scope); for (uint k = len; k > 0; --k) { bool exists; v = instance->getIndexed(k - 1, &exists); if (exists) - instance->putIndexed(k + ctx->callData->argc - 1, v); + instance->putIndexed(k + ctx->d()->callData->argc - 1, v); else - instance->deleteIndexedProperty(k + ctx->callData->argc - 1); + instance->deleteIndexedProperty(k + ctx->d()->callData->argc - 1); } - for (int i = 0; i < ctx->callData->argc; ++i) - instance->putIndexed(i, ctx->callData->args[i]); + for (int i = 0; i < ctx->d()->callData->argc; ++i) + instance->putIndexed(i, ctx->d()->callData->args[i]); } - uint newLen = len + ctx->callData->argc; + uint newLen = len + ctx->d()->callData->argc; if (instance->isArrayObject()) instance->setArrayLengthUnchecked(newLen); else - instance->put(ctx->engine->id_length, ScopedValue(scope, Primitive::fromDouble(newLen))); + instance->put(ctx->d()->engine->id_length, ScopedValue(scope, Primitive::fromDouble(newLen))); return Encode(newLen); } @@ -579,18 +574,18 @@ ReturnedValue ArrayPrototype::method_indexOf(CallContext *ctx) { Scope scope(ctx); - ScopedObject instance(scope, ctx->callData->thisObject.toObject(ctx)); + ScopedObject instance(scope, ctx->d()->callData->thisObject.toObject(ctx)); if (!instance) return Encode::undefined(); uint len = instance->getLength(); if (!len) return Encode(-1); - ScopedValue searchValue(scope, ctx->callData->argument(0)); + ScopedValue searchValue(scope, ctx->d()->callData->argument(0)); uint fromIndex = 0; - if (ctx->callData->argc >= 2) { - double f = ctx->callData->args[1].toInteger(); + if (ctx->d()->callData->argc >= 2) { + double f = ctx->d()->callData->args[1].toInteger(); if (scope.hasException()) return Encode::undefined(); if (f >= len) @@ -613,7 +608,7 @@ ReturnedValue ArrayPrototype::method_indexOf(CallContext *ctx) ScopedValue value(scope); - if (instance->hasAccessorProperty || (instance->arrayType() >= ArrayData::Sparse) || instance->protoHasArray()) { + if (instance->hasAccessorProperty() || (instance->arrayType() >= ArrayData::Sparse) || instance->protoHasArray()) { // lets be safe and slow for (uint i = fromIndex; i < len; ++i) { bool exists; @@ -623,13 +618,13 @@ ReturnedValue ArrayPrototype::method_indexOf(CallContext *ctx) if (exists && RuntimeHelpers::strictEqual(value, searchValue)) return Encode(i); } - } else if (!instance->arrayData) { + } else if (!instance->arrayData()) { return Encode(-1); } else { Q_ASSERT(instance->arrayType() == ArrayData::Simple || instance->arrayType() == ArrayData::Complex); - if (len > instance->arrayData->length()) - len = instance->arrayData->length(); - Value *val = instance->arrayData->data; + if (len > instance->arrayData()->length()) + len = instance->arrayData()->length(); + Value *val = instance->arrayData()->arrayData(); Value *end = val + len; val += fromIndex; while (val < end) { @@ -638,7 +633,7 @@ ReturnedValue ArrayPrototype::method_indexOf(CallContext *ctx) if (scope.hasException()) return Encode::undefined(); if (RuntimeHelpers::strictEqual(value, searchValue)) - return Encode((uint)(val - instance->arrayData->data)); + return Encode((uint)(val - instance->arrayData()->arrayData())); } ++val; } @@ -650,7 +645,7 @@ ReturnedValue ArrayPrototype::method_lastIndexOf(CallContext *ctx) { Scope scope(ctx); - ScopedObject instance(scope, ctx->callData->thisObject.toObject(ctx)); + ScopedObject instance(scope, ctx->d()->callData->thisObject.toObject(ctx)); if (!instance) return Encode::undefined(); uint len = instance->getLength(); @@ -660,13 +655,13 @@ ReturnedValue ArrayPrototype::method_lastIndexOf(CallContext *ctx) ScopedValue searchValue(scope); uint fromIndex = len; - if (ctx->callData->argc >= 1) + if (ctx->d()->callData->argc >= 1) searchValue = ctx->argument(0); else searchValue = Primitive::undefinedValue(); - if (ctx->callData->argc >= 2) { - double f = ctx->callData->args[1].toInteger(); + if (ctx->d()->callData->argc >= 2) { + double f = ctx->d()->callData->args[1].toInteger(); if (scope.hasException()) return Encode::undefined(); if (f > 0) @@ -695,7 +690,7 @@ ReturnedValue ArrayPrototype::method_lastIndexOf(CallContext *ctx) ReturnedValue ArrayPrototype::method_every(CallContext *ctx) { Scope scope(ctx); - Scoped<Object> instance(scope, ctx->callData->thisObject.toObject(ctx)); + Scoped<Object> instance(scope, ctx->d()->callData->thisObject.toObject(ctx)); if (!instance) return Encode::undefined(); @@ -729,7 +724,7 @@ ReturnedValue ArrayPrototype::method_every(CallContext *ctx) ReturnedValue ArrayPrototype::method_some(CallContext *ctx) { Scope scope(ctx); - Scoped<Object> instance(scope, ctx->callData->thisObject.toObject(ctx)); + Scoped<Object> instance(scope, ctx->d()->callData->thisObject.toObject(ctx)); if (!instance) return Encode::undefined(); @@ -763,7 +758,7 @@ ReturnedValue ArrayPrototype::method_some(CallContext *ctx) ReturnedValue ArrayPrototype::method_forEach(CallContext *ctx) { Scope scope(ctx); - Scoped<Object> instance(scope, ctx->callData->thisObject.toObject(ctx)); + Scoped<Object> instance(scope, ctx->d()->callData->thisObject.toObject(ctx)); if (!instance) return Encode::undefined(); @@ -794,7 +789,7 @@ ReturnedValue ArrayPrototype::method_forEach(CallContext *ctx) ReturnedValue ArrayPrototype::method_map(CallContext *ctx) { Scope scope(ctx); - Scoped<Object> instance(scope, ctx->callData->thisObject.toObject(ctx)); + Scoped<Object> instance(scope, ctx->d()->callData->thisObject.toObject(ctx)); if (!instance) return Encode::undefined(); @@ -804,7 +799,7 @@ ReturnedValue ArrayPrototype::method_map(CallContext *ctx) if (!callback) return ctx->throwTypeError(); - Scoped<ArrayObject> a(scope, ctx->engine->newArrayObject()); + Scoped<ArrayObject> a(scope, ctx->d()->engine->newArrayObject()); a->arrayReserve(len); a->setArrayLengthUnchecked(len); @@ -831,7 +826,7 @@ ReturnedValue ArrayPrototype::method_map(CallContext *ctx) ReturnedValue ArrayPrototype::method_filter(CallContext *ctx) { Scope scope(ctx); - Scoped<Object> instance(scope, ctx->callData->thisObject.toObject(ctx)); + Scoped<Object> instance(scope, ctx->d()->callData->thisObject.toObject(ctx)); if (!instance) return Encode::undefined(); @@ -841,7 +836,7 @@ ReturnedValue ArrayPrototype::method_filter(CallContext *ctx) if (!callback) return ctx->throwTypeError(); - Scoped<ArrayObject> a(scope, ctx->engine->newArrayObject()); + Scoped<ArrayObject> a(scope, ctx->d()->engine->newArrayObject()); a->arrayReserve(len); ScopedValue selected(scope); @@ -872,7 +867,7 @@ ReturnedValue ArrayPrototype::method_filter(CallContext *ctx) ReturnedValue ArrayPrototype::method_reduce(CallContext *ctx) { Scope scope(ctx); - Scoped<Object> instance(scope, ctx->callData->thisObject.toObject(ctx)); + Scoped<Object> instance(scope, ctx->d()->callData->thisObject.toObject(ctx)); if (!instance) return Encode::undefined(); @@ -886,7 +881,7 @@ ReturnedValue ArrayPrototype::method_reduce(CallContext *ctx) ScopedValue acc(scope); ScopedValue v(scope); - if (ctx->callData->argc > 1) { + if (ctx->d()->callData->argc > 1) { acc = ctx->argument(1); } else { bool kPresent = false; @@ -922,7 +917,7 @@ ReturnedValue ArrayPrototype::method_reduce(CallContext *ctx) ReturnedValue ArrayPrototype::method_reduceRight(CallContext *ctx) { Scope scope(ctx); - Scoped<Object> instance(scope, ctx->callData->thisObject.toObject(ctx)); + Scoped<Object> instance(scope, ctx->d()->callData->thisObject.toObject(ctx)); if (!instance) return Encode::undefined(); @@ -933,7 +928,7 @@ ReturnedValue ArrayPrototype::method_reduceRight(CallContext *ctx) return ctx->throwTypeError(); if (len == 0) { - if (ctx->callData->argc == 1) + if (ctx->d()->callData->argc == 1) return ctx->throwTypeError(); return ctx->argument(1); } @@ -941,7 +936,7 @@ ReturnedValue ArrayPrototype::method_reduceRight(CallContext *ctx) uint k = len; ScopedValue acc(scope); ScopedValue v(scope); - if (ctx->callData->argc > 1) { + if (ctx->d()->callData->argc > 1) { acc = ctx->argument(1); } else { bool kPresent = false; diff --git a/src/qml/jsruntime/qv4arrayobject_p.h b/src/qml/jsruntime/qv4arrayobject_p.h index e7f8ba711f..dccda2896e 100644 --- a/src/qml/jsruntime/qv4arrayobject_p.h +++ b/src/qml/jsruntime/qv4arrayobject_p.h @@ -51,8 +51,11 @@ namespace QV4 { struct ArrayCtor: FunctionObject { - V4_OBJECT - ArrayCtor(ExecutionContext *scope); + struct Data : FunctionObject::Data { + Data(ExecutionContext *scope); + }; + + V4_OBJECT(FunctionObject) static ReturnedValue construct(Managed *m, CallData *callData); static ReturnedValue call(Managed *that, CallData *callData); @@ -60,9 +63,7 @@ struct ArrayCtor: FunctionObject struct ArrayPrototype: ArrayObject { - ArrayPrototype(InternalClass *ic); - - void init(ExecutionEngine *engine, ObjectRef ctor); + void init(ExecutionEngine *engine, Object *ctor); static ReturnedValue method_isArray(CallContext *ctx); static ReturnedValue method_toString(CallContext *ctx); diff --git a/src/qml/jsruntime/qv4booleanobject.cpp b/src/qml/jsruntime/qv4booleanobject.cpp index 662ec64efb..38a0f7f549 100644 --- a/src/qml/jsruntime/qv4booleanobject.cpp +++ b/src/qml/jsruntime/qv4booleanobject.cpp @@ -46,8 +46,8 @@ using namespace QV4; DEFINE_OBJECT_VTABLE(BooleanCtor); DEFINE_OBJECT_VTABLE(BooleanObject); -BooleanCtor::BooleanCtor(ExecutionContext *scope) - : FunctionObject(scope, QStringLiteral("Boolean")) +BooleanCtor::Data::Data(ExecutionContext *scope) + : FunctionObject::Data(scope, QStringLiteral("Boolean")) { setVTable(staticVTable()); } @@ -66,7 +66,7 @@ ReturnedValue BooleanCtor::call(Managed *, CallData *callData) return Encode(value); } -void BooleanPrototype::init(ExecutionEngine *engine, ObjectRef ctor) +void BooleanPrototype::init(ExecutionEngine *engine, Object *ctor) { Scope scope(engine); ScopedObject o(scope); @@ -80,28 +80,28 @@ void BooleanPrototype::init(ExecutionEngine *engine, ObjectRef ctor) ReturnedValue BooleanPrototype::method_toString(CallContext *ctx) { bool result; - if (ctx->callData->thisObject.isBoolean()) { - result = ctx->callData->thisObject.booleanValue(); + if (ctx->d()->callData->thisObject.isBoolean()) { + result = ctx->d()->callData->thisObject.booleanValue(); } else { Scope scope(ctx); - Scoped<BooleanObject> thisObject(scope, ctx->callData->thisObject); + Scoped<BooleanObject> thisObject(scope, ctx->d()->callData->thisObject); if (!thisObject) return ctx->throwTypeError(); - result = thisObject->value.booleanValue(); + result = thisObject->value().booleanValue(); } - return Encode(ctx->engine->newString(QLatin1String(result ? "true" : "false"))); + return Encode(ctx->d()->engine->newString(QLatin1String(result ? "true" : "false"))); } ReturnedValue BooleanPrototype::method_valueOf(CallContext *ctx) { - if (ctx->callData->thisObject.isBoolean()) - return ctx->callData->thisObject.asReturnedValue(); + if (ctx->d()->callData->thisObject.isBoolean()) + return ctx->d()->callData->thisObject.asReturnedValue(); Scope scope(ctx); - Scoped<BooleanObject> thisObject(scope, ctx->callData->thisObject); + Scoped<BooleanObject> thisObject(scope, ctx->d()->callData->thisObject); if (!thisObject) return ctx->throwTypeError(); - return thisObject->value.asReturnedValue(); + return thisObject->value().asReturnedValue(); } diff --git a/src/qml/jsruntime/qv4booleanobject_p.h b/src/qml/jsruntime/qv4booleanobject_p.h index 617f7f6b01..35cfd5729e 100644 --- a/src/qml/jsruntime/qv4booleanobject_p.h +++ b/src/qml/jsruntime/qv4booleanobject_p.h @@ -51,8 +51,11 @@ namespace QV4 { struct BooleanCtor: FunctionObject { - V4_OBJECT - BooleanCtor(ExecutionContext *scope); + struct Data : FunctionObject::Data { + Data(ExecutionContext *scope); + }; + + V4_OBJECT(FunctionObject) static ReturnedValue construct(Managed *, CallData *callData); static ReturnedValue call(Managed *that, CallData *callData); @@ -60,8 +63,7 @@ struct BooleanCtor: FunctionObject struct BooleanPrototype: BooleanObject { - BooleanPrototype(InternalClass *ic): BooleanObject(ic) {} - void init(ExecutionEngine *engine, ObjectRef ctor); + void init(ExecutionEngine *engine, Object *ctor); static ReturnedValue method_toString(CallContext *ctx); static ReturnedValue method_valueOf(CallContext *ctx); diff --git a/src/qml/jsruntime/qv4context.cpp b/src/qml/jsruntime/qv4context.cpp index b43b4893a3..62d5859e87 100644 --- a/src/qml/jsruntime/qv4context.cpp +++ b/src/qml/jsruntime/qv4context.cpp @@ -52,27 +52,30 @@ using namespace QV4; DEFINE_MANAGED_VTABLE(ExecutionContext); +DEFINE_MANAGED_VTABLE(CallContext); +DEFINE_MANAGED_VTABLE(WithContext); +DEFINE_MANAGED_VTABLE(GlobalContext); -CallContext *ExecutionContext::newCallContext(FunctionObject *function, CallData *callData) +HeapObject *ExecutionContext::newCallContext(FunctionObject *function, CallData *callData) { - Q_ASSERT(function->function); + Q_ASSERT(function->function()); - CallContext *c = static_cast<CallContext *>(engine->memoryManager->allocManaged(requiredMemoryForExecutionContect(function, callData->argc))); - new (c) CallContext(engine, Type_CallContext); + CallContext::Data *c = reinterpret_cast<CallContext::Data *>(d()->engine->memoryManager->allocManaged(requiredMemoryForExecutionContect(function, callData->argc))); + new (c) CallContext::Data(d()->engine, Type_CallContext); c->function = function; c->realArgumentCount = callData->argc; - c->strictMode = function->strictMode; - c->outer = function->scope; + c->strictMode = function->strictMode(); + c->outer = function->scope(); c->activation = 0; - c->compilationUnit = function->function->compilationUnit; + c->compilationUnit = function->function()->compilationUnit; c->lookups = c->compilationUnit->runtimeLookups; c->locals = (Value *)((quintptr(c + 1) + 7) & ~7); - const CompiledData::Function *compiledFunction = function->function->compiledFunction; + const CompiledData::Function *compiledFunction = function->function()->compiledFunction; int nLocals = compiledFunction->nLocals; if (nLocals) std::fill(c->locals, c->locals + nLocals, Primitive::undefinedValue()); @@ -86,43 +89,41 @@ CallContext *ExecutionContext::newCallContext(FunctionObject *function, CallData return c; } -WithContext *ExecutionContext::newWithContext(ObjectRef with) +WithContext *ExecutionContext::newWithContext(Object *with) { - WithContext *w = new (engine->memoryManager) WithContext(engine, with); - return w; + return d()->engine->memoryManager->alloc<WithContext>(d()->engine, with); } -CatchContext *ExecutionContext::newCatchContext(const StringRef exceptionVarName, const ValueRef exceptionValue) +CatchContext *ExecutionContext::newCatchContext(String *exceptionVarName, const ValueRef exceptionValue) { - CatchContext *c = new (engine->memoryManager) CatchContext(engine, exceptionVarName, exceptionValue); - return c; + return d()->engine->memoryManager->alloc<CatchContext>(d()->engine, exceptionVarName, exceptionValue); } -CallContext *ExecutionContext::newQmlContext(FunctionObject *f, ObjectRef qml) +CallContext *ExecutionContext::newQmlContext(FunctionObject *f, Object *qml) { - CallContext *c = static_cast<CallContext *>(engine->memoryManager->allocManaged(requiredMemoryForExecutionContect(f, 0))); - new (c) CallContext(engine, qml, f); + CallContext *c = reinterpret_cast<CallContext*>(d()->engine->memoryManager->allocManaged(requiredMemoryForExecutionContect(f, 0))); + new (c->d()) CallContext::Data(d()->engine, qml, f); return c; } -void ExecutionContext::createMutableBinding(const StringRef name, bool deletable) +void ExecutionContext::createMutableBinding(String *name, bool deletable) { Scope scope(this); // find the right context to create the binding on - ScopedObject activation(scope, engine->globalObject); + ScopedObject activation(scope, d()->engine->globalObject); ExecutionContext *ctx = this; while (ctx) { - if (ctx->type >= Type_CallContext) { + if (ctx->d()->type >= Type_CallContext) { CallContext *c = static_cast<CallContext *>(ctx); - if (!c->activation) - c->activation = engine->newObject()->getPointer(); - activation = c->activation; + if (!c->d()->activation) + c->d()->activation = d()->engine->newObject()->getPointer(); + activation = c->d()->activation; break; } - ctx = ctx->outer; + ctx = ctx->d()->outer; } if (activation->hasProperty(name)) @@ -134,38 +135,38 @@ void ExecutionContext::createMutableBinding(const StringRef name, bool deletable } -GlobalContext::GlobalContext(ExecutionEngine *eng) - : ExecutionContext(eng, Type_GlobalContext) +GlobalContext::Data::Data(ExecutionEngine *eng) + : ExecutionContext::Data(eng, Type_GlobalContext) { global = eng->globalObject; } -WithContext::WithContext(ExecutionEngine *engine, ObjectRef with) - : ExecutionContext(engine, Type_WithContext) +WithContext::Data::Data(ExecutionEngine *engine, Object *with) + : ExecutionContext::Data(engine, Type_WithContext) { - callData = parent->callData; + callData = parent->d()->callData; outer = parent; - lookups = parent->lookups; - compilationUnit = parent->compilationUnit; + lookups = parent->d()->lookups; + compilationUnit = parent->d()->compilationUnit; - withObject = with.getPointer(); + withObject = with; } -CatchContext::CatchContext(ExecutionEngine *engine, const StringRef exceptionVarName, const ValueRef exceptionValue) - : ExecutionContext(engine, Type_CatchContext) +CatchContext::Data::Data(ExecutionEngine *engine, String *exceptionVarName, const ValueRef exceptionValue) + : ExecutionContext::Data(engine, Type_CatchContext) { - strictMode = parent->strictMode; - callData = parent->callData; + strictMode = parent->d()->strictMode; + callData = parent->d()->callData; outer = parent; - lookups = parent->lookups; - compilationUnit = parent->compilationUnit; + lookups = parent->d()->lookups; + compilationUnit = parent->d()->compilationUnit; this->exceptionVarName = exceptionVarName; this->exceptionValue = exceptionValue; } -CallContext::CallContext(ExecutionEngine *engine, ObjectRef qml, FunctionObject *function) - : ExecutionContext(engine, Type_QmlContext) +CallContext::Data::Data(ExecutionEngine *engine, Object *qml, FunctionObject *function) + : ExecutionContext::Data(engine, Type_QmlContext) { this->function = function; callData = reinterpret_cast<CallData *>(this + 1); @@ -174,12 +175,12 @@ CallContext::CallContext(ExecutionEngine *engine, ObjectRef qml, FunctionObject callData->thisObject = Primitive::undefinedValue(); strictMode = true; - outer = function->scope; + outer = function->scope(); - activation = qml.getPointer(); + activation = qml; - if (function->function) { - compilationUnit = function->function->compilationUnit; + if (function->function()) { + compilationUnit = function->function()->compilationUnit; lookups = compilationUnit->runtimeLookups; } @@ -190,170 +191,170 @@ CallContext::CallContext(ExecutionEngine *engine, ObjectRef qml, FunctionObject String * const *CallContext::formals() const { - return (function && function->function) ? function->function->internalClass->nameMap.constData() : 0; + return (d()->function && d()->function->function()) ? d()->function->function()->internalClass->nameMap.constData() : 0; } unsigned int CallContext::formalCount() const { - return function ? function->formalParameterCount() : 0; + return d()->function ? d()->function->formalParameterCount() : 0; } String * const *CallContext::variables() const { - return (function && function->function) ? function->function->internalClass->nameMap.constData() + function->function->compiledFunction->nFormals : 0; + return (d()->function && d()->function->function()) ? d()->function->function()->internalClass->nameMap.constData() + d()->function->function()->compiledFunction->nFormals : 0; } unsigned int CallContext::variableCount() const { - return function ? function->varCount() : 0; + return d()->function ? d()->function->varCount() : 0; } -bool ExecutionContext::deleteProperty(const StringRef name) +bool ExecutionContext::deleteProperty(String *name) { Scope scope(this); bool hasWith = false; - for (ExecutionContext *ctx = this; ctx; ctx = ctx->outer) { - if (ctx->type == Type_WithContext) { + for (ExecutionContext *ctx = this; ctx; ctx = ctx->d()->outer) { + if (ctx->d()->type == Type_WithContext) { hasWith = true; WithContext *w = static_cast<WithContext *>(ctx); - if (w->withObject->hasProperty(name)) - return w->withObject->deleteProperty(name); - } else if (ctx->type == Type_CatchContext) { + if (w->d()->withObject->hasProperty(name)) + return w->d()->withObject->deleteProperty(name); + } else if (ctx->d()->type == Type_CatchContext) { CatchContext *c = static_cast<CatchContext *>(ctx); - if (c->exceptionVarName->isEqualTo(name)) + if (c->d()->exceptionVarName->isEqualTo(name)) return false; - } else if (ctx->type >= Type_CallContext) { + } else if (ctx->d()->type >= Type_CallContext) { CallContext *c = static_cast<CallContext *>(ctx); - FunctionObject *f = c->function; - if (f->needsActivation || hasWith) { - uint index = f->function->internalClass->find(name); + FunctionObject *f = c->d()->function; + if (f->needsActivation() || hasWith) { + uint index = f->function()->internalClass->find(name); if (index < UINT_MAX) // ### throw in strict mode? return false; } - if (c->activation && c->activation->hasProperty(name)) - return c->activation->deleteProperty(name); - } else if (ctx->type == Type_GlobalContext) { + if (c->d()->activation && c->d()->activation->hasProperty(name)) + return c->d()->activation->deleteProperty(name); + } else if (ctx->d()->type == Type_GlobalContext) { GlobalContext *g = static_cast<GlobalContext *>(ctx); - if (g->global->hasProperty(name)) - return g->global->deleteProperty(name); + if (g->d()->global->hasProperty(name)) + return g->d()->global->deleteProperty(name); } } - if (strictMode) + if (d()->strictMode) throwSyntaxError(QStringLiteral("Can't delete property %1").arg(name->toQString())); return true; } bool CallContext::needsOwnArguments() const { - return function->needsActivation || callData->argc < static_cast<int>(function->formalParameterCount()); + return d()->function->needsActivation() || d()->callData->argc < static_cast<int>(d()->function->formalParameterCount()); } void ExecutionContext::markObjects(Managed *m, ExecutionEngine *engine) { ExecutionContext *ctx = static_cast<ExecutionContext *>(m); - if (ctx->outer) - ctx->outer->mark(engine); + if (ctx->d()->outer) + ctx->d()->outer->mark(engine); // ### shouldn't need these 3 lines - ctx->callData->thisObject.mark(engine); - for (int arg = 0; arg < ctx->callData->argc; ++arg) - ctx->callData->args[arg].mark(engine); + ctx->d()->callData->thisObject.mark(engine); + for (int arg = 0; arg < ctx->d()->callData->argc; ++arg) + ctx->d()->callData->args[arg].mark(engine); - if (ctx->type >= Type_CallContext) { + if (ctx->d()->type >= Type_CallContext) { QV4::CallContext *c = static_cast<CallContext *>(ctx); - for (unsigned local = 0, lastLocal = c->function->varCount(); local < lastLocal; ++local) - c->locals[local].mark(engine); - if (c->activation) - c->activation->mark(engine); - c->function->mark(engine); - } else if (ctx->type == Type_WithContext) { + for (unsigned local = 0, lastLocal = c->d()->function->varCount(); local < lastLocal; ++local) + c->d()->locals[local].mark(engine); + if (c->d()->activation) + c->d()->activation->mark(engine); + c->d()->function->mark(engine); + } else if (ctx->d()->type == Type_WithContext) { WithContext *w = static_cast<WithContext *>(ctx); - w->withObject->mark(engine); - } else if (ctx->type == Type_CatchContext) { + w->d()->withObject->mark(engine); + } else if (ctx->d()->type == Type_CatchContext) { CatchContext *c = static_cast<CatchContext *>(ctx); - c->exceptionVarName->mark(engine); - c->exceptionValue.mark(engine); - } else if (ctx->type == Type_GlobalContext) { + c->d()->exceptionVarName->mark(engine); + c->d()->exceptionValue.mark(engine); + } else if (ctx->d()->type == Type_GlobalContext) { GlobalContext *g = static_cast<GlobalContext *>(ctx); - g->global->mark(engine); + g->d()->global->mark(engine); } } -void ExecutionContext::setProperty(const StringRef name, const ValueRef value) +void ExecutionContext::setProperty(String *name, const ValueRef value) { Scope scope(this); - for (ExecutionContext *ctx = this; ctx; ctx = ctx->outer) { - if (ctx->type == Type_WithContext) { - ScopedObject w(scope, static_cast<WithContext *>(ctx)->withObject); + for (ExecutionContext *ctx = this; ctx; ctx = ctx->d()->outer) { + if (ctx->d()->type == Type_WithContext) { + ScopedObject w(scope, static_cast<WithContext *>(ctx)->d()->withObject); if (w->hasProperty(name)) { w->put(name, value); return; } - } else if (ctx->type == Type_CatchContext && static_cast<CatchContext *>(ctx)->exceptionVarName->isEqualTo(name)) { - static_cast<CatchContext *>(ctx)->exceptionValue = *value; + } else if (ctx->d()->type == Type_CatchContext && static_cast<CatchContext *>(ctx)->d()->exceptionVarName->isEqualTo(name)) { + static_cast<CatchContext *>(ctx)->d()->exceptionValue = *value; return; } else { ScopedObject activation(scope, (Object *)0); - if (ctx->type >= Type_CallContext) { + if (ctx->d()->type >= Type_CallContext) { CallContext *c = static_cast<CallContext *>(ctx); - if (c->function->function) { - uint index = c->function->function->internalClass->find(name); + if (c->d()->function->function()) { + uint index = c->d()->function->function()->internalClass->find(name); if (index < UINT_MAX) { - if (index < c->function->formalParameterCount()) { - c->callData->args[c->function->formalParameterCount() - index - 1] = *value; + if (index < c->d()->function->formalParameterCount()) { + c->d()->callData->args[c->d()->function->formalParameterCount() - index - 1] = *value; } else { - index -= c->function->formalParameterCount(); - c->locals[index] = *value; + index -= c->d()->function->formalParameterCount(); + c->d()->locals[index] = *value; } return; } } - activation = c->activation; - } else if (ctx->type == Type_GlobalContext) { - activation = static_cast<GlobalContext *>(ctx)->global; + activation = c->d()->activation; + } else if (ctx->d()->type == Type_GlobalContext) { + activation = static_cast<GlobalContext *>(ctx)->d()->global; } if (activation) { - if (ctx->type == Type_QmlContext) { + if (ctx->d()->type == Type_QmlContext) { activation->put(name, value); return; } else { - uint member = activation->internalClass->find(name); + uint member = activation->internalClass()->find(name); if (member < UINT_MAX) { - activation->putValue(activation->propertyAt(member), activation->internalClass->propertyData[member], value); + activation->putValue(activation->propertyAt(member), activation->internalClass()->propertyData[member], value); return; } } } } } - if (strictMode || name->equals(engine->id_this)) { - ScopedValue n(scope, name.asReturnedValue()); + if (d()->strictMode || name->equals(d()->engine->id_this.getPointer())) { + ScopedValue n(scope, name->asReturnedValue()); throwReferenceError(n); return; } - engine->globalObject->put(name, value); + d()->engine->globalObject->put(name, value); } -ReturnedValue ExecutionContext::getProperty(const StringRef name) +ReturnedValue ExecutionContext::getProperty(String *name) { Scope scope(this); ScopedValue v(scope); name->makeIdentifier(); - if (name->equals(engine->id_this)) - return callData->thisObject.asReturnedValue(); + if (name->equals(d()->engine->id_this.getPointer())) + return d()->callData->thisObject.asReturnedValue(); bool hasWith = false; bool hasCatchScope = false; - for (ExecutionContext *ctx = this; ctx; ctx = ctx->outer) { - if (ctx->type == Type_WithContext) { - ScopedObject w(scope, static_cast<WithContext *>(ctx)->withObject); + for (ExecutionContext *ctx = this; ctx; ctx = ctx->d()->outer) { + if (ctx->d()->type == Type_WithContext) { + ScopedObject w(scope, static_cast<WithContext *>(ctx)->d()->withObject); hasWith = true; bool hasProperty = false; v = w->get(name, &hasProperty); @@ -363,62 +364,62 @@ ReturnedValue ExecutionContext::getProperty(const StringRef name) continue; } - else if (ctx->type == Type_CatchContext) { + else if (ctx->d()->type == Type_CatchContext) { hasCatchScope = true; CatchContext *c = static_cast<CatchContext *>(ctx); - if (c->exceptionVarName->isEqualTo(name)) - return c->exceptionValue.asReturnedValue(); + if (c->d()->exceptionVarName->isEqualTo(name)) + return c->d()->exceptionValue.asReturnedValue(); } - else if (ctx->type >= Type_CallContext) { + else if (ctx->d()->type >= Type_CallContext) { QV4::CallContext *c = static_cast<CallContext *>(ctx); - ScopedFunctionObject f(scope, c->function); - if (f->function && (f->needsActivation || hasWith || hasCatchScope)) { - uint index = f->function->internalClass->find(name); + ScopedFunctionObject f(scope, c->d()->function); + if (f->function() && (f->needsActivation() || hasWith || hasCatchScope)) { + uint index = f->function()->internalClass->find(name); if (index < UINT_MAX) { - if (index < c->function->formalParameterCount()) - return c->callData->args[c->function->formalParameterCount() - index - 1].asReturnedValue(); - return c->locals[index - c->function->formalParameterCount()].asReturnedValue(); + if (index < c->d()->function->formalParameterCount()) + return c->d()->callData->args[c->d()->function->formalParameterCount() - index - 1].asReturnedValue(); + return c->d()->locals[index - c->d()->function->formalParameterCount()].asReturnedValue(); } } - if (c->activation) { + if (c->d()->activation) { bool hasProperty = false; - v = c->activation->get(name, &hasProperty); + v = c->d()->activation->get(name, &hasProperty); if (hasProperty) return v.asReturnedValue(); } - if (f->function && f->function->isNamedExpression() - && name->equals(f->function->name())) + if (f->function() && f->function()->isNamedExpression() + && name->equals(f->function()->name())) return f.asReturnedValue(); } - else if (ctx->type == Type_GlobalContext) { + else if (ctx->d()->type == Type_GlobalContext) { GlobalContext *g = static_cast<GlobalContext *>(ctx); bool hasProperty = false; - v = g->global->get(name, &hasProperty); + v = g->d()->global->get(name, &hasProperty); if (hasProperty) return v.asReturnedValue(); } } - ScopedValue n(scope, name.asReturnedValue()); + ScopedValue n(scope, name); return throwReferenceError(n); } -ReturnedValue ExecutionContext::getPropertyAndBase(const StringRef name, ObjectRef base) +ReturnedValue ExecutionContext::getPropertyAndBase(String *name, Object *&base) { Scope scope(this); ScopedValue v(scope); base = (Object *)0; name->makeIdentifier(); - if (name->equals(engine->id_this)) - return callData->thisObject.asReturnedValue(); + if (name->equals(d()->engine->id_this.getPointer())) + return d()->callData->thisObject.asReturnedValue(); bool hasWith = false; bool hasCatchScope = false; - for (ExecutionContext *ctx = this; ctx; ctx = ctx->outer) { - if (ctx->type == Type_WithContext) { - Object *w = static_cast<WithContext *>(ctx)->withObject; + for (ExecutionContext *ctx = this; ctx; ctx = ctx->d()->outer) { + if (ctx->d()->type == Type_WithContext) { + Object *w = static_cast<WithContext *>(ctx)->d()->withObject; hasWith = true; bool hasProperty = false; v = w->get(name, &hasProperty); @@ -429,103 +430,103 @@ ReturnedValue ExecutionContext::getPropertyAndBase(const StringRef name, ObjectR continue; } - else if (ctx->type == Type_CatchContext) { + else if (ctx->d()->type == Type_CatchContext) { hasCatchScope = true; CatchContext *c = static_cast<CatchContext *>(ctx); - if (c->exceptionVarName->isEqualTo(name)) - return c->exceptionValue.asReturnedValue(); + if (c->d()->exceptionVarName->isEqualTo(name)) + return c->d()->exceptionValue.asReturnedValue(); } - else if (ctx->type >= Type_CallContext) { + else if (ctx->d()->type >= Type_CallContext) { QV4::CallContext *c = static_cast<CallContext *>(ctx); - FunctionObject *f = c->function; - if (f->function && (f->needsActivation || hasWith || hasCatchScope)) { - uint index = f->function->internalClass->find(name); + FunctionObject *f = c->d()->function; + if (f->function() && (f->needsActivation() || hasWith || hasCatchScope)) { + uint index = f->function()->internalClass->find(name); if (index < UINT_MAX) { - if (index < c->function->formalParameterCount()) - return c->callData->args[c->function->formalParameterCount() - index - 1].asReturnedValue(); - return c->locals[index - c->function->formalParameterCount()].asReturnedValue(); + if (index < c->d()->function->formalParameterCount()) + return c->d()->callData->args[c->d()->function->formalParameterCount() - index - 1].asReturnedValue(); + return c->d()->locals[index - c->d()->function->formalParameterCount()].asReturnedValue(); } } - if (c->activation) { + if (c->d()->activation) { bool hasProperty = false; - v = c->activation->get(name, &hasProperty); + v = c->d()->activation->get(name, &hasProperty); if (hasProperty) { - if (ctx->type == Type_QmlContext) - base = c->activation; + if (ctx->d()->type == Type_QmlContext) + base = c->d()->activation; return v.asReturnedValue(); } } - if (f->function && f->function->isNamedExpression() - && name->equals(f->function->name())) - return c->function->asReturnedValue(); + if (f->function() && f->function()->isNamedExpression() + && name->equals(f->function()->name())) + return c->d()->function->asReturnedValue(); } - else if (ctx->type == Type_GlobalContext) { + else if (ctx->d()->type == Type_GlobalContext) { GlobalContext *g = static_cast<GlobalContext *>(ctx); bool hasProperty = false; - v = g->global->get(name, &hasProperty); + v = g->d()->global->get(name, &hasProperty); if (hasProperty) return v.asReturnedValue(); } } - ScopedValue n(scope, name.asReturnedValue()); + ScopedValue n(scope, name); return throwReferenceError(n); } ReturnedValue ExecutionContext::throwError(const ValueRef value) { - return engine->throwException(value); + return d()->engine->throwException(value); } ReturnedValue ExecutionContext::throwError(const QString &message) { Scope scope(this); - ScopedValue v(scope, engine->newString(message)); - v = engine->newErrorObject(v); + ScopedValue v(scope, d()->engine->newString(message)); + v = d()->engine->newErrorObject(v); return throwError(v); } ReturnedValue ExecutionContext::throwSyntaxError(const QString &message, const QString &fileName, int line, int column) { Scope scope(this); - Scoped<Object> error(scope, engine->newSyntaxErrorObject(message, fileName, line, column)); + Scoped<Object> error(scope, d()->engine->newSyntaxErrorObject(message, fileName, line, column)); return throwError(error); } ReturnedValue ExecutionContext::throwSyntaxError(const QString &message) { Scope scope(this); - Scoped<Object> error(scope, engine->newSyntaxErrorObject(message)); + Scoped<Object> error(scope, d()->engine->newSyntaxErrorObject(message)); return throwError(error); } ReturnedValue ExecutionContext::throwTypeError() { Scope scope(this); - Scoped<Object> error(scope, engine->newTypeErrorObject(QStringLiteral("Type error"))); + Scoped<Object> error(scope, d()->engine->newTypeErrorObject(QStringLiteral("Type error"))); return throwError(error); } ReturnedValue ExecutionContext::throwTypeError(const QString &message) { Scope scope(this); - Scoped<Object> error(scope, engine->newTypeErrorObject(message)); + Scoped<Object> error(scope, d()->engine->newTypeErrorObject(message)); return throwError(error); } ReturnedValue ExecutionContext::throwUnimplemented(const QString &message) { Scope scope(this); - ScopedValue v(scope, engine->newString(QStringLiteral("Unimplemented ") + message)); - v = engine->newErrorObject(v); + ScopedValue v(scope, d()->engine->newString(QStringLiteral("Unimplemented ") + message)); + v = d()->engine->newErrorObject(v); return throwError(v); } ReturnedValue ExecutionContext::catchException(StackTrace *trace) { - return engine->catchException(this, trace); + return d()->engine->catchException(this, trace); } ReturnedValue ExecutionContext::throwReferenceError(const ValueRef value) @@ -533,7 +534,7 @@ ReturnedValue ExecutionContext::throwReferenceError(const ValueRef value) Scope scope(this); Scoped<String> s(scope, value->toString(this)); QString msg = s->toQString() + QStringLiteral(" is not defined"); - Scoped<Object> error(scope, engine->newReferenceErrorObject(msg)); + Scoped<Object> error(scope, d()->engine->newReferenceErrorObject(msg)); return throwError(error); } @@ -541,7 +542,7 @@ ReturnedValue ExecutionContext::throwReferenceError(const QString &message, cons { Scope scope(this); QString msg = message; - Scoped<Object> error(scope, engine->newReferenceErrorObject(msg, fileName, line, column)); + Scoped<Object> error(scope, d()->engine->newReferenceErrorObject(msg, fileName, line, column)); return throwError(error); } @@ -550,20 +551,20 @@ ReturnedValue ExecutionContext::throwRangeError(const ValueRef value) Scope scope(this); ScopedString s(scope, value->toString(this)); QString msg = s->toQString() + QStringLiteral(" out of range"); - ScopedObject error(scope, engine->newRangeErrorObject(msg)); + ScopedObject error(scope, d()->engine->newRangeErrorObject(msg)); return throwError(error); } ReturnedValue ExecutionContext::throwRangeError(const QString &message) { Scope scope(this); - ScopedObject error(scope, engine->newRangeErrorObject(message)); + ScopedObject error(scope, d()->engine->newRangeErrorObject(message)); return throwError(error); } ReturnedValue ExecutionContext::throwURIError(const ValueRef msg) { Scope scope(this); - ScopedObject error(scope, engine->newURIErrorObject(msg)); + ScopedObject error(scope, d()->engine->newURIErrorObject(msg)); return throwError(error); } diff --git a/src/qml/jsruntime/qv4context_p.h b/src/qml/jsruntime/qv4context_p.h index a07cbf2da5..7e67028364 100644 --- a/src/qml/jsruntime/qv4context_p.h +++ b/src/qml/jsruntime/qv4context_p.h @@ -69,8 +69,6 @@ struct WithContext; struct Q_QML_EXPORT ExecutionContext : public Managed { - V4_MANAGED - Q_MANAGED_TYPE(ExecutionContext) enum { IsExecutionContext = true }; @@ -83,48 +81,66 @@ struct Q_QML_EXPORT ExecutionContext : public Managed Type_CallContext = 0x5, Type_QmlContext = 0x6 }; - - ExecutionContext(ExecutionEngine *engine, ContextType t) - : Managed(engine->executionContextClass) - { - this->type = t; - strictMode = false; - this->engine = engine; - this->parent = engine->currentContext(); - outer = 0; - lookups = 0; - compilationUnit = 0; - currentEvalCode = 0; - lineNumber = -1; - engine->current = this; - } - - ContextType type; - bool strictMode; - - CallData *callData; - - ExecutionEngine *engine; - ExecutionContext *parent; - ExecutionContext *outer; - Lookup *lookups; - CompiledData::CompilationUnit *compilationUnit; - struct EvalCode { Function *function; EvalCode *next; }; - EvalCode *currentEvalCode; - int lineNumber; + struct Data : Managed::Data { + Data(ExecutionEngine *engine, ContextType t) + : Managed::Data(engine->executionContextClass) + , type(t) + , strictMode(false) + , engine(engine) + , parent(engine->currentContext()) + , outer(0) + , lookups(0) + , compilationUnit(0) + , currentEvalCode(0) + , lineNumber(-1) + { + engine->current = reinterpret_cast<ExecutionContext *>(this); + } + ContextType type; + bool strictMode; + + CallData *callData; + + ExecutionEngine *engine; + ExecutionContext *parent; + ExecutionContext *outer; + Lookup *lookups; + CompiledData::CompilationUnit *compilationUnit; + EvalCode *currentEvalCode; + + int lineNumber; - CallContext *newCallContext(FunctionObject *f, CallData *callData); - WithContext *newWithContext(ObjectRef with); - CatchContext *newCatchContext(const StringRef exceptionVarName, const ValueRef exceptionValue); - CallContext *newQmlContext(FunctionObject *f, ObjectRef qml); + }; + V4_MANAGED(Managed) + Q_MANAGED_TYPE(ExecutionContext) - void createMutableBinding(const StringRef name, bool deletable); + ExecutionContext(ExecutionEngine *engine, ContextType t) + : Managed(engine->executionContextClass) + { + d()->type = t; + d()->strictMode = false; + d()->engine = engine; + d()->parent = engine->currentContext(); + d()->outer = 0; + d()->lookups = 0; + d()->compilationUnit = 0; + d()->currentEvalCode = 0; + d()->lineNumber = -1; + engine->current = this; + } + + HeapObject *newCallContext(FunctionObject *f, CallData *callData); + WithContext *newWithContext(Object *with); + CatchContext *newCatchContext(String *exceptionVarName, const ValueRef exceptionValue); + CallContext *newQmlContext(FunctionObject *f, Object *qml); + + void createMutableBinding(String *name, bool deletable); ReturnedValue throwError(const QV4::ValueRef value); ReturnedValue throwError(const QString &message); @@ -139,10 +155,10 @@ struct Q_QML_EXPORT ExecutionContext : public Managed ReturnedValue throwURIError(const ValueRef msg); ReturnedValue throwUnimplemented(const QString &message); - void setProperty(const StringRef name, const ValueRef value); - ReturnedValue getProperty(const StringRef name); - ReturnedValue getPropertyAndBase(const StringRef name, ObjectRef base); - bool deleteProperty(const StringRef name); + void setProperty(String *name, const ValueRef value); + ReturnedValue getProperty(String *name); + ReturnedValue getPropertyAndBase(String *name, Object *&base); + bool deleteProperty(String *name); // Can only be called from within catch(...), rethrows if no JS exception. ReturnedValue catchException(StackTrace *trace = 0); @@ -155,19 +171,22 @@ struct Q_QML_EXPORT ExecutionContext : public Managed struct CallContext : public ExecutionContext { - CallContext(ExecutionEngine *engine, ContextType t = Type_SimpleCallContext) - : ExecutionContext(engine, t) - { - function = 0; - locals = 0; - activation = 0; - } - CallContext(ExecutionEngine *engine, ObjectRef qml, QV4::FunctionObject *function); - - FunctionObject *function; - int realArgumentCount; - Value *locals; - Object *activation; + struct Data : ExecutionContext::Data { + Data(ExecutionEngine *engine, ContextType t = Type_SimpleCallContext) + : ExecutionContext::Data(engine, t) + { + function = 0; + locals = 0; + activation = 0; + } + Data(ExecutionEngine *engine, Object *qml, QV4::FunctionObject *function); + + FunctionObject *function; + int realArgumentCount; + Value *locals; + Object *activation; + }; + V4_MANAGED(ExecutionContext) // formals are in reverse order String * const *formals() const; @@ -180,52 +199,60 @@ struct CallContext : public ExecutionContext }; inline ReturnedValue CallContext::argument(int i) { - return i < callData->argc ? callData->args[i].asReturnedValue() : Primitive::undefinedValue().asReturnedValue(); + return i < d()->callData->argc ? d()->callData->args[i].asReturnedValue() : Primitive::undefinedValue().asReturnedValue(); } struct GlobalContext : public ExecutionContext { - GlobalContext(ExecutionEngine *engine); + struct Data : ExecutionContext::Data { + Data(ExecutionEngine *engine); + Object *global; + }; + V4_MANAGED(ExecutionContext) - Object *global; }; struct CatchContext : public ExecutionContext { - CatchContext(ExecutionEngine *engine, const StringRef exceptionVarName, const ValueRef exceptionValue); - - StringValue exceptionVarName; - Value exceptionValue; + struct Data : ExecutionContext::Data { + Data(ExecutionEngine *engine, String *exceptionVarName, const ValueRef exceptionValue); + StringValue exceptionVarName; + Value exceptionValue; + }; + V4_MANAGED(ExecutionContext) }; struct WithContext : public ExecutionContext { - WithContext(ExecutionEngine *engine, ObjectRef with); - Object *withObject; + struct Data : ExecutionContext::Data { + Data(ExecutionEngine *engine, Object *with); + Object *withObject; + }; + V4_MANAGED(ExecutionContext) }; inline CallContext *ExecutionContext::asCallContext() { - return type >= Type_SimpleCallContext ? static_cast<CallContext *>(this) : 0; + return d()->type >= Type_SimpleCallContext ? static_cast<CallContext *>(this) : 0; } inline const CallContext *ExecutionContext::asCallContext() const { - return type >= Type_SimpleCallContext ? static_cast<const CallContext *>(this) : 0; + return d()->type >= Type_SimpleCallContext ? static_cast<const CallContext *>(this) : 0; } inline void ExecutionEngine::pushContext(CallContext *context) { - context->parent = current; + context->d()->parent = current; current = context; - current->currentEvalCode = 0; + current->d()->currentEvalCode = 0; } inline ExecutionContext *ExecutionEngine::popContext() { - Q_ASSERT(current->parent); - current = current->parent; + Q_ASSERT(current->d()->parent); + current = current->d()->parent; return current; } @@ -235,7 +262,7 @@ struct ExecutionContextSaver ExecutionContext *savedContext; ExecutionContextSaver(ExecutionContext *context) - : engine(context->engine) + : engine(context->d()->engine) , savedContext(context) { } @@ -246,7 +273,7 @@ struct ExecutionContextSaver }; inline Scope::Scope(ExecutionContext *ctx) - : engine(ctx->engine) + : engine(ctx->d()->engine) #ifndef QT_NO_DEBUG , size(0) #endif @@ -256,7 +283,7 @@ inline Scope::Scope(ExecutionContext *ctx) /* Function *f, int argc */ #define requiredMemoryForExecutionContect(f, argc) \ - ((sizeof(CallContext) + 7) & ~7) + sizeof(Value) * (f->varCount() + qMax((uint)argc, f->formalParameterCount())) + sizeof(CallData) + ((sizeof(CallContext::Data) + 7) & ~7) + sizeof(Value) * (f->varCount() + qMax((uint)argc, f->formalParameterCount())) + sizeof(CallData) } // namespace QV4 diff --git a/src/qml/jsruntime/qv4dateobject.cpp b/src/qml/jsruntime/qv4dateobject.cpp index ceef88455b..b7fac9432f 100644 --- a/src/qml/jsruntime/qv4dateobject.cpp +++ b/src/qml/jsruntime/qv4dateobject.cpp @@ -643,8 +643,8 @@ static double getLocalTZA() DEFINE_OBJECT_VTABLE(DateObject); -DateObject::DateObject(ExecutionEngine *engine, const QDateTime &date) - : Object(engine->dateClass) +DateObject::Data::Data(ExecutionEngine *engine, const QDateTime &date) + : Object::Data(engine->dateClass) { setVTable(staticVTable()); value.setDouble(date.isValid() ? date.toMSecsSinceEpoch() : qSNaN()); @@ -652,13 +652,13 @@ DateObject::DateObject(ExecutionEngine *engine, const QDateTime &date) QDateTime DateObject::toQDateTime() const { - return ToDateTime(value.asDouble(), Qt::LocalTime); + return ToDateTime(date().asDouble(), Qt::LocalTime); } DEFINE_OBJECT_VTABLE(DateCtor); -DateCtor::DateCtor(ExecutionContext *scope) - : FunctionObject(scope, QStringLiteral("Date")) +DateCtor::Data::Data(ExecutionContext *scope) + : FunctionObject::Data(scope, QStringLiteral("Date")) { setVTable(staticVTable()); } @@ -674,7 +674,7 @@ ReturnedValue DateCtor::construct(Managed *m, CallData *callData) Scope scope(m->engine()); ScopedValue arg(scope, callData->args[0]); if (DateObject *d = arg->asDateObject()) - arg = d->value; + arg = d->date(); else arg = RuntimeHelpers::toPrimitive(arg, PREFERREDTYPE_HINT); @@ -707,7 +707,7 @@ ReturnedValue DateCtor::call(Managed *m, CallData *) return m->engine()->newString(ToString(t))->asReturnedValue(); } -void DatePrototype::init(ExecutionEngine *engine, ObjectRef ctor) +void DatePrototype::init(ExecutionEngine *engine, Object *ctor) { Scope scope(engine); ScopedObject o(scope); @@ -770,8 +770,8 @@ void DatePrototype::init(ExecutionEngine *engine, ObjectRef ctor) double DatePrototype::getThisDate(ExecutionContext *ctx) { - if (DateObject *thisObject = ctx->callData->thisObject.asDateObject()) - return thisObject->value.asDouble(); + if (DateObject *thisObject = ctx->d()->callData->thisObject.asDateObject()) + return thisObject->date().asDouble(); else { ctx->throwTypeError(); return 0; @@ -780,22 +780,22 @@ double DatePrototype::getThisDate(ExecutionContext *ctx) ReturnedValue DatePrototype::method_parse(CallContext *ctx) { - if (!ctx->callData->argc) + if (!ctx->d()->callData->argc) return Encode(qSNaN()); - return Encode(ParseString(ctx->callData->args[0].toString(ctx)->toQString())); + return Encode(ParseString(ctx->d()->callData->args[0].toString(ctx)->toQString())); } ReturnedValue DatePrototype::method_UTC(CallContext *ctx) { - const int numArgs = ctx->callData->argc; + const int numArgs = ctx->d()->callData->argc; if (numArgs >= 2) { - double year = ctx->callData->args[0].toNumber(); - double month = ctx->callData->args[1].toNumber(); - double day = numArgs >= 3 ? ctx->callData->args[2].toNumber() : 1; - double hours = numArgs >= 4 ? ctx->callData->args[3].toNumber() : 0; - double mins = numArgs >= 5 ? ctx->callData->args[4].toNumber() : 0; - double secs = numArgs >= 6 ? ctx->callData->args[5].toNumber() : 0; - double ms = numArgs >= 7 ? ctx->callData->args[6].toNumber() : 0; + double year = ctx->d()->callData->args[0].toNumber(); + double month = ctx->d()->callData->args[1].toNumber(); + double day = numArgs >= 3 ? ctx->d()->callData->args[2].toNumber() : 1; + double hours = numArgs >= 4 ? ctx->d()->callData->args[3].toNumber() : 0; + double mins = numArgs >= 5 ? ctx->d()->callData->args[4].toNumber() : 0; + double secs = numArgs >= 6 ? ctx->d()->callData->args[5].toNumber() : 0; + double ms = numArgs >= 7 ? ctx->d()->callData->args[6].toNumber() : 0; if (year >= 0 && year <= 99) year += 1900; double t = MakeDate(MakeDay(year, month, day), @@ -815,37 +815,37 @@ ReturnedValue DatePrototype::method_now(CallContext *ctx) ReturnedValue DatePrototype::method_toString(CallContext *ctx) { double t = getThisDate(ctx); - return ctx->engine->newString(ToString(t))->asReturnedValue(); + return ctx->d()->engine->newString(ToString(t))->asReturnedValue(); } ReturnedValue DatePrototype::method_toDateString(CallContext *ctx) { double t = getThisDate(ctx); - return ctx->engine->newString(ToDateString(t))->asReturnedValue(); + return ctx->d()->engine->newString(ToDateString(t))->asReturnedValue(); } ReturnedValue DatePrototype::method_toTimeString(CallContext *ctx) { double t = getThisDate(ctx); - return ctx->engine->newString(ToTimeString(t))->asReturnedValue(); + return ctx->d()->engine->newString(ToTimeString(t))->asReturnedValue(); } ReturnedValue DatePrototype::method_toLocaleString(CallContext *ctx) { double t = getThisDate(ctx); - return ctx->engine->newString(ToLocaleString(t))->asReturnedValue(); + return ctx->d()->engine->newString(ToLocaleString(t))->asReturnedValue(); } ReturnedValue DatePrototype::method_toLocaleDateString(CallContext *ctx) { double t = getThisDate(ctx); - return ctx->engine->newString(ToLocaleDateString(t))->asReturnedValue(); + return ctx->d()->engine->newString(ToLocaleDateString(t))->asReturnedValue(); } ReturnedValue DatePrototype::method_toLocaleTimeString(CallContext *ctx) { double t = getThisDate(ctx); - return ctx->engine->newString(ToLocaleTimeString(t))->asReturnedValue(); + return ctx->d()->engine->newString(ToLocaleTimeString(t))->asReturnedValue(); } ReturnedValue DatePrototype::method_valueOf(CallContext *ctx) @@ -1007,196 +1007,196 @@ ReturnedValue DatePrototype::method_getTimezoneOffset(CallContext *ctx) ReturnedValue DatePrototype::method_setTime(CallContext *ctx) { Scope scope(ctx); - Scoped<DateObject> self(scope, ctx->callData->thisObject); + Scoped<DateObject> self(scope, ctx->d()->callData->thisObject); if (!self) return ctx->throwTypeError(); - double t = ctx->callData->argc ? ctx->callData->args[0].toNumber() : qSNaN(); - self->value.setDouble(TimeClip(t)); - return self->value.asReturnedValue(); + double t = ctx->d()->callData->argc ? ctx->d()->callData->args[0].toNumber() : qSNaN(); + self->date().setDouble(TimeClip(t)); + return self->date().asReturnedValue(); } ReturnedValue DatePrototype::method_setMilliseconds(CallContext *ctx) { Scope scope(ctx); - Scoped<DateObject> self(scope, ctx->callData->thisObject); + Scoped<DateObject> self(scope, ctx->d()->callData->thisObject); if (!self) return ctx->throwTypeError(); - double t = LocalTime(self->value.asDouble()); - double ms = ctx->callData->argc ? ctx->callData->args[0].toNumber() : qSNaN(); - self->value.setDouble(TimeClip(UTC(MakeDate(Day(t), MakeTime(HourFromTime(t), MinFromTime(t), SecFromTime(t), ms))))); - return self->value.asReturnedValue(); + double t = LocalTime(self->date().asDouble()); + double ms = ctx->d()->callData->argc ? ctx->d()->callData->args[0].toNumber() : qSNaN(); + self->date().setDouble(TimeClip(UTC(MakeDate(Day(t), MakeTime(HourFromTime(t), MinFromTime(t), SecFromTime(t), ms))))); + return self->date().asReturnedValue(); } ReturnedValue DatePrototype::method_setUTCMilliseconds(CallContext *ctx) { - DateObject *self = ctx->callData->thisObject.asDateObject(); + DateObject *self = ctx->d()->callData->thisObject.asDateObject(); if (!self) return ctx->throwTypeError(); - double t = self->value.asDouble(); - double ms = ctx->callData->argc ? ctx->callData->args[0].toNumber() : qSNaN(); - self->value.setDouble(TimeClip(UTC(MakeDate(Day(t), MakeTime(HourFromTime(t), MinFromTime(t), SecFromTime(t), ms))))); - return self->value.asReturnedValue(); + double t = self->date().asDouble(); + double ms = ctx->d()->callData->argc ? ctx->d()->callData->args[0].toNumber() : qSNaN(); + self->date().setDouble(TimeClip(UTC(MakeDate(Day(t), MakeTime(HourFromTime(t), MinFromTime(t), SecFromTime(t), ms))))); + return self->date().asReturnedValue(); } ReturnedValue DatePrototype::method_setSeconds(CallContext *ctx) { - DateObject *self = ctx->callData->thisObject.asDateObject(); + DateObject *self = ctx->d()->callData->thisObject.asDateObject(); if (!self) return ctx->throwTypeError(); - double t = LocalTime(self->value.asDouble()); - double sec = ctx->callData->argc ? ctx->callData->args[0].toNumber() : qSNaN(); - double ms = (ctx->callData->argc < 2) ? msFromTime(t) : ctx->callData->args[1].toNumber(); + double t = LocalTime(self->date().asDouble()); + double sec = ctx->d()->callData->argc ? ctx->d()->callData->args[0].toNumber() : qSNaN(); + double ms = (ctx->d()->callData->argc < 2) ? msFromTime(t) : ctx->d()->callData->args[1].toNumber(); t = TimeClip(UTC(MakeDate(Day(t), MakeTime(HourFromTime(t), MinFromTime(t), sec, ms)))); - self->value.setDouble(t); - return self->value.asReturnedValue(); + self->date().setDouble(t); + return self->date().asReturnedValue(); } ReturnedValue DatePrototype::method_setUTCSeconds(CallContext *ctx) { - DateObject *self = ctx->callData->thisObject.asDateObject(); + DateObject *self = ctx->d()->callData->thisObject.asDateObject(); if (!self) return ctx->throwTypeError(); - double t = self->value.asDouble(); - double sec = ctx->callData->argc ? ctx->callData->args[0].toNumber() : qSNaN(); - double ms = (ctx->callData->argc < 2) ? msFromTime(t) : ctx->callData->args[1].toNumber(); + double t = self->date().asDouble(); + double sec = ctx->d()->callData->argc ? ctx->d()->callData->args[0].toNumber() : qSNaN(); + double ms = (ctx->d()->callData->argc < 2) ? msFromTime(t) : ctx->d()->callData->args[1].toNumber(); t = TimeClip(UTC(MakeDate(Day(t), MakeTime(HourFromTime(t), MinFromTime(t), sec, ms)))); - self->value.setDouble(t); - return self->value.asReturnedValue(); + self->date().setDouble(t); + return self->date().asReturnedValue(); } ReturnedValue DatePrototype::method_setMinutes(CallContext *ctx) { - DateObject *self = ctx->callData->thisObject.asDateObject(); + DateObject *self = ctx->d()->callData->thisObject.asDateObject(); if (!self) return ctx->throwTypeError(); - double t = LocalTime(self->value.asDouble()); - double min = ctx->callData->argc ? ctx->callData->args[0].toNumber() : qSNaN(); - double sec = (ctx->callData->argc < 2) ? SecFromTime(t) : ctx->callData->args[1].toNumber(); - double ms = (ctx->callData->argc < 3) ? msFromTime(t) : ctx->callData->args[2].toNumber(); + double t = LocalTime(self->date().asDouble()); + double min = ctx->d()->callData->argc ? ctx->d()->callData->args[0].toNumber() : qSNaN(); + double sec = (ctx->d()->callData->argc < 2) ? SecFromTime(t) : ctx->d()->callData->args[1].toNumber(); + double ms = (ctx->d()->callData->argc < 3) ? msFromTime(t) : ctx->d()->callData->args[2].toNumber(); t = TimeClip(UTC(MakeDate(Day(t), MakeTime(HourFromTime(t), min, sec, ms)))); - self->value.setDouble(t); - return self->value.asReturnedValue(); + self->date().setDouble(t); + return self->date().asReturnedValue(); } ReturnedValue DatePrototype::method_setUTCMinutes(CallContext *ctx) { - DateObject *self = ctx->callData->thisObject.asDateObject(); + DateObject *self = ctx->d()->callData->thisObject.asDateObject(); if (!self) return ctx->throwTypeError(); - double t = self->value.asDouble(); - double min = ctx->callData->argc ? ctx->callData->args[0].toNumber() : qSNaN(); - double sec = (ctx->callData->argc < 2) ? SecFromTime(t) : ctx->callData->args[1].toNumber(); - double ms = (ctx->callData->argc < 3) ? msFromTime(t) : ctx->callData->args[2].toNumber(); + double t = self->date().asDouble(); + double min = ctx->d()->callData->argc ? ctx->d()->callData->args[0].toNumber() : qSNaN(); + double sec = (ctx->d()->callData->argc < 2) ? SecFromTime(t) : ctx->d()->callData->args[1].toNumber(); + double ms = (ctx->d()->callData->argc < 3) ? msFromTime(t) : ctx->d()->callData->args[2].toNumber(); t = TimeClip(UTC(MakeDate(Day(t), MakeTime(HourFromTime(t), min, sec, ms)))); - self->value.setDouble(t); - return self->value.asReturnedValue(); + self->date().setDouble(t); + return self->date().asReturnedValue(); } ReturnedValue DatePrototype::method_setHours(CallContext *ctx) { - DateObject *self = ctx->callData->thisObject.asDateObject(); + DateObject *self = ctx->d()->callData->thisObject.asDateObject(); if (!self) return ctx->throwTypeError(); - double t = LocalTime(self->value.asDouble()); - double hour = ctx->callData->argc ? ctx->callData->args[0].toNumber() : qSNaN(); - double min = (ctx->callData->argc < 2) ? MinFromTime(t) : ctx->callData->args[1].toNumber(); - double sec = (ctx->callData->argc < 3) ? SecFromTime(t) : ctx->callData->args[2].toNumber(); - double ms = (ctx->callData->argc < 4) ? msFromTime(t) : ctx->callData->args[3].toNumber(); + double t = LocalTime(self->date().asDouble()); + double hour = ctx->d()->callData->argc ? ctx->d()->callData->args[0].toNumber() : qSNaN(); + double min = (ctx->d()->callData->argc < 2) ? MinFromTime(t) : ctx->d()->callData->args[1].toNumber(); + double sec = (ctx->d()->callData->argc < 3) ? SecFromTime(t) : ctx->d()->callData->args[2].toNumber(); + double ms = (ctx->d()->callData->argc < 4) ? msFromTime(t) : ctx->d()->callData->args[3].toNumber(); t = TimeClip(UTC(MakeDate(Day(t), MakeTime(hour, min, sec, ms)))); - self->value.setDouble(t); - return self->value.asReturnedValue(); + self->date().setDouble(t); + return self->date().asReturnedValue(); } ReturnedValue DatePrototype::method_setUTCHours(CallContext *ctx) { - DateObject *self = ctx->callData->thisObject.asDateObject(); + DateObject *self = ctx->d()->callData->thisObject.asDateObject(); if (!self) return ctx->throwTypeError(); - double t = self->value.asDouble(); - double hour = ctx->callData->argc ? ctx->callData->args[0].toNumber() : qSNaN(); - double min = (ctx->callData->argc < 2) ? MinFromTime(t) : ctx->callData->args[1].toNumber(); - double sec = (ctx->callData->argc < 3) ? SecFromTime(t) : ctx->callData->args[2].toNumber(); - double ms = (ctx->callData->argc < 4) ? msFromTime(t) : ctx->callData->args[3].toNumber(); + double t = self->date().asDouble(); + double hour = ctx->d()->callData->argc ? ctx->d()->callData->args[0].toNumber() : qSNaN(); + double min = (ctx->d()->callData->argc < 2) ? MinFromTime(t) : ctx->d()->callData->args[1].toNumber(); + double sec = (ctx->d()->callData->argc < 3) ? SecFromTime(t) : ctx->d()->callData->args[2].toNumber(); + double ms = (ctx->d()->callData->argc < 4) ? msFromTime(t) : ctx->d()->callData->args[3].toNumber(); t = TimeClip(UTC(MakeDate(Day(t), MakeTime(hour, min, sec, ms)))); - self->value.setDouble(t); - return self->value.asReturnedValue(); + self->date().setDouble(t); + return self->date().asReturnedValue(); } ReturnedValue DatePrototype::method_setDate(CallContext *ctx) { - DateObject *self = ctx->callData->thisObject.asDateObject(); + DateObject *self = ctx->d()->callData->thisObject.asDateObject(); if (!self) return ctx->throwTypeError(); - double t = LocalTime(self->value.asDouble()); - double date = ctx->callData->argc ? ctx->callData->args[0].toNumber() : qSNaN(); + double t = LocalTime(self->date().asDouble()); + double date = ctx->d()->callData->argc ? ctx->d()->callData->args[0].toNumber() : qSNaN(); t = TimeClip(UTC(MakeDate(MakeDay(YearFromTime(t), MonthFromTime(t), date), TimeWithinDay(t)))); - self->value.setDouble(t); - return self->value.asReturnedValue(); + self->date().setDouble(t); + return self->date().asReturnedValue(); } ReturnedValue DatePrototype::method_setUTCDate(CallContext *ctx) { - DateObject *self = ctx->callData->thisObject.asDateObject(); + DateObject *self = ctx->d()->callData->thisObject.asDateObject(); if (!self) return ctx->throwTypeError(); - double t = self->value.asDouble(); - double date = ctx->callData->argc ? ctx->callData->args[0].toNumber() : qSNaN(); + double t = self->date().asDouble(); + double date = ctx->d()->callData->argc ? ctx->d()->callData->args[0].toNumber() : qSNaN(); t = TimeClip(UTC(MakeDate(MakeDay(YearFromTime(t), MonthFromTime(t), date), TimeWithinDay(t)))); - self->value.setDouble(t); - return self->value.asReturnedValue(); + self->date().setDouble(t); + return self->date().asReturnedValue(); } ReturnedValue DatePrototype::method_setMonth(CallContext *ctx) { - DateObject *self = ctx->callData->thisObject.asDateObject(); + DateObject *self = ctx->d()->callData->thisObject.asDateObject(); if (!self) return ctx->throwTypeError(); - double t = LocalTime(self->value.asDouble()); - double month = ctx->callData->argc ? ctx->callData->args[0].toNumber() : qSNaN(); - double date = (ctx->callData->argc < 2) ? DateFromTime(t) : ctx->callData->args[1].toNumber(); + double t = LocalTime(self->date().asDouble()); + double month = ctx->d()->callData->argc ? ctx->d()->callData->args[0].toNumber() : qSNaN(); + double date = (ctx->d()->callData->argc < 2) ? DateFromTime(t) : ctx->d()->callData->args[1].toNumber(); t = TimeClip(UTC(MakeDate(MakeDay(YearFromTime(t), month, date), TimeWithinDay(t)))); - self->value.setDouble(t); - return self->value.asReturnedValue(); + self->date().setDouble(t); + return self->date().asReturnedValue(); } ReturnedValue DatePrototype::method_setUTCMonth(CallContext *ctx) { - DateObject *self = ctx->callData->thisObject.asDateObject(); + DateObject *self = ctx->d()->callData->thisObject.asDateObject(); if (!self) return ctx->throwTypeError(); - double t = self->value.asDouble(); - double month = ctx->callData->argc ? ctx->callData->args[0].toNumber() : qSNaN(); - double date = (ctx->callData->argc < 2) ? DateFromTime(t) : ctx->callData->args[1].toNumber(); + double t = self->date().asDouble(); + double month = ctx->d()->callData->argc ? ctx->d()->callData->args[0].toNumber() : qSNaN(); + double date = (ctx->d()->callData->argc < 2) ? DateFromTime(t) : ctx->d()->callData->args[1].toNumber(); t = TimeClip(UTC(MakeDate(MakeDay(YearFromTime(t), month, date), TimeWithinDay(t)))); - self->value.setDouble(t); - return self->value.asReturnedValue(); + self->date().setDouble(t); + return self->date().asReturnedValue(); } ReturnedValue DatePrototype::method_setYear(CallContext *ctx) { - DateObject *self = ctx->callData->thisObject.asDateObject(); + DateObject *self = ctx->d()->callData->thisObject.asDateObject(); if (!self) return ctx->throwTypeError(); - double t = self->value.asDouble(); + double t = self->date().asDouble(); if (std::isnan(t)) t = 0; else t = LocalTime(t); - double year = ctx->callData->argc ? ctx->callData->args[0].toNumber() : qSNaN(); + double year = ctx->d()->callData->argc ? ctx->d()->callData->args[0].toNumber() : qSNaN(); double r; if (std::isnan(year)) { r = qSNaN(); @@ -1207,50 +1207,50 @@ ReturnedValue DatePrototype::method_setYear(CallContext *ctx) r = UTC(MakeDate(r, TimeWithinDay(t))); r = TimeClip(r); } - self->value.setDouble(r); - return self->value.asReturnedValue(); + self->date().setDouble(r); + return self->date().asReturnedValue(); } ReturnedValue DatePrototype::method_setUTCFullYear(CallContext *ctx) { - DateObject *self = ctx->callData->thisObject.asDateObject(); + DateObject *self = ctx->d()->callData->thisObject.asDateObject(); if (!self) return ctx->throwTypeError(); - double t = self->value.asDouble(); - double year = ctx->callData->argc ? ctx->callData->args[0].toNumber() : qSNaN(); - double month = (ctx->callData->argc < 2) ? MonthFromTime(t) : ctx->callData->args[1].toNumber(); - double date = (ctx->callData->argc < 3) ? DateFromTime(t) : ctx->callData->args[2].toNumber(); + double t = self->date().asDouble(); + double year = ctx->d()->callData->argc ? ctx->d()->callData->args[0].toNumber() : qSNaN(); + double month = (ctx->d()->callData->argc < 2) ? MonthFromTime(t) : ctx->d()->callData->args[1].toNumber(); + double date = (ctx->d()->callData->argc < 3) ? DateFromTime(t) : ctx->d()->callData->args[2].toNumber(); t = TimeClip(UTC(MakeDate(MakeDay(year, month, date), TimeWithinDay(t)))); - self->value.setDouble(t); - return self->value.asReturnedValue(); + self->date().setDouble(t); + return self->date().asReturnedValue(); } ReturnedValue DatePrototype::method_setFullYear(CallContext *ctx) { - DateObject *self = ctx->callData->thisObject.asDateObject(); + DateObject *self = ctx->d()->callData->thisObject.asDateObject(); if (!self) return ctx->throwTypeError(); - double t = LocalTime(self->value.asDouble()); + double t = LocalTime(self->date().asDouble()); if (std::isnan(t)) t = 0; - double year = ctx->callData->argc ? ctx->callData->args[0].toNumber() : qSNaN(); - double month = (ctx->callData->argc < 2) ? MonthFromTime(t) : ctx->callData->args[1].toNumber(); - double date = (ctx->callData->argc < 3) ? DateFromTime(t) : ctx->callData->args[2].toNumber(); + double year = ctx->d()->callData->argc ? ctx->d()->callData->args[0].toNumber() : qSNaN(); + double month = (ctx->d()->callData->argc < 2) ? MonthFromTime(t) : ctx->d()->callData->args[1].toNumber(); + double date = (ctx->d()->callData->argc < 3) ? DateFromTime(t) : ctx->d()->callData->args[2].toNumber(); t = TimeClip(UTC(MakeDate(MakeDay(year, month, date), TimeWithinDay(t)))); - self->value.setDouble(t); - return self->value.asReturnedValue(); + self->date().setDouble(t); + return self->date().asReturnedValue(); } ReturnedValue DatePrototype::method_toUTCString(CallContext *ctx) { - DateObject *self = ctx->callData->thisObject.asDateObject(); + DateObject *self = ctx->d()->callData->thisObject.asDateObject(); if (!self) return ctx->throwTypeError(); - double t = self->value.asDouble(); - return ctx->engine->newString(ToUTCString(t))->asReturnedValue(); + double t = self->date().asDouble(); + return ctx->d()->engine->newString(ToUTCString(t))->asReturnedValue(); } static void addZeroPrefixedInt(QString &str, int num, int nDigits) @@ -1268,19 +1268,19 @@ static void addZeroPrefixedInt(QString &str, int num, int nDigits) ReturnedValue DatePrototype::method_toISOString(CallContext *ctx) { - DateObject *self = ctx->callData->thisObject.asDateObject(); + DateObject *self = ctx->d()->callData->thisObject.asDateObject(); if (!self) return ctx->throwTypeError(); - double t = self->value.asDouble(); + double t = self->date().asDouble(); if (!std::isfinite(t)) - return ctx->throwRangeError(ctx->callData->thisObject); + return ctx->throwRangeError(ctx->d()->callData->thisObject); QString result; int year = (int)YearFromTime(t); if (year < 0 || year > 9999) { if (qAbs(year) >= 1000000) - return ctx->engine->newString(QStringLiteral("Invalid Date"))->asReturnedValue(); + return ctx->d()->engine->newString(QStringLiteral("Invalid Date"))->asReturnedValue(); result += year < 0 ? QLatin1Char('-') : QLatin1Char('+'); year = qAbs(year); addZeroPrefixedInt(result, year, 6); @@ -1301,27 +1301,27 @@ ReturnedValue DatePrototype::method_toISOString(CallContext *ctx) addZeroPrefixedInt(result, msFromTime(t), 3); result += QLatin1Char('Z'); - return ctx->engine->newString(result)->asReturnedValue(); + return ctx->d()->engine->newString(result)->asReturnedValue(); } ReturnedValue DatePrototype::method_toJSON(CallContext *ctx) { Scope scope(ctx); - ScopedValue O(scope, RuntimeHelpers::toObject(ctx, ValueRef(&ctx->callData->thisObject))); + ScopedValue O(scope, RuntimeHelpers::toObject(ctx, ValueRef(&ctx->d()->callData->thisObject))); ScopedValue tv(scope, RuntimeHelpers::toPrimitive(O, NUMBER_HINT)); if (tv->isNumber() && !std::isfinite(tv->toNumber())) return Encode::null(); - ScopedString s(scope, ctx->engine->newString(QStringLiteral("toISOString"))); - ScopedValue v(scope, O->objectValue()->get(s)); + ScopedString s(scope, ctx->d()->engine->newString(QStringLiteral("toISOString"))); + ScopedValue v(scope, O->objectValue()->get(s.getPointer())); FunctionObject *toIso = v->asFunctionObject(); if (!toIso) return ctx->throwTypeError(); ScopedCallData callData(scope, 0); - callData->thisObject = ctx->callData->thisObject; + callData->thisObject = ctx->d()->callData->thisObject; return toIso->call(callData); } diff --git a/src/qml/jsruntime/qv4dateobject_p.h b/src/qml/jsruntime/qv4dateobject_p.h index c52e8c3ee1..6df4da45c9 100644 --- a/src/qml/jsruntime/qv4dateobject_p.h +++ b/src/qml/jsruntime/qv4dateobject_p.h @@ -52,27 +52,38 @@ class QDateTime; namespace QV4 { struct DateObject: Object { - V4_OBJECT + struct Data : Object::Data { + Data(ExecutionEngine *engine, const ValueRef date) + : Object::Data(engine->dateClass) + { + value = date; + } + Data(ExecutionEngine *engine, const QDateTime &date); + Data(InternalClass *ic) + : Object::Data(ic) + { + Q_ASSERT(internalClass->vtable == staticVTable()); + value = Primitive::fromDouble(qSNaN()); + } + Value value; + }; + V4_OBJECT(Object) Q_MANAGED_TYPE(DateObject) - Value value; - DateObject(ExecutionEngine *engine, const ValueRef date): Object(engine->dateClass) { - value = date; - } - DateObject(ExecutionEngine *engine, const QDateTime &value); - QDateTime toQDateTime() const; -protected: - DateObject(InternalClass *ic): Object(ic) { - Q_ASSERT(internalClass->vtable == staticVTable()); - value = Primitive::fromDouble(qSNaN()); - } + Value date() const { return d()->value; } + Value &date() { return d()->value; } + void setDate(const ValueRef date) { d()->value = date; } + + QDateTime toQDateTime() const; }; struct DateCtor: FunctionObject { - V4_OBJECT - DateCtor(ExecutionContext *scope); + struct Data : FunctionObject::Data { + Data(ExecutionContext *scope); + }; + V4_OBJECT(FunctionObject) static ReturnedValue construct(Managed *, CallData *callData); static ReturnedValue call(Managed *that, CallData *); @@ -80,8 +91,7 @@ struct DateCtor: FunctionObject struct DatePrototype: DateObject { - DatePrototype(InternalClass *ic): DateObject(ic) {} - void init(ExecutionEngine *engine, ObjectRef ctor); + void init(ExecutionEngine *engine, Object *ctor); static double getThisDate(ExecutionContext *ctx); diff --git a/src/qml/jsruntime/qv4debugging.cpp b/src/qml/jsruntime/qv4debugging.cpp index 06c6dbb4d9..04422b9f5e 100644 --- a/src/qml/jsruntime/qv4debugging.cpp +++ b/src/qml/jsruntime/qv4debugging.cpp @@ -210,7 +210,7 @@ Debugger::ExecutionState Debugger::currentExecutionState() const { ExecutionState state; state.fileName = getFunction()->sourceFile(); - state.lineNumber = engine()->currentContext()->lineNumber; + state.lineNumber = engine()->currentContext()->d()->lineNumber; return state; } @@ -224,12 +224,12 @@ static inline CallContext *findContext(ExecutionContext *ctxt, int frame) { while (ctxt) { CallContext *cCtxt = ctxt->asCallContext(); - if (cCtxt && cCtxt->function) { + if (cCtxt && cCtxt->d()->function) { if (frame < 1) return cCtxt; --frame; } - ctxt = ctxt->parent; + ctxt = ctxt->d()->parent; } return 0; @@ -238,7 +238,7 @@ static inline CallContext *findContext(ExecutionContext *ctxt, int frame) static inline CallContext *findScope(ExecutionContext *ctxt, int scope) { for (; scope > 0 && ctxt; --scope) - ctxt = ctxt->outer; + ctxt = ctxt->d()->outer; return ctxt ? ctxt->asCallContext() : 0; } @@ -327,7 +327,7 @@ void Debugger::collectLocalsInContext(Collector *collector, int frameNr, int sco QString qName; if (String *name = ctxt->variables()[i]) qName = name->toQString(); - v = ctxt->locals[i]; + v = ctxt->d()->locals[i]; collector->collect(qName, v); } } @@ -367,16 +367,16 @@ bool Debugger::collectThisInContext(Debugger::Collector *collector, int frame) ExecutionContext *ctxt = findContext(engine->currentContext(), frameNr); while (ctxt) { if (CallContext *cCtxt = ctxt->asCallContext()) - if (cCtxt->activation) + if (cCtxt->d()->activation) break; - ctxt = ctxt->outer; + ctxt = ctxt->d()->outer; } if (!ctxt) return false; Scope scope(engine); - ScopedObject o(scope, ctxt->asCallContext()->activation); + ScopedObject o(scope, ctxt->asCallContext()->d()->activation); collector->collect(o); return true; } @@ -434,12 +434,12 @@ QVector<ExecutionContext::ContextType> Debugger::getScopeTypes(int frame) const return types; CallContext *sctxt = findContext(m_engine->currentContext(), frame); - if (!sctxt || sctxt->type < ExecutionContext::Type_SimpleCallContext) + if (!sctxt || sctxt->d()->type < ExecutionContext::Type_SimpleCallContext) return types; CallContext *ctxt = static_cast<CallContext *>(sctxt); - for (ExecutionContext *it = ctxt; it; it = it->outer) - types.append(it->type); + for (ExecutionContext *it = ctxt; it; it = it->d()->outer) + types.append(it->d()->type); return types; } @@ -450,7 +450,7 @@ void Debugger::maybeBreakAtInstruction() return; QMutexLocker locker(&m_lock); - int lineNumber = engine()->currentContext()->lineNumber; + int lineNumber = engine()->currentContext()->d()->lineNumber; if (m_gatherSources) { m_gatherSources->run(); @@ -495,7 +495,7 @@ void Debugger::leavingFunction(const ReturnedValue &retVal) QMutexLocker locker(&m_lock); if (m_stepping != NotStepping && m_currentContext == m_engine->currentContext()) { - m_currentContext = m_engine->currentContext()->parent; + m_currentContext = m_engine->currentContext()->d()->parent; m_stepping = StepOver; m_returnedValue = retVal; } @@ -517,10 +517,10 @@ Function *Debugger::getFunction() const { ExecutionContext *context = m_engine->currentContext(); if (CallContext *callCtx = context->asCallContext()) - return callCtx->function->function; + return callCtx->d()->function->function(); else { - Q_ASSERT(context->type == QV4::ExecutionContext::Type_GlobalContext); - return context->engine->globalCode; + Q_ASSERT(context->d()->type == QV4::ExecutionContext::Type_GlobalContext); + return context->d()->engine->globalCode; } } @@ -726,7 +726,7 @@ void Debugger::Collector::collect(const QString &name, const ScopedValue &value) } } -void Debugger::Collector::collect(const ObjectRef object) +void Debugger::Collector::collect(Object *object) { bool property = true; qSwap(property, m_isProperty); diff --git a/src/qml/jsruntime/qv4debugging_p.h b/src/qml/jsruntime/qv4debugging_p.h index 47a7d77b28..f834b8d15f 100644 --- a/src/qml/jsruntime/qv4debugging_p.h +++ b/src/qml/jsruntime/qv4debugging_p.h @@ -105,7 +105,7 @@ public: virtual ~Collector(); void collect(const QString &name, const ScopedValue &value); - void collect(const ObjectRef object); + void collect(Object *object); protected: virtual void addUndefined(const QString &name) = 0; diff --git a/src/qml/jsruntime/qv4engine.cpp b/src/qml/jsruntime/qv4engine.cpp index 72be889e72..7be518916d 100644 --- a/src/qml/jsruntime/qv4engine.cpp +++ b/src/qml/jsruntime/qv4engine.cpp @@ -71,6 +71,7 @@ #include "qv4memberdata_p.h" #include <QtCore/QTextStream> +#include <QDateTime> #ifdef V4_ENABLE_JIT #include "qv4isel_masm_p.h" @@ -258,13 +259,13 @@ ExecutionEngine::ExecutionEngine(EvalISelFactory *factory) memberDataClass = InternalClass::create(this, MemberData::staticVTable(), 0); - ObjectPrototype *objectPrototype = new (memoryManager) ObjectPrototype(InternalClass::create(this, ObjectPrototype::staticVTable(), 0)); + ScopedObject objectPrototype(scope, memoryManager->alloc<ObjectPrototype>(InternalClass::create(this, ObjectPrototype::staticVTable(), 0))); objectClass = InternalClass::create(this, Object::staticVTable(), objectPrototype); Q_ASSERT(objectClass->vtable == Object::staticVTable()); arrayClass = InternalClass::create(this, ArrayObject::staticVTable(), objectPrototype); arrayClass = arrayClass->addMember(id_length, Attr_NotConfigurable|Attr_NotEnumerable); - ArrayPrototype *arrayPrototype = new (memoryManager) ArrayPrototype(arrayClass); + ScopedObject arrayPrototype(scope, memoryManager->alloc<ArrayPrototype>(arrayClass)); arrayClass = arrayClass->changePrototype(arrayPrototype); simpleArrayDataClass = InternalClass::create(this, SimpleArrayData::staticVTable(), 0); @@ -279,100 +280,100 @@ ExecutionEngine::ExecutionEngine(EvalISelFactory *factory) initRootContext(); - StringPrototype *stringPrototype = new (memoryManager) StringPrototype(InternalClass::create(this, StringPrototype::staticVTable(), objectPrototype)); + ScopedObject stringPrototype(scope, memoryManager->alloc<StringPrototype>(InternalClass::create(this, StringPrototype::staticVTable(), objectPrototype))); stringObjectClass = InternalClass::create(this, String::staticVTable(), stringPrototype); - NumberPrototype *numberPrototype = new (memoryManager) NumberPrototype(InternalClass::create(this, NumberPrototype::staticVTable(), objectPrototype)); + ScopedObject numberPrototype(scope, memoryManager->alloc<NumberPrototype>(InternalClass::create(this, NumberPrototype::staticVTable(), objectPrototype))); numberClass = InternalClass::create(this, NumberObject::staticVTable(), numberPrototype); - BooleanPrototype *booleanPrototype = new (memoryManager) BooleanPrototype(InternalClass::create(this, BooleanPrototype::staticVTable(), objectPrototype)); + ScopedObject booleanPrototype(scope, memoryManager->alloc<BooleanPrototype>(InternalClass::create(this, BooleanPrototype::staticVTable(), objectPrototype))); booleanClass = InternalClass::create(this, BooleanObject::staticVTable(), booleanPrototype); - DatePrototype *datePrototype = new (memoryManager) DatePrototype(InternalClass::create(this, DatePrototype::staticVTable(), objectPrototype)); + ScopedObject datePrototype(scope, memoryManager->alloc<DatePrototype>(InternalClass::create(this, DatePrototype::staticVTable(), objectPrototype))); dateClass = InternalClass::create(this, DateObject::staticVTable(), datePrototype); InternalClass *functionProtoClass = InternalClass::create(this, FunctionObject::staticVTable(), objectPrototype); uint index; functionProtoClass = functionProtoClass->addMember(id_prototype, Attr_NotEnumerable, &index); Q_ASSERT(index == FunctionObject::Index_Prototype); - FunctionPrototype *functionPrototype = new (memoryManager) FunctionPrototype(functionProtoClass); + ScopedObject functionPrototype(scope, memoryManager->alloc<FunctionPrototype>(functionProtoClass)); functionClass = InternalClass::create(this, FunctionObject::staticVTable(), functionPrototype); functionClass = functionClass->addMember(id_prototype, Attr_NotEnumerable|Attr_NotConfigurable, &index); Q_ASSERT(index == FunctionObject::Index_Prototype); protoClass = objectClass->addMember(id_constructor, Attr_NotEnumerable, &index); Q_ASSERT(index == FunctionObject::Index_ProtoConstructor); - RegExpPrototype *regExpPrototype = new (memoryManager) RegExpPrototype(InternalClass::create(this, RegExpPrototype::staticVTable(), objectPrototype)); - regExpClass = InternalClass::create(this, RegExpObject::staticVTable(), regExpPrototype); + Scoped<RegExpPrototype> regExpPrototype(scope, memoryManager->alloc<RegExpPrototype>(InternalClass::create(this, RegExpPrototype::staticVTable(), objectPrototype))); + regExpClass = InternalClass::create(this, RegExpObject::staticVTable(), regExpPrototype.getPointer()); regExpExecArrayClass = arrayClass->addMember(id_index, Attr_Data, &index); Q_ASSERT(index == RegExpObject::Index_ArrayIndex); regExpExecArrayClass = regExpExecArrayClass->addMember(id_input, Attr_Data, &index); Q_ASSERT(index == RegExpObject::Index_ArrayInput); - ErrorPrototype *errorPrototype = new (memoryManager) ErrorPrototype(InternalClass::create(this, ErrorObject::staticVTable(), objectPrototype)); + ScopedObject errorPrototype(scope, memoryManager->alloc<ErrorPrototype>(InternalClass::create(this, ErrorObject::staticVTable(), objectPrototype))); errorClass = InternalClass::create(this, ErrorObject::staticVTable(), errorPrototype); - EvalErrorPrototype *evalErrorPrototype = new (memoryManager) EvalErrorPrototype(errorClass); + ScopedObject evalErrorPrototype(scope, memoryManager->alloc<EvalErrorPrototype>(errorClass)); evalErrorClass = InternalClass::create(this, EvalErrorObject::staticVTable(), evalErrorPrototype); - RangeErrorPrototype *rangeErrorPrototype = new (memoryManager) RangeErrorPrototype(errorClass); + ScopedObject rangeErrorPrototype(scope, memoryManager->alloc<RangeErrorPrototype>(errorClass)); rangeErrorClass = InternalClass::create(this, RangeErrorObject::staticVTable(), rangeErrorPrototype); - ReferenceErrorPrototype *referenceErrorPrototype = new (memoryManager) ReferenceErrorPrototype(errorClass); + ScopedObject referenceErrorPrototype(scope, memoryManager->alloc<ReferenceErrorPrototype>(errorClass)); referenceErrorClass = InternalClass::create(this, ReferenceErrorObject::staticVTable(), referenceErrorPrototype); - SyntaxErrorPrototype *syntaxErrorPrototype = new (memoryManager) SyntaxErrorPrototype(errorClass); + ScopedObject syntaxErrorPrototype(scope, memoryManager->alloc<SyntaxErrorPrototype>(errorClass)); syntaxErrorClass = InternalClass::create(this, SyntaxErrorObject::staticVTable(), syntaxErrorPrototype); - TypeErrorPrototype *typeErrorPrototype = new (memoryManager) TypeErrorPrototype(errorClass); + ScopedObject typeErrorPrototype(scope, memoryManager->alloc<TypeErrorPrototype>(errorClass)); typeErrorClass = InternalClass::create(this, TypeErrorObject::staticVTable(), typeErrorPrototype); - URIErrorPrototype *uRIErrorPrototype = new (memoryManager) URIErrorPrototype(errorClass); + ScopedObject uRIErrorPrototype(scope, memoryManager->alloc<URIErrorPrototype>(errorClass)); uriErrorClass = InternalClass::create(this, URIErrorObject::staticVTable(), uRIErrorPrototype); - VariantPrototype *variantPrototype = new (memoryManager) VariantPrototype(InternalClass::create(this, VariantPrototype::staticVTable(), objectPrototype)); + ScopedObject variantPrototype(scope, memoryManager->alloc<VariantPrototype>(InternalClass::create(this, VariantPrototype::staticVTable(), objectPrototype))); variantClass = InternalClass::create(this, VariantObject::staticVTable(), variantPrototype); Q_ASSERT(variantClass->prototype == variantPrototype); - Q_ASSERT(variantPrototype->internalClass->prototype == objectPrototype); - - sequencePrototype = new (memoryManager) SequencePrototype(arrayClass); - - objectCtor = new (memoryManager) ObjectCtor(rootContext); - stringCtor = new (memoryManager) StringCtor(rootContext); - numberCtor = new (memoryManager) NumberCtor(rootContext); - booleanCtor = new (memoryManager) BooleanCtor(rootContext); - arrayCtor = new (memoryManager) ArrayCtor(rootContext); - functionCtor = new (memoryManager) FunctionCtor(rootContext); - dateCtor = new (memoryManager) DateCtor(rootContext); - regExpCtor = new (memoryManager) RegExpCtor(rootContext); - errorCtor = new (memoryManager) ErrorCtor(rootContext); - evalErrorCtor = new (memoryManager) EvalErrorCtor(rootContext); - rangeErrorCtor = new (memoryManager) RangeErrorCtor(rootContext); - referenceErrorCtor = new (memoryManager) ReferenceErrorCtor(rootContext); - syntaxErrorCtor = new (memoryManager) SyntaxErrorCtor(rootContext); - typeErrorCtor = new (memoryManager) TypeErrorCtor(rootContext); - uRIErrorCtor = new (memoryManager) URIErrorCtor(rootContext); - - objectPrototype->init(this, objectCtor); - stringPrototype->init(this, stringCtor); - numberPrototype->init(this, numberCtor); - booleanPrototype->init(this, booleanCtor); - arrayPrototype->init(this, arrayCtor); - datePrototype->init(this, dateCtor); - functionPrototype->init(this, functionCtor); - regExpPrototype->init(this, regExpCtor); - errorPrototype->init(this, errorCtor); - evalErrorPrototype->init(this, evalErrorCtor); - rangeErrorPrototype->init(this, rangeErrorCtor); - referenceErrorPrototype->init(this, referenceErrorCtor); - syntaxErrorPrototype->init(this, syntaxErrorCtor); - typeErrorPrototype->init(this, typeErrorCtor); - uRIErrorPrototype->init(this, uRIErrorCtor); - - variantPrototype->init(); + Q_ASSERT(variantPrototype->internalClass()->prototype == objectPrototype); + + sequencePrototype = ScopedValue(scope, memoryManager->alloc<SequencePrototype>(arrayClass)); + + objectCtor = memoryManager->alloc<ObjectCtor>(rootContext); + stringCtor = memoryManager->alloc<StringCtor>(rootContext); + numberCtor = memoryManager->alloc<NumberCtor>(rootContext); + booleanCtor = memoryManager->alloc<BooleanCtor>(rootContext); + arrayCtor = memoryManager->alloc<ArrayCtor>(rootContext); + functionCtor = memoryManager->alloc<FunctionCtor>(rootContext); + dateCtor = memoryManager->alloc<DateCtor>(rootContext); + regExpCtor = memoryManager->alloc<RegExpCtor>(rootContext); + errorCtor = memoryManager->alloc<ErrorCtor>(rootContext); + evalErrorCtor = memoryManager->alloc<EvalErrorCtor>(rootContext); + rangeErrorCtor = memoryManager->alloc<RangeErrorCtor>(rootContext); + referenceErrorCtor = memoryManager->alloc<ReferenceErrorCtor>(rootContext); + syntaxErrorCtor = memoryManager->alloc<SyntaxErrorCtor>(rootContext); + typeErrorCtor = memoryManager->alloc<TypeErrorCtor>(rootContext); + uRIErrorCtor = memoryManager->alloc<URIErrorCtor>(rootContext); + + static_cast<ObjectPrototype *>(objectPrototype.getPointer())->init(this, objectCtor.asObject()); + static_cast<StringPrototype *>(stringPrototype.getPointer())->init(this, stringCtor.asObject()); + static_cast<NumberPrototype *>(numberPrototype.getPointer())->init(this, numberCtor.asObject()); + static_cast<BooleanPrototype *>(booleanPrototype.getPointer())->init(this, booleanCtor.asObject()); + static_cast<ArrayPrototype *>(arrayPrototype.getPointer())->init(this, arrayCtor.asObject()); + static_cast<DatePrototype *>(datePrototype.getPointer())->init(this, dateCtor.asObject()); + static_cast<FunctionPrototype *>(functionPrototype.getPointer())->init(this, functionCtor.asObject()); + static_cast<RegExpPrototype *>(regExpPrototype.getPointer())->init(this, regExpCtor.asObject()); + static_cast<ErrorPrototype *>(errorPrototype.getPointer())->init(this, errorCtor.asObject()); + static_cast<EvalErrorPrototype *>(evalErrorPrototype.getPointer())->init(this, evalErrorCtor.asObject()); + static_cast<RangeErrorPrototype *>(rangeErrorPrototype.getPointer())->init(this, rangeErrorCtor.asObject()); + static_cast<ReferenceErrorPrototype *>(referenceErrorPrototype.getPointer())->init(this, referenceErrorCtor.asObject()); + static_cast<SyntaxErrorPrototype *>(syntaxErrorPrototype.getPointer())->init(this, syntaxErrorCtor.asObject()); + static_cast<TypeErrorPrototype *>(typeErrorPrototype.getPointer())->init(this, typeErrorCtor.asObject()); + static_cast<URIErrorPrototype *>(uRIErrorPrototype.getPointer())->init(this, uRIErrorCtor.asObject()); + + static_cast<VariantPrototype *>(variantPrototype.getPointer())->init(); static_cast<SequencePrototype *>(sequencePrototype.managed())->init(); // // set up the global object // globalObject = newObject()->getPointer(); - rootContext->global = globalObject; - rootContext->callData->thisObject = globalObject; - Q_ASSERT(globalObject->internalClass->vtable); + rootContext->d()->global = globalObject; + rootContext->d()->callData->thisObject = globalObject; + Q_ASSERT(globalObject->internalClass()->vtable); globalObject->defineDefaultProperty(QStringLiteral("Object"), objectCtor); globalObject->defineDefaultProperty(QStringLiteral("String"), stringCtor); @@ -390,14 +391,15 @@ ExecutionEngine::ExecutionEngine(EvalISelFactory *factory) globalObject->defineDefaultProperty(QStringLiteral("TypeError"), typeErrorCtor); globalObject->defineDefaultProperty(QStringLiteral("URIError"), uRIErrorCtor); ScopedObject o(scope); - globalObject->defineDefaultProperty(QStringLiteral("Math"), (o = new (memoryManager) MathObject(QV4::InternalClass::create(this, MathObject::staticVTable(), objectPrototype)))); - globalObject->defineDefaultProperty(QStringLiteral("JSON"), (o = new (memoryManager) JsonObject(QV4::InternalClass::create(this, JsonObject::staticVTable(), objectPrototype)))); + globalObject->defineDefaultProperty(QStringLiteral("Math"), (o = memoryManager->alloc<MathObject>(QV4::InternalClass::create(this, MathObject::staticVTable(), objectPrototype)))); + globalObject->defineDefaultProperty(QStringLiteral("JSON"), (o = memoryManager->alloc<JsonObject>(QV4::InternalClass::create(this, JsonObject::staticVTable(), objectPrototype)))); globalObject->defineReadonlyProperty(QStringLiteral("undefined"), Primitive::undefinedValue()); globalObject->defineReadonlyProperty(QStringLiteral("NaN"), Primitive::fromDouble(std::numeric_limits<double>::quiet_NaN())); globalObject->defineReadonlyProperty(QStringLiteral("Infinity"), Primitive::fromDouble(Q_INFINITY)); - evalFunction = new (memoryManager) EvalFunction(rootContext); + + evalFunction = Scoped<EvalFunction>(scope, memoryManager->alloc<EvalFunction>(rootContext)); globalObject->defineDefaultProperty(QStringLiteral("eval"), (o = evalFunction)); globalObject->defineDefaultProperty(QStringLiteral("parseInt"), GlobalFunctions::method_parseInt, 2); @@ -412,13 +414,15 @@ ExecutionEngine::ExecutionEngine(EvalISelFactory *factory) globalObject->defineDefaultProperty(QStringLiteral("unescape"), GlobalFunctions::method_unescape, 1); Scoped<String> name(scope, newString(QStringLiteral("thrower"))); - thrower = newBuiltinFunction(rootContext, name, throwTypeError)->getPointer(); + thrower = ScopedFunctionObject(scope, BuiltinFunction::create(rootContext, name.getPointer(), throwTypeError)).getPointer(); } ExecutionEngine::~ExecutionEngine() { delete debugger; + debugger = 0; delete profiler; + profiler = 0; delete m_multiplyWrappedQObjects; m_multiplyWrappedQObjects = 0; delete identifierTable; @@ -451,18 +455,20 @@ void ExecutionEngine::enableDebugger() void ExecutionEngine::enableProfiler() { Q_ASSERT(!profiler); - profiler = new QV4::Profiling::Profiler(); + profiler = new QV4::Profiling::Profiler(this); } void ExecutionEngine::initRootContext() { - rootContext = static_cast<GlobalContext *>(memoryManager->allocManaged(sizeof(GlobalContext) + sizeof(CallData))); - new (rootContext) GlobalContext(this); - rootContext->callData = reinterpret_cast<CallData *>(rootContext + 1); - rootContext->callData->tag = QV4::Value::_Integer_Type; - rootContext->callData->argc = 0; - rootContext->callData->thisObject = globalObject; - rootContext->callData->args[0] = Encode::undefined(); + GlobalContext *r = static_cast<GlobalContext*>(memoryManager->allocManaged(sizeof(GlobalContext::Data) + sizeof(CallData))); + new (r->d()) GlobalContext::Data(this); + r->d()->callData = reinterpret_cast<CallData *>(r->d() + 1); + r->d()->callData->tag = QV4::Value::_Integer_Type; + r->d()->callData->argc = 0; + r->d()->callData->thisObject = globalObject; + r->d()->callData->args[0] = Encode::undefined(); + + rootContext = r; } InternalClass *ExecutionEngine::newClass(const InternalClass &other) @@ -472,43 +478,32 @@ InternalClass *ExecutionEngine::newClass(const InternalClass &other) ExecutionContext *ExecutionEngine::pushGlobalContext() { - GlobalContext *g = new (memoryManager) GlobalContext(this); - g->callData = rootContext->callData; + GlobalContext *g = memoryManager->alloc<GlobalContext>(this); + g->d()->callData = rootContext->d()->callData; Q_ASSERT(currentContext() == g); return g; } -Returned<FunctionObject> *ExecutionEngine::newBuiltinFunction(ExecutionContext *scope, const StringRef name, ReturnedValue (*code)(CallContext *)) -{ - BuiltinFunction *f = new (memoryManager) BuiltinFunction(scope, name, code); - return f->asReturned<FunctionObject>(); -} - -Returned<BoundFunction> *ExecutionEngine::newBoundFunction(ExecutionContext *scope, FunctionObjectRef target, const ValueRef boundThis, const QVector<Value> &boundArgs) -{ - Q_ASSERT(target); - - BoundFunction *f = new (memoryManager) BoundFunction(scope, target, boundThis, boundArgs); - return f->asReturned<BoundFunction>(); -} - Returned<Object> *ExecutionEngine::newObject() { - Object *object = new (memoryManager) Object(this); + Scope scope(this); + ScopedObject object(scope, memoryManager->alloc<Object>(this)); return object->asReturned<Object>(); } Returned<Object> *ExecutionEngine::newObject(InternalClass *internalClass) { - Object *object = new (memoryManager) Object(internalClass); + Scope scope(this); + ScopedObject object(scope, memoryManager->alloc<Object>(internalClass)); return object->asReturned<Object>(); } Returned<String> *ExecutionEngine::newString(const QString &s) { - return (new (memoryManager) String(this, s))->asReturned<String>(); + Scope scope(this); + return ScopedString(scope, memoryManager->alloc<String>(this, s))->asReturned<String>(); } String *ExecutionEngine::newIdentifier(const QString &text) @@ -518,29 +513,31 @@ String *ExecutionEngine::newIdentifier(const QString &text) Returned<Object> *ExecutionEngine::newStringObject(const ValueRef value) { - StringObject *object = new (memoryManager) StringObject(this, value); + Scope scope(this); + Scoped<StringObject> object(scope, memoryManager->alloc<StringObject>(this, value)); return object->asReturned<Object>(); } Returned<Object> *ExecutionEngine::newNumberObject(const ValueRef value) { - NumberObject *object = new (memoryManager) NumberObject(this, value); + Scope scope(this); + Scoped<NumberObject> object(scope, memoryManager->alloc<NumberObject>(this, value)); return object->asReturned<Object>(); } Returned<Object> *ExecutionEngine::newBooleanObject(const ValueRef value) { - Object *object = new (memoryManager) BooleanObject(this, value); + Scope scope(this); + ScopedObject object(scope, memoryManager->alloc<BooleanObject>(this, value)); return object->asReturned<Object>(); } Returned<ArrayObject> *ExecutionEngine::newArrayObject(int count) { - ArrayObject *object = new (memoryManager) ArrayObject(this); + Scope scope(this); + ScopedArrayObject object(scope, memoryManager->alloc<ArrayObject>(this)); if (count) { - Scope scope(this); - ScopedValue protectArray(scope, object); if (count < 0x1000) object->arrayReserve(count); object->setArrayLengthUnchecked(count); @@ -550,26 +547,30 @@ Returned<ArrayObject> *ExecutionEngine::newArrayObject(int count) Returned<ArrayObject> *ExecutionEngine::newArrayObject(const QStringList &list) { - ArrayObject *object = new (memoryManager) ArrayObject(this, list); + Scope scope(this); + ScopedArrayObject object(scope, memoryManager->alloc<ArrayObject>(this, list)); return object->asReturned<ArrayObject>(); } Returned<ArrayObject> *ExecutionEngine::newArrayObject(InternalClass *ic) { - ArrayObject *object = new (memoryManager) ArrayObject(ic); + Scope scope(this); + ScopedArrayObject object(scope, memoryManager->alloc<ArrayObject>(ic)); return object->asReturned<ArrayObject>(); } Returned<DateObject> *ExecutionEngine::newDateObject(const ValueRef value) { - DateObject *object = new (memoryManager) DateObject(this, value); + Scope scope(this); + Scoped<DateObject> object(scope, memoryManager->alloc<DateObject>(this, value)); return object->asReturned<DateObject>(); } Returned<DateObject> *ExecutionEngine::newDateObject(const QDateTime &dt) { - DateObject *object = new (memoryManager) DateObject(this, dt); + Scope scope(this); + Scoped<DateObject> object(scope, memoryManager->alloc<DateObject>(this, dt)); return object->asReturned<DateObject>(); } @@ -588,21 +589,24 @@ Returned<RegExpObject> *ExecutionEngine::newRegExpObject(const QString &pattern, return newRegExpObject(re, global); } -Returned<RegExpObject> *ExecutionEngine::newRegExpObject(RegExpRef re, bool global) +Returned<RegExpObject> *ExecutionEngine::newRegExpObject(RegExp *re, bool global) { - RegExpObject *object = new (memoryManager) RegExpObject(this, re, global); + Scope scope(this); + Scoped<RegExpObject> object(scope, memoryManager->alloc<RegExpObject>(this, re, global)); return object->asReturned<RegExpObject>(); } Returned<RegExpObject> *ExecutionEngine::newRegExpObject(const QRegExp &re) { - RegExpObject *object = new (memoryManager) RegExpObject(this, re); + Scope scope(this); + Scoped<RegExpObject> object(scope, memoryManager->alloc<RegExpObject>(this, re)); return object->asReturned<RegExpObject>(); } Returned<Object> *ExecutionEngine::newErrorObject(const ValueRef value) { - ErrorObject *object = new (memoryManager) ErrorObject(errorClass, value); + Scope scope(this); + ScopedObject object(scope, memoryManager->alloc<ErrorObject>(errorClass, value)); return object->asReturned<Object>(); } @@ -610,57 +614,65 @@ Returned<Object> *ExecutionEngine::newSyntaxErrorObject(const QString &message) { Scope scope(this); ScopedString s(scope, newString(message)); - Object *error = new (memoryManager) SyntaxErrorObject(this, s); + ScopedObject error(scope, memoryManager->alloc<SyntaxErrorObject>(this, s)); return error->asReturned<Object>(); } Returned<Object> *ExecutionEngine::newSyntaxErrorObject(const QString &message, const QString &fileName, int line, int column) { - Object *error = new (memoryManager) SyntaxErrorObject(this, message, fileName, line, column); + Scope scope(this); + ScopedObject error(scope, memoryManager->alloc<SyntaxErrorObject>(this, message, fileName, line, column)); return error->asReturned<Object>(); } Returned<Object> *ExecutionEngine::newReferenceErrorObject(const QString &message) { - Object *o = new (memoryManager) ReferenceErrorObject(this, message); + Scope scope(this); + ScopedObject o(scope, memoryManager->alloc<ReferenceErrorObject>(this, message)); return o->asReturned<Object>(); } Returned<Object> *ExecutionEngine::newReferenceErrorObject(const QString &message, const QString &fileName, int lineNumber, int columnNumber) { - Object *o = new (memoryManager) ReferenceErrorObject(this, message, fileName, lineNumber, columnNumber); + Scope scope(this); + ScopedObject o(scope, memoryManager->alloc<ReferenceErrorObject>(this, message, fileName, lineNumber, columnNumber)); return o->asReturned<Object>(); } Returned<Object> *ExecutionEngine::newTypeErrorObject(const QString &message) { - Object *o = new (memoryManager) TypeErrorObject(this, message); + Scope scope(this); + ScopedObject o(scope, memoryManager->alloc<TypeErrorObject>(this, message)); return o->asReturned<Object>(); } Returned<Object> *ExecutionEngine::newRangeErrorObject(const QString &message) { - Object *o = new (memoryManager) RangeErrorObject(this, message); + Scope scope(this); + ScopedObject o(scope, memoryManager->alloc<RangeErrorObject>(this, message)); return o->asReturned<Object>(); } Returned<Object> *ExecutionEngine::newURIErrorObject(const ValueRef message) { - Object *o = new (memoryManager) URIErrorObject(this, message); + Scope scope(this); + ScopedObject o(scope, memoryManager->alloc<URIErrorObject>(this, message)); return o->asReturned<Object>(); } Returned<Object> *ExecutionEngine::newVariantObject(const QVariant &v) { - Object *o = new (memoryManager) VariantObject(this, v); + Scope scope(this); + ScopedObject o(scope, memoryManager->alloc<VariantObject>(this, v)); return o->asReturned<Object>(); } -Returned<Object> *ExecutionEngine::newForEachIteratorObject(ExecutionContext *ctx, const ObjectRef o) +Returned<Object> *ExecutionEngine::newForEachIteratorObject(ExecutionContext *ctx, Object *o) { - Object *obj = new (memoryManager) ForEachIteratorObject(ctx, o); + Scope scope(this); + ScopedObject obj(scope, memoryManager->alloc<ForEachIteratorObject>(ctx, o)); return obj->asReturned<Object>(); } @@ -668,20 +680,20 @@ Returned<Object> *ExecutionEngine::qmlContextObject() const { ExecutionContext *ctx = currentContext(); - if (ctx->type == QV4::ExecutionContext::Type_SimpleCallContext && !ctx->outer) - ctx = ctx->parent; + if (ctx->d()->type == QV4::ExecutionContext::Type_SimpleCallContext && !ctx->d()->outer) + ctx = ctx->d()->parent; - if (!ctx->outer) + if (!ctx->d()->outer) return 0; - while (ctx->outer && ctx->outer->type != ExecutionContext::Type_GlobalContext) - ctx = ctx->outer; + while (ctx->d()->outer && ctx->d()->outer->d()->type != ExecutionContext::Type_GlobalContext) + ctx = ctx->d()->outer; Q_ASSERT(ctx); - if (ctx->type != ExecutionContext::Type_QmlContext) + if (ctx->d()->type != ExecutionContext::Type_QmlContext) return 0; - return static_cast<CallContext *>(ctx)->activation->asReturned<Object>(); + return static_cast<CallContext *>(ctx)->d()->activation->asReturned<Object>(); } QVector<StackFrame> ExecutionEngine::stackTrace(int frameLimit) const @@ -693,30 +705,30 @@ QVector<StackFrame> ExecutionEngine::stackTrace(int frameLimit) const QV4::ExecutionContext *c = currentContext(); while (c && frameLimit) { CallContext *callCtx = c->asCallContext(); - if (callCtx && callCtx->function) { + if (callCtx && callCtx->d()->function) { StackFrame frame; - if (callCtx->function->function) - frame.source = callCtx->function->function->sourceFile(); - name = callCtx->function->name(); + if (callCtx->d()->function->function()) + frame.source = callCtx->d()->function->function()->sourceFile(); + name = callCtx->d()->function->name(); frame.function = name->toQString(); frame.line = -1; frame.column = -1; - if (callCtx->function->function) + if (callCtx->d()->function->function()) // line numbers can be negative for places where you can't set a real breakpoint - frame.line = qAbs(callCtx->lineNumber); + frame.line = qAbs(callCtx->d()->lineNumber); stack.append(frame); --frameLimit; } - c = c->parent; + c = c->d()->parent; } if (frameLimit && globalCode) { StackFrame frame; frame.source = globalCode->sourceFile(); frame.function = globalCode->name()->toQString(); - frame.line = rootContext->lineNumber; + frame.line = rootContext->d()->lineNumber; frame.column = -1; @@ -750,8 +762,8 @@ static inline char *v4StackTrace(const ExecutionContext *context) QString result; QTextStream str(&result); str << "stack=["; - if (context && context->engine) { - const QVector<StackFrame> stackTrace = context->engine->stackTrace(20); + if (context && context->d()->engine) { + const QVector<StackFrame> stackTrace = context->d()->engine->stackTrace(20); for (int i = 0; i < stackTrace.size(); ++i) { if (i) str << ','; @@ -781,12 +793,12 @@ QUrl ExecutionEngine::resolvedUrl(const QString &file) QV4::ExecutionContext *c = currentContext(); while (c) { CallContext *callCtx = c->asCallContext(); - if (callCtx && callCtx->function) { - if (callCtx->function->function) - base.setUrl(callCtx->function->function->sourceFile()); + if (callCtx && callCtx->d()->function) { + if (callCtx->d()->function->function()) + base.setUrl(callCtx->d()->function->function()->sourceFile()); break; } - c = c->parent; + c = c->d()->parent; } if (base.isEmpty() && globalCode) @@ -817,8 +829,8 @@ void ExecutionEngine::requireArgumentsAccessors(int n) delete [] oldAccessors; } for (int i = oldSize; i < nArgumentsAccessors; ++i) { - argumentsAccessors[i].value = Value::fromManaged(new (memoryManager) ArgumentsGetterFunction(rootContext, i)); - argumentsAccessors[i].set = Value::fromManaged(new (memoryManager) ArgumentsSetterFunction(rootContext, i)); + argumentsAccessors[i].value = ScopedValue(scope, memoryManager->alloc<ArgumentsGetterFunction>(rootContext, i)); + argumentsAccessors[i].set = ScopedValue(scope, memoryManager->alloc<ArgumentsSetterFunction>(rootContext, i)); } } } @@ -839,12 +851,12 @@ void ExecutionEngine::markObjects() ExecutionContext *c = currentContext(); while (c) { - Q_ASSERT(c->inUse); - if (!c->markBit) { - c->markBit = 1; + Q_ASSERT(c->inUse()); + if (!c->markBit()) { + c->d()->markBit = 1; c->markObjects(c, this); } - c = c->parent; + c = c->d()->parent; } id_empty->mark(this); @@ -932,7 +944,7 @@ ReturnedValue ExecutionEngine::throwException(const ValueRef value) QV4::Scope scope(this); QV4::Scoped<ErrorObject> error(scope, value); if (!!error) - exceptionStackTrace = error->stackTrace; + exceptionStackTrace = error->d()->stackTrace; else exceptionStackTrace = stackTrace(); @@ -971,7 +983,7 @@ QQmlError ExecutionEngine::catchExceptionAsQmlError(ExecutionContext *context) QV4::Scoped<QV4::ErrorObject> errorObj(scope, exception); if (!!errorObj && errorObj->asSyntaxError()) { QV4::ScopedString m(scope, errorObj->engine()->newString(QStringLiteral("message"))); - QV4::ScopedValue v(scope, errorObj->get(m)); + QV4::ScopedValue v(scope, errorObj->get(m.getPointer())); error.setDescription(v->toQStringNoThrow()); } else error.setDescription(exception->toQStringNoThrow()); diff --git a/src/qml/jsruntime/qv4engine_p.h b/src/qml/jsruntime/qv4engine_p.h index d678d6595e..a3f83de338 100644 --- a/src/qml/jsruntime/qv4engine_p.h +++ b/src/qml/jsruntime/qv4engine_p.h @@ -86,6 +86,7 @@ struct SyntaxErrorObject; struct ArgumentsObject; struct ExecutionContext; struct ExecutionEngine; +struct Members; class MemoryManager; class ExecutableAllocator; @@ -111,7 +112,7 @@ struct IdentifierTable; struct InternalClass; struct InternalClassPool; class MultiplyWrappedQObjectMap; -class RegExp; +struct RegExp; class RegExpCache; struct QmlExtensions; struct Exception; @@ -169,7 +170,6 @@ public: return jsStackTop->managed(); } - IdentifierTable *identifierTable; QV4::Debugging::Debugger *debugger; @@ -285,7 +285,7 @@ public: // calling preserve() on the object which removes it from this scarceResource list. class ScarceResourceData { public: - ScarceResourceData(const QVariant &data) : data(data) {} + ScarceResourceData(const QVariant &data = QVariant()) : data(data) {} QVariant data; QIntrusiveListNode node; }; @@ -306,9 +306,6 @@ public: void pushContext(CallContext *context); ExecutionContext *popContext(); - Returned<FunctionObject> *newBuiltinFunction(ExecutionContext *scope, const StringRef name, ReturnedValue (*code)(CallContext *)); - Returned<BoundFunction> *newBoundFunction(ExecutionContext *scope, FunctionObjectRef target, const ValueRef boundThis, const QVector<Value> &boundArgs); - Returned<Object> *newObject(); Returned<Object> *newObject(InternalClass *internalClass); @@ -327,7 +324,7 @@ public: Returned<DateObject> *newDateObject(const QDateTime &dt); Returned<RegExpObject> *newRegExpObject(const QString &pattern, int flags); - Returned<RegExpObject> *newRegExpObject(RegExpRef re, bool global); + Returned<RegExpObject> *newRegExpObject(RegExp *re, bool global); Returned<RegExpObject> *newRegExpObject(const QRegExp &re); Returned<Object> *newErrorObject(const ValueRef value); @@ -341,7 +338,7 @@ public: Returned<Object> *newVariantObject(const QVariant &v); - Returned<Object> *newForEachIteratorObject(ExecutionContext *ctx, const ObjectRef o); + Returned<Object> *newForEachIteratorObject(ExecutionContext *ctx, Object *o); Returned<Object> *qmlContextObject() const; @@ -378,10 +375,10 @@ private: inline void Managed::mark(QV4::ExecutionEngine *engine) { - Q_ASSERT(inUse); - if (markBit) + Q_ASSERT(inUse()); + if (markBit()) return; - markBit = 1; + d()->markBit = 1; engine->pushForGC(this); } diff --git a/src/qml/jsruntime/qv4errorobject.cpp b/src/qml/jsruntime/qv4errorobject.cpp index 9d6403e7dd..b99a82a1f5 100644 --- a/src/qml/jsruntime/qv4errorobject.cpp +++ b/src/qml/jsruntime/qv4errorobject.cpp @@ -71,104 +71,100 @@ using namespace QV4; -ErrorObject::ErrorObject(InternalClass *ic) - : Object(ic) - , stack(0) +ErrorObject::Data::Data(InternalClass *ic) + : Object::Data(ic) { - Scope scope(engine()); - ScopedValue protectThis(scope, this); + Scope scope(ic->engine); + Scoped<ErrorObject> e(scope, this); - ScopedString s(scope, ic->engine->newString(QStringLiteral("Error"))); - defineDefaultProperty(QStringLiteral("name"), s); + ScopedString s(scope, scope.engine->newString(QStringLiteral("Error"))); + e->defineDefaultProperty(QStringLiteral("name"), s); } -ErrorObject::ErrorObject(InternalClass *ic, const ValueRef message, ErrorType t) - : Object(ic) - , stack(0) +ErrorObject::Data::Data(InternalClass *ic, const ValueRef message, ErrorType t) + : Object::Data(ic) { subtype = t; - Scope scope(engine()); - ScopedValue protectThis(scope, this); + Scope scope(ic->engine); + Scoped<ErrorObject> e(scope, this); - defineAccessorProperty(QStringLiteral("stack"), ErrorObject::method_get_stack, 0); + e->defineAccessorProperty(QStringLiteral("stack"), ErrorObject::method_get_stack, 0); if (!message->isUndefined()) - defineDefaultProperty(QStringLiteral("message"), message); + e->defineDefaultProperty(QStringLiteral("message"), message); ScopedString s(scope); - defineDefaultProperty(QStringLiteral("name"), (s = ic->engine->newString(className()))); + e->defineDefaultProperty(QStringLiteral("name"), (s = scope.engine->newString(e->className()))); - stackTrace = ic->engine->stackTrace(); - if (!stackTrace.isEmpty()) { - defineDefaultProperty(QStringLiteral("fileName"), (s = ic->engine->newString(stackTrace.at(0).source))); - defineDefaultProperty(QStringLiteral("lineNumber"), Primitive::fromInt32(stackTrace.at(0).line)); + e->d()->stackTrace = scope.engine->stackTrace(); + if (!e->d()->stackTrace.isEmpty()) { + e->defineDefaultProperty(QStringLiteral("fileName"), (s = scope.engine->newString(e->d()->stackTrace.at(0).source))); + e->defineDefaultProperty(QStringLiteral("lineNumber"), Primitive::fromInt32(e->d()->stackTrace.at(0).line)); } } -ErrorObject::ErrorObject(InternalClass *ic, const QString &message, ErrorObject::ErrorType t) - : Object(ic) - , stack(0) +ErrorObject::Data::Data(InternalClass *ic, const QString &message, ErrorObject::ErrorType t) + : Object::Data(ic) { subtype = t; - Scope scope(engine()); - ScopedValue protectThis(scope, this); + Scope scope(ic->engine); + Scoped<ErrorObject> e(scope, this); ScopedString s(scope); - defineAccessorProperty(QStringLiteral("stack"), ErrorObject::method_get_stack, 0); + e->defineAccessorProperty(QStringLiteral("stack"), ErrorObject::method_get_stack, 0); - ScopedValue v(scope, ic->engine->newString(message)); - defineDefaultProperty(QStringLiteral("message"), v); - defineDefaultProperty(QStringLiteral("name"), (s = ic->engine->newString(className()))); + ScopedValue v(scope, scope.engine->newString(message)); + e->defineDefaultProperty(QStringLiteral("message"), v); + e->defineDefaultProperty(QStringLiteral("name"), (s = scope.engine->newString(e->className()))); - stackTrace = ic->engine->stackTrace(); - if (!stackTrace.isEmpty()) { - defineDefaultProperty(QStringLiteral("fileName"), (s = ic->engine->newString(stackTrace.at(0).source))); - defineDefaultProperty(QStringLiteral("lineNumber"), Primitive::fromInt32(stackTrace.at(0).line)); + e->d()->stackTrace = scope.engine->stackTrace(); + if (!e->d()->stackTrace.isEmpty()) { + e->defineDefaultProperty(QStringLiteral("fileName"), (s = scope.engine->newString(e->d()->stackTrace.at(0).source))); + e->defineDefaultProperty(QStringLiteral("lineNumber"), Primitive::fromInt32(e->d()->stackTrace.at(0).line)); } } -ErrorObject::ErrorObject(InternalClass *ic, const QString &message, const QString &fileName, int line, int column, ErrorObject::ErrorType t) - : Object(ic) - , stack(0) +ErrorObject::Data::Data(InternalClass *ic, const QString &message, const QString &fileName, int line, int column, ErrorObject::ErrorType t) + : Object::Data(ic) { subtype = t; - Scope scope(engine()); - ScopedValue protectThis(scope, this); + Scope scope(ic->engine); + Scoped<ErrorObject> e(scope, this); ScopedString s(scope); - defineAccessorProperty(QStringLiteral("stack"), ErrorObject::method_get_stack, 0); - defineDefaultProperty(QStringLiteral("name"), (s = ic->engine->newString(className()))); + e->defineAccessorProperty(QStringLiteral("stack"), ErrorObject::method_get_stack, 0); + e->defineDefaultProperty(QStringLiteral("name"), (s = scope.engine->newString(e->className()))); - stackTrace = ic->engine->stackTrace(); + e->d()->stackTrace = scope.engine->stackTrace(); StackFrame frame; frame.source = fileName; frame.line = line; frame.column = column; - stackTrace.prepend(frame); + e->d()->stackTrace.prepend(frame); - if (!stackTrace.isEmpty()) { - defineDefaultProperty(QStringLiteral("fileName"), (s = ic->engine->newString(stackTrace.at(0).source))); - defineDefaultProperty(QStringLiteral("lineNumber"), Primitive::fromInt32(stackTrace.at(0).line)); + if (!e->d()->stackTrace.isEmpty()) { + e->defineDefaultProperty(QStringLiteral("fileName"), (s = scope.engine->newString(e->d()->stackTrace.at(0).source))); + e->defineDefaultProperty(QStringLiteral("lineNumber"), Primitive::fromInt32(e->d()->stackTrace.at(0).line)); } - ScopedValue v(scope, ic->engine->newString(message)); - defineDefaultProperty(QStringLiteral("message"), v); + ScopedValue v(scope, scope.engine->newString(message)); + e->defineDefaultProperty(QStringLiteral("message"), v); } ReturnedValue ErrorObject::method_get_stack(CallContext *ctx) { Scope scope(ctx); - Scoped<ErrorObject> This(scope, ctx->callData->thisObject); + Scoped<ErrorObject> This(scope, ctx->d()->callData->thisObject); if (!This) return ctx->throwTypeError(); - if (!This->stack) { + if (!This->d()->stack) { QString trace; - for (int i = 0; i < This->stackTrace.count(); ++i) { + for (int i = 0; i < This->d()->stackTrace.count(); ++i) { if (i > 0) trace += QLatin1Char('\n'); - const StackFrame &frame = This->stackTrace[i]; + const StackFrame &frame = This->d()->stackTrace[i]; trace += frame.function; trace += QLatin1Char('@'); trace += frame.source; @@ -177,16 +173,16 @@ ReturnedValue ErrorObject::method_get_stack(CallContext *ctx) trace += QString::number(frame.line); } } - This->stack = ctx->engine->newString(trace)->getPointer(); + This->d()->stack = ctx->d()->engine->newString(trace)->getPointer(); } - return This->stack->asReturnedValue(); + return This->d()->stack->asReturnedValue(); } void ErrorObject::markObjects(Managed *that, ExecutionEngine *e) { ErrorObject *This = that->asErrorObject(); - if (This->stack) - This->stack->mark(e); + if (This->d()->stack) + This->d()->stack->mark(e); Object::markObjects(that, e); } @@ -194,58 +190,58 @@ DEFINE_OBJECT_VTABLE(ErrorObject); DEFINE_OBJECT_VTABLE(SyntaxErrorObject); -SyntaxErrorObject::SyntaxErrorObject(ExecutionEngine *engine, const ValueRef msg) - : ErrorObject(engine->syntaxErrorClass, msg, SyntaxError) +SyntaxErrorObject::Data::Data(ExecutionEngine *engine, const ValueRef msg) + : ErrorObject::Data(engine->syntaxErrorClass, msg, SyntaxError) { } -SyntaxErrorObject::SyntaxErrorObject(ExecutionEngine *engine, const QString &msg, const QString &fileName, int lineNumber, int columnNumber) - : ErrorObject(engine->syntaxErrorClass, msg, fileName, lineNumber, columnNumber, SyntaxError) +SyntaxErrorObject::Data::Data(ExecutionEngine *engine, const QString &msg, const QString &fileName, int lineNumber, int columnNumber) + : ErrorObject::Data(engine->syntaxErrorClass, msg, fileName, lineNumber, columnNumber, SyntaxError) { } -EvalErrorObject::EvalErrorObject(ExecutionEngine *engine, const ValueRef message) - : ErrorObject(engine->evalErrorClass, message, EvalError) +EvalErrorObject::Data::Data(ExecutionEngine *engine, const ValueRef message) + : ErrorObject::Data(engine->evalErrorClass, message, EvalError) { } -RangeErrorObject::RangeErrorObject(ExecutionEngine *engine, const ValueRef message) - : ErrorObject(engine->rangeErrorClass, message, RangeError) +RangeErrorObject::Data::Data(ExecutionEngine *engine, const ValueRef message) + : ErrorObject::Data(engine->rangeErrorClass, message, RangeError) { } -RangeErrorObject::RangeErrorObject(ExecutionEngine *engine, const QString &message) - : ErrorObject(engine->rangeErrorClass, message, RangeError) +RangeErrorObject::Data::Data(ExecutionEngine *engine, const QString &message) + : ErrorObject::Data(engine->rangeErrorClass, message, RangeError) { } -ReferenceErrorObject::ReferenceErrorObject(ExecutionEngine *engine, const ValueRef message) - : ErrorObject(engine->referenceErrorClass, message, ReferenceError) +ReferenceErrorObject::Data::Data(ExecutionEngine *engine, const ValueRef message) + : ErrorObject::Data(engine->referenceErrorClass, message, ReferenceError) { } -ReferenceErrorObject::ReferenceErrorObject(ExecutionEngine *engine, const QString &message) - : ErrorObject(engine->referenceErrorClass, message, ReferenceError) +ReferenceErrorObject::Data::Data(ExecutionEngine *engine, const QString &message) + : ErrorObject::Data(engine->referenceErrorClass, message, ReferenceError) { } -ReferenceErrorObject::ReferenceErrorObject(ExecutionEngine *engine, const QString &msg, const QString &fileName, int lineNumber, int columnNumber) - : ErrorObject(engine->referenceErrorClass, msg, fileName, lineNumber, columnNumber, ReferenceError) +ReferenceErrorObject::Data::Data(ExecutionEngine *engine, const QString &msg, const QString &fileName, int lineNumber, int columnNumber) + : ErrorObject::Data(engine->referenceErrorClass, msg, fileName, lineNumber, columnNumber, ReferenceError) { } -TypeErrorObject::TypeErrorObject(ExecutionEngine *engine, const ValueRef message) - : ErrorObject(engine->typeErrorClass, message, TypeError) +TypeErrorObject::Data::Data(ExecutionEngine *engine, const ValueRef message) + : ErrorObject::Data(engine->typeErrorClass, message, TypeError) { } -TypeErrorObject::TypeErrorObject(ExecutionEngine *engine, const QString &message) - : ErrorObject(engine->typeErrorClass, message, TypeError) +TypeErrorObject::Data::Data(ExecutionEngine *engine, const QString &message) + : ErrorObject::Data(engine->typeErrorClass, message, TypeError) { } -URIErrorObject::URIErrorObject(ExecutionEngine *engine, const ValueRef message) - : ErrorObject(engine->uriErrorClass, message, URIError) +URIErrorObject::Data::Data(ExecutionEngine *engine, const ValueRef message) + : ErrorObject::Data(engine->uriErrorClass, message, URIError) { } @@ -257,14 +253,14 @@ DEFINE_OBJECT_VTABLE(SyntaxErrorCtor); DEFINE_OBJECT_VTABLE(TypeErrorCtor); DEFINE_OBJECT_VTABLE(URIErrorCtor); -ErrorCtor::ErrorCtor(ExecutionContext *scope) - : FunctionObject(scope, QStringLiteral("Error")) +ErrorCtor::Data::Data(ExecutionContext *scope) + : FunctionObject::Data(scope, QStringLiteral("Error")) { setVTable(staticVTable()); } -ErrorCtor::ErrorCtor(ExecutionContext *scope, const QString &name) - : FunctionObject(scope, name) +ErrorCtor::Data::Data(ExecutionContext *scope, const QString &name) + : FunctionObject::Data(scope, name) { setVTable(staticVTable()); } @@ -281,8 +277,8 @@ ReturnedValue ErrorCtor::call(Managed *that, CallData *callData) return static_cast<Object *>(that)->construct(callData); } -EvalErrorCtor::EvalErrorCtor(ExecutionContext *scope) - : ErrorCtor(scope, QStringLiteral("EvalError")) +EvalErrorCtor::Data::Data(ExecutionContext *scope) + : ErrorCtor::Data(scope, QStringLiteral("EvalError")) { setVTable(staticVTable()); } @@ -291,11 +287,11 @@ ReturnedValue EvalErrorCtor::construct(Managed *m, CallData *callData) { Scope scope(m->engine()); ScopedValue v(scope, callData->argument(0)); - return (new (m->engine()->memoryManager) EvalErrorObject(m->engine(), v))->asReturnedValue(); + return (m->engine()->memoryManager->alloc<EvalErrorObject>(m->engine(), v))->asReturnedValue(); } -RangeErrorCtor::RangeErrorCtor(ExecutionContext *scope) - : ErrorCtor(scope, QStringLiteral("RangeError")) +RangeErrorCtor::Data::Data(ExecutionContext *scope) + : ErrorCtor::Data(scope, QStringLiteral("RangeError")) { setVTable(staticVTable()); } @@ -304,11 +300,11 @@ ReturnedValue RangeErrorCtor::construct(Managed *m, CallData *callData) { Scope scope(m->engine()); ScopedValue v(scope, callData->argument(0)); - return (new (m->engine()->memoryManager) RangeErrorObject(scope.engine, v))->asReturnedValue(); + return (m->engine()->memoryManager->alloc<RangeErrorObject>(scope.engine, v))->asReturnedValue(); } -ReferenceErrorCtor::ReferenceErrorCtor(ExecutionContext *scope) - : ErrorCtor(scope, QStringLiteral("ReferenceError")) +ReferenceErrorCtor::Data::Data(ExecutionContext *scope) + : ErrorCtor::Data(scope, QStringLiteral("ReferenceError")) { setVTable(staticVTable()); } @@ -317,11 +313,11 @@ ReturnedValue ReferenceErrorCtor::construct(Managed *m, CallData *callData) { Scope scope(m->engine()); ScopedValue v(scope, callData->argument(0)); - return (new (m->engine()->memoryManager) ReferenceErrorObject(scope.engine, v))->asReturnedValue(); + return (m->engine()->memoryManager->alloc<ReferenceErrorObject>(scope.engine, v))->asReturnedValue(); } -SyntaxErrorCtor::SyntaxErrorCtor(ExecutionContext *scope) - : ErrorCtor(scope, QStringLiteral("SyntaxError")) +SyntaxErrorCtor::Data::Data(ExecutionContext *scope) + : ErrorCtor::Data(scope, QStringLiteral("SyntaxError")) { setVTable(staticVTable()); } @@ -330,11 +326,11 @@ ReturnedValue SyntaxErrorCtor::construct(Managed *m, CallData *callData) { Scope scope(m->engine()); ScopedValue v(scope, callData->argument(0)); - return (new (m->engine()->memoryManager) SyntaxErrorObject(scope.engine, v))->asReturnedValue(); + return (m->engine()->memoryManager->alloc<SyntaxErrorObject>(scope.engine, v))->asReturnedValue(); } -TypeErrorCtor::TypeErrorCtor(ExecutionContext *scope) - : ErrorCtor(scope, QStringLiteral("TypeError")) +TypeErrorCtor::Data::Data(ExecutionContext *scope) + : ErrorCtor::Data(scope, QStringLiteral("TypeError")) { setVTable(staticVTable()); } @@ -343,11 +339,11 @@ ReturnedValue TypeErrorCtor::construct(Managed *m, CallData *callData) { Scope scope(m->engine()); ScopedValue v(scope, callData->argument(0)); - return (new (m->engine()->memoryManager) TypeErrorObject(scope.engine, v))->asReturnedValue(); + return (m->engine()->memoryManager->alloc<TypeErrorObject>(scope.engine, v))->asReturnedValue(); } -URIErrorCtor::URIErrorCtor(ExecutionContext *scope) - : ErrorCtor(scope, QStringLiteral("URIError")) +URIErrorCtor::Data::Data(ExecutionContext *scope) + : ErrorCtor::Data(scope, QStringLiteral("URIError")) { setVTable(staticVTable()); } @@ -356,10 +352,10 @@ ReturnedValue URIErrorCtor::construct(Managed *m, CallData *callData) { Scope scope(m->engine()); ScopedValue v(scope, callData->argument(0)); - return (new (m->engine()->memoryManager) URIErrorObject(scope.engine, v))->asReturnedValue(); + return (m->engine()->memoryManager->alloc<URIErrorObject>(scope.engine, v))->asReturnedValue(); } -void ErrorPrototype::init(ExecutionEngine *engine, ObjectRef ctor, Object *obj) +void ErrorPrototype::init(ExecutionEngine *engine, Object *ctor, Object *obj) { Scope scope(engine); ScopedString s(scope); @@ -375,19 +371,19 @@ ReturnedValue ErrorPrototype::method_toString(CallContext *ctx) { Scope scope(ctx); - Object *o = ctx->callData->thisObject.asObject(); + Object *o = ctx->d()->callData->thisObject.asObject(); if (!o) return ctx->throwTypeError(); - ScopedValue name(scope, o->get(ctx->engine->id_name)); + ScopedValue name(scope, o->get(ctx->d()->engine->id_name)); QString qname; if (name->isUndefined()) qname = QString::fromLatin1("Error"); else qname = name->toQString(); - ScopedString s(scope, ctx->engine->newString(QString::fromLatin1("message"))); - ScopedValue message(scope, o->get(s)); + ScopedString s(scope, ctx->d()->engine->newString(QString::fromLatin1("message"))); + ScopedValue message(scope, o->get(s.getPointer())); QString qmessage; if (!message->isUndefined()) qmessage = message->toQString(); @@ -401,5 +397,5 @@ ReturnedValue ErrorPrototype::method_toString(CallContext *ctx) str = qname + QLatin1String(": ") + qmessage; } - return ctx->engine->newString(str)->asReturnedValue(); + return ctx->d()->engine->newString(str)->asReturnedValue(); } diff --git a/src/qml/jsruntime/qv4errorobject_p.h b/src/qml/jsruntime/qv4errorobject_p.h index c44cc5cdb2..ddf30d2059 100644 --- a/src/qml/jsruntime/qv4errorobject_p.h +++ b/src/qml/jsruntime/qv4errorobject_p.h @@ -51,8 +51,6 @@ namespace QV4 { struct SyntaxErrorObject; struct ErrorObject: Object { - V4_OBJECT - Q_MANAGED_TYPE(ErrorObject) enum { IsErrorObject = true }; @@ -66,17 +64,19 @@ struct ErrorObject: Object { TypeError, URIError }; - - ErrorObject(InternalClass *ic); - ErrorObject(InternalClass *ic, const ValueRef message, ErrorType t = Error); - ErrorObject(InternalClass *ic, const QString &message, ErrorType t = Error); - ErrorObject(InternalClass *ic, const QString &message, const QString &fileName, int line, int column, ErrorType t = Error); + struct Data : Object::Data { + Data(InternalClass *ic); + Data(InternalClass *ic, const ValueRef message, ErrorType t = Error); + Data(InternalClass *ic, const QString &message, ErrorType t = Error); + Data(InternalClass *ic, const QString &message, const QString &fileName, int line, int column, ErrorType t = Error); + StackTrace stackTrace; + String *stack; + }; + V4_OBJECT(Object) + Q_MANAGED_TYPE(ErrorObject) SyntaxErrorObject *asSyntaxError(); - StackTrace stackTrace; - String *stack; - static ReturnedValue method_get_stack(CallContext *ctx); static void markObjects(Managed *that, ExecutionEngine *e); static void destroy(Managed *that) { static_cast<ErrorObject *>(that)->~ErrorObject(); } @@ -88,40 +88,55 @@ inline ErrorObject *value_cast(const Value &v) { } struct EvalErrorObject: ErrorObject { - EvalErrorObject(ExecutionEngine *engine, const ValueRef message); + struct Data : ErrorObject::Data { + Data(ExecutionEngine *engine, const ValueRef message); + }; }; struct RangeErrorObject: ErrorObject { - RangeErrorObject(ExecutionEngine *engine, const ValueRef message); - RangeErrorObject(ExecutionEngine *engine, const QString &msg); + struct Data : ErrorObject::Data { + Data(ExecutionEngine *engine, const ValueRef message); + Data(ExecutionEngine *engine, const QString &msg); + }; }; struct ReferenceErrorObject: ErrorObject { - ReferenceErrorObject(ExecutionEngine *engine, const ValueRef message); - ReferenceErrorObject(ExecutionEngine *engine, const QString &msg); - ReferenceErrorObject(ExecutionEngine *engine, const QString &msg, const QString &fileName, int lineNumber, int columnNumber); + struct Data : ErrorObject::Data { + Data(ExecutionEngine *engine, const ValueRef message); + Data(ExecutionEngine *engine, const QString &msg); + Data(ExecutionEngine *engine, const QString &msg, const QString &fileName, int lineNumber, int columnNumber); + }; }; struct SyntaxErrorObject: ErrorObject { - V4_OBJECT - SyntaxErrorObject(ExecutionEngine *engine, const ValueRef msg); - SyntaxErrorObject(ExecutionEngine *engine, const QString &msg, const QString &fileName, int lineNumber, int columnNumber); + struct Data : ErrorObject::Data { + Data(ExecutionEngine *engine, const ValueRef message); + Data(ExecutionEngine *engine, const QString &msg, const QString &fileName, int lineNumber, int columnNumber); + }; + V4_OBJECT(ErrorObject) }; struct TypeErrorObject: ErrorObject { - TypeErrorObject(ExecutionEngine *engine, const ValueRef message); - TypeErrorObject(ExecutionEngine *engine, const QString &msg); + struct Data : ErrorObject::Data { + Data(ExecutionEngine *engine, const ValueRef message); + Data(ExecutionEngine *engine, const QString &msg); + }; }; struct URIErrorObject: ErrorObject { - URIErrorObject(ExecutionEngine *engine, const ValueRef message); + struct Data : ErrorObject::Data { + Data(ExecutionEngine *engine, const ValueRef message); + }; }; struct ErrorCtor: FunctionObject { - V4_OBJECT - ErrorCtor(ExecutionContext *scope); - ErrorCtor(ExecutionContext *scope, const QString &name); + struct Data : FunctionObject::Data { + Data(ExecutionContext *scope); + Data(ExecutionContext *scope, const QString &name); + }; + + V4_OBJECT(FunctionObject) static ReturnedValue construct(Managed *, CallData *callData); static ReturnedValue call(Managed *that, CallData *callData); @@ -129,103 +144,107 @@ struct ErrorCtor: FunctionObject struct EvalErrorCtor: ErrorCtor { - V4_OBJECT - EvalErrorCtor(ExecutionContext *scope); + struct Data : ErrorCtor::Data { + Data(ExecutionContext *scope); + }; + V4_OBJECT(ErrorCtor) static ReturnedValue construct(Managed *m, CallData *callData); }; struct RangeErrorCtor: ErrorCtor { - V4_OBJECT - RangeErrorCtor(ExecutionContext *scope); + struct Data : ErrorCtor::Data { + Data(ExecutionContext *scope); + }; + V4_OBJECT(ErrorCtor) static ReturnedValue construct(Managed *m, CallData *callData); }; struct ReferenceErrorCtor: ErrorCtor { - V4_OBJECT - ReferenceErrorCtor(ExecutionContext *scope); + struct Data : ErrorCtor::Data { + Data(ExecutionContext *scope); + }; + V4_OBJECT(ErrorCtor) static ReturnedValue construct(Managed *m, CallData *callData); }; struct SyntaxErrorCtor: ErrorCtor { - V4_OBJECT - SyntaxErrorCtor(ExecutionContext *scope); + struct Data : ErrorCtor::Data { + Data(ExecutionContext *scope); + }; + V4_OBJECT(ErrorCtor) static ReturnedValue construct(Managed *m, CallData *callData); }; struct TypeErrorCtor: ErrorCtor { - V4_OBJECT - TypeErrorCtor(ExecutionContext *scope); + struct Data : ErrorCtor::Data { + Data(ExecutionContext *scope); + }; + V4_OBJECT(ErrorCtor) static ReturnedValue construct(Managed *m, CallData *callData); }; struct URIErrorCtor: ErrorCtor { - V4_OBJECT - URIErrorCtor(ExecutionContext *scope); + struct Data : ErrorCtor::Data { + Data(ExecutionContext *scope); + }; + V4_OBJECT(ErrorCtor) static ReturnedValue construct(Managed *m, CallData *callData); }; -struct ErrorPrototype: ErrorObject +struct ErrorPrototype : ErrorObject { - // ### shouldn't be undefined - ErrorPrototype(InternalClass *ic): ErrorObject(ic) {} - void init(ExecutionEngine *engine, ObjectRef ctor) { init(engine, ctor, this); } + void init(ExecutionEngine *engine, Object *ctor) { init(engine, ctor, this); } - static void init(ExecutionEngine *engine, ObjectRef ctor, Object *obj); + static void init(ExecutionEngine *engine, Object *ctor, Object *obj); static ReturnedValue method_toString(CallContext *ctx); }; -struct EvalErrorPrototype: ErrorObject +struct EvalErrorPrototype : ErrorObject { - EvalErrorPrototype(InternalClass *ic): ErrorObject(ic) { setVTable(staticVTable()); } - void init(ExecutionEngine *engine, ObjectRef ctor) { ErrorPrototype::init(engine, ctor, this); } + void init(ExecutionEngine *engine, Object *ctor) { ErrorPrototype::init(engine, ctor, this); } }; -struct RangeErrorPrototype: ErrorObject +struct RangeErrorPrototype : ErrorObject { - RangeErrorPrototype(InternalClass *ic): ErrorObject(ic) { setVTable(staticVTable()); } - void init(ExecutionEngine *engine, ObjectRef ctor) { ErrorPrototype::init(engine, ctor, this); } + void init(ExecutionEngine *engine, Object *ctor) { ErrorPrototype::init(engine, ctor, this); } }; -struct ReferenceErrorPrototype: ErrorObject +struct ReferenceErrorPrototype : ErrorObject { - ReferenceErrorPrototype(InternalClass *ic): ErrorObject(ic) { setVTable(staticVTable()); } - void init(ExecutionEngine *engine, ObjectRef ctor) { ErrorPrototype::init(engine, ctor, this); } + void init(ExecutionEngine *engine, Object *ctor) { ErrorPrototype::init(engine, ctor, this); } }; -struct SyntaxErrorPrototype: ErrorObject +struct SyntaxErrorPrototype : ErrorObject { - SyntaxErrorPrototype(InternalClass *ic): ErrorObject(ic) { setVTable(staticVTable()); } - void init(ExecutionEngine *engine, ObjectRef ctor) { ErrorPrototype::init(engine, ctor, this); } + void init(ExecutionEngine *engine, Object *ctor) { ErrorPrototype::init(engine, ctor, this); } }; -struct TypeErrorPrototype: ErrorObject +struct TypeErrorPrototype : ErrorObject { - TypeErrorPrototype(InternalClass *ic): ErrorObject(ic) { setVTable(staticVTable()); } - void init(ExecutionEngine *engine, ObjectRef ctor) { ErrorPrototype::init(engine, ctor, this); } + void init(ExecutionEngine *engine, Object *ctor) { ErrorPrototype::init(engine, ctor, this); } }; -struct URIErrorPrototype: ErrorObject +struct URIErrorPrototype : ErrorObject { - URIErrorPrototype(InternalClass *ic): ErrorObject(ic) { setVTable(staticVTable()); } - void init(ExecutionEngine *engine, ObjectRef ctor) { ErrorPrototype::init(engine, ctor, this); } + void init(ExecutionEngine *engine, Object *ctor) { ErrorPrototype::init(engine, ctor, this); } }; inline SyntaxErrorObject *ErrorObject::asSyntaxError() { - return subtype == SyntaxError ? static_cast<SyntaxErrorObject *>(this) : 0; + return subtype() == SyntaxError ? static_cast<SyntaxErrorObject *>(this) : 0; } } diff --git a/src/qml/jsruntime/qv4function.cpp b/src/qml/jsruntime/qv4function.cpp index 6fdf61f2c3..bf77b4434c 100644 --- a/src/qml/jsruntime/qv4function.cpp +++ b/src/qml/jsruntime/qv4function.cpp @@ -45,6 +45,7 @@ #include "qv4value_inl_p.h" #include "qv4engine_p.h" #include "qv4lookup_p.h" +#include "qv4mm_p.h" QT_BEGIN_NAMESPACE @@ -62,6 +63,8 @@ Function::Function(ExecutionEngine *engine, CompiledData::CompilationUnit *unit, internalClass = engine->emptyClass; const quint32 *formalsIndices = compiledFunction->formalsTable(); // iterate backwards, so we get the right ordering for duplicate names + Scope scope(engine); + ScopedString s(scope); for (int i = static_cast<int>(compiledFunction->nFormals - 1); i >= 0; --i) { String *arg = compilationUnit->runtimeStrings[formalsIndices[i]].asString(); while (1) { @@ -71,7 +74,7 @@ Function::Function(ExecutionEngine *engine, CompiledData::CompilationUnit *unit, break; } // duplicate arguments, need some trick to store them - arg = new (engine->memoryManager) String(engine, arg, engine->newString(QString(0xfffe))->getPointer()); + arg = (s = engine->memoryManager->alloc<String>(engine, arg, engine->newString(QString(0xfffe))->getPointer())).getPointer(); } } diff --git a/src/qml/jsruntime/qv4function_p.h b/src/qml/jsruntime/qv4function_p.h index e6385d861c..482f247319 100644 --- a/src/qml/jsruntime/qv4function_p.h +++ b/src/qml/jsruntime/qv4function_p.h @@ -94,8 +94,8 @@ struct Q_QML_EXPORT Function { ReturnedValue (*codePtr)(ExecutionContext *, const uchar *)); ~Function(); - inline StringRef name() { - return compilationUnit->runtimeStrings[compiledFunction->nameIndex]; + inline String *name() { + return compilationUnit->runtimeStrings[compiledFunction->nameIndex].getPointer(); } inline QString sourceFile() const { return compilationUnit->fileName(); } diff --git a/src/qml/jsruntime/qv4functionobject.cpp b/src/qml/jsruntime/qv4functionobject.cpp index 39a123c4d2..10974780f3 100644 --- a/src/qml/jsruntime/qv4functionobject.cpp +++ b/src/qml/jsruntime/qv4functionobject.cpp @@ -74,88 +74,88 @@ using namespace QV4; DEFINE_OBJECT_VTABLE(FunctionObject); -FunctionObject::FunctionObject(ExecutionContext *scope, const StringRef name, bool createProto) - : Object(scope->engine->functionClass) +FunctionObject::Data::Data(ExecutionContext *scope, String *name, bool createProto) + : Object::Data(scope->d()->engine->functionClass) , scope(scope) - , function(0) { - init(name, createProto); + Scope s(scope); + ScopedFunctionObject f(s, this); + f->init(name, createProto); } -FunctionObject::FunctionObject(ExecutionContext *scope, const QString &name, bool createProto) - : Object(scope->engine->functionClass) + +FunctionObject::Data::Data(ExecutionContext *scope, const QString &name, bool createProto) + : Object::Data(scope->d()->engine->functionClass) , scope(scope) - , function(0) { Scope s(scope); - ScopedValue protectThis(s, this); + ScopedFunctionObject f(s, this); ScopedString n(s, s.engine->newString(name)); - init(n, createProto); + f->init(n.getPointer(), createProto); } -FunctionObject::FunctionObject(ExecutionContext *scope, const ReturnedValue name) - : Object(scope->engine->functionClass) +FunctionObject::Data::Data(ExecutionContext *scope, const ReturnedValue name) + : Object::Data(scope->d()->engine->functionClass) , scope(scope) - , function(0) { Scope s(scope); - ScopedValue protectThis(s, this); + ScopedFunctionObject f(s, this); ScopedString n(s, name); - init(n, false); + f->init(n.getPointer(), false); } -FunctionObject::FunctionObject(InternalClass *ic) - : Object(ic) +FunctionObject::Data::Data(InternalClass *ic) + : Object::Data(ic) , scope(ic->engine->rootContext) - , function(0) { - needsActivation = false; - strictMode = false; + memberData.ensureIndex(ic->engine, Index_Prototype); memberData[Index_Prototype] = Encode::undefined(); } -FunctionObject::~FunctionObject() + +FunctionObject::Data::~Data() { if (function) function->compilationUnit->deref(); } -void FunctionObject::init(const StringRef n, bool createProto) +void FunctionObject::init(String *n, bool createProto) { - Scope s(internalClass->engine); + Scope s(internalClass()->engine); ScopedValue protectThis(s, this); - needsActivation = true; - strictMode = false; + d()->needsActivation = true; + d()->strictMode = false; + memberData().ensureIndex(s.engine, Index_Prototype); if (createProto) { - Scoped<Object> proto(s, scope->engine->newObject(scope->engine->protoClass)); - proto->memberData[Index_ProtoConstructor] = this->asReturnedValue(); - memberData[Index_Prototype] = proto.asReturnedValue(); + Scoped<Object> proto(s, scope()->d()->engine->newObject(scope()->d()->engine->protoClass)); + proto->memberData()[Index_ProtoConstructor] = this->asReturnedValue(); + memberData()[Index_Prototype] = proto.asReturnedValue(); } else { - memberData[Index_Prototype] = Encode::undefined(); + memberData()[Index_Prototype] = Encode::undefined(); } - ScopedValue v(s, n.asReturnedValue()); - defineReadonlyProperty(scope->engine->id_name, v); + ScopedValue v(s, n); + defineReadonlyProperty(s.engine->id_name, v); } ReturnedValue FunctionObject::name() { - return get(scope->engine->id_name); + return get(scope()->d()->engine->id_name); } ReturnedValue FunctionObject::newInstance() { - Scope scope(internalClass->engine); + Scope scope(internalClass()->engine); ScopedCallData callData(scope, 0); return construct(callData); } ReturnedValue FunctionObject::construct(Managed *that, CallData *) { - that->internalClass->engine->currentContext()->throwTypeError(); + that->internalClass()->engine->currentContext()->throwTypeError(); return Encode::undefined(); } @@ -167,8 +167,8 @@ ReturnedValue FunctionObject::call(Managed *, CallData *) void FunctionObject::markObjects(Managed *that, ExecutionEngine *e) { FunctionObject *o = static_cast<FunctionObject *>(that); - if (o->scope) - o->scope->mark(e); + if (o->scope()) + o->scope()->mark(e); Object::markObjects(that, e); } @@ -179,14 +179,14 @@ FunctionObject *FunctionObject::createScriptFunction(ExecutionContext *scope, Fu function->compiledFunction->flags & CompiledData::Function::HasCatchOrWith || function->compiledFunction->nFormals > QV4::Global::ReservedArgumentCount || function->isNamedExpression()) - return new (scope->engine->memoryManager) ScriptFunction(scope, function); - return new (scope->engine->memoryManager) SimpleScriptFunction(scope, function, createProto); + return scope->d()->engine->memoryManager->alloc<ScriptFunction>(scope, function); + return scope->d()->engine->memoryManager->alloc<SimpleScriptFunction>(scope, function, createProto); } DEFINE_OBJECT_VTABLE(FunctionCtor); -FunctionCtor::FunctionCtor(ExecutionContext *scope) - : FunctionObject(scope, QStringLiteral("Function")) +FunctionCtor::Data::Data(ExecutionContext *scope) + : FunctionObject::Data(scope, QStringLiteral("Function")) { setVTable(staticVTable()); } @@ -195,7 +195,7 @@ FunctionCtor::FunctionCtor(ExecutionContext *scope) ReturnedValue FunctionCtor::construct(Managed *that, CallData *callData) { FunctionCtor *f = static_cast<FunctionCtor *>(that); - ExecutionEngine *v4 = f->internalClass->engine; + ExecutionEngine *v4 = f->internalClass()->engine; ExecutionContext *ctx = v4->currentContext(); QString arguments; QString body; @@ -207,7 +207,7 @@ ReturnedValue FunctionCtor::construct(Managed *that, CallData *callData) } body = callData->args[callData->argc - 1].toString(ctx)->toQString(); } - if (ctx->engine->hasException) + if (ctx->d()->engine->hasException) return Encode::undefined(); QString function = QLatin1String("function(") + arguments + QLatin1String("){") + body + QLatin1String("}"); @@ -229,7 +229,7 @@ ReturnedValue FunctionCtor::construct(Managed *that, CallData *callData) IR::Module module(v4->debugger != 0); - QQmlJS::RuntimeCodegen cg(v4->currentContext(), f->strictMode); + QQmlJS::RuntimeCodegen cg(v4->currentContext(), f->strictMode()); cg.generateFromFunctionExpression(QString(), function, fe, &module); QV4::Compiler::JSUnitGenerator jsGenerator(&module); @@ -246,12 +246,14 @@ ReturnedValue FunctionCtor::call(Managed *that, CallData *callData) return construct(that, callData); } -FunctionPrototype::FunctionPrototype(InternalClass *ic) - : FunctionObject(ic) +DEFINE_OBJECT_VTABLE(FunctionPrototype); + +FunctionPrototype::Data::Data(InternalClass *ic) + : FunctionObject::Data(ic) { } -void FunctionPrototype::init(ExecutionEngine *engine, ObjectRef ctor) +void FunctionPrototype::init(ExecutionEngine *engine, Object *ctor) { Scope scope(engine); ScopedObject o(scope); @@ -270,17 +272,17 @@ void FunctionPrototype::init(ExecutionEngine *engine, ObjectRef ctor) ReturnedValue FunctionPrototype::method_toString(CallContext *ctx) { - FunctionObject *fun = ctx->callData->thisObject.asFunctionObject(); + FunctionObject *fun = ctx->d()->callData->thisObject.asFunctionObject(); if (!fun) return ctx->throwTypeError(); - return ctx->engine->newString(QStringLiteral("function() { [code] }"))->asReturnedValue(); + return ctx->d()->engine->newString(QStringLiteral("function() { [code] }"))->asReturnedValue(); } ReturnedValue FunctionPrototype::method_apply(CallContext *ctx) { Scope scope(ctx); - FunctionObject *o = ctx->callData->thisObject.asFunctionObject(); + FunctionObject *o = ctx->d()->callData->thisObject.asFunctionObject(); if (!o) return ctx->throwTypeError(); @@ -300,13 +302,13 @@ ReturnedValue FunctionPrototype::method_apply(CallContext *ctx) ScopedCallData callData(scope, len); if (len) { - if (arr->arrayType() != ArrayData::Simple || arr->protoHasArray() || arr->hasAccessorProperty) { + if (arr->arrayType() != ArrayData::Simple || arr->protoHasArray() || arr->hasAccessorProperty()) { for (quint32 i = 0; i < len; ++i) callData->args[i] = arr->getIndexed(i); } else { - int alen = qMin(len, arr->arrayData->length()); + int alen = qMin(len, arr->arrayData()->length()); if (alen) - memcpy(callData->args, arr->arrayData->data, alen*sizeof(Value)); + memcpy(callData->args, arr->arrayData()->arrayData(), alen*sizeof(Value)); for (quint32 i = alen; i < len; ++i) callData->args[i] = Primitive::undefinedValue(); } @@ -320,14 +322,14 @@ ReturnedValue FunctionPrototype::method_call(CallContext *ctx) { Scope scope(ctx); - FunctionObject *o = ctx->callData->thisObject.asFunctionObject(); + FunctionObject *o = ctx->d()->callData->thisObject.asFunctionObject(); if (!o) return ctx->throwTypeError(); - ScopedCallData callData(scope, ctx->callData->argc ? ctx->callData->argc - 1 : 0); - if (ctx->callData->argc) { - for (int i = 1; i < ctx->callData->argc; ++i) - callData->args[i - 1] = ctx->callData->args[i]; + ScopedCallData callData(scope, ctx->d()->callData->argc ? ctx->d()->callData->argc - 1 : 0); + if (ctx->d()->callData->argc) { + for (int i = 1; i < ctx->d()->callData->argc; ++i) + callData->args[i - 1] = ctx->d()->callData->args[i]; } callData->thisObject = ctx->argument(0); return o->call(callData); @@ -336,49 +338,34 @@ ReturnedValue FunctionPrototype::method_call(CallContext *ctx) ReturnedValue FunctionPrototype::method_bind(CallContext *ctx) { Scope scope(ctx); - Scoped<FunctionObject> target(scope, ctx->callData->thisObject); + Scoped<FunctionObject> target(scope, ctx->d()->callData->thisObject); if (!target) return ctx->throwTypeError(); ScopedValue boundThis(scope, ctx->argument(0)); - QVector<Value> boundArgs; - for (int i = 1; i < ctx->callData->argc; ++i) - boundArgs += ctx->callData->args[i]; + Members boundArgs; + boundArgs.reset(); + if (ctx->d()->callData->argc > 1) { + boundArgs.ensureIndex(scope.engine, ctx->d()->callData->argc - 1); + boundArgs.d()->d()->size = ctx->d()->callData->argc - 1; + memcpy(boundArgs.data(), ctx->d()->callData->args + 1, (ctx->d()->callData->argc - 1)*sizeof(Value)); + } + ScopedValue protectBoundArgs(scope, boundArgs.d()); - return ctx->engine->newBoundFunction(ctx->engine->rootContext, target, boundThis, boundArgs)->asReturnedValue(); + return BoundFunction::create(ctx->d()->engine->rootContext, target, boundThis, boundArgs)->asReturnedValue(); } DEFINE_OBJECT_VTABLE(ScriptFunction); -ScriptFunction::ScriptFunction(ExecutionContext *scope, Function *function) - : SimpleScriptFunction(scope, function, true) +ScriptFunction::Data::Data(ExecutionContext *scope, Function *function) + : SimpleScriptFunction::Data(scope, function, true) { setVTable(staticVTable()); - - Scope s(scope); - ScopedValue protectThis(s, this); - - // global function - if (!scope) - return; - - ExecutionEngine *v4 = scope->engine; - - needsActivation = function->needsActivation(); - strictMode = function->isStrict(); - - defineReadonlyProperty(scope->engine->id_length, Primitive::fromInt32(formalParameterCount())); - - if (scope->strictMode) { - Property pd(v4->thrower, v4->thrower); - insertMember(scope->engine->id_caller, pd, Attr_Accessor|Attr_NotConfigurable|Attr_NotEnumerable); - insertMember(scope->engine->id_arguments, pd, Attr_Accessor|Attr_NotConfigurable|Attr_NotEnumerable); - } } ReturnedValue ScriptFunction::construct(Managed *that, CallData *callData) { - ExecutionEngine *v4 = that->internalClass->engine; + ExecutionEngine *v4 = that->engine(); if (v4->hasException) return Encode::undefined(); CHECK_STACK_LIMITS(v4); @@ -391,13 +378,13 @@ ReturnedValue ScriptFunction::construct(Managed *that, CallData *callData) ExecutionContext *context = v4->currentContext(); callData->thisObject = obj.asReturnedValue(); - ExecutionContext *ctx = context->newCallContext(f.getPointer(), callData); + ExecutionContext *ctx = reinterpret_cast<ExecutionContext *>(context->newCallContext(f.getPointer(), callData)); ExecutionContextSaver ctxSaver(context); - ScopedValue result(scope, Q_V4_PROFILE(v4, ctx, f->function)); + ScopedValue result(scope, Q_V4_PROFILE(v4, ctx, f->function())); - if (f->function->compiledFunction->hasQmlDependencies()) - QmlContextWrapper::registerQmlDependencies(v4, f->function->compiledFunction); + if (f->function()->compiledFunction->hasQmlDependencies()) + QmlContextWrapper::registerQmlDependencies(v4, f->function()->compiledFunction); if (result->isObject()) return result.asReturnedValue(); @@ -407,7 +394,7 @@ ReturnedValue ScriptFunction::construct(Managed *that, CallData *callData) ReturnedValue ScriptFunction::call(Managed *that, CallData *callData) { ScriptFunction *f = static_cast<ScriptFunction *>(that); - ExecutionEngine *v4 = f->internalClass->engine; + ExecutionEngine *v4 = f->engine(); if (v4->hasException) return Encode::undefined(); CHECK_STACK_LIMITS(v4); @@ -415,53 +402,51 @@ ReturnedValue ScriptFunction::call(Managed *that, CallData *callData) ExecutionContext *context = v4->currentContext(); Scope scope(context); - CallContext *ctx = context->newCallContext(f, callData); + CallContext *ctx = reinterpret_cast<CallContext *>(context->newCallContext(f, callData)); ExecutionContextSaver ctxSaver(context); - ScopedValue result(scope, Q_V4_PROFILE(v4, ctx, f->function)); + ScopedValue result(scope, Q_V4_PROFILE(v4, ctx, f->function())); - if (f->function->compiledFunction->hasQmlDependencies()) - QmlContextWrapper::registerQmlDependencies(ctx->engine, f->function->compiledFunction); + if (f->function()->compiledFunction->hasQmlDependencies()) + QmlContextWrapper::registerQmlDependencies(ctx->d()->engine, f->function()->compiledFunction); return result.asReturnedValue(); } DEFINE_OBJECT_VTABLE(SimpleScriptFunction); -SimpleScriptFunction::SimpleScriptFunction(ExecutionContext *scope, Function *function, bool createProto) - : FunctionObject(scope, function->name(), createProto) +SimpleScriptFunction::Data::Data(ExecutionContext *scope, Function *function, bool createProto) + : FunctionObject::Data(scope, function->name(), createProto) { setVTable(staticVTable()); - Scope s(scope); - ScopedValue protectThis(s, this); - this->function = function; - this->function->compilationUnit->ref(); + function->compilationUnit->ref(); Q_ASSERT(function); Q_ASSERT(function->code); + needsActivation = function->needsActivation(); + strictMode = function->isStrict(); + // global function if (!scope) return; - ExecutionEngine *v4 = scope->engine; - - needsActivation = function->needsActivation(); - strictMode = function->isStrict(); + Scope s(scope); + ScopedFunctionObject f(s, this); - defineReadonlyProperty(scope->engine->id_length, Primitive::fromInt32(formalParameterCount())); + f->defineReadonlyProperty(scope->d()->engine->id_length, Primitive::fromInt32(f->formalParameterCount())); - if (scope->strictMode) { - Property pd(v4->thrower, v4->thrower); - insertMember(scope->engine->id_caller, pd, Attr_Accessor|Attr_NotConfigurable|Attr_NotEnumerable); - insertMember(scope->engine->id_arguments, pd, Attr_Accessor|Attr_NotConfigurable|Attr_NotEnumerable); + if (scope->d()->strictMode) { + Property pd(s.engine->thrower, s.engine->thrower); + f->insertMember(scope->d()->engine->id_caller, pd, Attr_Accessor|Attr_NotConfigurable|Attr_NotEnumerable); + f->insertMember(scope->d()->engine->id_arguments, pd, Attr_Accessor|Attr_NotConfigurable|Attr_NotEnumerable); } } ReturnedValue SimpleScriptFunction::construct(Managed *that, CallData *callData) { - ExecutionEngine *v4 = that->internalClass->engine; + ExecutionEngine *v4 = that->engine(); if (v4->hasException) return Encode::undefined(); CHECK_STACK_LIMITS(v4); @@ -475,24 +460,24 @@ ReturnedValue SimpleScriptFunction::construct(Managed *that, CallData *callData) ExecutionContext *context = v4->currentContext(); ExecutionContextSaver ctxSaver(context); - CallContext ctx(v4); - ctx.strictMode = f->strictMode; + CallContext::Data ctx(v4); + ctx.strictMode = f->strictMode(); ctx.callData = callData; ctx.function = f.getPointer(); - ctx.compilationUnit = f->function->compilationUnit; + ctx.compilationUnit = f->function()->compilationUnit; ctx.lookups = ctx.compilationUnit->runtimeLookups; - ctx.outer = f->scope; + ctx.outer = f->scope(); ctx.locals = v4->stackPush(f->varCount()); while (callData->argc < (int)f->formalParameterCount()) { callData->args[callData->argc] = Encode::undefined(); ++callData->argc; } - Q_ASSERT(v4->currentContext() == &ctx); + Q_ASSERT(v4->currentContext()->d() == &ctx); - Scoped<Object> result(scope, Q_V4_PROFILE(v4, &ctx, f->function)); + Scoped<Object> result(scope, Q_V4_PROFILE(v4, reinterpret_cast<CallContext *>(&ctx), f->function())); - if (f->function->compiledFunction->hasQmlDependencies()) - QmlContextWrapper::registerQmlDependencies(v4, f->function->compiledFunction); + if (f->function()->compiledFunction->hasQmlDependencies()) + QmlContextWrapper::registerQmlDependencies(v4, f->function()->compiledFunction); if (!result) return callData->thisObject.asReturnedValue(); @@ -501,7 +486,7 @@ ReturnedValue SimpleScriptFunction::construct(Managed *that, CallData *callData) ReturnedValue SimpleScriptFunction::call(Managed *that, CallData *callData) { - ExecutionEngine *v4 = that->internalClass->engine; + ExecutionEngine *v4 = that->internalClass()->engine; if (v4->hasException) return Encode::undefined(); CHECK_STACK_LIMITS(v4); @@ -512,24 +497,24 @@ ReturnedValue SimpleScriptFunction::call(Managed *that, CallData *callData) ExecutionContext *context = v4->currentContext(); ExecutionContextSaver ctxSaver(context); - CallContext ctx(v4); - ctx.strictMode = f->strictMode; + CallContext::Data ctx(v4); + ctx.strictMode = f->strictMode(); ctx.callData = callData; ctx.function = f; - ctx.compilationUnit = f->function->compilationUnit; + ctx.compilationUnit = f->function()->compilationUnit; ctx.lookups = ctx.compilationUnit->runtimeLookups; - ctx.outer = f->scope; + ctx.outer = f->scope(); ctx.locals = v4->stackPush(f->varCount()); while (callData->argc < (int)f->formalParameterCount()) { callData->args[callData->argc] = Encode::undefined(); ++callData->argc; } - Q_ASSERT(v4->currentContext() == &ctx); + Q_ASSERT(v4->currentContext()->d() == &ctx); - ScopedValue result(scope, Q_V4_PROFILE(v4, &ctx, f->function)); + ScopedValue result(scope, Q_V4_PROFILE(v4, reinterpret_cast<CallContext *>(&ctx), f->function())); - if (f->function->compiledFunction->hasQmlDependencies()) - QmlContextWrapper::registerQmlDependencies(v4, f->function->compiledFunction); + if (f->function()->compiledFunction->hasQmlDependencies()) + QmlContextWrapper::registerQmlDependencies(v4, f->function()->compiledFunction); return result.asReturnedValue(); } @@ -538,10 +523,10 @@ InternalClass *SimpleScriptFunction::internalClassForConstructor() { ReturnedValue proto = protoProperty(); InternalClass *classForConstructor; - Scope scope(internalClass->engine); + Scope scope(internalClass()->engine); ScopedObject p(scope, proto); if (p) - classForConstructor = internalClass->engine->constructClass->changePrototype(p.getPointer()); + classForConstructor = internalClass()->engine->constructClass->changePrototype(p.getPointer()); else classForConstructor = scope.engine->objectClass; @@ -552,8 +537,8 @@ InternalClass *SimpleScriptFunction::internalClassForConstructor() DEFINE_OBJECT_VTABLE(BuiltinFunction); -BuiltinFunction::BuiltinFunction(ExecutionContext *scope, const StringRef name, ReturnedValue (*code)(CallContext *)) - : FunctionObject(scope, name) +BuiltinFunction::Data::Data(ExecutionContext *scope, String *name, ReturnedValue (*code)(CallContext *)) + : FunctionObject::Data(scope, name) , code(code) { setVTable(staticVTable()); @@ -561,13 +546,13 @@ BuiltinFunction::BuiltinFunction(ExecutionContext *scope, const StringRef name, ReturnedValue BuiltinFunction::construct(Managed *f, CallData *) { - return f->internalClass->engine->currentContext()->throwTypeError(); + return f->internalClass()->engine->currentContext()->throwTypeError(); } ReturnedValue BuiltinFunction::call(Managed *that, CallData *callData) { BuiltinFunction *f = static_cast<BuiltinFunction *>(that); - ExecutionEngine *v4 = f->internalClass->engine; + ExecutionEngine *v4 = f->internalClass()->engine; if (v4->hasException) return Encode::undefined(); CHECK_STACK_LIMITS(v4); @@ -575,18 +560,18 @@ ReturnedValue BuiltinFunction::call(Managed *that, CallData *callData) ExecutionContext *context = v4->currentContext(); ExecutionContextSaver ctxSaver(context); - CallContext ctx(v4); - ctx.strictMode = f->scope->strictMode; // ### needed? scope or parent context? + CallContext::Data ctx(v4); + ctx.strictMode = f->scope()->d()->strictMode; // ### needed? scope or parent context? ctx.callData = callData; - Q_ASSERT(v4->currentContext() == &ctx); + Q_ASSERT(v4->currentContext()->d() == &ctx); - return f->code(&ctx); + return f->d()->code(reinterpret_cast<CallContext *>(&ctx)); } ReturnedValue IndexedBuiltinFunction::call(Managed *that, CallData *callData) { IndexedBuiltinFunction *f = static_cast<IndexedBuiltinFunction *>(that); - ExecutionEngine *v4 = f->internalClass->engine; + ExecutionEngine *v4 = f->internalClass()->engine; if (v4->hasException) return Encode::undefined(); CHECK_STACK_LIMITS(v4); @@ -594,82 +579,76 @@ ReturnedValue IndexedBuiltinFunction::call(Managed *that, CallData *callData) ExecutionContext *context = v4->currentContext(); ExecutionContextSaver ctxSaver(context); - CallContext ctx(v4); - ctx.strictMode = f->scope->strictMode; // ### needed? scope or parent context? + CallContext::Data ctx(v4); + ctx.strictMode = f->scope()->d()->strictMode; // ### needed? scope or parent context? ctx.callData = callData; - Q_ASSERT(v4->currentContext() == &ctx); + Q_ASSERT(v4->currentContext()->d() == &ctx); - return f->code(&ctx, f->index); + return f->d()->code(reinterpret_cast<CallContext *>(&ctx), f->d()->index); } DEFINE_OBJECT_VTABLE(IndexedBuiltinFunction); DEFINE_OBJECT_VTABLE(BoundFunction); -BoundFunction::BoundFunction(ExecutionContext *scope, FunctionObjectRef target, const ValueRef boundThis, const QVector<Value> &boundArgs) - : FunctionObject(scope, QStringLiteral("__bound function__")) +BoundFunction::Data::Data(ExecutionContext *scope, FunctionObject *target, const ValueRef boundThis, const Members &boundArgs) + : FunctionObject::Data(scope, QStringLiteral("__bound function__")) , target(target) , boundArgs(boundArgs) { + this->boundThis = boundThis; setVTable(staticVTable()); subtype = FunctionObject::BoundFunction; - this->boundThis = boundThis; Scope s(scope); - ScopedValue protectThis(s, this); + ScopedObject f(s, this); - ScopedValue l(s, target->get(scope->engine->id_length)); + ScopedValue l(s, target->get(s.engine->id_length)); int len = l->toUInt32(); len -= boundArgs.size(); if (len < 0) len = 0; - defineReadonlyProperty(scope->engine->id_length, Primitive::fromInt32(len)); + f->defineReadonlyProperty(s.engine->id_length, Primitive::fromInt32(len)); - ExecutionEngine *v4 = scope->engine; + ExecutionEngine *v4 = s.engine; Property pd(v4->thrower, v4->thrower); - insertMember(scope->engine->id_arguments, pd, Attr_Accessor|Attr_NotConfigurable|Attr_NotEnumerable); - insertMember(scope->engine->id_caller, pd, Attr_Accessor|Attr_NotConfigurable|Attr_NotEnumerable); -} - -void BoundFunction::destroy(Managed *that) -{ - static_cast<BoundFunction *>(that)->~BoundFunction(); + f->insertMember(s.engine->id_arguments, pd, Attr_Accessor|Attr_NotConfigurable|Attr_NotEnumerable); + f->insertMember(s.engine->id_caller, pd, Attr_Accessor|Attr_NotConfigurable|Attr_NotEnumerable); } ReturnedValue BoundFunction::call(Managed *that, CallData *dd) { BoundFunction *f = static_cast<BoundFunction *>(that); - Scope scope(f->scope->engine); + Scope scope(f->scope()->d()->engine); if (scope.hasException()) return Encode::undefined(); - ScopedCallData callData(scope, f->boundArgs.size() + dd->argc); - callData->thisObject = f->boundThis; - memcpy(callData->args, f->boundArgs.constData(), f->boundArgs.size()*sizeof(Value)); - memcpy(callData->args + f->boundArgs.size(), dd->args, dd->argc*sizeof(Value)); - return f->target->call(callData); + ScopedCallData callData(scope, f->boundArgs().size() + dd->argc); + callData->thisObject = f->boundThis(); + memcpy(callData->args, f->boundArgs().data(), f->boundArgs().size()*sizeof(Value)); + memcpy(callData->args + f->boundArgs().size(), dd->args, dd->argc*sizeof(Value)); + return f->target()->call(callData); } ReturnedValue BoundFunction::construct(Managed *that, CallData *dd) { BoundFunction *f = static_cast<BoundFunction *>(that); - Scope scope(f->scope->engine); + Scope scope(f->scope()->d()->engine); if (scope.hasException()) return Encode::undefined(); - ScopedCallData callData(scope, f->boundArgs.size() + dd->argc); - memcpy(callData->args, f->boundArgs.constData(), f->boundArgs.size()*sizeof(Value)); - memcpy(callData->args + f->boundArgs.size(), dd->args, dd->argc*sizeof(Value)); - return f->target->construct(callData); + ScopedCallData callData(scope, f->boundArgs().size() + dd->argc); + memcpy(callData->args, f->boundArgs().data(), f->boundArgs().size()*sizeof(Value)); + memcpy(callData->args + f->boundArgs().size(), dd->args, dd->argc*sizeof(Value)); + return f->target()->construct(callData); } void BoundFunction::markObjects(Managed *that, ExecutionEngine *e) { BoundFunction *o = static_cast<BoundFunction *>(that); - o->target->mark(e); - o->boundThis.mark(e); - for (int i = 0; i < o->boundArgs.size(); ++i) - o->boundArgs.at(i).mark(e); + o->target()->mark(e); + o->boundThis().mark(e); + 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 5b832d0595..907b660911 100644 --- a/src/qml/jsruntime/qv4functionobject_p.h +++ b/src/qml/jsruntime/qv4functionobject_p.h @@ -51,6 +51,7 @@ #include "qv4property_p.h" #include "qv4function_p.h" #include "qv4objectiterator_p.h" +#include "qv4mm_p.h" #include <QtCore/QString> #include <QtCore/QHash> @@ -94,7 +95,17 @@ struct InternalClass; struct Lookup; struct Q_QML_EXPORT FunctionObject: Object { - V4_OBJECT + struct Q_QML_PRIVATE_EXPORT Data : Object::Data { + Data(ExecutionContext *scope, String *name, bool createProto = false); + Data(ExecutionContext *scope, const QString &name = QString(), bool createProto = false); + Data(ExecutionContext *scope, const ReturnedValue name); + Data(InternalClass *ic); + ~Data(); + + ExecutionContext *scope; + Function *function; + }; + V4_OBJECT(Object) Q_MANAGED_TYPE(FunctionObject) enum { IsFunctionObject = true @@ -111,18 +122,15 @@ struct Q_QML_EXPORT FunctionObject: Object { Index_ProtoConstructor = 0 }; - ExecutionContext *scope; - ReturnedValue name(); - unsigned int formalParameterCount() { return function ? function->compiledFunction->nFormals : 0; } - unsigned int varCount() { return function ? function->compiledFunction->nLocals : 0; } - Function *function; - FunctionObject(ExecutionContext *scope, const StringRef name, bool createProto = false); - FunctionObject(ExecutionContext *scope, const QString &name = QString(), bool createProto = false); - FunctionObject(ExecutionContext *scope, const ReturnedValue name); - ~FunctionObject(); + ExecutionContext *scope() { return d()->scope; } + Function *function() { return d()->function; } + + ReturnedValue name(); + unsigned int formalParameterCount() { return function() ? function()->compiledFunction->nFormals : 0; } + unsigned int varCount() { return function() ? function()->compiledFunction->nLocals : 0; } - void init(const StringRef name, bool createProto); + void init(String *name, bool createProto); ReturnedValue newInstance(); @@ -130,6 +138,9 @@ struct Q_QML_EXPORT FunctionObject: Object { using Object::call; static ReturnedValue construct(Managed *that, CallData *); static ReturnedValue call(Managed *that, CallData *d); + static void destroy(Managed *m) { + static_cast<FunctionObject *>(m)->d()->~Data(); + } static FunctionObject *cast(const Value &v) { return v.asFunctionObject(); @@ -137,14 +148,13 @@ struct Q_QML_EXPORT FunctionObject: Object { static FunctionObject *createScriptFunction(ExecutionContext *scope, Function *function, bool createProto = true); - ReturnedValue protoProperty() { return memberData[Index_Prototype].asReturnedValue(); } + ReturnedValue protoProperty() { return memberData()[Index_Prototype].asReturnedValue(); } -protected: - FunctionObject(InternalClass *ic); + bool needsActivation() const { return d()->needsActivation; } + bool strictMode() const { return d()->strictMode; } + bool bindingKeyFlag() const { return d()->bindingKeyFlag; } static void markObjects(Managed *that, ExecutionEngine *e); - static void destroy(Managed *that) - { static_cast<FunctionObject*>(that)->~FunctionObject(); } }; template<> @@ -152,12 +162,13 @@ inline FunctionObject *value_cast(const Value &v) { return v.asFunctionObject(); } -DEFINE_REF(FunctionObject, Object); - struct FunctionCtor: FunctionObject { - V4_OBJECT - FunctionCtor(ExecutionContext *scope); + struct Data : FunctionObject::Data { + Data(ExecutionContext *scope); + }; + + V4_OBJECT(FunctionObject) static ReturnedValue construct(Managed *that, CallData *callData); static ReturnedValue call(Managed *that, CallData *callData); @@ -165,8 +176,12 @@ struct FunctionCtor: FunctionObject struct FunctionPrototype: FunctionObject { - FunctionPrototype(InternalClass *ic); - void init(ExecutionEngine *engine, ObjectRef ctor); + struct Data : FunctionObject::Data { + Data(InternalClass *ic); + }; + V4_OBJECT(FunctionObject) + + void init(ExecutionEngine *engine, Object *ctor); static ReturnedValue method_toString(CallContext *ctx); static ReturnedValue method_apply(CallContext *ctx); @@ -174,11 +189,17 @@ struct FunctionPrototype: FunctionObject static ReturnedValue method_bind(CallContext *ctx); }; -struct BuiltinFunction: FunctionObject { - V4_OBJECT - ReturnedValue (*code)(CallContext *); +struct Q_QML_EXPORT BuiltinFunction: FunctionObject { + struct Q_QML_EXPORT Data : FunctionObject::Data { + Data(ExecutionContext *scope, String *name, ReturnedValue (*code)(CallContext *)); + ReturnedValue (*code)(CallContext *); + }; + V4_OBJECT(FunctionObject) - BuiltinFunction(ExecutionContext *scope, const StringRef name, ReturnedValue (*code)(CallContext *)); + static BuiltinFunction *create(ExecutionContext *scope, String *name, ReturnedValue (*code)(CallContext *)) + { + return scope->engine()->memoryManager->alloc<BuiltinFunction>(scope, name, code); + } static ReturnedValue construct(Managed *, CallData *); static ReturnedValue call(Managed *that, CallData *callData); @@ -186,18 +207,18 @@ struct BuiltinFunction: FunctionObject { struct IndexedBuiltinFunction: FunctionObject { - V4_OBJECT - - ReturnedValue (*code)(CallContext *ctx, uint index); - uint index; - - IndexedBuiltinFunction(ExecutionContext *scope, uint index, ReturnedValue (*code)(CallContext *ctx, uint index)) - : FunctionObject(scope) - , code(code) - , index(index) - { - setVTable(staticVTable()); - } + struct Data : FunctionObject::Data { + Data(ExecutionContext *scope, uint index, ReturnedValue (*code)(CallContext *ctx, uint index)) + : FunctionObject::Data(scope), + code(code) + , index(index) + { + setVTable(staticVTable()); + } + ReturnedValue (*code)(CallContext *, uint index); + uint index; + }; + V4_OBJECT(FunctionObject) static ReturnedValue construct(Managed *m, CallData *) { @@ -209,8 +230,10 @@ struct IndexedBuiltinFunction: FunctionObject struct SimpleScriptFunction: FunctionObject { - V4_OBJECT - SimpleScriptFunction(ExecutionContext *scope, Function *function, bool createProto); + struct Data : FunctionObject::Data { + Data(ExecutionContext *scope, Function *function, bool createProto); + }; + V4_OBJECT(FunctionObject) static ReturnedValue construct(Managed *, CallData *callData); static ReturnedValue call(Managed *that, CallData *callData); @@ -219,8 +242,10 @@ struct SimpleScriptFunction: FunctionObject { }; struct ScriptFunction: SimpleScriptFunction { - V4_OBJECT - ScriptFunction(ExecutionContext *scope, Function *function); + struct Data : SimpleScriptFunction::Data { + Data(ExecutionContext *scope, Function *function); + }; + V4_OBJECT(FunctionObject) static ReturnedValue construct(Managed *, CallData *callData); static ReturnedValue call(Managed *that, CallData *callData); @@ -228,19 +253,26 @@ struct ScriptFunction: SimpleScriptFunction { struct BoundFunction: FunctionObject { - V4_OBJECT - FunctionObject *target; - Value boundThis; - QVector<Value> boundArgs; + struct Data : FunctionObject::Data { + Data(ExecutionContext *scope, FunctionObject *target, const ValueRef boundThis, const Members &boundArgs); + FunctionObject *target; + Value boundThis; + Members boundArgs; + }; + V4_OBJECT(FunctionObject) - BoundFunction(ExecutionContext *scope, FunctionObjectRef target, const ValueRef boundThis, const QVector<Value> &boundArgs); - ~BoundFunction() {} + static BoundFunction *create(ExecutionContext *scope, FunctionObject *target, const ValueRef boundThis, const QV4::Members &boundArgs) + { + return scope->engine()->memoryManager->alloc<BoundFunction>(scope, target, boundThis, boundArgs); + } + FunctionObject *target() { return d()->target; } + Value boundThis() const { return d()->boundThis; } + Members boundArgs() const { return d()->boundArgs; } static ReturnedValue construct(Managed *, CallData *d); static ReturnedValue call(Managed *that, CallData *dd); - static void destroy(Managed *); static void markObjects(Managed *that, ExecutionEngine *e); }; diff --git a/src/qml/jsruntime/qv4global_p.h b/src/qml/jsruntime/qv4global_p.h index a00231c3a1..039f5c1e78 100644 --- a/src/qml/jsruntime/qv4global_p.h +++ b/src/qml/jsruntime/qv4global_p.h @@ -74,15 +74,19 @@ inline double trunc(double d) { return d > 0 ? floor(d) : ceil(d); } // Decide whether to enable or disable the JIT // White list architectures +// +// NOTE: This should match the logic in qv4targetplatform_p.h! -#if defined(Q_PROCESSOR_X86) +#if defined(Q_PROCESSOR_X86) && (defined(Q_OS_WINDOWS) || defined(Q_OS_LINUX) || defined(Q_OS_QNX) || defined(Q_OS_FREEBSD)) #define V4_ENABLE_JIT -#elif defined(Q_PROCESSOR_X86_64) +#elif defined(Q_PROCESSOR_X86_64) && (defined(Q_OS_WINDOWS) || defined(Q_OS_LINUX) || defined(Q_OS_MAC) || defined(Q_OS_FREEBSD)) #define V4_ENABLE_JIT #elif defined(Q_PROCESSOR_ARM_32) #if defined(thumb2) || defined(__thumb2__) || ((defined(__thumb) || defined(__thumb__)) && __TARGET_ARCH_THUMB-0 == 4) #define V4_ENABLE_JIT +#elif defined(__ARM_ARCH_ISA_THUMB) && __ARM_ARCH_ISA_THUMB == 2 // clang 3.5 and later will set this if the core supports the Thumb-2 ISA. +#define V4_ENABLE_JIT #endif #endif @@ -161,12 +165,6 @@ template<typename T> struct Returned; typedef Returned<String> ReturnedString; typedef Returned<Object> ReturnedObject; typedef Returned<FunctionObject> ReturnedFunctionObject; -struct ManagedRef; -struct StringRef; -struct ObjectRef; -struct ArrayObjectRef; -struct FunctionObjectRef; -struct RegExpRef; struct PersistentValuePrivate; class PersistentValue; diff --git a/src/qml/jsruntime/qv4globalobject.cpp b/src/qml/jsruntime/qv4globalobject.cpp index eb0994c1e6..fc4a097915 100644 --- a/src/qml/jsruntime/qv4globalobject.cpp +++ b/src/qml/jsruntime/qv4globalobject.cpp @@ -346,11 +346,13 @@ static QString decode(const QString &input, DecodeMode decodeMode, bool *ok) DEFINE_OBJECT_VTABLE(EvalFunction); -EvalFunction::EvalFunction(ExecutionContext *scope) - : FunctionObject(scope, scope->engine->id_eval) +EvalFunction::Data::Data(ExecutionContext *scope) + : FunctionObject::Data(scope, scope->d()->engine->id_eval) { setVTable(staticVTable()); - defineReadonlyProperty(scope->engine->id_length, Primitive::fromInt32(1)); + Scope s(scope); + ScopedFunctionObject f(s, this); + f->defineReadonlyProperty(s.engine->id_length, Primitive::fromInt32(1)); } ReturnedValue EvalFunction::evalCall(CallData *callData, bool directCall) @@ -363,16 +365,16 @@ ReturnedValue EvalFunction::evalCall(CallData *callData, bool directCall) ContextStateSaver(ExecutionContext *context) : savedContext(context) - , strictMode(context->strictMode) - , evalCode(context->currentEvalCode) - , compilationUnit(context->compilationUnit) + , strictMode(context->d()->strictMode) + , evalCode(context->d()->currentEvalCode) + , compilationUnit(context->d()->compilationUnit) {} ~ContextStateSaver() { - savedContext->strictMode = strictMode; - savedContext->currentEvalCode = evalCode; - savedContext->compilationUnit = compilationUnit; + savedContext->d()->strictMode = strictMode; + savedContext->d()->currentEvalCode = evalCode; + savedContext->d()->compilationUnit = compilationUnit; } }; @@ -396,10 +398,10 @@ ReturnedValue EvalFunction::evalCall(CallData *callData, bool directCall) return callData->args[0].asReturnedValue(); const QString code = callData->args[0].stringValue()->toQString(); - bool inheritContext = !ctx->strictMode; + bool inheritContext = !ctx->d()->strictMode; Script script(ctx, code, QStringLiteral("eval code")); - script.strictMode = (directCall && parentContext->strictMode); + script.strictMode = (directCall && parentContext->d()->strictMode); script.inheritContext = inheritContext; script.parse(); if (scope.engine->hasException) @@ -409,14 +411,14 @@ ReturnedValue EvalFunction::evalCall(CallData *callData, bool directCall) if (!function) return Encode::undefined(); - strictMode = function->isStrict() || (ctx->strictMode); + d()->strictMode = function->isStrict() || (ctx->d()->strictMode); - needsActivation = function->needsActivation(); + d()->needsActivation = function->needsActivation(); - if (strictMode) { + if (strictMode()) { ScopedFunctionObject e(scope, FunctionObject::createScriptFunction(ctx, function)); ScopedCallData callData(scope, 0); - callData->thisObject = ctx->callData->thisObject; + callData->thisObject = ctx->d()->callData->thisObject; return e->call(callData); } @@ -424,12 +426,12 @@ ReturnedValue EvalFunction::evalCall(CallData *callData, bool directCall) ExecutionContext::EvalCode evalCode; evalCode.function = function; - evalCode.next = ctx->currentEvalCode; - ctx->currentEvalCode = &evalCode; + evalCode.next = ctx->d()->currentEvalCode; + ctx->d()->currentEvalCode = &evalCode; // set the correct strict mode flag on the context - ctx->strictMode = strictMode; - ctx->compilationUnit = function->compilationUnit; + ctx->d()->strictMode = strictMode(); + ctx->d()->compilationUnit = function->compilationUnit; return function->code(ctx, function->codeData); } @@ -470,7 +472,7 @@ ReturnedValue GlobalFunctions::method_parseInt(CallContext *ctx) String *inputString = string->toString(ctx); // 1 QString trimmed = inputString->toQString().trimmed(); // 2 - if (ctx->engine->hasException) + if (ctx->d()->engine->hasException) return Encode::undefined(); const QChar *pos = trimmed.constData(); @@ -574,117 +576,117 @@ ReturnedValue GlobalFunctions::method_parseFloat(CallContext *ctx) /// isNaN [15.1.2.4] ReturnedValue GlobalFunctions::method_isNaN(CallContext *ctx) { - if (!ctx->callData->argc) + if (!ctx->d()->callData->argc) // undefined gets converted to NaN return Encode(true); - if (ctx->callData->args[0].integerCompatible()) + if (ctx->d()->callData->args[0].integerCompatible()) return Encode(false); - double d = ctx->callData->args[0].toNumber(); + double d = ctx->d()->callData->args[0].toNumber(); return Encode((bool)std::isnan(d)); } /// isFinite [15.1.2.5] ReturnedValue GlobalFunctions::method_isFinite(CallContext *ctx) { - if (!ctx->callData->argc) + if (!ctx->d()->callData->argc) // undefined gets converted to NaN return Encode(false); - if (ctx->callData->args[0].integerCompatible()) + if (ctx->d()->callData->args[0].integerCompatible()) return Encode(true); - double d = ctx->callData->args[0].toNumber(); + double d = ctx->d()->callData->args[0].toNumber(); return Encode((bool)std::isfinite(d)); } /// decodeURI [15.1.3.1] ReturnedValue GlobalFunctions::method_decodeURI(CallContext *context) { - if (context->callData->argc == 0) + if (context->d()->callData->argc == 0) return Encode::undefined(); - QString uriString = context->callData->args[0].toString(context)->toQString(); + QString uriString = context->d()->callData->args[0].toString(context)->toQString(); bool ok; QString out = decode(uriString, DecodeNonReserved, &ok); if (!ok) { Scope scope(context); - ScopedString s(scope, context->engine->newString(QStringLiteral("malformed URI sequence"))); + ScopedString s(scope, context->d()->engine->newString(QStringLiteral("malformed URI sequence"))); return context->throwURIError(s); } - return context->engine->newString(out)->asReturnedValue(); + return context->d()->engine->newString(out)->asReturnedValue(); } /// decodeURIComponent [15.1.3.2] ReturnedValue GlobalFunctions::method_decodeURIComponent(CallContext *context) { - if (context->callData->argc == 0) + if (context->d()->callData->argc == 0) return Encode::undefined(); - QString uriString = context->callData->args[0].toString(context)->toQString(); + QString uriString = context->d()->callData->args[0].toString(context)->toQString(); bool ok; QString out = decode(uriString, DecodeAll, &ok); if (!ok) { Scope scope(context); - ScopedString s(scope, context->engine->newString(QStringLiteral("malformed URI sequence"))); + ScopedString s(scope, context->d()->engine->newString(QStringLiteral("malformed URI sequence"))); return context->throwURIError(s); } - return context->engine->newString(out)->asReturnedValue(); + return context->d()->engine->newString(out)->asReturnedValue(); } /// encodeURI [15.1.3.3] ReturnedValue GlobalFunctions::method_encodeURI(CallContext *context) { - if (context->callData->argc == 0) + if (context->d()->callData->argc == 0) return Encode::undefined(); - QString uriString = context->callData->args[0].toString(context)->toQString(); + QString uriString = context->d()->callData->args[0].toString(context)->toQString(); bool ok; QString out = encode(uriString, uriUnescapedReserved, &ok); if (!ok) { Scope scope(context); - ScopedString s(scope, context->engine->newString(QStringLiteral("malformed URI sequence"))); + ScopedString s(scope, context->d()->engine->newString(QStringLiteral("malformed URI sequence"))); return context->throwURIError(s); } - return context->engine->newString(out)->asReturnedValue(); + return context->d()->engine->newString(out)->asReturnedValue(); } /// encodeURIComponent [15.1.3.4] ReturnedValue GlobalFunctions::method_encodeURIComponent(CallContext *context) { - if (context->callData->argc == 0) + if (context->d()->callData->argc == 0) return Encode::undefined(); - QString uriString = context->callData->args[0].toString(context)->toQString(); + QString uriString = context->d()->callData->args[0].toString(context)->toQString(); bool ok; QString out = encode(uriString, uriUnescaped, &ok); if (!ok) { Scope scope(context); - ScopedString s(scope, context->engine->newString(QStringLiteral("malformed URI sequence"))); + ScopedString s(scope, context->d()->engine->newString(QStringLiteral("malformed URI sequence"))); return context->throwURIError(s); } - return context->engine->newString(out)->asReturnedValue(); + return context->d()->engine->newString(out)->asReturnedValue(); } ReturnedValue GlobalFunctions::method_escape(CallContext *context) { - if (!context->callData->argc) - return context->engine->newString(QStringLiteral("undefined"))->asReturnedValue(); + if (!context->d()->callData->argc) + return context->d()->engine->newString(QStringLiteral("undefined"))->asReturnedValue(); - QString str = context->callData->args[0].toString(context)->toQString(); - return context->engine->newString(escape(str))->asReturnedValue(); + QString str = context->d()->callData->args[0].toString(context)->toQString(); + return context->d()->engine->newString(escape(str))->asReturnedValue(); } ReturnedValue GlobalFunctions::method_unescape(CallContext *context) { - if (!context->callData->argc) - return context->engine->newString(QStringLiteral("undefined"))->asReturnedValue(); + if (!context->d()->callData->argc) + return context->d()->engine->newString(QStringLiteral("undefined"))->asReturnedValue(); - QString str = context->callData->args[0].toString(context)->toQString(); - return context->engine->newString(unescape(str))->asReturnedValue(); + QString str = context->d()->callData->args[0].toString(context)->toQString(); + return context->d()->engine->newString(unescape(str))->asReturnedValue(); } diff --git a/src/qml/jsruntime/qv4globalobject_p.h b/src/qml/jsruntime/qv4globalobject_p.h index 63823acc19..b3fcb0c89b 100644 --- a/src/qml/jsruntime/qv4globalobject_p.h +++ b/src/qml/jsruntime/qv4globalobject_p.h @@ -50,8 +50,11 @@ namespace QV4 { struct Q_QML_EXPORT EvalFunction : FunctionObject { - V4_OBJECT - EvalFunction(ExecutionContext *scope); + struct Data : FunctionObject::Data { + Data(ExecutionContext *scope); + }; + + V4_OBJECT(FunctionObject) ReturnedValue evalCall(CallData *callData, bool directCall); diff --git a/src/qml/jsruntime/qv4identifier.cpp b/src/qml/jsruntime/qv4identifier.cpp index 87fbd6f8e4..bbb756bab3 100644 --- a/src/qml/jsruntime/qv4identifier.cpp +++ b/src/qml/jsruntime/qv4identifier.cpp @@ -149,8 +149,8 @@ const IdentifierHashEntry *IdentifierHashBase::lookup(String *str) const { if (!d) return 0; - if (str->identifier) - return lookup(str->identifier); + if (str->d()->identifier) + return lookup(str->d()->identifier); return lookup(str->toQString()); } diff --git a/src/qml/jsruntime/qv4identifiertable.cpp b/src/qml/jsruntime/qv4identifiertable.cpp index e300a4811e..8627438fe1 100644 --- a/src/qml/jsruntime/qv4identifiertable.cpp +++ b/src/qml/jsruntime/qv4identifiertable.cpp @@ -69,7 +69,7 @@ IdentifierTable::~IdentifierTable() { for (int i = 0; i < alloc; ++i) if (entries[i]) - delete entries[i]->identifier; + delete entries[i]->d()->identifier; free(entries); } @@ -77,12 +77,12 @@ void IdentifierTable::addEntry(String *str) { uint hash = str->hashValue(); - if (str->subtype == String::StringType_ArrayIndex) + if (str->subtype() == String::StringType_ArrayIndex) return; - str->identifier = new Identifier; - str->identifier->string = str->toQString(); - str->identifier->hashValue = hash; + str->d()->identifier = new Identifier; + str->d()->identifier->string = str->toQString(); + str->d()->identifier->hashValue = hash; bool grow = (alloc <= size*2); @@ -95,7 +95,7 @@ void IdentifierTable::addEntry(String *str) String *e = entries[i]; if (!e) continue; - uint idx = e->stringHash % newAlloc; + uint idx = e->d()->stringHash % newAlloc; while (newEntries[idx]) { ++idx; idx %= newAlloc; @@ -123,7 +123,7 @@ String *IdentifierTable::insertString(const QString &s) uint hash = String::createHashValue(s.constData(), s.length()); uint idx = hash % alloc; while (String *e = entries[idx]) { - if (e->stringHash == hash && e->toQString() == s) + if (e->d()->stringHash == hash && e->toQString() == s) return e; ++idx; idx %= alloc; @@ -137,29 +137,29 @@ String *IdentifierTable::insertString(const QString &s) Identifier *IdentifierTable::identifierImpl(const String *str) { - if (str->identifier) - return str->identifier; + if (str->d()->identifier) + return str->d()->identifier; uint hash = str->hashValue(); - if (str->subtype == String::StringType_ArrayIndex) + if (str->subtype() == String::StringType_ArrayIndex) return 0; uint idx = hash % alloc; while (String *e = entries[idx]) { - if (e->stringHash == hash && e->isEqualTo(str)) { - str->identifier = e->identifier; - return e->identifier; + if (e->d()->stringHash == hash && e->isEqualTo(str)) { + str->d()->identifier = e->d()->identifier; + return e->d()->identifier; } ++idx; idx %= alloc; } addEntry(const_cast<QV4::String *>(str)); - return str->identifier; + return str->d()->identifier; } Identifier *IdentifierTable::identifier(const QString &s) { - return insertString(s)->identifier; + return insertString(s)->d()->identifier; } Identifier *IdentifierTable::identifier(const char *s, int len) @@ -171,15 +171,15 @@ Identifier *IdentifierTable::identifier(const char *s, int len) QLatin1String latin(s, len); uint idx = hash % alloc; while (String *e = entries[idx]) { - if (e->stringHash == hash && e->toQString() == latin) - return e->identifier; + if (e->d()->stringHash == hash && e->toQString() == latin) + return e->d()->identifier; ++idx; idx %= alloc; } String *str = engine->newString(QString::fromLatin1(s, len))->getPointer(); addEntry(str); - return str->identifier; + return str->d()->identifier; } } diff --git a/src/qml/jsruntime/qv4identifiertable_p.h b/src/qml/jsruntime/qv4identifiertable_p.h index 09956fc342..7675d1642e 100644 --- a/src/qml/jsruntime/qv4identifiertable_p.h +++ b/src/qml/jsruntime/qv4identifiertable_p.h @@ -69,8 +69,8 @@ public: String *insertString(const QString &s); Identifier *identifier(const String *str) { - if (str->identifier) - return str->identifier; + if (str->d()->identifier) + return str->d()->identifier; return identifierImpl(str); } @@ -82,11 +82,11 @@ public: void mark(ExecutionEngine *e) { for (int i = 0; i < alloc; ++i) { String *entry = entries[i]; - if (!entry || entry->markBit) + if (!entry || entry->markBit()) continue; - entry->markBit = 1; - Q_ASSERT(entry->internalClass->vtable->markObjects); - entry->internalClass->vtable->markObjects(entry, e); + entry->d()->markBit = 1; + Q_ASSERT(entry->internalClass()->vtable->markObjects); + entry->internalClass()->vtable->markObjects(entry, e); } } }; diff --git a/src/qml/jsruntime/qv4include.cpp b/src/qml/jsruntime/qv4include.cpp index d5bae0e35e..b9576e1bee 100644 --- a/src/qml/jsruntime/qv4include.cpp +++ b/src/qml/jsruntime/qv4include.cpp @@ -89,11 +89,11 @@ QV4::ReturnedValue QV4Include::resultValue(QV4::ExecutionEngine *v4, Status stat QV4::ScopedObject o(scope, v4->newObject()); QV4::ScopedString s(scope); QV4::ScopedValue v(scope); - o->put((s = v4->newString(QStringLiteral("OK"))), (v = QV4::Primitive::fromInt32(Ok))); - o->put((s = v4->newString(QStringLiteral("LOADING"))), (v = QV4::Primitive::fromInt32(Loading))); - o->put((s = v4->newString(QStringLiteral("NETWORK_ERROR"))), (v = QV4::Primitive::fromInt32(NetworkError))); - o->put((s = v4->newString(QStringLiteral("EXCEPTION"))), (v = QV4::Primitive::fromInt32(Exception))); - o->put((s = v4->newString(QStringLiteral("status"))), (v = QV4::Primitive::fromInt32(status))); + o->put((s = v4->newString(QStringLiteral("OK"))).getPointer(), (v = QV4::Primitive::fromInt32(Ok))); + o->put((s = v4->newString(QStringLiteral("LOADING"))).getPointer(), (v = QV4::Primitive::fromInt32(Loading))); + o->put((s = v4->newString(QStringLiteral("NETWORK_ERROR"))).getPointer(), (v = QV4::Primitive::fromInt32(NetworkError))); + o->put((s = v4->newString(QStringLiteral("EXCEPTION"))).getPointer(), (v = QV4::Primitive::fromInt32(Exception))); + o->put((s = v4->newString(QStringLiteral("status"))).getPointer(), (v = QV4::Primitive::fromInt32(status))); return o.asReturnedValue(); } @@ -160,13 +160,13 @@ void QV4Include::finished() script.run(); if (scope.engine->hasException) { QV4::ScopedValue ex(scope, ctx->catchException()); - resultObj->put(status, QV4::ScopedValue(scope, QV4::Primitive::fromInt32(Exception))); - resultObj->put(QV4::ScopedString(scope, v4->newString(QStringLiteral("exception"))), ex); + resultObj->put(status.getPointer(), QV4::ScopedValue(scope, QV4::Primitive::fromInt32(Exception))); + resultObj->put(v4->newString(QStringLiteral("exception"))->getPointer(), ex); } else { - resultObj->put(status, QV4::ScopedValue(scope, QV4::Primitive::fromInt32(Ok))); + resultObj->put(status.getPointer(), QV4::ScopedValue(scope, QV4::Primitive::fromInt32(Ok))); } } else { - resultObj->put(QV4::ScopedString(scope, v4->newString(QStringLiteral("status"))), QV4::ScopedValue(scope, QV4::Primitive::fromInt32(NetworkError))); + resultObj->put(v4->newString(QStringLiteral("status"))->getPointer(), QV4::ScopedValue(scope, QV4::Primitive::fromInt32(NetworkError))); } QV4::ScopedValue cb(scope, m_callbackFunction.value()); @@ -181,27 +181,26 @@ void QV4Include::finished() */ QV4::ReturnedValue QV4Include::method_include(QV4::CallContext *ctx) { - if (!ctx->callData->argc) + if (!ctx->d()->callData->argc) return QV4::Encode::undefined(); - QV4::ExecutionEngine *v4 = ctx->engine; - QV4::Scope scope(v4); - QV8Engine *engine = v4->v8Engine; - QQmlContextData *context = QV4::QmlContextWrapper::callingContext(v4); + QV4::Scope scope(ctx->engine()); + QV8Engine *engine = scope.engine->v8Engine; + QQmlContextData *context = QV4::QmlContextWrapper::callingContext(scope.engine); if (!context || !context->isJSContext) V4THROW_ERROR("Qt.include(): Can only be called from JavaScript files"); - QUrl url(ctx->engine->resolvedUrl(ctx->callData->args[0].toQStringNoThrow())); + QUrl url(scope.engine->resolvedUrl(ctx->d()->callData->args[0].toQStringNoThrow())); QV4::ScopedValue callbackFunction(scope, QV4::Primitive::undefinedValue()); - if (ctx->callData->argc >= 2 && ctx->callData->args[1].asFunctionObject()) - callbackFunction = ctx->callData->args[1]; + if (ctx->d()->callData->argc >= 2 && ctx->d()->callData->args[1].asFunctionObject()) + callbackFunction = ctx->d()->callData->args[1]; QString localFile = QQmlFile::urlToLocalFileOrQrc(url); QV4::ScopedValue result(scope); - QV4::ScopedObject qmlcontextobject(scope, v4->qmlContextObject()); + QV4::ScopedObject qmlcontextobject(scope, scope.engine->qmlContextObject()); if (localFile.isEmpty()) { QV4Include *i = new QV4Include(url, engine, context, @@ -218,21 +217,21 @@ QV4::ReturnedValue QV4Include::method_include(QV4::CallContext *ctx) QString code = QString::fromUtf8(data); QmlIR::Document::removeScriptPragmas(code); - QV4::Script script(v4, qmlcontextobject, code, url.toString()); + QV4::Script script(scope.engine, qmlcontextobject, code, url.toString()); - QV4::ExecutionContext *ctx = v4->currentContext(); + QV4::ExecutionContext *ctx = scope.engine->currentContext(); script.parse(); - if (!v4->hasException) + if (!scope.engine->hasException) script.run(); - if (v4->hasException) { + if (scope.engine->hasException) { QV4::ScopedValue ex(scope, ctx->catchException()); - result = resultValue(v4, Exception); - result->asObject()->put(QV4::ScopedString(scope, v4->newString(QStringLiteral("exception"))), ex); + result = resultValue(scope.engine, Exception); + result->asObject()->put(scope.engine->newString(QStringLiteral("exception"))->getPointer(), ex); } else { - result = resultValue(v4, Ok); + result = resultValue(scope.engine, Ok); } } else { - result = resultValue(v4, NetworkError); + result = resultValue(scope.engine, NetworkError); } callback(callbackFunction, result); diff --git a/src/qml/jsruntime/qv4internalclass.cpp b/src/qml/jsruntime/qv4internalclass.cpp index 3dc20b8e76..2edaf6fe96 100644 --- a/src/qml/jsruntime/qv4internalclass.cpp +++ b/src/qml/jsruntime/qv4internalclass.cpp @@ -155,18 +155,18 @@ InternalClass::InternalClass(const QV4::InternalClass &other) void InternalClass::changeMember(Object *object, String *string, PropertyAttributes data, uint *index) { uint idx; - InternalClass *newClass = object->internalClass->changeMember(string, data, &idx); + InternalClass *newClass = object->internalClass()->changeMember(string, data, &idx); if (index) *index = idx; - if (newClass->size > object->internalClass->size) { - Q_ASSERT(newClass->size == object->internalClass->size + 1); - memmove(object->memberData.data() + idx + 2, object->memberData.data() + idx + 1, (object->internalClass->size - idx - 1)*sizeof(Value)); - } else if (newClass->size < object->internalClass->size) { - Q_ASSERT(newClass->size == object->internalClass->size - 1); - memmove(object->memberData.data() + idx + 1, object->memberData.data() + idx + 2, (object->internalClass->size - idx - 2)*sizeof(Value)); + if (newClass->size > object->internalClass()->size) { + Q_ASSERT(newClass->size == object->internalClass()->size + 1); + memmove(object->memberData().data() + idx + 2, object->memberData().data() + idx + 1, (object->internalClass()->size - idx - 1)*sizeof(Value)); + } else if (newClass->size < object->internalClass()->size) { + Q_ASSERT(newClass->size == object->internalClass()->size - 1); + memmove(object->memberData().data() + idx + 1, object->memberData().data() + idx + 2, (object->internalClass()->size - idx - 2)*sizeof(Value)); } - object->internalClass = newClass; + object->setInternalClass(newClass); } InternalClass *InternalClass::changeMember(String *string, PropertyAttributes data, uint *index) @@ -181,7 +181,7 @@ InternalClass *InternalClass::changeMember(String *string, PropertyAttributes da if (data == propertyData.at(idx)) return this; - Transition t = { { string->identifier }, (int)data.flags() }; + Transition t = { { string->d()->identifier }, (int)data.flags() }; QHash<Transition, InternalClass *>::const_iterator tit = transitions.constFind(t); if (tit != transitions.constEnd()) return tit.value(); @@ -271,40 +271,30 @@ InternalClass *InternalClass::changeVTable(const ManagedVTable *vt) return newClass; } -void InternalClass::addMember(Object *object, StringRef string, PropertyAttributes data, uint *index) -{ - return addMember(object, string.getPointer(), data, index); -} - void InternalClass::addMember(Object *object, String *string, PropertyAttributes data, uint *index) { data.resolve(); - object->internalClass->engine->identifierTable->identifier(string); - if (object->internalClass->propertyTable.lookup(string->identifier) < object->internalClass->size) { + object->internalClass()->engine->identifierTable->identifier(string); + if (object->internalClass()->propertyTable.lookup(string->d()->identifier) < object->internalClass()->size) { changeMember(object, string, data, index); return; } uint idx; - InternalClass *newClass = object->internalClass->addMemberImpl(string, data, &idx); + InternalClass *newClass = object->internalClass()->addMemberImpl(string, data, &idx); if (index) *index = idx; - object->internalClass = newClass; + object->setInternalClass(newClass); } -InternalClass *InternalClass::addMember(StringRef string, PropertyAttributes data, uint *index) -{ - return addMember(string.getPointer(), data, index); -} - InternalClass *InternalClass::addMember(String *string, PropertyAttributes data, uint *index) { data.resolve(); engine->identifierTable->identifier(string); - if (propertyTable.lookup(string->identifier) < size) + if (propertyTable.lookup(string->d()->identifier) < size) return changeMember(string, data, index); return addMemberImpl(string, data, index); @@ -312,7 +302,7 @@ InternalClass *InternalClass::addMember(String *string, PropertyAttributes data, InternalClass *InternalClass::addMemberImpl(String *string, PropertyAttributes data, uint *index) { - Transition t = { { string->identifier }, (int)data.flags() }; + Transition t = { { string->d()->identifier }, (int)data.flags() }; QHash<Transition, InternalClass *>::const_iterator tit = transitions.constFind(t); if (index) @@ -322,7 +312,7 @@ InternalClass *InternalClass::addMemberImpl(String *string, PropertyAttributes d // create a new class and add it to the tree InternalClass *newClass = engine->newClass(*this); - PropertyHash::Entry e = { string->identifier, newClass->size }; + PropertyHash::Entry e = { string->d()->identifier, newClass->size }; newClass->propertyTable.addEntry(e, newClass->size); // The incoming string can come from anywhere, so make sure to @@ -346,15 +336,15 @@ InternalClass *InternalClass::addMemberImpl(String *string, PropertyAttributes d void InternalClass::removeMember(Object *object, Identifier *id) { - InternalClass *oldClass = object->internalClass; + InternalClass *oldClass = object->internalClass(); uint propIdx = oldClass->propertyTable.lookup(id); Q_ASSERT(propIdx < oldClass->size); Transition t = { { id } , -1 }; - QHash<Transition, InternalClass *>::const_iterator tit = object->internalClass->transitions.constFind(t); + QHash<Transition, InternalClass *>::const_iterator tit = object->internalClass()->transitions.constFind(t); - if (tit != object->internalClass->transitions.constEnd()) { - object->internalClass = tit.value(); + if (tit != object->internalClass()->transitions.constEnd()) { + object->setInternalClass(tit.value()); } else { // create a new class and add it to the tree InternalClass *newClass = oldClass->engine->emptyClass->changeVTable(oldClass->vtable); @@ -365,24 +355,19 @@ void InternalClass::removeMember(Object *object, Identifier *id) if (!oldClass->propertyData.at(i).isEmpty()) newClass = newClass->addMember(oldClass->nameMap.at(i), oldClass->propertyData.at(i)); } - object->internalClass = newClass; + object->setInternalClass(newClass); } // remove the entry in memberdata - memmove(object->memberData.data() + propIdx, object->memberData.data() + propIdx + 1, (object->internalClass->size - propIdx)*sizeof(Value)); - - oldClass->transitions.insert(t, object->internalClass); -} + memmove(object->memberData().data() + propIdx, object->memberData().data() + propIdx + 1, (object->internalClass()->size - propIdx)*sizeof(Value)); -uint InternalClass::find(const StringRef string) -{ - return find(string.getPointer()); + oldClass->transitions.insert(t, object->internalClass()); } uint InternalClass::find(const String *string) { engine->identifierTable->identifier(string); - const Identifier *id = string->identifier; + const Identifier *id = string->d()->identifier; uint index = propertyTable.lookup(id); if (index < size) diff --git a/src/qml/jsruntime/qv4internalclass_p.h b/src/qml/jsruntime/qv4internalclass_p.h index bd1828a146..830d5f792f 100644 --- a/src/qml/jsruntime/qv4internalclass_p.h +++ b/src/qml/jsruntime/qv4internalclass_p.h @@ -234,14 +234,11 @@ struct InternalClass : public QQmlJS::Managed { static InternalClass *create(ExecutionEngine *engine, const ManagedVTable *vtable, Object *proto); InternalClass *changePrototype(Object *proto); InternalClass *changeVTable(const ManagedVTable *vt); - static void addMember(Object *object, StringRef string, PropertyAttributes data, uint *index); static void addMember(Object *object, String *string, PropertyAttributes data, uint *index); - InternalClass *addMember(StringRef string, PropertyAttributes data, uint *index = 0); InternalClass *addMember(String *string, PropertyAttributes data, uint *index = 0); InternalClass *changeMember(String *string, PropertyAttributes data, uint *index = 0); static void changeMember(Object *object, String *string, PropertyAttributes data, uint *index = 0); static void removeMember(Object *object, Identifier *id); - uint find(const StringRef string); uint find(const String *s); InternalClass *sealed(); diff --git a/src/qml/jsruntime/qv4jsonobject.cpp b/src/qml/jsruntime/qv4jsonobject.cpp index ca82af1b30..2cbb72e15f 100644 --- a/src/qml/jsruntime/qv4jsonobject.cpp +++ b/src/qml/jsruntime/qv4jsonobject.cpp @@ -81,7 +81,7 @@ private: ReturnedValue parseObject(); ReturnedValue parseArray(); - bool parseMember(ObjectRef o); + bool parseMember(Object *o); bool parseString(QString *string); bool parseValue(ValueRef val); bool parseNumber(ValueRef val); @@ -237,7 +237,7 @@ ReturnedValue JsonParser::parseObject() BEGIN << "parseObject pos=" << json; Scope scope(context); - ScopedObject o(scope, context->engine->newObject()); + ScopedObject o(scope, context->d()->engine->newObject()); QChar token = nextToken(); while (token == Quote) { @@ -268,7 +268,7 @@ ReturnedValue JsonParser::parseObject() /* member = string name-separator value */ -bool JsonParser::parseMember(ObjectRef o) +bool JsonParser::parseMember(Object *o) { BEGIN << "parseMember"; Scope scope(context); @@ -285,12 +285,12 @@ bool JsonParser::parseMember(ObjectRef o) if (!parseValue(val)) return false; - ScopedString s(scope, context->engine->newIdentifier(key)); + ScopedString s(scope, context->d()->engine->newIdentifier(key)); uint idx = s->asArrayIndex(); if (idx < UINT_MAX) { o->putIndexed(idx, val); } else { - o->insertMember(s, val); + o->insertMember(s.getPointer(), val); } END; @@ -304,7 +304,7 @@ ReturnedValue JsonParser::parseArray() { Scope scope(context); BEGIN << "parseArray"; - Scoped<ArrayObject> array(scope, context->engine->newArrayObject()); + Scoped<ArrayObject> array(scope, context->d()->engine->newArrayObject()); if (++nestingLevel > nestingLimit) { lastError = QJsonParseError::DeepNesting; @@ -407,7 +407,7 @@ bool JsonParser::parseValue(ValueRef val) return false; DEBUG << "value: string"; END; - val = context->engine->newString(value); + val = context->d()->engine->newString(value); return true; } case BeginArray: { @@ -656,8 +656,8 @@ struct Stringify Stringify(ExecutionContext *ctx) : ctx(ctx), replacerFunction(0) {} QString Str(const QString &key, ValueRef v); - QString JA(ArrayObjectRef a); - QString JO(ObjectRef o); + QString JA(ArrayObject *a); + QString JO(Object *o); QString makeMember(const QString &key, ValueRef v); }; @@ -710,21 +710,21 @@ QString Stringify::Str(const QString &key, ValueRef v) ScopedValue value(scope, *v); ScopedObject o(scope, value); if (o) { - ScopedString s(scope, ctx->engine->newString(QStringLiteral("toJSON"))); - Scoped<FunctionObject> toJSON(scope, o->get(s)); + ScopedString s(scope, ctx->d()->engine->newString(QStringLiteral("toJSON"))); + Scoped<FunctionObject> toJSON(scope, o->get(s.getPointer())); if (!!toJSON) { ScopedCallData callData(scope, 1); callData->thisObject = value; - callData->args[0] = ctx->engine->newString(key); + callData->args[0] = ctx->d()->engine->newString(key); value = toJSON->call(callData); } } if (replacerFunction) { - ScopedObject holder(scope, ctx->engine->newObject()); + ScopedObject holder(scope, ctx->d()->engine->newObject()); holder->put(ctx, QString(), value); ScopedCallData callData(scope, 2); - callData->args[0] = ctx->engine->newString(key); + callData->args[0] = ctx->d()->engine->newString(key); callData->args[1] = value; callData->thisObject = holder; value = replacerFunction->call(callData); @@ -733,11 +733,11 @@ QString Stringify::Str(const QString &key, ValueRef v) o = value.asReturnedValue(); if (o) { if (NumberObject *n = o->asNumberObject()) - value = n->value; + value = n->value(); else if (StringObject *so = o->asStringObject()) - value = so->value; + value = so->d()->value; else if (BooleanObject *b =o->asBooleanObject()) - value = b->value; + value = b->value(); } if (value->isNull()) @@ -780,9 +780,9 @@ QString Stringify::makeMember(const QString &key, ValueRef v) return QString(); } -QString Stringify::JO(ObjectRef o) +QString Stringify::JO(Object *o) { - if (stack.contains(o.getPointer())) { + if (stack.contains(o)) { ctx->throwTypeError(); return QString(); } @@ -790,7 +790,7 @@ QString Stringify::JO(ObjectRef o) Scope scope(ctx); QString result; - stack.push(o.getPointer()); + stack.push(o); QString stepback = indent; indent += gap; @@ -814,7 +814,7 @@ QString Stringify::JO(ObjectRef o) for (int i = 0; i < propertyList.size(); ++i) { bool exists; s = propertyList.at(i); - ScopedValue v(scope, o->get(s, &exists)); + ScopedValue v(scope, o->get(s.getPointer(), &exists)); if (!exists) continue; QString member = makeMember(s->toQString(), v); @@ -837,9 +837,9 @@ QString Stringify::JO(ObjectRef o) return result; } -QString Stringify::JA(ArrayObjectRef a) +QString Stringify::JA(ArrayObject *a) { - if (stack.contains(a.getPointer())) { + if (stack.contains(a)) { ctx->throwTypeError(); return QString(); } @@ -847,7 +847,7 @@ QString Stringify::JA(ArrayObjectRef a) Scope scope(a->engine()); QString result; - stack.push(a.getPointer()); + stack.push(a); QString stepback = indent; indent += gap; @@ -883,14 +883,14 @@ QString Stringify::JA(ArrayObjectRef a) } -JsonObject::JsonObject(InternalClass *ic) - : Object(ic) +JsonObject::Data::Data(InternalClass *ic) + : Object::Data(ic) { Scope scope(ic->engine); - ScopedObject protectThis(scope, this); + ScopedObject o(scope, this); - defineDefaultProperty(QStringLiteral("parse"), method_parse, 2); - defineDefaultProperty(QStringLiteral("stringify"), method_stringify, 3); + o->defineDefaultProperty(QStringLiteral("parse"), method_parse, 2); + o->defineDefaultProperty(QStringLiteral("stringify"), method_stringify, 3); } @@ -939,9 +939,9 @@ ReturnedValue JsonObject::method_stringify(CallContext *ctx) ScopedValue s(scope, ctx->argument(2)); if (NumberObject *n = s->asNumberObject()) - s = n->value; + s = n->value(); else if (StringObject *so = s->asStringObject()) - s = so->value; + s = so->d()->value; if (s->isNumber()) { stringify.gap = QString(qMin(10, (int)s->toInteger()), ' '); @@ -954,7 +954,7 @@ ReturnedValue JsonObject::method_stringify(CallContext *ctx) QString result = stringify.Str(QString(), arg0); if (result.isEmpty() || scope.engine->hasException) return Encode::undefined(); - return ctx->engine->newString(result)->asReturnedValue(); + return ctx->d()->engine->newString(result)->asReturnedValue(); } @@ -962,7 +962,7 @@ ReturnedValue JsonObject::method_stringify(CallContext *ctx) ReturnedValue JsonObject::fromJsonValue(ExecutionEngine *engine, const QJsonValue &value) { if (value.isString()) - return engine->currentContext()->engine->newString(value.toString())->asReturnedValue(); + return engine->currentContext()->d()->engine->newString(value.toString())->asReturnedValue(); else if (value.isDouble()) return Encode(value.toDouble()); else if (value.isBool()) @@ -1008,12 +1008,12 @@ QV4::ReturnedValue JsonObject::fromJsonObject(ExecutionEngine *engine, const QJs ScopedValue v(scope); for (QJsonObject::const_iterator it = object.begin(); it != object.end(); ++it) { v = fromJsonValue(engine, it.value()); - o->put((s = engine->newString(it.key())), v); + o->put((s = engine->newString(it.key())).getPointer(), v); } return o.asReturnedValue(); } -QJsonObject JsonObject::toJsonObject(ObjectRef o, V4ObjectSet &visitedObjects) +QJsonObject JsonObject::toJsonObject(Object *o, V4ObjectSet &visitedObjects) { QJsonObject result; if (!o || o->asFunctionObject()) @@ -1061,7 +1061,7 @@ QV4::ReturnedValue JsonObject::fromJsonArray(ExecutionEngine *engine, const QJso return a.asReturnedValue(); } -QJsonArray JsonObject::toJsonArray(ArrayObjectRef a, V4ObjectSet &visitedObjects) +QJsonArray JsonObject::toJsonArray(ArrayObject *a, V4ObjectSet &visitedObjects) { QJsonArray result; if (!a) diff --git a/src/qml/jsruntime/qv4jsonobject_p.h b/src/qml/jsruntime/qv4jsonobject_p.h index 34a4f4dd4b..03d5ad29c8 100644 --- a/src/qml/jsruntime/qv4jsonobject_p.h +++ b/src/qml/jsruntime/qv4jsonobject_p.h @@ -51,12 +51,14 @@ QT_BEGIN_NAMESPACE namespace QV4 { struct JsonObject : Object { + struct Data : Object::Data { + Data(InternalClass *ic); + }; Q_MANAGED_TYPE(JsonObject) - V4_OBJECT + V4_OBJECT(Object) private: typedef QSet<QV4::Object *> V4ObjectSet; public: - JsonObject(InternalClass *ic); static ReturnedValue method_parse(CallContext *ctx); static ReturnedValue method_stringify(CallContext *ctx); @@ -67,15 +69,15 @@ public: static inline QJsonValue toJsonValue(const QV4::ValueRef value) { V4ObjectSet visitedObjects; return toJsonValue(value, visitedObjects); } - static inline QJsonObject toJsonObject(QV4::ObjectRef o) + static inline QJsonObject toJsonObject(QV4::Object *o) { V4ObjectSet visitedObjects; return toJsonObject(o, visitedObjects); } - static inline QJsonArray toJsonArray(QV4::ArrayObjectRef a) + static inline QJsonArray toJsonArray(QV4::ArrayObject *a) { V4ObjectSet visitedObjects; return toJsonArray(a, visitedObjects); } private: static QJsonValue toJsonValue(const QV4::ValueRef value, V4ObjectSet &visitedObjects); - static QJsonObject toJsonObject(QV4::ObjectRef o, V4ObjectSet &visitedObjects); - static QJsonArray toJsonArray(QV4::ArrayObjectRef a, V4ObjectSet &visitedObjects); + static QJsonObject toJsonObject(Object *o, V4ObjectSet &visitedObjects); + static QJsonArray toJsonArray(ArrayObject *a, V4ObjectSet &visitedObjects); }; diff --git a/src/qml/jsruntime/qv4lookup.cpp b/src/qml/jsruntime/qv4lookup.cpp index 1155bbf9e9..57154c4779 100644 --- a/src/qml/jsruntime/qv4lookup.cpp +++ b/src/qml/jsruntime/qv4lookup.cpp @@ -51,13 +51,13 @@ ReturnedValue Lookup::lookup(ValueRef thisObject, Object *obj, PropertyAttribute { int i = 0; while (i < Size && obj) { - classList[i] = obj->internalClass; + classList[i] = obj->internalClass(); - index = obj->internalClass->find(name); + index = obj->internalClass()->find(name); if (index != UINT_MAX) { level = i; - *attrs = obj->internalClass->propertyData.at(index); - return !attrs->isAccessor() ? obj->memberData[index].asReturnedValue() : obj->getValue(thisObject, obj->propertyAt(index), *attrs); + *attrs = obj->internalClass()->propertyData.at(index); + return !attrs->isAccessor() ? obj->memberData()[index].asReturnedValue() : obj->getValue(thisObject, obj->propertyAt(index), *attrs); } obj = obj->prototype(); @@ -66,10 +66,10 @@ ReturnedValue Lookup::lookup(ValueRef thisObject, Object *obj, PropertyAttribute level = Size; while (obj) { - index = obj->internalClass->find(name); + index = obj->internalClass()->find(name); if (index != UINT_MAX) { - *attrs = obj->internalClass->propertyData.at(index); - return !attrs->isAccessor() ? obj->memberData[index].asReturnedValue() : obj->getValue(thisObject, obj->propertyAt(index), *attrs); + *attrs = obj->internalClass()->propertyData.at(index); + return !attrs->isAccessor() ? obj->memberData()[index].asReturnedValue() : obj->getValue(thisObject, obj->propertyAt(index), *attrs); } obj = obj->prototype(); @@ -82,13 +82,13 @@ ReturnedValue Lookup::lookup(Object *obj, PropertyAttributes *attrs) Object *thisObject = obj; int i = 0; while (i < Size && obj) { - classList[i] = obj->internalClass; + classList[i] = obj->internalClass(); - index = obj->internalClass->find(name); + index = obj->internalClass()->find(name); if (index != UINT_MAX) { level = i; - *attrs = obj->internalClass->propertyData.at(index); - return !attrs->isAccessor() ? obj->memberData[index].asReturnedValue() : thisObject->getValue(obj->propertyAt(index), *attrs); + *attrs = obj->internalClass()->propertyData.at(index); + return !attrs->isAccessor() ? obj->memberData()[index].asReturnedValue() : thisObject->getValue(obj->propertyAt(index), *attrs); } obj = obj->prototype(); @@ -97,10 +97,10 @@ ReturnedValue Lookup::lookup(Object *obj, PropertyAttributes *attrs) level = Size; while (obj) { - index = obj->internalClass->find(name); + index = obj->internalClass()->find(name); if (index != UINT_MAX) { - *attrs = obj->internalClass->propertyData.at(index); - return !attrs->isAccessor() ? obj->memberData[index].asReturnedValue() : thisObject->getValue(obj->propertyAt(index), *attrs); + *attrs = obj->internalClass()->propertyData.at(index); + return !attrs->isAccessor() ? obj->memberData()[index].asReturnedValue() : thisObject->getValue(obj->propertyAt(index), *attrs); } obj = obj->prototype(); @@ -147,8 +147,8 @@ ReturnedValue Lookup::indexedGetterFallback(Lookup *l, const ValueRef object, co } if (idx < UINT_MAX) { - if (!o->arrayData->hasAttributes()) { - ScopedValue v(scope, o->arrayData->get(idx)); + if (!o->arrayData()->hasAttributes()) { + ScopedValue v(scope, o->arrayData()->get(idx)); if (!v->isEmpty()) return v->asReturnedValue(); } @@ -159,7 +159,7 @@ ReturnedValue Lookup::indexedGetterFallback(Lookup *l, const ValueRef object, co ScopedString name(scope, index->toString(ctx)); if (scope.hasException()) return Encode::undefined(); - return o->get(name); + return o->get(name.getPointer()); } @@ -171,10 +171,10 @@ ReturnedValue Lookup::indexedGetterObjectInt(Lookup *l, const ValueRef object, c return indexedGetterGeneric(l, object, index); Object *o = object->objectValue(); - if (o->arrayData && o->arrayData->type == ArrayData::Simple) { - if (idx < static_cast<SimpleArrayData *>(o->arrayData)->len) - if (!o->arrayData->data[idx].isEmpty()) - return o->arrayData->data[idx].asReturnedValue(); + if (o->arrayData() && o->arrayData()->type() == ArrayData::Simple) { + if (idx < static_cast<SimpleArrayData *>(o->arrayData())->len()) + if (!o->arrayData()->arrayData()[idx].isEmpty()) + return o->arrayData()->arrayData()[idx].asReturnedValue(); } return indexedGetterFallback(l, object, index); @@ -184,7 +184,7 @@ void Lookup::indexedSetterGeneric(Lookup *l, const ValueRef object, const ValueR { if (object->isObject()) { Object *o = object->objectValue(); - if (o->arrayData && o->arrayData->type == ArrayData::Simple && index->asArrayIndex() < UINT_MAX) { + if (o->arrayData() && o->arrayData()->type() == ArrayData::Simple && index->asArrayIndex() < UINT_MAX) { l->indexedSetter = indexedSetterObjectInt; indexedSetterObjectInt(l, object, index, v); return; @@ -203,10 +203,10 @@ void Lookup::indexedSetterFallback(Lookup *l, const ValueRef object, const Value uint idx = index->asArrayIndex(); if (idx < UINT_MAX) { - if (o->arrayData && o->arrayData->type == ArrayData::Simple) { - SimpleArrayData *s = static_cast<SimpleArrayData *>(o->arrayData); - if (s && idx < s->len && !s->data[idx].isEmpty()) { - s->data[idx] = value; + if (o->arrayData() && o->arrayData()->type() == ArrayData::Simple) { + SimpleArrayData *s = static_cast<SimpleArrayData *>(o->arrayData()); + if (s && idx < s->len() && !s->arrayData()[idx].isEmpty()) { + s->arrayData()[idx] = value; return; } } @@ -215,7 +215,7 @@ void Lookup::indexedSetterFallback(Lookup *l, const ValueRef object, const Value } ScopedString name(scope, index->toString(ctx)); - o->put(name, value); + o->put(name.getPointer(), value); } void Lookup::indexedSetterObjectInt(Lookup *l, const ValueRef object, const ValueRef index, const ValueRef v) @@ -227,10 +227,10 @@ void Lookup::indexedSetterObjectInt(Lookup *l, const ValueRef object, const Valu } Object *o = object->objectValue(); - if (o->arrayData && o->arrayData->type == ArrayData::Simple) { - SimpleArrayData *s = static_cast<SimpleArrayData *>(o->arrayData); - if (idx < s->len && !s->data[idx].isEmpty()) { - s->data[idx] = v; + if (o->arrayData() && o->arrayData()->type() == ArrayData::Simple) { + SimpleArrayData *s = static_cast<SimpleArrayData *>(o->arrayData()); + if (idx < s->len() && !s->arrayData()[idx].isEmpty()) { + s->arrayData()[idx] = v; return; } } @@ -254,7 +254,7 @@ ReturnedValue Lookup::getterGeneric(QV4::Lookup *l, const ValueRef object) case Value::Managed_Type: Q_ASSERT(object->isString()); proto = engine->stringObjectClass->prototype; - if (l->name->equals(engine->id_length)) { + if (l->name->equals(engine->id_length.getPointer())) { // special case, as the property is on the object itself l->getter = stringLengthGetter; return stringLengthGetter(l, object); @@ -331,7 +331,7 @@ ReturnedValue Lookup::getterFallback(Lookup *l, const ValueRef object) if (!o) return Encode::undefined(); QV4::ScopedString s(scope, l->name); - return o->get(s); + return o->get(s.getPointer()); } ReturnedValue Lookup::getter0(Lookup *l, const ValueRef object) @@ -340,8 +340,8 @@ ReturnedValue Lookup::getter0(Lookup *l, const ValueRef object) // we can safely cast to a QV4::Object here. If object is actually a string, // the internal class won't match Object *o = object->objectValue(); - if (l->classList[0] == o->internalClass) - return o->memberData[l->index].asReturnedValue(); + if (l->classList[0] == o->internalClass()) + return o->memberData()[l->index].asReturnedValue(); } return getterTwoClasses(l, object); } @@ -352,9 +352,9 @@ ReturnedValue Lookup::getter1(Lookup *l, const ValueRef object) // we can safely cast to a QV4::Object here. If object is actually a string, // the internal class won't match Object *o = object->objectValue(); - if (l->classList[0] == o->internalClass && - l->classList[1] == o->prototype()->internalClass) - return o->prototype()->memberData[l->index].asReturnedValue(); + if (l->classList[0] == o->internalClass() && + l->classList[1] == o->prototype()->internalClass()) + return o->prototype()->memberData()[l->index].asReturnedValue(); } return getterTwoClasses(l, object); } @@ -365,12 +365,12 @@ ReturnedValue Lookup::getter2(Lookup *l, const ValueRef object) // we can safely cast to a QV4::Object here. If object is actually a string, // the internal class won't match Object *o = object->objectValue(); - if (l->classList[0] == o->internalClass) { + if (l->classList[0] == o->internalClass()) { o = o->prototype(); - if (l->classList[1] == o->internalClass) { + if (l->classList[1] == o->internalClass()) { o = o->prototype(); - if (l->classList[2] == o->internalClass) - return o->memberData[l->index].asReturnedValue(); + if (l->classList[2] == o->internalClass()) + return o->memberData()[l->index].asReturnedValue(); } } } @@ -384,10 +384,10 @@ ReturnedValue Lookup::getter0getter0(Lookup *l, const ValueRef object) // we can safely cast to a QV4::Object here. If object is actually a string, // the internal class won't match Object *o = object->objectValue(); - if (l->classList[0] == o->internalClass) - return o->memberData[l->index].asReturnedValue(); - if (l->classList[2] == o->internalClass) - return o->memberData[l->index2].asReturnedValue(); + if (l->classList[0] == o->internalClass()) + return o->memberData()[l->index].asReturnedValue(); + if (l->classList[2] == o->internalClass()) + return o->memberData()[l->index2].asReturnedValue(); } l->getter = getterFallback; return getterFallback(l, object); @@ -399,11 +399,11 @@ ReturnedValue Lookup::getter0getter1(Lookup *l, const ValueRef object) // we can safely cast to a QV4::Object here. If object is actually a string, // the internal class won't match Object *o = object->objectValue(); - if (l->classList[0] == o->internalClass) - return o->memberData[l->index].asReturnedValue(); - if (l->classList[2] == o->internalClass && - l->classList[3] == o->prototype()->internalClass) - return o->prototype()->memberData[l->index2].asReturnedValue(); + if (l->classList[0] == o->internalClass()) + return o->memberData()[l->index].asReturnedValue(); + if (l->classList[2] == o->internalClass() && + l->classList[3] == o->prototype()->internalClass()) + return o->prototype()->memberData()[l->index2].asReturnedValue(); } l->getter = getterFallback; return getterFallback(l, object); @@ -415,12 +415,12 @@ ReturnedValue Lookup::getter1getter1(Lookup *l, const ValueRef object) // we can safely cast to a QV4::Object here. If object is actually a string, // the internal class won't match Object *o = object->objectValue(); - if (l->classList[0] == o->internalClass && - l->classList[1] == o->prototype()->internalClass) - return o->prototype()->memberData[l->index].asReturnedValue(); - if (l->classList[2] == o->internalClass && - l->classList[3] == o->prototype()->internalClass) - return o->prototype()->memberData[l->index2].asReturnedValue(); + if (l->classList[0] == o->internalClass() && + l->classList[1] == o->prototype()->internalClass()) + return o->prototype()->memberData()[l->index].asReturnedValue(); + if (l->classList[2] == o->internalClass() && + l->classList[3] == o->prototype()->internalClass()) + return o->prototype()->memberData()[l->index2].asReturnedValue(); return getterFallback(l, object); } l->getter = getterFallback; @@ -434,7 +434,7 @@ ReturnedValue Lookup::getterAccessor0(Lookup *l, const ValueRef object) // we can safely cast to a QV4::Object here. If object is actually a string, // the internal class won't match Object *o = object->objectValue(); - if (l->classList[0] == o->internalClass) { + if (l->classList[0] == o->internalClass()) { Scope scope(o->engine()); FunctionObject *getter = o->propertyAt(l->index)->getter(); if (!getter) @@ -455,8 +455,8 @@ ReturnedValue Lookup::getterAccessor1(Lookup *l, const ValueRef object) // we can safely cast to a QV4::Object here. If object is actually a string, // the internal class won't match Object *o = object->objectValue(); - if (l->classList[0] == o->internalClass && - l->classList[1] == o->prototype()->internalClass) { + if (l->classList[0] == o->internalClass() && + l->classList[1] == o->prototype()->internalClass()) { Scope scope(o->engine()); FunctionObject *getter = o->prototype()->propertyAt(l->index)->getter(); if (!getter) @@ -477,11 +477,11 @@ ReturnedValue Lookup::getterAccessor2(Lookup *l, const ValueRef object) // we can safely cast to a QV4::Object here. If object is actually a string, // the internal class won't match Object *o = object->objectValue(); - if (l->classList[0] == o->internalClass) { + if (l->classList[0] == o->internalClass()) { o = o->prototype(); - if (l->classList[1] == o->internalClass) { + if (l->classList[1] == o->internalClass()) { o = o->prototype(); - if (l->classList[2] == o->internalClass) { + if (l->classList[2] == o->internalClass()) { Scope scope(o->engine()); FunctionObject *getter = o->propertyAt(l->index)->getter(); if (!getter) @@ -502,8 +502,8 @@ ReturnedValue Lookup::primitiveGetter0(Lookup *l, const ValueRef object) { if (object->type() == l->type) { Object *o = l->proto; - if (l->classList[0] == o->internalClass) - return o->memberData[l->index].asReturnedValue(); + if (l->classList[0] == o->internalClass()) + return o->memberData()[l->index].asReturnedValue(); } l->getter = getterGeneric; return getterGeneric(l, object); @@ -513,9 +513,9 @@ ReturnedValue Lookup::primitiveGetter1(Lookup *l, const ValueRef object) { if (object->type() == l->type) { Object *o = l->proto; - if (l->classList[0] == o->internalClass && - l->classList[1] == o->prototype()->internalClass) - return o->prototype()->memberData[l->index].asReturnedValue(); + if (l->classList[0] == o->internalClass() && + l->classList[1] == o->prototype()->internalClass()) + return o->prototype()->memberData()[l->index].asReturnedValue(); } l->getter = getterGeneric; return getterGeneric(l, object); @@ -525,7 +525,7 @@ ReturnedValue Lookup::primitiveGetterAccessor0(Lookup *l, const ValueRef object) { if (object->type() == l->type) { Object *o = l->proto; - if (l->classList[0] == o->internalClass) { + if (l->classList[0] == o->internalClass()) { Scope scope(o->engine()); FunctionObject *getter = o->propertyAt(l->index)->getter(); if (!getter) @@ -544,8 +544,8 @@ ReturnedValue Lookup::primitiveGetterAccessor1(Lookup *l, const ValueRef object) { if (object->type() == l->type) { Object *o = l->proto; - if (l->classList[0] == o->internalClass && - l->classList[1] == o->prototype()->internalClass) { + if (l->classList[0] == o->internalClass() && + l->classList[1] == o->prototype()->internalClass()) { Scope scope(o->engine()); FunctionObject *getter = o->prototype()->propertyAt(l->index)->getter(); if (!getter) @@ -563,7 +563,7 @@ ReturnedValue Lookup::primitiveGetterAccessor1(Lookup *l, const ValueRef object) ReturnedValue Lookup::stringLengthGetter(Lookup *l, const ValueRef object) { if (String *s = object->asString()) - return Encode(s->length()); + return Encode(s->d()->length()); l->getter = getterGeneric; return getterGeneric(l, object); @@ -572,7 +572,7 @@ ReturnedValue Lookup::stringLengthGetter(Lookup *l, const ValueRef object) ReturnedValue Lookup::arrayLengthGetter(Lookup *l, const ValueRef object) { if (ArrayObject *a = object->asArrayObject()) - return a->memberData[ArrayObject::LengthPropertyIndex].asReturnedValue(); + return a->memberData()[ArrayObject::LengthPropertyIndex].asReturnedValue(); l->getter = getterGeneric; return getterGeneric(l, object); @@ -581,7 +581,7 @@ ReturnedValue Lookup::arrayLengthGetter(Lookup *l, const ValueRef object) ReturnedValue Lookup::globalGetterGeneric(Lookup *l, ExecutionContext *ctx) { - Object *o = ctx->engine->globalObject; + Object *o = ctx->d()->engine->globalObject; PropertyAttributes attrs; ReturnedValue v = l->lookup(o, &attrs); if (v != Primitive::emptyValue().asReturnedValue()) { @@ -610,9 +610,9 @@ ReturnedValue Lookup::globalGetterGeneric(Lookup *l, ExecutionContext *ctx) ReturnedValue Lookup::globalGetter0(Lookup *l, ExecutionContext *ctx) { - Object *o = ctx->engine->globalObject; - if (l->classList[0] == o->internalClass) - return o->memberData[l->index].asReturnedValue(); + Object *o = ctx->d()->engine->globalObject; + if (l->classList[0] == o->internalClass()) + return o->memberData()[l->index].asReturnedValue(); l->globalGetter = globalGetterGeneric; return globalGetterGeneric(l, ctx); @@ -620,10 +620,10 @@ ReturnedValue Lookup::globalGetter0(Lookup *l, ExecutionContext *ctx) ReturnedValue Lookup::globalGetter1(Lookup *l, ExecutionContext *ctx) { - Object *o = ctx->engine->globalObject; - if (l->classList[0] == o->internalClass && - l->classList[1] == o->prototype()->internalClass) - return o->prototype()->memberData[l->index].asReturnedValue(); + Object *o = ctx->d()->engine->globalObject; + if (l->classList[0] == o->internalClass() && + l->classList[1] == o->prototype()->internalClass()) + return o->prototype()->memberData()[l->index].asReturnedValue(); l->globalGetter = globalGetterGeneric; return globalGetterGeneric(l, ctx); @@ -631,13 +631,13 @@ ReturnedValue Lookup::globalGetter1(Lookup *l, ExecutionContext *ctx) ReturnedValue Lookup::globalGetter2(Lookup *l, ExecutionContext *ctx) { - Object *o = ctx->engine->globalObject; - if (l->classList[0] == o->internalClass) { + Object *o = ctx->d()->engine->globalObject; + if (l->classList[0] == o->internalClass()) { o = o->prototype(); - if (l->classList[1] == o->internalClass) { + if (l->classList[1] == o->internalClass()) { o = o->prototype(); - if (l->classList[2] == o->internalClass) { - return o->prototype()->memberData[l->index].asReturnedValue(); + if (l->classList[2] == o->internalClass()) { + return o->prototype()->memberData()[l->index].asReturnedValue(); } } } @@ -647,8 +647,8 @@ ReturnedValue Lookup::globalGetter2(Lookup *l, ExecutionContext *ctx) ReturnedValue Lookup::globalGetterAccessor0(Lookup *l, ExecutionContext *ctx) { - Object *o = ctx->engine->globalObject; - if (l->classList[0] == o->internalClass) { + Object *o = ctx->d()->engine->globalObject; + if (l->classList[0] == o->internalClass()) { Scope scope(o->engine()); FunctionObject *getter = o->propertyAt(l->index)->getter(); if (!getter) @@ -664,9 +664,9 @@ ReturnedValue Lookup::globalGetterAccessor0(Lookup *l, ExecutionContext *ctx) ReturnedValue Lookup::globalGetterAccessor1(Lookup *l, ExecutionContext *ctx) { - Object *o = ctx->engine->globalObject; - if (l->classList[0] == o->internalClass && - l->classList[1] == o->prototype()->internalClass) { + Object *o = ctx->d()->engine->globalObject; + if (l->classList[0] == o->internalClass() && + l->classList[1] == o->prototype()->internalClass()) { Scope scope(o->engine()); FunctionObject *getter = o->prototype()->propertyAt(l->index)->getter(); if (!getter) @@ -682,12 +682,12 @@ ReturnedValue Lookup::globalGetterAccessor1(Lookup *l, ExecutionContext *ctx) ReturnedValue Lookup::globalGetterAccessor2(Lookup *l, ExecutionContext *ctx) { - Object *o = ctx->engine->globalObject; - if (l->classList[0] == o->internalClass) { + Object *o = ctx->d()->engine->globalObject; + if (l->classList[0] == o->internalClass()) { o = o->prototype(); - if (l->classList[1] == o->internalClass) { + if (l->classList[1] == o->internalClass()) { o = o->prototype(); - if (l->classList[2] == o->internalClass) { + if (l->classList[2] == o->internalClass()) { Scope scope(o->engine()); FunctionObject *getter = o->propertyAt(l->index)->getter(); if (!getter) @@ -712,7 +712,7 @@ void Lookup::setterGeneric(Lookup *l, const ValueRef object, const ValueRef valu if (!o) // type error return; ScopedString s(scope, l->name); - o->put(s, value); + o->put(s.getPointer(), value); return; } o->setLookup(l, value); @@ -743,15 +743,15 @@ void Lookup::setterFallback(Lookup *l, const ValueRef object, const ValueRef val QV4::ScopedObject o(scope, object->toObject(scope.engine->currentContext())); if (o) { QV4::ScopedString s(scope, l->name); - o->put(s, value); + o->put(s.getPointer(), value); } } void Lookup::setter0(Lookup *l, const ValueRef object, const ValueRef value) { Object *o = static_cast<Object *>(object->asManaged()); - if (o && o->internalClass == l->classList[0]) { - o->memberData[l->index] = *value; + if (o && o->internalClass() == l->classList[0]) { + o->memberData()[l->index] = *value; return; } @@ -761,12 +761,12 @@ void Lookup::setter0(Lookup *l, const ValueRef object, const ValueRef value) void Lookup::setterInsert0(Lookup *l, const ValueRef object, const ValueRef value) { Object *o = static_cast<Object *>(object->asManaged()); - if (o && o->internalClass == l->classList[0]) { + if (o && o->internalClass() == l->classList[0]) { if (!o->prototype()) { - if (l->index >= o->memberData.size()) + if (l->index >= o->memberData().size()) o->ensureMemberIndex(l->index); - o->memberData[l->index] = *value; - o->internalClass = l->classList[3]; + o->memberData()[l->index] = *value; + o->setInternalClass(l->classList[3]); return; } } @@ -778,13 +778,13 @@ void Lookup::setterInsert0(Lookup *l, const ValueRef object, const ValueRef valu void Lookup::setterInsert1(Lookup *l, const ValueRef object, const ValueRef value) { Object *o = static_cast<Object *>(object->asManaged()); - if (o && o->internalClass == l->classList[0]) { + if (o && o->internalClass() == l->classList[0]) { Object *p = o->prototype(); - if (p && p->internalClass == l->classList[1]) { - if (l->index >= o->memberData.size()) + if (p && p->internalClass() == l->classList[1]) { + if (l->index >= o->memberData().size()) o->ensureMemberIndex(l->index); - o->memberData[l->index] = *value; - o->internalClass = l->classList[3]; + o->memberData()[l->index] = *value; + o->setInternalClass(l->classList[3]); return; } } @@ -796,15 +796,15 @@ void Lookup::setterInsert1(Lookup *l, const ValueRef object, const ValueRef valu void Lookup::setterInsert2(Lookup *l, const ValueRef object, const ValueRef value) { Object *o = static_cast<Object *>(object->asManaged()); - if (o && o->internalClass == l->classList[0]) { + if (o && o->internalClass() == l->classList[0]) { Object *p = o->prototype(); - if (p && p->internalClass == l->classList[1]) { + if (p && p->internalClass() == l->classList[1]) { p = p->prototype(); - if (p && p->internalClass == l->classList[2]) { - if (l->index >= o->memberData.size()) + if (p && p->internalClass() == l->classList[2]) { + if (l->index >= o->memberData().size()) o->ensureMemberIndex(l->index); - o->memberData[l->index] = *value; - o->internalClass = l->classList[3]; + o->memberData()[l->index] = *value; + o->setInternalClass(l->classList[3]); return; } } @@ -818,12 +818,12 @@ void Lookup::setter0setter0(Lookup *l, const ValueRef object, const ValueRef val { Object *o = static_cast<Object *>(object->asManaged()); if (o) { - if (o->internalClass == l->classList[0]) { - o->memberData[l->index] = *value; + if (o->internalClass() == l->classList[0]) { + o->memberData()[l->index] = *value; return; } - if (o->internalClass == l->classList[1]) { - o->memberData[l->index2] = *value; + if (o->internalClass() == l->classList[1]) { + o->memberData()[l->index2] = *value; return; } } diff --git a/src/qml/jsruntime/qv4managed.cpp b/src/qml/jsruntime/qv4managed.cpp index 1f4030a4ed..6fc402e48f 100644 --- a/src/qml/jsruntime/qv4managed.cpp +++ b/src/qml/jsruntime/qv4managed.cpp @@ -45,8 +45,10 @@ using namespace QV4; + const ManagedVTable Managed::static_vtbl = { + 0, Managed::IsExecutionContext, Managed::IsString, Managed::IsObject, @@ -56,7 +58,7 @@ const ManagedVTable Managed::static_vtbl = 0, Managed::MyType, "Managed", - destroy, + 0, 0 /*markObjects*/, isEqualTo }; @@ -69,33 +71,15 @@ void *Managed::operator new(size_t size, MemoryManager *mm) return mm->allocManaged(size); } -void Managed::operator delete(void *ptr) -{ - if (!ptr) - return; - - Managed *m = static_cast<Managed *>(ptr); - m->_data = 0; - m->markBit = 0; - m->~Managed(); -} - -void Managed::operator delete(void *ptr, MemoryManager *mm) -{ - Q_UNUSED(mm); - - operator delete(ptr); -} - ExecutionEngine *Managed::engine() const { - return internalClass ? internalClass->engine : 0; + return internalClass()->engine; } QString Managed::className() const { const char *s = 0; - switch (Type(internalClass->vtable->type)) { + switch (Type(internalClass()->vtable->type)) { case Type_Invalid: case Type_String: return QString(); @@ -124,7 +108,7 @@ QString Managed::className() const s = "RegExp"; break; case Type_ErrorObject: - switch (ErrorObject::ErrorType(subtype)) { + switch (ErrorObject::ErrorType(subtype())) { case ErrorObject::Error: s = "Error"; break; @@ -177,10 +161,17 @@ QString Managed::className() const void Managed::setVTable(const ManagedVTable *vt) { + Q_ASSERT(internalClass()); + d()->internalClass = internalClass()->changeVTable(vt); +} + +void Managed::Data::setVTable(const ManagedVTable *vt) +{ Q_ASSERT(internalClass); internalClass = internalClass->changeVTable(vt); } + bool Managed::isEqualTo(Managed *, Managed *) { return false; diff --git a/src/qml/jsruntime/qv4managed_p.h b/src/qml/jsruntime/qv4managed_p.h index 06d3e4884b..b88531d8ed 100644 --- a/src/qml/jsruntime/qv4managed_p.h +++ b/src/qml/jsruntime/qv4managed_p.h @@ -62,26 +62,44 @@ inline int qYouForgotTheQ_MANAGED_Macro(T, T) { return 0; } template <typename T1, typename T2> inline void qYouForgotTheQ_MANAGED_Macro(T1, T2) {} -#define V4_MANAGED \ +#ifdef Q_COMPILER_STATIC_ASSERT +#define V4_MANAGED_SIZE_TEST void __dataTest() { Q_STATIC_ASSERT(sizeof(*this) == sizeof(Managed)); } +#else +#define V4_MANAGED_SIZE_TEST +#endif + +#define V4_MANAGED(superClass) \ public: \ Q_MANAGED_CHECK \ + typedef superClass SuperClass; \ static const QV4::ManagedVTable static_vtbl; \ static inline const QV4::ManagedVTable *staticVTable() { return &static_vtbl; } \ template <typename T> \ QV4::Returned<T> *asReturned() { return QV4::Returned<T>::create(this); } \ + V4_MANAGED_SIZE_TEST \ + const Data *d() const { return &static_cast<const Data &>(Managed::data); } \ + Data *d() { return &static_cast<Data &>(Managed::data); } -#define V4_OBJECT \ +#define V4_OBJECT(superClass) \ public: \ Q_MANAGED_CHECK \ + typedef superClass SuperClass; \ static const QV4::ObjectVTable static_vtbl; \ static inline const QV4::ManagedVTable *staticVTable() { return &static_vtbl.managedVTable; } \ template <typename T> \ QV4::Returned<T> *asReturned() { return QV4::Returned<T>::create(this); } \ + V4_MANAGED_SIZE_TEST \ + const Data *d() const { return &static_cast<const Data &>(Managed::data); } \ + Data *d() { return &static_cast<Data &>(Managed::data); } #define Q_MANAGED_TYPE(type) \ public: \ enum { MyType = Type_##type }; +#define Q_VTABLE_FUNCTION(classname, func) \ + (classname::func == QV4::Managed::func ? 0 : classname::func) + + struct GCDeletable { GCDeletable() : next(0), lastCall(false) {} @@ -92,6 +110,7 @@ struct GCDeletable struct ManagedVTable { + const ManagedVTable * const parent; uint isExecutionContext : 1; uint isString : 1; uint isObject : 1; @@ -111,22 +130,23 @@ struct ObjectVTable ManagedVTable managedVTable; ReturnedValue (*call)(Managed *, CallData *data); ReturnedValue (*construct)(Managed *, CallData *data); - ReturnedValue (*get)(Managed *, const StringRef name, bool *hasProperty); + ReturnedValue (*get)(Managed *, String *name, bool *hasProperty); ReturnedValue (*getIndexed)(Managed *, uint index, bool *hasProperty); - void (*put)(Managed *, const StringRef name, const ValueRef value); + void (*put)(Managed *, String *name, const ValueRef value); void (*putIndexed)(Managed *, uint index, const ValueRef value); - PropertyAttributes (*query)(const Managed *, StringRef name); + PropertyAttributes (*query)(const Managed *, String *name); PropertyAttributes (*queryIndexed)(const Managed *, uint index); - bool (*deleteProperty)(Managed *m, const StringRef name); + bool (*deleteProperty)(Managed *m, String *name); bool (*deleteIndexedProperty)(Managed *m, uint index); ReturnedValue (*getLookup)(Managed *m, Lookup *l); void (*setLookup)(Managed *m, Lookup *l, const ValueRef v); uint (*getLength)(const Managed *m); - void (*advanceIterator)(Managed *m, ObjectIterator *it, StringRef name, uint *index, Property *p, PropertyAttributes *attributes); + void (*advanceIterator)(Managed *m, ObjectIterator *it, String *&name, uint *index, Property *p, PropertyAttributes *attributes); }; -#define DEFINE_MANAGED_VTABLE_INT(classname) \ +#define DEFINE_MANAGED_VTABLE_INT(classname, parentVTable) \ { \ + parentVTable, \ classname::IsExecutionContext, \ classname::IsString, \ classname::IsObject, \ @@ -135,21 +155,20 @@ struct ObjectVTable classname::IsArrayData, \ 0, \ classname::MyType, \ - #classname, \ - destroy, \ + #classname, \ + Q_VTABLE_FUNCTION(classname, destroy), \ markObjects, \ isEqualTo \ } - #define DEFINE_MANAGED_VTABLE(classname) \ -const QV4::ManagedVTable classname::static_vtbl = DEFINE_MANAGED_VTABLE_INT(classname) +const QV4::ManagedVTable classname::static_vtbl = DEFINE_MANAGED_VTABLE_INT(classname, 0) #define DEFINE_OBJECT_VTABLE(classname) \ const QV4::ObjectVTable classname::static_vtbl = \ { \ - DEFINE_MANAGED_VTABLE_INT(classname), \ + DEFINE_MANAGED_VTABLE_INT(classname, &classname::SuperClass::static_vtbl == &Object::static_vtbl ? 0 : &classname::SuperClass::static_vtbl.managedVTable), \ call, \ construct, \ get, \ @@ -166,30 +185,43 @@ const QV4::ObjectVTable classname::static_vtbl = \ advanceIterator \ } -#define DEFINE_MANAGED_VTABLE_WITH_NAME(classname, name) \ -const QV4::ObjectVTable classname::static_vtbl = \ -{ \ - DEFINE_MANAGED_VTABLE_INT(name), \ - call, \ - construct, \ - get, \ - getIndexed, \ - put, \ - putIndexed, \ - query, \ - queryIndexed, \ - deleteProperty, \ - deleteIndexedProperty, \ - getLookup, \ - setLookup, \ - getLength, \ - advanceIterator \ -} - - struct Q_QML_PRIVATE_EXPORT Managed { - V4_MANAGED + struct Q_QML_PRIVATE_EXPORT Data : HeapObject { + Data() {} + Data(InternalClass *internal) + : internalClass(internal) + , inUse(1) + , extensible(1) + { + // #### +// Q_ASSERT(internal && internal->vtable); + } + InternalClass *internalClass; + struct { + uchar markBit : 1; + uchar inUse : 1; + uchar extensible : 1; // used by Object + uchar _unused : 1; + uchar needsActivation : 1; // used by FunctionObject + uchar strictMode : 1; // used by FunctionObject + uchar bindingKeyFlag : 1; + uchar hasAccessorProperty : 1; + uchar _type; + mutable uchar subtype; + uchar _flags; + }; + + void setVTable(const ManagedVTable *vt); + ReturnedValue asReturnedValue() const { + return reinterpret_cast<Managed *>(const_cast<Data *>(this))->asReturnedValue(); + } + + void *operator new(size_t, Managed *m) { return m; } + void *operator new(size_t, Managed::Data *m) { return m; } + }; + Data data; + V4_MANAGED(Managed) enum { IsExecutionContext = false, IsString = false, @@ -205,17 +237,13 @@ private: protected: Managed(InternalClass *internal) - : internalClass(internal), _data(0) + : data(internal) { - Q_ASSERT(internalClass && internalClass->vtable); - inUse = 1; extensible = 1; } public: void *operator new(size_t size, MemoryManager *mm); void *operator new(size_t, Managed *m) { return m; } - void operator delete(void *ptr); - void operator delete(void *ptr, MemoryManager *mm); inline void mark(QV4::ExecutionEngine *engine); @@ -248,12 +276,18 @@ public: template <typename T> T *as() { // ### FIXME: - if (!this || !internalClass) + if (!this || !internalClass()) return 0; #if !defined(QT_NO_QOBJECT_CHECK) static_cast<T *>(this)->qt_check_for_QMANAGED_macro(static_cast<T *>(this)); #endif - return internalClass->vtable == T::staticVTable() ? static_cast<T *>(this) : 0; + const ManagedVTable *vt = internalClass()->vtable; + while (vt) { + if (vt == T::staticVTable()) + return static_cast<T *>(this); + vt = vt->parent; + } + return 0; } template <typename T> const T *as() const { @@ -263,24 +297,30 @@ public: #if !defined(QT_NO_QOBJECT_CHECK) static_cast<T *>(this)->qt_check_for_QMANAGED_macro(static_cast<T *>(const_cast<Managed *>(this))); #endif - return internalClass->vtable == T::staticVTable() ? static_cast<const T *>(this) : 0; + const ManagedVTable *vt = internalClass()->vtable; + while (vt) { + if (vt == T::staticVTable()) + return static_cast<T *>(this); + vt = vt->parent; + } + return 0; } - String *asString() { return internalClass->vtable->isString ? reinterpret_cast<String *>(this) : 0; } - Object *asObject() { return internalClass->vtable->isObject ? reinterpret_cast<Object *>(this) : 0; } - ArrayObject *asArrayObject() { return internalClass->vtable->type == Type_ArrayObject ? reinterpret_cast<ArrayObject *>(this) : 0; } - FunctionObject *asFunctionObject() { return internalClass->vtable->isFunctionObject ? reinterpret_cast<FunctionObject *>(this) : 0; } - BooleanObject *asBooleanObject() { return internalClass->vtable->type == Type_BooleanObject ? reinterpret_cast<BooleanObject *>(this) : 0; } - NumberObject *asNumberObject() { return internalClass->vtable->type == Type_NumberObject ? reinterpret_cast<NumberObject *>(this) : 0; } - StringObject *asStringObject() { return internalClass->vtable->type == Type_StringObject ? reinterpret_cast<StringObject *>(this) : 0; } - DateObject *asDateObject() { return internalClass->vtable->type == Type_DateObject ? reinterpret_cast<DateObject *>(this) : 0; } - ErrorObject *asErrorObject() { return internalClass->vtable->isErrorObject ? reinterpret_cast<ErrorObject *>(this) : 0; } - ArgumentsObject *asArgumentsObject() { return internalClass->vtable->type == Type_ArgumentsObject ? reinterpret_cast<ArgumentsObject *>(this) : 0; } + String *asString() { return internalClass()->vtable->isString ? reinterpret_cast<String *>(this) : 0; } + Object *asObject() { return internalClass()->vtable->isObject ? reinterpret_cast<Object *>(this) : 0; } + ArrayObject *asArrayObject() { return internalClass()->vtable->type == Type_ArrayObject ? reinterpret_cast<ArrayObject *>(this) : 0; } + FunctionObject *asFunctionObject() { return internalClass()->vtable->isFunctionObject ? reinterpret_cast<FunctionObject *>(this) : 0; } + BooleanObject *asBooleanObject() { return internalClass()->vtable->type == Type_BooleanObject ? reinterpret_cast<BooleanObject *>(this) : 0; } + NumberObject *asNumberObject() { return internalClass()->vtable->type == Type_NumberObject ? reinterpret_cast<NumberObject *>(this) : 0; } + StringObject *asStringObject() { return internalClass()->vtable->type == Type_StringObject ? reinterpret_cast<StringObject *>(this) : 0; } + DateObject *asDateObject() { return internalClass()->vtable->type == Type_DateObject ? reinterpret_cast<DateObject *>(this) : 0; } + ErrorObject *asErrorObject() { return internalClass()->vtable->isErrorObject ? reinterpret_cast<ErrorObject *>(this) : 0; } + ArgumentsObject *asArgumentsObject() { return internalClass()->vtable->type == Type_ArgumentsObject ? reinterpret_cast<ArgumentsObject *>(this) : 0; } - bool isListType() const { return internalClass->vtable->type == Type_QmlSequence; } + bool isListType() const { return internalClass()->vtable->type == Type_QmlSequence; } - bool isArrayObject() const { return internalClass->vtable->type == Type_ArrayObject; } - bool isStringObject() const { return internalClass->vtable->type == Type_StringObject; } + bool isArrayObject() const { return internalClass()->vtable->type == Type_ArrayObject; } + bool isStringObject() const { return internalClass()->vtable->type == Type_StringObject; } QString className() const; @@ -297,33 +337,22 @@ public: void setVTable(const ManagedVTable *vt); bool isEqualTo(Managed *other) - { return internalClass->vtable->isEqualTo(this, other); } + { return internalClass()->vtable->isEqualTo(this, other); } - static void destroy(Managed *that) { that->_data = 0; } static bool isEqualTo(Managed *m, Managed *other); ReturnedValue asReturnedValue() { return Value::fromManaged(this).asReturnedValue(); } + InternalClass *internalClass() const { return d()->internalClass; } + void setInternalClass(InternalClass *ic) { d()->internalClass = ic; } - InternalClass *internalClass; + uchar subtype() const { return d()->subtype; } + void setSubtype(uchar subtype) const { d()->subtype = subtype; } - union { - uint _data; - struct { - uchar markBit : 1; - uchar inUse : 1; - uchar extensible : 1; // used by Object - uchar _unused : 1; - uchar needsActivation : 1; // used by FunctionObject - uchar strictMode : 1; // used by FunctionObject - uchar bindingKeyFlag : 1; - uchar hasAccessorProperty : 1; - uchar _type; - mutable uchar subtype; - uchar _flags; - }; - }; + bool inUse() const { return d()->inUse; } + bool markBit() const { return d()->markBit; } + static void destroy(Managed *) {} private: friend class MemoryManager; friend struct Identifiers; @@ -358,69 +387,6 @@ inline FunctionObject *managed_cast(Managed *m) return m->asFunctionObject(); } - -Value *extractValuePointer(const ScopedValue &); -template<typename T> -Value *extractValuePointer(const Scoped<T> &); - -#define DEFINE_REF_METHODS(Class, Base) \ - Class##Ref(const QV4::ScopedValue &v) \ - { QV4::Value *val = extractValuePointer(v); ptr = QV4::value_cast<Class>(*val) ? val : 0; } \ - Class##Ref(const QV4::Scoped<Class> &v) { ptr = extractValuePointer(v); } \ - Class##Ref(QV4::TypedValue<Class> &v) { ptr = &v; } \ - Class##Ref(QV4::Value &v) { ptr = QV4::value_cast<Class>(v) ? &v : 0; } \ - Class##Ref &operator=(Class *t) { \ - if (sizeof(void *) == 4) \ - ptr->tag = QV4::Value::Managed_Type; \ - ptr->m = t; \ - return *this; \ - } \ - Class##Ref &operator=(QV4::Returned<Class> *t) { \ - if (sizeof(void *) == 4) \ - ptr->tag = QV4::Value::Managed_Type; \ - ptr->m = t->getPointer(); \ - return *this; \ - } \ - operator const Class *() const { return ptr ? static_cast<Class*>(ptr->managed()) : 0; } \ - const Class *operator->() const { return static_cast<Class*>(ptr->managed()); } \ - operator Class *() { return ptr ? static_cast<Class*>(ptr->managed()) : 0; } \ - Class *operator->() { return static_cast<Class*>(ptr->managed()); } \ - Class *getPointer() const { return static_cast<Class *>(ptr->managed()); } \ - operator QV4::Returned<Class> *() const { return ptr ? QV4::Returned<Class>::create(getPointer()) : 0; } \ - static Class##Ref null() { Class##Ref c; c.ptr = 0; return c; } \ -protected: \ - Class##Ref() {} \ -public: \ - -#define DEFINE_REF(Class, Base) \ -struct Class##Ref : public Base##Ref \ -{ DEFINE_REF_METHODS(Class, Base) } \ - - -struct ManagedRef { - // Important: Do NOT add a copy constructor to this class or any derived class - // adding a copy constructor actually changes the calling convention, ie. - // is not even binary compatible. Adding it would break assumptions made - // in the jit'ed code. - DEFINE_REF_METHODS(Managed, Managed); - - bool operator==(const ManagedRef &other) { - if (ptr == other.ptr) - return true; - return ptr && other.ptr && ptr->m == other.ptr->m; - } - bool operator!=(const ManagedRef &other) { - return !operator==(other); - } - bool operator!() const { return !ptr || !ptr->managed(); } - - bool isNull() const { return !ptr; } - ReturnedValue asReturnedValue() const { return ptr ? ptr->val : Primitive::undefinedValue().asReturnedValue(); } - -public: - Value *ptr; -}; - } diff --git a/src/qml/jsruntime/qv4mathobject.cpp b/src/qml/jsruntime/qv4mathobject.cpp index 16d76e6914..3b8100c3fb 100644 --- a/src/qml/jsruntime/qv4mathobject.cpp +++ b/src/qml/jsruntime/qv4mathobject.cpp @@ -55,39 +55,39 @@ DEFINE_OBJECT_VTABLE(MathObject); static const double qt_PI = 2.0 * ::asin(1.0); -MathObject::MathObject(InternalClass *ic) - : Object(ic) +MathObject::Data::Data(InternalClass *ic) + : Object::Data(ic) { Scope scope(ic->engine); - ScopedObject protectThis(scope, this); - - defineReadonlyProperty(QStringLiteral("E"), Primitive::fromDouble(::exp(1.0))); - defineReadonlyProperty(QStringLiteral("LN2"), Primitive::fromDouble(::log(2.0))); - defineReadonlyProperty(QStringLiteral("LN10"), Primitive::fromDouble(::log(10.0))); - defineReadonlyProperty(QStringLiteral("LOG2E"), Primitive::fromDouble(1.0/::log(2.0))); - defineReadonlyProperty(QStringLiteral("LOG10E"), Primitive::fromDouble(1.0/::log(10.0))); - defineReadonlyProperty(QStringLiteral("PI"), Primitive::fromDouble(qt_PI)); - defineReadonlyProperty(QStringLiteral("SQRT1_2"), Primitive::fromDouble(::sqrt(0.5))); - defineReadonlyProperty(QStringLiteral("SQRT2"), Primitive::fromDouble(::sqrt(2.0))); - - defineDefaultProperty(QStringLiteral("abs"), method_abs, 1); - defineDefaultProperty(QStringLiteral("acos"), method_acos, 1); - defineDefaultProperty(QStringLiteral("asin"), method_asin, 0); - defineDefaultProperty(QStringLiteral("atan"), method_atan, 1); - defineDefaultProperty(QStringLiteral("atan2"), method_atan2, 2); - defineDefaultProperty(QStringLiteral("ceil"), method_ceil, 1); - defineDefaultProperty(QStringLiteral("cos"), method_cos, 1); - defineDefaultProperty(QStringLiteral("exp"), method_exp, 1); - defineDefaultProperty(QStringLiteral("floor"), method_floor, 1); - defineDefaultProperty(QStringLiteral("log"), method_log, 1); - defineDefaultProperty(QStringLiteral("max"), method_max, 2); - defineDefaultProperty(QStringLiteral("min"), method_min, 2); - defineDefaultProperty(QStringLiteral("pow"), method_pow, 2); - defineDefaultProperty(QStringLiteral("random"), method_random, 0); - defineDefaultProperty(QStringLiteral("round"), method_round, 1); - defineDefaultProperty(QStringLiteral("sin"), method_sin, 1); - defineDefaultProperty(QStringLiteral("sqrt"), method_sqrt, 1); - defineDefaultProperty(QStringLiteral("tan"), method_tan, 1); + ScopedObject m(scope, this); + + m->defineReadonlyProperty(QStringLiteral("E"), Primitive::fromDouble(::exp(1.0))); + m->defineReadonlyProperty(QStringLiteral("LN2"), Primitive::fromDouble(::log(2.0))); + m->defineReadonlyProperty(QStringLiteral("LN10"), Primitive::fromDouble(::log(10.0))); + m->defineReadonlyProperty(QStringLiteral("LOG2E"), Primitive::fromDouble(1.0/::log(2.0))); + m->defineReadonlyProperty(QStringLiteral("LOG10E"), Primitive::fromDouble(1.0/::log(10.0))); + m->defineReadonlyProperty(QStringLiteral("PI"), Primitive::fromDouble(qt_PI)); + m->defineReadonlyProperty(QStringLiteral("SQRT1_2"), Primitive::fromDouble(::sqrt(0.5))); + m->defineReadonlyProperty(QStringLiteral("SQRT2"), Primitive::fromDouble(::sqrt(2.0))); + + m->defineDefaultProperty(QStringLiteral("abs"), method_abs, 1); + m->defineDefaultProperty(QStringLiteral("acos"), method_acos, 1); + m->defineDefaultProperty(QStringLiteral("asin"), method_asin, 0); + m->defineDefaultProperty(QStringLiteral("atan"), method_atan, 1); + m->defineDefaultProperty(QStringLiteral("atan2"), method_atan2, 2); + m->defineDefaultProperty(QStringLiteral("ceil"), method_ceil, 1); + m->defineDefaultProperty(QStringLiteral("cos"), method_cos, 1); + m->defineDefaultProperty(QStringLiteral("exp"), method_exp, 1); + m->defineDefaultProperty(QStringLiteral("floor"), method_floor, 1); + m->defineDefaultProperty(QStringLiteral("log"), method_log, 1); + m->defineDefaultProperty(QStringLiteral("max"), method_max, 2); + m->defineDefaultProperty(QStringLiteral("min"), method_min, 2); + m->defineDefaultProperty(QStringLiteral("pow"), method_pow, 2); + m->defineDefaultProperty(QStringLiteral("random"), method_random, 0); + m->defineDefaultProperty(QStringLiteral("round"), method_round, 1); + m->defineDefaultProperty(QStringLiteral("sin"), method_sin, 1); + m->defineDefaultProperty(QStringLiteral("sqrt"), method_sqrt, 1); + m->defineDefaultProperty(QStringLiteral("tan"), method_tan, 1); } /* copies the sign from y to x and returns the result */ @@ -104,15 +104,15 @@ static double copySign(double x, double y) ReturnedValue MathObject::method_abs(CallContext *context) { - if (!context->callData->argc) + if (!context->d()->callData->argc) return Encode(qSNaN()); - if (context->callData->args[0].isInteger()) { - int i = context->callData->args[0].integerValue(); + if (context->d()->callData->args[0].isInteger()) { + int i = context->d()->callData->args[0].integerValue(); return Encode(i < 0 ? - i : i); } - double v = context->callData->args[0].toNumber(); + double v = context->d()->callData->args[0].toNumber(); if (v == 0) // 0 | -0 return Encode(0); @@ -121,7 +121,7 @@ ReturnedValue MathObject::method_abs(CallContext *context) ReturnedValue MathObject::method_acos(CallContext *context) { - double v = context->callData->argc ? context->callData->args[0].toNumber() : 2; + double v = context->d()->callData->argc ? context->d()->callData->args[0].toNumber() : 2; if (v > 1) return Encode(qSNaN()); @@ -130,7 +130,7 @@ ReturnedValue MathObject::method_acos(CallContext *context) ReturnedValue MathObject::method_asin(CallContext *context) { - double v = context->callData->argc ? context->callData->args[0].toNumber() : 2; + double v = context->d()->callData->argc ? context->d()->callData->args[0].toNumber() : 2; if (v > 1) return Encode(qSNaN()); else @@ -139,7 +139,7 @@ ReturnedValue MathObject::method_asin(CallContext *context) ReturnedValue MathObject::method_atan(CallContext *context) { - double v = context->callData->argc ? context->callData->args[0].toNumber() : qSNaN(); + double v = context->d()->callData->argc ? context->d()->callData->args[0].toNumber() : qSNaN(); if (v == 0.0) return Encode(v); else @@ -148,8 +148,8 @@ ReturnedValue MathObject::method_atan(CallContext *context) ReturnedValue MathObject::method_atan2(CallContext *context) { - double v1 = context->callData->argc ? context->callData->args[0].toNumber() : qSNaN(); - double v2 = context->callData->argc > 1 ? context->callData->args[1].toNumber() : qSNaN(); + double v1 = context->d()->callData->argc ? context->d()->callData->args[0].toNumber() : qSNaN(); + double v2 = context->d()->callData->argc > 1 ? context->d()->callData->args[1].toNumber() : qSNaN(); if ((v1 < 0) && qIsFinite(v1) && qIsInf(v2) && (copySign(1.0, v2) == 1.0)) return Encode(copySign(0, -1.0)); @@ -166,7 +166,7 @@ ReturnedValue MathObject::method_atan2(CallContext *context) ReturnedValue MathObject::method_ceil(CallContext *context) { - double v = context->callData->argc ? context->callData->args[0].toNumber() : qSNaN(); + double v = context->d()->callData->argc ? context->d()->callData->args[0].toNumber() : qSNaN(); if (v < 0.0 && v > -1.0) return Encode(copySign(0, -1.0)); else @@ -175,13 +175,13 @@ ReturnedValue MathObject::method_ceil(CallContext *context) ReturnedValue MathObject::method_cos(CallContext *context) { - double v = context->callData->argc ? context->callData->args[0].toNumber() : qSNaN(); + double v = context->d()->callData->argc ? context->d()->callData->args[0].toNumber() : qSNaN(); return Encode(::cos(v)); } ReturnedValue MathObject::method_exp(CallContext *context) { - double v = context->callData->argc ? context->callData->args[0].toNumber() : qSNaN(); + double v = context->d()->callData->argc ? context->d()->callData->args[0].toNumber() : qSNaN(); if (qIsInf(v)) { if (copySign(1.0, v) == -1.0) return Encode(0); @@ -194,13 +194,13 @@ ReturnedValue MathObject::method_exp(CallContext *context) ReturnedValue MathObject::method_floor(CallContext *context) { - double v = context->callData->argc ? context->callData->args[0].toNumber() : qSNaN(); + double v = context->d()->callData->argc ? context->d()->callData->args[0].toNumber() : qSNaN(); return Encode(::floor(v)); } ReturnedValue MathObject::method_log(CallContext *context) { - double v = context->callData->argc ? context->callData->args[0].toNumber() : qSNaN(); + double v = context->d()->callData->argc ? context->d()->callData->args[0].toNumber() : qSNaN(); if (v < 0) return Encode(qSNaN()); else @@ -210,8 +210,8 @@ ReturnedValue MathObject::method_log(CallContext *context) ReturnedValue MathObject::method_max(CallContext *context) { double mx = -qInf(); - for (int i = 0; i < context->callData->argc; ++i) { - double x = context->callData->args[i].toNumber(); + for (int i = 0; i < context->d()->callData->argc; ++i) { + double x = context->d()->callData->args[i].toNumber(); if (x > mx || std::isnan(x)) mx = x; } @@ -221,8 +221,8 @@ ReturnedValue MathObject::method_max(CallContext *context) ReturnedValue MathObject::method_min(CallContext *context) { double mx = qInf(); - for (int i = 0; i < context->callData->argc; ++i) { - double x = context->callData->args[i].toNumber(); + for (int i = 0; i < context->d()->callData->argc; ++i) { + double x = context->d()->callData->args[i].toNumber(); if ((x == 0 && mx == x && copySign(1.0, x) == -1.0) || (x < mx) || std::isnan(x)) { mx = x; @@ -233,8 +233,8 @@ ReturnedValue MathObject::method_min(CallContext *context) ReturnedValue MathObject::method_pow(CallContext *context) { - double x = context->callData->argc > 0 ? context->callData->args[0].toNumber() : qSNaN(); - double y = context->callData->argc > 1 ? context->callData->args[1].toNumber() : qSNaN(); + double x = context->d()->callData->argc > 0 ? context->d()->callData->args[0].toNumber() : qSNaN(); + double y = context->d()->callData->argc > 1 ? context->d()->callData->args[1].toNumber() : qSNaN(); if (std::isnan(y)) return Encode(qSNaN()); @@ -294,26 +294,26 @@ ReturnedValue MathObject::method_random(CallContext *context) ReturnedValue MathObject::method_round(CallContext *context) { - double v = context->callData->argc ? context->callData->args[0].toNumber() : qSNaN(); + double v = context->d()->callData->argc ? context->d()->callData->args[0].toNumber() : qSNaN(); v = copySign(::floor(v + 0.5), v); return Encode(v); } ReturnedValue MathObject::method_sin(CallContext *context) { - double v = context->callData->argc ? context->callData->args[0].toNumber() : qSNaN(); + double v = context->d()->callData->argc ? context->d()->callData->args[0].toNumber() : qSNaN(); return Encode(::sin(v)); } ReturnedValue MathObject::method_sqrt(CallContext *context) { - double v = context->callData->argc ? context->callData->args[0].toNumber() : qSNaN(); + double v = context->d()->callData->argc ? context->d()->callData->args[0].toNumber() : qSNaN(); return Encode(::sqrt(v)); } ReturnedValue MathObject::method_tan(CallContext *context) { - double v = context->callData->argc ? context->callData->args[0].toNumber() : qSNaN(); + double v = context->d()->callData->argc ? context->d()->callData->args[0].toNumber() : qSNaN(); if (v == 0.0) return Encode(v); else diff --git a/src/qml/jsruntime/qv4mathobject_p.h b/src/qml/jsruntime/qv4mathobject_p.h index 18a80c2ba0..65366aab86 100644 --- a/src/qml/jsruntime/qv4mathobject_p.h +++ b/src/qml/jsruntime/qv4mathobject_p.h @@ -49,9 +49,12 @@ namespace QV4 { struct MathObject: Object { - V4_OBJECT + struct Data : Object::Data { + Data(InternalClass *ic); + }; + + V4_OBJECT(Object) Q_MANAGED_TYPE(MathObject) - MathObject(InternalClass *ic); static ReturnedValue method_abs(CallContext *context); static ReturnedValue method_acos(CallContext *context); diff --git a/src/qml/jsruntime/qv4memberdata.cpp b/src/qml/jsruntime/qv4memberdata.cpp index aeb4c38a8e..7eca47c3ce 100644 --- a/src/qml/jsruntime/qv4memberdata.cpp +++ b/src/qml/jsruntime/qv4memberdata.cpp @@ -44,29 +44,13 @@ using namespace QV4; -const ManagedVTable MemberData::static_vtbl = -{ - MemberData::IsExecutionContext, - MemberData::IsString, - MemberData::IsObject, - MemberData::IsFunctionObject, - MemberData::IsErrorObject, - MemberData::IsArrayData, - 0, - MemberData::MyType, - "MemberData", - destroy, - markObjects, - isEqualTo -}; - - +DEFINE_MANAGED_VTABLE(MemberData); void MemberData::markObjects(Managed *that, ExecutionEngine *e) { MemberData *m = static_cast<MemberData *>(that); - for (uint i = 0; i < m->size; ++i) - m->data[i].mark(e); + for (uint i = 0; i < m->d()->size; ++i) + m->d()->data[i].mark(e); } void Members::ensureIndex(QV4::ExecutionEngine *e, uint idx) @@ -74,13 +58,13 @@ void Members::ensureIndex(QV4::ExecutionEngine *e, uint idx) uint s = size(); if (idx >= s) { int newAlloc = qMax((uint)4, 2*idx); - uint alloc = sizeof(MemberData) + (newAlloc)*sizeof(Value); - MemberData *newMemberData = reinterpret_cast<MemberData *>(e->memoryManager->allocManaged(alloc)); + uint alloc = sizeof(MemberData::Data) + (newAlloc)*sizeof(Value); + MemberData *newMemberData = static_cast<MemberData *>(e->memoryManager->allocManaged(alloc)); if (d()) - memcpy(newMemberData, d(), sizeof(MemberData) + s*sizeof(Value)); + memcpy(newMemberData, d(), sizeof(MemberData::Data) + s*sizeof(Value)); else new (newMemberData) MemberData(e->memberDataClass); - newMemberData->size = newAlloc; + newMemberData->d()->size = newAlloc; m = newMemberData; } } diff --git a/src/qml/jsruntime/qv4memberdata_p.h b/src/qml/jsruntime/qv4memberdata_p.h index 03aa75a365..cd8667adb7 100644 --- a/src/qml/jsruntime/qv4memberdata_p.h +++ b/src/qml/jsruntime/qv4memberdata_p.h @@ -50,23 +50,29 @@ namespace QV4 { struct MemberData : Managed { - V4_MANAGED - uint size; - Value data[1]; + struct Data : Managed::Data { + union { + uint size; + double _dummy; + }; + Value data[1]; + }; + V4_MANAGED(Managed) MemberData(QV4::InternalClass *ic) : Managed(ic) {} - Value &operator[] (uint idx) { return data[idx]; } + Value &operator[] (uint idx) { return d()->data[idx]; } static void markObjects(Managed *that, ExecutionEngine *e); }; struct Members : Value { + void reset() { m = 0; } void ensureIndex(QV4::ExecutionEngine *e, uint idx); - Value &operator[] (uint idx) const { return static_cast<MemberData *>(managed())->data[idx]; } - inline uint size() const { return d() ? d()->size : 0; } + Value &operator[] (uint idx) const { return static_cast<MemberData *>(managed())->d()->data[idx]; } + inline uint size() const { return d() ? d()->d()->size : 0; } inline MemberData *d() const { return static_cast<MemberData *>(managed()); } - Value *data() const { return static_cast<MemberData *>(managed())->data; } + Value *data() const { return static_cast<MemberData *>(managed())->d()->data; } void mark(ExecutionEngine *e) const { MemberData *m = d(); diff --git a/src/qml/jsruntime/qv4mm.cpp b/src/qml/jsruntime/qv4mm.cpp index ca2ccd33f7..3e7ac17078 100644 --- a/src/qml/jsruntime/qv4mm.cpp +++ b/src/qml/jsruntime/qv4mm.cpp @@ -57,6 +57,7 @@ #include <cstdlib> #include <algorithm> #include "qv4alloca_p.h" +#include "qv4profiling_p.h" #ifdef V4_USE_VALGRIND #include <valgrind/valgrind.h> @@ -102,6 +103,7 @@ struct MemoryManager::Data struct LargeItem { LargeItem *next; + size_t size; void *data; Managed *managed() { @@ -149,8 +151,10 @@ struct MemoryManager::Data ~Data() { - for (QVector<Chunk>::iterator i = heapChunks.begin(), ei = heapChunks.end(); i != ei; ++i) + for (QVector<Chunk>::iterator i = heapChunks.begin(), ei = heapChunks.end(); i != ei; ++i) { + Q_V4_PROFILE_DEALLOC(engine, 0, i->memory.size(), Profiling::HeapPage); i->memory.deallocate(); + } } }; @@ -174,7 +178,7 @@ MemoryManager::MemoryManager() #endif } -Managed *MemoryManager::alloc(std::size_t size) +Managed *MemoryManager::allocData(std::size_t size) { if (m_d->aggressiveGC) runGC(); @@ -190,9 +194,12 @@ Managed *MemoryManager::alloc(std::size_t size) // doesn't fit into a small bucket if (size >= MemoryManager::Data::MaxItemSize) { // we use malloc for this - MemoryManager::Data::LargeItem *item = static_cast<MemoryManager::Data::LargeItem *>(malloc(size + sizeof(MemoryManager::Data::LargeItem))); + MemoryManager::Data::LargeItem *item = static_cast<MemoryManager::Data::LargeItem *>( + malloc(Q_V4_PROFILE_ALLOC(m_d->engine, size + sizeof(MemoryManager::Data::LargeItem), + Profiling::LargeItem))); memset(item, 0, size + sizeof(MemoryManager::Data::LargeItem)); item->next = m_d->largeItems; + item->size = size; m_d->largeItems = item; return item->managed(); } @@ -218,7 +225,9 @@ Managed *MemoryManager::alloc(std::size_t size) std::size_t allocSize = m_d->maxChunkSize*(size_t(1) << shift); allocSize = roundUpToMultipleOf(WTF::pageSize(), allocSize); Data::Chunk allocation; - allocation.memory = PageAllocation::allocate(allocSize, OSAllocator::JSGCHeapPages); + allocation.memory = PageAllocation::allocate( + Q_V4_PROFILE_ALLOC(m_d->engine, allocSize, Profiling::HeapPage), + OSAllocator::JSGCHeapPages); allocation.chunkSize = int(size); m_d->heapChunks.append(allocation); std::sort(m_d->heapChunks.begin(), m_d->heapChunks.end()); @@ -228,7 +237,6 @@ Managed *MemoryManager::alloc(std::size_t size) Managed **last = &m_d->smallItems[pos]; while (chunk <= end) { Managed *o = reinterpret_cast<Managed *>(chunk); - o->_data = 0; *last = o; last = o->nextFreeRef(); chunk += size; @@ -247,6 +255,7 @@ Managed *MemoryManager::alloc(std::size_t size) #ifdef V4_USE_VALGRIND VALGRIND_MEMPOOL_ALLOC(this, m, size); #endif + Q_V4_PROFILE_ALLOC(m_d->engine, size, Profiling::SmallItem); ++m_d->allocCount[pos]; ++m_d->totalAlloc; @@ -308,8 +317,8 @@ void MemoryManager::mark() // now that we marked all roots, start marking recursively and popping from the mark stack while (m_d->engine->jsStackTop > markBase) { Managed *m = m_d->engine->popForGC(); - Q_ASSERT (m->internalClass->vtable->markObjects); - m->internalClass->vtable->markObjects(m, m_d->engine); + Q_ASSERT (m->internalClass()->vtable->markObjects); + m->internalClass()->vtable->markObjects(m, m_d->engine); } } @@ -325,7 +334,7 @@ void MemoryManager::sweep(bool lastSweep) continue; } if (Managed *m = weak->value.asManaged()) { - if (!m->markBit) { + if (!m->markBit()) { weak->value = Primitive::undefinedValue(); PersistentValuePrivate *n = weak->next; weak->removeFromList(); @@ -338,7 +347,7 @@ void MemoryManager::sweep(bool lastSweep) if (MultiplyWrappedQObjectMap *multiplyWrappedQObjects = m_d->engine->m_multiplyWrappedQObjects) { for (MultiplyWrappedQObjectMap::Iterator it = multiplyWrappedQObjects->begin(); it != multiplyWrappedQObjects->end();) { - if (!it.value()->markBit) + if (!it.value()->markBit()) it = multiplyWrappedQObjects->erase(it); else ++it; @@ -352,18 +361,19 @@ void MemoryManager::sweep(bool lastSweep) Data::LargeItem **last = &m_d->largeItems; while (i) { Managed *m = i->managed(); - Q_ASSERT(m->inUse); - if (m->markBit) { - m->markBit = 0; + Q_ASSERT(m->inUse()); + if (m->markBit()) { + m->d()->markBit = 0; last = &i->next; i = i->next; continue; } - if (m->internalClass->vtable->destroy) - m->internalClass->vtable->destroy(m); + if (m->internalClass()->vtable->destroy) + m->internalClass()->vtable->destroy(m); *last = i->next; - free(i); + free(Q_V4_PROFILE_DEALLOC(m_d->engine, i, i->size + sizeof(Data::LargeItem), + Profiling::LargeItem)); i = *last; } @@ -392,16 +402,16 @@ void MemoryManager::sweep(char *chunkStart, std::size_t chunkSize, size_t size) Q_ASSERT((qintptr) chunk % 16 == 0); - if (m->inUse) { - if (m->markBit) { - m->markBit = 0; + if (m->inUse()) { + if (m->markBit()) { + m->d()->markBit = 0; } else { // qDebug() << "-- collecting it." << m << *f << m->nextFree(); #ifdef V4_USE_VALGRIND VALGRIND_ENABLE_ERROR_REPORTING; #endif - if (m->internalClass->vtable->destroy) - m->internalClass->vtable->destroy(m); + if (m->internalClass()->vtable->destroy) + m->internalClass()->vtable->destroy(m); memset(m, 0, size); m->setNextFree(*f); @@ -409,6 +419,7 @@ void MemoryManager::sweep(char *chunkStart, std::size_t chunkSize, size_t size) VALGRIND_DISABLE_ERROR_REPORTING; VALGRIND_MEMPOOL_FREE(this, m); #endif + Q_V4_PROFILE_DEALLOC(m_d->engine, m, size, Profiling::SmallItem); *f = m; } } @@ -439,9 +450,7 @@ void MemoryManager::runGC() mark(); sweep(); } else { - int totalMem = 0; - for (int i = 0; i < m_d->heapChunks.size(); ++i) - totalMem += m_d->heapChunks.at(i).memory.size(); + int totalMem = getAllocatedMem(); QTime t; t.start(); @@ -467,22 +476,38 @@ void MemoryManager::runGC() m_d->totalAlloc = 0; } -uint MemoryManager::getUsedMem() +size_t MemoryManager::getUsedMem() const { - uint usedMem = 0; - for (QVector<Data::Chunk>::iterator i = m_d->heapChunks.begin(), ei = m_d->heapChunks.end(); i != ei; ++i) { + size_t usedMem = 0; + for (QVector<Data::Chunk>::const_iterator i = m_d->heapChunks.begin(), ei = m_d->heapChunks.end(); i != ei; ++i) { char *chunkStart = reinterpret_cast<char *>(i->memory.base()); char *chunkEnd = chunkStart + i->memory.size() - i->chunkSize; for (char *chunk = chunkStart; chunk <= chunkEnd; chunk += i->chunkSize) { Managed *m = reinterpret_cast<Managed *>(chunk); Q_ASSERT((qintptr) chunk % 16 == 0); - if (m->inUse) + if (m->inUse()) usedMem += i->chunkSize; } } return usedMem; } +size_t MemoryManager::getAllocatedMem() const +{ + size_t total = 0; + for (int i = 0; i < m_d->heapChunks.size(); ++i) + total += m_d->heapChunks.at(i).memory.size(); + return total; +} + +size_t MemoryManager::getLargeItemsMem() const +{ + size_t total = 0; + for (const Data::LargeItem *i = m_d->largeItems; i != 0; i = i->next) + total += i->size; + return total; +} + MemoryManager::~MemoryManager() { PersistentValuePrivate *persistent = m_persistentValues; @@ -526,11 +551,6 @@ void MemoryManager::registerDeletable(GCDeletable *d) m_d->deletable = d; } -ExecutionEngine *MemoryManager::engine() const -{ - return m_d->engine; -} - #ifdef DETAILED_MM_STATS void MemoryManager::willAllocate(std::size_t size) { @@ -545,11 +565,11 @@ void MemoryManager::willAllocate(std::size_t size) void MemoryManager::collectFromJSStack() const { - Value *v = engine()->jsStackBase; - Value *top = engine()->jsStackTop; + Value *v = m_d->engine->jsStackBase; + Value *top = m_d->engine->jsStackTop; while (v < top) { Managed *m = v->asManaged(); - if (m && m->inUse) + if (m && m->inUse()) // Skip pointers to already freed objects, they are bogus as well m->mark(m_d->engine); ++v; diff --git a/src/qml/jsruntime/qv4mm_p.h b/src/qml/jsruntime/qv4mm_p.h index 47020c12f0..f0025dc70e 100644 --- a/src/qml/jsruntime/qv4mm_p.h +++ b/src/qml/jsruntime/qv4mm_p.h @@ -99,10 +99,58 @@ public: inline Managed *allocManaged(std::size_t size) { size = align(size); - Managed *o = alloc(size); + Managed *o = allocData(size); return o; } + template <typename ManagedType> + ManagedType *alloc() + { + ManagedType *t = static_cast<ManagedType*>(allocManaged(sizeof(typename ManagedType::Data))); + (void)new (t->d()) typename ManagedType::Data(); + return t; + } + + template <typename ManagedType, typename Arg1> + ManagedType *alloc(Arg1 arg1) + { + ManagedType *t = static_cast<ManagedType*>(allocManaged(sizeof(typename ManagedType::Data))); + (void)new (t->d()) typename ManagedType::Data(arg1); + return t; + } + + template <typename ManagedType, typename Arg1, typename Arg2> + ManagedType *alloc(Arg1 arg1, Arg2 arg2) + { + ManagedType *t = static_cast<ManagedType*>(allocManaged(sizeof(typename ManagedType::Data))); + (void)new (t->d()) typename ManagedType::Data(arg1, arg2); + return t; + } + + template <typename ManagedType, typename Arg1, typename Arg2, typename Arg3> + ManagedType *alloc(Arg1 arg1, Arg2 arg2, Arg3 arg3) + { + ManagedType *t = static_cast<ManagedType*>(allocManaged(sizeof(typename ManagedType::Data))); + (void)new (t->d()) typename ManagedType::Data(arg1, arg2, arg3); + return t; + } + + template <typename ManagedType, typename Arg1, typename Arg2, typename Arg3, typename Arg4> + ManagedType *alloc(Arg1 arg1, Arg2 arg2, Arg3 arg3, Arg4 arg4) + { + ManagedType *t = static_cast<ManagedType*>(allocManaged(sizeof(typename ManagedType::Data))); + (void)new (t->d()) typename ManagedType::Data(arg1, arg2, arg3, arg4); + return t; + } + + template <typename ManagedType, typename Arg1, typename Arg2, typename Arg3, typename Arg4, typename Arg5> + ManagedType *alloc(Arg1 arg1, Arg2 arg2, Arg3 arg3, Arg4 arg4, Arg5 arg5) + { + ManagedType *t = static_cast<ManagedType*>(allocManaged(sizeof(typename ManagedType::Data))); + (void)new (t->d()) typename ManagedType::Data(arg1, arg2, arg3, arg4, arg5); + return t; + } + bool isGCBlocked() const; void setGCBlocked(bool blockGC); void runGC(); @@ -113,12 +161,14 @@ public: void registerDeletable(GCDeletable *d); + size_t getUsedMem() const; + size_t getAllocatedMem() const; + size_t getLargeItemsMem() const; + protected: /// expects size to be aligned // TODO: try to inline - Managed *alloc(std::size_t size); - - ExecutionEngine *engine() const; + Managed *allocData(std::size_t size); #ifdef DETAILED_MM_STATS void willAllocate(std::size_t size); @@ -129,7 +179,6 @@ private: void mark(); void sweep(bool lastSweep = false); void sweep(char *chunkStart, std::size_t chunkSize, size_t size); - uint getUsedMem(); protected: QScopedPointer<Data> m_d; diff --git a/src/qml/jsruntime/qv4numberobject.cpp b/src/qml/jsruntime/qv4numberobject.cpp index c97e86f2cd..f1bac1109a 100644 --- a/src/qml/jsruntime/qv4numberobject.cpp +++ b/src/qml/jsruntime/qv4numberobject.cpp @@ -51,8 +51,8 @@ using namespace QV4; DEFINE_OBJECT_VTABLE(NumberCtor); DEFINE_OBJECT_VTABLE(NumberObject); -NumberCtor::NumberCtor(ExecutionContext *scope) - : FunctionObject(scope, QStringLiteral("Number")) +NumberCtor::Data::Data(ExecutionContext *scope) + : FunctionObject::Data(scope, QStringLiteral("Number")) { setVTable(staticVTable()); } @@ -71,7 +71,7 @@ ReturnedValue NumberCtor::call(Managed *, CallData *callData) return Encode(dbl); } -void NumberPrototype::init(ExecutionEngine *engine, ObjectRef ctor) +void NumberPrototype::init(ExecutionEngine *engine, Object *ctor) { Scope scope(engine); ScopedObject o(scope); @@ -103,40 +103,40 @@ void NumberPrototype::init(ExecutionEngine *engine, ObjectRef ctor) inline ReturnedValue thisNumberValue(ExecutionContext *ctx) { - if (ctx->callData->thisObject.isNumber()) - return ctx->callData->thisObject.asReturnedValue(); - NumberObject *n = ctx->callData->thisObject.asNumberObject(); + if (ctx->d()->callData->thisObject.isNumber()) + return ctx->d()->callData->thisObject.asReturnedValue(); + NumberObject *n = ctx->d()->callData->thisObject.asNumberObject(); if (!n) return ctx->throwTypeError(); - return n->value.asReturnedValue(); + return n->value().asReturnedValue(); } inline double thisNumber(ExecutionContext *ctx) { - if (ctx->callData->thisObject.isNumber()) - return ctx->callData->thisObject.asDouble(); - NumberObject *n = ctx->callData->thisObject.asNumberObject(); + if (ctx->d()->callData->thisObject.isNumber()) + return ctx->d()->callData->thisObject.asDouble(); + NumberObject *n = ctx->d()->callData->thisObject.asNumberObject(); if (!n) return ctx->throwTypeError(); - return n->value.asDouble(); + return n->value().asDouble(); } ReturnedValue NumberPrototype::method_toString(CallContext *ctx) { double num = thisNumber(ctx); - if (ctx->engine->hasException) + if (ctx->d()->engine->hasException) return Encode::undefined(); - if (ctx->callData->argc && !ctx->callData->args[0].isUndefined()) { - int radix = ctx->callData->args[0].toInt32(); + if (ctx->d()->callData->argc && !ctx->d()->callData->args[0].isUndefined()) { + int radix = ctx->d()->callData->args[0].toInt32(); if (radix < 2 || radix > 36) return ctx->throwError(QString::fromLatin1("Number.prototype.toString: %0 is not a valid radix") .arg(radix)); if (std::isnan(num)) { - return ctx->engine->newString(QStringLiteral("NaN"))->asReturnedValue(); + return ctx->d()->engine->newString(QStringLiteral("NaN"))->asReturnedValue(); } else if (qIsInf(num)) { - return ctx->engine->newString(QLatin1String(num < 0 ? "-Infinity" : "Infinity"))->asReturnedValue(); + return ctx->d()->engine->newString(QLatin1String(num < 0 ? "-Infinity" : "Infinity"))->asReturnedValue(); } if (radix != 10) { @@ -166,7 +166,7 @@ ReturnedValue NumberPrototype::method_toString(CallContext *ctx) } if (negative) str.prepend(QLatin1Char('-')); - return ctx->engine->newString(str)->asReturnedValue(); + return ctx->d()->engine->newString(str)->asReturnedValue(); } } @@ -178,7 +178,7 @@ ReturnedValue NumberPrototype::method_toLocaleString(CallContext *ctx) Scope scope(ctx); ScopedValue v(scope, thisNumberValue(ctx)); ScopedString str(scope, v->toString(ctx)); - if (ctx->engine->hasException) + if (ctx->d()->engine->hasException) return Encode::undefined(); return str.asReturnedValue(); } @@ -191,19 +191,19 @@ ReturnedValue NumberPrototype::method_valueOf(CallContext *ctx) ReturnedValue NumberPrototype::method_toFixed(CallContext *ctx) { double v = thisNumber(ctx); - if (ctx->engine->hasException) + if (ctx->d()->engine->hasException) return Encode::undefined(); double fdigits = 0; - if (ctx->callData->argc > 0) - fdigits = ctx->callData->args[0].toInteger(); + if (ctx->d()->callData->argc > 0) + fdigits = ctx->d()->callData->args[0].toInteger(); if (std::isnan(fdigits)) fdigits = 0; if (fdigits < 0 || fdigits > 20) - return ctx->throwRangeError(ctx->callData->thisObject); + return ctx->throwRangeError(ctx->d()->callData->thisObject); QString str; if (std::isnan(v)) @@ -214,22 +214,22 @@ ReturnedValue NumberPrototype::method_toFixed(CallContext *ctx) str = QString::number(v, 'f', int (fdigits)); else return RuntimeHelpers::stringFromNumber(ctx, v)->asReturnedValue(); - return ctx->engine->newString(str)->asReturnedValue(); + return ctx->d()->engine->newString(str)->asReturnedValue(); } ReturnedValue NumberPrototype::method_toExponential(CallContext *ctx) { Scope scope(ctx); double d = thisNumber(ctx); - if (ctx->engine->hasException) + if (ctx->d()->engine->hasException) return Encode::undefined(); int fdigits = -1; - if (ctx->callData->argc && !ctx->callData->args[0].isUndefined()) { - fdigits = ctx->callData->args[0].toInt32(); + if (ctx->d()->callData->argc && !ctx->d()->callData->args[0].isUndefined()) { + fdigits = ctx->d()->callData->args[0].toInt32(); if (fdigits < 0 || fdigits > 20) { - ScopedString error(scope, ctx->engine->newString(QStringLiteral("Number.prototype.toExponential: fractionDigits out of range"))); + ScopedString error(scope, ctx->d()->engine->newString(QStringLiteral("Number.prototype.toExponential: fractionDigits out of range"))); return ctx->throwRangeError(error); } } @@ -239,22 +239,22 @@ ReturnedValue NumberPrototype::method_toExponential(CallContext *ctx) double_conversion::DoubleToStringConverter::EcmaScriptConverter().ToExponential(d, fdigits, &builder); QString result = QString::fromLatin1(builder.Finalize()); - return ctx->engine->newString(result)->asReturnedValue(); + return ctx->d()->engine->newString(result)->asReturnedValue(); } ReturnedValue NumberPrototype::method_toPrecision(CallContext *ctx) { Scope scope(ctx); ScopedValue v(scope, thisNumberValue(ctx)); - if (ctx->engine->hasException) + if (ctx->d()->engine->hasException) return Encode::undefined(); - if (!ctx->callData->argc || ctx->callData->args[0].isUndefined()) + if (!ctx->d()->callData->argc || ctx->d()->callData->args[0].isUndefined()) return RuntimeHelpers::toString(ctx, v); - double precision = ctx->callData->args[0].toInt32(); + double precision = ctx->d()->callData->args[0].toInt32(); if (precision < 1 || precision > 21) { - ScopedString error(scope, ctx->engine->newString(QStringLiteral("Number.prototype.toPrecision: precision out of range"))); + ScopedString error(scope, ctx->d()->engine->newString(QStringLiteral("Number.prototype.toPrecision: precision out of range"))); return ctx->throwRangeError(error); } @@ -263,5 +263,5 @@ ReturnedValue NumberPrototype::method_toPrecision(CallContext *ctx) double_conversion::DoubleToStringConverter::EcmaScriptConverter().ToPrecision(v->asDouble(), precision, &builder); QString result = QString::fromLatin1(builder.Finalize()); - return ctx->engine->newString(result)->asReturnedValue(); + return ctx->d()->engine->newString(result)->asReturnedValue(); } diff --git a/src/qml/jsruntime/qv4numberobject_p.h b/src/qml/jsruntime/qv4numberobject_p.h index ccabcf6727..3e776f0f2f 100644 --- a/src/qml/jsruntime/qv4numberobject_p.h +++ b/src/qml/jsruntime/qv4numberobject_p.h @@ -51,8 +51,10 @@ namespace QV4 { struct NumberCtor: FunctionObject { - V4_OBJECT - NumberCtor(ExecutionContext *scope); + struct Data : FunctionObject::Data { + Data(ExecutionContext *scope); + }; + V4_OBJECT(FunctionObject) static ReturnedValue construct(Managed *that, CallData *callData); static ReturnedValue call(Managed *, CallData *callData); @@ -60,8 +62,7 @@ struct NumberCtor: FunctionObject struct NumberPrototype: NumberObject { - NumberPrototype(InternalClass *ic): NumberObject(ic) {} - void init(ExecutionEngine *engine, ObjectRef ctor); + void init(ExecutionEngine *engine, Object *ctor); static ReturnedValue method_toString(CallContext *ctx); static ReturnedValue method_toLocaleString(CallContext *ctx); diff --git a/src/qml/jsruntime/qv4object.cpp b/src/qml/jsruntime/qv4object.cpp index c8d360d511..e0f05a65f8 100644 --- a/src/qml/jsruntime/qv4object.cpp +++ b/src/qml/jsruntime/qv4object.cpp @@ -70,29 +70,16 @@ using namespace QV4; DEFINE_OBJECT_VTABLE(Object); -Object::Object(ExecutionEngine *engine) - : Managed(engine->objectClass) +Object::Data::Data(InternalClass *internalClass) + : Managed::Data(internalClass) { -} - -Object::Object(InternalClass *ic) - : Managed(ic) -{ - Q_ASSERT(internalClass->vtable && internalClass->vtable != &Managed::static_vtbl); - - Q_ASSERT(!memberData.d()); if (internalClass->size) { - Scope scope(engine()); - ScopedObject protectThis(scope, this); - memberData.ensureIndex(engine(), internalClass->size); + Scope scope(internalClass->engine); + ScopedObject o(scope, this); + o->memberData().ensureIndex(internalClass->engine, internalClass->size); } } -Object::~Object() -{ - _data = 0; -} - bool Object::setPrototype(Object *proto) { Object *pp = proto; @@ -101,20 +88,15 @@ bool Object::setPrototype(Object *proto) return false; pp = pp->prototype(); } - internalClass = internalClass->changePrototype(proto); + setInternalClass(internalClass()->changePrototype(proto)); return true; } -void Object::destroy(Managed *that) -{ - static_cast<Object *>(that)->~Object(); -} - void Object::put(ExecutionContext *ctx, const QString &name, const ValueRef value) { Scope scope(ctx); - ScopedString n(scope, ctx->engine->newString(name)); - put(n, value); + ScopedString n(scope, ctx->d()->engine->newString(name)); + put(n.getPointer(), value); } ReturnedValue Object::getValue(const ValueRef thisObject, const Property *p, PropertyAttributes attrs) @@ -133,7 +115,7 @@ ReturnedValue Object::getValue(const ValueRef thisObject, const Property *p, Pro void Object::putValue(Property *pd, PropertyAttributes attrs, const ValueRef value) { - if (internalClass->engine->hasException) + if (internalClass()->engine->hasException) return; if (attrs.isAccessor()) { @@ -155,7 +137,7 @@ void Object::putValue(Property *pd, PropertyAttributes attrs, const ValueRef val return; reject: - if (engine()->currentContext()->strictMode) + if (engine()->currentContext()->d()->strictMode) engine()->currentContext()->throwTypeError(); } @@ -164,7 +146,7 @@ void Object::defineDefaultProperty(const QString &name, ValueRef value) ExecutionEngine *e = engine(); Scope scope(e); ScopedString s(scope, e->newIdentifier(name)); - defineDefaultProperty(s, value); + defineDefaultProperty(s.getPointer(), value); } void Object::defineDefaultProperty(const QString &name, ReturnedValue (*code)(CallContext *), int argumentCount) @@ -172,16 +154,16 @@ void Object::defineDefaultProperty(const QString &name, ReturnedValue (*code)(Ca ExecutionEngine *e = engine(); Scope scope(e); ScopedString s(scope, e->newIdentifier(name)); - Scoped<FunctionObject> function(scope, e->newBuiltinFunction(e->rootContext, s, code)); + Scoped<FunctionObject> function(scope, BuiltinFunction::create(e->rootContext, s.getPointer(), code)); function->defineReadonlyProperty(e->id_length, Primitive::fromInt32(argumentCount)); - defineDefaultProperty(s, function); + defineDefaultProperty(s.getPointer(), function); } -void Object::defineDefaultProperty(const StringRef name, ReturnedValue (*code)(CallContext *), int argumentCount) +void Object::defineDefaultProperty(String *name, ReturnedValue (*code)(CallContext *), int argumentCount) { ExecutionEngine *e = engine(); Scope scope(e); - Scoped<FunctionObject> function(scope, e->newBuiltinFunction(e->rootContext, name, code)); + Scoped<FunctionObject> function(scope, BuiltinFunction::create(e->rootContext, name, code)); function->defineReadonlyProperty(e->id_length, Primitive::fromInt32(argumentCount)); defineDefaultProperty(name, function); } @@ -191,16 +173,16 @@ void Object::defineAccessorProperty(const QString &name, ReturnedValue (*getter) ExecutionEngine *e = engine(); Scope scope(e); Scoped<String> s(scope, e->newIdentifier(name)); - defineAccessorProperty(s, getter, setter); + defineAccessorProperty(s.getPointer(), getter, setter); } -void Object::defineAccessorProperty(const StringRef name, ReturnedValue (*getter)(CallContext *), ReturnedValue (*setter)(CallContext *)) +void Object::defineAccessorProperty(String *name, ReturnedValue (*getter)(CallContext *), ReturnedValue (*setter)(CallContext *)) { ExecutionEngine *v4 = engine(); QV4::Scope scope(v4); ScopedProperty p(scope); - p->setGetter(getter ? v4->newBuiltinFunction(v4->rootContext, name, getter)->getPointer() : 0); - p->setSetter(setter ? v4->newBuiltinFunction(v4->rootContext, name, setter)->getPointer() : 0); + p->setGetter(getter ? ScopedFunctionObject(scope, BuiltinFunction::create(v4->rootContext, name, getter)).getPointer() : 0); + p->setSetter(setter ? ScopedFunctionObject(scope, BuiltinFunction::create(v4->rootContext, name, setter)).getPointer() : 0); insertMember(name, p, QV4::Attr_Accessor|QV4::Attr_NotConfigurable|QV4::Attr_NotEnumerable); } @@ -209,10 +191,10 @@ void Object::defineReadonlyProperty(const QString &name, ValueRef value) QV4::ExecutionEngine *e = engine(); Scope scope(e); ScopedString s(scope, e->newIdentifier(name)); - defineReadonlyProperty(s, value); + defineReadonlyProperty(s.getPointer(), value); } -void Object::defineReadonlyProperty(const StringRef name, ValueRef value) +void Object::defineReadonlyProperty(String *name, ValueRef value) { insertMember(name, value, Attr_ReadOnly); } @@ -221,45 +203,45 @@ void Object::markObjects(Managed *that, ExecutionEngine *e) { Object *o = static_cast<Object *>(that); - o->memberData.mark(e); - if (o->arrayData) - o->arrayData->mark(e); + o->memberData().mark(e); + if (o->arrayData()) + o->arrayData()->mark(e); } void Object::ensureMemberIndex(uint idx) { - memberData.ensureIndex(engine(), idx); + memberData().ensureIndex(engine(), idx); } -void Object::insertMember(const StringRef s, const Property &p, PropertyAttributes attributes) +void Object::insertMember(String *s, const Property &p, PropertyAttributes attributes) { uint idx; - InternalClass::addMember(this, s.getPointer(), attributes, &idx); + InternalClass::addMember(this, s, attributes, &idx); - ensureMemberIndex(internalClass->size); + ensureMemberIndex(internalClass()->size); if (attributes.isAccessor()) { - hasAccessorProperty = 1; + setHasAccessorProperty(); Property *pp = propertyAt(idx); pp->value = p.value; pp->set = p.set; } else { - memberData[idx] = p.value; + memberData()[idx] = p.value; } } // Section 8.12.1 -Property *Object::__getOwnProperty__(const StringRef name, PropertyAttributes *attrs) +Property *Object::__getOwnProperty__(String *name, PropertyAttributes *attrs) { uint idx = name->asArrayIndex(); if (idx != UINT_MAX) return __getOwnProperty__(idx, attrs); - uint member = internalClass->find(name); + uint member = internalClass()->find(name); if (member < UINT_MAX) { if (attrs) - *attrs = internalClass->propertyData[member]; + *attrs = internalClass()->propertyData[member]; return propertyAt(member); } @@ -270,10 +252,10 @@ Property *Object::__getOwnProperty__(const StringRef name, PropertyAttributes *a Property *Object::__getOwnProperty__(uint index, PropertyAttributes *attrs) { - Property *p = arrayData->getProperty(index); + Property *p = arrayData()->getProperty(index); if (p) { if (attrs) - *attrs = arrayData->attributes(index); + *attrs = arrayData()->attributes(index); return p; } if (isStringObject()) { @@ -288,7 +270,7 @@ Property *Object::__getOwnProperty__(uint index, PropertyAttributes *attrs) } // Section 8.12.2 -Property *Object::__getPropertyDescriptor__(const StringRef name, PropertyAttributes *attrs) const +Property *Object::__getPropertyDescriptor__(String *name, PropertyAttributes *attrs) const { uint idx = name->asArrayIndex(); if (idx != UINT_MAX) @@ -297,10 +279,10 @@ Property *Object::__getPropertyDescriptor__(const StringRef name, PropertyAttrib const Object *o = this; while (o) { - uint idx = o->internalClass->find(name.getPointer()); + uint idx = o->internalClass()->find(name); if (idx < UINT_MAX) { if (attrs) - *attrs = o->internalClass->propertyData[idx]; + *attrs = o->internalClass()->propertyData[idx]; return o->propertyAt(idx); } @@ -315,10 +297,10 @@ Property *Object::__getPropertyDescriptor__(uint index, PropertyAttributes *attr { const Object *o = this; while (o) { - Property *p = o->arrayData->getProperty(index); + Property *p = o->arrayData()->getProperty(index); if (p) { if (attrs) - *attrs = o->arrayData->attributes(index); + *attrs = o->arrayData()->attributes(index); return p; } if (o->isStringObject()) { @@ -336,7 +318,7 @@ Property *Object::__getPropertyDescriptor__(uint index, PropertyAttributes *attr return 0; } -bool Object::hasProperty(const StringRef name) const +bool Object::hasProperty(String *name) const { uint idx = name->asArrayIndex(); if (idx != UINT_MAX) @@ -366,13 +348,13 @@ bool Object::hasProperty(uint index) const return false; } -bool Object::hasOwnProperty(const StringRef name) const +bool Object::hasOwnProperty(String *name) const { uint idx = name->asArrayIndex(); if (idx != UINT_MAX) return hasOwnProperty(idx); - if (internalClass->find(name) < UINT_MAX) + if (internalClass()->find(name) < UINT_MAX) return true; if (!query(name).isEmpty()) return true; @@ -381,11 +363,11 @@ bool Object::hasOwnProperty(const StringRef name) const bool Object::hasOwnProperty(uint index) const { - if (!arrayData->isEmpty(index)) + if (!arrayData()->isEmpty(index)) return true; if (isStringObject()) { - String *s = static_cast<const StringObject *>(this)->value.asString(); - if (index < (uint)s->length()) + String *s = static_cast<const StringObject *>(this)->d()->value.asString(); + if (index < (uint)s->d()->length()) return true; } if (!queryIndexed(index).isEmpty()) @@ -403,7 +385,7 @@ ReturnedValue Object::call(Managed *m, CallData *) return m->engine()->currentContext()->throwTypeError(); } -ReturnedValue Object::get(Managed *m, const StringRef name, bool *hasProperty) +ReturnedValue Object::get(Managed *m, String *name, bool *hasProperty) { return static_cast<Object *>(m)->internalGet(name, hasProperty); } @@ -413,7 +395,7 @@ ReturnedValue Object::getIndexed(Managed *m, uint index, bool *hasProperty) return static_cast<Object *>(m)->internalGetIndexed(index, hasProperty); } -void Object::put(Managed *m, const StringRef name, const ValueRef value) +void Object::put(Managed *m, String *name, const ValueRef value) { static_cast<Object *>(m)->internalPut(name, value); } @@ -423,16 +405,16 @@ void Object::putIndexed(Managed *m, uint index, const ValueRef value) static_cast<Object *>(m)->internalPutIndexed(index, value); } -PropertyAttributes Object::query(const Managed *m, StringRef name) +PropertyAttributes Object::query(const Managed *m, String *name) { uint idx = name->asArrayIndex(); if (idx != UINT_MAX) return queryIndexed(m, idx); const Object *o = static_cast<const Object *>(m); - idx = o->internalClass->find(name.getPointer()); + idx = o->internalClass()->find(name); if (idx < UINT_MAX) - return o->internalClass->propertyData[idx]; + return o->internalClass()->propertyData[idx]; return Attr_Invalid; } @@ -440,18 +422,18 @@ PropertyAttributes Object::query(const Managed *m, StringRef name) PropertyAttributes Object::queryIndexed(const Managed *m, uint index) { const Object *o = static_cast<const Object *>(m); - if (o->arrayData->get(index) != Primitive::emptyValue().asReturnedValue()) - return o->arrayData->attributes(index); + if (o->arrayData()->get(index) != Primitive::emptyValue().asReturnedValue()) + return o->arrayData()->attributes(index); if (o->isStringObject()) { - String *s = static_cast<const StringObject *>(o)->value.asString(); - if (index < (uint)s->length()) + String *s = static_cast<const StringObject *>(o)->d()->value.asString(); + if (index < (uint)s->d()->length()) return (Attr_NotWritable|Attr_NotConfigurable); } return Attr_Invalid; } -bool Object::deleteProperty(Managed *m, const StringRef name) +bool Object::deleteProperty(Managed *m, String *name) { return static_cast<Object *>(m)->internalDeleteProperty(name); } @@ -497,46 +479,46 @@ void Object::setLookup(Managed *m, Lookup *l, const ValueRef value) Scope scope(m->engine()); ScopedObject o(scope, static_cast<Object *>(m)); - InternalClass *c = o->internalClass; + InternalClass *c = o->internalClass(); uint idx = c->find(l->name); if (!o->isArrayObject() || idx != ArrayObject::LengthPropertyIndex) { - if (idx != UINT_MAX && o->internalClass->propertyData[idx].isData() && o->internalClass->propertyData[idx].isWritable()) { - l->classList[0] = o->internalClass; + if (idx != UINT_MAX && o->internalClass()->propertyData[idx].isData() && o->internalClass()->propertyData[idx].isWritable()) { + l->classList[0] = o->internalClass(); l->index = idx; l->setter = Lookup::setter0; - o->memberData[idx] = *value; + o->memberData()[idx] = *value; return; } if (idx != UINT_MAX) { - o->putValue(o->propertyAt(idx), o->internalClass->propertyData[idx], value); + o->putValue(o->propertyAt(idx), o->internalClass()->propertyData[idx], value); return; } } ScopedString s(scope, l->name); - o->put(s, value); + o->put(s.getPointer(), value); - if (o->internalClass == c) + if (o->internalClass() == c) return; - idx = o->internalClass->find(l->name); + idx = o->internalClass()->find(l->name); if (idx == UINT_MAX) return; l->classList[0] = c; - l->classList[3] = o->internalClass; + l->classList[3] = o->internalClass(); l->index = idx; if (!o->prototype()) { l->setter = Lookup::setterInsert0; return; } o = o->prototype(); - l->classList[1] = o->internalClass; + l->classList[1] = o->internalClass(); if (!o->prototype()) { l->setter = Lookup::setterInsert1; return; } o = o->prototype(); - l->classList[2] = o->internalClass; + l->classList[2] = o->internalClass(); if (!o->prototype()) { l->setter = Lookup::setterInsert2; return; @@ -544,13 +526,13 @@ void Object::setLookup(Managed *m, Lookup *l, const ValueRef value) l->setter = Lookup::setterGeneric; } -void Object::advanceIterator(Managed *m, ObjectIterator *it, StringRef name, uint *index, Property *pd, PropertyAttributes *attrs) +void Object::advanceIterator(Managed *m, ObjectIterator *it, String *&name, uint *index, Property *pd, PropertyAttributes *attrs) { Object *o = static_cast<Object *>(m); name = (String *)0; *index = UINT_MAX; - if (o->arrayData) { + if (o->arrayData()) { if (!it->arrayIndex) it->arrayNode = o->sparseBegin(); @@ -559,9 +541,9 @@ void Object::advanceIterator(Managed *m, ObjectIterator *it, StringRef name, uin while (it->arrayNode != o->sparseEnd()) { int k = it->arrayNode->key(); uint pidx = it->arrayNode->value; - Property *p = reinterpret_cast<Property *>(o->arrayData->data + pidx); + Property *p = reinterpret_cast<Property *>(o->arrayData()->arrayData() + pidx); it->arrayNode = it->arrayNode->nextNode(); - PropertyAttributes a = o->arrayData->attributes(k); + PropertyAttributes a = o->arrayData()->attributes(k); if (!(it->flags & ObjectIterator::EnumerableOnly) || a.isEnumerable()) { it->arrayIndex = k + 1; *index = k; @@ -574,9 +556,9 @@ void Object::advanceIterator(Managed *m, ObjectIterator *it, StringRef name, uin it->arrayIndex = UINT_MAX; } // dense arrays - while (it->arrayIndex < o->arrayData->length()) { - Value *val = o->arrayData->data + it->arrayIndex; - PropertyAttributes a = o->arrayData->attributes(it->arrayIndex); + while (it->arrayIndex < o->arrayData()->length()) { + Value *val = o->arrayData()->arrayData() + it->arrayIndex; + PropertyAttributes a = o->arrayData()->attributes(it->arrayIndex); ++it->arrayIndex; if (!val->isEmpty() && (!(it->flags & ObjectIterator::EnumerableOnly) || a.isEnumerable())) { @@ -588,8 +570,8 @@ void Object::advanceIterator(Managed *m, ObjectIterator *it, StringRef name, uin } } - while (it->memberIndex < o->internalClass->size) { - String *n = o->internalClass->nameMap.at(it->memberIndex); + while (it->memberIndex < o->internalClass()->size) { + String *n = o->internalClass()->nameMap.at(it->memberIndex); if (!n) { // accessor properties have a dummy entry with n == 0 ++it->memberIndex; @@ -597,7 +579,7 @@ void Object::advanceIterator(Managed *m, ObjectIterator *it, StringRef name, uin } Property *p = o->propertyAt(it->memberIndex); - PropertyAttributes a = o->internalClass->propertyData[it->memberIndex]; + PropertyAttributes a = o->internalClass()->propertyData[it->memberIndex]; ++it->memberIndex; if (!(it->flags & ObjectIterator::EnumerableOnly) || a.isEnumerable()) { name = n; @@ -611,7 +593,7 @@ void Object::advanceIterator(Managed *m, ObjectIterator *it, StringRef name, uin } // Section 8.12.3 -ReturnedValue Object::internalGet(const StringRef name, bool *hasProperty) +ReturnedValue Object::internalGet(String *name, bool *hasProperty) { uint idx = name->asArrayIndex(); if (idx != UINT_MAX) @@ -621,11 +603,11 @@ ReturnedValue Object::internalGet(const StringRef name, bool *hasProperty) Object *o = this; while (o) { - uint idx = o->internalClass->find(name.getPointer()); + uint idx = o->internalClass()->find(name); if (idx < UINT_MAX) { if (hasProperty) *hasProperty = true; - return getValue(o->propertyAt(idx), o->internalClass->propertyData.at(idx)); + return getValue(o->propertyAt(idx), o->internalClass()->propertyData.at(idx)); } o = o->prototype(); @@ -642,10 +624,10 @@ ReturnedValue Object::internalGetIndexed(uint index, bool *hasProperty) PropertyAttributes attrs; Object *o = this; while (o) { - Property *p = o->arrayData->getProperty(index); + Property *p = o->arrayData()->getProperty(index); if (p) { pd = p; - attrs = o->arrayData->attributes(index); + attrs = o->arrayData()->attributes(index); break; } if (o->isStringObject()) { @@ -671,9 +653,9 @@ ReturnedValue Object::internalGetIndexed(uint index, bool *hasProperty) // Section 8.12.5 -void Object::internalPut(const StringRef name, const ValueRef value) +void Object::internalPut(String *name, const ValueRef value) { - if (internalClass->engine->hasException) + if (internalClass()->engine->hasException) return; uint idx = name->asArrayIndex(); @@ -682,12 +664,12 @@ void Object::internalPut(const StringRef name, const ValueRef value) name->makeIdentifier(); - uint member = internalClass->find(name.getPointer()); + uint member = internalClass()->find(name); Property *pd = 0; PropertyAttributes attrs; if (member < UINT_MAX) { pd = propertyAt(member); - attrs = internalClass->propertyData[member]; + attrs = internalClass()->propertyData[member]; } // clause 1 @@ -713,7 +695,7 @@ void Object::internalPut(const StringRef name, const ValueRef value) } return; } else if (!prototype()) { - if (!extensible) + if (!isExtensible()) goto reject; } else { // clause 4 @@ -721,10 +703,10 @@ void Object::internalPut(const StringRef name, const ValueRef value) if (attrs.isAccessor()) { if (!pd->setter()) goto reject; - } else if (!extensible || !attrs.isWritable()) { + } else if (!isExtensible() || !attrs.isWritable()) { goto reject; } - } else if (!extensible) { + } else if (!isExtensible()) { goto reject; } } @@ -747,7 +729,7 @@ void Object::internalPut(const StringRef name, const ValueRef value) return; reject: - if (engine()->currentContext()->strictMode) { + if (engine()->currentContext()->d()->strictMode) { QString message = QStringLiteral("Cannot assign to read-only property \""); message += name->toQString(); message += QLatin1Char('\"'); @@ -757,14 +739,14 @@ void Object::internalPut(const StringRef name, const ValueRef value) void Object::internalPutIndexed(uint index, const ValueRef value) { - if (internalClass->engine->hasException) + if (internalClass()->engine->hasException) return; PropertyAttributes attrs; - Property *pd = arrayData->getProperty(index); + Property *pd = arrayData()->getProperty(index); if (pd) - attrs = arrayData->attributes(index); + attrs = arrayData()->attributes(index); if (!pd && isStringObject()) { pd = static_cast<StringObject *>(this)->getIndex(index); @@ -785,7 +767,7 @@ void Object::internalPutIndexed(uint index, const ValueRef value) pd->value = *value; return; } else if (!prototype()) { - if (!extensible) + if (!isExtensible()) goto reject; } else { // clause 4 @@ -793,10 +775,10 @@ void Object::internalPutIndexed(uint index, const ValueRef value) if (attrs.isAccessor()) { if (!pd->setter()) goto reject; - } else if (!extensible || !attrs.isWritable()) { + } else if (!isExtensible() || !attrs.isWritable()) { goto reject; } - } else if (!extensible) { + } else if (!isExtensible()) { goto reject; } } @@ -819,14 +801,14 @@ void Object::internalPutIndexed(uint index, const ValueRef value) return; reject: - if (engine()->currentContext()->strictMode) + if (engine()->currentContext()->d()->strictMode) engine()->currentContext()->throwTypeError(); } // Section 8.12.7 -bool Object::internalDeleteProperty(const StringRef name) +bool Object::internalDeleteProperty(String *name) { - if (internalClass->engine->hasException) + if (internalClass()->engine->hasException) return false; uint idx = name->asArrayIndex(); @@ -835,13 +817,13 @@ bool Object::internalDeleteProperty(const StringRef name) name->makeIdentifier(); - uint memberIdx = internalClass->find(name); + uint memberIdx = internalClass()->find(name); if (memberIdx != UINT_MAX) { - if (internalClass->propertyData[memberIdx].isConfigurable()) { - InternalClass::removeMember(this, name->identifier); + if (internalClass()->propertyData[memberIdx].isConfigurable()) { + InternalClass::removeMember(this, name->identifier()); return true; } - if (engine()->currentContext()->strictMode) + if (engine()->currentContext()->d()->strictMode) engine()->currentContext()->throwTypeError(); return false; } @@ -851,19 +833,19 @@ bool Object::internalDeleteProperty(const StringRef name) bool Object::internalDeleteIndexedProperty(uint index) { - if (internalClass->engine->hasException) + if (internalClass()->engine->hasException) return false; - if (!arrayData || arrayData->vtable()->del(this, index)) + if (!arrayData() || arrayData()->vtable()->del(this, index)) return true; - if (engine()->currentContext()->strictMode) + if (engine()->currentContext()->d()->strictMode) engine()->currentContext()->throwTypeError(); return false; } // Section 8.12.9 -bool Object::__defineOwnProperty__(ExecutionContext *ctx, const StringRef name, const Property &p, PropertyAttributes attrs) +bool Object::__defineOwnProperty__(ExecutionContext *ctx, String *name, const Property &p, PropertyAttributes attrs) { uint idx = name->asArrayIndex(); if (idx != UINT_MAX) @@ -876,10 +858,10 @@ bool Object::__defineOwnProperty__(ExecutionContext *ctx, const StringRef name, PropertyAttributes *cattrs; uint memberIndex; - if (isArrayObject() && name->equals(ctx->engine->id_length)) { - assert(ArrayObject::LengthPropertyIndex == internalClass->find(ctx->engine->id_length)); + if (isArrayObject() && name->equals(ctx->d()->engine->id_length)) { + assert(ArrayObject::LengthPropertyIndex == internalClass()->find(ctx->d()->engine->id_length)); Property *lp = propertyAt(ArrayObject::LengthPropertyIndex); - cattrs = internalClass->propertyData.constData() + ArrayObject::LengthPropertyIndex; + cattrs = internalClass()->propertyData.constData() + ArrayObject::LengthPropertyIndex; if (attrs.isEmpty() || p.isSubset(attrs, *lp, *cattrs)) return true; if (!cattrs->isWritable() || attrs.type() == PropertyAttributes::Accessor || attrs.isConfigurable() || attrs.isEnumerable()) @@ -900,18 +882,18 @@ bool Object::__defineOwnProperty__(ExecutionContext *ctx, const StringRef name, if (!succeeded) goto reject; if (attrs.isAccessor()) - hasAccessorProperty = 1; + setHasAccessorProperty(); return true; } // Clause 1 - memberIndex = internalClass->find(name.getPointer()); + memberIndex = internalClass()->find(name); current = (memberIndex < UINT_MAX) ? propertyAt(memberIndex) : 0; - cattrs = internalClass->propertyData.constData() + memberIndex; + cattrs = internalClass()->propertyData.constData() + memberIndex; if (!current) { // clause 3 - if (!extensible) + if (!isExtensible()) goto reject; // clause 4 Property pd; @@ -923,7 +905,7 @@ bool Object::__defineOwnProperty__(ExecutionContext *ctx, const StringRef name, return __defineOwnProperty__(ctx, memberIndex, name, p, attrs); reject: - if (ctx->strictMode) + if (ctx->d()->strictMode) ctx->throwTypeError(); return false; } @@ -931,7 +913,7 @@ reject: bool Object::__defineOwnProperty__(ExecutionContext *ctx, uint index, const Property &p, PropertyAttributes attrs) { // 15.4.5.1, 4b - if (isArrayObject() && index >= getLength() && !internalClass->propertyData[ArrayObject::LengthPropertyIndex].isWritable()) + if (isArrayObject() && index >= getLength() && !internalClass()->propertyData[ArrayObject::LengthPropertyIndex].isWritable()) goto reject; if (ArgumentsObject::isNonStrictArgumentsObject(this)) @@ -939,7 +921,7 @@ bool Object::__defineOwnProperty__(ExecutionContext *ctx, uint index, const Prop return defineOwnProperty2(ctx, index, p, attrs); reject: - if (ctx->strictMode) + if (ctx->d()->strictMode) ctx->throwTypeError(); return false; } @@ -950,14 +932,14 @@ bool Object::defineOwnProperty2(ExecutionContext *ctx, uint index, const Propert // Clause 1 { - current = arrayData->getProperty(index); + current = arrayData()->getProperty(index); if (!current && isStringObject()) current = static_cast<StringObject *>(this)->getIndex(index); } if (!current) { // clause 3 - if (!extensible) + if (!isExtensible()) goto reject; // clause 4 Property pp; @@ -973,14 +955,14 @@ bool Object::defineOwnProperty2(ExecutionContext *ctx, uint index, const Propert return true; } - return __defineOwnProperty__(ctx, index, StringRef::null(), p, attrs); + return __defineOwnProperty__(ctx, index, 0, p, attrs); reject: - if (ctx->strictMode) + if (ctx->d()->strictMode) ctx->throwTypeError(); return false; } -bool Object::__defineOwnProperty__(ExecutionContext *ctx, uint index, const StringRef member, const Property &p, PropertyAttributes attrs) +bool Object::__defineOwnProperty__(ExecutionContext *ctx, uint index, String *member, const Property &p, PropertyAttributes attrs) { // clause 5 if (attrs.isEmpty()) @@ -988,12 +970,12 @@ bool Object::__defineOwnProperty__(ExecutionContext *ctx, uint index, const Stri Property *current; PropertyAttributes cattrs; - if (!member.isNull()) { + if (member) { current = propertyAt(index); - cattrs = internalClass->propertyData[index]; + cattrs = internalClass()->propertyData[index]; } else { - current = arrayData->getProperty(index); - cattrs = arrayData->attributes(index); + current = arrayData()->getProperty(index); + cattrs = arrayData()->attributes(index); } // clause 6 @@ -1021,11 +1003,11 @@ bool Object::__defineOwnProperty__(ExecutionContext *ctx, uint index, const Stri // 9b cattrs.setType(PropertyAttributes::Accessor); cattrs.clearWritable(); - if (member.isNull()) { + if (!member) { // need to convert the array and the slot initSparseArray(); setArrayAttributes(index, cattrs); - current = arrayData->getProperty(index); + current = arrayData()->getProperty(index); } current->setGetter(0); current->setSetter(0); @@ -1033,10 +1015,10 @@ bool Object::__defineOwnProperty__(ExecutionContext *ctx, uint index, const Stri // 9c cattrs.setType(PropertyAttributes::Data); cattrs.setWritable(false); - if (member.isNull()) { + if (!member) { // need to convert the array and the slot setArrayAttributes(index, cattrs); - current = arrayData->getProperty(index); + current = arrayData()->getProperty(index); } current->value = Primitive::undefinedValue(); } @@ -1058,16 +1040,16 @@ bool Object::__defineOwnProperty__(ExecutionContext *ctx, uint index, const Stri accept: current->merge(cattrs, p, attrs); - if (!member.isNull()) { - InternalClass::changeMember(this, member.getPointer(), cattrs); + if (member) { + InternalClass::changeMember(this, member, cattrs); } else { setArrayAttributes(index, cattrs); } if (cattrs.isAccessor()) - hasAccessorProperty = 1; + setHasAccessorProperty(); return true; reject: - if (ctx->strictMode) + if (ctx->d()->strictMode) ctx->throwTypeError(); return false; } @@ -1076,8 +1058,8 @@ bool Object::__defineOwnProperty__(ExecutionContext *ctx, uint index, const Stri bool Object::__defineOwnProperty__(ExecutionContext *ctx, const QString &name, const Property &p, PropertyAttributes attrs) { Scope scope(ctx); - ScopedString s(scope, ctx->engine->newString(name)); - return __defineOwnProperty__(ctx, s, p, attrs); + ScopedString s(scope, ctx->d()->engine->newString(name)); + return __defineOwnProperty__(ctx, s.getPointer(), p, attrs); } @@ -1086,7 +1068,7 @@ void Object::copyArrayData(Object *other) Q_ASSERT(isArrayObject()); Scope scope(engine()); - if (other->protoHasArray() || other->hasAccessorProperty) { + if (other->protoHasArray() || other->hasAccessorProperty()) { uint len = other->getLength(); Q_ASSERT(len); @@ -1094,30 +1076,30 @@ void Object::copyArrayData(Object *other) for (uint i = 0; i < len; ++i) { arraySet(i, (v = other->getIndexed(i))); } - } else if (!other->arrayData) { + } else if (!other->arrayData()) { ; - } else if (other->hasAccessorProperty && other->arrayData->attrs && other->arrayData->isSparse()){ + } else if (other->hasAccessorProperty() && other->arrayData()->attrs() && other->arrayData()->isSparse()){ // do it the slow way ScopedValue v(scope); - for (const SparseArrayNode *it = static_cast<const SparseArrayData *>(other->arrayData)->sparse->begin(); - it != static_cast<const SparseArrayData *>(other->arrayData)->sparse->end(); it = it->nextNode()) { - v = other->getValue(reinterpret_cast<Property *>(other->arrayData->data + it->value), other->arrayData->attrs[it->value]); + for (const SparseArrayNode *it = static_cast<const SparseArrayData *>(other->arrayData())->sparse()->begin(); + it != static_cast<const SparseArrayData *>(other->arrayData())->sparse()->end(); it = it->nextNode()) { + v = other->getValue(reinterpret_cast<Property *>(other->arrayData()->arrayData() + it->value), other->arrayData()->attrs()[it->value]); arraySet(it->key(), v); } } else { - Q_ASSERT(!arrayData && other->arrayData); - ArrayData::realloc(this, other->arrayData->type, 0, other->arrayData->alloc, other->arrayData->attrs); + Q_ASSERT(!arrayData() && other->arrayData()); + ArrayData::realloc(this, other->arrayData()->type(), 0, other->arrayData()->alloc(), other->arrayData()->attrs()); if (other->arrayType() == ArrayData::Sparse) { - SparseArrayData *od = static_cast<SparseArrayData *>(other->arrayData); - SparseArrayData *dd = static_cast<SparseArrayData *>(arrayData); - dd->sparse = new SparseArray(*od->sparse); - dd->freeList = od->freeList; + SparseArrayData *od = static_cast<SparseArrayData *>(other->arrayData()); + SparseArrayData *dd = static_cast<SparseArrayData *>(arrayData()); + dd->setSparse(new SparseArray(*od->sparse())); + dd->freeList() = od->freeList(); } else { - SimpleArrayData *d = static_cast<SimpleArrayData *>(arrayData); - d->len = static_cast<SimpleArrayData *>(other->arrayData)->len; - d->offset = 0; + SimpleArrayData *d = static_cast<SimpleArrayData *>(arrayData()); + d->len() = static_cast<SimpleArrayData *>(other->arrayData())->len(); + d->offset() = 0; } - memcpy(arrayData->data, other->arrayData->data, arrayData->alloc*sizeof(Value)); + memcpy(arrayData()->arrayData(), other->arrayData()->arrayData(), arrayData()->alloc()*sizeof(Value)); } setArrayLengthUnchecked(other->getLength()); } @@ -1132,15 +1114,15 @@ uint Object::getLength(const Managed *m) bool Object::setArrayLength(uint newLen) { Q_ASSERT(isArrayObject()); - if (!internalClass->propertyData[ArrayObject::LengthPropertyIndex].isWritable()) + if (!internalClass()->propertyData[ArrayObject::LengthPropertyIndex].isWritable()) return false; uint oldLen = getLength(); bool ok = true; if (newLen < oldLen) { - if (!arrayData) { + if (!arrayData()) { Q_ASSERT(!newLen); } else { - uint l = arrayData->vtable()->truncate(this, newLen); + uint l = arrayData()->vtable()->truncate(this, newLen); if (l != newLen) ok = false; newLen = l; @@ -1164,30 +1146,23 @@ void Object::initSparseArray() DEFINE_OBJECT_VTABLE(ArrayObject); -ArrayObject::ArrayObject(ExecutionEngine *engine, const QStringList &list) - : Object(engine->arrayClass) +ArrayObject::Data::Data(ExecutionEngine *engine, const QStringList &list) + : Object::Data(engine->arrayClass) { - init(engine); + init(); Scope scope(engine); - ScopedValue protectThis(scope, this); + ScopedObject a(scope, this); // Converts a QStringList to JS. // The result is a new Array object with length equal to the length // of the QStringList, and the elements being the QStringList's // elements converted to JS Strings. int len = list.count(); - arrayReserve(len); + a->arrayReserve(len); ScopedValue v(scope); for (int ii = 0; ii < len; ++ii) - arrayPut(ii, (v = engine->newString(list.at(ii)))); - setArrayLengthUnchecked(len); -} - -void ArrayObject::init(ExecutionEngine *engine) -{ - Q_UNUSED(engine); - - memberData[LengthPropertyIndex] = Primitive::fromInt32(0); + a->arrayPut(ii, (v = engine->newString(list.at(ii)))); + a->setArrayLengthUnchecked(len); } ReturnedValue ArrayObject::getLookup(Managed *m, Lookup *l) @@ -1196,7 +1171,7 @@ ReturnedValue ArrayObject::getLookup(Managed *m, Lookup *l) // special case, as the property is on the object itself l->getter = Lookup::arrayLengthGetter; ArrayObject *a = static_cast<ArrayObject *>(m); - return a->memberData[ArrayObject::LengthPropertyIndex].asReturnedValue(); + return a->memberData()[ArrayObject::LengthPropertyIndex].asReturnedValue(); } return Object::getLookup(m, l); } @@ -1204,16 +1179,16 @@ ReturnedValue ArrayObject::getLookup(Managed *m, Lookup *l) uint ArrayObject::getLength(const Managed *m) { const ArrayObject *a = static_cast<const ArrayObject *>(m); - if (a->memberData[ArrayObject::LengthPropertyIndex].isInteger()) - return a->memberData[ArrayObject::LengthPropertyIndex].integerValue(); - return Primitive::toUInt32(a->memberData[ArrayObject::LengthPropertyIndex].doubleValue()); + if (a->memberData()[ArrayObject::LengthPropertyIndex].isInteger()) + return a->memberData()[ArrayObject::LengthPropertyIndex].integerValue(); + return Primitive::toUInt32(a->memberData()[ArrayObject::LengthPropertyIndex].doubleValue()); } QStringList ArrayObject::toQStringList() const { QStringList result; - QV4::ExecutionEngine *engine = internalClass->engine; + QV4::ExecutionEngine *engine = internalClass()->engine; Scope scope(engine); ScopedValue v(scope); diff --git a/src/qml/jsruntime/qv4object_p.h b/src/qml/jsruntime/qv4object_p.h index 40f38ee347..67459d5e77 100644 --- a/src/qml/jsruntime/qv4object_p.h +++ b/src/qml/jsruntime/qv4object_p.h @@ -103,39 +103,49 @@ struct URIErrorPrototype; struct Q_QML_EXPORT Object: Managed { - V4_OBJECT + struct Data : Managed::Data { + Data(ExecutionEngine *engine) + : Managed::Data(engine->objectClass) + { + } + Data(InternalClass *internal = 0); + + Members memberData; + ArrayData *arrayData; + }; + V4_OBJECT(Object) Q_MANAGED_TYPE(Object) + enum { IsObject = true }; - Members memberData; - ArrayData *arrayData; + Members &memberData() { return d()->memberData; } + const Members &memberData() const { return d()->memberData; } + const ArrayData *arrayData() const { return d()->arrayData; } + ArrayData *arrayData() { return d()->arrayData; } + void setArrayData(ArrayData *a) { d()->arrayData = a; } - Property *propertyAt(uint index) const { return reinterpret_cast<Property *>(memberData.data() + index); } + Property *propertyAt(uint index) const { return reinterpret_cast<Property *>(memberData().data() + index); } - Object(ExecutionEngine *engine); - Object(InternalClass *internalClass); - ~Object(); - - const ObjectVTable *vtable() const { return reinterpret_cast<const ObjectVTable *>(internalClass->vtable); } - Object *prototype() const { return internalClass->prototype; } + const ObjectVTable *vtable() const { return reinterpret_cast<const ObjectVTable *>(internalClass()->vtable); } + Object *prototype() const { return internalClass()->prototype; } bool setPrototype(Object *proto); - Property *__getOwnProperty__(const StringRef name, PropertyAttributes *attrs = 0); + Property *__getOwnProperty__(String *name, PropertyAttributes *attrs = 0); Property *__getOwnProperty__(uint index, PropertyAttributes *attrs = 0); - Property *__getPropertyDescriptor__(const StringRef name, PropertyAttributes *attrs = 0) const; + Property *__getPropertyDescriptor__(String *name, PropertyAttributes *attrs = 0) const; Property *__getPropertyDescriptor__(uint index, PropertyAttributes *attrs = 0) const; - bool hasProperty(const StringRef name) const; + bool hasProperty(String *name) const; bool hasProperty(uint index) const; - bool hasOwnProperty(const StringRef name) const; + bool hasOwnProperty(String *name) const; bool hasOwnProperty(uint index) const; - bool __defineOwnProperty__(ExecutionContext *ctx, uint index, const StringRef member, const Property &p, PropertyAttributes attrs); - bool __defineOwnProperty__(ExecutionContext *ctx, const StringRef name, const Property &p, PropertyAttributes attrs); + bool __defineOwnProperty__(ExecutionContext *ctx, uint index, String *member, const Property &p, PropertyAttributes attrs); + bool __defineOwnProperty__(ExecutionContext *ctx, String *name, const Property &p, PropertyAttributes attrs); bool __defineOwnProperty__(ExecutionContext *ctx, uint index, const Property &p, PropertyAttributes attrs); bool __defineOwnProperty__(ExecutionContext *ctx, const QString &name, const Property &p, PropertyAttributes attrs); bool defineOwnProperty2(ExecutionContext *ctx, uint index, const Property &p, PropertyAttributes attrs); @@ -155,24 +165,31 @@ struct Q_QML_EXPORT Object: Managed { void putValue(Property *pd, PropertyAttributes attrs, const ValueRef value); /* The spec default: Writable: true, Enumerable: false, Configurable: true */ - void defineDefaultProperty(const StringRef name, ValueRef value) { + void defineDefaultProperty(String *name, ValueRef value) { insertMember(name, value, Attr_Data|Attr_NotEnumerable); } void defineDefaultProperty(const QString &name, ValueRef value); void defineDefaultProperty(const QString &name, ReturnedValue (*code)(CallContext *), int argumentCount = 0); - void defineDefaultProperty(const StringRef name, ReturnedValue (*code)(CallContext *), int argumentCount = 0); + void defineDefaultProperty(String *name, ReturnedValue (*code)(CallContext *), int argumentCount = 0); void defineAccessorProperty(const QString &name, ReturnedValue (*getter)(CallContext *), ReturnedValue (*setter)(CallContext *)); - void defineAccessorProperty(const StringRef name, ReturnedValue (*getter)(CallContext *), ReturnedValue (*setter)(CallContext *)); + void defineAccessorProperty(String *name, ReturnedValue (*getter)(CallContext *), ReturnedValue (*setter)(CallContext *)); /* Fixed: Writable: false, Enumerable: false, Configurable: false */ void defineReadonlyProperty(const QString &name, ValueRef value); - void defineReadonlyProperty(const StringRef name, ValueRef value); + void defineReadonlyProperty(String *name, ValueRef value); - void insertMember(const StringRef s, const ValueRef v, PropertyAttributes attributes = Attr_Data) { - insertMember(s, Property(*v), attributes); + void insertMember(String *s, const ValueRef v, PropertyAttributes attributes = Attr_Data) { + Property p(*v); + insertMember(s, p, attributes); } - void insertMember(const StringRef s, const Property &p, PropertyAttributes attributes); + void insertMember(String *s, const Property &p, PropertyAttributes attributes); + + inline ExecutionEngine *engine() const { return internalClass()->engine; } - inline ExecutionEngine *engine() const { return internalClass->engine; } + inline bool hasAccessorProperty() const { return d()->hasAccessorProperty; } + inline void setHasAccessorProperty() { d()->hasAccessorProperty = true; } + + bool isExtensible() const { return d()->extensible; } + void setExtensible(bool b) { d()->extensible = b; } // Array handling @@ -186,30 +203,30 @@ public: void arraySet(uint index, ValueRef value); bool arrayPut(uint index, ValueRef value) { - return arrayData->vtable()->put(this, index, value); + return arrayData()->vtable()->put(this, index, value); } bool arrayPut(uint index, Value *values, uint n) { - return arrayData->vtable()->putArray(this, index, values, n); + return arrayData()->vtable()->putArray(this, index, values, n); } void setArrayAttributes(uint i, PropertyAttributes a) { - Q_ASSERT(arrayData); - if (arrayData->attrs || a != Attr_Data) { + Q_ASSERT(arrayData()); + if (arrayData()->attrs() || a != Attr_Data) { ArrayData::ensureAttributes(this); a.resolve(); - arrayData->vtable()->setAttribute(this, i, a); + arrayData()->vtable()->setAttribute(this, i, a); } } void push_back(const ValueRef v); ArrayData::Type arrayType() const { - return arrayData ? arrayData->type : ArrayData::Simple; + return arrayData() ? arrayData()->type() : ArrayData::Simple; } // ### remove me void setArrayType(ArrayData::Type t) { Q_ASSERT(t != ArrayData::Simple && t != ArrayData::Sparse); arrayCreate(); - arrayData->type = t; + arrayData()->setType(t); } inline void arrayReserve(uint n) { @@ -217,7 +234,7 @@ public: } void arrayCreate() { - if (!arrayData) + if (!arrayData()) ArrayData::realloc(this, ArrayData::Simple, 0, 0, false); #ifdef CHECK_SPARSE_ARRAYS initSparseArray(); @@ -225,34 +242,34 @@ public: } void initSparseArray(); - SparseArrayNode *sparseBegin() { return arrayType() == ArrayData::Sparse ? static_cast<SparseArrayData *>(arrayData)->sparse->begin() : 0; } - SparseArrayNode *sparseEnd() { return arrayType() == ArrayData::Sparse ? static_cast<SparseArrayData *>(arrayData)->sparse->end() : 0; } + SparseArrayNode *sparseBegin() { return arrayType() == ArrayData::Sparse ? static_cast<SparseArrayData *>(arrayData())->sparse()->begin() : 0; } + SparseArrayNode *sparseEnd() { return arrayType() == ArrayData::Sparse ? static_cast<SparseArrayData *>(arrayData())->sparse()->end() : 0; } inline bool protoHasArray() { Scope scope(engine()); Scoped<Object> p(scope, this); while ((p = p->prototype())) - if (p->arrayData) + if (p->arrayData()) return true; return false; } void ensureMemberIndex(uint idx); - inline ReturnedValue get(const StringRef name, bool *hasProperty = 0) + inline ReturnedValue get(String *name, bool *hasProperty = 0) { return vtable()->get(this, name, hasProperty); } inline ReturnedValue getIndexed(uint idx, bool *hasProperty = 0) { return vtable()->getIndexed(this, idx, hasProperty); } - inline void put(const StringRef name, const ValueRef v) + inline void put(String *name, const ValueRef v) { vtable()->put(this, name, v); } inline void putIndexed(uint idx, const ValueRef v) { vtable()->putIndexed(this, idx, v); } - PropertyAttributes query(StringRef name) const + PropertyAttributes query(String *name) const { return vtable()->query(this, name); } PropertyAttributes queryIndexed(uint index) const { return vtable()->queryIndexed(this, index); } - bool deleteProperty(const StringRef name) + bool deleteProperty(String *name) { return vtable()->deleteProperty(this, name); } bool deleteIndexedProperty(uint index) { return vtable()->deleteIndexedProperty(this, index); } @@ -260,7 +277,7 @@ public: { return vtable()->getLookup(this, l); } void setLookup(Lookup *l, const ValueRef v) { vtable()->setLookup(this, l, v); } - void advanceIterator(ObjectIterator *it, StringRef name, uint *index, Property *p, PropertyAttributes *attributes) + void advanceIterator(ObjectIterator *it, String *&name, uint *index, Property *p, PropertyAttributes *attributes) { vtable()->advanceIterator(this, it, name, index, p, attributes); } uint getLength() const { return vtable()->getLength(this); } @@ -269,29 +286,28 @@ public: inline ReturnedValue call(CallData *d) { return vtable()->call(this, d); } protected: - static void destroy(Managed *that); static void markObjects(Managed *that, ExecutionEngine *e); static ReturnedValue construct(Managed *m, CallData *); static ReturnedValue call(Managed *m, CallData *); - static ReturnedValue get(Managed *m, const StringRef name, bool *hasProperty); + static ReturnedValue get(Managed *m, String *name, bool *hasProperty); static ReturnedValue getIndexed(Managed *m, uint index, bool *hasProperty); - static void put(Managed *m, const StringRef name, const ValueRef value); + static void put(Managed *m, String *name, const ValueRef value); static void putIndexed(Managed *m, uint index, const ValueRef value); - static PropertyAttributes query(const Managed *m, StringRef name); + static PropertyAttributes query(const Managed *m, String *name); static PropertyAttributes queryIndexed(const Managed *m, uint index); - static bool deleteProperty(Managed *m, const StringRef name); + static bool deleteProperty(Managed *m, String *name); static bool deleteIndexedProperty(Managed *m, uint index); static ReturnedValue getLookup(Managed *m, Lookup *l); static void setLookup(Managed *m, Lookup *l, const ValueRef v); - static void advanceIterator(Managed *m, ObjectIterator *it, StringRef name, uint *index, Property *p, PropertyAttributes *attributes); + static void advanceIterator(Managed *m, ObjectIterator *it, String *&name, uint *index, Property *p, PropertyAttributes *attributes); static uint getLength(const Managed *m); private: - ReturnedValue internalGet(const StringRef name, bool *hasProperty); + ReturnedValue internalGet(String *name, bool *hasProperty); ReturnedValue internalGetIndexed(uint index, bool *hasProperty); - void internalPut(const StringRef name, const ValueRef value); + void internalPut(String *name, const ValueRef value); void internalPutIndexed(uint index, const ValueRef value); - bool internalDeleteProperty(const StringRef name); + bool internalDeleteProperty(String *name); bool internalDeleteIndexedProperty(uint index); friend struct ObjectIterator; @@ -299,48 +315,62 @@ private: }; struct BooleanObject: Object { - V4_OBJECT + struct Data : Object::Data { + Data(ExecutionEngine *engine, const ValueRef val) + : Object::Data(engine->booleanClass) + { + value = val; + } + Data(InternalClass *ic) + : Object::Data(ic) + { + Q_ASSERT(internalClass->vtable == staticVTable()); + value = Encode(false); + } + Value value; + }; + V4_OBJECT(Object) Q_MANAGED_TYPE(BooleanObject) - Value value; - BooleanObject(ExecutionEngine *engine, const ValueRef val) - : Object(engine->booleanClass) { - value = val; - } -protected: - BooleanObject(InternalClass *ic) - : Object(ic) { - Q_ASSERT(internalClass->vtable == staticVTable()); - value = Encode(false); - } + + Value value() const { return d()->value; } + }; struct NumberObject: Object { - V4_OBJECT + struct Data : Object::Data { + Data(ExecutionEngine *engine, const ValueRef val) + : Object::Data(engine->numberClass) { + value = val; + } + Data(InternalClass *ic) + : Object::Data(ic) { + Q_ASSERT(internalClass->vtable == staticVTable()); + value = Encode((int)0); + } + Value value; + }; + V4_OBJECT(Object) Q_MANAGED_TYPE(NumberObject) - Value value; - NumberObject(ExecutionEngine *engine, const ValueRef val) - : Object(engine->numberClass) { - value = val; - } -protected: - NumberObject(InternalClass *ic) - : Object(ic) { - Q_ASSERT(internalClass->vtable == staticVTable()); - value = Encode((int)0); - } + + Value value() const { return d()->value; } + }; struct ArrayObject: Object { - V4_OBJECT + struct Data : Object::Data { + Data(ExecutionEngine *engine) : Object::Data(engine->arrayClass) { init(); } + Data(ExecutionEngine *engine, const QStringList &list); + Data(InternalClass *ic) : Object::Data(ic) { init(); } + void init() + { memberData[LengthPropertyIndex] = Primitive::fromInt32(0); } + }; + + V4_OBJECT(Object) Q_MANAGED_TYPE(ArrayObject) enum { LengthPropertyIndex = 0 }; - ArrayObject(ExecutionEngine *engine) : Object(engine->arrayClass) { init(engine); } - ArrayObject(ExecutionEngine *engine, const QStringList &list); - ArrayObject(InternalClass *ic) : Object(ic) { init(ic->engine); } - void init(ExecutionEngine *engine); static ReturnedValue getLookup(Managed *m, Lookup *l); @@ -353,7 +383,7 @@ struct ArrayObject: Object { inline void Object::setArrayLengthUnchecked(uint l) { if (isArrayObject()) - memberData[ArrayObject::LengthPropertyIndex] = Primitive::fromUInt32(l); + memberData()[ArrayObject::LengthPropertyIndex] = Primitive::fromUInt32(l); } inline void Object::push_back(const ValueRef v) @@ -371,12 +401,12 @@ inline void Object::arraySet(uint index, const Property &p, PropertyAttributes a // ### Clean up arrayCreate(); if (attributes.isAccessor()) { - hasAccessorProperty = 1; + setHasAccessorProperty(); initSparseArray(); - } else if (index > 0x1000 && index > 2*arrayData->alloc) { + } else if (index > 0x1000 && index > 2*arrayData()->alloc()) { initSparseArray(); } else { - arrayData->vtable()->reallocate(this, index + 1, false); + arrayData()->vtable()->reallocate(this, index + 1, false); } setArrayAttributes(index, attributes); Property *pd = ArrayData::insert(this, index, attributes.isAccessor()); @@ -391,7 +421,7 @@ inline void Object::arraySet(uint index, const Property &p, PropertyAttributes a inline void Object::arraySet(uint index, ValueRef value) { arrayCreate(); - if (index > 0x1000 && index > 2*arrayData->alloc) { + if (index > 0x1000 && index > 2*arrayData()->alloc()) { initSparseArray(); } Property *pd = ArrayData::insert(this, index); @@ -418,23 +448,6 @@ inline ReturnedValue value_convert<Object>(ExecutionEngine *e, const Value &v) } #endif -struct ObjectRef : public ManagedRef -{ - DEFINE_REF_METHODS(Object, Managed) - - static ObjectRef fromValuePointer(Value *s) { - ObjectRef r; - r.ptr = s; - if (sizeof(void *) == 8) - r.ptr->val = 0; - else - *r.ptr = Value::fromManaged(0); - return r; - } -}; - -DEFINE_REF(ArrayObject, Object); - } QT_END_NAMESPACE diff --git a/src/qml/jsruntime/qv4objectiterator.cpp b/src/qml/jsruntime/qv4objectiterator.cpp index e5f693c323..216700fe69 100644 --- a/src/qml/jsruntime/qv4objectiterator.cpp +++ b/src/qml/jsruntime/qv4objectiterator.cpp @@ -46,63 +46,71 @@ using namespace QV4; -ObjectIterator::ObjectIterator(Value *scratch1, Value *scratch2, const ObjectRef o, uint flags) - : object(ObjectRef::fromValuePointer(scratch1)) - , current(ObjectRef::fromValuePointer(scratch2)) +ObjectIterator::ObjectIterator(Value *scratch1, Value *scratch2, Object *o, uint flags) + : object(scratch1) + , current(scratch2) , arrayNode(0) , arrayIndex(0) , memberIndex(0) , flags(flags) { - object = o.getPointer(); - current = o.getPointer(); - - if (!!object && object->asArgumentsObject()) { + object->o = o; + current->o = o; +#if QT_POINTER_SIZE == 4 + object->tag = QV4::Value::Managed_Type; + current->tag = QV4::Value::Managed_Type; +#endif + + if (object->as<ArgumentsObject>()) { Scope scope(object->engine()); Scoped<ArgumentsObject> (scope, object->asReturnedValue())->fullyCreate(); } } -ObjectIterator::ObjectIterator(Scope &scope, const ObjectRef o, uint flags) - : object(ObjectRef::fromValuePointer(scope.alloc(1))) - , current(ObjectRef::fromValuePointer(scope.alloc(1))) +ObjectIterator::ObjectIterator(Scope &scope, Object *o, uint flags) + : object(scope.alloc(1)) + , current(scope.alloc(1)) , arrayNode(0) , arrayIndex(0) , memberIndex(0) , flags(flags) { - object = o; - current = o; - - if (!!object && object->asArgumentsObject()) { + object->o = o; + current->o = o; +#if QT_POINTER_SIZE == 4 + object->tag = QV4::Value::Managed_Type; + current->tag = QV4::Value::Managed_Type; +#endif + + if (object->as<ArgumentsObject>()) { Scope scope(object->engine()); Scoped<ArgumentsObject> (scope, object->asReturnedValue())->fullyCreate(); } } -void ObjectIterator::next(StringRef name, uint *index, Property *pd, PropertyAttributes *attrs) +void ObjectIterator::next(String *&name, uint *index, Property *pd, PropertyAttributes *attrs) { name = (String *)0; *index = UINT_MAX; - if (!object) { + if (!object->asObject()) { *attrs = PropertyAttributes(); return; } while (1) { - if (!current) + if (!current->asObject()) break; while (1) { - current->advanceIterator(this, name, index, pd, attrs); + current->asObject()->advanceIterator(this, name, index, pd, attrs); if (attrs->isEmpty()) break; // check the property is not already defined earlier in the proto chain - if (current != object) { - Object *o = object; + if (current->asObject() != object->asObject()) { + Object *o = object->asObject(); bool shadowed = false; - while (o != current) { + while (o != current->asObject()) { if ((!!name && o->hasOwnProperty(name)) || (*index != UINT_MAX && o->hasOwnProperty(*index))) { shadowed = true; @@ -117,9 +125,9 @@ void ObjectIterator::next(StringRef name, uint *index, Property *pd, PropertyAtt } if (flags & WithProtoChain) - current = current->prototype(); + current->o = current->objectValue()->prototype(); else - current = (Object *)0; + current->o = (Object *)0; arrayIndex = 0; memberIndex = 0; @@ -129,7 +137,7 @@ void ObjectIterator::next(StringRef name, uint *index, Property *pd, PropertyAtt ReturnedValue ObjectIterator::nextPropertyName(ValueRef value) { - if (!object) + if (!object->asObject()) return Encode::null(); PropertyAttributes attrs; @@ -137,11 +145,13 @@ ReturnedValue ObjectIterator::nextPropertyName(ValueRef value) uint index; Scope scope(object->engine()); ScopedString name(scope); - next(name, &index, &p, &attrs); + String *n; + next(n, &index, &p, &attrs); + name = n; if (attrs.isEmpty()) return Encode::null(); - value = object->getValue(&p, attrs); + value = object->objectValue()->getValue(&p, attrs); if (!!name) return name->asReturnedValue(); @@ -151,7 +161,7 @@ ReturnedValue ObjectIterator::nextPropertyName(ValueRef value) ReturnedValue ObjectIterator::nextPropertyNameAsString(ValueRef value) { - if (!object) + if (!object->asObject()) return Encode::null(); PropertyAttributes attrs; @@ -159,11 +169,13 @@ ReturnedValue ObjectIterator::nextPropertyNameAsString(ValueRef value) uint index; Scope scope(object->engine()); ScopedString name(scope); - next(name, &index, &p, &attrs); + String *n; + next(n, &index, &p, &attrs); + name = n; if (attrs.isEmpty()) return Encode::null(); - value = object->getValue(&p, attrs); + value = object->objectValue()->getValue(&p, attrs); if (!!name) return name->asReturnedValue(); @@ -173,7 +185,7 @@ ReturnedValue ObjectIterator::nextPropertyNameAsString(ValueRef value) ReturnedValue ObjectIterator::nextPropertyNameAsString() { - if (!object) + if (!object->asObject()) return Encode::null(); PropertyAttributes attrs; @@ -181,7 +193,9 @@ ReturnedValue ObjectIterator::nextPropertyNameAsString() uint index; Scope scope(object->engine()); ScopedString name(scope); - next(name, &index, &p, &attrs); + String *n; + next(n, &index, &p, &attrs); + name = n; if (attrs.isEmpty()) return Encode::null(); @@ -197,7 +211,7 @@ DEFINE_OBJECT_VTABLE(ForEachIteratorObject); void ForEachIteratorObject::markObjects(Managed *that, ExecutionEngine *e) { ForEachIteratorObject *o = static_cast<ForEachIteratorObject *>(that); - o->workArea[0].mark(e); - o->workArea[1].mark(e); + o->d()->workArea[0].mark(e); + o->d()->workArea[1].mark(e); Object::markObjects(that, e); } diff --git a/src/qml/jsruntime/qv4objectiterator_p.h b/src/qml/jsruntime/qv4objectiterator_p.h index c87f284288..f20ad17b4a 100644 --- a/src/qml/jsruntime/qv4objectiterator_p.h +++ b/src/qml/jsruntime/qv4objectiterator_p.h @@ -67,37 +67,38 @@ struct Q_QML_EXPORT ObjectIterator WithProtoChain = 0x2, }; - ObjectRef object; - ObjectRef current; + Value *object; + Value *current; SparseArrayNode *arrayNode; uint arrayIndex; uint memberIndex; uint flags; - ObjectIterator(Value *scratch1, Value *scratch2, const ObjectRef o, uint flags); - ObjectIterator(Scope &scope, const ObjectRef o, uint flags); - void next(StringRef name, uint *index, Property *pd, PropertyAttributes *attributes = 0); + ObjectIterator(Value *scratch1, Value *scratch2, Object *o, uint flags); + ObjectIterator(Scope &scope, Object *o, uint flags); + void next(String *&name, uint *index, Property *pd, PropertyAttributes *attributes = 0); ReturnedValue nextPropertyName(ValueRef value); ReturnedValue nextPropertyNameAsString(ValueRef value); ReturnedValue nextPropertyNameAsString(); }; struct ForEachIteratorObject: Object { - V4_OBJECT + struct Data : Object::Data { + Data(ExecutionContext *ctx, Object *o) + : Object::Data(ctx->engine()) + , it(workArea, workArea + 1, o, ObjectIterator::EnumerableOnly|ObjectIterator::WithProtoChain) { + setVTable(staticVTable()); + } + ObjectIterator it; + Value workArea[2]; + }; + V4_OBJECT(Object) Q_MANAGED_TYPE(ForeachIteratorObject) - ObjectIterator it; - ForEachIteratorObject(ExecutionContext *ctx, const ObjectRef o) - : Object(ctx->engine), it(workArea, workArea + 1, - o, ObjectIterator::EnumerableOnly|ObjectIterator::WithProtoChain) { - setVTable(staticVTable()); - } - ReturnedValue nextPropertyName() { return it.nextPropertyNameAsString(); } + ReturnedValue nextPropertyName() { return d()->it.nextPropertyNameAsString(); } protected: static void markObjects(Managed *that, ExecutionEngine *e); - - Value workArea[2]; }; diff --git a/src/qml/jsruntime/qv4objectproto.cpp b/src/qml/jsruntime/qv4objectproto.cpp index 5c824bdfbd..6b8a19c7e6 100644 --- a/src/qml/jsruntime/qv4objectproto.cpp +++ b/src/qml/jsruntime/qv4objectproto.cpp @@ -74,8 +74,8 @@ using namespace QV4; DEFINE_OBJECT_VTABLE(ObjectCtor); -ObjectCtor::ObjectCtor(ExecutionContext *scope) - : FunctionObject(scope, QStringLiteral("Object")) +ObjectCtor::Data::Data(ExecutionContext *scope) + : FunctionObject::Data(scope, QStringLiteral("Object")) { setVTable(staticVTable()); } @@ -102,7 +102,7 @@ ReturnedValue ObjectCtor::call(Managed *m, CallData *callData) return RuntimeHelpers::toObject(m->engine()->currentContext(), ValueRef(&callData->args[0])); } -void ObjectPrototype::init(ExecutionEngine *v4, ObjectRef ctor) +void ObjectPrototype::init(ExecutionEngine *v4, Object *ctor) { Scope scope(v4); ScopedObject o(scope, this); @@ -133,10 +133,9 @@ void ObjectPrototype::init(ExecutionEngine *v4, ObjectRef ctor) defineDefaultProperty(QStringLiteral("__defineGetter__"), method_defineGetter, 2); defineDefaultProperty(QStringLiteral("__defineSetter__"), method_defineSetter, 2); - Scoped<String> id_proto(scope, v4->id___proto__); - Property p(v4->newBuiltinFunction(v4->rootContext, id_proto, method_get_proto)->getPointer(), - v4->newBuiltinFunction(v4->rootContext, id_proto, method_set_proto)->getPointer()); - insertMember(StringRef(v4->id___proto__), p, Attr_Accessor|Attr_NotEnumerable); + Property p(ScopedFunctionObject(scope, BuiltinFunction::create(v4->rootContext, v4->id___proto__, method_get_proto)).getPointer(), + ScopedFunctionObject(scope, BuiltinFunction::create(v4->rootContext, v4->id___proto__, method_set_proto)).getPointer()); + insertMember(v4->id___proto__, p, Attr_Accessor|Attr_NotEnumerable); } ReturnedValue ObjectPrototype::method_getPrototypeOf(CallContext *ctx) @@ -165,7 +164,7 @@ ReturnedValue ObjectPrototype::method_getOwnPropertyDescriptor(CallContext *ctx) if (scope.hasException()) return Encode::undefined(); PropertyAttributes attrs; - Property *desc = O->__getOwnProperty__(name, &attrs); + Property *desc = O->__getOwnProperty__(name.getPointer(), &attrs); return fromPropertyDescriptor(ctx, desc, attrs); } @@ -176,7 +175,7 @@ ReturnedValue ObjectPrototype::method_getOwnPropertyNames(CallContext *context) if (!O) return context->throwTypeError(); - ScopedArrayObject array(scope, getOwnPropertyNames(context->engine, context->callData->args[0])); + ScopedArrayObject array(scope, getOwnPropertyNames(context->d()->engine, context->d()->callData->args[0])); return array.asReturnedValue(); } @@ -187,11 +186,11 @@ ReturnedValue ObjectPrototype::method_create(CallContext *ctx) if (!O->isObject() && !O->isNull()) return ctx->throwTypeError(); - Scoped<Object> newObject(scope, ctx->engine->newObject()); + Scoped<Object> newObject(scope, ctx->d()->engine->newObject()); newObject->setPrototype(O->asObject()); - if (ctx->callData->argc > 1 && !ctx->callData->args[1].isUndefined()) { - ctx->callData->args[0] = newObject.asReturnedValue(); + if (ctx->d()->callData->argc > 1 && !ctx->d()->callData->args[1].isUndefined()) { + ctx->d()->callData->args[0] = newObject.asReturnedValue(); return method_defineProperties(ctx); } @@ -216,7 +215,7 @@ ReturnedValue ObjectPrototype::method_defineProperty(CallContext *ctx) if (scope.engine->hasException) return Encode::undefined(); - if (!O->__defineOwnProperty__(ctx, name, pd, attrs)) + if (!O->__defineOwnProperty__(ctx, name.getPointer(), pd, attrs)) return ctx->throwTypeError(); return O.asReturnedValue(); @@ -240,7 +239,9 @@ ReturnedValue ObjectPrototype::method_defineProperties(CallContext *ctx) uint index; PropertyAttributes attrs; Property pd; - it.next(name, &index, &pd, &attrs); + String *nm; + it.next(nm, &index, &pd, &attrs); + name = nm; if (attrs.isEmpty()) break; Property n; @@ -251,7 +252,7 @@ ReturnedValue ObjectPrototype::method_defineProperties(CallContext *ctx) return Encode::undefined(); bool ok; if (name) - ok = O->__defineOwnProperty__(ctx, name, n, nattrs); + ok = O->__defineOwnProperty__(ctx, name.getPointer(), n, nattrs); else ok = O->__defineOwnProperty__(ctx, index, n, nattrs); if (!ok) @@ -268,15 +269,15 @@ ReturnedValue ObjectPrototype::method_seal(CallContext *ctx) if (!o) return ctx->throwTypeError(); - o->extensible = false; + o->setExtensible(false); - o->internalClass = o->internalClass->sealed(); + o->setInternalClass(o->internalClass()->sealed()); - if (o->arrayData) { + if (o->arrayData()) { ArrayData::ensureAttributes(o.getPointer()); - for (uint i = 0; i < o->arrayData->alloc; ++i) { - if (!o->arrayData->isEmpty(i)) - o->arrayData->attrs[i].setConfigurable(false); + for (uint i = 0; i < o->arrayData()->alloc(); ++i) { + if (!o->arrayData()->isEmpty(i)) + o->arrayData()->attrs()[i].setConfigurable(false); } } @@ -293,17 +294,17 @@ ReturnedValue ObjectPrototype::method_freeze(CallContext *ctx) if (ArgumentsObject::isNonStrictArgumentsObject(o.getPointer())) Scoped<ArgumentsObject>(scope, o)->fullyCreate(); - o->extensible = false; + o->setExtensible(false); - o->internalClass = o->internalClass->frozen(); + o->setInternalClass(o->internalClass()->frozen()); - if (o->arrayData) { + if (o->arrayData()) { ArrayData::ensureAttributes(o.getPointer()); - for (uint i = 0; i < o->arrayData->alloc; ++i) { - if (!o->arrayData->isEmpty(i)) - o->arrayData->attrs[i].setConfigurable(false); - if (o->arrayData->attrs[i].isData()) - o->arrayData->attrs[i].setWritable(false); + for (uint i = 0; i < o->arrayData()->alloc(); ++i) { + if (!o->arrayData()->isEmpty(i)) + o->arrayData()->attrs()[i].setConfigurable(false); + if (o->arrayData()->attrs()[i].isData()) + o->arrayData()->attrs()[i].setWritable(false); } } return o.asReturnedValue(); @@ -316,7 +317,7 @@ ReturnedValue ObjectPrototype::method_preventExtensions(CallContext *ctx) if (!o) return ctx->throwTypeError(); - o->extensible = false; + o->setExtensible(false); return o.asReturnedValue(); } @@ -327,22 +328,22 @@ ReturnedValue ObjectPrototype::method_isSealed(CallContext *ctx) if (!o) return ctx->throwTypeError(); - if (o->extensible) + if (o->isExtensible()) return Encode(false); - if (o->internalClass != o->internalClass->sealed()) + if (o->internalClass() != o->internalClass()->sealed()) return Encode(false); - if (!o->arrayData || !o->arrayData->length()) + if (!o->arrayData() || !o->arrayData()->length()) return Encode(true); - if (o->arrayData->length() && !o->arrayData->attrs) + if (o->arrayData()->length() && !o->arrayData()->attrs()) return Encode(false); - for (uint i = 0; i < o->arrayData->alloc; ++i) { + for (uint i = 0; i < o->arrayData()->alloc(); ++i) { // ### Fix for sparse arrays - if (!o->arrayData->isEmpty(i)) - if (o->arrayData->attributes(i).isConfigurable()) + if (!o->arrayData()->isEmpty(i)) + if (o->arrayData()->attributes(i).isConfigurable()) return Encode(false); } @@ -356,22 +357,22 @@ ReturnedValue ObjectPrototype::method_isFrozen(CallContext *ctx) if (!o) return ctx->throwTypeError(); - if (o->extensible) + if (o->isExtensible()) return Encode(false); - if (o->internalClass != o->internalClass->frozen()) + if (o->internalClass() != o->internalClass()->frozen()) return Encode(false); - if (!o->arrayData->length()) + if (!o->arrayData()->length()) return Encode(true); - if (o->arrayData->length() && !o->arrayData->attrs) + if (o->arrayData()->length() && !o->arrayData()->attrs()) return Encode(false); - for (uint i = 0; i < o->arrayData->alloc; ++i) { + for (uint i = 0; i < o->arrayData()->alloc(); ++i) { // ### Fix for sparse arrays - if (!o->arrayData->isEmpty(i)) - if (o->arrayData->attributes(i).isConfigurable() || o->arrayData->attributes(i).isWritable()) + if (!o->arrayData()->isEmpty(i)) + if (o->arrayData()->attributes(i).isConfigurable() || o->arrayData()->attributes(i).isWritable()) return Encode(false); } @@ -385,7 +386,7 @@ ReturnedValue ObjectPrototype::method_isExtensible(CallContext *ctx) if (!o) return ctx->throwTypeError(); - return Encode((bool)o->extensible); + return Encode((bool)o->isExtensible()); } ReturnedValue ObjectPrototype::method_keys(CallContext *ctx) @@ -395,7 +396,7 @@ ReturnedValue ObjectPrototype::method_keys(CallContext *ctx) if (!o) return ctx->throwTypeError(); - Scoped<ArrayObject> a(scope, ctx->engine->newArrayObject()); + Scoped<ArrayObject> a(scope, ctx->d()->engine->newArrayObject()); ObjectIterator it(scope, o, ObjectIterator::EnumerableOnly); ScopedValue name(scope); @@ -412,24 +413,24 @@ ReturnedValue ObjectPrototype::method_keys(CallContext *ctx) ReturnedValue ObjectPrototype::method_toString(CallContext *ctx) { Scope scope(ctx); - if (ctx->callData->thisObject.isUndefined()) { - return ctx->engine->newString(QStringLiteral("[object Undefined]"))->asReturnedValue(); - } else if (ctx->callData->thisObject.isNull()) { - return ctx->engine->newString(QStringLiteral("[object Null]"))->asReturnedValue(); + if (ctx->d()->callData->thisObject.isUndefined()) { + return ctx->d()->engine->newString(QStringLiteral("[object Undefined]"))->asReturnedValue(); + } else if (ctx->d()->callData->thisObject.isNull()) { + return ctx->d()->engine->newString(QStringLiteral("[object Null]"))->asReturnedValue(); } else { - ScopedObject obj(scope, RuntimeHelpers::toObject(ctx, ValueRef(&ctx->callData->thisObject))); + ScopedObject obj(scope, RuntimeHelpers::toObject(ctx, ValueRef(&ctx->d()->callData->thisObject))); QString className = obj->className(); - return ctx->engine->newString(QString::fromLatin1("[object %1]").arg(className))->asReturnedValue(); + return ctx->d()->engine->newString(QString::fromLatin1("[object %1]").arg(className))->asReturnedValue(); } } ReturnedValue ObjectPrototype::method_toLocaleString(CallContext *ctx) { Scope scope(ctx); - ScopedObject o(scope, ctx->callData->thisObject.toObject(ctx)); + ScopedObject o(scope, ctx->d()->callData->thisObject.toObject(ctx)); if (!o) return Encode::undefined(); - Scoped<FunctionObject> f(scope, o->get(ctx->engine->id_toString)); + Scoped<FunctionObject> f(scope, o->get(ctx->d()->engine->id_toString)); if (!f) return ctx->throwTypeError(); ScopedCallData callData(scope, 0); @@ -440,8 +441,8 @@ ReturnedValue ObjectPrototype::method_toLocaleString(CallContext *ctx) ReturnedValue ObjectPrototype::method_valueOf(CallContext *ctx) { Scope scope(ctx); - ScopedValue v(scope, ctx->callData->thisObject.toObject(ctx)); - if (ctx->engine->hasException) + ScopedValue v(scope, ctx->d()->callData->thisObject.toObject(ctx)); + if (ctx->d()->engine->hasException) return Encode::undefined(); return v.asReturnedValue(); } @@ -452,12 +453,12 @@ ReturnedValue ObjectPrototype::method_hasOwnProperty(CallContext *ctx) Scoped<String> P(scope, ctx->argument(0), Scoped<String>::Convert); if (scope.engine->hasException) return Encode::undefined(); - Scoped<Object> O(scope, ctx->callData->thisObject, Scoped<Object>::Convert); + Scoped<Object> O(scope, ctx->d()->callData->thisObject, Scoped<Object>::Convert); if (scope.engine->hasException) return Encode::undefined(); - bool r = O->hasOwnProperty(P); + bool r = O->hasOwnProperty(P.getPointer()); if (!r) - r = !O->query(P).isEmpty(); + r = !O->query(P.getPointer()).isEmpty(); return Encode(r); } @@ -468,7 +469,7 @@ ReturnedValue ObjectPrototype::method_isPrototypeOf(CallContext *ctx) if (!V) return Encode(false); - Scoped<Object> O(scope, ctx->callData->thisObject, Scoped<Object>::Convert); + Scoped<Object> O(scope, ctx->d()->callData->thisObject, Scoped<Object>::Convert); if (scope.engine->hasException) return Encode::undefined(); Scoped<Object> proto(scope, V->prototype()); @@ -487,17 +488,17 @@ ReturnedValue ObjectPrototype::method_propertyIsEnumerable(CallContext *ctx) if (scope.engine->hasException) return Encode::undefined(); - Scoped<Object> o(scope, ctx->callData->thisObject, Scoped<Object>::Convert); + Scoped<Object> o(scope, ctx->d()->callData->thisObject, Scoped<Object>::Convert); if (scope.engine->hasException) return Encode::undefined(); PropertyAttributes attrs; - o->__getOwnProperty__(p, &attrs); + o->__getOwnProperty__(p.getPointer(), &attrs); return Encode(attrs.isEnumerable()); } ReturnedValue ObjectPrototype::method_defineGetter(CallContext *ctx) { - if (ctx->callData->argc < 2) + if (ctx->d()->callData->argc < 2) return ctx->throwTypeError(); Scope scope(ctx); @@ -509,23 +510,23 @@ ReturnedValue ObjectPrototype::method_defineGetter(CallContext *ctx) if (scope.engine->hasException) return Encode::undefined(); - Scoped<Object> o(scope, ctx->callData->thisObject); + Scoped<Object> o(scope, ctx->d()->callData->thisObject); if (!o) { - if (!ctx->callData->thisObject.isUndefined()) + if (!ctx->d()->callData->thisObject.isUndefined()) return Encode::undefined(); - o = ctx->engine->globalObject; + o = ctx->d()->engine->globalObject; } Property pd; pd.value = f; pd.set = Primitive::emptyValue(); - o->__defineOwnProperty__(ctx, prop, pd, Attr_Accessor); + o->__defineOwnProperty__(ctx, prop.getPointer(), pd, Attr_Accessor); return Encode::undefined(); } ReturnedValue ObjectPrototype::method_defineSetter(CallContext *ctx) { - if (ctx->callData->argc < 2) + if (ctx->d()->callData->argc < 2) return ctx->throwTypeError(); Scope scope(ctx); @@ -537,24 +538,24 @@ ReturnedValue ObjectPrototype::method_defineSetter(CallContext *ctx) if (scope.engine->hasException) return Encode::undefined(); - Scoped<Object> o(scope, ctx->callData->thisObject); + Scoped<Object> o(scope, ctx->d()->callData->thisObject); if (!o) { - if (!ctx->callData->thisObject.isUndefined()) + if (!ctx->d()->callData->thisObject.isUndefined()) return Encode::undefined(); - o = ctx->engine->globalObject; + o = ctx->d()->engine->globalObject; } Property pd; pd.value = Primitive::emptyValue(); pd.set = f; - o->__defineOwnProperty__(ctx, prop, pd, Attr_Accessor); + o->__defineOwnProperty__(ctx, prop.getPointer(), pd, Attr_Accessor); return Encode::undefined(); } ReturnedValue ObjectPrototype::method_get_proto(CallContext *ctx) { Scope scope(ctx); - ScopedObject o(scope, ctx->callData->thisObject.asObject()); + ScopedObject o(scope, ctx->d()->callData->thisObject.asObject()); if (!o) return ctx->throwTypeError(); @@ -564,21 +565,21 @@ ReturnedValue ObjectPrototype::method_get_proto(CallContext *ctx) ReturnedValue ObjectPrototype::method_set_proto(CallContext *ctx) { Scope scope(ctx); - Scoped<Object> o(scope, ctx->callData->thisObject); - if (!o || !ctx->callData->argc) + Scoped<Object> o(scope, ctx->d()->callData->thisObject); + if (!o || !ctx->d()->callData->argc) return ctx->throwTypeError(); - if (ctx->callData->args[0].isNull()) { + if (ctx->d()->callData->args[0].isNull()) { o->setPrototype(0); return Encode::undefined(); } - Scoped<Object> p(scope, ctx->callData->args[0]); + Scoped<Object> p(scope, ctx->d()->callData->args[0]); bool ok = false; if (!!p) { if (o->prototype() == p.getPointer()) { ok = true; - } else if (o->extensible) { + } else if (o->isExtensible()) { ok = o->setPrototype(p.getPointer()); } } @@ -601,14 +602,14 @@ void ObjectPrototype::toPropertyDescriptor(ExecutionContext *ctx, const ValueRef desc->set = Primitive::emptyValue(); ScopedValue tmp(scope); - if (o->hasProperty(ctx->engine->id_enumerable)) - attrs->setEnumerable((tmp = o->get(ctx->engine->id_enumerable))->toBoolean()); + if (o->hasProperty(ctx->d()->engine->id_enumerable)) + attrs->setEnumerable((tmp = o->get(ctx->d()->engine->id_enumerable))->toBoolean()); - if (o->hasProperty(ctx->engine->id_configurable)) - attrs->setConfigurable((tmp = o->get(ctx->engine->id_configurable))->toBoolean()); + if (o->hasProperty(ctx->d()->engine->id_configurable)) + attrs->setConfigurable((tmp = o->get(ctx->d()->engine->id_configurable))->toBoolean()); - if (o->hasProperty(ctx->engine->id_get)) { - ScopedValue get(scope, o->get(ctx->engine->id_get)); + if (o->hasProperty(ctx->d()->engine->id_get)) { + ScopedValue get(scope, o->get(ctx->d()->engine->id_get)); FunctionObject *f = get->asFunctionObject(); if (f || get->isUndefined()) { desc->value = get; @@ -619,8 +620,8 @@ void ObjectPrototype::toPropertyDescriptor(ExecutionContext *ctx, const ValueRef attrs->setType(PropertyAttributes::Accessor); } - if (o->hasProperty(ctx->engine->id_set)) { - ScopedValue set(scope, o->get(ctx->engine->id_set)); + if (o->hasProperty(ctx->d()->engine->id_set)) { + ScopedValue set(scope, o->get(ctx->d()->engine->id_set)); FunctionObject *f = set->asFunctionObject(); if (f || set->isUndefined()) { desc->set = set; @@ -631,22 +632,22 @@ void ObjectPrototype::toPropertyDescriptor(ExecutionContext *ctx, const ValueRef attrs->setType(PropertyAttributes::Accessor); } - if (o->hasProperty(ctx->engine->id_writable)) { + if (o->hasProperty(ctx->d()->engine->id_writable)) { if (attrs->isAccessor()) { ctx->throwTypeError(); return; } - attrs->setWritable((tmp = o->get(ctx->engine->id_writable))->toBoolean()); + attrs->setWritable((tmp = o->get(ctx->d()->engine->id_writable))->toBoolean()); // writable forces it to be a data descriptor desc->value = Primitive::undefinedValue(); } - if (o->hasProperty(ctx->engine->id_value)) { + if (o->hasProperty(ctx->d()->engine->id_value)) { if (attrs->isAccessor()) { ctx->throwTypeError(); return; } - desc->value = o->get(ctx->engine->id_value); + desc->value = o->get(ctx->d()->engine->id_value); attrs->setType(PropertyAttributes::Data); } @@ -660,7 +661,7 @@ ReturnedValue ObjectPrototype::fromPropertyDescriptor(ExecutionContext *ctx, con if (!desc) return Encode::undefined(); - ExecutionEngine *engine = ctx->engine; + ExecutionEngine *engine = ctx->d()->engine; Scope scope(engine); // Let obj be the result of creating a new object as if by the expression new Object() where Object // is the standard built-in constructor with that name. @@ -671,24 +672,24 @@ ReturnedValue ObjectPrototype::fromPropertyDescriptor(ExecutionContext *ctx, con if (attrs.isData()) { pd.value = desc->value; s = engine->newString(QStringLiteral("value")); - o->__defineOwnProperty__(ctx, s, pd, Attr_Data); + o->__defineOwnProperty__(ctx, s.getPointer(), pd, Attr_Data); pd.value = Primitive::fromBoolean(attrs.isWritable()); s = engine->newString(QStringLiteral("writable")); - o->__defineOwnProperty__(ctx, s, pd, Attr_Data); + o->__defineOwnProperty__(ctx, s.getPointer(), pd, Attr_Data); } else { pd.value = desc->getter() ? desc->getter()->asReturnedValue() : Encode::undefined(); s = engine->newString(QStringLiteral("get")); - o->__defineOwnProperty__(ctx, s, pd, Attr_Data); + o->__defineOwnProperty__(ctx, s.getPointer(), pd, Attr_Data); pd.value = desc->setter() ? desc->setter()->asReturnedValue() : Encode::undefined(); s = engine->newString(QStringLiteral("set")); - o->__defineOwnProperty__(ctx, s, pd, Attr_Data); + o->__defineOwnProperty__(ctx, s.getPointer(), pd, Attr_Data); } pd.value = Primitive::fromBoolean(attrs.isEnumerable()); s = engine->newString(QStringLiteral("enumerable")); - o->__defineOwnProperty__(ctx, s, pd, Attr_Data); + o->__defineOwnProperty__(ctx, s.getPointer(), pd, Attr_Data); pd.value = Primitive::fromBoolean(attrs.isConfigurable()); s = engine->newString(QStringLiteral("configurable")); - o->__defineOwnProperty__(ctx, s, pd, Attr_Data); + o->__defineOwnProperty__(ctx, s.getPointer(), pd, Attr_Data); return o.asReturnedValue(); } diff --git a/src/qml/jsruntime/qv4objectproto_p.h b/src/qml/jsruntime/qv4objectproto_p.h index 2b9974be06..c34b367223 100644 --- a/src/qml/jsruntime/qv4objectproto_p.h +++ b/src/qml/jsruntime/qv4objectproto_p.h @@ -51,8 +51,10 @@ namespace QV4 { struct ObjectCtor: FunctionObject { - V4_OBJECT - ObjectCtor(ExecutionContext *scope); + struct Data : FunctionObject::Data { + Data(ExecutionContext *scope); + }; + V4_OBJECT(FunctionObject) static ReturnedValue construct(Managed *that, CallData *callData); static ReturnedValue call(Managed *that, CallData *callData); @@ -60,9 +62,7 @@ struct ObjectCtor: FunctionObject struct ObjectPrototype: Object { - ObjectPrototype(InternalClass *ic) : Object(ic) {} - - void init(ExecutionEngine *engine, ObjectRef ctor); + void init(ExecutionEngine *engine, Object *ctor); static ReturnedValue method_getPrototypeOf(CallContext *ctx); static ReturnedValue method_getOwnPropertyDescriptor(CallContext *ctx); diff --git a/src/qml/jsruntime/qv4persistent_p.h b/src/qml/jsruntime/qv4persistent_p.h index 21f37f3d96..7b0f80e06a 100644 --- a/src/qml/jsruntime/qv4persistent_p.h +++ b/src/qml/jsruntime/qv4persistent_p.h @@ -84,13 +84,11 @@ public: PersistentValue(ReturnedValue val); template<typename T> PersistentValue(Returned<T> *obj); - PersistentValue(const ManagedRef obj); PersistentValue &operator=(const ValueRef other); PersistentValue &operator=(const ScopedValue &other); PersistentValue &operator =(ReturnedValue other); template<typename T> PersistentValue &operator=(Returned<T> *obj); - PersistentValue &operator=(const ManagedRef obj); ~PersistentValue(); ReturnedValue value() const { diff --git a/src/qml/jsruntime/qv4profiling.cpp b/src/qml/jsruntime/qv4profiling.cpp index 8a0cc56448..b70e9de1a0 100644 --- a/src/qml/jsruntime/qv4profiling.cpp +++ b/src/qml/jsruntime/qv4profiling.cpp @@ -40,6 +40,7 @@ ****************************************************************************/ #include "qv4profiling_p.h" +#include "qv4mm_p.h" QT_BEGIN_NAMESPACE @@ -60,10 +61,12 @@ FunctionCallProperties FunctionCall::resolve() const } -Profiler::Profiler() : enabled(false) +Profiler::Profiler(QV4::ExecutionEngine *engine) : enabled(false), m_engine(engine) { static int metatype = qRegisterMetaType<QList<QV4::Profiling::FunctionCallProperties> >(); + static int metatype2 = qRegisterMetaType<QList<QV4::Profiling::MemoryAllocationProperties> >(); Q_UNUSED(metatype); + Q_UNUSED(metatype2); m_timer.start(); } @@ -87,13 +90,29 @@ void Profiler::reportData() FunctionCallProperties props = call.resolve(); resolved.insert(std::upper_bound(resolved.begin(), resolved.end(), props, comp), props); } - emit dataReady(resolved); + emit dataReady(resolved, m_memory_data); } void Profiler::startProfiling() { if (!enabled) { m_data.clear(); + m_memory_data.clear(); + + qint64 timestamp = m_timer.nsecsElapsed(); + MemoryAllocationProperties heap = {timestamp, + (qint64)m_engine->memoryManager->getAllocatedMem(), + HeapPage}; + m_memory_data.append(heap); + MemoryAllocationProperties small = {timestamp, + (qint64)m_engine->memoryManager->getUsedMem(), + SmallItem}; + m_memory_data.append(small); + MemoryAllocationProperties large = {timestamp, + (qint64)m_engine->memoryManager->getLargeItemsMem(), + LargeItem}; + m_memory_data.append(large); + enabled = true; } } diff --git a/src/qml/jsruntime/qv4profiling_p.h b/src/qml/jsruntime/qv4profiling_p.h index 6869b3134d..b9ddac0309 100644 --- a/src/qml/jsruntime/qv4profiling_p.h +++ b/src/qml/jsruntime/qv4profiling_p.h @@ -54,6 +54,12 @@ namespace QV4 { namespace Profiling { +enum MemoryType { + HeapPage, + LargeItem, + SmallItem +}; + struct FunctionCallProperties { qint64 start; qint64 end; @@ -63,6 +69,12 @@ struct FunctionCallProperties { int column; }; +struct MemoryAllocationProperties { + qint64 timestamp; + qint64 size; + MemoryType type; +}; + class FunctionCall { public: @@ -101,6 +113,14 @@ private: qint64 m_end; }; +#define Q_V4_PROFILE_ALLOC(engine, size, type)\ + (engine->profiler && engine->profiler->enabled ?\ + engine->profiler->trackAlloc(size, type) : size) + +#define Q_V4_PROFILE_DEALLOC(engine, pointer, size, type) \ + (engine->profiler && engine->profiler->enabled ?\ + engine->profiler->trackDealloc(pointer, size, type) : pointer) + #define Q_V4_PROFILE(engine, ctx, function)\ ((engine->profiler && engine->profiler->enabled) ?\ Profiling::FunctionCallProfiler::profileCall(engine->profiler, ctx, function) :\ @@ -110,7 +130,21 @@ class Q_QML_EXPORT Profiler : public QObject { Q_OBJECT Q_DISABLE_COPY(Profiler) public: - Profiler(); + Profiler(QV4::ExecutionEngine *engine); + + size_t trackAlloc(size_t size, MemoryType type) + { + MemoryAllocationProperties allocation = {m_timer.nsecsElapsed(), (qint64)size, type}; + m_memory_data.append(allocation); + return size; + } + + void *trackDealloc(void *pointer, size_t size, MemoryType type) + { + MemoryAllocationProperties allocation = {m_timer.nsecsElapsed(), -(qint64)size, type}; + m_memory_data.append(allocation); + return pointer; + } bool enabled; @@ -121,11 +155,14 @@ public slots: void setTimer(const QElapsedTimer &timer) { m_timer = timer; } signals: - void dataReady(const QList<QV4::Profiling::FunctionCallProperties> &); + void dataReady(const QList<QV4::Profiling::FunctionCallProperties> &, + const QList<QV4::Profiling::MemoryAllocationProperties> &); private: + QV4::ExecutionEngine *m_engine; QElapsedTimer m_timer; QVector<FunctionCall> m_data; + QList<MemoryAllocationProperties> m_memory_data; friend class FunctionCallProfiler; }; @@ -160,10 +197,12 @@ public: } // namespace Profiling } // namespace QV4 +Q_DECLARE_TYPEINFO(QV4::Profiling::MemoryAllocationProperties, Q_MOVABLE_TYPE); Q_DECLARE_TYPEINFO(QV4::Profiling::FunctionCallProperties, Q_MOVABLE_TYPE); Q_DECLARE_TYPEINFO(QV4::Profiling::FunctionCall, Q_MOVABLE_TYPE); QT_END_NAMESPACE Q_DECLARE_METATYPE(QList<QV4::Profiling::FunctionCallProperties>) +Q_DECLARE_METATYPE(QList<QV4::Profiling::MemoryAllocationProperties>) #endif // QV4PROFILING_H diff --git a/src/qml/jsruntime/qv4qobjectwrapper.cpp b/src/qml/jsruntime/qv4qobjectwrapper.cpp index d64f821a38..e12b8f1756 100644 --- a/src/qml/jsruntime/qv4qobjectwrapper.cpp +++ b/src/qml/jsruntime/qv4qobjectwrapper.cpp @@ -87,7 +87,7 @@ QT_BEGIN_NAMESPACE using namespace QV4; -static QPair<QObject *, int> extractQtMethod(QV4::FunctionObjectRef function) +static QPair<QObject *, int> extractQtMethod(QV4::FunctionObject *function) { QV4::ExecutionEngine *v4 = function->engine(); if (v4) { @@ -239,14 +239,11 @@ static QV4::ReturnedValue LoadProperty(QV8Engine *engine, QObject *object, } } -QObjectWrapper::QObjectWrapper(ExecutionEngine *engine, QObject *object) - : Object(engine) - , m_object(object) +QObjectWrapper::Data::Data(ExecutionEngine *engine, QObject *object) + : Object::Data(engine) + , object(object) { setVTable(staticVTable()); - - Scope scope(engine); - ScopedObject protectThis(scope, this); } void QObjectWrapper::initializeBindings(ExecutionEngine *engine) @@ -259,21 +256,21 @@ QQmlPropertyData *QObjectWrapper::findProperty(ExecutionEngine *engine, QQmlCont { Q_UNUSED(revisionMode); - QQmlData *ddata = QQmlData::get(m_object, false); + QQmlData *ddata = QQmlData::get(d()->object, false); if (!ddata) return 0; QQmlPropertyData *result = 0; if (ddata && ddata->propertyCache) - result = ddata->propertyCache->property(name, m_object, qmlContext); + result = ddata->propertyCache->property(name, d()->object, qmlContext); else - result = QQmlPropertyCache::property(engine->v8Engine->engine(), m_object, name, qmlContext, *local); + result = QQmlPropertyCache::property(engine->v8Engine->engine(), d()->object, name, qmlContext, *local); return result; } ReturnedValue QObjectWrapper::getQmlProperty(ExecutionContext *ctx, QQmlContextData *qmlContext, String *n, QObjectWrapper::RevisionMode revisionMode, bool *hasProperty, bool includeImports) { - if (QQmlData::wasDeleted(m_object)) { + if (QQmlData::wasDeleted(d()->object)) { if (hasProperty) *hasProperty = false; return QV4::Encode::undefined(); @@ -284,14 +281,14 @@ ReturnedValue QObjectWrapper::getQmlProperty(ExecutionContext *ctx, QQmlContextD if (name->equals(scope.engine->id_destroy) || name->equals(scope.engine->id_toString)) { int index = name->equals(scope.engine->id_destroy) ? QV4::QObjectMethod::DestroyMethod : QV4::QObjectMethod::ToStringMethod; - QV4::ScopedValue method(scope, QV4::QObjectMethod::create(ctx->engine->rootContext, m_object, index)); + QV4::ScopedValue method(scope, QV4::QObjectMethod::create(ctx->d()->engine->rootContext, d()->object, index)); if (hasProperty) *hasProperty = true; return method.asReturnedValue(); } QQmlPropertyData local; - QQmlPropertyData *result = findProperty(ctx->engine, qmlContext, name.getPointer(), revisionMode, &local); + QQmlPropertyData *result = findProperty(ctx->d()->engine, qmlContext, name.getPointer(), revisionMode, &local); if (!result) { if (includeImports && name->startsWithUpper()) { @@ -306,18 +303,18 @@ ReturnedValue QObjectWrapper::getQmlProperty(ExecutionContext *ctx, QQmlContextD if (r.scriptIndex != -1) { return QV4::Encode::undefined(); } else if (r.type) { - return QmlTypeWrapper::create(ctx->engine->v8Engine, m_object, r.type, QmlTypeWrapper::ExcludeEnums); + return QmlTypeWrapper::create(ctx->d()->engine->v8Engine, d()->object, r.type, QmlTypeWrapper::ExcludeEnums); } else if (r.importNamespace) { - return QmlTypeWrapper::create(ctx->engine->v8Engine, m_object, qmlContext->imports, r.importNamespace, QmlTypeWrapper::ExcludeEnums); + return QmlTypeWrapper::create(ctx->d()->engine->v8Engine, d()->object, qmlContext->imports, r.importNamespace, QmlTypeWrapper::ExcludeEnums); } Q_ASSERT(!"Unreachable"); } } } - return QV4::Object::get(this, name, hasProperty); + return QV4::Object::get(this, name.getPointer(), hasProperty); } - QQmlData *ddata = QQmlData::get(m_object, false); + QQmlData *ddata = QQmlData::get(d()->object, false); if (revisionMode == QV4::QObjectWrapper::CheckRevision && result->hasRevision()) { if (ddata && ddata->propertyCache && !ddata->propertyCache->isAllowedInRevision(result)) { @@ -330,7 +327,7 @@ ReturnedValue QObjectWrapper::getQmlProperty(ExecutionContext *ctx, QQmlContextD if (hasProperty) *hasProperty = true; - return getProperty(m_object, ctx, result); + return getProperty(d()->object, ctx, result); } ReturnedValue QObjectWrapper::getProperty(QObject *object, ExecutionContext *ctx, QQmlPropertyData *property, bool captureRequired) @@ -345,23 +342,23 @@ ReturnedValue QObjectWrapper::getProperty(QObject *object, ExecutionContext *ctx Q_ASSERT(vmemo); return vmemo->vmeMethod(property->coreIndex); } else if (property->isV4Function()) { - QV4::Scoped<QV4::Object> qmlcontextobject(scope, ctx->engine->qmlContextObject()); - return QV4::QObjectMethod::create(ctx->engine->rootContext, object, property->coreIndex, qmlcontextobject); + QV4::Scoped<QV4::Object> qmlcontextobject(scope, ctx->d()->engine->qmlContextObject()); + return QV4::QObjectMethod::create(ctx->d()->engine->rootContext, object, property->coreIndex, qmlcontextobject); } else if (property->isSignalHandler()) { - QV4::Scoped<QV4::QmlSignalHandler> handler(scope, new (ctx->engine->memoryManager) QV4::QmlSignalHandler(ctx->engine, object, property->coreIndex)); + QV4::Scoped<QV4::QmlSignalHandler> handler(scope, scope.engine->memoryManager->alloc<QV4::QmlSignalHandler>(ctx->d()->engine, object, property->coreIndex)); - QV4::ScopedString connect(scope, ctx->engine->newIdentifier(QStringLiteral("connect"))); - QV4::ScopedString disconnect(scope, ctx->engine->newIdentifier(QStringLiteral("disconnect"))); - handler->put(connect, QV4::ScopedValue(scope, ctx->engine->functionClass->prototype->get(connect))); - handler->put(disconnect, QV4::ScopedValue(scope, ctx->engine->functionClass->prototype->get(disconnect))); + QV4::ScopedString connect(scope, ctx->d()->engine->newIdentifier(QStringLiteral("connect"))); + QV4::ScopedString disconnect(scope, ctx->d()->engine->newIdentifier(QStringLiteral("disconnect"))); + handler->put(connect.getPointer(), QV4::ScopedValue(scope, ctx->d()->engine->functionClass->prototype->get(connect.getPointer()))); + handler->put(disconnect.getPointer(), QV4::ScopedValue(scope, ctx->d()->engine->functionClass->prototype->get(disconnect.getPointer()))); return handler.asReturnedValue(); } else { - return QV4::QObjectMethod::create(ctx->engine->rootContext, object, property->coreIndex); + return QV4::QObjectMethod::create(ctx->d()->engine->rootContext, object, property->coreIndex); } } - QQmlEnginePrivate *ep = ctx->engine->v8Engine->engine() ? QQmlEnginePrivate::get(ctx->engine->v8Engine->engine()) : 0; + QQmlEnginePrivate *ep = ctx->d()->engine->v8Engine->engine() ? QQmlEnginePrivate::get(ctx->d()->engine->v8Engine->engine()) : 0; if (property->hasAccessors()) { QQmlNotifier *n = 0; @@ -370,7 +367,7 @@ ReturnedValue QObjectWrapper::getProperty(QObject *object, ExecutionContext *ctx if (ep && ep->propertyCapture && property->accessors->notifier) nptr = &n; - QV4::ScopedValue rv(scope, LoadProperty<ReadAccessor::Accessor>(ctx->engine->v8Engine, object, *property, nptr)); + QV4::ScopedValue rv(scope, LoadProperty<ReadAccessor::Accessor>(ctx->d()->engine->v8Engine, object, *property, nptr)); if (captureRequired) { if (property->accessors->notifier) { @@ -392,9 +389,9 @@ ReturnedValue QObjectWrapper::getProperty(QObject *object, ExecutionContext *ctx Q_ASSERT(vmemo); return vmemo->vmeProperty(property->coreIndex); } else if (property->isDirect()) { - return LoadProperty<ReadAccessor::Direct>(ctx->engine->v8Engine, object, *property, 0); + return LoadProperty<ReadAccessor::Direct>(ctx->d()->engine->v8Engine, object, *property, 0); } else { - return LoadProperty<ReadAccessor::Indirect>(ctx->engine->v8Engine, object, *property, 0); + return LoadProperty<ReadAccessor::Indirect>(ctx->d()->engine->v8Engine, object, *property, 0); } } @@ -413,7 +410,7 @@ ReturnedValue QObjectWrapper::getQmlProperty(ExecutionContext *ctx, QQmlContextD return QV4::Encode::null(); } - QV4::Scoped<QObjectWrapper> wrapper(scope, wrap(ctx->engine, object)); + QV4::Scoped<QObjectWrapper> wrapper(scope, wrap(ctx->d()->engine, object)); if (!wrapper) { if (hasProperty) *hasProperty = false; @@ -431,7 +428,7 @@ bool QObjectWrapper::setQmlProperty(ExecutionContext *ctx, QQmlContextData *qmlC QQmlPropertyData local; QQmlPropertyData *result = 0; { - result = QQmlPropertyCache::property(ctx->engine->v8Engine->engine(), object, name, qmlContext, local); + result = QQmlPropertyCache::property(ctx->d()->engine->v8Engine->engine(), object, name, qmlContext, local); } if (!result) @@ -460,7 +457,7 @@ void QObjectWrapper::setProperty(QObject *object, ExecutionContext *ctx, QQmlPro QV4::Scope scope(ctx); QV4::ScopedFunctionObject f(scope, value); if (f) { - if (!f->bindingKeyFlag) { + if (!f->bindingKeyFlag()) { if (!property->isVarProperty() && property->propType != qMetaTypeId<QJSValue>()) { // assigning a JS function to a non var or QJSValue property or is not allowed. QString error = QLatin1String("Cannot assign JavaScript function to "); @@ -473,7 +470,7 @@ void QObjectWrapper::setProperty(QObject *object, ExecutionContext *ctx, QQmlPro } } else { // binding assignment. - QQmlContextData *callingQmlContext = QV4::QmlContextWrapper::callingContext(ctx->engine); + QQmlContextData *callingQmlContext = QV4::QmlContextWrapper::callingContext(ctx->d()->engine); QV4::Scoped<QQmlBindingFunction> bindingFunction(scope, f); bindingFunction->initBindingLocation(); @@ -513,7 +510,7 @@ void QObjectWrapper::setProperty(QObject *object, ExecutionContext *ctx, QQmlPro } else if (value->isUndefined() && property->propType == QMetaType::QJsonValue) { PROPERTY_STORE(QJsonValue, QJsonValue(QJsonValue::Undefined)); } else if (!newBinding && property->propType == qMetaTypeId<QJSValue>()) { - PROPERTY_STORE(QJSValue, new QJSValuePrivate(ctx->engine, value)); + PROPERTY_STORE(QJSValue, new QJSValuePrivate(ctx->d()->engine, value)); } else if (value->isUndefined()) { QString error = QLatin1String("Cannot assign [undefined] to "); if (!QMetaType::typeName(property->propType)) @@ -541,11 +538,11 @@ void QObjectWrapper::setProperty(QObject *object, ExecutionContext *ctx, QQmlPro } else { QVariant v; if (property->isQList()) - v = ctx->engine->v8Engine->toVariant(value, qMetaTypeId<QList<QObject *> >()); + v = ctx->d()->engine->v8Engine->toVariant(value, qMetaTypeId<QList<QObject *> >()); else - v = ctx->engine->v8Engine->toVariant(value, property->propType); + v = ctx->d()->engine->v8Engine->toVariant(value, property->propType); - QQmlContextData *callingQmlContext = QV4::QmlContextWrapper::callingContext(ctx->engine); + QQmlContextData *callingQmlContext = QV4::QmlContextWrapper::callingContext(ctx->d()->engine); if (!QQmlPropertyPrivate::write(object, *property, v, callingQmlContext)) { const char *valueType = 0; if (v.userType() == QVariant::Invalid) valueType = "null"; @@ -634,9 +631,9 @@ ReturnedValue QObjectWrapper::getProperty(QObject *object, ExecutionContext *ctx void QObjectWrapper::setProperty(ExecutionContext *ctx, int propertyIndex, const ValueRef value) { - if (QQmlData::wasDeleted(m_object)) + if (QQmlData::wasDeleted(d()->object)) return; - QQmlData *ddata = QQmlData::get(m_object, /*create*/false); + QQmlData *ddata = QQmlData::get(d()->object, /*create*/false); if (!ddata) return; @@ -644,7 +641,7 @@ void QObjectWrapper::setProperty(ExecutionContext *ctx, int propertyIndex, const Q_ASSERT(cache); QQmlPropertyData *property = cache->property(propertyIndex); Q_ASSERT(property); // We resolved this property earlier, so it better exist! - return setProperty(m_object, ctx, property, value); + return setProperty(d()->object, ctx, property, value); } bool QObjectWrapper::isEqualTo(Managed *a, Managed *b) @@ -661,28 +658,28 @@ ReturnedValue QObjectWrapper::create(ExecutionEngine *engine, QObject *object) QQmlEngine *qmlEngine = engine->v8Engine->engine(); if (qmlEngine) QQmlData::ensurePropertyCache(qmlEngine, object); - return (new (engine->memoryManager) QV4::QObjectWrapper(engine, object))->asReturnedValue(); + return (engine->memoryManager->alloc<QV4::QObjectWrapper>(engine, object))->asReturnedValue(); } -QV4::ReturnedValue QObjectWrapper::get(Managed *m, const StringRef name, bool *hasProperty) +QV4::ReturnedValue QObjectWrapper::get(Managed *m, String *name, bool *hasProperty) { QObjectWrapper *that = static_cast<QObjectWrapper*>(m); ExecutionEngine *v4 = m->engine(); QQmlContextData *qmlContext = QV4::QmlContextWrapper::callingContext(v4); - return that->getQmlProperty(v4->currentContext(), qmlContext, name.getPointer(), IgnoreRevision, hasProperty, /*includeImports*/ true); + return that->getQmlProperty(v4->currentContext(), qmlContext, name, IgnoreRevision, hasProperty, /*includeImports*/ true); } -void QObjectWrapper::put(Managed *m, const StringRef name, const ValueRef value) +void QObjectWrapper::put(Managed *m, String *name, const ValueRef value) { QObjectWrapper *that = static_cast<QObjectWrapper*>(m); ExecutionEngine *v4 = m->engine(); - if (v4->hasException || QQmlData::wasDeleted(that->m_object)) + if (v4->hasException || QQmlData::wasDeleted(that->d()->object)) return; QQmlContextData *qmlContext = QV4::QmlContextWrapper::callingContext(v4); - if (!setQmlProperty(v4->currentContext(), qmlContext, that->m_object, name.getPointer(), QV4::QObjectWrapper::IgnoreRevision, value)) { - QQmlData *ddata = QQmlData::get(that->m_object); + if (!setQmlProperty(v4->currentContext(), qmlContext, that->d()->object, name, QV4::QObjectWrapper::IgnoreRevision, value)) { + QQmlData *ddata = QQmlData::get(that->d()->object); // Types created by QML are not extensible at run-time, but for other QObjects we can store them // as regular JavaScript properties, like on JavaScript objects. if (ddata && ddata->context) { @@ -695,7 +692,7 @@ void QObjectWrapper::put(Managed *m, const StringRef name, const ValueRef value) } } -PropertyAttributes QObjectWrapper::query(const Managed *m, StringRef name) +PropertyAttributes QObjectWrapper::query(const Managed *m, String *name) { const QObjectWrapper *that = static_cast<const QObjectWrapper*>(m); ExecutionEngine *engine = that->engine(); @@ -708,27 +705,36 @@ PropertyAttributes QObjectWrapper::query(const Managed *m, StringRef name) return QV4::Object::query(m, name); } -void QObjectWrapper::advanceIterator(Managed *m, ObjectIterator *it, StringRef name, uint *index, Property *p, PropertyAttributes *attributes) +void QObjectWrapper::advanceIterator(Managed *m, ObjectIterator *it, String *&name, uint *index, Property *p, PropertyAttributes *attributes) { + // Used to block access to QObject::destroyed() and QObject::deleteLater() from QML + static const int destroyedIdx1 = QObject::staticMetaObject.indexOfSignal("destroyed(QObject*)"); + static const int destroyedIdx2 = QObject::staticMetaObject.indexOfSignal("destroyed()"); + static const int deleteLaterIdx = QObject::staticMetaObject.indexOfSlot("deleteLater()"); + name = (String *)0; *index = UINT_MAX; QObjectWrapper *that = static_cast<QObjectWrapper*>(m); - if (that->m_object) { - const QMetaObject *mo = that->m_object->metaObject(); + if (that->d()->object) { + const QMetaObject *mo = that->d()->object->metaObject(); const int propertyCount = mo->propertyCount(); if (it->arrayIndex < static_cast<uint>(propertyCount)) { - name = that->engine()->newString(QString::fromUtf8(mo->property(it->arrayIndex).name())); + name = that->engine()->newString(QString::fromUtf8(mo->property(it->arrayIndex).name()))->getPointer(); ++it->arrayIndex; *attributes = QV4::Attr_Data; p->value = that->get(name); return; } const int methodCount = mo->methodCount(); - if (it->arrayIndex < static_cast<uint>(propertyCount + methodCount)) { - name = that->engine()->newString(QString::fromUtf8(mo->method(it->arrayIndex - propertyCount).name())); + while (it->arrayIndex < static_cast<uint>(propertyCount + methodCount)) { + const int index = it->arrayIndex - propertyCount; + const QMetaMethod method = mo->method(index); ++it->arrayIndex; + if (method.access() == QMetaMethod::Private || index == deleteLaterIdx || index == destroyedIdx1 || index == destroyedIdx2) + continue; + name = that->engine()->newString(QString::fromUtf8(method.name()))->getPointer(); *attributes = QV4::Attr_Data; p->value = that->get(name); return; @@ -857,10 +863,10 @@ struct QObjectSlotDispatcher : public QtPrivate::QSlotObjectBase ReturnedValue QObjectWrapper::method_connect(CallContext *ctx) { - if (ctx->callData->argc == 0) + if (ctx->d()->callData->argc == 0) V4THROW_ERROR("Function.prototype.connect: no arguments given"); - QPair<QObject *, int> signalInfo = extractQtSignal(ctx->callData->thisObject); + QPair<QObject *, int> signalInfo = extractQtSignal(ctx->d()->callData->thisObject); QObject *signalObject = signalInfo.first; int signalIndex = signalInfo.second; // in method range, not signal range! @@ -877,11 +883,11 @@ ReturnedValue QObjectWrapper::method_connect(CallContext *ctx) QV4::ScopedFunctionObject f(scope); QV4::ScopedValue thisObject (scope, QV4::Encode::undefined()); - if (ctx->callData->argc == 1) { - f = ctx->callData->args[0]; - } else if (ctx->callData->argc >= 2) { - thisObject = ctx->callData->args[0]; - f = ctx->callData->args[1]; + if (ctx->d()->callData->argc == 1) { + f = ctx->d()->callData->args[0]; + } else if (ctx->d()->callData->argc >= 2) { + thisObject = ctx->d()->callData->args[0]; + f = ctx->d()->callData->args[1]; } if (!f) @@ -908,12 +914,12 @@ ReturnedValue QObjectWrapper::method_connect(CallContext *ctx) ReturnedValue QObjectWrapper::method_disconnect(CallContext *ctx) { - if (ctx->callData->argc == 0) + if (ctx->d()->callData->argc == 0) V4THROW_ERROR("Function.prototype.disconnect: no arguments given"); QV4::Scope scope(ctx); - QPair<QObject *, int> signalInfo = extractQtSignal(ctx->callData->thisObject); + QPair<QObject *, int> signalInfo = extractQtSignal(ctx->d()->callData->thisObject); QObject *signalObject = signalInfo.first; int signalIndex = signalInfo.second; @@ -929,11 +935,11 @@ ReturnedValue QObjectWrapper::method_disconnect(CallContext *ctx) QV4::ScopedFunctionObject functionValue(scope); QV4::ScopedValue functionThisValue(scope, QV4::Encode::undefined()); - if (ctx->callData->argc == 1) { - functionValue = ctx->callData->args[0]; - } else if (ctx->callData->argc >= 2) { - functionThisValue = ctx->callData->args[0]; - functionValue = ctx->callData->args[1]; + if (ctx->d()->callData->argc == 1) { + functionValue = ctx->d()->callData->args[0]; + } else if (ctx->d()->callData->argc >= 2) { + functionThisValue = ctx->d()->callData->args[0]; + functionValue = ctx->d()->callData->args[1]; } if (!functionValue) @@ -945,7 +951,7 @@ ReturnedValue QObjectWrapper::method_disconnect(CallContext *ctx) QPair<QObject *, int> functionData = extractQtMethod(functionValue); void *a[] = { - ctx->engine, + ctx->d()->engine, functionValue.ptr, functionThisValue.ptr, functionData.first, @@ -975,7 +981,7 @@ void QObjectWrapper::markObjects(Managed *that, QV4::ExecutionEngine *e) { QObjectWrapper *This = static_cast<QObjectWrapper*>(that); - if (QObject *o = This->m_object.data()) { + if (QObject *o = This->d()->object.data()) { QQmlVMEMetaObject *vme = QQmlVMEMetaObject::get(o); if (vme) vme->mark(e); @@ -1017,9 +1023,9 @@ namespace { void QObjectWrapper::destroy(Managed *that) { QObjectWrapper *This = static_cast<QObjectWrapper*>(that); - QPointer<QObject> object = This->m_object; + QPointer<QObject> object = This->d()->object; ExecutionEngine *engine = This->engine(); - This->~QObjectWrapper(); + This->d()->~Data(); This = 0; if (!object) return; @@ -1728,7 +1734,7 @@ QV4::ReturnedValue CallArgument::toValue(QV8Engine *engine) } else if (type == -1 || type == qMetaTypeId<QVariant>()) { QVariant value = *qvariantPtr; QV4::ScopedValue rv(scope, engine->fromVariant(value)); - QV4::QObjectWrapperRef qobjectWrapper = rv; + QV4::Scoped<QV4::QObjectWrapper> qobjectWrapper(scope, rv); if (!!qobjectWrapper) { if (QObject *object = qobjectWrapper->object()) QQmlData::get(object, true)->setImplicitDestructible(); @@ -1741,28 +1747,28 @@ QV4::ReturnedValue CallArgument::toValue(QV8Engine *engine) ReturnedValue QObjectMethod::create(ExecutionContext *scope, QObject *object, int index, const ValueRef qmlGlobal) { - return (new (scope->engine->memoryManager) QObjectMethod(scope, object, index, qmlGlobal))->asReturnedValue(); + return (scope->d()->engine->memoryManager->alloc<QObjectMethod>(scope, object, index, qmlGlobal))->asReturnedValue(); } -QObjectMethod::QObjectMethod(ExecutionContext *scope, QObject *object, int index, const ValueRef qmlGlobal) - : FunctionObject(scope) - , m_object(object) - , m_index(index) +QObjectMethod::Data::Data(ExecutionContext *scope, QObject *object, int index, const ValueRef qmlGlobal) + : FunctionObject::Data(scope) + , object(object) + , index(index) + , qmlGlobal(qmlGlobal) { setVTable(staticVTable()); subtype = WrappedQtMethod; - m_qmlGlobal = qmlGlobal; } QV4::ReturnedValue QObjectMethod::method_toString(QV4::ExecutionContext *ctx) { QString result; - if (m_object) { - QString objectName = m_object->objectName(); + if (d()->object) { + QString objectName = d()->object->objectName(); - result += QString::fromUtf8(m_object->metaObject()->className()); + result += QString::fromUtf8(d()->object->metaObject()->className()); result += QLatin1String("(0x"); - result += QString::number((quintptr)m_object.data(),16); + result += QString::number((quintptr)d()->object.data(),16); if (!objectName.isEmpty()) { result += QLatin1String(", \""); @@ -1775,14 +1781,14 @@ QV4::ReturnedValue QObjectMethod::method_toString(QV4::ExecutionContext *ctx) result = QLatin1String("null"); } - return ctx->engine->newString(result)->asReturnedValue(); + return ctx->d()->engine->newString(result)->asReturnedValue(); } QV4::ReturnedValue QObjectMethod::method_destroy(QV4::ExecutionContext *ctx, const ValueRef args, int argc) { - if (!m_object) + if (!d()->object) return Encode::undefined(); - if (QQmlData::keepAliveDuringGarbageCollection(m_object)) + if (QQmlData::keepAliveDuringGarbageCollection(d()->object)) return ctx->throwError(QStringLiteral("Invalid attempt to destroy() an indestructible object")); int delay = 0; @@ -1790,9 +1796,9 @@ QV4::ReturnedValue QObjectMethod::method_destroy(QV4::ExecutionContext *ctx, con delay = args[0].toUInt32(); if (delay > 0) - QTimer::singleShot(delay, m_object, SLOT(deleteLater())); + QTimer::singleShot(delay, d()->object, SLOT(deleteLater())); else - m_object->deleteLater(); + d()->object->deleteLater(); return Encode::undefined(); } @@ -1806,12 +1812,12 @@ ReturnedValue QObjectMethod::call(Managed *m, CallData *callData) ReturnedValue QObjectMethod::callInternal(CallData *callData) { ExecutionContext *context = engine()->currentContext(); - if (m_index == DestroyMethod) + if (d()->index == DestroyMethod) return method_destroy(context, callData->args, callData->argc); - else if (m_index == ToStringMethod) + else if (d()->index == ToStringMethod) return method_toString(context); - QObject *object = m_object.data(); + QObject *object = d()->object.data(); if (!object) return Encode::undefined(); @@ -1819,7 +1825,7 @@ ReturnedValue QObjectMethod::callInternal(CallData *callData) if (!ddata) return Encode::undefined(); - QV8Engine *v8Engine = context->engine->v8Engine; + QV8Engine *v8Engine = context->d()->engine->v8Engine; QV4::ExecutionEngine *v4 = QV8Engine::getV4(v8Engine); QV4::Scope scope(v4); @@ -1827,16 +1833,16 @@ ReturnedValue QObjectMethod::callInternal(CallData *callData) if (QQmlData *ddata = static_cast<QQmlData *>(QObjectPrivate::get(object)->declarativeData)) { if (ddata->propertyCache) { - QQmlPropertyData *d = ddata->propertyCache->method(m_index); - if (!d) + QQmlPropertyData *data = ddata->propertyCache->method(d()->index); + if (!data) return QV4::Encode::undefined(); - method = *d; + method = *data; } } if (method.coreIndex == -1) { const QMetaObject *mo = object->metaObject(); - const QMetaMethod moMethod = mo->method(m_index); + const QMetaMethod moMethod = mo->method(d()->index); method.load(moMethod); if (method.coreIndex == -1) @@ -1845,7 +1851,7 @@ ReturnedValue QObjectMethod::callInternal(CallData *callData) // Look for overloaded methods QByteArray methodName = moMethod.name(); const int methodOffset = mo->methodOffset(); - for (int ii = m_index - 1; ii >= methodOffset; --ii) { + for (int ii = d()->index - 1; ii >= methodOffset; --ii) { if (methodName == mo->method(ii).name()) { method.setFlags(method.getFlags() | QQmlPropertyData::IsOverload); method.overrideIndexIsProperty = 0; @@ -1858,7 +1864,7 @@ ReturnedValue QObjectMethod::callInternal(CallData *callData) if (method.isV4Function()) { QV4::ScopedValue rv(scope, QV4::Primitive::undefinedValue()); - QV4::ScopedValue qmlGlobal(scope, m_qmlGlobal.value()); + QV4::ScopedValue qmlGlobal(scope, d()->qmlGlobal.value()); QQmlV4Function func(callData, rv, qmlGlobal, QmlContextWrapper::getContext(qmlGlobal), v8Engine); @@ -1879,10 +1885,10 @@ ReturnedValue QObjectMethod::callInternal(CallData *callData) DEFINE_OBJECT_VTABLE(QObjectMethod); -QmlSignalHandler::QmlSignalHandler(ExecutionEngine *engine, QObject *object, int signalIndex) - : Object(engine) - , m_object(object) - , m_signalIndex(signalIndex) +QmlSignalHandler::Data::Data(ExecutionEngine *engine, QObject *object, int signalIndex) + : Object::Data(engine) + , object(object) + , signalIndex(signalIndex) { setVTable(staticVTable()); } diff --git a/src/qml/jsruntime/qv4qobjectwrapper_p.h b/src/qml/jsruntime/qv4qobjectwrapper_p.h index 0af01c5614..a774917713 100644 --- a/src/qml/jsruntime/qv4qobjectwrapper_p.h +++ b/src/qml/jsruntime/qv4qobjectwrapper_p.h @@ -77,13 +77,17 @@ struct QObjectSlotDispatcher; struct Q_QML_EXPORT QObjectWrapper : public QV4::Object { - V4_OBJECT + struct Data : QV4::Object::Data { + Data(ExecutionEngine *engine, QObject *object); + QPointer<QObject> object; + }; + V4_OBJECT(QV4::Object) enum RevisionMode { IgnoreRevision, CheckRevision }; static void initializeBindings(ExecutionEngine *engine); - QObject *object() const { return m_object.data(); } + QObject *object() const { return d()->object.data(); } ReturnedValue getQmlProperty(ExecutionContext *ctx, QQmlContextData *qmlContext, String *name, RevisionMode revisionMode, bool *hasProperty = 0, bool includeImports = false); static ReturnedValue getQmlProperty(ExecutionContext *ctx, QQmlContextData *qmlContext, QObject *object, String *name, RevisionMode revisionMode, bool *hasProperty = 0); @@ -106,16 +110,12 @@ private: static ReturnedValue create(ExecutionEngine *engine, QObject *object); - QObjectWrapper(ExecutionEngine *engine, QObject *object); - QQmlPropertyData *findProperty(ExecutionEngine *engine, QQmlContextData *qmlContext, String *name, RevisionMode revisionMode, QQmlPropertyData *local) const; - QPointer<QObject> m_object; - - static ReturnedValue get(Managed *m, const StringRef name, bool *hasProperty); - static void put(Managed *m, const StringRef name, const ValueRef value); - static PropertyAttributes query(const Managed *, StringRef name); - static void advanceIterator(Managed *m, ObjectIterator *it, StringRef name, uint *index, Property *p, PropertyAttributes *attributes); + static ReturnedValue get(Managed *m, String *name, bool *hasProperty); + static void put(Managed *m, String *name, const ValueRef value); + static PropertyAttributes query(const Managed *, String *name); + static void advanceIterator(Managed *m, ObjectIterator *it, String *&name, uint *index, Property *p, PropertyAttributes *attributes); static void markObjects(Managed *that, QV4::ExecutionEngine *e); static void destroy(Managed *that); @@ -125,51 +125,52 @@ private: struct QObjectMethod : public QV4::FunctionObject { - V4_OBJECT + struct Data : QV4::FunctionObject::Data { + Data(QV4::ExecutionContext *scope, QObject *object, int index, const ValueRef qmlGlobal); + QPointer<QObject> object; + int index; + QV4::PersistentValue qmlGlobal; + }; + V4_OBJECT(QV4::FunctionObject) enum { DestroyMethod = -1, ToStringMethod = -2 }; static ReturnedValue create(QV4::ExecutionContext *scope, QObject *object, int index, const ValueRef qmlGlobal = Primitive::undefinedValue()); - int methodIndex() const { return m_index; } - QObject *object() const { return m_object.data(); } - -private: - QObjectMethod(QV4::ExecutionContext *scope, QObject *object, int index, const ValueRef qmlGlobal); + int methodIndex() const { return d()->index; } + QObject *object() const { return d()->object.data(); } QV4::ReturnedValue method_toString(QV4::ExecutionContext *ctx); QV4::ReturnedValue method_destroy(QV4::ExecutionContext *ctx, const ValueRef args, int argc); - QPointer<QObject> m_object; - int m_index; - QV4::PersistentValue m_qmlGlobal; - static ReturnedValue call(Managed *, CallData *callData); ReturnedValue callInternal(CallData *callData); static void destroy(Managed *that) { - static_cast<QObjectMethod *>(that)->~QObjectMethod(); + static_cast<QObjectMethod *>(that)->d()->~Data(); } }; struct QmlSignalHandler : public QV4::Object { - V4_OBJECT + struct Data : QV4::Object::Data { + Data(ExecutionEngine *engine, QObject *object, int signalIndex); + QPointer<QObject> object; + int signalIndex; + }; + V4_OBJECT(QV4::Object) - QmlSignalHandler(ExecutionEngine *engine, QObject *object, int signalIndex); - int signalIndex() const { return m_signalIndex; } - QObject *object() const { return m_object.data(); } + int signalIndex() const { return d()->signalIndex; } + QObject *object() const { return d()->object.data(); } private: - QPointer<QObject> m_object; - int m_signalIndex; static void destroy(Managed *that) { - static_cast<QmlSignalHandler *>(that)->~QmlSignalHandler(); + static_cast<QmlSignalHandler *>(that)->d()->~Data(); } }; @@ -195,8 +196,6 @@ private Q_SLOTS: void removeDestroyedObject(QObject*); }; -DEFINE_REF(QObjectWrapper, Object); - } QT_END_NAMESPACE diff --git a/src/qml/jsruntime/qv4regexp.cpp b/src/qml/jsruntime/qv4regexp.cpp index e5490cffd1..e2de584e31 100644 --- a/src/qml/jsruntime/qv4regexp.cpp +++ b/src/qml/jsruntime/qv4regexp.cpp @@ -42,6 +42,7 @@ #include "qv4regexp_p.h" #include "qv4engine_p.h" #include "qv4scopedvalue_p.h" +#include "qv4mm_p.h" using namespace QV4; @@ -49,7 +50,7 @@ RegExpCache::~RegExpCache() { for (RegExpCache::Iterator it = begin(), e = end(); it != e; ++it) - it.value()->m_cache = 0; + it.value()->d()->cache = 0; clear(); } @@ -63,11 +64,11 @@ uint RegExp::match(const QString &string, int start, uint *matchOffsets) WTF::String s(string); #if ENABLE(YARR_JIT) - if (!m_jitCode.isFallBack() && m_jitCode.has16BitCode()) - return m_jitCode.execute(s.characters16(), start, s.length(), (int*)matchOffsets).start; + if (!jitCode().isFallBack() && jitCode().has16BitCode()) + return jitCode().execute(s.characters16(), start, s.length(), (int*)matchOffsets).start; #endif - return JSC::Yarr::interpret(m_byteCode.get(), s.characters16(), string.length(), start, matchOffsets); + return JSC::Yarr::interpret(byteCode().get(), s.characters16(), string.length(), start, matchOffsets); } RegExp* RegExp::create(ExecutionEngine* engine, const QString& pattern, bool ignoreCase, bool multiline) @@ -80,53 +81,49 @@ RegExp* RegExp::create(ExecutionEngine* engine, const QString& pattern, bool ign return result; } - RegExp *result = new (engine->memoryManager) RegExp(engine, pattern, ignoreCase, multiline); + RegExp *result = engine->memoryManager->alloc<RegExp>(engine, pattern, ignoreCase, multiline); if (!cache) cache = engine->regExpCache = new RegExpCache; - result->m_cache = cache; + result->d()->cache = cache; cache->insert(key, result); return result; } -RegExp::RegExp(ExecutionEngine* engine, const QString &pattern, bool ignoreCase, bool multiline) - : Managed(engine->regExpValueClass) - , m_pattern(pattern) - , m_cache(0) - , m_subPatternCount(0) - , m_ignoreCase(ignoreCase) - , m_multiLine(multiline) +RegExp::Data::Data(ExecutionEngine* engine, const QString &pattern, bool ignoreCase, bool multiline) + : Managed::Data(engine->regExpValueClass) + , pattern(pattern) + , ignoreCase(ignoreCase) + , multiLine(multiline) { - if (!engine) - return; + setVTable(staticVTable()); const char* error = 0; JSC::Yarr::YarrPattern yarrPattern(WTF::String(pattern), ignoreCase, multiline, &error); if (error) return; - m_subPatternCount = yarrPattern.m_numSubpatterns; - m_byteCode = JSC::Yarr::byteCompile(yarrPattern, engine->bumperPointerAllocator); + subPatternCount = yarrPattern.m_numSubpatterns; + byteCode = JSC::Yarr::byteCompile(yarrPattern, engine->bumperPointerAllocator); #if ENABLE(YARR_JIT) if (!yarrPattern.m_containsBackreferences && engine->iselFactory->jitCompileRegexps()) { JSC::JSGlobalData dummy(engine->regExpAllocator); - JSC::Yarr::jitCompile(yarrPattern, JSC::Yarr::Char16, &dummy, m_jitCode); + JSC::Yarr::jitCompile(yarrPattern, JSC::Yarr::Char16, &dummy, jitCode); } #endif } -RegExp::~RegExp() +RegExp::Data::~Data() { - if (m_cache) { + if (cache) { RegExpCacheKey key(this); - m_cache->remove(key); + cache->remove(key); } - _data = 0; } void RegExp::destroy(Managed *that) { - static_cast<RegExp*>(that)->~RegExp(); + static_cast<RegExp*>(that)->d()->~Data(); } void RegExp::markObjects(Managed *that, ExecutionEngine *e) diff --git a/src/qml/jsruntime/qv4regexp_p.h b/src/qml/jsruntime/qv4regexp_p.h index 1bcc2c6f5a..e1d3a9ef90 100644 --- a/src/qml/jsruntime/qv4regexp_p.h +++ b/src/qml/jsruntime/qv4regexp_p.h @@ -62,6 +62,50 @@ QT_BEGIN_NAMESPACE namespace QV4 { struct ExecutionEngine; +struct RegExpCacheKey; + +struct RegExp : public Managed +{ + struct Data : Managed::Data { + Data(ExecutionEngine* engine, const QString& pattern, bool ignoreCase, bool multiline); + ~Data(); + QString pattern; + OwnPtr<JSC::Yarr::BytecodePattern> byteCode; +#if ENABLE(YARR_JIT) + JSC::Yarr::YarrCodeBlock jitCode; +#endif + RegExpCache *cache; + int subPatternCount; + bool ignoreCase; + bool multiLine; + }; + V4_MANAGED(Managed) + Q_MANAGED_TYPE(RegExp) + + + QString pattern() const { return d()->pattern; } + OwnPtr<JSC::Yarr::BytecodePattern> &byteCode() { return d()->byteCode; } +#if ENABLE(YARR_JIT) + JSC::Yarr::YarrCodeBlock jitCode() const { return d()->jitCode; } +#endif + RegExpCache *cache() const { return d()->cache; } + int subPatternCount() const { return d()->subPatternCount; } + bool ignoreCase() const { return d()->ignoreCase; } + bool multiLine() const { return d()->multiLine; } + + static RegExp* create(ExecutionEngine* engine, const QString& pattern, bool ignoreCase = false, bool multiline = false); + + bool isValid() const { return d()->byteCode.get(); } + + uint match(const QString& string, int start, uint *matchOffsets); + + int captureCount() const { return subPatternCount() + 1; } + + static void destroy(Managed *that); + static void markObjects(Managed *that, QV4::ExecutionEngine *e); + + friend class RegExpCache; +}; struct RegExpCacheKey { @@ -70,7 +114,7 @@ struct RegExpCacheKey , ignoreCase(ignoreCase) , multiLine(multiLine) { } - explicit inline RegExpCacheKey(const RegExp *re); + explicit inline RegExpCacheKey(const RegExp::Data *re); bool operator==(const RegExpCacheKey &other) const { return pattern == other.pattern && ignoreCase == other.ignoreCase && multiLine == other.multiLine; } @@ -82,6 +126,12 @@ struct RegExpCacheKey uint multiLine : 1; }; +inline RegExpCacheKey::RegExpCacheKey(const RegExp::Data *re) + : pattern(re->pattern) + , ignoreCase(re->ignoreCase) + , multiLine(re->multiLine) +{} + inline uint qHash(const RegExpCacheKey& key, uint seed = 0) Q_DECL_NOTHROW { return qHash(key.pattern, seed); } @@ -91,49 +141,6 @@ public: ~RegExpCache(); }; -class RegExp : public Managed -{ - V4_MANAGED - Q_MANAGED_TYPE(RegExp) -public: - static RegExp* create(ExecutionEngine* engine, const QString& pattern, bool ignoreCase = false, bool multiline = false); - ~RegExp(); - - QString pattern() const { return m_pattern; } - - bool isValid() const { return m_byteCode.get(); } - - uint match(const QString& string, int start, uint *matchOffsets); - - bool ignoreCase() const { return m_ignoreCase; } - bool multiLine() const { return m_multiLine; } - int captureCount() const { return m_subPatternCount + 1; } - -protected: - static void destroy(Managed *that); - static void markObjects(Managed *that, QV4::ExecutionEngine *e); - -private: - friend class RegExpCache; - Q_DISABLE_COPY(RegExp); - RegExp(ExecutionEngine* engine, const QString& pattern, bool ignoreCase, bool multiline); - - const QString m_pattern; - OwnPtr<JSC::Yarr::BytecodePattern> m_byteCode; -#if ENABLE(YARR_JIT) - JSC::Yarr::YarrCodeBlock m_jitCode; -#endif - RegExpCache *m_cache; - int m_subPatternCount; - const bool m_ignoreCase; - const bool m_multiLine; -}; - -inline RegExpCacheKey::RegExpCacheKey(const RegExp *re) - : pattern(re->pattern()) - , ignoreCase(re->ignoreCase()) - , multiLine(re->multiLine()) -{} } diff --git a/src/qml/jsruntime/qv4regexpobject.cpp b/src/qml/jsruntime/qv4regexpobject.cpp index 956d1c594e..6a592ee792 100644 --- a/src/qml/jsruntime/qv4regexpobject.cpp +++ b/src/qml/jsruntime/qv4regexpobject.cpp @@ -70,32 +70,43 @@ Q_CORE_EXPORT QString qt_regexp_toCanonical(const QString &, QRegExp::PatternSyn using namespace QV4; DEFINE_OBJECT_VTABLE(RegExpObject); +DEFINE_OBJECT_VTABLE(RegExpPrototype); -RegExpObject::RegExpObject(InternalClass *ic) - : Object(ic) - , value(RegExp::create(ic->engine, QString(), false, false)) - , global(false) +RegExpObject::Data::Data(InternalClass *ic) + : Object::Data(ic) { - Q_ASSERT(internalClass->vtable == staticVTable()); - init(ic->engine); + setVTable(staticVTable()); + + Scope scope(ic->engine); + Scoped<RegExpObject> o(scope, this); + o->d()->value = reinterpret_cast<RegExp *>(RegExp::create(ic->engine, QString(), false, false)); + o->d()->global = false; + o->init(ic->engine); } -RegExpObject::RegExpObject(ExecutionEngine *engine, RegExpRef value, bool global) - : Object(engine->regExpClass) +RegExpObject::Data::Data(ExecutionEngine *engine, RegExp *value, bool global) + : Object::Data(engine->regExpClass) , value(value) , global(global) { - init(engine); + setVTable(staticVTable()); + + Scope scope(engine); + Scoped<RegExpObject> o(scope, this); + o->init(engine); } // Converts a QRegExp to a JS RegExp. // The conversion is not 100% exact since ECMA regexp and QRegExp // have different semantics/flags, but we try to do our best. -RegExpObject::RegExpObject(ExecutionEngine *engine, const QRegExp &re) - : Object(engine->regExpClass) - , value(0) - , global(false) +RegExpObject::Data::Data(ExecutionEngine *engine, const QRegExp &re) + : Object::Data(engine->regExpClass) { + setVTable(staticVTable()); + + value = 0; + global = false; + // Convert the pattern to a ECMAScript pattern. QString pattern = QT_PREPEND_NAMESPACE(qt_regexp_toCanonical)(re.pattern(), re.patternSyntax()); if (re.isMinimal()) { @@ -134,27 +145,25 @@ RegExpObject::RegExpObject(ExecutionEngine *engine, const QRegExp &re) } Scope scope(engine); - ScopedObject protectThis(scope, this); + Scoped<RegExpObject> o(scope, this); - value = RegExp::create(engine, pattern, re.caseSensitivity() == Qt::CaseInsensitive, false); + o->d()->value = reinterpret_cast<RegExp *>(RegExp::create(engine, pattern, re.caseSensitivity() == Qt::CaseInsensitive, false)); - init(engine); + o->init(engine); } void RegExpObject::init(ExecutionEngine *engine) { - setVTable(staticVTable()); - Scope scope(engine); ScopedObject protectThis(scope, this); ScopedString lastIndex(scope, engine->newIdentifier(QStringLiteral("lastIndex"))); ScopedValue v(scope, Primitive::fromInt32(0)); - insertMember(lastIndex, v, Attr_NotEnumerable|Attr_NotConfigurable); - if (!this->value) + insertMember(lastIndex.getPointer(), v, Attr_NotEnumerable|Attr_NotConfigurable); + if (!this->value()) return; - QString p = this->value->pattern(); + QString p = this->value()->pattern(); if (p.isEmpty()) { p = QStringLiteral("(?:)"); } else { @@ -163,29 +172,24 @@ void RegExpObject::init(ExecutionEngine *engine) } defineReadonlyProperty(QStringLiteral("source"), (v = engine->newString(p))); - defineReadonlyProperty(QStringLiteral("global"), Primitive::fromBoolean(global)); - defineReadonlyProperty(QStringLiteral("ignoreCase"), Primitive::fromBoolean(this->value->ignoreCase())); - defineReadonlyProperty(QStringLiteral("multiline"), Primitive::fromBoolean(this->value->multiLine())); + defineReadonlyProperty(QStringLiteral("global"), Primitive::fromBoolean(global())); + defineReadonlyProperty(QStringLiteral("ignoreCase"), Primitive::fromBoolean(this->value()->ignoreCase())); + defineReadonlyProperty(QStringLiteral("multiline"), Primitive::fromBoolean(this->value()->multiLine())); } -void RegExpObject::destroy(Managed *that) -{ - static_cast<RegExpObject *>(that)->~RegExpObject(); -} - void RegExpObject::markObjects(Managed *that, ExecutionEngine *e) { RegExpObject *re = static_cast<RegExpObject*>(that); - if (re->value) - re->value->mark(e); + if (re->value()) + re->value()->mark(e); Object::markObjects(that, e); } Property *RegExpObject::lastIndexProperty(ExecutionContext *ctx) { Q_UNUSED(ctx); - Q_ASSERT(0 == internalClass->find(ctx->engine->newIdentifier(QStringLiteral("lastIndex")))); + Q_ASSERT(0 == internalClass()->find(ctx->d()->engine->newIdentifier(QStringLiteral("lastIndex")))); return propertyAt(0); } @@ -194,19 +198,19 @@ Property *RegExpObject::lastIndexProperty(ExecutionContext *ctx) // have different semantics/flags, but we try to do our best. QRegExp RegExpObject::toQRegExp() const { - Qt::CaseSensitivity caseSensitivity = value->ignoreCase() ? Qt::CaseInsensitive : Qt::CaseSensitive; - return QRegExp(value->pattern(), caseSensitivity, QRegExp::RegExp2); + Qt::CaseSensitivity caseSensitivity = value()->ignoreCase() ? Qt::CaseInsensitive : Qt::CaseSensitive; + return QRegExp(value()->pattern(), caseSensitivity, QRegExp::RegExp2); } QString RegExpObject::toString() const { QString result = QLatin1Char('/') + source(); result += QLatin1Char('/'); - if (global) + if (global()) result += QLatin1Char('g'); - if (value->ignoreCase()) + if (value()->ignoreCase()) result += QLatin1Char('i'); - if (value->multiLine()) + if (value()->multiLine()) result += QLatin1Char('m'); return result; } @@ -215,35 +219,35 @@ QString RegExpObject::source() const { Scope scope(engine()); ScopedString source(scope, scope.engine->newIdentifier(QStringLiteral("source"))); - ScopedValue s(scope, const_cast<RegExpObject *>(this)->get(source)); + ScopedValue s(scope, const_cast<RegExpObject *>(this)->get(source.getPointer())); return s->toQString(); } uint RegExpObject::flags() const { uint f = 0; - if (global) + if (global()) f |= QV4::RegExpObject::RegExp_Global; - if (value->ignoreCase()) + if (value()->ignoreCase()) f |= QV4::RegExpObject::RegExp_IgnoreCase; - if (value->multiLine()) + if (value()->multiLine()) f |= QV4::RegExpObject::RegExp_Multiline; return f; } DEFINE_OBJECT_VTABLE(RegExpCtor); -RegExpCtor::RegExpCtor(ExecutionContext *scope) - : FunctionObject(scope, QStringLiteral("RegExp")) +RegExpCtor::Data::Data(ExecutionContext *scope) + : FunctionObject::Data(scope, QStringLiteral("RegExp")) { setVTable(staticVTable()); clearLastMatch(); } -void RegExpCtor::clearLastMatch() +void RegExpCtor::Data::clearLastMatch() { lastMatch = Primitive::nullValue(); - lastInput = engine()->id_empty; + lastInput = internalClass->engine->id_empty; lastMatchStart = 0; lastMatchEnd = 0; } @@ -260,8 +264,7 @@ ReturnedValue RegExpCtor::construct(Managed *m, CallData *callData) if (!f->isUndefined()) return ctx->throwTypeError(); - Scoped<RegExp> newRe(scope, re->value); - return Encode(ctx->engine->newRegExpObject(newRe, re->global)); + return Encode(ctx->d()->engine->newRegExpObject(re->value(), re->global())); } QString pattern; @@ -291,11 +294,11 @@ ReturnedValue RegExpCtor::construct(Managed *m, CallData *callData) } } - Scoped<RegExp> regexp(scope, RegExp::create(ctx->engine, pattern, ignoreCase, multiLine)); + RegExp *regexp = reinterpret_cast<RegExp *>(RegExp::create(ctx->d()->engine, pattern, ignoreCase, multiLine)); if (!regexp->isValid()) return ctx->throwSyntaxError(QStringLiteral("Invalid regular expression")); - return Encode(ctx->engine->newRegExpObject(regexp, global)); + return Encode(ctx->d()->engine->newRegExpObject(regexp, global)); } ReturnedValue RegExpCtor::call(Managed *that, CallData *callData) @@ -311,15 +314,16 @@ ReturnedValue RegExpCtor::call(Managed *that, CallData *callData) void RegExpCtor::markObjects(Managed *that, ExecutionEngine *e) { RegExpCtor *This = static_cast<RegExpCtor*>(that); - This->lastMatch.mark(e); - This->lastInput.mark(e); + This->lastMatch().mark(e); + This->lastInput().mark(e); FunctionObject::markObjects(that, e); } -void RegExpPrototype::init(ExecutionEngine *engine, ObjectRef ctor) +void RegExpPrototype::init(ExecutionEngine *engine, Object *constructor) { Scope scope(engine); ScopedObject o(scope); + ScopedObject ctor(scope, constructor); ctor->defineReadonlyProperty(engine->id_prototype, (o = this)); ctor->defineReadonlyProperty(engine->id_length, Primitive::fromInt32(2)); @@ -355,7 +359,7 @@ void RegExpPrototype::init(ExecutionEngine *engine, ObjectRef ctor) ReturnedValue RegExpPrototype::method_exec(CallContext *ctx) { Scope scope(ctx); - Scoped<RegExpObject> r(scope, ctx->callData->thisObject.as<RegExpObject>()); + Scoped<RegExpObject> r(scope, ctx->d()->callData->thisObject.as<RegExpObject>()); if (!r) return ctx->throwTypeError(); @@ -365,17 +369,17 @@ ReturnedValue RegExpPrototype::method_exec(CallContext *ctx) return Encode::undefined(); QString s = arg->stringValue()->toQString(); - int offset = r->global ? r->lastIndexProperty(ctx)->value.toInt32() : 0; + int offset = r->global() ? r->lastIndexProperty(ctx)->value.toInt32() : 0; if (offset < 0 || offset > s.length()) { r->lastIndexProperty(ctx)->value = Primitive::fromInt32(0); return Encode::null(); } - uint* matchOffsets = (uint*)alloca(r->value->captureCount() * 2 * sizeof(uint)); - const int result = r->value->match(s, offset, matchOffsets); + uint* matchOffsets = (uint*)alloca(r->value()->captureCount() * 2 * sizeof(uint)); + const int result = r->value()->match(s, offset, matchOffsets); - Scoped<RegExpCtor> regExpCtor(scope, ctx->engine->regExpCtor); - regExpCtor->clearLastMatch(); + Scoped<RegExpCtor> regExpCtor(scope, ctx->d()->engine->regExpCtor); + regExpCtor->d()->clearLastMatch(); if (result == -1) { r->lastIndexProperty(ctx)->value = Primitive::fromInt32(0); @@ -383,26 +387,27 @@ ReturnedValue RegExpPrototype::method_exec(CallContext *ctx) } // fill in result data - Scoped<ArrayObject> array(scope, ctx->engine->newArrayObject(ctx->engine->regExpExecArrayClass)); - int len = r->value->captureCount(); + Scoped<ArrayObject> array(scope, ctx->d()->engine->newArrayObject(ctx->d()->engine->regExpExecArrayClass)); + int len = r->value()->captureCount(); array->arrayReserve(len); ScopedValue v(scope); for (int i = 0; i < len; ++i) { int start = matchOffsets[i * 2]; int end = matchOffsets[i * 2 + 1]; - v = (start != -1 && end != -1) ? ctx->engine->newString(s.mid(start, end - start))->asReturnedValue() : Encode::undefined(); + v = (start != -1 && end != -1) ? ctx->d()->engine->newString(s.mid(start, end - start))->asReturnedValue() : Encode::undefined(); array->arrayPut(i, v); } array->setArrayLengthUnchecked(len); - array->memberData[Index_ArrayIndex] = Primitive::fromInt32(result); - array->memberData[Index_ArrayInput] = arg.asReturnedValue(); + array->memberData()[Index_ArrayIndex] = Primitive::fromInt32(result); + array->memberData()[Index_ArrayInput] = arg.asReturnedValue(); - regExpCtor->lastMatch = array; - regExpCtor->lastInput = arg->stringValue(); - regExpCtor->lastMatchStart = matchOffsets[0]; - regExpCtor->lastMatchEnd = matchOffsets[1]; + RegExpCtor::Data *dd = regExpCtor->d(); + dd->lastMatch = array; + dd->lastInput = arg->stringValue(); + dd->lastMatchStart = matchOffsets[0]; + dd->lastMatchEnd = matchOffsets[1]; - if (r->global) + if (r->global()) r->lastIndexProperty(ctx)->value = Primitive::fromInt32(matchOffsets[1]); return array.asReturnedValue(); @@ -418,27 +423,27 @@ ReturnedValue RegExpPrototype::method_test(CallContext *ctx) ReturnedValue RegExpPrototype::method_toString(CallContext *ctx) { Scope scope(ctx); - Scoped<RegExpObject> r(scope, ctx->callData->thisObject.as<RegExpObject>()); + Scoped<RegExpObject> r(scope, ctx->d()->callData->thisObject.as<RegExpObject>()); if (!r) return ctx->throwTypeError(); - return ctx->engine->newString(r->toString())->asReturnedValue(); + return ctx->d()->engine->newString(r->toString())->asReturnedValue(); } ReturnedValue RegExpPrototype::method_compile(CallContext *ctx) { Scope scope(ctx); - Scoped<RegExpObject> r(scope, ctx->callData->thisObject.as<RegExpObject>()); + Scoped<RegExpObject> r(scope, ctx->d()->callData->thisObject.as<RegExpObject>()); if (!r) return ctx->throwTypeError(); - ScopedCallData callData(scope, ctx->callData->argc); - memcpy(callData->args, ctx->callData->args, ctx->callData->argc*sizeof(Value)); + ScopedCallData callData(scope, ctx->d()->callData->argc); + memcpy(callData->args, ctx->d()->callData->args, ctx->d()->callData->argc*sizeof(Value)); - Scoped<RegExpObject> re(scope, ctx->engine->regExpCtor.asFunctionObject()->construct(callData)); + Scoped<RegExpObject> re(scope, ctx->d()->engine->regExpCtor.asFunctionObject()->construct(callData)); - r->value = re->value; - r->global = re->global; + r->d()->value = re->value(); + r->d()->global = re->global(); return Encode::undefined(); } @@ -446,42 +451,42 @@ template <int index> ReturnedValue RegExpPrototype::method_get_lastMatch_n(CallContext *ctx) { Scope scope(ctx); - ScopedArrayObject lastMatch(scope, static_cast<RegExpCtor*>(ctx->engine->regExpCtor.objectValue())->lastMatch); + ScopedArrayObject lastMatch(scope, static_cast<RegExpCtor*>(ctx->d()->engine->regExpCtor.objectValue())->lastMatch()); ScopedValue result(scope, lastMatch ? lastMatch->getIndexed(index) : Encode::undefined()); if (result->isUndefined()) - return ctx->engine->newString(QString())->asReturnedValue(); + return ctx->d()->engine->newString(QString())->asReturnedValue(); return result.asReturnedValue(); } ReturnedValue RegExpPrototype::method_get_lastParen(CallContext *ctx) { Scope scope(ctx); - ScopedArrayObject lastMatch(scope, static_cast<RegExpCtor*>(ctx->engine->regExpCtor.objectValue())->lastMatch); + ScopedArrayObject lastMatch(scope, static_cast<RegExpCtor*>(ctx->d()->engine->regExpCtor.objectValue())->lastMatch()); ScopedValue result(scope, lastMatch ? lastMatch->getIndexed(lastMatch->getLength() - 1) : Encode::undefined()); if (result->isUndefined()) - return ctx->engine->newString(QString())->asReturnedValue(); + return ctx->d()->engine->newString(QString())->asReturnedValue(); return result.asReturnedValue(); } ReturnedValue RegExpPrototype::method_get_input(CallContext *ctx) { - return static_cast<RegExpCtor*>(ctx->engine->regExpCtor.objectValue())->lastInput.asReturnedValue(); + return static_cast<RegExpCtor*>(ctx->d()->engine->regExpCtor.objectValue())->lastInput().asReturnedValue(); } ReturnedValue RegExpPrototype::method_get_leftContext(CallContext *ctx) { Scope scope(ctx); - Scoped<RegExpCtor> regExpCtor(scope, ctx->engine->regExpCtor); - QString lastInput = regExpCtor->lastInput->toQString(); - return ctx->engine->newString(lastInput.left(regExpCtor->lastMatchStart))->asReturnedValue(); + Scoped<RegExpCtor> regExpCtor(scope, ctx->d()->engine->regExpCtor); + QString lastInput = regExpCtor->lastInput()->toQString(); + return ctx->d()->engine->newString(lastInput.left(regExpCtor->lastMatchStart()))->asReturnedValue(); } ReturnedValue RegExpPrototype::method_get_rightContext(CallContext *ctx) { Scope scope(ctx); - Scoped<RegExpCtor> regExpCtor(scope, ctx->engine->regExpCtor); - QString lastInput = regExpCtor->lastInput->toQString(); - return ctx->engine->newString(lastInput.mid(regExpCtor->lastMatchEnd))->asReturnedValue(); + Scoped<RegExpCtor> regExpCtor(scope, ctx->d()->engine->regExpCtor); + QString lastInput = regExpCtor->lastInput()->toQString(); + return ctx->d()->engine->newString(lastInput.mid(regExpCtor->lastMatchEnd()))->asReturnedValue(); } QT_END_NAMESPACE diff --git a/src/qml/jsruntime/qv4regexpobject_p.h b/src/qml/jsruntime/qv4regexpobject_p.h index 1b408749d3..ac07707b2f 100644 --- a/src/qml/jsruntime/qv4regexpobject_p.h +++ b/src/qml/jsruntime/qv4regexpobject_p.h @@ -63,11 +63,18 @@ QT_BEGIN_NAMESPACE namespace QV4 { -class RegExp; - struct RegExpObject: Object { - V4_OBJECT + struct Data : Object::Data { + Data(ExecutionEngine *engine, RegExp *value, bool global); + Data(ExecutionEngine *engine, const QRegExp &re); + Data(InternalClass *ic); + + RegExp *value; + bool global; + }; + V4_OBJECT(Object) Q_MANAGED_TYPE(RegExpObject) + // needs to be compatible with the flags in qv4jsir_p.h enum Flags { RegExp_Global = 0x01, @@ -80,39 +87,37 @@ struct RegExpObject: Object { Index_ArrayInput = Index_ArrayIndex + 1 }; - RegExp* value; - Property *lastIndexProperty(ExecutionContext *ctx); - bool global; - - RegExpObject(ExecutionEngine *engine, RegExpRef value, bool global); - RegExpObject(ExecutionEngine *engine, const QRegExp &re); - ~RegExpObject() {} + RegExp *value() const { return d()->value; } + bool global() const { return d()->global; } void init(ExecutionEngine *engine); + Property *lastIndexProperty(ExecutionContext *ctx); QRegExp toQRegExp() const; QString toString() const; QString source() const; uint flags() const; protected: - RegExpObject(InternalClass *ic); - static void destroy(Managed *that); static void markObjects(Managed *that, ExecutionEngine *e); }; -DEFINE_REF(RegExp, Object); - struct RegExpCtor: FunctionObject { - V4_OBJECT - RegExpCtor(ExecutionContext *scope); + struct Data : FunctionObject::Data { + Data(ExecutionContext *scope); + Value lastMatch; + StringValue lastInput; + int lastMatchStart; + int lastMatchEnd; + void clearLastMatch(); + }; + V4_OBJECT(FunctionObject) - Value lastMatch; - StringValue lastInput; - int lastMatchStart; - int lastMatchEnd; - void clearLastMatch(); + Value lastMatch() { return d()->lastMatch; } + StringValue lastInput() { return d()->lastInput; } + int lastMatchStart() { return d()->lastMatchStart; } + int lastMatchEnd() { return d()->lastMatchEnd; } static ReturnedValue construct(Managed *m, CallData *callData); static ReturnedValue call(Managed *that, CallData *callData); @@ -121,8 +126,16 @@ struct RegExpCtor: FunctionObject struct RegExpPrototype: RegExpObject { - RegExpPrototype(InternalClass *ic): RegExpObject(ic) {} - void init(ExecutionEngine *engine, ObjectRef ctor); + struct Data : RegExpObject::Data + { + Data(InternalClass *ic): RegExpObject::Data(ic) + { + setVTable(staticVTable()); + } + }; + V4_OBJECT(RegExpObject) + + void init(ExecutionEngine *engine, Object *ctor); static ReturnedValue method_exec(CallContext *ctx); static ReturnedValue method_test(CallContext *ctx); diff --git a/src/qml/jsruntime/qv4runtime.cpp b/src/qml/jsruntime/qv4runtime.cpp index e44d1a07a6..7ea8dbd0aa 100644 --- a/src/qml/jsruntime/qv4runtime.cpp +++ b/src/qml/jsruntime/qv4runtime.cpp @@ -265,10 +265,9 @@ void RuntimeHelpers::numberToString(QString *result, double num, int radix) ReturnedValue Runtime::closure(ExecutionContext *ctx, int functionId) { - QV4::Function *clos = ctx->compilationUnit->runtimeFunctions[functionId]; + QV4::Function *clos = ctx->d()->compilationUnit->runtimeFunctions[functionId]; Q_ASSERT(clos); - FunctionObject *f = FunctionObject::createScriptFunction(ctx, clos); - return f->asReturnedValue(); + return FunctionObject::createScriptFunction(ctx, clos)->asReturnedValue(); } ReturnedValue Runtime::deleteElement(ExecutionContext *ctx, const ValueRef base, const ValueRef index) @@ -283,10 +282,10 @@ ReturnedValue Runtime::deleteElement(ExecutionContext *ctx, const ValueRef base, } ScopedString name(scope, index->toString(ctx)); - return Runtime::deleteMember(ctx, base, name); + return Runtime::deleteMember(ctx, base, name.getPointer()); } -ReturnedValue Runtime::deleteMember(ExecutionContext *ctx, const ValueRef base, const StringRef name) +ReturnedValue Runtime::deleteMember(ExecutionContext *ctx, const ValueRef base, String *name) { Scope scope(ctx); ScopedObject obj(scope, base->toObject(ctx)); @@ -295,7 +294,7 @@ ReturnedValue Runtime::deleteMember(ExecutionContext *ctx, const ValueRef base, return Encode(obj->deleteProperty(name)); } -ReturnedValue Runtime::deleteName(ExecutionContext *ctx, const StringRef name) +ReturnedValue Runtime::deleteName(ExecutionContext *ctx, String *name) { Scope scope(ctx); return Encode(ctx->deleteProperty(name)); @@ -310,8 +309,8 @@ QV4::ReturnedValue Runtime::instanceof(ExecutionContext *ctx, const ValueRef lef if (!f) return ctx->throwTypeError(); - if (f->subtype == FunctionObject::BoundFunction) - f = static_cast<BoundFunction *>(f)->target; + if (f->subtype() == FunctionObject::BoundFunction) + f = static_cast<BoundFunction *>(f)->target(); Object *v = left->asObject(); if (!v) @@ -341,7 +340,7 @@ QV4::ReturnedValue Runtime::in(ExecutionContext *ctx, const ValueRef left, const ScopedString s(scope, left->toString(ctx)); if (scope.hasException()) return Encode::undefined(); - bool r = right->objectValue()->hasProperty(s); + bool r = right->objectValue()->hasProperty(s.getPointer()); return Encode(r); } @@ -370,7 +369,7 @@ Returned<String> *RuntimeHelpers::stringFromNumber(ExecutionContext *ctx, double { QString qstr; RuntimeHelpers::numberToString(&qstr, number, 10); - return ctx->engine->newString(qstr); + return ctx->engine()->newString(qstr); } ReturnedValue RuntimeHelpers::objectDefaultValue(Object *object, int typeHint) @@ -382,7 +381,7 @@ ReturnedValue RuntimeHelpers::objectDefaultValue(Object *object, int typeHint) typeHint = NUMBER_HINT; } - ExecutionEngine *engine = object->internalClass->engine; + ExecutionEngine *engine = object->internalClass()->engine; if (engine->hasException) return Encode::undefined(); @@ -428,13 +427,13 @@ Returned<Object> *RuntimeHelpers::convertToObject(ExecutionContext *ctx, const V ctx->throwTypeError(); return 0; case Value::Boolean_Type: - return ctx->engine->newBooleanObject(value); + return ctx->engine()->newBooleanObject(value); case Value::Managed_Type: Q_ASSERT(value->isString()); - return ctx->engine->newStringObject(value); + return ctx->engine()->newStringObject(value); case Value::Integer_Type: default: // double - return ctx->engine->newNumberObject(value); + return ctx->engine()->newNumberObject(value); } } @@ -444,14 +443,14 @@ Returned<String> *RuntimeHelpers::convertToString(ExecutionContext *ctx, const V case Value::Empty_Type: Q_ASSERT(!"empty Value encountered"); case Value::Undefined_Type: - return ctx->engine->id_undefined.ret(); + return ctx->engine()->id_undefined.ret(); case Value::Null_Type: - return ctx->engine->id_null.ret(); + return ctx->engine()->id_null.ret(); case Value::Boolean_Type: if (value->booleanValue()) - return ctx->engine->id_true.ret(); + return ctx->engine()->id_true.ret(); else - return ctx->engine->id_false.ret(); + return ctx->engine()->id_false.ret(); case Value::Managed_Type: if (value->isString()) return value->stringValue()->asReturned<String>(); @@ -475,14 +474,14 @@ static Returned<String> *convert_to_string_add(ExecutionContext *ctx, const Valu case Value::Empty_Type: Q_ASSERT(!"empty Value encountered"); case Value::Undefined_Type: - return ctx->engine->id_undefined.ret(); + return ctx->engine()->id_undefined.ret(); case Value::Null_Type: - return ctx->engine->id_null.ret(); + return ctx->engine()->id_null.ret(); case Value::Boolean_Type: if (value->booleanValue()) - return ctx->engine->id_true.ret(); + return ctx->engine()->id_true.ret(); else - return ctx->engine->id_false.ret(); + return ctx->engine()->id_false.ret(); case Value::Managed_Type: if (value->isString()) return value->stringValue()->asReturned<String>(); @@ -511,11 +510,11 @@ QV4::ReturnedValue RuntimeHelpers::addHelper(ExecutionContext *ctx, const ValueR pright = convert_to_string_add(ctx, pright); if (scope.engine->hasException) return Encode::undefined(); - if (!pleft->stringValue()->length()) + if (!pleft->stringValue()->d()->length()) return pright->asReturnedValue(); - if (!pright->stringValue()->length()) + if (!pright->stringValue()->d()->length()) return pleft->asReturnedValue(); - return (new (ctx->engine->memoryManager) String(ctx->engine, pleft->stringValue(), pright->stringValue()))->asReturnedValue(); + return (ctx->engine()->memoryManager->alloc<String>(ctx->d()->engine, pleft->stringValue(), pright->stringValue()))->asReturnedValue(); } double x = RuntimeHelpers::toNumber(pleft); double y = RuntimeHelpers::toNumber(pright); @@ -527,11 +526,11 @@ QV4::ReturnedValue Runtime::addString(QV4::ExecutionContext *ctx, const QV4::Val Q_ASSERT(left->isString() || right->isString()); if (left->isString() && right->isString()) { - if (!left->stringValue()->length()) + if (!left->stringValue()->d()->length()) return right->asReturnedValue(); - if (!right->stringValue()->length()) + if (!right->stringValue()->d()->length()) return left->asReturnedValue(); - return (new (ctx->engine->memoryManager) String(ctx->engine, left->stringValue(), right->stringValue()))->asReturnedValue(); + return (ctx->engine()->memoryManager->alloc<String>(ctx->d()->engine, left->stringValue(), right->stringValue()))->asReturnedValue(); } Scope scope(ctx); @@ -544,14 +543,14 @@ QV4::ReturnedValue Runtime::addString(QV4::ExecutionContext *ctx, const QV4::Val pright = convert_to_string_add(ctx, right); if (scope.engine->hasException) return Encode::undefined(); - if (!pleft->stringValue()->length()) + if (!pleft->stringValue()->d()->length()) return pright->asReturnedValue(); - if (!pright->stringValue()->length()) + if (!pright->stringValue()->d()->length()) return pleft->asReturnedValue(); - return (new (ctx->engine->memoryManager) String(ctx->engine, pleft->stringValue(), pright->stringValue()))->asReturnedValue(); + return (ctx->engine()->memoryManager->alloc<String>(ctx->d()->engine, pleft->stringValue(), pright->stringValue()))->asReturnedValue(); } -void Runtime::setProperty(ExecutionContext *ctx, const ValueRef object, const StringRef name, const ValueRef value) +void Runtime::setProperty(ExecutionContext *ctx, const ValueRef object, String *name, const ValueRef value) { Scope scope(ctx); ScopedObject o(scope, object->toObject(ctx)); @@ -588,8 +587,8 @@ ReturnedValue Runtime::getElement(ExecutionContext *ctx, const ValueRef object, } if (idx < UINT_MAX) { - if (!o->arrayData->hasAttributes()) { - ScopedValue v(scope, o->arrayData->get(idx)); + if (!o->arrayData()->hasAttributes()) { + ScopedValue v(scope, o->arrayData()->get(idx)); if (!v->isEmpty()) return v->asReturnedValue(); } @@ -600,7 +599,7 @@ ReturnedValue Runtime::getElement(ExecutionContext *ctx, const ValueRef object, ScopedString name(scope, index->toString(ctx)); if (scope.hasException()) return Encode::undefined(); - return o->get(name); + return o->get(name.getPointer()); } void Runtime::setElement(ExecutionContext *ctx, const ValueRef object, const ValueRef index, const ValueRef value) @@ -613,9 +612,9 @@ void Runtime::setElement(ExecutionContext *ctx, const ValueRef object, const Val uint idx = index->asArrayIndex(); if (idx < UINT_MAX) { if (o->arrayType() == ArrayData::Simple) { - SimpleArrayData *s = static_cast<SimpleArrayData *>(o->arrayData); - if (s && idx < s->len && !s->data[idx].isEmpty()) { - s->data[idx] = value; + SimpleArrayData *s = static_cast<SimpleArrayData *>(o->arrayData()); + if (s && idx < s->len() && !s->arrayData()[idx].isEmpty()) { + s->arrayData()[idx] = value; return; } } @@ -624,7 +623,7 @@ void Runtime::setElement(ExecutionContext *ctx, const ValueRef object, const Val } ScopedString name(scope, index->toString(ctx)); - o->put(name, value); + o->put(name.getPointer(), value); } ReturnedValue Runtime::foreachIterator(ExecutionContext *ctx, const ValueRef in) @@ -633,7 +632,7 @@ ReturnedValue Runtime::foreachIterator(ExecutionContext *ctx, const ValueRef in) Scoped<Object> o(scope, (Object *)0); if (!in->isNullOrUndefined()) o = in->toObject(ctx); - Scoped<Object> it(scope, ctx->engine->newForEachIteratorObject(ctx, o)); + Scoped<Object> it(scope, ctx->engine()->newForEachIteratorObject(ctx, o)); return it.asReturnedValue(); } @@ -648,12 +647,12 @@ ReturnedValue Runtime::foreachNextPropertyName(const ValueRef foreach_iterator) } -void Runtime::setActivationProperty(ExecutionContext *ctx, const StringRef name, const ValueRef value) +void Runtime::setActivationProperty(ExecutionContext *ctx, String *name, const ValueRef value) { ctx->setProperty(name, value); } -ReturnedValue Runtime::getProperty(ExecutionContext *ctx, const ValueRef object, const StringRef name) +ReturnedValue Runtime::getProperty(ExecutionContext *ctx, const ValueRef object, String *name) { Scope scope(ctx); @@ -672,7 +671,7 @@ ReturnedValue Runtime::getProperty(ExecutionContext *ctx, const ValueRef object, return o->get(name); } -ReturnedValue Runtime::getActivationProperty(ExecutionContext *ctx, const StringRef name) +ReturnedValue Runtime::getActivationProperty(ExecutionContext *ctx, String *name) { return ctx->getProperty(name); } @@ -866,31 +865,31 @@ QV4::Bool Runtime::compareLessEqual(const QV4::ValueRef l, const QV4::ValueRef r } #ifndef V4_BOOTSTRAP -ReturnedValue Runtime::callGlobalLookup(ExecutionContext *context, uint index, CallDataRef callData) +ReturnedValue Runtime::callGlobalLookup(ExecutionContext *context, uint index, CallData *callData) { Scope scope(context); Q_ASSERT(callData->thisObject.isUndefined()); - Lookup *l = context->lookups + index; + Lookup *l = context->d()->lookups + index; Scoped<FunctionObject> o(scope, l->globalGetter(l, context)); if (!o) return context->throwTypeError(); - if (o.getPointer() == context->engine->evalFunction && l->name->equals(context->engine->id_eval)) + if (o.getPointer() == scope.engine->evalFunction && l->name->equals(scope.engine->id_eval)) return static_cast<EvalFunction *>(o.getPointer())->evalCall(callData, true); return o->call(callData); } -ReturnedValue Runtime::callActivationProperty(ExecutionContext *context, const StringRef name, CallDataRef callData) +ReturnedValue Runtime::callActivationProperty(ExecutionContext *context, String *name, CallData *callData) { Q_ASSERT(callData->thisObject.isUndefined()); Scope scope(context); ScopedObject base(scope); - ScopedValue func(scope, context->getPropertyAndBase(name, base)); - if (context->engine->hasException) + ScopedValue func(scope, context->getPropertyAndBase(name, base.ptr->o)); + if (scope.engine->hasException) return Encode::undefined(); if (base) @@ -905,14 +904,14 @@ ReturnedValue Runtime::callActivationProperty(ExecutionContext *context, const S return context->throwTypeError(msg); } - if (o == context->engine->evalFunction && name->equals(context->engine->id_eval)) { + if (o == scope.engine->evalFunction && name->equals(scope.engine->id_eval)) { return static_cast<EvalFunction *>(o)->evalCall(callData, true); } return o->call(callData); } -ReturnedValue Runtime::callProperty(ExecutionContext *context, const StringRef name, CallDataRef callData) +ReturnedValue Runtime::callProperty(ExecutionContext *context, String *name, CallData *callData) { Scope scope(context); Scoped<Object> baseObject(scope, callData->thisObject); @@ -938,9 +937,9 @@ ReturnedValue Runtime::callProperty(ExecutionContext *context, const StringRef n return o->call(callData); } -ReturnedValue Runtime::callPropertyLookup(ExecutionContext *context, uint index, CallDataRef callData) +ReturnedValue Runtime::callPropertyLookup(ExecutionContext *context, uint index, CallData *callData) { - Lookup *l = context->lookups + index; + Lookup *l = context->d()->lookups + index; Value v; v = l->getter(l, callData->thisObject); if (!v.isObject()) @@ -949,7 +948,7 @@ ReturnedValue Runtime::callPropertyLookup(ExecutionContext *context, uint index, return v.objectValue()->call(callData); } -ReturnedValue Runtime::callElement(ExecutionContext *context, const ValueRef index, CallDataRef callData) +ReturnedValue Runtime::callElement(ExecutionContext *context, const ValueRef index, CallData *callData) { Scope scope(context); ScopedObject baseObject(scope, callData->thisObject.toObject(context)); @@ -959,14 +958,14 @@ ReturnedValue Runtime::callElement(ExecutionContext *context, const ValueRef ind return Encode::undefined(); callData->thisObject = baseObject; - ScopedObject o(scope, baseObject->get(s)); + ScopedObject o(scope, baseObject->get(s.getPointer())); if (!o) return context->throwTypeError(); return o->call(callData); } -ReturnedValue Runtime::callValue(ExecutionContext *context, const ValueRef func, CallDataRef callData) +ReturnedValue Runtime::callValue(ExecutionContext *context, const ValueRef func, CallData *callData) { if (!func->isObject()) return context->throwTypeError(); @@ -975,12 +974,12 @@ ReturnedValue Runtime::callValue(ExecutionContext *context, const ValueRef func, } -ReturnedValue Runtime::constructGlobalLookup(ExecutionContext *context, uint index, CallDataRef callData) +ReturnedValue Runtime::constructGlobalLookup(ExecutionContext *context, uint index, CallData *callData) { Scope scope(context); Q_ASSERT(callData->thisObject.isUndefined()); - Lookup *l = context->lookups + index; + Lookup *l = context->d()->lookups + index; Scoped<Object> f(scope, l->globalGetter(l, context)); if (!f) return context->throwTypeError(); @@ -989,11 +988,11 @@ ReturnedValue Runtime::constructGlobalLookup(ExecutionContext *context, uint ind } -ReturnedValue Runtime::constructActivationProperty(ExecutionContext *context, const StringRef name, CallDataRef callData) +ReturnedValue Runtime::constructActivationProperty(ExecutionContext *context, String *name, CallData *callData) { Scope scope(context); ScopedValue func(scope, context->getProperty(name)); - if (context->engine->hasException) + if (scope.engine->hasException) return Encode::undefined(); Object *f = func->asObject(); @@ -1003,7 +1002,7 @@ ReturnedValue Runtime::constructActivationProperty(ExecutionContext *context, co return f->construct(callData); } -ReturnedValue Runtime::constructValue(ExecutionContext *context, const ValueRef func, CallDataRef callData) +ReturnedValue Runtime::constructValue(ExecutionContext *context, const ValueRef func, CallData *callData) { Object *f = func->asObject(); if (!f) @@ -1012,7 +1011,7 @@ ReturnedValue Runtime::constructValue(ExecutionContext *context, const ValueRef return f->construct(callData); } -ReturnedValue Runtime::constructProperty(ExecutionContext *context, const StringRef name, CallDataRef callData) +ReturnedValue Runtime::constructProperty(ExecutionContext *context, String *name, CallData *callData) { Scope scope(context); ScopedObject thisObject(scope, callData->thisObject.toObject(context)); @@ -1026,9 +1025,9 @@ ReturnedValue Runtime::constructProperty(ExecutionContext *context, const String return f->construct(callData); } -ReturnedValue Runtime::constructPropertyLookup(ExecutionContext *context, uint index, CallDataRef callData) +ReturnedValue Runtime::constructPropertyLookup(ExecutionContext *context, uint index, CallData *callData) { - Lookup *l = context->lookups + index; + Lookup *l = context->d()->lookups + index; Value v; v = l->getter(l, callData->thisObject); if (!v.isObject()) @@ -1050,39 +1049,39 @@ ReturnedValue Runtime::typeofValue(ExecutionContext *ctx, const ValueRef value) ScopedString res(scope); switch (value->type()) { case Value::Undefined_Type: - res = ctx->engine->id_undefined; + res = ctx->engine()->id_undefined; break; case Value::Null_Type: - res = ctx->engine->id_object; + res = ctx->engine()->id_object; break; case Value::Boolean_Type: - res = ctx->engine->id_boolean; + res = ctx->engine()->id_boolean; break; case Value::Managed_Type: if (value->isString()) - res = ctx->engine->id_string; + res = ctx->engine()->id_string; else if (value->objectValue()->asFunctionObject()) - res = ctx->engine->id_function; + res = ctx->engine()->id_function; else - res = ctx->engine->id_object; // ### implementation-defined + res = ctx->engine()->id_object; // ### implementation-defined break; default: - res = ctx->engine->id_number; + res = ctx->engine()->id_number; break; } return res.asReturnedValue(); } -QV4::ReturnedValue Runtime::typeofName(ExecutionContext *context, const StringRef name) +QV4::ReturnedValue Runtime::typeofName(ExecutionContext *context, String *name) { Scope scope(context); ScopedValue prop(scope, context->getProperty(name)); // typeof doesn't throw. clear any possible exception - context->engine->hasException = false; + scope.engine->hasException = false; return Runtime::typeofValue(context, prop); } -QV4::ReturnedValue Runtime::typeofMember(ExecutionContext *context, const ValueRef base, const StringRef name) +QV4::ReturnedValue Runtime::typeofMember(ExecutionContext *context, const ValueRef base, String *name) { Scope scope(context); ScopedObject obj(scope, base->toObject(context)); @@ -1099,7 +1098,7 @@ QV4::ReturnedValue Runtime::typeofElement(ExecutionContext *context, const Value ScopedObject obj(scope, base->toObject(context)); if (scope.engine->hasException) return Encode::undefined(); - ScopedValue prop(scope, obj->get(name)); + ScopedValue prop(scope, obj->get(name.getPointer())); return Runtime::typeofValue(context, prop); } @@ -1107,29 +1106,29 @@ ExecutionContext *Runtime::pushWithScope(const ValueRef o, ExecutionContext *ctx { Scope scope(ctx); ScopedObject obj(scope, o->toObject(ctx)); - return ctx->newWithContext(obj); + return reinterpret_cast<ExecutionContext *>(ctx->newWithContext(obj)); } ReturnedValue Runtime::unwindException(ExecutionContext *ctx) { - if (!ctx->engine->hasException) + if (!ctx->engine()->hasException) return Primitive::emptyValue().asReturnedValue(); - return ctx->engine->catchException(ctx, 0); + return ctx->engine()->catchException(ctx, 0); } -ExecutionContext *Runtime::pushCatchScope(ExecutionContext *ctx, const StringRef exceptionVarName) +ExecutionContext *Runtime::pushCatchScope(ExecutionContext *ctx, String *exceptionVarName) { Scope scope(ctx); - ScopedValue v(scope, ctx->engine->catchException(ctx, 0)); - return ctx->newCatchContext(exceptionVarName, v); + ScopedValue v(scope, ctx->engine()->catchException(ctx, 0)); + return reinterpret_cast<ExecutionContext *>(ctx->newCatchContext(exceptionVarName, v)); } ExecutionContext *Runtime::popScope(ExecutionContext *ctx) { - return ctx->engine->popContext(); + return ctx->engine()->popContext(); } -void Runtime::declareVar(ExecutionContext *ctx, bool deletable, const StringRef name) +void Runtime::declareVar(ExecutionContext *ctx, bool deletable, String *name) { ctx->createMutableBinding(name, deletable); } @@ -1137,7 +1136,7 @@ void Runtime::declareVar(ExecutionContext *ctx, bool deletable, const StringRef ReturnedValue Runtime::arrayLiteral(ExecutionContext *ctx, Value *values, uint length) { Scope scope(ctx); - Scoped<ArrayObject> a(scope, ctx->engine->newArrayObject()); + Scoped<ArrayObject> a(scope, ctx->engine()->newArrayObject()); if (length) { a->arrayReserve(length); @@ -1150,8 +1149,8 @@ ReturnedValue Runtime::arrayLiteral(ExecutionContext *ctx, Value *values, uint l ReturnedValue Runtime::objectLiteral(QV4::ExecutionContext *ctx, const QV4::Value *args, int classId, int arrayValueCount, int arrayGetterSetterCountAndFlags) { Scope scope(ctx); - QV4::InternalClass *klass = ctx->compilationUnit->runtimeClasses[classId]; - Scoped<Object> o(scope, ctx->engine->newObject(klass)); + QV4::InternalClass *klass = ctx->d()->compilationUnit->runtimeClasses[classId]; + Scoped<Object> o(scope, ctx->engine()->newObject(klass)); { bool needSparseArray = arrayGetterSetterCountAndFlags >> 30; @@ -1160,26 +1159,30 @@ ReturnedValue Runtime::objectLiteral(QV4::ExecutionContext *ctx, const QV4::Valu } for (uint i = 0; i < klass->size; ++i) - o->memberData[i] = *args++; - - ScopedValue entry(scope); - for (int i = 0; i < arrayValueCount; ++i) { - uint idx = args->toUInt32(); - ++args; - entry = *args++; - o->arraySet(idx, entry); + o->memberData()[i] = *args++; + + if (arrayValueCount > 0) { + ScopedValue entry(scope); + for (int i = 0; i < arrayValueCount; ++i) { + uint idx = args->toUInt32(); + ++args; + entry = *args++; + o->arraySet(idx, entry); + } } - ScopedProperty pd(scope); uint arrayGetterSetterCount = arrayGetterSetterCountAndFlags & ((1 << 30) - 1); - for (uint i = 0; i < arrayGetterSetterCount; ++i) { - uint idx = args->toUInt32(); - ++args; - pd->value = *args; - ++args; - pd->set = *args; - ++args; - o->arraySet(idx, pd, Attr_Accessor); + if (arrayGetterSetterCount > 0) { + ScopedProperty pd(scope); + for (uint i = 0; i < arrayGetterSetterCount; ++i) { + uint idx = args->toUInt32(); + ++args; + pd->value = *args; + ++args; + pd->set = *args; + ++args; + o->arraySet(idx, pd, Attr_Accessor); + } } return o.asReturnedValue(); @@ -1187,9 +1190,9 @@ ReturnedValue Runtime::objectLiteral(QV4::ExecutionContext *ctx, const QV4::Valu QV4::ReturnedValue Runtime::setupArgumentsObject(ExecutionContext *ctx) { - assert(ctx->type >= ExecutionContext::Type_CallContext); + Q_ASSERT(ctx->d()->type >= ExecutionContext::Type_CallContext); CallContext *c = static_cast<CallContext *>(ctx); - return (new (c->engine->memoryManager) ArgumentsObject(c))->asReturnedValue(); + return (c->engine()->memoryManager->alloc<ArgumentsObject>(c))->asReturnedValue(); } #endif // V4_BOOTSTRAP @@ -1275,27 +1278,27 @@ unsigned Runtime::doubleToUInt(const double &d) ReturnedValue Runtime::regexpLiteral(ExecutionContext *ctx, int id) { - return ctx->compilationUnit->runtimeRegularExpressions[id].asReturnedValue(); + return ctx->d()->compilationUnit->runtimeRegularExpressions[id].asReturnedValue(); } ReturnedValue Runtime::getQmlIdArray(NoThrowContext *ctx) { - return ctx->engine->qmlContextObject()->getPointer()->as<QmlContextWrapper>()->idObjectsArray(); + return ctx->engine()->qmlContextObject()->getPointer()->as<QmlContextWrapper>()->idObjectsArray(); } ReturnedValue Runtime::getQmlContextObject(NoThrowContext *ctx) { - QQmlContextData *context = QmlContextWrapper::callingContext(ctx->engine); + QQmlContextData *context = QmlContextWrapper::callingContext(ctx->engine()); if (!context) return Encode::undefined(); - return QObjectWrapper::wrap(ctx->engine, context->contextObject); + return QObjectWrapper::wrap(ctx->d()->engine, context->contextObject); } ReturnedValue Runtime::getQmlScopeObject(NoThrowContext *ctx) { Scope scope(ctx); - QV4::Scoped<QmlContextWrapper> c(scope, ctx->engine->qmlContextObject()->getPointer()->as<QmlContextWrapper>()); - return QObjectWrapper::wrap(ctx->engine, c->getScopeObject()); + QV4::Scoped<QmlContextWrapper> c(scope, ctx->engine()->qmlContextObject()->getPointer()->as<QmlContextWrapper>()); + return QObjectWrapper::wrap(ctx->d()->engine, c->getScopeObject()); } ReturnedValue Runtime::getQmlQObjectProperty(ExecutionContext *ctx, const ValueRef object, int propertyIndex, bool captureRequired) @@ -1312,11 +1315,11 @@ ReturnedValue Runtime::getQmlQObjectProperty(ExecutionContext *ctx, const ValueR QV4::ReturnedValue Runtime::getQmlAttachedProperty(ExecutionContext *ctx, int attachedPropertiesId, int propertyIndex) { Scope scope(ctx); - QV4::Scoped<QmlContextWrapper> c(scope, ctx->engine->qmlContextObject()->getPointer()->as<QmlContextWrapper>()); + QV4::Scoped<QmlContextWrapper> c(scope, ctx->engine()->qmlContextObject()->getPointer()->as<QmlContextWrapper>()); QObject *scopeObject = c->getScopeObject(); QObject *attachedObject = qmlAttachedPropertiesObjectById(attachedPropertiesId, scopeObject); - QQmlEngine *qmlEngine = ctx->engine->v8Engine->engine(); + QQmlEngine *qmlEngine = ctx->engine()->v8Engine->engine(); QQmlData::ensurePropertyCache(qmlEngine, attachedObject); return QV4::QObjectWrapper::getProperty(attachedObject, ctx, propertyIndex, /*captureRequired*/true); } @@ -1334,24 +1337,24 @@ void Runtime::setQmlQObjectProperty(ExecutionContext *ctx, const ValueRef object ReturnedValue Runtime::getQmlImportedScripts(NoThrowContext *ctx) { - QQmlContextData *context = QmlContextWrapper::callingContext(ctx->engine); + QQmlContextData *context = QmlContextWrapper::callingContext(ctx->engine()); if (!context) return Encode::undefined(); return context->importedScripts.value(); } -QV4::ReturnedValue Runtime::getQmlSingleton(QV4::NoThrowContext *ctx, const QV4::StringRef name) +QV4::ReturnedValue Runtime::getQmlSingleton(QV4::NoThrowContext *ctx, String *name) { - return ctx->engine->qmlContextObject()->getPointer()->as<QmlContextWrapper>()->qmlSingletonWrapper(ctx->engine->v8Engine, name); + return ctx->engine()->qmlContextObject()->getPointer()->as<QmlContextWrapper>()->qmlSingletonWrapper(ctx->engine()->v8Engine, name); } void Runtime::convertThisToObject(ExecutionContext *ctx) { - Value *t = &ctx->callData->thisObject; + Value *t = &ctx->d()->callData->thisObject; if (t->isObject()) return; if (t->isNullOrUndefined()) { - *t = ctx->engine->globalObject->asReturnedValue(); + *t = ctx->engine()->globalObject->asReturnedValue(); } else { *t = t->toObject(ctx)->asReturnedValue(); } diff --git a/src/qml/jsruntime/qv4runtime_p.h b/src/qml/jsruntime/qv4runtime_p.h index 0979105680..992b027379 100644 --- a/src/qml/jsruntime/qv4runtime_p.h +++ b/src/qml/jsruntime/qv4runtime_p.h @@ -105,51 +105,51 @@ struct NoThrowContext : public ExecutionContext struct Q_QML_PRIVATE_EXPORT Runtime { // call - static ReturnedValue callGlobalLookup(ExecutionContext *context, uint index, CallDataRef callData); - static ReturnedValue callActivationProperty(ExecutionContext *, const StringRef name, CallDataRef callData); - static ReturnedValue callProperty(ExecutionContext *context, const StringRef name, CallDataRef callData); - static ReturnedValue callPropertyLookup(ExecutionContext *context, uint index, CallDataRef callData); - static ReturnedValue callElement(ExecutionContext *context, const ValueRef index, CallDataRef callData); - static ReturnedValue callValue(ExecutionContext *context, const ValueRef func, CallDataRef callData); + static ReturnedValue callGlobalLookup(ExecutionContext *context, uint index, CallData *callData); + static ReturnedValue callActivationProperty(ExecutionContext *, String *name, CallData *callData); + static ReturnedValue callProperty(ExecutionContext *context, String *name, CallData *callData); + static ReturnedValue callPropertyLookup(ExecutionContext *context, uint index, CallData *callData); + static ReturnedValue callElement(ExecutionContext *context, const ValueRef index, CallData *callData); + static ReturnedValue callValue(ExecutionContext *context, const ValueRef func, CallData *callData); // construct - static ReturnedValue constructGlobalLookup(ExecutionContext *context, uint index, CallDataRef callData); - static ReturnedValue constructActivationProperty(ExecutionContext *, const StringRef name, CallDataRef callData); - static ReturnedValue constructProperty(ExecutionContext *context, const StringRef name, CallDataRef callData); - static ReturnedValue constructPropertyLookup(ExecutionContext *context, uint index, CallDataRef callData); - static ReturnedValue constructValue(ExecutionContext *context, const ValueRef func, CallDataRef callData); + static ReturnedValue constructGlobalLookup(ExecutionContext *context, uint index, CallData *callData); + static ReturnedValue constructActivationProperty(ExecutionContext *, String *name, CallData *callData); + static ReturnedValue constructProperty(ExecutionContext *context, String *name, CallData *callData); + static ReturnedValue constructPropertyLookup(ExecutionContext *context, uint index, CallData *callData); + static ReturnedValue constructValue(ExecutionContext *context, const ValueRef func, CallData *callData); // set & get - static void setActivationProperty(ExecutionContext *ctx, const StringRef name, const ValueRef value); - static void setProperty(ExecutionContext *ctx, const ValueRef object, const StringRef name, const ValueRef value); + static void setActivationProperty(ExecutionContext *ctx, String *name, const ValueRef value); + static void setProperty(ExecutionContext *ctx, const ValueRef object, String *name, const ValueRef value); static void setElement(ExecutionContext *ctx, const ValueRef object, const ValueRef index, const ValueRef value); - static ReturnedValue getProperty(ExecutionContext *ctx, const ValueRef object, const StringRef name); - static ReturnedValue getActivationProperty(ExecutionContext *ctx, const StringRef name); + static ReturnedValue getProperty(ExecutionContext *ctx, const ValueRef object, String *name); + static ReturnedValue getActivationProperty(ExecutionContext *ctx, String *name); static ReturnedValue getElement(ExecutionContext *ctx, const ValueRef object, const ValueRef index); // typeof static ReturnedValue typeofValue(ExecutionContext *ctx, const ValueRef val); - static ReturnedValue typeofName(ExecutionContext *context, const StringRef name); - static ReturnedValue typeofMember(ExecutionContext* context, const ValueRef base, const StringRef name); + static ReturnedValue typeofName(ExecutionContext *context, String *name); + static ReturnedValue typeofMember(ExecutionContext* context, const ValueRef base, String *name); static ReturnedValue typeofElement(ExecutionContext* context, const ValueRef base, const ValueRef index); // delete static ReturnedValue deleteElement(ExecutionContext *ctx, const ValueRef base, const ValueRef index); - static ReturnedValue deleteMember(ExecutionContext *ctx, const ValueRef base, const StringRef name); - static ReturnedValue deleteName(ExecutionContext *ctx, const StringRef name); + static ReturnedValue deleteMember(ExecutionContext *ctx, const ValueRef base, String *name); + static ReturnedValue deleteName(ExecutionContext *ctx, String *name); // exceptions & scopes static void throwException(ExecutionContext*, const ValueRef value); static ReturnedValue unwindException(ExecutionContext *ctx); static ExecutionContext *pushWithScope(const ValueRef o, ExecutionContext *ctx); - static ExecutionContext *pushCatchScope(ExecutionContext *ctx, const StringRef exceptionVarName); + static ExecutionContext *pushCatchScope(ExecutionContext *ctx, String *exceptionVarName); static ExecutionContext *popScope(ExecutionContext *ctx); // closures static ReturnedValue closure(ExecutionContext *ctx, int functionId); // function header - static void declareVar(ExecutionContext *ctx, bool deletable, const StringRef name); + static void declareVar(ExecutionContext *ctx, bool deletable, String *name); static ReturnedValue setupArgumentsObject(ExecutionContext *ctx); static void convertThisToObject(ExecutionContext *ctx); @@ -226,7 +226,7 @@ struct Q_QML_PRIVATE_EXPORT Runtime { static ReturnedValue getQmlImportedScripts(NoThrowContext *ctx); static ReturnedValue getQmlContextObject(NoThrowContext *ctx); static ReturnedValue getQmlScopeObject(NoThrowContext *ctx); - static ReturnedValue getQmlSingleton(NoThrowContext *ctx, const StringRef name); + static ReturnedValue getQmlSingleton(NoThrowContext *ctx, String *name); static ReturnedValue getQmlAttachedProperty(ExecutionContext *ctx, int attachedPropertiesId, int propertyIndex); static ReturnedValue getQmlQObjectProperty(ExecutionContext *ctx, const ValueRef object, int propertyIndex, bool captureRequired); static void setQmlQObjectProperty(ExecutionContext *ctx, const ValueRef object, int propertyIndex, const ValueRef value); diff --git a/src/qml/jsruntime/qv4scopedvalue_p.h b/src/qml/jsruntime/qv4scopedvalue_p.h index 5d471ab4fb..563d097440 100644 --- a/src/qml/jsruntime/qv4scopedvalue_p.h +++ b/src/qml/jsruntime/qv4scopedvalue_p.h @@ -117,6 +117,18 @@ struct ScopedValue #endif } + ScopedValue(const Scope &scope, HeapObject *o) + { + ptr = scope.engine->jsStackTop++; + ptr->m = reinterpret_cast<Managed *>(o); +#if QT_POINTER_SIZE == 4 + ptr->tag = QV4::Value::Managed_Type; +#endif +#ifndef QT_NO_DEBUG + ++scope.size; +#endif + } + ScopedValue(const Scope &scope, Managed *m) { ptr = scope.engine->jsStackTop++; @@ -150,6 +162,14 @@ struct ScopedValue return *this; } + ScopedValue &operator=(HeapObject *o) { + ptr->m = reinterpret_cast<Managed *>(o); +#if QT_POINTER_SIZE == 4 + ptr->tag = QV4::Value::Managed_Type; +#endif + return *this; + } + ScopedValue &operator=(Managed *m) { ptr->val = m->asReturnedValue(); return *this; @@ -215,6 +235,19 @@ struct Scoped ++scope.size; #endif } + Scoped(const Scope &scope, HeapObject *o) + { + Value v; + v.m = reinterpret_cast<Managed *>(o); +#if QT_POINTER_SIZE == 4 + v.tag = QV4::Value::Managed_Type; +#endif + ptr = scope.engine->jsStackTop++; + setPointer(value_cast<T>(v)); +#ifndef QT_NO_DEBUG + ++scope.size; +#endif + } Scoped(const Scope &scope, const ScopedValue &v) { ptr = scope.engine->jsStackTop++; @@ -280,6 +313,15 @@ struct Scoped #endif } + Scoped<T> &operator=(HeapObject *o) { + Value v; + v.m = reinterpret_cast<Managed *>(o); +#if QT_POINTER_SIZE == 4 + v.tag = QV4::Value::Managed_Type; +#endif + setPointer(value_cast<T>(v)); + return *this; + } Scoped<T> &operator=(const Value &v) { setPointer(value_cast<T>(v)); return *this; @@ -308,6 +350,9 @@ struct Scoped return *this; } + operator T *() { + return static_cast<T *>(ptr->managed()); + } T *operator->() { return static_cast<T *>(ptr->managed()); @@ -379,10 +424,6 @@ struct ScopedCallData { }; -struct StringRef; -struct ObjectRef; -struct FunctionObjectRef; - template<typename T> inline Scoped<T>::Scoped(const Scope &scope, const ValueRef &v) { @@ -400,38 +441,6 @@ inline Scoped<T> &Scoped<T>::operator=(const ValueRef &v) return *this; } -struct CallDataRef { - CallDataRef(const ScopedCallData &c) - : ptr(c.ptr) {} - CallDataRef(CallData *v) { ptr = v; } - // Important: Do NOT add a copy constructor to this class - // adding a copy constructor actually changes the calling convention, ie. - // is not even binary compatible. Adding it would break assumptions made - // in the jit'ed code. - CallDataRef &operator=(const ScopedCallData &c) - { *ptr = *c.ptr; return *this; } - CallDataRef &operator=(const CallDataRef &o) - { *ptr = *o.ptr; return *this; } - - operator const CallData *() const { - return ptr; - } - const CallData *operator->() const { - return ptr; - } - - operator CallData *() { - return ptr; - } - CallData *operator->() { - return ptr; - } - -private: - CallData *ptr; -}; - - template <typename T> inline Value &Value::operator=(Returned<T> *t) { @@ -467,14 +476,20 @@ inline Returned<T> *Value::as() template<typename T> inline TypedValue<T> &TypedValue<T>::operator =(T *t) { - val = t->asReturnedValue(); + m = t; +#if QT_POINTER_SIZE == 4 + tag = Managed_Type; +#endif return *this; } template<typename T> inline TypedValue<T> &TypedValue<T>::operator =(const Scoped<T> &v) { - val = v.ptr->val; + m = v.ptr->managed(); +#if QT_POINTER_SIZE == 4 + tag = Managed_Type; +#endif return *this; } @@ -517,22 +532,12 @@ PersistentValue::PersistentValue(Returned<T> *obj) { } -inline PersistentValue::PersistentValue(const ManagedRef obj) - : d(new PersistentValuePrivate(obj.asReturnedValue())) -{ -} - template<typename T> inline PersistentValue &PersistentValue::operator=(Returned<T> *obj) { return operator=(QV4::Value::fromManaged(obj->getPointer()).asReturnedValue()); } -inline PersistentValue &PersistentValue::operator=(const ManagedRef obj) -{ - return operator=(obj.asReturnedValue()); -} - inline PersistentValue &PersistentValue::operator=(const ScopedValue &other) { return operator=(other.asReturnedValue()); @@ -573,18 +578,6 @@ inline ValueRef &ValueRef::operator=(const ScopedValue &o) return *this; } - -inline Value *extractValuePointer(const ScopedValue &v) -{ - return v.ptr; -} - -template<typename T> -Value *extractValuePointer(const Scoped<T> &v) -{ - return v.ptr; -} - struct ScopedProperty { ScopedProperty(Scope &scope) diff --git a/src/qml/jsruntime/qv4script.cpp b/src/qml/jsruntime/qv4script.cpp index 36f61a1df5..e08a63bd1f 100644 --- a/src/qml/jsruntime/qv4script.cpp +++ b/src/qml/jsruntime/qv4script.cpp @@ -61,12 +61,11 @@ using namespace QV4; -QmlBindingWrapper::QmlBindingWrapper(ExecutionContext *scope, Function *f, ObjectRef qml) - : FunctionObject(scope, scope->engine->id_eval, /*createProto = */ false) +QmlBindingWrapper::Data::Data(ExecutionContext *scope, Function *f, Object *qml) + : FunctionObject::Data(scope, scope->d()->engine->id_eval, /*createProto = */ false) , qml(qml) - , qmlContext(0) { - Q_ASSERT(scope->inUse); + Q_ASSERT(scope->inUse()); setVTable(staticVTable()); function = f; @@ -75,32 +74,30 @@ QmlBindingWrapper::QmlBindingWrapper(ExecutionContext *scope, Function *f, Objec needsActivation = function ? function->needsActivation() : false; Scope s(scope); - ScopedValue protectThis(s, this); + Scoped<QmlBindingWrapper> o(s, this); - defineReadonlyProperty(scope->engine->id_length, Primitive::fromInt32(1)); + o->defineReadonlyProperty(scope->d()->engine->id_length, Primitive::fromInt32(1)); - qmlContext = scope->engine->currentContext()->newQmlContext(this, qml); - scope->engine->popContext(); + o->d()->qmlContext = reinterpret_cast<CallContext *>(s.engine->currentContext()->newQmlContext(o, qml)); + s.engine->popContext(); } -QmlBindingWrapper::QmlBindingWrapper(ExecutionContext *scope, ObjectRef qml) - : FunctionObject(scope, scope->engine->id_eval, /*createProto = */ false) +QmlBindingWrapper::Data::Data(ExecutionContext *scope, Object *qml) + : FunctionObject::Data(scope, scope->d()->engine->id_eval, /*createProto = */ false) , qml(qml) - , qmlContext(0) { - Q_ASSERT(scope->inUse); + Q_ASSERT(scope->inUse()); setVTable(staticVTable()); - function = 0; needsActivation = false; Scope s(scope); - ScopedValue protectThis(s, this); + Scoped<QmlBindingWrapper> o(s, this); - defineReadonlyProperty(scope->engine->id_length, Primitive::fromInt32(1)); + o->defineReadonlyProperty(scope->d()->engine->id_length, Primitive::fromInt32(1)); - qmlContext = scope->engine->currentContext()->newQmlContext(this, qml); - scope->engine->popContext(); + o->d()->qmlContext = reinterpret_cast<CallContext *>(s.engine->currentContext()->newQmlContext(o, qml)); + s.engine->popContext(); } ReturnedValue QmlBindingWrapper::call(Managed *that, CallData *) @@ -110,13 +107,13 @@ ReturnedValue QmlBindingWrapper::call(Managed *that, CallData *) Scope scope(engine); QmlBindingWrapper *This = static_cast<QmlBindingWrapper *>(that); - if (!This->function) + if (!This->function()) return QV4::Encode::undefined(); - CallContext *ctx = This->qmlContext; - std::fill(ctx->locals, ctx->locals + ctx->function->varCount(), Primitive::undefinedValue()); + CallContext *ctx = This->d()->qmlContext; + std::fill(ctx->d()->locals, ctx->d()->locals + ctx->d()->function->varCount(), Primitive::undefinedValue()); engine->pushContext(ctx); - ScopedValue result(scope, This->function->code(ctx, This->function->codeData)); + ScopedValue result(scope, This->function()->code(ctx, This->function()->codeData)); engine->popContext(); return result.asReturnedValue(); @@ -125,16 +122,16 @@ ReturnedValue QmlBindingWrapper::call(Managed *that, CallData *) void QmlBindingWrapper::markObjects(Managed *m, ExecutionEngine *e) { QmlBindingWrapper *wrapper = static_cast<QmlBindingWrapper*>(m); - if (wrapper->qml) - wrapper->qml->mark(e); + if (wrapper->d()->qml) + wrapper->d()->qml->mark(e); FunctionObject::markObjects(m, e); - if (wrapper->qmlContext) - wrapper->qmlContext->mark(e); + if (wrapper->d()->qmlContext) + wrapper->d()->qmlContext->mark(e); } static ReturnedValue signalParameterGetter(QV4::CallContext *ctx, uint parameterIndex) { - QV4::CallContext *signalEmittingContext = ctx->parent->asCallContext(); + QV4::CallContext *signalEmittingContext = ctx->d()->parent->asCallContext(); Q_ASSERT(signalEmittingContext); return signalEmittingContext->argument(parameterIndex); } @@ -144,7 +141,7 @@ Returned<FunctionObject> *QmlBindingWrapper::createQmlCallableForFunction(QQmlCo ExecutionEngine *engine = QQmlEnginePrivate::getV4Engine(qmlContext->engine); QV4::Scope valueScope(engine); QV4::ScopedObject qmlScopeObject(valueScope, QV4::QmlContextWrapper::qmlScope(engine->v8Engine, qmlContext, scopeObject)); - QV4::Scoped<QV4::QmlBindingWrapper> wrapper(valueScope, new (engine->memoryManager) QV4::QmlBindingWrapper(engine->rootContext, qmlScopeObject)); + QV4::Scoped<QV4::QmlBindingWrapper> wrapper(valueScope, engine->memoryManager->alloc<QV4::QmlBindingWrapper>(engine->rootContext, qmlScopeObject)); if (!signalParameters.isEmpty()) { if (error) @@ -153,10 +150,11 @@ Returned<FunctionObject> *QmlBindingWrapper::createQmlCallableForFunction(QQmlCo QV4::ScopedString s(valueScope); int index = 0; foreach (const QByteArray ¶m, signalParameters) { - p->setGetter(new (engine->memoryManager) QV4::IndexedBuiltinFunction(wrapper->context(), index++, signalParameterGetter)); + QV4::ScopedFunctionObject g(valueScope, engine->memoryManager->alloc<QV4::IndexedBuiltinFunction>(wrapper->context(), index++, signalParameterGetter)); + p->setGetter(g); p->setSetter(0); s = engine->newString(QString::fromUtf8(param)); - qmlScopeObject->insertMember(s, p, QV4::Attr_Accessor|QV4::Attr_NotEnumerable|QV4::Attr_NotConfigurable); + qmlScopeObject->insertMember(s.getPointer(), p, QV4::Attr_Accessor|QV4::Attr_NotEnumerable|QV4::Attr_NotConfigurable); } } @@ -166,35 +164,37 @@ Returned<FunctionObject> *QmlBindingWrapper::createQmlCallableForFunction(QQmlCo DEFINE_OBJECT_VTABLE(QmlBindingWrapper); -struct CompilationUnitHolder : public QV4::Object +struct CompilationUnitHolder : public Object { - V4_OBJECT + struct Data : Object::Data { + Data(ExecutionEngine *engine, CompiledData::CompilationUnit *unit) + : Object::Data(engine) + , unit(unit) + { + unit->ref(); + setVTable(staticVTable()); + } + ~Data() + { + unit->deref(); + } + QV4::CompiledData::CompilationUnit *unit; + }; + V4_OBJECT(Object) - CompilationUnitHolder(ExecutionEngine *engine, CompiledData::CompilationUnit *unit) - : Object(engine) - , unit(unit) - { - unit->ref(); - setVTable(staticVTable()); - } - ~CompilationUnitHolder() - { - unit->deref(); - } static void destroy(Managed *that) { - static_cast<CompilationUnitHolder*>(that)->~CompilationUnitHolder(); + static_cast<CompilationUnitHolder*>(that)->d()->~Data(); } - QV4::CompiledData::CompilationUnit *unit; }; DEFINE_OBJECT_VTABLE(CompilationUnitHolder); -Script::Script(ExecutionEngine *v4, ObjectRef qml, CompiledData::CompilationUnit *compilationUnit) +Script::Script(ExecutionEngine *v4, Object *qml, CompiledData::CompilationUnit *compilationUnit) : line(0), column(0), scope(v4->rootContext), strictMode(false), inheritContext(true), parsed(false) - , qml(qml.asReturnedValue()), vmFunction(0), parseAsBinding(true) + , qml(qml->asReturnedValue()), vmFunction(0), parseAsBinding(true) { parsed = true; @@ -202,7 +202,7 @@ Script::Script(ExecutionEngine *v4, ObjectRef qml, CompiledData::CompilationUnit vmFunction = compilationUnit->linkToEngine(v4); Q_ASSERT(vmFunction); Scope valueScope(v4); - ScopedValue holder(valueScope, new (v4->memoryManager) CompilationUnitHolder(v4, compilationUnit)); + ScopedObject holder(valueScope, v4->memoryManager->alloc<CompilationUnitHolder>(v4, compilationUnit)); compilationUnitHolder = holder.asReturnedValue(); } else vmFunction = 0; @@ -221,7 +221,7 @@ void Script::parse() parsed = true; - ExecutionEngine *v4 = scope->engine; + ExecutionEngine *v4 = scope->d()->engine; Scope valueScope(v4); MemoryManager::GCBlocker gcBlocker(v4->memoryManager); @@ -274,7 +274,7 @@ void Script::parse() isel->setUseFastLookups(false); QV4::CompiledData::CompilationUnit *compilationUnit = isel->compile(); vmFunction = compilationUnit->linkToEngine(v4); - ScopedValue holder(valueScope, new (v4->memoryManager) CompilationUnitHolder(v4, compilationUnit)); + ScopedObject holder(valueScope, v4->memoryManager->alloc<CompilationUnitHolder>(v4, compilationUnit)); compilationUnitHolder = holder.asReturnedValue(); } @@ -295,16 +295,16 @@ ReturnedValue Script::run() ContextStateSaver(ExecutionContext *context) : savedContext(context) - , strictMode(context->strictMode) - , lookups(context->lookups) - , compilationUnit(context->compilationUnit) + , strictMode(context->d()->strictMode) + , lookups(context->d()->lookups) + , compilationUnit(context->d()->compilationUnit) {} ~ContextStateSaver() { - savedContext->strictMode = strictMode; - savedContext->lookups = lookups; - savedContext->compilationUnit = compilationUnit; + savedContext->d()->strictMode = strictMode; + savedContext->d()->lookups = lookups; + savedContext->d()->compilationUnit = compilationUnit; } }; @@ -313,7 +313,7 @@ ReturnedValue Script::run() if (!vmFunction) return Encode::undefined(); - QV4::ExecutionEngine *engine = scope->engine; + QV4::ExecutionEngine *engine = scope->d()->engine; QV4::Scope valueScope(engine); if (qml.isUndefined()) { @@ -321,14 +321,14 @@ ReturnedValue Script::run() ExecutionContextSaver ctxSaver(scope); ContextStateSaver stateSaver(scope); - scope->strictMode = vmFunction->isStrict(); - scope->lookups = vmFunction->compilationUnit->runtimeLookups; - scope->compilationUnit = vmFunction->compilationUnit; + scope->d()->strictMode = vmFunction->isStrict(); + scope->d()->lookups = vmFunction->compilationUnit->runtimeLookups; + scope->d()->compilationUnit = vmFunction->compilationUnit; return vmFunction->code(scope, vmFunction->codeData); } else { ScopedObject qmlObj(valueScope, qml.value()); - FunctionObject *f = new (engine->memoryManager) QmlBindingWrapper(scope, vmFunction, qmlObj); + ScopedFunctionObject f(valueScope, engine->memoryManager->alloc<QmlBindingWrapper>(scope, vmFunction, qmlObj)); ScopedCallData callData(valueScope, 0); callData->thisObject = Primitive::undefinedValue(); return f->call(callData); @@ -401,14 +401,14 @@ ReturnedValue Script::qmlBinding() { if (!parsed) parse(); - ExecutionEngine *v4 = scope->engine; + ExecutionEngine *v4 = scope->d()->engine; Scope valueScope(v4); ScopedObject qmlObj(valueScope, qml.value()); - ScopedObject v(valueScope, new (v4->memoryManager) QmlBindingWrapper(scope, vmFunction, qmlObj)); + ScopedObject v(valueScope, v4->memoryManager->alloc<QmlBindingWrapper>(scope, vmFunction, qmlObj)); return v.asReturnedValue(); } -QV4::ReturnedValue Script::evaluate(ExecutionEngine *engine, const QString &script, ObjectRef scopeObject) +QV4::ReturnedValue Script::evaluate(ExecutionEngine *engine, const QString &script, Object *scopeObject) { QV4::Scope scope(engine); QV4::Script qmlScript(engine, scopeObject, script, QString()); diff --git a/src/qml/jsruntime/qv4script_p.h b/src/qml/jsruntime/qv4script_p.h index de582f9674..6a749d1438 100644 --- a/src/qml/jsruntime/qv4script_p.h +++ b/src/qml/jsruntime/qv4script_p.h @@ -55,23 +55,25 @@ namespace QV4 { struct ExecutionContext; -struct QmlBindingWrapper : FunctionObject { - V4_OBJECT - - QmlBindingWrapper(ExecutionContext *scope, Function *f, ObjectRef qml); - // Constructor for QML functions and signal handlers, resulting binding wrapper is not callable! - QmlBindingWrapper(ExecutionContext *scope, ObjectRef qml); +struct Q_QML_EXPORT QmlBindingWrapper : FunctionObject { + struct Data : FunctionObject::Data { + Data(ExecutionContext *scope, Function *f, Object *qml); + // Constructor for QML functions and signal handlers, resulting binding wrapper is not callable! + Data(ExecutionContext *scope, Object *qml); + Object *qml; + CallContext *qmlContext; + }; + V4_OBJECT(FunctionObject) static ReturnedValue call(Managed *that, CallData *); static void markObjects(Managed *m, ExecutionEngine *e); - CallContext *context() const { return qmlContext; } + CallContext *context() const { return d()->qmlContext; } - static Returned<FunctionObject> *createQmlCallableForFunction(QQmlContextData *qmlContext, QObject *scopeObject, QV4::Function *runtimeFunction, const QList<QByteArray> &signalParameters = QList<QByteArray>(), QString *error = 0); + static Returned<FunctionObject> *createQmlCallableForFunction(QQmlContextData *qmlContext, QObject *scopeObject, QV4::Function *runtimeFunction, + const QList<QByteArray> &signalParameters = QList<QByteArray>(), QString *error = 0); private: - Object *qml; - CallContext *qmlContext; }; struct Q_QML_EXPORT Script { @@ -79,11 +81,11 @@ struct Q_QML_EXPORT Script { : sourceFile(source), line(line), column(column), sourceCode(sourceCode) , scope(scope), strictMode(false), inheritContext(false), parsed(false) , vmFunction(0), parseAsBinding(false) {} - Script(ExecutionEngine *engine, ObjectRef qml, const QString &sourceCode, const QString &source = QString(), int line = 1, int column = 0) + Script(ExecutionEngine *engine, Object *qml, const QString &sourceCode, const QString &source = QString(), int line = 1, int column = 0) : sourceFile(source), line(line), column(column), sourceCode(sourceCode) , scope(engine->rootContext), strictMode(false), inheritContext(true), parsed(false) - , qml(qml.asReturnedValue()), vmFunction(0), parseAsBinding(true) {} - Script(ExecutionEngine *engine, ObjectRef qml, CompiledData::CompilationUnit *compilationUnit); + , qml(qml->asReturnedValue()), vmFunction(0), parseAsBinding(true) {} + Script(ExecutionEngine *engine, Object *qml, CompiledData::CompilationUnit *compilationUnit); ~Script(); QString sourceFile; int line; @@ -106,7 +108,7 @@ struct Q_QML_EXPORT Script { static QV4::CompiledData::CompilationUnit *precompile(IR::Module *module, Compiler::JSUnitGenerator *unitGenerator, ExecutionEngine *engine, const QUrl &url, const QString &source, QList<QQmlError> *reportedErrors = 0); - static ReturnedValue evaluate(ExecutionEngine *engine, const QString &script, ObjectRef scopeObject); + static ReturnedValue evaluate(ExecutionEngine *engine, const QString &script, Object *scopeObject); }; } diff --git a/src/qml/jsruntime/qv4sequenceobject.cpp b/src/qml/jsruntime/qv4sequenceobject.cpp index 89231cfe5f..b55cd2daad 100644 --- a/src/qml/jsruntime/qv4sequenceobject.cpp +++ b/src/qml/jsruntime/qv4sequenceobject.cpp @@ -58,13 +58,13 @@ using namespace QV4; // helper function to generate valid warnings if errors occur during sequence operations. static void generateWarning(QV4::ExecutionContext *ctx, const QString& description) { - QQmlEngine *engine = ctx->engine->v8Engine->engine(); + QQmlEngine *engine = ctx->d()->engine->v8Engine->engine(); if (!engine) return; QQmlError retn; retn.setDescription(description); - QV4::StackFrame frame = ctx->engine->currentStackFrame(); + QV4::StackFrame frame = ctx->d()->engine->currentStackFrame(); retn.setLine(frame.line); retn.setUrl(QUrl(frame.source)); @@ -163,38 +163,41 @@ template <> bool convertValueToElement(const ValueRef value) } template <typename Container> -class QQmlSequence : public QV4::Object +struct QQmlSequence : public QV4::Object { - V4_OBJECT + struct Data : Object::Data { + Data(QV4::ExecutionEngine *engine, const Container &container) + : Object::Data(InternalClass::create(engine, staticVTable(), engine->sequencePrototype.asObject())) + , container(container) + , propertyIndex(-1) + , isReference(false) + { + QV4::Scope scope(engine); + QV4::Scoped<QQmlSequence<Container> > o(scope, this); + o->setArrayType(ArrayData::Custom); + o->init(); + } + + Data(QV4::ExecutionEngine *engine, QObject *object, int propertyIndex) + : Object::Data(InternalClass::create(engine, staticVTable(), engine->sequencePrototype.asObject())) + , object(object) + , propertyIndex(propertyIndex) + , isReference(true) + { + QV4::Scope scope(engine); + QV4::Scoped<QQmlSequence<Container> > o(scope, this); + o->setArrayType(ArrayData::Custom); + o->loadReference(); + o->init(); + } + mutable Container container; + QPointer<QObject> object; + int propertyIndex; + bool isReference; + }; + V4_OBJECT(QV4::Object) Q_MANAGED_TYPE(QmlSequence) public: - QQmlSequence(QV4::ExecutionEngine *engine, const Container &container) - : QV4::Object(InternalClass::create(engine, staticVTable(), engine->sequencePrototype.asObject())) - , m_container(container) - , m_object(0) - , m_propertyIndex(-1) - , m_isReference(false) - { - QV4::Scope scope(engine); - QV4::ScopedObject protectThis(scope, this); - Q_UNUSED(protectThis); - setArrayType(ArrayData::Custom); - init(); - } - - QQmlSequence(QV4::ExecutionEngine *engine, QObject *object, int propertyIndex) - : QV4::Object(InternalClass::create(engine, staticVTable(), engine->sequencePrototype.asObject())) - , m_object(object) - , m_propertyIndex(propertyIndex) - , m_isReference(true) - { - QV4::Scope scope(engine); - QV4::ScopedObject protectThis(scope, this); - Q_UNUSED(protectThis); - setArrayType(ArrayData::Custom); - loadReference(); - init(); - } void init() { @@ -210,8 +213,8 @@ public: *hasProperty = false; return Encode::undefined(); } - if (m_isReference) { - if (!m_object) { + if (d()->isReference) { + if (!d()->object) { if (hasProperty) *hasProperty = false; return Encode::undefined(); @@ -219,10 +222,10 @@ public: loadReference(); } qint32 signedIdx = static_cast<qint32>(index); - if (signedIdx < m_container.count()) { + if (signedIdx < d()->container.count()) { if (hasProperty) *hasProperty = true; - return convertElementToValue(engine(), m_container.at(signedIdx)); + return convertElementToValue(engine(), d()->container.at(signedIdx)); } if (hasProperty) *hasProperty = false; @@ -231,7 +234,7 @@ public: void containerPutIndexed(uint index, const QV4::ValueRef value) { - if (internalClass->engine->hasException) + if (internalClass()->engine->hasException) return; /* Qt containers have int (rather than uint) allowable indexes. */ @@ -240,33 +243,33 @@ public: return; } - if (m_isReference) { - if (!m_object) + if (d()->isReference) { + if (!d()->object) return; loadReference(); } qint32 signedIdx = static_cast<qint32>(index); - int count = m_container.count(); + int count = d()->container.count(); typename Container::value_type element = convertValueToElement<typename Container::value_type>(value); if (signedIdx == count) { - m_container.append(element); + d()->container.append(element); } else if (signedIdx < count) { - m_container[signedIdx] = element; + d()->container[signedIdx] = element; } else { /* according to ECMA262r3 we need to insert */ /* the value at the given index, increasing length to index+1. */ - m_container.reserve(signedIdx + 1); + d()->container.reserve(signedIdx + 1); while (signedIdx > count++) { - m_container.append(typename Container::value_type()); + d()->container.append(typename Container::value_type()); } - m_container.append(element); + d()->container.append(element); } - if (m_isReference) + if (d()->isReference) storeReference(); } @@ -277,33 +280,33 @@ public: generateWarning(engine()->currentContext(), QLatin1String("Index out of range during indexed query")); return QV4::Attr_Invalid; } - if (m_isReference) { - if (!m_object) + if (d()->isReference) { + if (!d()->object) return QV4::Attr_Invalid; loadReference(); } qint32 signedIdx = static_cast<qint32>(index); - return (signedIdx < m_container.count()) ? QV4::Attr_Data : QV4::Attr_Invalid; + return (signedIdx < d()->container.count()) ? QV4::Attr_Data : QV4::Attr_Invalid; } - void containerAdvanceIterator(ObjectIterator *it, StringRef name, uint *index, Property *p, PropertyAttributes *attrs) + void containerAdvanceIterator(ObjectIterator *it, String *&name, uint *index, Property *p, PropertyAttributes *attrs) { name = (String *)0; *index = UINT_MAX; - if (m_isReference) { - if (!m_object) { + if (d()->isReference) { + if (!d()->object) { QV4::Object::advanceIterator(this, it, name, index, p, attrs); return; } loadReference(); } - if (it->arrayIndex < static_cast<uint>(m_container.count())) { + if (it->arrayIndex < static_cast<uint>(d()->container.count())) { *index = it->arrayIndex; ++it->arrayIndex; *attrs = QV4::Attr_Data; - p->value = convertElementToValue(engine(), m_container.at(*index)); + p->value = convertElementToValue(engine(), d()->container.at(*index)); return; } QV4::Object::advanceIterator(this, it, name, index, p, attrs); @@ -314,21 +317,21 @@ public: /* Qt containers have int (rather than uint) allowable indexes. */ if (index > INT_MAX) return false; - if (m_isReference) { - if (!m_object) + if (d()->isReference) { + if (!d()->object) return false; loadReference(); } qint32 signedIdx = static_cast<qint32>(index); - if (signedIdx >= m_container.count()) + if (signedIdx >= d()->container.count()) return false; /* according to ECMA262r3 it should be Undefined, */ /* but we cannot, so we insert a default-value instead. */ - m_container.replace(signedIdx, typename Container::value_type()); + d()->container.replace(signedIdx, typename Container::value_type()); - if (m_isReference) + if (d()->isReference) storeReference(); return true; @@ -339,9 +342,9 @@ public: QQmlSequence<Container> *otherSequence = other->as<QQmlSequence<Container> >(); if (!otherSequence) return false; - if (m_isReference && otherSequence->m_isReference) { - return m_object == otherSequence->m_object && m_propertyIndex == otherSequence->m_propertyIndex; - } else if (!m_isReference && !otherSequence->m_isReference) { + if (d()->isReference && otherSequence->d()->isReference) { + return d()->object == otherSequence->d()->object && d()->propertyIndex == otherSequence->d()->propertyIndex; + } else if (!d()->isReference && !otherSequence->d()->isReference) { return this == otherSequence; } return false; @@ -366,9 +369,9 @@ public: QV4::Scope scope(m_ctx); ScopedObject compare(scope, m_compareFn); ScopedCallData callData(scope, 2); - callData->args[0] = convertElementToValue(this->m_ctx->engine, lhs); - callData->args[1] = convertElementToValue(this->m_ctx->engine, rhs); - callData->thisObject = this->m_ctx->engine->globalObject; + callData->args[0] = convertElementToValue(this->m_ctx->d()->engine, lhs); + callData->args[1] = convertElementToValue(this->m_ctx->d()->engine, rhs); + callData->thisObject = this->m_ctx->d()->engine->globalObject; QV4::ScopedValue result(scope, compare->call(callData)); return result->toNumber() < 0; } @@ -380,82 +383,82 @@ public: void sort(QV4::CallContext *ctx) { - if (m_isReference) { - if (!m_object) + if (d()->isReference) { + if (!d()->object) return; loadReference(); } QV4::Scope scope(ctx); - if (ctx->callData->argc == 1 && ctx->callData->args[0].asFunctionObject()) { - CompareFunctor cf(ctx, ctx->callData->args[0]); - std::sort(m_container.begin(), m_container.end(), cf); + if (ctx->d()->callData->argc == 1 && ctx->d()->callData->args[0].asFunctionObject()) { + CompareFunctor cf(ctx, ctx->d()->callData->args[0]); + std::sort(d()->container.begin(), d()->container.end(), cf); } else { DefaultCompareFunctor cf; - std::sort(m_container.begin(), m_container.end(), cf); + std::sort(d()->container.begin(), d()->container.end(), cf); } - if (m_isReference) + if (d()->isReference) storeReference(); } static QV4::ReturnedValue method_get_length(QV4::CallContext *ctx) { QV4::Scope scope(ctx); - QV4::Scoped<QQmlSequence<Container> > This(scope, ctx->callData->thisObject.as<QQmlSequence<Container> >()); + QV4::Scoped<QQmlSequence<Container> > This(scope, ctx->d()->callData->thisObject.as<QQmlSequence<Container> >()); if (!This) return ctx->throwTypeError(); - if (This->m_isReference) { - if (!This->m_object) + if (This->d()->isReference) { + if (!This->d()->object) return QV4::Encode(0); This->loadReference(); } - return QV4::Encode(This->m_container.count()); + return QV4::Encode(This->d()->container.count()); } static QV4::ReturnedValue method_set_length(QV4::CallContext* ctx) { QV4::Scope scope(ctx); - QV4::Scoped<QQmlSequence<Container> > This(scope, ctx->callData->thisObject.as<QQmlSequence<Container> >()); + QV4::Scoped<QQmlSequence<Container> > This(scope, ctx->d()->callData->thisObject.as<QQmlSequence<Container> >()); if (!This) return ctx->throwTypeError(); - quint32 newLength = ctx->callData->args[0].toUInt32(); + quint32 newLength = ctx->d()->callData->args[0].toUInt32(); /* Qt containers have int (rather than uint) allowable indexes. */ if (newLength > INT_MAX) { generateWarning(ctx, QLatin1String("Index out of range during length set")); return QV4::Encode::undefined(); } /* Read the sequence from the QObject property if we're a reference */ - if (This->m_isReference) { - if (!This->m_object) + if (This->d()->isReference) { + if (!This->d()->object) return QV4::Encode::undefined(); This->loadReference(); } /* Determine whether we need to modify the sequence */ qint32 newCount = static_cast<qint32>(newLength); - qint32 count = This->m_container.count(); + qint32 count = This->d()->container.count(); if (newCount == count) { return QV4::Encode::undefined(); } else if (newCount > count) { /* according to ECMA262r3 we need to insert */ /* undefined values increasing length to newLength. */ /* We cannot, so we insert default-values instead. */ - This->m_container.reserve(newCount); + This->d()->container.reserve(newCount); while (newCount > count++) { - This->m_container.append(typename Container::value_type()); + This->d()->container.append(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->m_container.removeAt(count); + This->d()->container.removeAt(count); } } /* write back if required. */ - if (This->m_isReference) { + if (This->d()->isReference) { /* write back. already checked that object is non-null, so skip that check here. */ This->storeReference(); } @@ -463,9 +466,9 @@ public: } QVariant toVariant() const - { return QVariant::fromValue<Container>(m_container); } + { return QVariant::fromValue<Container>(d()->container); } - static QVariant toVariant(QV4::ArrayObjectRef array) + static QVariant toVariant(QV4::ArrayObject *array) { QV4::Scope scope(array->engine()); Container result; @@ -479,27 +482,22 @@ public: private: void loadReference() const { - Q_ASSERT(m_object); - Q_ASSERT(m_isReference); - void *a[] = { &m_container, 0 }; - QMetaObject::metacall(m_object, QMetaObject::ReadProperty, m_propertyIndex, a); + Q_ASSERT(d()->object); + Q_ASSERT(d()->isReference); + void *a[] = { &d()->container, 0 }; + QMetaObject::metacall(d()->object, QMetaObject::ReadProperty, d()->propertyIndex, a); } void storeReference() { - Q_ASSERT(m_object); - Q_ASSERT(m_isReference); + Q_ASSERT(d()->object); + Q_ASSERT(d()->isReference); int status = -1; QQmlPropertyPrivate::WriteFlags flags = QQmlPropertyPrivate::DontRemoveBinding; - void *a[] = { &m_container, 0, &status, &flags }; - QMetaObject::metacall(m_object, QMetaObject::WriteProperty, m_propertyIndex, a); + void *a[] = { &d()->container, 0, &status, &flags }; + QMetaObject::metacall(d()->object, QMetaObject::WriteProperty, d()->propertyIndex, a); } - mutable Container m_container; - QPointer<QObject> m_object; - int m_propertyIndex; - bool m_isReference; - static QV4::ReturnedValue getIndexed(QV4::Managed *that, uint index, bool *hasProperty) { return static_cast<QQmlSequence<Container> *>(that)->containerGetIndexed(index, hasProperty); } static void putIndexed(Managed *that, uint index, const QV4::ValueRef value) @@ -510,7 +508,7 @@ private: { return static_cast<QQmlSequence<Container> *>(that)->containerDeleteIndexedProperty(index); } static bool isEqualTo(Managed *that, Managed *other) { return static_cast<QQmlSequence<Container> *>(that)->containerIsEqualTo(other); } - static void advanceIterator(Managed *that, ObjectIterator *it, StringRef name, uint *index, Property *p, PropertyAttributes *attrs) + static void advanceIterator(Managed *that, ObjectIterator *it, String *&name, uint *index, Property *p, PropertyAttributes *attrs) { return static_cast<QQmlSequence<Container> *>(that)->containerAdvanceIterator(it, name, index, p, attrs); } static void destroy(Managed *that) @@ -539,27 +537,22 @@ template<> DEFINE_OBJECT_VTABLE(QQmlRealList); #define REGISTER_QML_SEQUENCE_METATYPE(unused, unused2, SequenceType, unused3) qRegisterMetaType<SequenceType>(#SequenceType); -SequencePrototype::SequencePrototype(InternalClass *ic) - : QV4::Object(ic) -{ - FOREACH_QML_SEQUENCE_TYPE(REGISTER_QML_SEQUENCE_METATYPE) -} -#undef REGISTER_QML_SEQUENCE_METATYPE - void SequencePrototype::init() { + FOREACH_QML_SEQUENCE_TYPE(REGISTER_QML_SEQUENCE_METATYPE) defineDefaultProperty(QStringLiteral("sort"), method_sort, 1); defineDefaultProperty(engine()->id_valueOf, method_valueOf, 0); } +#undef REGISTER_QML_SEQUENCE_METATYPE QV4::ReturnedValue SequencePrototype::method_sort(QV4::CallContext *ctx) { QV4::Scope scope(ctx); - QV4::ScopedObject o(scope, ctx->callData->thisObject); + QV4::ScopedObject o(scope, ctx->d()->callData->thisObject); if (!o || !o->isListType()) return ctx->throwTypeError(); - if (ctx->callData->argc >= 2) + if (ctx->d()->callData->argc >= 2) return o.asReturnedValue(); #define CALL_SORT(SequenceElementType, SequenceElementTypeName, SequenceType, DefaultValue) \ @@ -587,7 +580,7 @@ bool SequencePrototype::isSequenceType(int sequenceTypeId) #define NEW_REFERENCE_SEQUENCE(ElementType, ElementTypeName, SequenceType, unused) \ if (sequenceType == qMetaTypeId<SequenceType>()) { \ - QV4::Scoped<QV4::Object> obj(scope, new (engine->memoryManager) QQml##ElementTypeName##List(engine, object, propertyIndex)); \ + QV4::Scoped<QV4::Object> obj(scope, engine->memoryManager->alloc<QQml##ElementTypeName##List>(engine, object, propertyIndex)); \ return obj.asReturnedValue(); \ } else @@ -605,7 +598,7 @@ ReturnedValue SequencePrototype::newSequence(QV4::ExecutionEngine *engine, int s #define NEW_COPY_SEQUENCE(ElementType, ElementTypeName, SequenceType, unused) \ if (sequenceType == qMetaTypeId<SequenceType>()) { \ - QV4::Scoped<QV4::Object> obj(scope, new (engine->memoryManager) QQml##ElementTypeName##List(engine, v.value<SequenceType >())); \ + QV4::Scoped<QV4::Object> obj(scope, engine->memoryManager->alloc<QQml##ElementTypeName##List>(engine, v.value<SequenceType >())); \ return obj.asReturnedValue(); \ } else @@ -627,7 +620,7 @@ ReturnedValue SequencePrototype::fromVariant(QV4::ExecutionEngine *engine, const return list->toVariant(); \ else -QVariant SequencePrototype::toVariant(ObjectRef object) +QVariant SequencePrototype::toVariant(Object *object) { Q_ASSERT(object->isListType()); FOREACH_QML_SEQUENCE_TYPE(SEQUENCE_TO_VARIANT) { /* else */ return QVariant(); } @@ -660,7 +653,7 @@ QVariant SequencePrototype::toVariant(const QV4::ValueRef array, int typeHint, b return qMetaTypeId<SequenceType>(); \ } else -int SequencePrototype::metaTypeForSequence(QV4::ObjectRef object) +int SequencePrototype::metaTypeForSequence(QV4::Object *object) { FOREACH_QML_SEQUENCE_TYPE(MAP_META_TYPE) /*else*/ { diff --git a/src/qml/jsruntime/qv4sequenceobject_p.h b/src/qml/jsruntime/qv4sequenceobject_p.h index 4a5e82b688..727f312930 100644 --- a/src/qml/jsruntime/qv4sequenceobject_p.h +++ b/src/qml/jsruntime/qv4sequenceobject_p.h @@ -65,13 +65,11 @@ namespace QV4 { struct SequencePrototype : public QV4::Object { - SequencePrototype(QV4::InternalClass *ic); - void init(); static ReturnedValue method_valueOf(QV4::CallContext *ctx) { - return ctx->callData->thisObject.toString(ctx)->asReturnedValue(); + return ctx->d()->callData->thisObject.toString(ctx)->asReturnedValue(); } static ReturnedValue method_sort(QV4::CallContext *ctx); @@ -79,8 +77,8 @@ struct SequencePrototype : public QV4::Object static bool isSequenceType(int sequenceTypeId); static ReturnedValue newSequence(QV4::ExecutionEngine *engine, int sequenceTypeId, QObject *object, int propertyIndex, bool *succeeded); static ReturnedValue fromVariant(QV4::ExecutionEngine *engine, const QVariant& v, bool *succeeded); - static int metaTypeForSequence(ObjectRef object); - static QVariant toVariant(QV4::ObjectRef object); + static int metaTypeForSequence(Object *object); + static QVariant toVariant(Object *object); static QVariant toVariant(const ValueRef array, int typeHint, bool *succeeded); }; diff --git a/src/qml/jsruntime/qv4serialize.cpp b/src/qml/jsruntime/qv4serialize.cpp index 3d754389a2..4e88a331a4 100644 --- a/src/qml/jsruntime/qv4serialize.cpp +++ b/src/qml/jsruntime/qv4serialize.cpp @@ -208,7 +208,7 @@ void Serialize::serialize(QByteArray &data, const QV4::ValueRef v, QV8Engine *en } else if (QV4::DateObject *d = v->asDateObject()) { reserve(data, sizeof(quint32) + sizeof(double)); push(data, valueheader(WorkerDate)); - push(data, d->value.asDouble()); + push(data, d->date().asDouble()); } else if (v->as<RegExpObject>()) { Scoped<RegExpObject> re(scope, v); quint32 flags = re->flags(); @@ -281,7 +281,7 @@ void Serialize::serialize(QByteArray &data, const QV4::ValueRef v, QV8Engine *en QV4::ExecutionContext *ctx = v4->currentContext(); str = s; - val = o->get(str); + val = o->get(str.getPointer()); if (scope.hasException()) ctx->catchException(); @@ -342,7 +342,7 @@ ReturnedValue Serialize::deserialize(const char *&data, QV8Engine *engine) name = deserialize(data, engine); value = deserialize(data, engine); n = name.asReturnedValue(); - o->put(n, value); + o->put(n.getPointer(), value); } return o.asReturnedValue(); } @@ -372,7 +372,7 @@ ReturnedValue Serialize::deserialize(const char *&data, QV8Engine *engine) QVariant var = qVariantFromValue(ref); QV4::ScopedValue v(scope, engine->fromVariant((var))); QV4::ScopedString s(scope, v4->newString(QStringLiteral("__qml:hidden:ref"))); - rv->asObject()->defineReadonlyProperty(s, v); + rv->asObject()->defineReadonlyProperty(s.getPointer(), v); agent->release(); agent->setV8Engine(engine); diff --git a/src/qml/jsruntime/qv4string.cpp b/src/qml/jsruntime/qv4string.cpp index d9aa881f21..123d1648c2 100644 --- a/src/qml/jsruntime/qv4string.cpp +++ b/src/qml/jsruntime/qv4string.cpp @@ -108,7 +108,7 @@ static uint toArrayIndex(const char *ch, const char *end, bool *ok) const ObjectVTable String::static_vtbl = { - DEFINE_MANAGED_VTABLE_INT(String), + DEFINE_MANAGED_VTABLE_INT(String, 0), 0, 0, get, @@ -133,13 +133,13 @@ void String::destroy(Managed *that) void String::markObjects(Managed *that, ExecutionEngine *e) { String *s = static_cast<String *>(that); - if (s->largestSubLength) { - s->left->mark(e); - s->right->mark(e); + if (s->d()->largestSubLength) { + s->d()->left->mark(e); + s->d()->right->mark(e); } } -ReturnedValue String::get(Managed *m, const StringRef name, bool *hasProperty) +ReturnedValue String::get(Managed *m, String *name, bool *hasProperty) { ExecutionEngine *v4 = m->engine(); Scope scope(v4); @@ -148,7 +148,7 @@ ReturnedValue String::get(Managed *m, const StringRef name, bool *hasProperty) if (name->equals(v4->id_length)) { if (hasProperty) *hasProperty = true; - return Primitive::fromInt32(that->_text->size).asReturnedValue(); + return Primitive::fromInt32(that->d()->text->size).asReturnedValue(); } PropertyAttributes attrs; Property *pd = v4->stringObjectClass->prototype->__getPropertyDescriptor__(name, &attrs); @@ -168,7 +168,7 @@ ReturnedValue String::getIndexed(Managed *m, uint index, bool *hasProperty) Scope scope(engine); ScopedString that(scope, static_cast<String *>(m)); - if (index < static_cast<uint>(that->_text->size)) { + if (index < static_cast<uint>(that->d()->text->size)) { if (hasProperty) *hasProperty = true; return Encode(engine->newString(that->toQString().mid(index, 1))); @@ -185,7 +185,7 @@ ReturnedValue String::getIndexed(Managed *m, uint index, bool *hasProperty) return engine->stringObjectClass->prototype->getValue(that, pd, attrs); } -void String::put(Managed *m, const StringRef name, const ValueRef value) +void String::put(Managed *m, String *name, const ValueRef value) { Scope scope(m->engine()); if (scope.hasException()) @@ -206,7 +206,7 @@ void String::putIndexed(Managed *m, uint index, const ValueRef value) o->putIndexed(index, value); } -PropertyAttributes String::query(const Managed *m, StringRef name) +PropertyAttributes String::query(const Managed *m, String *name) { uint idx = name->asArrayIndex(); if (idx != UINT_MAX) @@ -217,10 +217,10 @@ PropertyAttributes String::query(const Managed *m, StringRef name) PropertyAttributes String::queryIndexed(const Managed *m, uint index) { const String *that = static_cast<const String *>(m); - return (index < static_cast<uint>(that->_text->size)) ? Attr_NotConfigurable|Attr_NotWritable : Attr_Invalid; + return (index < static_cast<uint>(that->d()->text->size)) ? Attr_NotConfigurable|Attr_NotWritable : Attr_Invalid; } -bool String::deleteProperty(Managed *, const StringRef) +bool String::deleteProperty(Managed *, String *) { return false; } @@ -235,44 +235,50 @@ bool String::isEqualTo(Managed *t, Managed *o) if (t == o) return true; - if (!o->internalClass->vtable->isString) + if (!o->internalClass()->vtable->isString) return false; String *that = static_cast<String *>(t); String *other = static_cast<String *>(o); if (that->hashValue() != other->hashValue()) return false; - if (that->identifier && that->identifier == other->identifier) + if (that->identifier() && that->identifier() == other->identifier()) return true; - if (that->subtype >= StringType_UInt && that->subtype == other->subtype) + if (that->subtype() >= StringType_UInt && that->subtype() == other->subtype()) return true; return that->toQString() == other->toQString(); } -String::String(ExecutionEngine *engine, const QString &text) - : Managed(engine->stringClass), _text(const_cast<QString &>(text).data_ptr()) - , identifier(0), stringHash(UINT_MAX) - , largestSubLength(0) +String::Data::Data(ExecutionEngine *engine, const QString &t) + : Managed::Data(engine->stringClass) { - _text->ref.ref(); - len = _text->size; subtype = StringType_Unknown; + + text = const_cast<QString &>(t).data_ptr(); + text->ref.ref(); + identifier = 0; + stringHash = UINT_MAX; + largestSubLength = 0; + len = text->size; } -String::String(ExecutionEngine *engine, String *l, String *r) - : Managed(engine->stringClass) - , left(l), right(r) - , stringHash(UINT_MAX), largestSubLength(qMax(l->largestSubLength, r->largestSubLength)) - , len(l->len + r->len) +String::Data::Data(ExecutionEngine *engine, String *l, String *r) + : Managed::Data(engine->stringClass) { subtype = StringType_Unknown; - if (!l->largestSubLength && l->len > largestSubLength) - largestSubLength = l->len; - if (!r->largestSubLength && r->len > largestSubLength) - largestSubLength = r->len; + left = l; + right = r; + stringHash = UINT_MAX; + largestSubLength = qMax(l->d()->largestSubLength, r->d()->largestSubLength); + len = l->d()->len + r->d()->len; + + if (!l->d()->largestSubLength && l->d()->len > largestSubLength) + largestSubLength = l->d()->len; + if (!r->d()->largestSubLength && r->d()->len > largestSubLength) + largestSubLength = r->d()->len; // make sure we don't get excessive depth in our strings if (len > 256 && len >= 2*largestSubLength) @@ -283,10 +289,10 @@ uint String::toUInt(bool *ok) const { *ok = true; - if (subtype == StringType_Unknown) + if (subtype() == StringType_Unknown) createHashValue(); - if (subtype >= StringType_UInt) - return stringHash; + if (subtype() >= StringType_UInt) + return d()->stringHash; // ### this conversion shouldn't be required double d = RuntimeHelpers::stringToNumber(toQString()); @@ -297,15 +303,15 @@ uint String::toUInt(bool *ok) const return UINT_MAX; } -bool String::equals(const StringRef other) const +bool String::equals(String *other) const { - if (this == other.getPointer()) + if (this == other) return true; if (hashValue() != other->hashValue()) return false; - if (identifier && identifier == other->identifier) + if (identifier() && identifier() == other->identifier()) return true; - if (subtype >= StringType_UInt && subtype == other->subtype) + if (subtype() >= StringType_UInt && subtype() == other->subtype()) return true; return toQString() == other->toQString(); @@ -313,13 +319,13 @@ bool String::equals(const StringRef other) const void String::makeIdentifierImpl() const { - if (largestSubLength) - simplifyString(); - Q_ASSERT(!largestSubLength); + if (d()->largestSubLength) + d()->simplifyString(); + Q_ASSERT(!d()->largestSubLength); engine()->identifierTable->identifier(this); } -void String::simplifyString() const +void String::Data::simplifyString() const { Q_ASSERT(largestSubLength); @@ -327,20 +333,20 @@ void String::simplifyString() const QString result(l, Qt::Uninitialized); QChar *ch = const_cast<QChar *>(result.constData()); recursiveAppend(ch); - _text = result.data_ptr(); - _text->ref.ref(); + text = result.data_ptr(); + text->ref.ref(); identifier = 0; largestSubLength = 0; } -QChar *String::recursiveAppend(QChar *ch) const +QChar *String::Data::recursiveAppend(QChar *ch) const { if (largestSubLength) { - ch = left->recursiveAppend(ch); - ch = right->recursiveAppend(ch); + ch = left->d()->recursiveAppend(ch); + ch = right->d()->recursiveAppend(ch); } else { - memcpy(ch, _text->data(), _text->size*sizeof(QChar)); - ch += _text->size; + memcpy(ch, text->data(), text->size*sizeof(QChar)); + ch += text->size; } return ch; } @@ -348,17 +354,17 @@ QChar *String::recursiveAppend(QChar *ch) const void String::createHashValue() const { - if (largestSubLength) - simplifyString(); - Q_ASSERT(!largestSubLength); - const QChar *ch = reinterpret_cast<const QChar *>(_text->data()); - const QChar *end = ch + _text->size; + if (d()->largestSubLength) + d()->simplifyString(); + Q_ASSERT(!d()->largestSubLength); + const QChar *ch = reinterpret_cast<const QChar *>(d()->text->data()); + const QChar *end = ch + d()->text->size; // array indices get their number as hash value bool ok; - stringHash = ::toArrayIndex(ch, end, &ok); + d()->stringHash = ::toArrayIndex(ch, end, &ok); if (ok) { - subtype = (stringHash == UINT_MAX) ? StringType_UInt : StringType_ArrayIndex; + setSubtype((d()->stringHash == UINT_MAX) ? StringType_UInt : StringType_ArrayIndex); return; } @@ -368,8 +374,8 @@ void String::createHashValue() const ++ch; } - stringHash = h; - subtype = StringType_Regular; + d()->stringHash = h; + setSubtype(StringType_Regular); } uint String::createHashValue(const QChar *ch, int length) @@ -414,7 +420,7 @@ uint String::createHashValue(const char *ch, int length) uint String::getLength(const Managed *m) { - return static_cast<const String *>(m)->length(); + return static_cast<const String *>(m)->d()->length(); } #endif // V4_BOOTSTRAP diff --git a/src/qml/jsruntime/qv4string_p.h b/src/qml/jsruntime/qv4string_p.h index ed2a4e3646..f9d3cd1cc0 100644 --- a/src/qml/jsruntime/qv4string_p.h +++ b/src/qml/jsruntime/qv4string_p.h @@ -53,8 +53,36 @@ struct Identifier; struct Q_QML_PRIVATE_EXPORT String : public Managed { #ifndef V4_BOOTSTRAP + struct Q_QML_PRIVATE_EXPORT Data : Managed::Data { + Data(ExecutionEngine *engine, const QString &text); + Data(ExecutionEngine *engine, String *l, String *n); + ~Data() { + if (!largestSubLength && !text->ref.deref()) + QStringData::deallocate(text); + } + void simplifyString() const; + int length() const { + Q_ASSERT((largestSubLength && + (len == left->d()->len + right->d()->len)) || + len == (uint)text->size); + return len; + } + union { + mutable QStringData *text; + mutable String *left; + }; + union { + mutable Identifier *identifier; + mutable String *right; + }; + mutable uint stringHash; + mutable uint largestSubLength; + uint len; + private: + QChar *recursiveAppend(QChar *ch) const; + }; // ### FIXME: Should this be a V4_OBJECT - V4_OBJECT + V4_OBJECT(QV4::Managed) Q_MANAGED_TYPE(String) enum { IsString = true @@ -67,24 +95,16 @@ struct Q_QML_PRIVATE_EXPORT String : public Managed { StringType_ArrayIndex }; - String(ExecutionEngine *engine, const QString &text); - String(ExecutionEngine *engine, String *l, String *n); - ~String() { - if (!largestSubLength && !_text->ref.deref()) - QStringData::deallocate(_text); - _data = 0; - } - - bool equals(const StringRef other) const; + bool equals(String *other) const; inline bool isEqualTo(const String *other) const { if (this == other) return true; if (hashValue() != other->hashValue()) return false; - Q_ASSERT(!largestSubLength); - if (identifier && identifier == other->identifier) + Q_ASSERT(!d()->largestSubLength); + if (d()->identifier && d()->identifier == other->d()->identifier) return true; - if (subtype >= StringType_UInt && subtype == other->subtype) + if (subtype() >= StringType_UInt && subtype() == other->subtype()) return true; return toQString() == other->toQString(); @@ -95,34 +115,32 @@ struct Q_QML_PRIVATE_EXPORT String : public Managed { } inline QString toQString() const { - if (largestSubLength) - simplifyString(); - QStringDataPtr ptr = { _text }; - _text->ref.ref(); + if (d()->largestSubLength) + d()->simplifyString(); + QStringDataPtr ptr = { d()->text }; + d()->text->ref.ref(); return QString(ptr); } - void simplifyString() const; - inline unsigned hashValue() const { - if (subtype == StringType_Unknown) + if (subtype() == StringType_Unknown) createHashValue(); - Q_ASSERT(!largestSubLength); + Q_ASSERT(!d()->largestSubLength); - return stringHash; + return d()->stringHash; } uint asArrayIndex() const { - if (subtype == StringType_Unknown) + if (subtype() == StringType_Unknown) createHashValue(); - Q_ASSERT(!largestSubLength); - if (subtype == StringType_ArrayIndex) - return stringHash; + Q_ASSERT(!d()->largestSubLength); + if (subtype() == StringType_ArrayIndex) + return d()->stringHash; return UINT_MAX; } uint toUInt(bool *ok) const; void makeIdentifier() const { - if (identifier) + if (d()->identifier) return; makeIdentifierImpl(); } @@ -135,44 +153,26 @@ struct Q_QML_PRIVATE_EXPORT String : public Managed { bool startsWithUpper() const { const String *l = this; - while (l->largestSubLength) - l = l->left; - return l->_text->size && QChar::isUpper(l->_text->data()[0]); - } - int length() const { - Q_ASSERT((largestSubLength && (len == left->len + right->len)) || len == (uint)_text->size); - return len; + while (l->d()->largestSubLength) + l = l->d()->left; + return l->d()->text->size && QChar::isUpper(l->d()->text->data()[0]); } - union { - mutable QStringData *_text; - mutable String *left; - }; - union { - mutable Identifier *identifier; - mutable String *right; - }; - mutable uint stringHash; - mutable uint largestSubLength; - uint len; - + Identifier *identifier() const { return d()->identifier; } protected: static void destroy(Managed *); static void markObjects(Managed *that, ExecutionEngine *e); - static ReturnedValue get(Managed *m, const StringRef name, bool *hasProperty); + static ReturnedValue get(Managed *m, String *name, bool *hasProperty); static ReturnedValue getIndexed(Managed *m, uint index, bool *hasProperty); - static void put(Managed *m, const StringRef name, const ValueRef value); + static void put(Managed *m, String *name, const ValueRef value); static void putIndexed(Managed *m, uint index, const ValueRef value); - static PropertyAttributes query(const Managed *m, StringRef name); + static PropertyAttributes query(const Managed *m, String *name); static PropertyAttributes queryIndexed(const Managed *m, uint index); - static bool deleteProperty(Managed *, const StringRef); + static bool deleteProperty(Managed *, String *); static bool deleteIndexedProperty(Managed *m, uint index); static bool isEqualTo(Managed *that, Managed *o); static uint getLength(const Managed *m); - -private: - QChar *recursiveAppend(QChar *ch) const; #endif public: @@ -191,7 +191,6 @@ inline ReturnedValue value_convert<String>(ExecutionEngine *e, const Value &v) return v.toString(e)->asReturnedValue(); } -DEFINE_REF(String, Managed); #endif } diff --git a/src/qml/jsruntime/qv4stringobject.cpp b/src/qml/jsruntime/qv4stringobject.cpp index f1e51703a8..3f683495cd 100644 --- a/src/qml/jsruntime/qv4stringobject.cpp +++ b/src/qml/jsruntime/qv4stringobject.cpp @@ -77,44 +77,38 @@ using namespace QV4; DEFINE_OBJECT_VTABLE(StringObject); -StringObject::StringObject(InternalClass *ic) - : Object(ic) +StringObject::Data::Data(InternalClass *ic) + : Object::Data(ic) { Q_ASSERT(internalClass->vtable == staticVTable()); - - Scope scope(engine()); - ScopedObject protectThis(scope, this); - value = ic->engine->newString(QStringLiteral(""))->asReturnedValue(); - tmpProperty.value = Primitive::undefinedValue(); - defineReadonlyProperty(ic->engine->id_length, Primitive::fromInt32(0)); + Scope scope(ic->engine); + ScopedObject s(scope, this); + s->defineReadonlyProperty(ic->engine->id_length, Primitive::fromInt32(0)); } -StringObject::StringObject(ExecutionEngine *engine, const ValueRef val) - : Object(engine->stringObjectClass) +StringObject::Data::Data(ExecutionEngine *engine, const ValueRef val) + : Object::Data(engine->stringObjectClass) { + value = val; + Q_ASSERT(value.isString()); + tmpProperty.value = Primitive::undefinedValue(); setVTable(staticVTable()); Scope scope(engine); - ScopedObject protectThis(scope, this); - - value = *val; - - tmpProperty.value = Primitive::undefinedValue(); - - assert(value.isString()); - defineReadonlyProperty(engine->id_length, Primitive::fromUInt32(value.stringValue()->toQString().length())); + ScopedObject s(scope, this); + s->defineReadonlyProperty(engine->id_length, Primitive::fromUInt32(value.stringValue()->toQString().length())); } Property *StringObject::getIndex(uint index) const { - QString str = value.stringValue()->toQString(); + QString str = d()->value.stringValue()->toQString(); if (index >= (uint)str.length()) return 0; - tmpProperty.value = Encode(internalClass->engine->newString(str.mid(index, 1))); - return &tmpProperty; + d()->tmpProperty.value = Encode(internalClass()->engine->newString(str.mid(index, 1))); + return &d()->tmpProperty; } bool StringObject::deleteIndexedProperty(Managed *m, uint index) @@ -127,19 +121,19 @@ bool StringObject::deleteIndexedProperty(Managed *m, uint index) return false; } - if (index < static_cast<uint>(o->value.stringValue()->toQString().length())) { - if (v4->currentContext()->strictMode) + if (index < static_cast<uint>(o->d()->value.stringValue()->toQString().length())) { + if (v4->currentContext()->d()->strictMode) v4->currentContext()->throwTypeError(); return false; } return true; } -void StringObject::advanceIterator(Managed *m, ObjectIterator *it, StringRef name, uint *index, Property *p, PropertyAttributes *attrs) +void StringObject::advanceIterator(Managed *m, ObjectIterator *it, String *&name, uint *index, Property *p, PropertyAttributes *attrs) { name = (String *)0; StringObject *s = static_cast<StringObject *>(m); - uint slen = s->value.stringValue()->toQString().length(); + uint slen = s->d()->value.stringValue()->toQString().length(); if (it->arrayIndex <= slen) { while (it->arrayIndex < slen) { *index = it->arrayIndex; @@ -152,7 +146,7 @@ void StringObject::advanceIterator(Managed *m, ObjectIterator *it, StringRef nam return; } } - if (s->arrayData) { + if (s->arrayData()) { it->arrayNode = s->sparseBegin(); // iterate until we're past the end of the string while (it->arrayNode && it->arrayNode->key() < slen) @@ -166,15 +160,15 @@ void StringObject::advanceIterator(Managed *m, ObjectIterator *it, StringRef nam void StringObject::markObjects(Managed *that, ExecutionEngine *e) { StringObject *o = static_cast<StringObject *>(that); - o->value.stringValue()->mark(e); - o->tmpProperty.value.mark(e); + o->d()->value.stringValue()->mark(e); + o->d()->tmpProperty.value.mark(e); Object::markObjects(that, e); } DEFINE_OBJECT_VTABLE(StringCtor); -StringCtor::StringCtor(ExecutionContext *scope) - : FunctionObject(scope, QStringLiteral("String")) +StringCtor::Data::Data(ExecutionContext *scope) + : FunctionObject::Data(scope, QStringLiteral("String")) { setVTable(staticVTable()); } @@ -203,7 +197,7 @@ ReturnedValue StringCtor::call(Managed *m, CallData *callData) return value.asReturnedValue(); } -void StringPrototype::init(ExecutionEngine *engine, ObjectRef ctor) +void StringPrototype::init(ExecutionEngine *engine, Object *ctor) { Scope scope(engine); ScopedObject o(scope); @@ -238,11 +232,11 @@ void StringPrototype::init(ExecutionEngine *engine, ObjectRef ctor) static QString getThisString(ExecutionContext *ctx) { Scope scope(ctx); - ScopedValue t(scope, ctx->callData->thisObject); + ScopedValue t(scope, ctx->d()->callData->thisObject); if (t->isString()) return t->stringValue()->toQString(); if (StringObject *thisString = t->asStringObject()) - return thisString->value.stringValue()->toQString(); + return thisString->d()->value.stringValue()->toQString(); if (t->isUndefined() || t->isNull()) { ctx->throwTypeError(); return QString(); @@ -252,41 +246,41 @@ static QString getThisString(ExecutionContext *ctx) ReturnedValue StringPrototype::method_toString(CallContext *context) { - if (context->callData->thisObject.isString()) - return context->callData->thisObject.asReturnedValue(); + if (context->d()->callData->thisObject.isString()) + return context->d()->callData->thisObject.asReturnedValue(); - StringObject *o = context->callData->thisObject.asStringObject(); + StringObject *o = context->d()->callData->thisObject.asStringObject(); if (!o) return context->throwTypeError(); - return o->value.asReturnedValue(); + return o->d()->value.asReturnedValue(); } ReturnedValue StringPrototype::method_charAt(CallContext *context) { const QString str = getThisString(context); - if (context->engine->hasException) + if (context->d()->engine->hasException) return Encode::undefined(); int pos = 0; - if (context->callData->argc > 0) - pos = (int) context->callData->args[0].toInteger(); + if (context->d()->callData->argc > 0) + pos = (int) context->d()->callData->args[0].toInteger(); QString result; if (pos >= 0 && pos < str.length()) result += str.at(pos); - return context->engine->newString(result)->asReturnedValue(); + return context->d()->engine->newString(result)->asReturnedValue(); } ReturnedValue StringPrototype::method_charCodeAt(CallContext *context) { const QString str = getThisString(context); - if (context->engine->hasException) + if (context->d()->engine->hasException) return Encode::undefined(); int pos = 0; - if (context->callData->argc > 0) - pos = (int) context->callData->args[0].toInteger(); + if (context->d()->callData->argc > 0) + pos = (int) context->d()->callData->args[0].toInteger(); if (pos >= 0 && pos < str.length()) @@ -304,30 +298,30 @@ ReturnedValue StringPrototype::method_concat(CallContext *context) return Encode::undefined(); ScopedValue v(scope); - for (int i = 0; i < context->callData->argc; ++i) { - v = RuntimeHelpers::toString(context, ValueRef(&context->callData->args[i])); + for (int i = 0; i < context->d()->callData->argc; ++i) { + v = RuntimeHelpers::toString(context, ValueRef(&context->d()->callData->args[i])); if (scope.hasException()) return Encode::undefined(); Q_ASSERT(v->isString()); value += v->stringValue()->toQString(); } - return context->engine->newString(value)->asReturnedValue(); + return context->d()->engine->newString(value)->asReturnedValue(); } ReturnedValue StringPrototype::method_indexOf(CallContext *context) { QString value = getThisString(context); - if (context->engine->hasException) + if (context->d()->engine->hasException) return Encode::undefined(); QString searchString; - if (context->callData->argc) - searchString = context->callData->args[0].toString(context)->toQString(); + if (context->d()->callData->argc) + searchString = context->d()->callData->args[0].toString(context)->toQString(); int pos = 0; - if (context->callData->argc > 1) - pos = (int) context->callData->args[1].toInteger(); + if (context->d()->callData->argc > 1) + pos = (int) context->d()->callData->args[1].toInteger(); int index = -1; if (! value.isEmpty()) @@ -345,8 +339,8 @@ ReturnedValue StringPrototype::method_lastIndexOf(CallContext *context) return Encode::undefined(); QString searchString; - if (context->callData->argc) - searchString = context->callData->args[0].toQString(); + if (context->d()->callData->argc) + searchString = context->d()->callData->args[0].toQString(); ScopedValue posArg(scope, context->argument(1)); double position = RuntimeHelpers::toNumber(posArg); @@ -371,36 +365,36 @@ ReturnedValue StringPrototype::method_localeCompare(CallContext *context) if (scope.engine->hasException) return Encode::undefined(); - ScopedValue v(scope, context->callData->argument(0)); + ScopedValue v(scope, context->d()->callData->argument(0)); const QString that = v->toQString(); return Encode(QString::localeAwareCompare(value, that)); } ReturnedValue StringPrototype::method_match(CallContext *context) { - if (context->callData->thisObject.isUndefined() || context->callData->thisObject.isNull()) + if (context->d()->callData->thisObject.isUndefined() || context->d()->callData->thisObject.isNull()) return context->throwTypeError(); Scope scope(context); - ScopedString s(scope, context->callData->thisObject.toString(context)); + ScopedString s(scope, context->d()->callData->thisObject.toString(context)); - ScopedValue regexp(scope, context->callData->argument(0)); + ScopedValue regexp(scope, context->d()->callData->argument(0)); Scoped<RegExpObject> rx(scope, regexp); if (!rx) { ScopedCallData callData(scope, 1); callData->args[0] = regexp; - rx = context->engine->regExpCtor.asFunctionObject()->construct(callData); + rx = context->d()->engine->regExpCtor.asFunctionObject()->construct(callData); } if (!rx) // ### CHECK return context->throwTypeError(); - bool global = rx->global; + bool global = rx->global(); // ### use the standard builtin function, not the one that might be redefined in the proto - ScopedString execString(scope, context->engine->newString(QStringLiteral("exec"))); - Scoped<FunctionObject> exec(scope, context->engine->regExpClass->prototype->get(execString)); + ScopedString execString(scope, context->d()->engine->newString(QStringLiteral("exec"))); + Scoped<FunctionObject> exec(scope, context->d()->engine->regExpClass->prototype->get(execString.getPointer())); ScopedCallData callData(scope, 1); callData->thisObject = rx; @@ -408,9 +402,9 @@ ReturnedValue StringPrototype::method_match(CallContext *context) if (!global) return exec->call(callData); - ScopedString lastIndex(scope, context->engine->newString(QStringLiteral("lastIndex"))); - rx->put(lastIndex, ScopedValue(scope, Primitive::fromInt32(0))); - Scoped<ArrayObject> a(scope, context->engine->newArrayObject()); + ScopedString lastIndex(scope, context->d()->engine->newString(QStringLiteral("lastIndex"))); + rx->put(lastIndex.getPointer(), ScopedValue(scope, Primitive::fromInt32(0))); + Scoped<ArrayObject> a(scope, context->d()->engine->newArrayObject()); double previousLastIndex = 0; uint n = 0; @@ -422,11 +416,11 @@ ReturnedValue StringPrototype::method_match(CallContext *context) if (result->isNull()) break; assert(result->isObject()); - index = rx->get(lastIndex, 0); + index = rx->get(lastIndex.getPointer(), 0); double thisIndex = index->toInteger(); if (previousLastIndex == thisIndex) { previousLastIndex = thisIndex + 1; - rx->put(lastIndex, ScopedValue(scope, Primitive::fromDouble(previousLastIndex))); + rx->put(lastIndex.getPointer(), ScopedValue(scope, Primitive::fromDouble(previousLastIndex))); } else { previousLastIndex = thisIndex; } @@ -491,10 +485,10 @@ ReturnedValue StringPrototype::method_replace(CallContext *ctx) { Scope scope(ctx); QString string; - if (StringObject *thisString = ctx->callData->thisObject.asStringObject()) - string = thisString->value.stringValue()->toQString(); + if (StringObject *thisString = ctx->d()->callData->thisObject.asStringObject()) + string = thisString->d()->value.stringValue()->toQString(); else - string = ctx->callData->thisObject.toString(ctx)->toQString(); + string = ctx->d()->callData->thisObject.toString(ctx)->toQString(); int numCaptures = 0; int numStringMatches = 0; @@ -510,7 +504,7 @@ ReturnedValue StringPrototype::method_replace(CallContext *ctx) uint offset = 0; // We extract the pointer here to work around a compiler bug on Android. - Scoped<RegExp> re(scope, regExp->value); + Scoped<RegExp> re(scope, regExp->value()); while (true) { int oldSize = nMatchOffsets; if (allocatedMatchOffsets < nMatchOffsets + re->captureCount() * 2) { @@ -526,14 +520,14 @@ ReturnedValue StringPrototype::method_replace(CallContext *ctx) break; } nMatchOffsets += re->captureCount() * 2; - if (!regExp->global) + if (!regExp->d()->global) break; offset = qMax(offset + 1, matchOffsets[oldSize + 1]); } - if (regExp->global) + if (regExp->global()) regExp->lastIndexProperty(ctx)->value = Primitive::fromUInt32(0); - numStringMatches = nMatchOffsets / (regExp->value->captureCount() * 2); - numCaptures = regExp->value->captureCount(); + numStringMatches = nMatchOffsets / (regExp->value()->captureCount() * 2); + numCaptures = regExp->value()->captureCount(); } else { numCaptures = 1; QString searchString = searchValue->toString(ctx)->toQString(); @@ -563,14 +557,14 @@ ReturnedValue StringPrototype::method_replace(CallContext *ctx) uint end = matchOffsets[idx + 1]; entry = Primitive::undefinedValue(); if (start != JSC::Yarr::offsetNoMatch && end != JSC::Yarr::offsetNoMatch) - entry = ctx->engine->newString(string.mid(start, end - start)); + entry = ctx->d()->engine->newString(string.mid(start, end - start)); callData->args[k] = entry; } uint matchStart = matchOffsets[i * numCaptures * 2]; Q_ASSERT(matchStart >= static_cast<uint>(lastEnd)); uint matchEnd = matchOffsets[i * numCaptures * 2 + 1]; callData->args[numCaptures] = Primitive::fromUInt32(matchStart); - callData->args[numCaptures + 1] = ctx->engine->newString(string); + callData->args[numCaptures + 1] = ctx->d()->engine->newString(string); replacement = searchCallback->call(callData); result += string.midRef(lastEnd, matchStart - lastEnd); @@ -600,7 +594,7 @@ ReturnedValue StringPrototype::method_replace(CallContext *ctx) if (matchOffsets != _matchOffsets) free(matchOffsets); - return ctx->engine->newString(result)->asReturnedValue(); + return ctx->d()->engine->newString(result)->asReturnedValue(); } ReturnedValue StringPrototype::method_search(CallContext *ctx) @@ -614,14 +608,14 @@ ReturnedValue StringPrototype::method_search(CallContext *ctx) if (!regExp) { ScopedCallData callData(scope, 1); callData->args[0] = regExpValue; - regExpValue = ctx->engine->regExpCtor.asFunctionObject()->construct(callData); + regExpValue = ctx->d()->engine->regExpCtor.asFunctionObject()->construct(callData); if (scope.engine->hasException) return Encode::undefined(); regExp = regExpValue->as<RegExpObject>(); Q_ASSERT(regExp); } - uint* matchOffsets = (uint*)alloca(regExp->value->captureCount() * 2 * sizeof(uint)); - uint result = regExp->value->match(string, /*offset*/0, matchOffsets); + uint* matchOffsets = (uint*)alloca(regExp->value()->captureCount() * 2 * sizeof(uint)); + uint result = regExp->value()->match(string, /*offset*/0, matchOffsets); if (result == JSC::Yarr::offsetNoMatch) return Encode(-1); return Encode(result); @@ -630,14 +624,14 @@ ReturnedValue StringPrototype::method_search(CallContext *ctx) ReturnedValue StringPrototype::method_slice(CallContext *ctx) { const QString text = getThisString(ctx); - if (ctx->engine->hasException) + if (ctx->d()->engine->hasException) return Encode::undefined(); const double length = text.length(); - double start = ctx->callData->argc ? ctx->callData->args[0].toInteger() : 0; - double end = (ctx->callData->argc < 2 || ctx->callData->args[1].isUndefined()) - ? length : ctx->callData->args[1].toInteger(); + double start = ctx->d()->callData->argc ? ctx->d()->callData->args[0].toInteger() : 0; + double end = (ctx->d()->callData->argc < 2 || ctx->d()->callData->args[1].isUndefined()) + ? length : ctx->d()->callData->args[1].toInteger(); if (start < 0) start = qMax(length + start, 0.); @@ -653,7 +647,7 @@ ReturnedValue StringPrototype::method_slice(CallContext *ctx) const int intEnd = int(end); int count = qMax(0, intEnd - intStart); - return ctx->engine->newString(text.mid(intStart, count))->asReturnedValue(); + return ctx->d()->engine->newString(text.mid(intStart, count))->asReturnedValue(); } ReturnedValue StringPrototype::method_split(CallContext *ctx) @@ -666,15 +660,15 @@ ReturnedValue StringPrototype::method_split(CallContext *ctx) ScopedValue separatorValue(scope, ctx->argument(0)); ScopedValue limitValue(scope, ctx->argument(1)); - ScopedArrayObject array(scope, ctx->engine->newArrayObject()); + ScopedArrayObject array(scope, ctx->d()->engine->newArrayObject()); if (separatorValue->isUndefined()) { if (limitValue->isUndefined()) { - ScopedString s(scope, ctx->engine->newString(text)); + ScopedString s(scope, ctx->d()->engine->newString(text)); array->push_back(s); return array.asReturnedValue(); } - return ctx->engine->newString(text.left(limitValue->toInteger()))->asReturnedValue(); + return ctx->d()->engine->newString(text.left(limitValue->toInteger()))->asReturnedValue(); } uint limit = limitValue->isUndefined() ? UINT_MAX : limitValue->toUInt32(); @@ -684,55 +678,55 @@ ReturnedValue StringPrototype::method_split(CallContext *ctx) Scoped<RegExpObject> re(scope, separatorValue); if (re) { - if (re->value->pattern().isEmpty()) { + if (re->value()->pattern().isEmpty()) { re = (RegExpObject *)0; - separatorValue = ctx->engine->newString(QString()); + separatorValue = ctx->d()->engine->newString(QString()); } } ScopedString s(scope); if (re) { uint offset = 0; - uint* matchOffsets = (uint*)alloca(re->value->captureCount() * 2 * sizeof(uint)); + uint* matchOffsets = (uint*)alloca(re->value()->captureCount() * 2 * sizeof(uint)); while (true) { - uint result = re->value->match(text, offset, matchOffsets); + uint result = re->value()->match(text, offset, matchOffsets); if (result == JSC::Yarr::offsetNoMatch) break; - array->push_back((s = ctx->engine->newString(text.mid(offset, matchOffsets[0] - offset)))); + array->push_back((s = ctx->d()->engine->newString(text.mid(offset, matchOffsets[0] - offset)))); offset = qMax(offset + 1, matchOffsets[1]); if (array->getLength() >= limit) break; - for (int i = 1; i < re->value->captureCount(); ++i) { + for (int i = 1; i < re->value()->captureCount(); ++i) { uint start = matchOffsets[i * 2]; uint end = matchOffsets[i * 2 + 1]; - array->push_back((s = ctx->engine->newString(text.mid(start, end - start)))); + array->push_back((s = ctx->d()->engine->newString(text.mid(start, end - start)))); if (array->getLength() >= limit) break; } } if (array->getLength() < limit) - array->push_back((s = ctx->engine->newString(text.mid(offset)))); + array->push_back((s = ctx->d()->engine->newString(text.mid(offset)))); } else { QString separator = separatorValue->toString(ctx)->toQString(); if (separator.isEmpty()) { for (uint i = 0; i < qMin(limit, uint(text.length())); ++i) - array->push_back((s = ctx->engine->newString(text.mid(i, 1)))); + array->push_back((s = ctx->d()->engine->newString(text.mid(i, 1)))); return array.asReturnedValue(); } int start = 0; int end; while ((end = text.indexOf(separator, start)) != -1) { - array->push_back((s = ctx->engine->newString(text.mid(start, end - start)))); + array->push_back((s = ctx->d()->engine->newString(text.mid(start, end - start)))); start = end + separator.size(); if (array->getLength() >= limit) break; } if (array->getLength() < limit && start != -1) - array->push_back((s = ctx->engine->newString(text.mid(start)))); + array->push_back((s = ctx->d()->engine->newString(text.mid(start)))); } return array.asReturnedValue(); } @@ -740,16 +734,16 @@ ReturnedValue StringPrototype::method_split(CallContext *ctx) ReturnedValue StringPrototype::method_substr(CallContext *context) { const QString value = getThisString(context); - if (context->engine->hasException) + if (context->d()->engine->hasException) return Encode::undefined(); double start = 0; - if (context->callData->argc > 0) - start = context->callData->args[0].toInteger(); + if (context->d()->callData->argc > 0) + start = context->d()->callData->args[0].toInteger(); double length = +qInf(); - if (context->callData->argc > 1) - length = context->callData->args[1].toInteger(); + if (context->d()->callData->argc > 1) + length = context->d()->callData->args[1].toInteger(); double count = value.length(); if (start < 0) @@ -759,21 +753,21 @@ ReturnedValue StringPrototype::method_substr(CallContext *context) qint32 x = Primitive::toInt32(start); qint32 y = Primitive::toInt32(length); - return context->engine->newString(value.mid(x, y))->asReturnedValue(); + return context->d()->engine->newString(value.mid(x, y))->asReturnedValue(); } ReturnedValue StringPrototype::method_substring(CallContext *context) { QString value = getThisString(context); - if (context->engine->hasException) + if (context->d()->engine->hasException) return Encode::undefined(); int length = value.length(); double start = 0; double end = length; - if (context->callData->argc > 0) - start = context->callData->args[0].toInteger(); + if (context->d()->callData->argc > 0) + start = context->d()->callData->args[0].toInteger(); Scope scope(context); ScopedValue endValue(scope, context->argument(1)); @@ -800,15 +794,15 @@ ReturnedValue StringPrototype::method_substring(CallContext *context) qint32 x = (int)start; qint32 y = (int)(end - start); - return context->engine->newString(value.mid(x, y))->asReturnedValue(); + return context->d()->engine->newString(value.mid(x, y))->asReturnedValue(); } ReturnedValue StringPrototype::method_toLowerCase(CallContext *ctx) { QString value = getThisString(ctx); - if (ctx->engine->hasException) + if (ctx->d()->engine->hasException) return Encode::undefined(); - return ctx->engine->newString(value.toLower())->asReturnedValue(); + return ctx->d()->engine->newString(value.toLower())->asReturnedValue(); } ReturnedValue StringPrototype::method_toLocaleLowerCase(CallContext *ctx) @@ -819,9 +813,9 @@ ReturnedValue StringPrototype::method_toLocaleLowerCase(CallContext *ctx) ReturnedValue StringPrototype::method_toUpperCase(CallContext *ctx) { QString value = getThisString(ctx); - if (ctx->engine->hasException) + if (ctx->d()->engine->hasException) return Encode::undefined(); - return ctx->engine->newString(value.toUpper())->asReturnedValue(); + return ctx->d()->engine->newString(value.toUpper())->asReturnedValue(); } ReturnedValue StringPrototype::method_toLocaleUpperCase(CallContext *ctx) @@ -831,19 +825,19 @@ ReturnedValue StringPrototype::method_toLocaleUpperCase(CallContext *ctx) ReturnedValue StringPrototype::method_fromCharCode(CallContext *context) { - QString str(context->callData->argc, Qt::Uninitialized); + QString str(context->d()->callData->argc, Qt::Uninitialized); QChar *ch = str.data(); - for (int i = 0; i < context->callData->argc; ++i) { - *ch = QChar(context->callData->args[i].toUInt16()); + for (int i = 0; i < context->d()->callData->argc; ++i) { + *ch = QChar(context->d()->callData->args[i].toUInt16()); ++ch; } - return context->engine->newString(str)->asReturnedValue(); + return context->d()->engine->newString(str)->asReturnedValue(); } ReturnedValue StringPrototype::method_trim(CallContext *ctx) { QString s = getThisString(ctx); - if (ctx->engine->hasException) + if (ctx->d()->engine->hasException) return Encode::undefined(); const QChar *chars = s.constData(); @@ -857,5 +851,5 @@ ReturnedValue StringPrototype::method_trim(CallContext *ctx) break; } - return ctx->engine->newString(QString(chars + start, end - start + 1))->asReturnedValue(); + return ctx->d()->engine->newString(QString(chars + start, end - start + 1))->asReturnedValue(); } diff --git a/src/qml/jsruntime/qv4stringobject_p.h b/src/qml/jsruntime/qv4stringobject_p.h index c38fd5b75f..0fc556f849 100644 --- a/src/qml/jsruntime/qv4stringobject_p.h +++ b/src/qml/jsruntime/qv4stringobject_p.h @@ -50,27 +50,32 @@ QT_BEGIN_NAMESPACE namespace QV4 { struct StringObject: Object { - V4_OBJECT + struct Data : Object::Data { + Data(ExecutionEngine *engine, const ValueRef value); + Data(InternalClass *ic); + Value value; + // ### get rid of tmpProperty + mutable Property tmpProperty; + }; + V4_OBJECT(Object) Q_MANAGED_TYPE(StringObject) - Value value; - mutable Property tmpProperty; - StringObject(ExecutionEngine *engine, const ValueRef value); Property *getIndex(uint index) const; static bool deleteIndexedProperty(Managed *m, uint index); protected: - StringObject(InternalClass *ic); - static void advanceIterator(Managed *m, ObjectIterator *it, StringRef name, uint *index, Property *p, PropertyAttributes *attrs); + static void advanceIterator(Managed *m, ObjectIterator *it, String *&name, uint *index, Property *p, PropertyAttributes *attrs); static void markObjects(Managed *that, ExecutionEngine *e); }; struct StringCtor: FunctionObject { - V4_OBJECT - StringCtor(ExecutionContext *scope); + struct Data : FunctionObject::Data { + Data(ExecutionContext *scope); + }; + V4_OBJECT(FunctionObject) static ReturnedValue construct(Managed *m, CallData *callData); static ReturnedValue call(Managed *that, CallData *callData); @@ -78,8 +83,7 @@ struct StringCtor: FunctionObject struct StringPrototype: StringObject { - StringPrototype(InternalClass *ic): StringObject(ic) {} - void init(ExecutionEngine *engine, ObjectRef ctor); + void init(ExecutionEngine *engine, Object *ctor); static ReturnedValue method_toString(CallContext *context); static ReturnedValue method_charAt(CallContext *context); diff --git a/src/qml/jsruntime/qv4value.cpp b/src/qml/jsruntime/qv4value.cpp index e9246f7a14..e122b18892 100644 --- a/src/qml/jsruntime/qv4value.cpp +++ b/src/qml/jsruntime/qv4value.cpp @@ -95,7 +95,7 @@ double Value::toNumberImpl() const if (isString()) return RuntimeHelpers::stringToNumber(stringValue()->toQString()); { - ExecutionContext *ctx = objectValue()->internalClass->engine->currentContext(); + ExecutionContext *ctx = objectValue()->internalClass()->engine->currentContext(); Scope scope(ctx); ScopedValue prim(scope, RuntimeHelpers::toPrimitive(ValueRef::fromRawValue(this), NUMBER_HINT)); return prim->toNumber(); @@ -129,7 +129,7 @@ QString Value::toQStringNoThrow() const if (isString()) return stringValue()->toQString(); { - ExecutionContext *ctx = objectValue()->internalClass->engine->currentContext(); + ExecutionContext *ctx = objectValue()->internalClass()->engine->currentContext(); Scope scope(ctx); ScopedValue ex(scope); bool caughtException = false; @@ -182,7 +182,7 @@ QString Value::toQString() const if (isString()) return stringValue()->toQString(); { - ExecutionContext *ctx = objectValue()->internalClass->engine->currentContext(); + ExecutionContext *ctx = objectValue()->internalClass()->engine->currentContext(); Scope scope(ctx); ScopedValue prim(scope, RuntimeHelpers::toPrimitive(ValueRef::fromRawValue(this), STRING_HINT)); return prim->toQString(); diff --git a/src/qml/jsruntime/qv4value_inl_p.h b/src/qml/jsruntime/qv4value_inl_p.h index 1fe9e1c165..84a8e1adf2 100644 --- a/src/qml/jsruntime/qv4value_inl_p.h +++ b/src/qml/jsruntime/qv4value_inl_p.h @@ -64,13 +64,13 @@ inline bool Value::isString() const { if (!isManaged()) return false; - return managed() && managed()->internalClass->vtable->isString; + return managed() && managed()->internalClass()->vtable->isString; } inline bool Value::isObject() const { if (!isManaged()) return false; - return managed() && managed()->internalClass->vtable->isObject; + return managed() && managed()->internalClass()->vtable->isObject; } inline bool Value::isPrimitive() const diff --git a/src/qml/jsruntime/qv4value_p.h b/src/qml/jsruntime/qv4value_p.h index 29cb8b42ed..7b49db74d9 100644 --- a/src/qml/jsruntime/qv4value_p.h +++ b/src/qml/jsruntime/qv4value_p.h @@ -64,6 +64,8 @@ struct Returned : private T using T::asReturnedValue; }; +struct HeapObject {}; + struct Q_QML_PRIVATE_EXPORT Value { /* @@ -347,6 +349,10 @@ struct Q_QML_PRIVATE_EXPORT Value val = Value::fromManaged(t).val; return *this; } + Value &operator=(HeapObject *o) { + m = reinterpret_cast<Managed *>(o); + return *this; + } template<typename T> Value &operator=(const Scoped<T> &t); @@ -430,7 +436,10 @@ struct TypedValue : public Value { template<typename X> TypedValue &operator =(X *x) { - val = Value::fromManaged(x).val; + m = x; +#if QT_POINTER_SIZE == 4 + tag = Managed_Type; +#endif } TypedValue &operator =(T *t); TypedValue &operator =(const Scoped<T> &v); @@ -441,6 +450,7 @@ struct TypedValue : public Value bool operator!() const { return !managed(); } + operator T *() { return static_cast<T *>(managed()); } T *operator->() { return static_cast<T *>(managed()); } const T *operator->() const { return static_cast<T *>(managed()); } T *getPointer() const { return static_cast<T *>(managed()); } diff --git a/src/qml/jsruntime/qv4variantobject.cpp b/src/qml/jsruntime/qv4variantobject.cpp index 92cc19d8b9..a5b22a2de8 100644 --- a/src/qml/jsruntime/qv4variantobject.cpp +++ b/src/qml/jsruntime/qv4variantobject.cpp @@ -51,18 +51,15 @@ using namespace QV4; DEFINE_OBJECT_VTABLE(VariantObject); -VariantObject::VariantObject(InternalClass *ic) - : Object(ic) - , ExecutionEngine::ScarceResourceData(QVariant()) - , m_vmePropertyReferenceCount(0) +VariantObject::Data::Data(InternalClass *ic) + : Object::Data(ic) { } -VariantObject::VariantObject(ExecutionEngine *engine, const QVariant &value) - : Object(engine->variantClass) - , ExecutionEngine::ScarceResourceData(value) - , m_vmePropertyReferenceCount(0) +VariantObject::Data::Data(ExecutionEngine *engine, const QVariant &value) + : Object::Data(engine->variantClass) { + data = value; if (isScarce()) engine->scarceResources.insert(this); } @@ -89,7 +86,7 @@ QVariant VariantObject::toVariant(const QV4::ValueRef v) return QVariant(); } -bool VariantObject::isScarce() const +bool VariantObject::Data::isScarce() const { QVariant::Type t = data.type(); return t == QVariant::Pixmap || t == QVariant::Image; @@ -98,9 +95,7 @@ bool VariantObject::isScarce() const void VariantObject::destroy(Managed *that) { VariantObject *v = static_cast<VariantObject *>(that); - if (v->isScarce()) - v->node.remove(); - v->~VariantObject(); + v->d()->~Data(); } bool VariantObject::isEqualTo(Managed *m, Managed *other) @@ -109,40 +104,35 @@ bool VariantObject::isEqualTo(Managed *m, Managed *other) assert(lv); if (QV4::VariantObject *rv = other->as<QV4::VariantObject>()) - return lv->data == rv->data; + return lv->d()->data == rv->d()->data; if (QV4::QmlValueTypeWrapper *v = other->as<QmlValueTypeWrapper>()) - return v->isEqual(lv->data); + return v->isEqual(lv->d()->data); return false; } void VariantObject::addVmePropertyReference() { - if (isScarce() && ++m_vmePropertyReferenceCount == 1) { + if (d()->isScarce() && ++d()->vmePropertyReferenceCount == 1) { // remove from the ep->scarceResources list // since it is now no longer eligible to be // released automatically by the engine. - node.remove(); + d()->node.remove(); } } void VariantObject::removeVmePropertyReference() { - if (isScarce() && --m_vmePropertyReferenceCount == 0) { + if (d()->isScarce() && --d()->vmePropertyReferenceCount == 0) { // and add to the ep->scarceResources list // since it is now eligible to be released // automatically by the engine. - internalClass->engine->scarceResources.insert(this); + internalClass()->engine->scarceResources.insert(d()); } } -VariantPrototype::VariantPrototype(InternalClass *ic) - : VariantObject(ic) -{ -} - void VariantPrototype::init() { defineDefaultProperty(QStringLiteral("preserve"), method_preserve, 0); @@ -154,20 +144,20 @@ void VariantPrototype::init() QV4::ReturnedValue VariantPrototype::method_preserve(CallContext *ctx) { Scope scope(ctx); - Scoped<VariantObject> o(scope, ctx->callData->thisObject.as<QV4::VariantObject>()); - if (o && o->isScarce()) - o->node.remove(); + Scoped<VariantObject> o(scope, ctx->d()->callData->thisObject.as<QV4::VariantObject>()); + if (o && o->d()->isScarce()) + o->d()->node.remove(); return Encode::undefined(); } QV4::ReturnedValue VariantPrototype::method_destroy(CallContext *ctx) { Scope scope(ctx); - Scoped<VariantObject> o(scope, ctx->callData->thisObject.as<QV4::VariantObject>()); + Scoped<VariantObject> o(scope, ctx->d()->callData->thisObject.as<QV4::VariantObject>()); if (o) { - if (o->isScarce()) - o->node.remove(); - o->data = QVariant(); + if (o->d()->isScarce()) + o->d()->node.remove(); + o->d()->data = QVariant(); } return Encode::undefined(); } @@ -175,26 +165,26 @@ QV4::ReturnedValue VariantPrototype::method_destroy(CallContext *ctx) QV4::ReturnedValue VariantPrototype::method_toString(CallContext *ctx) { Scope scope(ctx); - Scoped<VariantObject> o(scope, ctx->callData->thisObject.as<QV4::VariantObject>()); + Scoped<VariantObject> o(scope, ctx->d()->callData->thisObject.as<QV4::VariantObject>()); if (!o) return Encode::undefined(); - QString result = o->data.toString(); - if (result.isEmpty() && !o->data.canConvert(QVariant::String)) - result = QString::fromLatin1("QVariant(%0)").arg(QString::fromLatin1(o->data.typeName())); - return Encode(ctx->engine->newString(result)); + QString result = o->d()->data.toString(); + if (result.isEmpty() && !o->d()->data.canConvert(QVariant::String)) + result = QString::fromLatin1("QVariant(%0)").arg(QString::fromLatin1(o->d()->data.typeName())); + return Encode(ctx->d()->engine->newString(result)); } QV4::ReturnedValue VariantPrototype::method_valueOf(CallContext *ctx) { Scope scope(ctx); - Scoped<VariantObject> o(scope, ctx->callData->thisObject.as<QV4::VariantObject>()); + Scoped<VariantObject> o(scope, ctx->d()->callData->thisObject.as<QV4::VariantObject>()); if (o) { - QVariant v = o->data; + QVariant v = o->d()->data; switch (v.type()) { case QVariant::Invalid: return Encode::undefined(); case QVariant::String: - return Encode(ctx->engine->newString(v.toString())); + return Encode(ctx->d()->engine->newString(v.toString())); case QVariant::Int: return Encode(v.toInt()); case QVariant::Double: @@ -206,7 +196,7 @@ QV4::ReturnedValue VariantPrototype::method_valueOf(CallContext *ctx) break; } } - return ctx->callData->thisObject.asReturnedValue(); + return ctx->d()->callData->thisObject.asReturnedValue(); } QT_END_NAMESPACE diff --git a/src/qml/jsruntime/qv4variantobject_p.h b/src/qml/jsruntime/qv4variantobject_p.h index 656608d49b..18e93f6ca7 100644 --- a/src/qml/jsruntime/qv4variantobject_p.h +++ b/src/qml/jsruntime/qv4variantobject_p.h @@ -64,31 +64,33 @@ QT_BEGIN_NAMESPACE namespace QV4 { -struct VariantObject : Object, public ExecutionEngine::ScarceResourceData +struct VariantObject : Object { - V4_OBJECT -public: - VariantObject(InternalClass *ic); - VariantObject(ExecutionEngine *engine, const QVariant &value); + struct Data : Object::Data, public ExecutionEngine::ScarceResourceData + { + Data(InternalClass *ic); + Data(ExecutionEngine *engine, const QVariant &value); + ~Data() { + if (isScarce()) + node.remove(); + } + bool isScarce() const; + int vmePropertyReferenceCount; + }; + V4_OBJECT(Object) static QVariant toVariant(const ValueRef v); void addVmePropertyReference(); void removeVmePropertyReference(); - bool isScarce() const; - int m_vmePropertyReferenceCount; static void destroy(Managed *that); static bool isEqualTo(Managed *m, Managed *other); }; -DEFINE_REF(VariantObject, Object); - struct VariantPrototype : VariantObject { public: - VariantPrototype(InternalClass *ic); - void init(); static ReturnedValue method_preserve(CallContext *ctx); diff --git a/src/qml/jsruntime/qv4vme_moth.cpp b/src/qml/jsruntime/qv4vme_moth.cpp index 8e52ed5a96..7f058bf8b7 100644 --- a/src/qml/jsruntime/qv4vme_moth.cpp +++ b/src/qml/jsruntime/qv4vme_moth.cpp @@ -185,14 +185,14 @@ QV4::ReturnedValue VME::run(QV4::ExecutionContext *context, const uchar *code const uchar *exceptionHandler = 0; - context->lineNumber = -1; - QV4::ExecutionEngine *engine = context->engine; + context->d()->lineNumber = -1; + QV4::ExecutionEngine *engine = context->d()->engine; #ifdef DO_TRACE_INSTR qDebug("Starting VME with context=%p and code=%p", context, code); #endif // DO_TRACE_INSTR - QV4::StringValue * const runtimeStrings = context->compilationUnit->runtimeStrings; + QV4::StringValue * const runtimeStrings = context->d()->compilationUnit->runtimeStrings; // setup lookup scopes int scopeDepth = 0; @@ -200,28 +200,28 @@ QV4::ReturnedValue VME::run(QV4::ExecutionContext *context, const uchar *code QV4::ExecutionContext *scope = context; while (scope) { ++scopeDepth; - scope = scope->outer; + scope = scope->d()->outer; } } QV4::Value **scopes = static_cast<QV4::Value **>(alloca(sizeof(QV4::Value *)*(2 + 2*scopeDepth))); { - scopes[0] = const_cast<QV4::Value *>(context->compilationUnit->data->constants()); + scopes[0] = const_cast<QV4::Value *>(context->d()->compilationUnit->data->constants()); // stack gets setup in push instruction scopes[1] = 0; QV4::ExecutionContext *scope = context; int i = 0; while (scope) { - if (scope->type >= QV4::ExecutionContext::Type_SimpleCallContext) { + if (scope->d()->type >= QV4::ExecutionContext::Type_SimpleCallContext) { QV4::CallContext *cc = static_cast<QV4::CallContext *>(scope); - scopes[2*i + 2] = cc->callData->args; - scopes[2*i + 3] = cc->locals; + scopes[2*i + 2] = cc->d()->callData->args; + scopes[2*i + 3] = cc->d()->locals; } else { scopes[2*i + 2] = 0; scopes[2*i + 3] = 0; } ++i; - scope = scope->outer; + scope = scope->d()->outer; } } @@ -253,7 +253,7 @@ QV4::ReturnedValue VME::run(QV4::ExecutionContext *context, const uchar *code MOTH_BEGIN_INSTR(LoadRegExp) // TRACE(value, "%s", instr.value.toString(context)->toQString().toUtf8().constData()); - VALUE(instr.result) = context->compilationUnit->runtimeRegularExpressions[instr.regExpId]; + VALUE(instr.result) = context->d()->compilationUnit->runtimeRegularExpressions[instr.regExpId]; MOTH_END_INSTR(LoadRegExp) MOTH_BEGIN_INSTR(LoadClosure) @@ -267,7 +267,7 @@ QV4::ReturnedValue VME::run(QV4::ExecutionContext *context, const uchar *code MOTH_BEGIN_INSTR(GetGlobalLookup) TRACE(inline, "property name = %s", runtimeStrings[instr.name]->toQString().toUtf8().constData()); - QV4::Lookup *l = context->lookups + instr.index; + QV4::Lookup *l = context->d()->lookups + instr.index; STOREVALUE(instr.result, l->globalGetter(l, context)); MOTH_END_INSTR(GetGlobalLookup) @@ -282,7 +282,7 @@ QV4::ReturnedValue VME::run(QV4::ExecutionContext *context, const uchar *code MOTH_END_INSTR(LoadElement) MOTH_BEGIN_INSTR(LoadElementLookup) - QV4::Lookup *l = context->lookups + instr.lookup; + QV4::Lookup *l = context->d()->lookups + instr.lookup; STOREVALUE(instr.result, l->indexedGetter(l, VALUEPTR(instr.base), VALUEPTR(instr.index))); MOTH_END_INSTR(LoadElementLookup) @@ -292,7 +292,7 @@ QV4::ReturnedValue VME::run(QV4::ExecutionContext *context, const uchar *code MOTH_END_INSTR(StoreElement) MOTH_BEGIN_INSTR(StoreElementLookup) - QV4::Lookup *l = context->lookups + instr.lookup; + QV4::Lookup *l = context->d()->lookups + instr.lookup; l->indexedSetter(l, VALUEPTR(instr.base), VALUEPTR(instr.index), VALUEPTR(instr.source)); CHECK_EXCEPTION; MOTH_END_INSTR(StoreElementLookup) @@ -302,7 +302,7 @@ QV4::ReturnedValue VME::run(QV4::ExecutionContext *context, const uchar *code MOTH_END_INSTR(LoadProperty) MOTH_BEGIN_INSTR(GetLookup) - QV4::Lookup *l = context->lookups + instr.index; + QV4::Lookup *l = context->d()->lookups + instr.index; STOREVALUE(instr.result, l->getter(l, VALUEPTR(instr.base))); MOTH_END_INSTR(GetLookup) @@ -312,7 +312,7 @@ QV4::ReturnedValue VME::run(QV4::ExecutionContext *context, const uchar *code MOTH_END_INSTR(StoreProperty) MOTH_BEGIN_INSTR(SetLookup) - QV4::Lookup *l = context->lookups + instr.index; + QV4::Lookup *l = context->d()->lookups + instr.index; l->setter(l, VALUEPTR(instr.base), VALUEPTR(instr.source)); CHECK_EXCEPTION; MOTH_END_INSTR(SetLookup) @@ -333,7 +333,7 @@ QV4::ReturnedValue VME::run(QV4::ExecutionContext *context, const uchar *code MOTH_BEGIN_INSTR(Push) TRACE(inline, "stack size: %u", instr.value); stackSize = instr.value; - stack = context->engine->stackPush(stackSize); + stack = context->engine()->stackPush(stackSize); #ifndef QT_NO_DEBUG memset(stack, 0, stackSize * sizeof(QV4::Value)); #endif @@ -342,7 +342,7 @@ QV4::ReturnedValue VME::run(QV4::ExecutionContext *context, const uchar *code MOTH_BEGIN_INSTR(CallValue) #if 0 //def DO_TRACE_INSTR - if (Debugging::Debugger *debugger = context->engine->debugger) { + if (Debugging::Debugger *debugger = context->engine()->debugger) { if (QV4::FunctionObject *o = (VALUE(instr.dest)).asFunctionObject()) { if (Debugging::FunctionDebugInfo *info = debugger->debugInfo(o)) { QString n = debugger->name(o); @@ -655,24 +655,24 @@ QV4::ReturnedValue VME::run(QV4::ExecutionContext *context, const uchar *code MOTH_END_INSTR(BinopContext) MOTH_BEGIN_INSTR(Ret) - context->engine->stackPop(stackSize); + context->engine()->stackPop(stackSize); // TRACE(Ret, "returning value %s", result.toString(context)->toQString().toUtf8().constData()); return VALUE(instr.result).asReturnedValue(); MOTH_END_INSTR(Ret) MOTH_BEGIN_INSTR(Debug) - context->lineNumber = instr.lineNumber; - QV4::Debugging::Debugger *debugger = context->engine->debugger; + context->d()->lineNumber = instr.lineNumber; + QV4::Debugging::Debugger *debugger = context->engine()->debugger; if (debugger && debugger->pauseAtNextOpportunity()) debugger->maybeBreakAtInstruction(); MOTH_END_INSTR(Debug) MOTH_BEGIN_INSTR(Line) - context->lineNumber = instr.lineNumber; + context->d()->lineNumber = instr.lineNumber; MOTH_END_INSTR(Debug) MOTH_BEGIN_INSTR(LoadThis) - VALUE(instr.result) = context->callData->thisObject; + VALUE(instr.result) = context->d()->callData->thisObject; MOTH_END_INSTR(LoadThis) MOTH_BEGIN_INSTR(LoadQmlIdArray) @@ -706,9 +706,9 @@ QV4::ReturnedValue VME::run(QV4::ExecutionContext *context, const uchar *code Q_ASSERT(false); catchException: - Q_ASSERT(context->engine->hasException); + Q_ASSERT(context->engine()->hasException); if (!exceptionHandler) { - context->engine->stackPop(stackSize); + context->engine()->stackPop(stackSize); return QV4::Encode::undefined(); } code = exceptionHandler; @@ -732,7 +732,7 @@ void **VME::instructionJumpTable() QV4::ReturnedValue VME::exec(QV4::ExecutionContext *ctxt, const uchar *code) { VME vme; - QV4::Debugging::Debugger *debugger = ctxt->engine->debugger; + QV4::Debugging::Debugger *debugger = ctxt->engine()->debugger; if (debugger) debugger->enteringFunction(); QV4::ReturnedValue retVal = vme.run(ctxt, code); diff --git a/src/qml/qml/ftw/qhashedstring_p.h b/src/qml/qml/ftw/qhashedstring_p.h index 61a492013d..57217a6bf8 100644 --- a/src/qml/qml/ftw/qhashedstring_p.h +++ b/src/qml/qml/ftw/qhashedstring_p.h @@ -245,7 +245,7 @@ public: } inline bool equals(const QV4::String *string) const { - if (length != string->length() || hash != string->hashValue()) + if (length != string->d()->length() || hash != string->hashValue()) return false; if (isQString()) { QStringDataPtr dd; diff --git a/src/qml/qml/qqml.h b/src/qml/qml/qqml.h index 721f2cc5a8..86cb395c3d 100644 --- a/src/qml/qml/qqml.h +++ b/src/qml/qml/qqml.h @@ -198,6 +198,44 @@ int qmlRegisterUncreatableType(const char *uri, int versionMajor, int versionMin return QQmlPrivate::qmlregister(QQmlPrivate::TypeRegistration, &type); } +template<typename T, typename E> +int qmlRegisterExtendedUncreatableType(const char *uri, int versionMajor, int versionMinor, const char *qmlName, const QString& reason) +{ + QML_GETTYPENAMES + + QQmlAttachedPropertiesFunc attached = QQmlPrivate::attachedPropertiesFunc<E>(); + const QMetaObject * attachedMetaObject = QQmlPrivate::attachedPropertiesMetaObject<E>(); + if (!attached) { + attached = QQmlPrivate::attachedPropertiesFunc<T>(); + attachedMetaObject = QQmlPrivate::attachedPropertiesMetaObject<T>(); + } + + QQmlPrivate::RegisterType type = { + 0, + + qRegisterNormalizedMetaType<T *>(pointerName.constData()), + qRegisterNormalizedMetaType<QQmlListProperty<T> >(listName.constData()), + 0, 0, + reason, + + uri, versionMajor, versionMinor, qmlName, &T::staticMetaObject, + + attached, + attachedMetaObject, + + QQmlPrivate::StaticCastSelector<T,QQmlParserStatus>::cast(), + QQmlPrivate::StaticCastSelector<T,QQmlPropertyValueSource>::cast(), + QQmlPrivate::StaticCastSelector<T,QQmlPropertyValueInterceptor>::cast(), + + QQmlPrivate::createParent<E>, &E::staticMetaObject, + + 0, + 0 + }; + + return QQmlPrivate::qmlregister(QQmlPrivate::TypeRegistration, &type); +} + template<typename T> int qmlRegisterType(const char *uri, int versionMajor, int versionMinor, const char *qmlName) { @@ -414,6 +452,45 @@ int qmlRegisterCustomType(const char *uri, int versionMajor, int versionMinor, return QQmlPrivate::qmlregister(QQmlPrivate::TypeRegistration, &type); } +template<typename T, typename E> +int qmlRegisterCustomExtendedType(const char *uri, int versionMajor, int versionMinor, + const char *qmlName, QQmlCustomParser *parser) +{ + QML_GETTYPENAMES + + QQmlAttachedPropertiesFunc attached = QQmlPrivate::attachedPropertiesFunc<E>(); + const QMetaObject * attachedMetaObject = QQmlPrivate::attachedPropertiesMetaObject<E>(); + if (!attached) { + attached = QQmlPrivate::attachedPropertiesFunc<T>(); + attachedMetaObject = QQmlPrivate::attachedPropertiesMetaObject<T>(); + } + + QQmlPrivate::RegisterType type = { + 0, + + qRegisterNormalizedMetaType<T *>(pointerName.constData()), + qRegisterNormalizedMetaType<QQmlListProperty<T> >(listName.constData()), + sizeof(T), QQmlPrivate::createInto<T>, + QString(), + + uri, versionMajor, versionMinor, qmlName, &T::staticMetaObject, + + attached, + attachedMetaObject, + + QQmlPrivate::StaticCastSelector<T,QQmlParserStatus>::cast(), + QQmlPrivate::StaticCastSelector<T,QQmlPropertyValueSource>::cast(), + QQmlPrivate::StaticCastSelector<T,QQmlPropertyValueInterceptor>::cast(), + + QQmlPrivate::createParent<E>, &E::staticMetaObject, + + parser, + 0 + }; + + return QQmlPrivate::qmlregister(QQmlPrivate::TypeRegistration, &type); +} + class QQmlContext; class QQmlEngine; class QJSValue; diff --git a/src/qml/qml/qqmlbinding.cpp b/src/qml/qml/qqmlbinding.cpp index 571d78312e..1ba7a8091d 100644 --- a/src/qml/qml/qqmlbinding.cpp +++ b/src/qml/qml/qqmlbinding.cpp @@ -71,34 +71,6 @@ QQmlAbstractBinding::VTable QQmlBinding_vtable = { QQmlBinding::Identifier QQmlBinding::Invalid = -1; -QQmlBinding * -QQmlBinding::createBinding(Identifier id, QObject *obj, QQmlContext *ctxt) -{ - if (id < 0) - return 0; - - QQmlBinding *rv = 0; - - QQmlContextData *ctxtdata = QQmlContextData::get(ctxt); - QQmlEnginePrivate *engine = QQmlEnginePrivate::get(ctxt->engine()); - if (engine && ctxtdata && !ctxtdata->url.isEmpty()) { - QQmlTypeData *typeData = engine->typeLoader.getType(ctxtdata->url); - Q_ASSERT(typeData); - - if (QQmlCompiledData *cdata = typeData->compiledData()) { - QV4::ExecutionEngine *v4 = engine->v4engine(); - QV4::Scope valueScope(v4); - QV4::Function *runtimeFunction = cdata->compilationUnit->runtimeFunctions[cdata->customParserBindings[id]]; - QV4::ScopedValue function(valueScope, QV4::QmlBindingWrapper::createQmlCallableForFunction(ctxtdata, obj, runtimeFunction)); - rv = new QQmlBinding(function, obj, ctxtdata); - } - - typeData->release(); - } - - return rv; -} - static QQmlJavaScriptExpression::VTable QQmlBinding_jsvtable = { QQmlBinding::expressionIdentifier, QQmlBinding::expressionChanged @@ -134,7 +106,7 @@ QQmlBinding::QQmlBinding(const QQmlScriptString &script, QObject *obj, QQmlConte Q_ASSERT(typeData); if (QQmlCompiledData *cdata = typeData->compiledData()) { - url = cdata->name; + url = cdata->fileName(); if (scriptPrivate->bindingId != QQmlBinding::Invalid) runtimeFunction = cdata->compilationUnit->runtimeFunctions.at(scriptPrivate->bindingId); } @@ -213,13 +185,13 @@ void QQmlBinding::update(QQmlPropertyPrivate::WriteFlags flags) QV4::Scope scope(ep->v4engine()); QV4::ScopedFunctionObject f(scope, v4function.value()); Q_ASSERT(f); - if (f->bindingKeyFlag) { - QQmlSourceLocation loc = f->as<QV4::QQmlBindingFunction>()->bindingLocation; + if (f->bindingKeyFlag()) { + QQmlSourceLocation loc = f->as<QV4::QQmlBindingFunction>()->d()->bindingLocation; url = loc.sourceFile; lineNumber = loc.line; columnNumber = loc.column; } else { - QV4::Function *function = f->asFunctionObject()->function; + QV4::Function *function = f->asFunctionObject()->function(); Q_ASSERT(function); url = function->sourceFile(); @@ -312,7 +284,7 @@ QString QQmlBinding::expressionIdentifier(QQmlJavaScriptExpression *e) QQmlEnginePrivate *ep = QQmlEnginePrivate::get(This->context()->engine); QV4::Scope scope(ep->v4engine()); QV4::ScopedValue f(scope, This->v4function.value()); - QV4::Function *function = f->asFunctionObject()->function; + QV4::Function *function = f->asFunctionObject()->function(); QString url = function->sourceFile(); quint16 lineNumber = function->compiledFunction->location.line; diff --git a/src/qml/qml/qqmlbinding_p.h b/src/qml/qml/qqmlbinding_p.h index 3c2c832e0c..879129fe85 100644 --- a/src/qml/qml/qqmlbinding_p.h +++ b/src/qml/qml/qqmlbinding_p.h @@ -112,8 +112,6 @@ public: typedef int Identifier; static Identifier Invalid; - static QQmlBinding *createBinding(Identifier, QObject *, QQmlContext *); - QVariant evaluate(); static QString expressionIdentifier(QQmlJavaScriptExpression *); diff --git a/src/qml/qml/qqmlboundsignal.cpp b/src/qml/qml/qqmlboundsignal.cpp index 876f367097..cec5c31898 100644 --- a/src/qml/qml/qqmlboundsignal.cpp +++ b/src/qml/qml/qqmlboundsignal.cpp @@ -190,7 +190,7 @@ QV4::Function *QQmlBoundSignalExpression::function() const Q_ASSERT (context() && engine()); QV4::Scope scope(QQmlEnginePrivate::get(engine())->v4engine()); QV4::Scoped<QV4::FunctionObject> v(scope, m_v8function.value()); - return v ? v->function : 0; + return v ? v->function() : 0; } return 0; } diff --git a/src/qml/qml/qqmlcompiler_p.h b/src/qml/qml/qqmlcompiler_p.h index f3b6f621ce..129d312ad1 100644 --- a/src/qml/qml/qqmlcompiler_p.h +++ b/src/qml/qml/qqmlcompiler_p.h @@ -91,8 +91,8 @@ public: QQmlEngine *engine; - QString name; - QUrl url; + QString fileName() const { return compilationUnit->fileName(); } + QUrl url() const { return QUrl(fileName()); } QQmlTypeNameCache *importCache; int metaTypeId; @@ -136,13 +136,8 @@ public: // index in first hash is component index, hash inside maps from object index in that scope to integer id QHash<int, QHash<int, int> > objectIndexToIdPerComponent; QHash<int, int> objectIndexToIdForRoot; - // hash key is object index - struct CustomParserData { - QByteArray compilationArtifact; // produced by custom parser - QBitArray bindings; // bindings covered by the custom parser - }; - QHash<int, CustomParserData> customParserData; - QVector<int> customParserBindings; // index is binding identifier, value is compiled function index. + // hash key is object index, value is indicies of bindings covered by custom parser + QHash<int, QBitArray> customParserBindings; QHash<int, QBitArray> deferredBindingsPerObject; // index is object index int totalBindingsCount; // Number of bindings used in this type int totalParserStatusCount; // Number of instantiated types that are QQmlParserStatus subclasses @@ -154,9 +149,6 @@ public: bool isInitialized() const { return hasEngine(); } void initialize(QQmlEngine *); - QV4::Function *functionForBindingId(int bindingId) const - { return compilationUnit->runtimeFunctions[customParserBindings[bindingId]]; } - protected: virtual void destroy(); // From QQmlRefCount virtual void clear(); // From QQmlCleanup diff --git a/src/qml/qml/qqmlcomponent.cpp b/src/qml/qml/qqmlcomponent.cpp index 68f950d840..616f54d174 100644 --- a/src/qml/qml/qqmlcomponent.cpp +++ b/src/qml/qml/qqmlcomponent.cpp @@ -592,7 +592,7 @@ QQmlComponent::QQmlComponent(QQmlEngine *engine, QQmlCompiledData *cc, int start d->cc = cc; cc->addref(); d->start = start; - d->url = cc->url; + d->url = cc->url(); d->progress = 1.0; } @@ -1079,11 +1079,18 @@ void QQmlComponent::create(QQmlIncubator &incubator, QQmlContext *context, class QQmlComponentIncubator; -class QmlIncubatorObject : public QV4::Object +struct QmlIncubatorObject : public QV4::Object { - V4_OBJECT -public: - QmlIncubatorObject(QV8Engine *engine, QQmlIncubator::IncubationMode = QQmlIncubator::Asynchronous); + struct Data : QV4::Object::Data { + Data(QV8Engine *engine, QQmlIncubator::IncubationMode = QQmlIncubator::Asynchronous); + QScopedPointer<QQmlComponentIncubator> incubator; + QV8Engine *v8; + QPointer<QObject> parent; + QV4::Value valuemap; + QV4::Value qmlGlobal; + QV4::Value statusChanged; + }; + V4_OBJECT(QV4::Object) static QV4::ReturnedValue method_get_statusChanged(QV4::CallContext *ctx); static QV4::ReturnedValue method_set_statusChanged(QV4::CallContext *ctx); @@ -1094,13 +1101,6 @@ public: static void destroy(Managed *that); static void markObjects(Managed *that, QV4::ExecutionEngine *e); - QScopedPointer<QQmlComponentIncubator> incubator; - QV8Engine *v8; - QPointer<QObject> parent; - QV4::Value valuemap; - QV4::Value qmlGlobal; - QV4::Value m_statusChanged; - void statusChanged(QQmlIncubator::Status); void setInitialState(QObject *); }; @@ -1110,20 +1110,24 @@ DEFINE_OBJECT_VTABLE(QmlIncubatorObject); class QQmlComponentIncubator : public QQmlIncubator { public: - QQmlComponentIncubator(QmlIncubatorObject *inc, IncubationMode mode) + QQmlComponentIncubator(QmlIncubatorObject::Data *inc, IncubationMode mode) : QQmlIncubator(mode) , incubatorObject(inc) {} virtual void statusChanged(Status s) { - incubatorObject->statusChanged(s); + QV4::Scope scope(incubatorObject->internalClass->engine); + QV4::Scoped<QmlIncubatorObject> i(scope, incubatorObject); + i->statusChanged(s); } virtual void setInitialState(QObject *o) { - incubatorObject->setInitialState(o); + QV4::Scope scope(incubatorObject->internalClass->engine); + QV4::Scoped<QmlIncubatorObject> i(scope, incubatorObject); + i->setInitialState(o); } - QmlIncubatorObject *incubatorObject; + QmlIncubatorObject::Data *incubatorObject; }; @@ -1359,17 +1363,17 @@ void QQmlComponent::incubateObject(QQmlV4Function *args) QQmlComponentExtension *e = componentExtension(args->engine()); - QV4::Scoped<QmlIncubatorObject> r(scope, new (v4->memoryManager) QmlIncubatorObject(args->engine(), mode)); + QV4::Scoped<QmlIncubatorObject> r(scope, v4->memoryManager->alloc<QmlIncubatorObject>(args->engine(), mode)); QV4::ScopedObject p(scope, e->incubationProto.value()); r->setPrototype(p.getPointer()); if (!valuemap->isUndefined()) { - r->valuemap = valuemap; - r->qmlGlobal = args->qmlGlobal(); + r->d()->valuemap = valuemap; + r->d()->qmlGlobal = args->qmlGlobal(); } - r->parent = parent; + r->d()->parent = parent; - QQmlIncubator *incubator = r.getPointer()->incubator.data(); + QQmlIncubator *incubator = r.getPointer()->d()->incubator.data(); create(*incubator, creationContext()); if (incubator->status() == QQmlIncubator::Null) { @@ -1419,21 +1423,21 @@ QQmlComponentExtension::QQmlComponentExtension(QV8Engine *engine) QV4::ReturnedValue QmlIncubatorObject::method_get_object(QV4::CallContext *ctx) { QV4::Scope scope(ctx); - QV4::Scoped<QmlIncubatorObject> o(scope, ctx->callData->thisObject.as<QmlIncubatorObject>()); + QV4::Scoped<QmlIncubatorObject> o(scope, ctx->d()->callData->thisObject.as<QmlIncubatorObject>()); if (!o) return ctx->throwTypeError(); - return QV4::QObjectWrapper::wrap(ctx->engine, o->incubator->object()); + return QV4::QObjectWrapper::wrap(ctx->d()->engine, o->d()->incubator->object()); } QV4::ReturnedValue QmlIncubatorObject::method_forceCompletion(QV4::CallContext *ctx) { QV4::Scope scope(ctx); - QV4::Scoped<QmlIncubatorObject> o(scope, ctx->callData->thisObject.as<QmlIncubatorObject>()); + QV4::Scoped<QmlIncubatorObject> o(scope, ctx->d()->callData->thisObject.as<QmlIncubatorObject>()); if (!o) return ctx->throwTypeError(); - o->incubator->forceCompletion(); + o->d()->incubator->forceCompletion(); return QV4::Encode::undefined(); } @@ -1441,32 +1445,32 @@ QV4::ReturnedValue QmlIncubatorObject::method_forceCompletion(QV4::CallContext * QV4::ReturnedValue QmlIncubatorObject::method_get_status(QV4::CallContext *ctx) { QV4::Scope scope(ctx); - QV4::Scoped<QmlIncubatorObject> o(scope, ctx->callData->thisObject.as<QmlIncubatorObject>()); + QV4::Scoped<QmlIncubatorObject> o(scope, ctx->d()->callData->thisObject.as<QmlIncubatorObject>()); if (!o) return ctx->throwTypeError(); - return QV4::Encode(o->incubator->status()); + return QV4::Encode(o->d()->incubator->status()); } QV4::ReturnedValue QmlIncubatorObject::method_get_statusChanged(QV4::CallContext *ctx) { QV4::Scope scope(ctx); - QV4::Scoped<QmlIncubatorObject> o(scope, ctx->callData->thisObject.as<QmlIncubatorObject>()); + QV4::Scoped<QmlIncubatorObject> o(scope, ctx->d()->callData->thisObject.as<QmlIncubatorObject>()); if (!o) return ctx->throwTypeError(); - return o->m_statusChanged.asReturnedValue(); + return o->d()->statusChanged.asReturnedValue(); } QV4::ReturnedValue QmlIncubatorObject::method_set_statusChanged(QV4::CallContext *ctx) { QV4::Scope scope(ctx); - QV4::Scoped<QmlIncubatorObject> o(scope, ctx->callData->thisObject.as<QmlIncubatorObject>()); - if (!o || ctx->callData->argc < 1) + QV4::Scoped<QmlIncubatorObject> o(scope, ctx->d()->callData->thisObject.as<QmlIncubatorObject>()); + if (!o || ctx->d()->callData->argc < 1) return ctx->throwTypeError(); - o->m_statusChanged = ctx->callData->args[0]; + o->d()->statusChanged = ctx->d()->callData->args[0]; return QV4::Encode::undefined(); } @@ -1474,65 +1478,63 @@ QQmlComponentExtension::~QQmlComponentExtension() { } -QmlIncubatorObject::QmlIncubatorObject(QV8Engine *engine, QQmlIncubator::IncubationMode m) - : Object(QV8Engine::getV4(engine)) +QmlIncubatorObject::Data::Data(QV8Engine *engine, QQmlIncubator::IncubationMode m) + : Object::Data(QV8Engine::getV4(engine)) + , v8(engine) + , valuemap(QV4::Primitive::undefinedValue()) + , qmlGlobal(QV4::Primitive::undefinedValue()) + , statusChanged(QV4::Primitive::undefinedValue()) { - incubator.reset(new QQmlComponentIncubator(this, m)); - v8 = engine; setVTable(staticVTable()); - valuemap = QV4::Primitive::undefinedValue(); - qmlGlobal = QV4::Primitive::undefinedValue(); - m_statusChanged = QV4::Primitive::undefinedValue(); + incubator.reset(new QQmlComponentIncubator(this, m)); } void QmlIncubatorObject::setInitialState(QObject *o) { - QQmlComponent_setQmlParent(o, parent); + QQmlComponent_setQmlParent(o, d()->parent); - if (!valuemap.isUndefined()) { - QV4::ExecutionEngine *v4 = QV8Engine::getV4(v8); + if (!d()->valuemap.isUndefined()) { + QV4::ExecutionEngine *v4 = QV8Engine::getV4(d()->v8); QV4::Scope scope(v4); - QV4::Scoped<QV4::FunctionObject> f(scope, QV4::Script::evaluate(v4, QString::fromLatin1(INITIALPROPERTIES_SOURCE), qmlGlobal)); + QV4::Scoped<QV4::FunctionObject> f(scope, QV4::Script::evaluate(v4, QString::fromLatin1(INITIALPROPERTIES_SOURCE), d()->qmlGlobal.asObject())); QV4::ScopedCallData callData(scope, 2); callData->thisObject = v4->globalObject; callData->args[0] = QV4::QObjectWrapper::wrap(v4, o); - callData->args[1] = valuemap; + callData->args[1] = d()->valuemap; f->call(callData); } } void QmlIncubatorObject::destroy(Managed *that) { - QmlIncubatorObject *o = that->as<QmlIncubatorObject>(); - Q_ASSERT(o); - o->~QmlIncubatorObject(); + that->as<QmlIncubatorObject>()->d()->~Data(); } void QmlIncubatorObject::markObjects(QV4::Managed *that, QV4::ExecutionEngine *e) { QmlIncubatorObject *o = that->as<QmlIncubatorObject>(); Q_ASSERT(o); - o->valuemap.mark(e); - o->qmlGlobal.mark(e); - o->m_statusChanged.mark(e); + o->d()->valuemap.mark(e); + o->d()->qmlGlobal.mark(e); + o->d()->statusChanged.mark(e); Object::markObjects(that, e); } void QmlIncubatorObject::statusChanged(QQmlIncubator::Status s) { - QV4::Scope scope(QV8Engine::getV4(v8)); + QV4::Scope scope(QV8Engine::getV4(d()->v8)); // hold the incubated object in a scoped value to prevent it's destruction before this method returns - QV4::ScopedObject incubatedObject(scope, QV4::QObjectWrapper::wrap(scope.engine, incubator->object())); + QV4::ScopedObject incubatedObject(scope, QV4::QObjectWrapper::wrap(scope.engine, d()->incubator->object())); if (s == QQmlIncubator::Ready) { - Q_ASSERT(QQmlData::get(incubator->object())); - QQmlData::get(incubator->object())->explicitIndestructibleSet = false; - QQmlData::get(incubator->object())->indestructible = false; + Q_ASSERT(QQmlData::get(d()->incubator->object())); + QQmlData::get(d()->incubator->object())->explicitIndestructibleSet = false; + QQmlData::get(d()->incubator->object())->indestructible = false; } - QV4::ScopedFunctionObject f(scope, m_statusChanged); + QV4::ScopedFunctionObject f(scope, d()->statusChanged); if (f) { QV4::ExecutionContext *ctx = scope.engine->currentContext(); QV4::ScopedCallData callData(scope, 1); @@ -1542,7 +1544,7 @@ void QmlIncubatorObject::statusChanged(QQmlIncubator::Status s) if (scope.hasException()) { ctx->catchException(); QQmlError error = QV4::ExecutionEngine::catchExceptionAsQmlError(ctx); - QQmlEnginePrivate::warning(QQmlEnginePrivate::get(v8->engine()), error); + QQmlEnginePrivate::warning(QQmlEnginePrivate::get(d()->v8->engine()), error); } } } diff --git a/src/qml/qml/qqmlcontextwrapper.cpp b/src/qml/qml/qqmlcontextwrapper.cpp index a5574b706a..83ef8c6230 100644 --- a/src/qml/qml/qqmlcontextwrapper.cpp +++ b/src/qml/qml/qqmlcontextwrapper.cpp @@ -61,15 +61,18 @@ using namespace QV4; DEFINE_OBJECT_VTABLE(QmlContextWrapper); -QmlContextWrapper::QmlContextWrapper(QV8Engine *engine, QQmlContextData *context, QObject *scopeObject, bool ownsContext) - : Object(QV8Engine::getV4(engine)), - readOnly(true), ownsContext(ownsContext), isNullWrapper(false), - context(context), scopeObject(scopeObject), idObjectsWrapper(0) +QmlContextWrapper::Data::Data(QV8Engine *engine, QQmlContextData *context, QObject *scopeObject, bool ownsContext) + : Object::Data(QV8Engine::getV4(engine)) + , readOnly(true) + , ownsContext(ownsContext) + , isNullWrapper(false) + , context(context) + , scopeObject(scopeObject) { setVTable(staticVTable()); } -QmlContextWrapper::~QmlContextWrapper() +QmlContextWrapper::Data::~Data() { if (context && ownsContext) context->destroy(); @@ -80,7 +83,7 @@ ReturnedValue QmlContextWrapper::qmlScope(QV8Engine *v8, QQmlContextData *ctxt, ExecutionEngine *v4 = QV8Engine::getV4(v8); Scope valueScope(v4); - Scoped<QmlContextWrapper> w(valueScope, new (v4->memoryManager) QmlContextWrapper(v8, ctxt, scope)); + Scoped<QmlContextWrapper> w(valueScope, v4->memoryManager->alloc<QmlContextWrapper>(v8, ctxt, scope)); return w.asReturnedValue(); } @@ -94,8 +97,8 @@ ReturnedValue QmlContextWrapper::urlScope(QV8Engine *v8, const QUrl &url) context->isInternal = true; context->isJSContext = true; - Scoped<QmlContextWrapper> w(scope, new (v4->memoryManager) QmlContextWrapper(v8, context, 0, true)); - w->isNullWrapper = true; + Scoped<QmlContextWrapper> w(scope, v4->memoryManager->alloc<QmlContextWrapper>(v8, context, (QObject*)0, true)); + w->d()->isNullWrapper = true; return w.asReturnedValue(); } @@ -127,11 +130,11 @@ void QmlContextWrapper::takeContextOwnership(const ValueRef qmlglobal) Scope scope(v4); QV4::Scoped<QmlContextWrapper> c(scope, qmlglobal); Q_ASSERT(c); - c->ownsContext = true; + c->d()->ownsContext = true; } -ReturnedValue QmlContextWrapper::get(Managed *m, const StringRef name, bool *hasProperty) +ReturnedValue QmlContextWrapper::get(Managed *m, String *name, bool *hasProperty) { QV4::ExecutionEngine *v4 = m->engine(); QV4::Scope scope(v4); @@ -149,10 +152,10 @@ ReturnedValue QmlContextWrapper::get(Managed *m, const StringRef name, bool *has return result.asReturnedValue(); } - if (resource->isNullWrapper) + if (resource->d()->isNullWrapper) return Object::get(m, name, hasProperty); - if (QV4::QmlContextWrapper::callingContext(v4) != resource->context) + if (QV4::QmlContextWrapper::callingContext(v4) != resource->d()->context) return Object::get(m, name, hasProperty); result = Object::get(m, name, &hasProp); @@ -211,7 +214,7 @@ ReturnedValue QmlContextWrapper::get(Managed *m, const StringRef name, bool *has while (context) { // Search context properties if (context->propertyNames.count()) { - int propertyIdx = context->propertyNames.value(name.getPointer()); + int propertyIdx = context->propertyNames.value(name); if (propertyIdx != -1) { @@ -247,7 +250,7 @@ ReturnedValue QmlContextWrapper::get(Managed *m, const StringRef name, bool *has if (scopeObject) { bool hasProp = false; QV4::ScopedValue result(scope, QV4::QObjectWrapper::getQmlProperty(v4->currentContext(), context, scopeObject, - name.getPointer(), QV4::QObjectWrapper::CheckRevision, &hasProp)); + name, QV4::QObjectWrapper::CheckRevision, &hasProp)); if (hasProp) { if (hasProperty) *hasProperty = true; @@ -260,7 +263,7 @@ ReturnedValue QmlContextWrapper::get(Managed *m, const StringRef name, bool *has // Search context object if (context->contextObject) { bool hasProp = false; - result = QV4::QObjectWrapper::getQmlProperty(v4->currentContext(), context, context->contextObject, name.getPointer(), QV4::QObjectWrapper::CheckRevision, &hasProp); + result = QV4::QObjectWrapper::getQmlProperty(v4->currentContext(), context, context->contextObject, name, QV4::QObjectWrapper::CheckRevision, &hasProp); if (hasProp) { if (hasProperty) *hasProperty = true; @@ -276,7 +279,7 @@ ReturnedValue QmlContextWrapper::get(Managed *m, const StringRef name, bool *has return Primitive::undefinedValue().asReturnedValue(); } -void QmlContextWrapper::put(Managed *m, const StringRef name, const ValueRef value) +void QmlContextWrapper::put(Managed *m, String *name, const ValueRef value) { ExecutionEngine *v4 = m->engine(); QV4::Scope scope(v4); @@ -295,11 +298,11 @@ void QmlContextWrapper::put(Managed *m, const StringRef name, const ValueRef val return; } - if (wrapper->isNullWrapper) { - if (wrapper && wrapper->readOnly) { + if (wrapper->d()->isNullWrapper) { + if (wrapper && wrapper->d()->readOnly) { QString error = QLatin1String("Invalid write to global property \"") + name->toQString() + QLatin1Char('"'); - Scoped<String> e(scope, v4->currentContext()->engine->newString(error)); + Scoped<String> e(scope, v4->currentContext()->d()->engine->newString(error)); v4->currentContext()->throwError(e); return; } @@ -322,18 +325,18 @@ void QmlContextWrapper::put(Managed *m, const StringRef name, const ValueRef val while (context) { // Search context properties - if (context->propertyNames.count() && -1 != context->propertyNames.value(name.getPointer())) + if (context->propertyNames.count() && -1 != context->propertyNames.value(name)) return; // Search scope object if (scopeObject && - QV4::QObjectWrapper::setQmlProperty(v4->currentContext(), context, scopeObject, name.getPointer(), QV4::QObjectWrapper::CheckRevision, value)) + QV4::QObjectWrapper::setQmlProperty(v4->currentContext(), context, scopeObject, name, QV4::QObjectWrapper::CheckRevision, value)) return; scopeObject = 0; // Search context object if (context->contextObject && - QV4::QObjectWrapper::setQmlProperty(v4->currentContext(), context, context->contextObject, name.getPointer(), QV4::QObjectWrapper::CheckRevision, value)) + QV4::QObjectWrapper::setQmlProperty(v4->currentContext(), context, context->contextObject, name, QV4::QObjectWrapper::CheckRevision, value)) return; context = context->parent; @@ -341,7 +344,7 @@ void QmlContextWrapper::put(Managed *m, const StringRef name, const ValueRef val expressionContext->unresolvedNames = true; - if (wrapper->readOnly) { + if (wrapper->d()->readOnly) { QString error = QLatin1String("Invalid write to global property \"") + name->toQString() + QLatin1Char('"'); v4->currentContext()->throwError(error); @@ -353,14 +356,14 @@ void QmlContextWrapper::put(Managed *m, const StringRef name, const ValueRef val void QmlContextWrapper::destroy(Managed *that) { - static_cast<QmlContextWrapper *>(that)->~QmlContextWrapper(); + static_cast<QmlContextWrapper *>(that)->d()->~Data(); } void QmlContextWrapper::markObjects(Managed *m, ExecutionEngine *engine) { QmlContextWrapper *This = static_cast<QmlContextWrapper*>(m); - if (This->idObjectsWrapper) - This->idObjectsWrapper->mark(engine); + if (This->d()->idObjectsWrapper) + This->d()->idObjectsWrapper->mark(engine); Object::markObjects(m, engine); } @@ -409,19 +412,21 @@ void QmlContextWrapper::registerQmlDependencies(ExecutionEngine *engine, const C ReturnedValue QmlContextWrapper::idObjectsArray() { - if (!idObjectsWrapper) { + if (!d()->idObjectsWrapper) { ExecutionEngine *v4 = engine(); - idObjectsWrapper = new (v4->memoryManager) QQmlIdObjectsArray(v4, this); + Scope scope(v4); + Scoped<QQmlIdObjectsArray> a(scope, v4->memoryManager->alloc<QQmlIdObjectsArray>(v4, this)); + d()->idObjectsWrapper = a.getPointer(); } - return idObjectsWrapper->asReturnedValue(); + return d()->idObjectsWrapper->asReturnedValue(); } -ReturnedValue QmlContextWrapper::qmlSingletonWrapper(QV8Engine *v8, const StringRef &name) +ReturnedValue QmlContextWrapper::qmlSingletonWrapper(QV8Engine *v8, String *name) { - if (!context->imports) + if (!d()->context->imports) return Encode::undefined(); // Search for attached properties, enums and imported scripts - QQmlTypeNameCache::Result r = context->imports->query(name); + QQmlTypeNameCache::Result r = d()->context->imports->query(name); Q_ASSERT(r.isValid()); Q_ASSERT(r.type); @@ -439,8 +444,8 @@ ReturnedValue QmlContextWrapper::qmlSingletonWrapper(QV8Engine *v8, const String DEFINE_OBJECT_VTABLE(QQmlIdObjectsArray); -QQmlIdObjectsArray::QQmlIdObjectsArray(ExecutionEngine *engine, QmlContextWrapper *contextWrapper) - : Object(engine) +QQmlIdObjectsArray::Data::Data(ExecutionEngine *engine, QmlContextWrapper *contextWrapper) + : Object::Data(engine) , contextWrapper(contextWrapper) { setVTable(staticVTable()); @@ -449,7 +454,7 @@ QQmlIdObjectsArray::QQmlIdObjectsArray(ExecutionEngine *engine, QmlContextWrappe ReturnedValue QQmlIdObjectsArray::getIndexed(Managed *m, uint index, bool *hasProperty) { QQmlIdObjectsArray *This = static_cast<QQmlIdObjectsArray*>(m); - QQmlContextData *context = This->contextWrapper->getContext(); + QQmlContextData *context = This->d()->contextWrapper->getContext(); if (!context) { if (hasProperty) *hasProperty = false; @@ -475,7 +480,7 @@ ReturnedValue QQmlIdObjectsArray::getIndexed(Managed *m, uint index, bool *hasPr void QQmlIdObjectsArray::markObjects(Managed *that, ExecutionEngine *engine) { QQmlIdObjectsArray *This = static_cast<QQmlIdObjectsArray*>(that); - This->contextWrapper->mark(engine); + This->d()->contextWrapper->mark(engine); Object::markObjects(that, engine); } diff --git a/src/qml/qml/qqmlcontextwrapper_p.h b/src/qml/qml/qqmlcontextwrapper_p.h index 3facf71aa0..d6f25ac79a 100644 --- a/src/qml/qml/qqmlcontextwrapper_p.h +++ b/src/qml/qml/qqmlcontextwrapper_p.h @@ -73,9 +73,18 @@ struct QQmlIdObjectsArray; struct Q_QML_EXPORT QmlContextWrapper : Object { - V4_OBJECT - QmlContextWrapper(QV8Engine *engine, QQmlContextData *context, QObject *scopeObject, bool ownsContext = false); - ~QmlContextWrapper(); + struct Data : Object::Data { + Data(QV8Engine *engine, QQmlContextData *context, QObject *scopeObject, bool ownsContext = false); + ~Data(); + bool readOnly; + bool ownsContext; + bool isNullWrapper; + + QQmlGuardedContextData context; + QPointer<QObject> scopeObject; + QQmlIdObjectsArray *idObjectsWrapper; + }; + V4_OBJECT(Object) static ReturnedValue qmlScope(QV8Engine *e, QQmlContextData *ctxt, QObject *scope); static ReturnedValue urlScope(QV8Engine *e, const QUrl &); @@ -83,41 +92,35 @@ struct Q_QML_EXPORT QmlContextWrapper : Object static QQmlContextData *callingContext(ExecutionEngine *v4); static void takeContextOwnership(const ValueRef qmlglobal); - inline QObject *getScopeObject() const { return scopeObject; } - inline QQmlContextData *getContext() const { return context; } + inline QObject *getScopeObject() const { return d()->scopeObject; } + inline QQmlContextData *getContext() const { return d()->context; } static QQmlContextData *getContext(const ValueRef value); - void setReadOnly(bool b) { readOnly = b; } + void setReadOnly(bool b) { d()->readOnly = b; } - static ReturnedValue get(Managed *m, const StringRef name, bool *hasProperty); - static void put(Managed *m, const StringRef name, const ValueRef value); + static ReturnedValue get(Managed *m, String *name, bool *hasProperty); + static void put(Managed *m, String *name, const ValueRef value); static void destroy(Managed *that); static void markObjects(Managed *m, ExecutionEngine *engine); static void registerQmlDependencies(ExecutionEngine *context, const CompiledData::Function *compiledFunction); ReturnedValue idObjectsArray(); - ReturnedValue qmlSingletonWrapper(QV8Engine *e, const StringRef &name); + ReturnedValue qmlSingletonWrapper(QV8Engine *e, String *name); - bool readOnly; - bool ownsContext; - bool isNullWrapper; - - QQmlGuardedContextData context; - QPointer<QObject> scopeObject; -private: - QQmlIdObjectsArray *idObjectsWrapper; }; struct QQmlIdObjectsArray : public Object { - V4_OBJECT - QQmlIdObjectsArray(ExecutionEngine *engine, QmlContextWrapper *contextWrapper); + struct Data : Object::Data { + Data(ExecutionEngine *engine, QmlContextWrapper *contextWrapper); + QmlContextWrapper *contextWrapper; + }; + V4_OBJECT(Object) static ReturnedValue getIndexed(Managed *m, uint index, bool *hasProperty); static void markObjects(Managed *that, ExecutionEngine *engine); - QmlContextWrapper *contextWrapper; }; } diff --git a/src/qml/qml/qqmlcustomparser.cpp b/src/qml/qml/qqmlcustomparser.cpp index 75acbdb778..312c4a8a10 100644 --- a/src/qml/qml/qqmlcustomparser.cpp +++ b/src/qml/qml/qqmlcustomparser.cpp @@ -109,6 +109,12 @@ void QQmlCustomParser::error(const QV4::CompiledData::Location &location, const exceptions << error; } +struct StaticQtMetaObject : public QObject +{ + static const QMetaObject *get() + { return &staticQtMetaObject; } +}; + /*! If \a script is a simple enumeration expression (eg. Text.AlignLeft), returns the integer equivalent (eg. 1), and sets \a ok to true. @@ -125,7 +131,34 @@ int QQmlCustomParser::evaluateEnum(const QByteArray& script, bool *ok) const if (dot == -1) return -1; - return compiler->evaluateEnum(QString::fromUtf8(script.left(dot)), script.mid(dot+1), ok); + + QString scope = QString::fromUtf8(script.left(dot)); + QByteArray enumValue = script.mid(dot+1); + + if (scope != QLatin1String("Qt")) { + if (imports.isNull()) + return -1; + QQmlType *type = 0; + + if (imports.isT1()) { + imports.asT1()->resolveType(scope, &type, 0, 0, 0); + } else { + QQmlTypeNameCache::Result result = imports.asT2()->query(scope); + if (result.isValid()) + type = result.type; + } + + return type ? type->enumValue(QHashedCStringRef(enumValue.constData(), enumValue.length()), ok) : -1; + } + + const QMetaObject *mo = StaticQtMetaObject::get(); + int i = mo->enumeratorCount(); + while (i--) { + int v = mo->enumerator(i).keyToValue(enumValue.constData(), ok); + if (*ok) + return v; + } + return -1; } /*! @@ -137,17 +170,6 @@ const QMetaObject *QQmlCustomParser::resolveType(const QString& name) const return compiler->resolveType(name); } -QQmlBinding::Identifier QQmlCustomParser::bindingIdentifier(const QV4::CompiledData::Binding *binding) -{ - return compiler->bindingIdentifier(binding, this); -} - -struct StaticQtMetaObject : public QObject -{ - static const QMetaObject *get() - { return &staticQtMetaObject; } -}; - int QQmlCustomParserCompilerBackend::evaluateEnum(const QString &scope, const QByteArray &enumValue, bool *ok) const { Q_ASSERT_X(ok, "QQmlCompiler::evaluateEnum", "ok must not be a null pointer"); diff --git a/src/qml/qml/qqmlcustomparser_p.h b/src/qml/qml/qqmlcustomparser_p.h index 2ce6375870..9e3f810738 100644 --- a/src/qml/qml/qqmlcustomparser_p.h +++ b/src/qml/qml/qqmlcustomparser_p.h @@ -71,8 +71,6 @@ struct QQmlCustomParserCompilerBackend int evaluateEnum(const QString &scope, const QByteArray& enumValue, bool *ok) const; const QMetaObject *resolveType(const QString& name) const; - - virtual QQmlBinding::Identifier bindingIdentifier(const QV4::CompiledData::Binding *, QQmlCustomParser *) { return QQmlBinding::Invalid; } }; class Q_QML_PRIVATE_EXPORT QQmlCustomParser @@ -92,8 +90,8 @@ public: void clearErrors(); Flags flags() const { return m_flags; } - virtual QByteArray compile(const QV4::CompiledData::QmlUnit *qmlUnit, const QList<const QV4::CompiledData::Binding *> &bindings) = 0; - virtual void setCustomData(QObject *, const QByteArray &, QQmlCompiledData *cdata) = 0; + virtual void verifyBindings(const QV4::CompiledData::QmlUnit *, const QList<const QV4::CompiledData::Binding *> &) = 0; + virtual void applyBindings(QObject *, QQmlCompiledData *, const QList<const QV4::CompiledData::Binding *> &) = 0; QList<QQmlError> errors() const { return exceptions; } @@ -108,13 +106,13 @@ protected: const QMetaObject *resolveType(const QString&) const; - QQmlBinding::Identifier bindingIdentifier(const QV4::CompiledData::Binding *binding); - private: QList<QQmlError> exceptions; QQmlCustomParserCompilerBackend *compiler; Flags m_flags; + QBiPointer<const QQmlImports, QQmlTypeNameCache> imports; friend class QQmlPropertyValidator; + friend class QQmlObjectCreator; }; Q_DECLARE_OPERATORS_FOR_FLAGS(QQmlCustomParser::Flags) diff --git a/src/qml/qml/qqmlengine.cpp b/src/qml/qml/qqmlengine.cpp index 9bf983ab85..9ba6e67079 100644 --- a/src/qml/qml/qqmlengine.cpp +++ b/src/qml/qml/qqmlengine.cpp @@ -585,9 +585,6 @@ QQmlEnginePrivate::~QQmlEnginePrivate() if (incubationController) incubationController->d = 0; incubationController = 0; - delete rootContext; - rootContext = 0; - for(QHash<const QMetaObject *, QQmlPropertyCache *>::Iterator iter = propertyCache.begin(); iter != propertyCache.end(); ++iter) (*iter)->release(); for(QHash<QPair<QQmlType *, int>, QQmlPropertyCache *>::Iterator iter = typePropertyCache.begin(); iter != typePropertyCache.end(); ++iter) @@ -907,6 +904,8 @@ QQmlEngine::~QQmlEngine() if (d->isDebugging) QQmlDebugServer::instance()->removeEngine(this); + d->typeLoader.invalidate(); + // Emit onDestruction signals for the root context before // we destroy the contexts, engine, Singleton Types etc. that // may be required to handle the destruction signal. @@ -919,6 +918,9 @@ QQmlEngine::~QQmlEngine() QList<QQmlType*> singletonTypes = QQmlMetaType::qmlSingletonTypes(); foreach (QQmlType *currType, singletonTypes) currType->singletonInstanceInfo()->destroy(this); + + delete d->rootContext; + d->rootContext = 0; } /*! \fn void QQmlEngine::quit() diff --git a/src/qml/qml/qqmlerror.cpp b/src/qml/qml/qqmlerror.cpp index c583156c43..6d72bfcffa 100644 --- a/src/qml/qml/qqmlerror.cpp +++ b/src/qml/qml/qqmlerror.cpp @@ -249,16 +249,17 @@ QString QQmlError::toString() const QUrl u(url()); int l(line()); - if (u.isEmpty()) { + if (u.isEmpty() || (u.isLocalFile() && u.path().isEmpty())) rv = QLatin1String("<Unknown File>"); - } else if (l != -1) { - rv = u.toString() + QLatin1Char(':') + QString::number(l); + else + rv = u.toString(); + + if (l != -1) { + rv += QLatin1Char(':') + QString::number(l); int c(column()); if (c != -1) rv += QLatin1Char(':') + QString::number(c); - } else { - rv = u.toString(); } rv += QLatin1String(": ") + description(); diff --git a/src/qml/qml/qqmlexpression.cpp b/src/qml/qml/qqmlexpression.cpp index 4dc3704bbb..e993ed98eb 100644 --- a/src/qml/qml/qqmlexpression.cpp +++ b/src/qml/qml/qqmlexpression.cpp @@ -161,7 +161,7 @@ QQmlExpression::QQmlExpression(const QQmlScriptString &script, QQmlContext *ctxt Q_ASSERT(typeData); if (QQmlCompiledData *cdata = typeData->compiledData()) { - d->url = cdata->name; + d->url = cdata->fileName(); d->line = scriptPrivate->lineNumber; d->column = scriptPrivate->columnNumber; diff --git a/src/qml/qml/qqmlfileselector.cpp b/src/qml/qml/qqmlfileselector.cpp index 187c3656c6..8498a4d67d 100644 --- a/src/qml/qml/qqmlfileselector.cpp +++ b/src/qml/qml/qqmlfileselector.cpp @@ -106,8 +106,8 @@ QQmlFileSelector::QQmlFileSelector(QQmlEngine* engine, QObject* parent) { Q_D(QQmlFileSelector); d->engine = engine; - interceptorInstances()->insert(d->myInstance, this); - d->engine->setUrlInterceptor(d->myInstance); + interceptorInstances()->insert(d->myInstance.data(), this); + d->engine->setUrlInterceptor(d->myInstance.data()); } QQmlFileSelector::~QQmlFileSelector() @@ -117,7 +117,7 @@ QQmlFileSelector::~QQmlFileSelector() d->engine->setUrlInterceptor(0); d->engine = 0; } - interceptorInstances()->remove(d->myInstance); + interceptorInstances()->remove(d->myInstance.data()); } QQmlFileSelectorPrivate::QQmlFileSelectorPrivate() @@ -125,7 +125,7 @@ QQmlFileSelectorPrivate::QQmlFileSelectorPrivate() Q_Q(QQmlFileSelector); ownSelector = true; selector = new QFileSelector(q); - myInstance = new QQmlFileSelectorInterceptor(this); + myInstance.reset(new QQmlFileSelectorInterceptor(this)); } /*! diff --git a/src/qml/qml/qqmlfileselector_p.h b/src/qml/qml/qqmlfileselector_p.h index 501f563ade..73a98788ee 100644 --- a/src/qml/qml/qqmlfileselector_p.h +++ b/src/qml/qml/qqmlfileselector_p.h @@ -71,7 +71,7 @@ public: QFileSelector* selector; QPointer<QQmlEngine> engine; bool ownSelector; - QQmlFileSelectorInterceptor* myInstance; + QScopedPointer<QQmlFileSelectorInterceptor> myInstance; }; class Q_QML_PRIVATE_EXPORT QQmlFileSelectorInterceptor : public QQmlAbstractUrlInterceptor diff --git a/src/qml/qml/qqmlincubator.cpp b/src/qml/qml/qqmlincubator.cpp index 4cdeb19719..0665a4ac1a 100644 --- a/src/qml/qml/qqmlincubator.cpp +++ b/src/qml/qml/qqmlincubator.cpp @@ -283,7 +283,7 @@ void QQmlIncubatorPrivate::incubate(QQmlInstantiationInterrupt &i) if (!compiledData) return; - QML_MEMORY_SCOPE_URL(compiledData->url); + QML_MEMORY_SCOPE_URL(compiledData->url()); QExplicitlySharedDataPointer<QQmlIncubatorPrivate> protectThis(this); @@ -297,7 +297,7 @@ void QQmlIncubatorPrivate::incubate(QQmlInstantiationInterrupt &i) if (!guardOk) { QQmlError error; - error.setUrl(compiledData->url); + error.setUrl(compiledData->url()); error.setDescription(QQmlComponent::tr("Object destroyed during incubation")); errors << error; progress = QQmlIncubatorPrivate::Completed; diff --git a/src/qml/qml/qqmlinfo.cpp b/src/qml/qml/qqmlinfo.cpp index 63ce2d419c..2f013863ca 100644 --- a/src/qml/qml/qqmlinfo.cpp +++ b/src/qml/qml/qqmlinfo.cpp @@ -147,7 +147,7 @@ QQmlInfo::~QQmlInfo() d->buffer.prepend(QLatin1String("QML ") + typeName + QLatin1String(": ")); QQmlData *ddata = QQmlData::get(object, false); - if (ddata && ddata->outerContext && !ddata->outerContext->url.isEmpty()) { + if (ddata && ddata->outerContext) { error.setUrl(ddata->outerContext->url); error.setLine(ddata->lineNumber); error.setColumn(ddata->columnNumber); diff --git a/src/qml/qml/qqmljavascriptexpression.cpp b/src/qml/qml/qqmljavascriptexpression.cpp index 560a4c8afd..8fea5e66d3 100644 --- a/src/qml/qml/qqmljavascriptexpression.cpp +++ b/src/qml/qml/qqmljavascriptexpression.cpp @@ -158,7 +158,7 @@ QV4::ReturnedValue QQmlJavaScriptExpression::evaluate(QQmlContextData *context, QV4::ExecutionContext *ctx = v4->currentContext(); callData->thisObject = v4->globalObject; if (scopeObject()) { - QV4::ScopedValue value(scope, QV4::QObjectWrapper::wrap(ctx->engine, scopeObject())); + QV4::ScopedValue value(scope, QV4::QObjectWrapper::wrap(ctx->d()->engine, scopeObject())); if (value->isObject()) callData->thisObject = value; } diff --git a/src/qml/qml/qqmllistwrapper.cpp b/src/qml/qml/qqmllistwrapper.cpp index fd50e2dbbc..b84752501f 100644 --- a/src/qml/qml/qqmllistwrapper.cpp +++ b/src/qml/qml/qqmllistwrapper.cpp @@ -52,18 +52,18 @@ using namespace QV4; DEFINE_OBJECT_VTABLE(QmlListWrapper); -QmlListWrapper::QmlListWrapper(QV8Engine *engine) - : Object(QV8Engine::getV4(engine)), - v8(engine) +QmlListWrapper::Data::Data(QV8Engine *engine) + : Object::Data(QV8Engine::getV4(engine)) + , v8(engine) { setVTable(staticVTable()); + QV4::Scope scope(QV8Engine::getV4(engine)); - QV4::ScopedObject protectThis(scope, this); - Q_UNUSED(protectThis); - setArrayType(ArrayData::Custom); + QV4::ScopedObject o(scope, this); + o->setArrayType(ArrayData::Custom); } -QmlListWrapper::~QmlListWrapper() +QmlListWrapper::Data::~Data() { } @@ -75,10 +75,10 @@ ReturnedValue QmlListWrapper::create(QV8Engine *v8, QObject *object, int propId, ExecutionEngine *v4 = QV8Engine::getV4(v8); Scope scope(v4); - Scoped<QmlListWrapper> r(scope, new (v4->memoryManager) QmlListWrapper(v8)); - r->object = object; - r->propertyType = propType; - void *args[] = { &r->property, 0 }; + Scoped<QmlListWrapper> r(scope, v4->memoryManager->alloc<QmlListWrapper>(v8)); + r->d()->object = object; + r->d()->propertyType = propType; + void *args[] = { &r->d()->property, 0 }; QMetaObject::metacall(object, QMetaObject::ReadProperty, propId, args); return r.asReturnedValue(); } @@ -88,31 +88,31 @@ ReturnedValue QmlListWrapper::create(QV8Engine *v8, const QQmlListProperty<QObje ExecutionEngine *v4 = QV8Engine::getV4(v8); Scope scope(v4); - Scoped<QmlListWrapper> r(scope, new (v4->memoryManager) QmlListWrapper(v8)); - r->object = prop.object; - r->property = prop; - r->propertyType = propType; + Scoped<QmlListWrapper> r(scope, v4->memoryManager->alloc<QmlListWrapper>(v8)); + r->d()->object = prop.object; + r->d()->property = prop; + r->d()->propertyType = propType; return r.asReturnedValue(); } QVariant QmlListWrapper::toVariant() const { - if (!object) + if (!d()->object) return QVariant(); - return QVariant::fromValue(QQmlListReferencePrivate::init(property, propertyType, v8->engine())); + return QVariant::fromValue(QQmlListReferencePrivate::init(d()->property, d()->propertyType, d()->v8->engine())); } -ReturnedValue QmlListWrapper::get(Managed *m, const StringRef name, bool *hasProperty) +ReturnedValue QmlListWrapper::get(Managed *m, String *name, bool *hasProperty) { QV4::ExecutionEngine *v4 = m->engine(); QmlListWrapper *w = m->as<QmlListWrapper>(); if (!w) return v4->currentContext()->throwTypeError(); - if (name->equals(v4->id_length) && !w->object.isNull()) { - quint32 count = w->property.count ? w->property.count(&w->property) : 0; + if (name->equals(v4->id_length) && !w->d()->object.isNull()) { + quint32 count = w->d()->property.count ? w->d()->property.count(&w->d()->property) : 0; return Primitive::fromUInt32(count).asReturnedValue(); } @@ -135,11 +135,11 @@ ReturnedValue QmlListWrapper::getIndexed(Managed *m, uint index, bool *hasProper return e->currentContext()->throwTypeError(); } - quint32 count = w->property.count ? w->property.count(&w->property) : 0; - if (index < count && w->property.at) { + quint32 count = w->d()->property.count ? w->d()->property.count(&w->d()->property) : 0; + if (index < count && w->d()->property.at) { if (hasProperty) *hasProperty = true; - return QV4::QObjectWrapper::wrap(e, w->property.at(&w->property, index)); + return QV4::QObjectWrapper::wrap(e, w->d()->property.at(&w->d()->property, index)); } if (hasProperty) @@ -147,7 +147,7 @@ ReturnedValue QmlListWrapper::getIndexed(Managed *m, uint index, bool *hasProper return Primitive::undefinedValue().asReturnedValue(); } -void QmlListWrapper::put(Managed *m, const StringRef name, const ValueRef value) +void QmlListWrapper::put(Managed *m, String *name, const ValueRef value) { // doesn't do anything. Should we throw? Q_UNUSED(m); @@ -158,20 +158,20 @@ void QmlListWrapper::put(Managed *m, const StringRef name, const ValueRef value) void QmlListWrapper::destroy(Managed *that) { QmlListWrapper *w = that->as<QmlListWrapper>(); - w->~QmlListWrapper(); + w->d()->~Data(); } -void QmlListWrapper::advanceIterator(Managed *m, ObjectIterator *it, StringRef name, uint *index, Property *p, PropertyAttributes *attrs) +void QmlListWrapper::advanceIterator(Managed *m, ObjectIterator *it, String *&name, uint *index, Property *p, PropertyAttributes *attrs) { name = (String *)0; *index = UINT_MAX; QmlListWrapper *w = m->as<QmlListWrapper>(); - quint32 count = w->property.count ? w->property.count(&w->property) : 0; + quint32 count = w->d()->property.count ? w->d()->property.count(&w->d()->property) : 0; if (it->arrayIndex < count) { *index = it->arrayIndex; ++it->arrayIndex; *attrs = QV4::Attr_Data; - p->value = QV4::QObjectWrapper::wrap(w->engine(), w->property.at(&w->property, *index)); + p->value = QV4::QObjectWrapper::wrap(w->engine(), w->d()->property.at(&w->d()->property, *index)); return; } return QV4::Object::advanceIterator(m, it, name, index, p, attrs); diff --git a/src/qml/qml/qqmllistwrapper_p.h b/src/qml/qml/qqmllistwrapper_p.h index a7ce8b30bf..f6aee04487 100644 --- a/src/qml/qml/qqmllistwrapper_p.h +++ b/src/qml/qml/qqmllistwrapper_p.h @@ -69,30 +69,26 @@ namespace QV4 { struct Q_QML_EXPORT QmlListWrapper : Object { - V4_OBJECT -protected: - QmlListWrapper(QV8Engine *engine); - ~QmlListWrapper(); - -public: + struct Data : Object::Data { + Data(QV8Engine *engine); + ~Data(); + QV8Engine *v8; + QPointer<QObject> object; + QQmlListProperty<QObject> property; + int propertyType; + }; + V4_OBJECT(Object) static ReturnedValue create(QV8Engine *v8, QObject *object, int propId, int propType); static ReturnedValue create(QV8Engine *v8, const QQmlListProperty<QObject> &prop, int propType); QVariant toVariant() const; - static ReturnedValue get(Managed *m, const StringRef name, bool *hasProperty); + static ReturnedValue get(Managed *m, String *name, bool *hasProperty); static ReturnedValue getIndexed(Managed *m, uint index, bool *hasProperty); - static void put(Managed *m, const StringRef name, const ValueRef value); - static void advanceIterator(Managed *m, ObjectIterator *it, StringRef name, uint *index, Property *p, PropertyAttributes *attributes); + static void put(Managed *m, String *name, const ValueRef value); + static void advanceIterator(Managed *m, ObjectIterator *it, String *&name, uint *index, Property *p, PropertyAttributes *attributes); static void destroy(Managed *that); - -private: - QV8Engine *v8; - QPointer<QObject> object; - QQmlListProperty<QObject> property; - int propertyType; - }; } diff --git a/src/qml/qml/qqmllocale.cpp b/src/qml/qml/qqmllocale.cpp index 178280b27c..b1ce0da8e0 100644 --- a/src/qml/qml/qqmllocale.cpp +++ b/src/qml/qml/qqmllocale.cpp @@ -82,171 +82,171 @@ void QQmlDateExtension::registerExtension(QV4::ExecutionEngine *engine) QV4::ReturnedValue QQmlDateExtension::method_toLocaleString(QV4::CallContext *ctx) { - if (ctx->callData->argc > 2) + if (ctx->d()->callData->argc > 2) return QV4::DatePrototype::method_toLocaleString(ctx); QV4::Scope scope(ctx); - QV4::DateObject *date = ctx->callData->thisObject.asDateObject(); + QV4::DateObject *date = ctx->d()->callData->thisObject.asDateObject(); if (!date) return QV4::DatePrototype::method_toLocaleString(ctx); QDateTime dt = date->toQDateTime(); - if (ctx->callData->argc == 0) { + if (ctx->d()->callData->argc == 0) { // Use QLocale for standard toLocaleString() function QLocale locale; - return ctx->engine->newString(locale.toString(dt))->asReturnedValue(); + return ctx->d()->engine->newString(locale.toString(dt))->asReturnedValue(); } - if (!isLocaleObject(ctx->callData->args[0])) + if (!isLocaleObject(ctx->d()->callData->args[0])) return QV4::DatePrototype::method_toLocaleString(ctx); // Use the default Date toLocaleString() - GET_LOCALE_DATA_RESOURCE(ctx->callData->args[0]); + GET_LOCALE_DATA_RESOURCE(ctx->d()->callData->args[0]); QLocale::FormatType enumFormat = QLocale::LongFormat; QString formattedDt; - if (ctx->callData->argc == 2) { - if (ctx->callData->args[1].isString()) { - QString format = ctx->callData->args[1].stringValue()->toQString(); - formattedDt = r->locale.toString(dt, format); - } else if (ctx->callData->args[1].isNumber()) { - quint32 intFormat = ctx->callData->args[1].toNumber(); + if (ctx->d()->callData->argc == 2) { + if (ctx->d()->callData->args[1].isString()) { + QString format = ctx->d()->callData->args[1].stringValue()->toQString(); + formattedDt = r->d()->locale.toString(dt, format); + } else if (ctx->d()->callData->args[1].isNumber()) { + quint32 intFormat = ctx->d()->callData->args[1].toNumber(); QLocale::FormatType format = QLocale::FormatType(intFormat); - formattedDt = r->locale.toString(dt, format); + formattedDt = r->d()->locale.toString(dt, format); } else { V4THROW_ERROR("Locale: Date.toLocaleString(): Invalid datetime format"); } } else { - formattedDt = r->locale.toString(dt, enumFormat); + formattedDt = r->d()->locale.toString(dt, enumFormat); } - return ctx->engine->newString(formattedDt)->asReturnedValue(); + return ctx->d()->engine->newString(formattedDt)->asReturnedValue(); } QV4::ReturnedValue QQmlDateExtension::method_toLocaleTimeString(QV4::CallContext *ctx) { - if (ctx->callData->argc > 2) + if (ctx->d()->callData->argc > 2) return QV4::DatePrototype::method_toLocaleTimeString(ctx); QV4::Scope scope(ctx); - QV4::DateObject *date = ctx->callData->thisObject.asDateObject(); + QV4::DateObject *date = ctx->d()->callData->thisObject.asDateObject(); if (!date) return QV4::DatePrototype::method_toLocaleTimeString(ctx); QDateTime dt = date->toQDateTime(); QTime time = dt.time(); - if (ctx->callData->argc == 0) { + if (ctx->d()->callData->argc == 0) { // Use QLocale for standard toLocaleString() function QLocale locale; - return ctx->engine->newString(locale.toString(time))->asReturnedValue(); + return ctx->d()->engine->newString(locale.toString(time))->asReturnedValue(); } - if (!isLocaleObject(ctx->callData->args[0])) + if (!isLocaleObject(ctx->d()->callData->args[0])) return QV4::DatePrototype::method_toLocaleTimeString(ctx); // Use the default Date toLocaleTimeString() - GET_LOCALE_DATA_RESOURCE(ctx->callData->args[0]); + GET_LOCALE_DATA_RESOURCE(ctx->d()->callData->args[0]); QLocale::FormatType enumFormat = QLocale::LongFormat; QString formattedTime; - if (ctx->callData->argc == 2) { - if (ctx->callData->args[1].isString()) { - QString format = ctx->callData->args[1].stringValue()->toQString(); - formattedTime = r->locale.toString(time, format); - } else if (ctx->callData->args[1].isNumber()) { - quint32 intFormat = ctx->callData->args[1].toNumber(); + if (ctx->d()->callData->argc == 2) { + if (ctx->d()->callData->args[1].isString()) { + QString format = ctx->d()->callData->args[1].stringValue()->toQString(); + formattedTime = r->d()->locale.toString(time, format); + } else if (ctx->d()->callData->args[1].isNumber()) { + quint32 intFormat = ctx->d()->callData->args[1].toNumber(); QLocale::FormatType format = QLocale::FormatType(intFormat); - formattedTime = r->locale.toString(time, format); + formattedTime = r->d()->locale.toString(time, format); } else { V4THROW_ERROR("Locale: Date.toLocaleTimeString(): Invalid time format"); } } else { - formattedTime = r->locale.toString(time, enumFormat); + formattedTime = r->d()->locale.toString(time, enumFormat); } - return ctx->engine->newString(formattedTime)->asReturnedValue(); + return ctx->d()->engine->newString(formattedTime)->asReturnedValue(); } QV4::ReturnedValue QQmlDateExtension::method_toLocaleDateString(QV4::CallContext *ctx) { - if (ctx->callData->argc > 2) + if (ctx->d()->callData->argc > 2) return QV4::DatePrototype::method_toLocaleDateString(ctx); QV4::Scope scope(ctx); - QV4::DateObject *dateObj = ctx->callData->thisObject.asDateObject(); + QV4::DateObject *dateObj = ctx->d()->callData->thisObject.asDateObject(); if (!dateObj) return QV4::DatePrototype::method_toLocaleDateString(ctx); QDateTime dt = dateObj->toQDateTime(); QDate date = dt.date(); - if (ctx->callData->argc == 0) { + if (ctx->d()->callData->argc == 0) { // Use QLocale for standard toLocaleString() function QLocale locale; - return ctx->engine->newString(locale.toString(date))->asReturnedValue(); + return ctx->d()->engine->newString(locale.toString(date))->asReturnedValue(); } - if (!isLocaleObject(ctx->callData->args[0])) + if (!isLocaleObject(ctx->d()->callData->args[0])) return QV4::DatePrototype::method_toLocaleDateString(ctx); // Use the default Date toLocaleDateString() - GET_LOCALE_DATA_RESOURCE(ctx->callData->args[0]); + GET_LOCALE_DATA_RESOURCE(ctx->d()->callData->args[0]); QLocale::FormatType enumFormat = QLocale::LongFormat; QString formattedDate; - if (ctx->callData->argc == 2) { - if (ctx->callData->args[1].isString()) { - QString format = ctx->callData->args[1].stringValue()->toQString(); - formattedDate = r->locale.toString(date, format); - } else if (ctx->callData->args[1].isNumber()) { - quint32 intFormat = ctx->callData->args[1].toNumber(); + if (ctx->d()->callData->argc == 2) { + if (ctx->d()->callData->args[1].isString()) { + QString format = ctx->d()->callData->args[1].stringValue()->toQString(); + formattedDate = r->d()->locale.toString(date, format); + } else if (ctx->d()->callData->args[1].isNumber()) { + quint32 intFormat = ctx->d()->callData->args[1].toNumber(); QLocale::FormatType format = QLocale::FormatType(intFormat); - formattedDate = r->locale.toString(date, format); + formattedDate = r->d()->locale.toString(date, format); } else { V4THROW_ERROR("Locale: Date.loLocaleDateString(): Invalid date format"); } } else { - formattedDate = r->locale.toString(date, enumFormat); + formattedDate = r->d()->locale.toString(date, enumFormat); } - return ctx->engine->newString(formattedDate)->asReturnedValue(); + return ctx->d()->engine->newString(formattedDate)->asReturnedValue(); } QV4::ReturnedValue QQmlDateExtension::method_fromLocaleString(QV4::CallContext *ctx) { - QV4::ExecutionEngine * const engine = ctx->engine; - if (ctx->callData->argc == 1 && ctx->callData->args[0].isString()) { + QV4::ExecutionEngine * const engine = ctx->d()->engine; + if (ctx->d()->callData->argc == 1 && ctx->d()->callData->args[0].isString()) { QLocale locale; - QString dateString = ctx->callData->args[0].stringValue()->toQString(); + QString dateString = ctx->d()->callData->args[0].stringValue()->toQString(); QDateTime dt = locale.toDateTime(dateString); return QV4::Encode(engine->newDateObject(dt)); } QV4::Scope scope(ctx); - if (ctx->callData->argc < 1 || ctx->callData->argc > 3 || !isLocaleObject(ctx->callData->args[0])) + if (ctx->d()->callData->argc < 1 || ctx->d()->callData->argc > 3 || !isLocaleObject(ctx->d()->callData->args[0])) V4THROW_ERROR("Locale: Date.fromLocaleString(): Invalid arguments"); - GET_LOCALE_DATA_RESOURCE(ctx->callData->args[0]); + GET_LOCALE_DATA_RESOURCE(ctx->d()->callData->args[0]); QLocale::FormatType enumFormat = QLocale::LongFormat; QDateTime dt; - QString dateString = ctx->callData->args[1].toQStringNoThrow(); - if (ctx->callData->argc == 3) { - if (ctx->callData->args[2].isString()) { - QString format = ctx->callData->args[2].stringValue()->toQString(); - dt = r->locale.toDateTime(dateString, format); - } else if (ctx->callData->args[2].isNumber()) { - quint32 intFormat = ctx->callData->args[2].toNumber(); + QString dateString = ctx->d()->callData->args[1].toQStringNoThrow(); + if (ctx->d()->callData->argc == 3) { + if (ctx->d()->callData->args[2].isString()) { + QString format = ctx->d()->callData->args[2].stringValue()->toQString(); + dt = r->d()->locale.toDateTime(dateString, format); + } else if (ctx->d()->callData->args[2].isNumber()) { + quint32 intFormat = ctx->d()->callData->args[2].toNumber(); QLocale::FormatType format = QLocale::FormatType(intFormat); - dt = r->locale.toDateTime(dateString, format); + dt = r->d()->locale.toDateTime(dateString, format); } else { V4THROW_ERROR("Locale: Date.fromLocaleString(): Invalid datetime format"); } } else { - dt = r->locale.toDateTime(dateString, enumFormat); + dt = r->d()->locale.toDateTime(dateString, enumFormat); } return QV4::Encode(engine->newDateObject(dt)); @@ -254,40 +254,40 @@ QV4::ReturnedValue QQmlDateExtension::method_fromLocaleString(QV4::CallContext * QV4::ReturnedValue QQmlDateExtension::method_fromLocaleTimeString(QV4::CallContext *ctx) { - QV4::ExecutionEngine * const engine = ctx->engine; + QV4::ExecutionEngine * const engine = ctx->d()->engine; - if (ctx->callData->argc == 1 && ctx->callData->args[0].isString()) { + if (ctx->d()->callData->argc == 1 && ctx->d()->callData->args[0].isString()) { QLocale locale; - QString timeString = ctx->callData->args[0].stringValue()->toQString(); + QString timeString = ctx->d()->callData->args[0].stringValue()->toQString(); QTime time = locale.toTime(timeString); QDateTime dt = QDateTime::currentDateTime(); dt.setTime(time); return QV4::Encode(engine->newDateObject(dt)); } - if (ctx->callData->argc < 1 || ctx->callData->argc > 3 || !isLocaleObject(ctx->callData->args[0])) + if (ctx->d()->callData->argc < 1 || ctx->d()->callData->argc > 3 || !isLocaleObject(ctx->d()->callData->args[0])) V4THROW_ERROR("Locale: Date.fromLocaleTimeString(): Invalid arguments"); QV4::Scope scope(ctx); - GET_LOCALE_DATA_RESOURCE(ctx->callData->args[0]); + GET_LOCALE_DATA_RESOURCE(ctx->d()->callData->args[0]); QLocale::FormatType enumFormat = QLocale::LongFormat; QTime tm; - QString dateString = ctx->callData->args[1].toQStringNoThrow(); - if (ctx->callData->argc == 3) { - if (ctx->callData->args[2].isString()) { - QString format = ctx->callData->args[2].stringValue()->toQString(); - tm = r->locale.toTime(dateString, format); - } else if (ctx->callData->args[2].isNumber()) { - quint32 intFormat = ctx->callData->args[2].toNumber(); + QString dateString = ctx->d()->callData->args[1].toQStringNoThrow(); + if (ctx->d()->callData->argc == 3) { + if (ctx->d()->callData->args[2].isString()) { + QString format = ctx->d()->callData->args[2].stringValue()->toQString(); + tm = r->d()->locale.toTime(dateString, format); + } else if (ctx->d()->callData->args[2].isNumber()) { + quint32 intFormat = ctx->d()->callData->args[2].toNumber(); QLocale::FormatType format = QLocale::FormatType(intFormat); - tm = r->locale.toTime(dateString, format); + tm = r->d()->locale.toTime(dateString, format); } else { V4THROW_ERROR("Locale: Date.fromLocaleTimeString(): Invalid datetime format"); } } else { - tm = r->locale.toTime(dateString, enumFormat); + tm = r->d()->locale.toTime(dateString, enumFormat); } QDateTime dt; @@ -301,38 +301,38 @@ QV4::ReturnedValue QQmlDateExtension::method_fromLocaleTimeString(QV4::CallConte QV4::ReturnedValue QQmlDateExtension::method_fromLocaleDateString(QV4::CallContext *ctx) { - QV4::ExecutionEngine * const engine = ctx->engine; + QV4::ExecutionEngine * const engine = ctx->d()->engine; - if (ctx->callData->argc == 1 && ctx->callData->args[0].isString()) { + if (ctx->d()->callData->argc == 1 && ctx->d()->callData->args[0].isString()) { QLocale locale; - QString dateString = ctx->callData->args[0].stringValue()->toQString(); + QString dateString = ctx->d()->callData->args[0].stringValue()->toQString(); QDate date = locale.toDate(dateString); return QV4::Encode(engine->newDateObject(QDateTime(date))); } - if (ctx->callData->argc < 1 || ctx->callData->argc > 3 || !isLocaleObject(ctx->callData->args[0])) + if (ctx->d()->callData->argc < 1 || ctx->d()->callData->argc > 3 || !isLocaleObject(ctx->d()->callData->args[0])) V4THROW_ERROR("Locale: Date.fromLocaleDateString(): Invalid arguments"); QV4::Scope scope(ctx); - GET_LOCALE_DATA_RESOURCE(ctx->callData->args[0]); + GET_LOCALE_DATA_RESOURCE(ctx->d()->callData->args[0]); QLocale::FormatType enumFormat = QLocale::LongFormat; QDate dt; - QString dateString = ctx->callData->args[1].toQStringNoThrow(); - if (ctx->callData->argc == 3) { - if (ctx->callData->args[2].isString()) { - QString format = ctx->callData->args[2].stringValue()->toQString(); - dt = r->locale.toDate(dateString, format); - } else if (ctx->callData->args[2].isNumber()) { - quint32 intFormat = ctx->callData->args[2].toNumber(); + QString dateString = ctx->d()->callData->args[1].toQStringNoThrow(); + if (ctx->d()->callData->argc == 3) { + if (ctx->d()->callData->args[2].isString()) { + QString format = ctx->d()->callData->args[2].stringValue()->toQString(); + dt = r->d()->locale.toDate(dateString, format); + } else if (ctx->d()->callData->args[2].isNumber()) { + quint32 intFormat = ctx->d()->callData->args[2].toNumber(); QLocale::FormatType format = QLocale::FormatType(intFormat); - dt = r->locale.toDate(dateString, format); + dt = r->d()->locale.toDate(dateString, format); } else { V4THROW_ERROR("Locale: Date.fromLocaleDateString(): Invalid datetime format"); } } else { - dt = r->locale.toDate(dateString, enumFormat); + dt = r->d()->locale.toDate(dateString, enumFormat); } return QV4::Encode(engine->newDateObject(QDateTime(dt))); @@ -340,7 +340,7 @@ QV4::ReturnedValue QQmlDateExtension::method_fromLocaleDateString(QV4::CallConte QV4::ReturnedValue QQmlDateExtension::method_timeZoneUpdated(QV4::CallContext *ctx) { - if (ctx->callData->argc != 0) + if (ctx->d()->callData->argc != 0) V4THROW_ERROR("Locale: Date.timeZoneUpdated(): Invalid arguments"); QV4::DatePrototype::timezoneUpdated(); @@ -360,75 +360,75 @@ void QQmlNumberExtension::registerExtension(QV4::ExecutionEngine *engine) QV4::ReturnedValue QQmlNumberExtension::method_toLocaleString(QV4::CallContext *ctx) { - if (ctx->callData->argc > 3) + if (ctx->d()->callData->argc > 3) V4THROW_ERROR("Locale: Number.toLocaleString(): Invalid arguments"); - double number = ctx->callData->thisObject.toNumber(); + double number = ctx->d()->callData->thisObject.toNumber(); - if (ctx->callData->argc == 0) { + if (ctx->d()->callData->argc == 0) { // Use QLocale for standard toLocaleString() function QLocale locale; - return ctx->engine->newString(locale.toString(number))->asReturnedValue(); + return ctx->d()->engine->newString(locale.toString(number))->asReturnedValue(); } - if (!isLocaleObject(ctx->callData->args[0])) + if (!isLocaleObject(ctx->d()->callData->args[0])) return QV4::NumberPrototype::method_toLocaleString(ctx); // Use the default Number toLocaleString() QV4::Scope scope(ctx); - GET_LOCALE_DATA_RESOURCE(ctx->callData->args[0]); + GET_LOCALE_DATA_RESOURCE(ctx->d()->callData->args[0]); quint16 format = 'f'; - if (ctx->callData->argc > 1) { - if (!ctx->callData->args[1].isString()) + if (ctx->d()->callData->argc > 1) { + if (!ctx->d()->callData->args[1].isString()) V4THROW_ERROR("Locale: Number.toLocaleString(): Invalid arguments"); - QV4::String *fs = ctx->callData->args[1].toString(ctx); - if (fs->length()) + QV4::String *fs = ctx->d()->callData->args[1].toString(ctx); + if (fs->d()->length()) format = fs->toQString().at(0).unicode(); } int prec = 2; - if (ctx->callData->argc > 2) { - if (!ctx->callData->args[2].isNumber()) + if (ctx->d()->callData->argc > 2) { + if (!ctx->d()->callData->args[2].isNumber()) V4THROW_ERROR("Locale: Number.toLocaleString(): Invalid arguments"); - prec = ctx->callData->args[2].toInt32(); + prec = ctx->d()->callData->args[2].toInt32(); } - return ctx->engine->newString(r->locale.toString(number, (char)format, prec))->asReturnedValue(); + return ctx->d()->engine->newString(r->d()->locale.toString(number, (char)format, prec))->asReturnedValue(); } QV4::ReturnedValue QQmlNumberExtension::method_toLocaleCurrencyString(QV4::CallContext *ctx) { - if (ctx->callData->argc > 2) + if (ctx->d()->callData->argc > 2) V4THROW_ERROR("Locale: Number.toLocaleCurrencyString(): Invalid arguments"); - double number = ctx->callData->thisObject.toNumber(); + double number = ctx->d()->callData->thisObject.toNumber(); - if (ctx->callData->argc == 0) { + if (ctx->d()->callData->argc == 0) { // Use QLocale for standard toLocaleString() function QLocale locale; - return ctx->engine->newString(locale.toString(number))->asReturnedValue(); + return ctx->d()->engine->newString(locale.toString(number))->asReturnedValue(); } - if (!isLocaleObject(ctx->callData->args[0])) + if (!isLocaleObject(ctx->d()->callData->args[0])) V4THROW_ERROR("Locale: Number.toLocaleCurrencyString(): Invalid arguments"); QV4::Scope scope(ctx); - GET_LOCALE_DATA_RESOURCE(ctx->callData->args[0]); + GET_LOCALE_DATA_RESOURCE(ctx->d()->callData->args[0]); QString symbol; - if (ctx->callData->argc > 1) { - if (!ctx->callData->args[1].isString()) + if (ctx->d()->callData->argc > 1) { + if (!ctx->d()->callData->args[1].isString()) V4THROW_ERROR("Locale: Number.toLocaleString(): Invalid arguments"); - symbol = ctx->callData->args[1].toQStringNoThrow(); + symbol = ctx->d()->callData->args[1].toQStringNoThrow(); } - return ctx->engine->newString(r->locale.toCurrencyString(number, symbol))->asReturnedValue(); + return ctx->d()->engine->newString(r->d()->locale.toCurrencyString(number, symbol))->asReturnedValue(); } QV4::ReturnedValue QQmlNumberExtension::method_fromLocaleString(QV4::CallContext *ctx) { - if (ctx->callData->argc < 1 || ctx->callData->argc > 2) + if (ctx->d()->callData->argc < 1 || ctx->d()->callData->argc > 2) V4THROW_ERROR("Locale: Number.fromLocaleString(): Invalid arguments"); int numberIdx = 0; @@ -436,18 +436,18 @@ QV4::ReturnedValue QQmlNumberExtension::method_fromLocaleString(QV4::CallContext QV4::Scope scope(ctx); - if (ctx->callData->argc == 2) { - if (!isLocaleObject(ctx->callData->args[0])) + if (ctx->d()->callData->argc == 2) { + if (!isLocaleObject(ctx->d()->callData->args[0])) V4THROW_ERROR("Locale: Number.fromLocaleString(): Invalid arguments"); - GET_LOCALE_DATA_RESOURCE(ctx->callData->args[0]); - locale = r->locale; + GET_LOCALE_DATA_RESOURCE(ctx->d()->callData->args[0]); + locale = r->d()->locale; numberIdx = 1; } - QV4::String *ns = ctx->callData->args[numberIdx].toString(ctx); - if (!ns->length()) + QV4::String *ns = ctx->d()->callData->args[numberIdx].toString(ctx); + if (!ns->d()->length()) return QV4::Encode(Q_QNAN); bool ok = false; @@ -499,7 +499,7 @@ QV4::ReturnedValue QQmlLocaleData::method_get_weekDays(QV4::CallContext *ctx) QList<Qt::DayOfWeek> days = locale->weekdays(); - QV4::Scoped<QV4::ArrayObject> result(scope, ctx->engine->newArrayObject()); + QV4::Scoped<QV4::ArrayObject> result(scope, ctx->d()->engine->newArrayObject()); result->arrayReserve(days.size()); for (int i = 0; i < days.size(); ++i) { int day = days.at(i); @@ -520,11 +520,11 @@ QV4::ReturnedValue QQmlLocaleData::method_get_uiLanguages(QV4::CallContext *ctx) return QV4::Encode::undefined(); QStringList langs = locale->uiLanguages(); - QV4::Scoped<QV4::ArrayObject> result(scope, ctx->engine->newArrayObject()); + QV4::Scoped<QV4::ArrayObject> result(scope, ctx->d()->engine->newArrayObject()); result->arrayReserve(langs.size()); QV4::ScopedValue v(scope); for (int i = 0; i < langs.size(); ++i) - result->arrayPut(i, (v = ctx->engine->newString(langs.at(i)))); + result->arrayPut(i, (v = ctx->d()->engine->newString(langs.at(i)))); result->setArrayLengthUnchecked(langs.size()); @@ -537,16 +537,16 @@ QV4::ReturnedValue QQmlLocaleData::method_currencySymbol(QV4::CallContext *ctx) if (!locale) return QV4::Encode::undefined(); - if (ctx->callData->argc > 1) + if (ctx->d()->callData->argc > 1) V4THROW_ERROR("Locale: currencySymbol(): Invalid arguments"); QLocale::CurrencySymbolFormat format = QLocale::CurrencySymbol; - if (ctx->callData->argc == 1) { - quint32 intFormat = ctx->callData->args[0].toNumber(); + if (ctx->d()->callData->argc == 1) { + quint32 intFormat = ctx->d()->callData->args[0].toNumber(); format = QLocale::CurrencySymbolFormat(intFormat); } - return ctx->engine->newString(locale->currencySymbol(format))->asReturnedValue(); + return ctx->d()->engine->newString(locale->currencySymbol(format))->asReturnedValue(); } #define LOCALE_FORMAT(FUNC) \ @@ -554,14 +554,14 @@ QV4::ReturnedValue QQmlLocaleData::method_ ##FUNC (QV4::CallContext *ctx) { \ QLocale *locale = getThisLocale(ctx); \ if (!locale) \ return QV4::Encode::undefined(); \ - if (ctx->callData->argc > 1) \ + if (ctx->d()->callData->argc > 1) \ V4THROW_ERROR("Locale: " #FUNC "(): Invalid arguments"); \ QLocale::FormatType format = QLocale::LongFormat;\ - if (ctx->callData->argc == 1) { \ - quint32 intFormat = ctx->callData->args[0].toUInt32(); \ + if (ctx->d()->callData->argc == 1) { \ + quint32 intFormat = ctx->d()->callData->args[0].toUInt32(); \ format = QLocale::FormatType(intFormat); \ } \ - return ctx->engine->newString(locale-> FUNC (format))->asReturnedValue(); \ + return ctx->engine()->newString(locale-> FUNC (format))->asReturnedValue(); \ } LOCALE_FORMAT(dateTimeFormat) @@ -574,16 +574,16 @@ QV4::ReturnedValue QQmlLocaleData::method_ ## VARIABLE (QV4::CallContext *ctx) { QLocale *locale = getThisLocale(ctx); \ if (!locale) \ return QV4::Encode::undefined(); \ - if (ctx->callData->argc < 1 || ctx->callData->argc > 2) \ + if (ctx->d()->callData->argc < 1 || ctx->d()->callData->argc > 2) \ V4THROW_ERROR("Locale: " #VARIABLE "(): Invalid arguments"); \ QLocale::FormatType enumFormat = QLocale::LongFormat; \ - int idx = ctx->callData->args[0].toInt32() + 1; \ + int idx = ctx->d()->callData->args[0].toInt32() + 1; \ if (idx < 1 || idx > 12) \ V4THROW_ERROR("Locale: Invalid month"); \ QString name; \ - if (ctx->callData->argc == 2) { \ - if (ctx->callData->args[1].isNumber()) { \ - quint32 intFormat = ctx->callData->args[1].toUInt32(); \ + if (ctx->d()->callData->argc == 2) { \ + if (ctx->d()->callData->args[1].isNumber()) { \ + quint32 intFormat = ctx->d()->callData->args[1].toUInt32(); \ QLocale::FormatType format = QLocale::FormatType(intFormat); \ name = locale-> VARIABLE(idx, format); \ } else { \ @@ -592,7 +592,7 @@ QV4::ReturnedValue QQmlLocaleData::method_ ## VARIABLE (QV4::CallContext *ctx) { } else { \ name = locale-> VARIABLE(idx, enumFormat); \ } \ - return ctx->engine->newString(name)->asReturnedValue(); \ + return ctx->engine()->newString(name)->asReturnedValue(); \ } // 0 -> 7 as Qt::Sunday is 7, but Sunday is 0 in JS Date @@ -601,17 +601,17 @@ QV4::ReturnedValue QQmlLocaleData::method_ ## VARIABLE (QV4::CallContext *ctx) { QLocale *locale = getThisLocale(ctx); \ if (!locale) \ return QV4::Encode::undefined(); \ - if (ctx->callData->argc < 1 || ctx->callData->argc > 2) \ + if (ctx->d()->callData->argc < 1 || ctx->d()->callData->argc > 2) \ V4THROW_ERROR("Locale: " #VARIABLE "(): Invalid arguments"); \ QLocale::FormatType enumFormat = QLocale::LongFormat; \ - int idx = ctx->callData->args[0].toInt32(); \ + int idx = ctx->d()->callData->args[0].toInt32(); \ if (idx < 0 || idx > 7) \ V4THROW_ERROR("Locale: Invalid day"); \ if (idx == 0) idx = 7; \ QString name; \ - if (ctx->callData->argc == 2) { \ - if (ctx->callData->args[1].isNumber()) { \ - quint32 intFormat = ctx->callData->args[1].toUInt32(); \ + if (ctx->d()->callData->argc == 2) { \ + if (ctx->d()->callData->args[1].isNumber()) { \ + quint32 intFormat = ctx->d()->callData->args[1].toUInt32(); \ QLocale::FormatType format = QLocale::FormatType(intFormat); \ name = locale-> VARIABLE(idx, format); \ } else { \ @@ -620,7 +620,7 @@ QV4::ReturnedValue QQmlLocaleData::method_ ## VARIABLE (QV4::CallContext *ctx) { } else { \ name = locale-> VARIABLE(idx, enumFormat); \ } \ - return ctx->engine->newString(name)->asReturnedValue(); \ + return ctx->engine()->newString(name)->asReturnedValue(); \ } LOCALE_FORMATTED_MONTHNAME(monthName) @@ -633,7 +633,7 @@ LOCALE_FORMATTED_DAYNAME(standaloneDayName) QLocale *locale = getThisLocale(ctx); \ if (!locale) \ return QV4::Encode::undefined(); \ - return ctx->engine->newString(locale-> VARIABLE())->asReturnedValue();\ + return ctx->engine()->newString(locale-> VARIABLE())->asReturnedValue();\ } LOCALE_STRING_PROPERTY(name) @@ -814,8 +814,8 @@ QV4::ReturnedValue QQmlLocale::wrap(QV8Engine *engine, const QLocale &locale) QV8LocaleDataDeletable *d = localeV8Data(engine); QV4::ExecutionEngine *v4 = QV8Engine::getV4(engine); QV4::Scope scope(v4); - QV4::Scoped<QQmlLocaleData> wrapper(scope, new (v4->memoryManager) QQmlLocaleData(v4)); - wrapper->locale = locale; + QV4::Scoped<QQmlLocaleData> wrapper(scope, v4->memoryManager->alloc<QQmlLocaleData>(v4)); + wrapper->d()->locale = locale; QV4::ScopedObject p(scope, d->prototype.value()); wrapper->setPrototype(p.getPointer()); return wrapper.asReturnedValue(); @@ -828,14 +828,14 @@ void QQmlLocale::registerStringLocaleCompare(QV4::ExecutionEngine *engine) QV4::ReturnedValue QQmlLocale::method_localeCompare(QV4::CallContext *ctx) { - if (ctx->callData->argc != 1 || (!ctx->callData->args[0].isString() && !ctx->callData->args[0].asStringObject())) + if (ctx->d()->callData->argc != 1 || (!ctx->d()->callData->args[0].isString() && !ctx->d()->callData->args[0].asStringObject())) return QV4::StringPrototype::method_localeCompare(ctx); - if (!ctx->callData->thisObject.isString() && !ctx->callData->thisObject.asStringObject()) + if (!ctx->d()->callData->thisObject.isString() && !ctx->d()->callData->thisObject.asStringObject()) return QV4::StringPrototype::method_localeCompare(ctx); - QString thisString = ctx->callData->thisObject.toQStringNoThrow(); - QString thatString = ctx->callData->args[0].toQStringNoThrow(); + QString thisString = ctx->d()->callData->thisObject.toQStringNoThrow(); + QString thatString = ctx->d()->callData->args[0].toQStringNoThrow(); return QV4::Encode(QString::localeAwareCompare(thisString, thatString)); } diff --git a/src/qml/qml/qqmllocale_p.h b/src/qml/qml/qqmllocale_p.h index cafe448313..8ec7cbf61f 100644 --- a/src/qml/qml/qqmllocale_p.h +++ b/src/qml/qml/qqmllocale_p.h @@ -129,25 +129,25 @@ private: static QV4::ReturnedValue method_localeCompare(QV4::CallContext *ctx); }; -class QQmlLocaleData : public QV4::Object +struct QQmlLocaleData : public QV4::Object { - V4_OBJECT -public: - QQmlLocaleData(QV4::ExecutionEngine *engine) - : QV4::Object(engine) - { - setVTable(staticVTable()); - } - - QLocale locale; + struct Data : Object::Data { + Data(QV4::ExecutionEngine *engine) + : Object::Data(engine) + { + setVTable(staticVTable()); + } + QLocale locale; + }; + V4_OBJECT(Object) static QLocale *getThisLocale(QV4::CallContext *ctx) { - QQmlLocaleData *thisObject = ctx->callData->thisObject.asObject()->as<QQmlLocaleData>(); + QQmlLocaleData *thisObject = ctx->d()->callData->thisObject.asObject()->as<QQmlLocaleData>(); if (!thisObject) { ctx->throwTypeError(); return 0; } - return &thisObject->locale; + return &thisObject->d()->locale; } static QV4::ReturnedValue method_currencySymbol(QV4::CallContext *ctx); diff --git a/src/qml/qml/qqmlobjectcreator.cpp b/src/qml/qml/qqmlobjectcreator.cpp index 36c7dfb0e9..9501b705ba 100644 --- a/src/qml/qml/qqmlobjectcreator.cpp +++ b/src/qml/qml/qqmlobjectcreator.cpp @@ -183,8 +183,8 @@ QObject *QQmlObjectCreator::create(int subComponentIndex, QObject *parent, QQmlI context = new QQmlContextData; context->isInternal = true; - context->url = compiledData->url; - context->urlString = compiledData->name; + context->url = compiledData->url(); + context->urlString = compiledData->fileName(); context->imports = compiledData->importCache; context->imports->addref(); context->setParent(parentContext); @@ -261,7 +261,7 @@ bool QQmlObjectCreator::populateDeferredProperties(QObject *instance) QV4::ScopedValue scopeObjectProtector(valueScope, declarativeData->jsWrapper.value()); Q_UNUSED(scopeObjectProtector); QV4::ScopedObject qmlScope(valueScope, QV4::QmlContextWrapper::qmlScope(QV8Engine::get(engine), context, _scopeObject)); - QV4::Scoped<QV4::QmlBindingWrapper> qmlBindingWrapper(valueScope, new (v4->memoryManager) QV4::QmlBindingWrapper(v4->rootContext, qmlScope)); + QV4::Scoped<QV4::QmlBindingWrapper> qmlBindingWrapper(valueScope, v4->memoryManager->alloc<QV4::QmlBindingWrapper>(v4->rootContext, qmlScope)); QV4::ExecutionContext *qmlContext = qmlBindingWrapper->context(); qSwap(_qmlContext, qmlContext); @@ -388,7 +388,7 @@ void QQmlObjectCreator::setPropertyValue(QQmlPropertyData *property, const QV4:: QString string = binding->valueAsString(&qmlUnit->header); // Encoded dir-separators defeat QUrl processing - decode them first string.replace(QLatin1String("%2f"), QLatin1String("/"), Qt::CaseInsensitive); - QUrl value = string.isEmpty() ? QUrl() : compiledData->url.resolved(QUrl(string)); + QUrl value = string.isEmpty() ? QUrl() : compiledData->url().resolved(QUrl(string)); // Apply URL interceptor if (engine->urlInterceptor()) value = engine->urlInterceptor()->intercept(value, QQmlAbstractUrlInterceptor::UrlString); @@ -583,7 +583,7 @@ void QQmlObjectCreator::setPropertyValue(QQmlPropertyData *property, const QV4:: } else if (property->propType == qMetaTypeId<QList<QUrl> >()) { Q_ASSERT(binding->type == QV4::CompiledData::Binding::Type_String); QString urlString = binding->valueAsString(&qmlUnit->header); - QUrl u = urlString.isEmpty() ? QUrl() : compiledData->url.resolved(QUrl(urlString)); + QUrl u = urlString.isEmpty() ? QUrl() : compiledData->url().resolved(QUrl(urlString)); QList<QUrl> value; value.append(u); argv[0] = reinterpret_cast<void *>(&value); @@ -1010,7 +1010,7 @@ void QQmlObjectCreator::setupFunctions() void QQmlObjectCreator::recordError(const QV4::CompiledData::Location &location, const QString &description) { QQmlError error; - error.setUrl(compiledData->url); + error.setUrl(compiledData->url()); error.setLine(location.line); error.setColumn(location.column); error.setDescription(description); @@ -1067,7 +1067,7 @@ QObject *QQmlObjectCreator::createInstance(int index, QObject *parent, bool isCo sharedState->allCreatedObjects.push(instance); } else { Q_ASSERT(typeRef->component); - Q_QML_OC_PROFILE(sharedState->profiler, profiler.update(typeRef->component->name, + Q_QML_OC_PROFILE(sharedState->profiler, profiler.update(typeRef->component->fileName(), context->url, obj->location.line, obj->location.column)); if (typeRef->component->qmlUnit->isSingleton()) { @@ -1127,10 +1127,19 @@ QObject *QQmlObjectCreator::createInstance(int index, QObject *parent, bool isCo QBitArray bindingsToSkip; if (customParser) { - QHash<int, QQmlCompiledData::CustomParserData>::ConstIterator entry = compiledData->customParserData.find(index); - if (entry != compiledData->customParserData.constEnd()) { - customParser->setCustomData(instance, entry->compilationArtifact, compiledData); - bindingsToSkip = entry->bindings; + QHash<int, QBitArray>::ConstIterator customParserBindings = compiledData->customParserBindings.find(index); + if (customParserBindings != compiledData->customParserBindings.constEnd()) { + customParser->imports = compiledData->importCache; + + QList<const QV4::CompiledData::Binding *> bindings; + const QV4::CompiledData::Object *obj = qmlUnit->objectAt(index); + for (int i = 0; i < customParserBindings->count(); ++i) + if (customParserBindings->testBit(i)) + bindings << obj->bindingTable() + i; + customParser->applyBindings(instance, compiledData, bindings); + + customParser->imports = (QQmlTypeNameCache*)0; + bindingsToSkip = *customParserBindings; } } @@ -1154,7 +1163,7 @@ QObject *QQmlObjectCreator::createInstance(int index, QObject *parent, bool isCo QV4::ScopedValue scopeObjectProtector(valueScope, ddata ? ddata->jsWrapper.value() : 0); Q_UNUSED(scopeObjectProtector); QV4::ScopedObject qmlScope(valueScope, QV4::QmlContextWrapper::qmlScope(QV8Engine::get(engine), context, _scopeObject)); - QV4::Scoped<QV4::QmlBindingWrapper> qmlBindingWrapper(valueScope, new (v4->memoryManager) QV4::QmlBindingWrapper(v4->rootContext, qmlScope)); + QV4::Scoped<QV4::QmlBindingWrapper> qmlBindingWrapper(valueScope, v4->memoryManager->alloc<QV4::QmlBindingWrapper>(v4->rootContext, qmlScope)); QV4::ExecutionContext *qmlContext = qmlBindingWrapper->context(); qSwap(_qmlContext, qmlContext); diff --git a/src/qml/qml/qqmlproperty.cpp b/src/qml/qml/qqmlproperty.cpp index 1075b53c5e..96f303dcb5 100644 --- a/src/qml/qml/qqmlproperty.cpp +++ b/src/qml/qml/qqmlproperty.cpp @@ -1427,7 +1427,8 @@ bool QQmlPropertyPrivate::write(QObject *object, list << value.toInt(); v = QVariant::fromValue<QList<int> >(list); ok = true; - } else if (variantType == QVariant::Double && propertyType == qMetaTypeId<QList<qreal> >()) { + } else if ((variantType == QVariant::Double || variantType == QVariant::Int) + && (propertyType == qMetaTypeId<QList<qreal> >())) { QList<qreal> list; list << value.toReal(); v = QVariant::fromValue<QList<qreal> >(list); @@ -1533,7 +1534,7 @@ bool QQmlPropertyPrivate::writeBinding(QObject *object, return false; } else if (isVarProperty) { QV4::FunctionObject *f = result->asFunctionObject(); - if (f && f->bindingKeyFlag) { + if (f && f->bindingKeyFlag()) { // we explicitly disallow this case to avoid confusion. Users can still store one // in an array in a var property if they need to, but the common case is user error. expression->delayedError()->setErrorDescription(QLatin1String("Invalid use of Qt.binding() in a binding declaration.")); @@ -1551,7 +1552,7 @@ bool QQmlPropertyPrivate::writeBinding(QObject *object, writeValueProperty(object, core, QVariant(), context, flags); } else if (type == qMetaTypeId<QJSValue>()) { QV4::FunctionObject *f = result->asFunctionObject(); - if (f && f->bindingKeyFlag) { + if (f && f->bindingKeyFlag()) { expression->delayedError()->setErrorDescription(QLatin1String("Invalid use of Qt.binding() in a binding declaration.")); expression->delayedError()->setErrorObject(object); return false; @@ -1569,7 +1570,7 @@ bool QQmlPropertyPrivate::writeBinding(QObject *object, expression->delayedError()->setErrorObject(object); return false; } else if (QV4::FunctionObject *f = result->asFunctionObject()) { - if (f->bindingKeyFlag) + if (f->bindingKeyFlag()) expression->delayedError()->setErrorDescription(QLatin1String("Invalid use of Qt.binding() in a binding declaration.")); else expression->delayedError()->setErrorDescription(QLatin1String("Unable to assign a function to a property of any type other than var.")); diff --git a/src/qml/qml/qqmltypeloader.cpp b/src/qml/qml/qqmltypeloader.cpp index 7fc08bd114..36dc17a085 100644 --- a/src/qml/qml/qqmltypeloader.cpp +++ b/src/qml/qml/qqmltypeloader.cpp @@ -897,11 +897,20 @@ QQmlDataLoader::QQmlDataLoader(QQmlEngine *engine) /*! \internal */ QQmlDataLoader::~QQmlDataLoader() { + invalidate(); +} + +void QQmlDataLoader::invalidate() +{ for (NetworkReplies::Iterator iter = m_networkReplies.begin(); iter != m_networkReplies.end(); ++iter) (*iter)->release(); + m_networkReplies.clear(); - shutdownThread(); - delete m_thread; + if (m_thread) { + shutdownThread(); + delete m_thread; + m_thread = 0; + } } void QQmlDataLoader::lock() @@ -1228,7 +1237,7 @@ void QQmlDataLoader::setCachedUnit(QQmlDataBlob *blob, const QQmlPrivate::Cached void QQmlDataLoader::shutdownThread() { - if (!m_thread->isShutdown()) + if (m_thread && !m_thread->isShutdown()) m_thread->shutdown(); } @@ -2207,7 +2216,7 @@ void QQmlTypeData::dataReceived(const Data &data) QQmlEngine *qmlEngine = typeLoader()->engine(); m_document.reset(new QmlIR::Document(QV8Engine::getV4(qmlEngine)->debugger != 0)); QmlIR::IRBuilder compiler(QV8Engine::get(qmlEngine)->illegalNames()); - if (!compiler.generateFromQml(code, finalUrlString(), finalUrlString(), m_document.data())) { + if (!compiler.generateFromQml(code, finalUrlString(), m_document.data())) { QList<QQmlError> errors; foreach (const QQmlJS::DiagnosticMessage &msg, compiler.errors) { QQmlError e; @@ -2332,10 +2341,8 @@ void QQmlTypeData::compile() Q_ASSERT(m_compiledData == 0); m_compiledData = new QQmlCompiledData(typeLoader()->engine()); - m_compiledData->url = finalUrl(); - m_compiledData->name = finalUrlString(); - QQmlCompilingProfiler prof(QQmlEnginePrivate::get(typeLoader()->engine())->profiler, m_compiledData->name); + QQmlCompilingProfiler prof(QQmlEnginePrivate::get(typeLoader()->engine())->profiler, finalUrlString()); QQmlTypeCompiler compiler(QQmlEnginePrivate::get(typeLoader()->engine()), m_compiledData, this, m_document.data()); if (!compiler.compile()) { @@ -2547,7 +2554,7 @@ void QQmlScriptData::initialize(QQmlEngine *engine) QV8Engine *v8engine = ep->v8engine(); QV4::ExecutionEngine *v4 = QV8Engine::getV4(v8engine); - m_program = new QV4::Script(v4, QV4::ObjectRef::null(), m_precompiledScript); + m_program = new QV4::Script(v4, 0, m_precompiledScript); addToEngine(engine); diff --git a/src/qml/qml/qqmltypeloader_p.h b/src/qml/qml/qqmltypeloader_p.h index b09ac15861..3d0b77e2a5 100644 --- a/src/qml/qml/qqmltypeloader_p.h +++ b/src/qml/qml/qqmltypeloader_p.h @@ -233,6 +233,7 @@ public: QQmlEngine *engine() const; void initializeEngine(QQmlExtensionInterface *, const char *); + void invalidate(); protected: void shutdownThread(); diff --git a/src/qml/qml/qqmltypewrapper.cpp b/src/qml/qml/qqmltypewrapper.cpp index 573779acab..53afd36437 100644 --- a/src/qml/qml/qqmltypewrapper.cpp +++ b/src/qml/qml/qqmltypewrapper.cpp @@ -56,14 +56,15 @@ using namespace QV4; DEFINE_OBJECT_VTABLE(QmlTypeWrapper); -QmlTypeWrapper::QmlTypeWrapper(QV8Engine *engine) - : Object(QV8Engine::getV4(engine)), - v8(engine), mode(IncludeEnums), type(0), typeNamespace(0), importNamespace(0) +QmlTypeWrapper::Data::Data(QV8Engine *engine) + : Object::Data(QV8Engine::getV4(engine)) + , v8(engine) + , mode(IncludeEnums) { setVTable(staticVTable()); } -QmlTypeWrapper::~QmlTypeWrapper() +QmlTypeWrapper::Data::~Data() { if (typeNamespace) typeNamespace->release(); @@ -71,14 +72,14 @@ QmlTypeWrapper::~QmlTypeWrapper() bool QmlTypeWrapper::isSingleton() const { - return type && type->isSingleton(); + return d()->type && d()->type->isSingleton(); } QVariant QmlTypeWrapper::toVariant() const { - if (type && type->isSingleton()) { - QQmlEngine *e = v8->engine(); - QQmlType::SingletonInstanceInfo *siinfo = type->singletonInstanceInfo(); + if (d()->type && d()->type->isSingleton()) { + QQmlEngine *e = d()->v8->engine(); + QQmlType::SingletonInstanceInfo *siinfo = d()->type->singletonInstanceInfo(); siinfo->init(e); // note: this will also create QJSValue singleton which isn't strictly required. QObject *qobjectSingleton = siinfo->qobjectApi(e); if (qobjectSingleton) { @@ -98,8 +99,8 @@ ReturnedValue QmlTypeWrapper::create(QV8Engine *v8, QObject *o, QQmlType *t, Typ ExecutionEngine *v4 = QV8Engine::getV4(v8); Scope scope(v4); - Scoped<QmlTypeWrapper> w(scope, new (v4->memoryManager) QmlTypeWrapper(v8)); - w->mode = mode; w->object = o; w->type = t; + Scoped<QmlTypeWrapper> w(scope, v4->memoryManager->alloc<QmlTypeWrapper>(v8)); + w->d()->mode = mode; w->d()->object = o; w->d()->type = t; return w.asReturnedValue(); } @@ -112,14 +113,14 @@ ReturnedValue QmlTypeWrapper::create(QV8Engine *v8, QObject *o, QQmlTypeNameCach ExecutionEngine *v4 = QV8Engine::getV4(v8); Scope scope(v4); - Scoped<QmlTypeWrapper> w(scope, new (v4->memoryManager) QmlTypeWrapper(v8)); - w->mode = mode; w->object = o; w->typeNamespace = t; w->importNamespace = importNamespace; + Scoped<QmlTypeWrapper> w(scope, v4->memoryManager->alloc<QmlTypeWrapper>(v8)); + w->d()->mode = mode; w->d()->object = o; w->d()->typeNamespace = t; w->d()->importNamespace = importNamespace; t->addref(); return w.asReturnedValue(); } -ReturnedValue QmlTypeWrapper::get(Managed *m, const StringRef name, bool *hasProperty) +ReturnedValue QmlTypeWrapper::get(Managed *m, String *name, bool *hasProperty) { QV4::ExecutionEngine *v4 = m->engine(); QV4::Scope scope(v4); @@ -132,13 +133,13 @@ ReturnedValue QmlTypeWrapper::get(Managed *m, const StringRef name, bool *hasPro if (hasProperty) *hasProperty = true; - QV8Engine *v8engine = w->v8; + QV8Engine *v8engine = w->d()->v8; QQmlContextData *context = v8engine->callingContext(); - QObject *object = w->object; + QObject *object = w->d()->object; - if (w->type) { - QQmlType *type = w->type; + if (w->d()->type) { + QQmlType *type = w->d()->type; // singleton types are handled differently to other types. if (type->isSingleton()) { @@ -150,7 +151,7 @@ ReturnedValue QmlTypeWrapper::get(Managed *m, const StringRef name, bool *hasPro if (qobjectSingleton) { // check for enum value if (name->startsWithUpper()) { - if (w->mode == IncludeEnums) { + if (w->d()->mode == IncludeEnums) { // ### Optimize QByteArray enumName = name->toQString().toUtf8(); const QMetaObject *metaObject = qobjectSingleton->metaObject(); @@ -165,7 +166,7 @@ ReturnedValue QmlTypeWrapper::get(Managed *m, const StringRef name, bool *hasPro } // check for property. - return QV4::QObjectWrapper::getQmlProperty(v4->currentContext(), context, qobjectSingleton, name.getPointer(), QV4::QObjectWrapper::IgnoreRevision, hasProperty); + return QV4::QObjectWrapper::getQmlProperty(v4->currentContext(), context, qobjectSingleton, name, QV4::QObjectWrapper::IgnoreRevision, hasProperty); } else if (!siinfo->scriptApi(e).isUndefined()) { // NOTE: if used in a binding, changes will not trigger re-evaluation since non-NOTIFYable. QV4::ScopedObject o(scope, QJSValuePrivate::get(siinfo->scriptApi(e))->getValue(v4)); @@ -185,10 +186,10 @@ ReturnedValue QmlTypeWrapper::get(Managed *m, const StringRef name, bool *hasPro // Fall through to base implementation - } else if (w->object) { + } else if (w->d()->object) { QObject *ao = qmlAttachedPropertiesObjectById(type->attachedPropertiesId(), object); if (ao) - return QV4::QObjectWrapper::getQmlProperty(v4->currentContext(), context, ao, name.getPointer(), QV4::QObjectWrapper::IgnoreRevision, hasProperty); + return QV4::QObjectWrapper::getQmlProperty(v4->currentContext(), context, ao, name, QV4::QObjectWrapper::IgnoreRevision, hasProperty); // Fall through to base implementation } @@ -198,19 +199,19 @@ ReturnedValue QmlTypeWrapper::get(Managed *m, const StringRef name, bool *hasPro // Fall through to base implementation - } else if (w->typeNamespace) { - Q_ASSERT(w->importNamespace); - QQmlTypeNameCache::Result r = w->typeNamespace->query(name, w->importNamespace); + } else if (w->d()->typeNamespace) { + Q_ASSERT(w->d()->importNamespace); + QQmlTypeNameCache::Result r = w->d()->typeNamespace->query(name, w->d()->importNamespace); if (r.isValid()) { QQmlContextData *context = v8engine->callingContext(); if (r.type) { - return create(w->v8, object, r.type, w->mode); + return create(w->d()->v8, object, r.type, w->d()->mode); } else if (r.scriptIndex != -1) { QV4::ScopedObject scripts(scope, context->importedScripts); return scripts->getIndexed(r.scriptIndex); } else if (r.importNamespace) { - return create(w->v8, object, context->imports, r.importNamespace); + return create(w->d()->v8, object, context->imports, r.importNamespace); } return QV4::Encode::undefined(); @@ -229,7 +230,7 @@ ReturnedValue QmlTypeWrapper::get(Managed *m, const StringRef name, bool *hasPro } -void QmlTypeWrapper::put(Managed *m, const StringRef name, const ValueRef value) +void QmlTypeWrapper::put(Managed *m, String *name, const ValueRef value) { QmlTypeWrapper *w = m->as<QmlTypeWrapper>(); QV4::ExecutionEngine *v4 = m->engine(); @@ -244,12 +245,12 @@ void QmlTypeWrapper::put(Managed *m, const StringRef name, const ValueRef value) QV8Engine *v8engine = v4->v8Engine; QQmlContextData *context = v8engine->callingContext(); - QQmlType *type = w->type; - if (type && !type->isSingleton() && w->object) { - QObject *object = w->object; + QQmlType *type = w->d()->type; + if (type && !type->isSingleton() && w->d()->object) { + QObject *object = w->d()->object; QObject *ao = qmlAttachedPropertiesObjectById(type->attachedPropertiesId(), object); if (ao) - QV4::QObjectWrapper::setQmlProperty(v4->currentContext(), context, ao, name.getPointer(), QV4::QObjectWrapper::IgnoreRevision, value); + QV4::QObjectWrapper::setQmlProperty(v4->currentContext(), context, ao, name, QV4::QObjectWrapper::IgnoreRevision, value); } else if (type && type->isSingleton()) { QQmlEngine *e = v8engine->engine(); QQmlType::SingletonInstanceInfo *siinfo = type->singletonInstanceInfo(); @@ -257,7 +258,7 @@ void QmlTypeWrapper::put(Managed *m, const StringRef name, const ValueRef value) QObject *qobjectSingleton = siinfo->qobjectApi(e); if (qobjectSingleton) { - QV4::QObjectWrapper::setQmlProperty(v4->currentContext(), context, qobjectSingleton, name.getPointer(), QV4::QObjectWrapper::IgnoreRevision, value); + QV4::QObjectWrapper::setQmlProperty(v4->currentContext(), context, qobjectSingleton, name, QV4::QObjectWrapper::IgnoreRevision, value); } else if (!siinfo->scriptApi(e).isUndefined()) { QV4::ScopedObject apiprivate(scope, QJSValuePrivate::get(siinfo->scriptApi(e))->value); if (!apiprivate) { @@ -271,19 +272,17 @@ void QmlTypeWrapper::put(Managed *m, const StringRef name, const ValueRef value) } } -PropertyAttributes QmlTypeWrapper::query(const Managed *m, StringRef name) +PropertyAttributes QmlTypeWrapper::query(const Managed *m, String *name) { // ### Implement more efficiently. - Scope scope(m->engine()); - ScopedString n(scope, name); bool hasProperty = false; - static_cast<Object *>(const_cast<Managed*>(m))->get(n, &hasProperty); + static_cast<Object *>(const_cast<Managed*>(m))->get(name, &hasProperty); return hasProperty ? Attr_Data : Attr_Invalid; } void QmlTypeWrapper::destroy(Managed *that) { - static_cast<QmlTypeWrapper *>(that)->~QmlTypeWrapper(); + static_cast<QmlTypeWrapper *>(that)->d()->~Data(); } bool QmlTypeWrapper::isEqualTo(Managed *a, Managed *b) diff --git a/src/qml/qml/qqmltypewrapper_p.h b/src/qml/qml/qqmltypewrapper_p.h index 355a6751a9..27ecac991e 100644 --- a/src/qml/qml/qqmltypewrapper_p.h +++ b/src/qml/qml/qqmltypewrapper_p.h @@ -68,13 +68,23 @@ namespace QV4 { struct Q_QML_EXPORT QmlTypeWrapper : Object { - V4_OBJECT + enum TypeNameMode { IncludeEnums, ExcludeEnums }; + + struct Data : Object::Data { + Data(QV8Engine *engine); + ~Data(); + QV8Engine *v8; + TypeNameMode mode; + QPointer<QObject> object; + + QQmlType *type; + QQmlTypeNameCache *typeNamespace; + const void *importNamespace; + }; + V4_OBJECT(Object) private: - QmlTypeWrapper(QV8Engine *engine); - ~QmlTypeWrapper(); public: - enum TypeNameMode { IncludeEnums, ExcludeEnums }; bool isSingleton() const; @@ -84,22 +94,13 @@ public: static ReturnedValue create(QV8Engine *, QObject *, QQmlTypeNameCache *, const void *, TypeNameMode = IncludeEnums); - static ReturnedValue get(Managed *m, const StringRef name, bool *hasProperty); - static void put(Managed *m, const StringRef name, const ValueRef value); - static PropertyAttributes query(const Managed *, StringRef name); + static ReturnedValue get(Managed *m, String *name, bool *hasProperty); + static void put(Managed *m, String *name, const ValueRef value); + static PropertyAttributes query(const Managed *, String *name); static void destroy(Managed *that); -protected: static bool isEqualTo(Managed *that, Managed *o); -private: - QV8Engine *v8; - TypeNameMode mode; - QPointer<QObject> object; - - QQmlType *type; - QQmlTypeNameCache *typeNamespace; - const void *importNamespace; }; } diff --git a/src/qml/qml/qqmlvaluetypewrapper.cpp b/src/qml/qml/qqmlvaluetypewrapper.cpp index 9a87493e54..1de596b4d3 100644 --- a/src/qml/qml/qqmlvaluetypewrapper.cpp +++ b/src/qml/qml/qqmlvaluetypewrapper.cpp @@ -59,41 +59,46 @@ using namespace QV4; DEFINE_OBJECT_VTABLE(QmlValueTypeWrapper); -class QmlValueTypeReference : public QmlValueTypeWrapper +struct QmlValueTypeReference : public QmlValueTypeWrapper { -public: - QmlValueTypeReference(QV8Engine *engine); - - QPointer<QObject> object; - int property; + struct Data : QmlValueTypeWrapper::Data + { + Data(QV8Engine *engine); + QPointer<QObject> object; + int property; + }; + V4_OBJECT(QmlValueTypeWrapper) }; -class QmlValueTypeCopy : public QmlValueTypeWrapper -{ -public: - QmlValueTypeCopy(QV8Engine *engine); +DEFINE_OBJECT_VTABLE(QmlValueTypeReference); - QVariant value; +struct QmlValueTypeCopy : public QmlValueTypeWrapper +{ + struct Data : QmlValueTypeWrapper::Data + { + Data(QV8Engine *engine); + QVariant value; + }; + V4_OBJECT(QmlValueTypeWrapper) }; -QmlValueTypeWrapper::QmlValueTypeWrapper(QV8Engine *engine, ObjectType objectType) - : Object(QV8Engine::getV4(engine)), objectType(objectType) -{ - v8 = engine; - setVTable(staticVTable()); -} +DEFINE_OBJECT_VTABLE(QmlValueTypeCopy); -QmlValueTypeWrapper::~QmlValueTypeWrapper() +QmlValueTypeWrapper::Data::Data(QV8Engine *engine, ObjectType objectType) + : Object::Data(QV8Engine::getV4(engine)) + , v8(engine) + , objectType(objectType) { + setVTable(staticVTable()); } -QmlValueTypeReference::QmlValueTypeReference(QV8Engine *engine) -: QmlValueTypeWrapper(engine, Reference) +QmlValueTypeReference::Data::Data(QV8Engine *engine) + : QmlValueTypeWrapper::Data(engine, Reference) { } -QmlValueTypeCopy::QmlValueTypeCopy(QV8Engine *engine) -: QmlValueTypeWrapper(engine, Copy) +QmlValueTypeCopy::Data::Data(QV8Engine *engine) + : QmlValueTypeWrapper::Data(engine, Copy) { } @@ -102,30 +107,30 @@ static bool readReferenceValue(const QmlValueTypeReference *reference) { // A reference resource may be either a "true" reference (eg, to a QVector3D property) // or a "variant" reference (eg, to a QVariant property which happens to contain a value-type). - QMetaProperty writebackProperty = reference->object->metaObject()->property(reference->property); + QMetaProperty writebackProperty = reference->d()->object->metaObject()->property(reference->d()->property); if (writebackProperty.userType() == QMetaType::QVariant) { // variant-containing-value-type reference QVariant variantReferenceValue; - reference->type->readVariantValue(reference->object, reference->property, &variantReferenceValue); + reference->d()->type->readVariantValue(reference->d()->object, reference->d()->property, &variantReferenceValue); int variantReferenceType = variantReferenceValue.userType(); - if (variantReferenceType != reference->type->userType()) { + if (variantReferenceType != reference->d()->type->userType()) { // This is a stale VariantReference. That is, the variant has been // overwritten with a different type in the meantime. // We need to modify this reference to the updated value type, if // possible, or return false if it is not a value type. if (QQmlValueTypeFactory::isValueType(variantReferenceType)) { - reference->type = QQmlValueTypeFactory::valueType(variantReferenceType); - if (!reference->type) { + reference->d()->type = QQmlValueTypeFactory::valueType(variantReferenceType); + if (!reference->d()->type) { return false; } } else { return false; } } - reference->type->setValue(variantReferenceValue); + reference->d()->type->setValue(variantReferenceValue); } else { // value-type reference - reference->type->read(reference->object, reference->property); + reference->d()->type->read(reference->d()->object, reference->d()->property); } return true; } @@ -147,10 +152,10 @@ ReturnedValue QmlValueTypeWrapper::create(QV8Engine *v8, QObject *object, int pr Scope scope(v4); initProto(v4); - Scoped<QmlValueTypeReference> r(scope, new (v4->memoryManager) QmlValueTypeReference(v8)); - r->setPrototype(v4->qmlExtensions()->valueTypeWrapperPrototype); - r->type = type; r->object = object; r->property = property; - return r.asReturnedValue(); + QmlValueTypeReference *r = v4->memoryManager->alloc<QmlValueTypeReference>(v8); + r->d()->internalClass = r->d()->internalClass->changePrototype(v4->qmlExtensions()->valueTypeWrapperPrototype); + r->d()->type = type; r->d()->object = object; r->d()->property = property; + return r->asReturnedValue(); } ReturnedValue QmlValueTypeWrapper::create(QV8Engine *v8, const QVariant &value, QQmlValueType *type) @@ -159,45 +164,44 @@ ReturnedValue QmlValueTypeWrapper::create(QV8Engine *v8, const QVariant &value, Scope scope(v4); initProto(v4); - Scoped<QmlValueTypeCopy> r(scope, new (v4->memoryManager) QmlValueTypeCopy(v8)); - r->setPrototype(v4->qmlExtensions()->valueTypeWrapperPrototype); - r->type = type; r->value = value; - return r.asReturnedValue(); + QmlValueTypeCopy *r = v4->memoryManager->alloc<QmlValueTypeCopy>(v8); + r->d()->internalClass = r->d()->internalClass->changePrototype(v4->qmlExtensions()->valueTypeWrapperPrototype); + r->d()->type = type; r->d()->value = value; + return r->asReturnedValue(); } QVariant QmlValueTypeWrapper::toVariant() const { - if (objectType == QmlValueTypeWrapper::Reference) { + if (d()->objectType == QmlValueTypeWrapper::Reference) { const QmlValueTypeReference *reference = static_cast<const QmlValueTypeReference *>(this); - if (reference->object && readReferenceValue(reference)) { - return reference->type->value(); + if (reference->d()->object && readReferenceValue(reference)) { + return reference->d()->type->value(); } else { return QVariant(); } } else { - Q_ASSERT(objectType == QmlValueTypeWrapper::Copy); - return static_cast<const QmlValueTypeCopy *>(this)->value; + Q_ASSERT(d()->objectType == QmlValueTypeWrapper::Copy); + return static_cast<const QmlValueTypeCopy *>(this)->d()->value; } } void QmlValueTypeWrapper::destroy(Managed *that) { QmlValueTypeWrapper *w = that->as<QmlValueTypeWrapper>(); - assert(w); - if (w->objectType == Reference) - static_cast<QmlValueTypeReference *>(w)->~QmlValueTypeReference(); + if (w->d()->objectType == Reference) + static_cast<QmlValueTypeReference *>(w)->d()->~Data(); else - static_cast<QmlValueTypeCopy *>(w)->~QmlValueTypeCopy(); + static_cast<QmlValueTypeCopy *>(w)->d()->~Data(); } bool QmlValueTypeWrapper::isEqualTo(Managed *m, Managed *other) { QV4::QmlValueTypeWrapper *lv = m->as<QmlValueTypeWrapper>(); - assert(lv); + Q_ASSERT(lv); if (QV4::VariantObject *rv = other->as<VariantObject>()) - return lv->isEqual(rv->data); + return lv->isEqual(rv->d()->data); if (QV4::QmlValueTypeWrapper *v = other->as<QmlValueTypeWrapper>()) return lv->isEqual(v->toVariant()); @@ -205,7 +209,7 @@ bool QmlValueTypeWrapper::isEqualTo(Managed *m, Managed *other) return false; } -PropertyAttributes QmlValueTypeWrapper::query(const Managed *m, StringRef name) +PropertyAttributes QmlValueTypeWrapper::query(const Managed *m, String *name) { const QmlValueTypeWrapper *r = m->as<const QmlValueTypeWrapper>(); QV4::ExecutionEngine *v4 = m->engine(); @@ -217,59 +221,59 @@ PropertyAttributes QmlValueTypeWrapper::query(const Managed *m, StringRef name) QQmlPropertyData local; QQmlPropertyData *result = 0; { - QQmlData *ddata = QQmlData::get(r->type, false); + QQmlData *ddata = QQmlData::get(r->d()->type, false); if (ddata && ddata->propertyCache) - result = ddata->propertyCache->property(name.getPointer(), 0, 0); + result = ddata->propertyCache->property(name, 0, 0); else - result = QQmlPropertyCache::property(r->v8->engine(), r->type, name.getPointer(), 0, local); + result = QQmlPropertyCache::property(r->d()->v8->engine(), r->d()->type, name, 0, local); } return result ? Attr_Data : Attr_Invalid; } bool QmlValueTypeWrapper::isEqual(const QVariant& value) { - if (objectType == QmlValueTypeWrapper::Reference) { + if (d()->objectType == QmlValueTypeWrapper::Reference) { QmlValueTypeReference *reference = static_cast<QmlValueTypeReference *>(this); - if (reference->object && readReferenceValue(reference)) { - return reference->type->isEqual(value); + if (reference->d()->object && readReferenceValue(reference)) { + return reference->d()->type->isEqual(value); } else { return false; } } else { - Q_ASSERT(objectType == QmlValueTypeWrapper::Copy); + Q_ASSERT(d()->objectType == QmlValueTypeWrapper::Copy); QmlValueTypeCopy *copy = static_cast<QmlValueTypeCopy *>(this); - type->setValue(copy->value); - if (type->isEqual(value)) + d()->type->setValue(copy->d()->value); + if (d()->type->isEqual(value)) return true; - return (value == copy->value); + return (value == copy->d()->value); } } ReturnedValue QmlValueTypeWrapper::method_toString(CallContext *ctx) { - Object *o = ctx->callData->thisObject.asObject(); + Object *o = ctx->d()->callData->thisObject.asObject(); if (!o) return ctx->throwTypeError(); QmlValueTypeWrapper *w = o->as<QmlValueTypeWrapper>(); if (!w) return ctx->throwTypeError(); - if (w->objectType == QmlValueTypeWrapper::Reference) { + if (w->d()->objectType == QmlValueTypeWrapper::Reference) { QmlValueTypeReference *reference = static_cast<QmlValueTypeReference *>(w); - if (reference->object && readReferenceValue(reference)) { - return w->v8->toString(w->type->toString()); + if (reference->d()->object && readReferenceValue(reference)) { + return w->d()->v8->toString(w->d()->type->toString()); } else { return QV4::Encode::undefined(); } } else { - Q_ASSERT(w->objectType == QmlValueTypeWrapper::Copy); + Q_ASSERT(w->d()->objectType == QmlValueTypeWrapper::Copy); QmlValueTypeCopy *copy = static_cast<QmlValueTypeCopy *>(w); - w->type->setValue(copy->value); - return w->v8->toString(w->type->toString()); + w->d()->type->setValue(copy->d()->value); + return w->d()->v8->toString(w->d()->type->toString()); } } -ReturnedValue QmlValueTypeWrapper::get(Managed *m, const StringRef name, bool *hasProperty) +ReturnedValue QmlValueTypeWrapper::get(Managed *m, String *name, bool *hasProperty) { QmlValueTypeWrapper *r = m->as<QmlValueTypeWrapper>(); QV4::ExecutionEngine *v4 = m->engine(); @@ -277,28 +281,28 @@ ReturnedValue QmlValueTypeWrapper::get(Managed *m, const StringRef name, bool *h return v4->currentContext()->throwTypeError(); // Note: readReferenceValue() can change the reference->type. - if (r->objectType == QmlValueTypeWrapper::Reference) { + if (r->d()->objectType == QmlValueTypeWrapper::Reference) { QmlValueTypeReference *reference = static_cast<QmlValueTypeReference *>(r); - if (!reference->object || !readReferenceValue(reference)) + if (!reference->d()->object || !readReferenceValue(reference)) return Primitive::undefinedValue().asReturnedValue(); } else { - Q_ASSERT(r->objectType == QmlValueTypeWrapper::Copy); + Q_ASSERT(r->d()->objectType == QmlValueTypeWrapper::Copy); QmlValueTypeCopy *copy = static_cast<QmlValueTypeCopy *>(r); - r->type->setValue(copy->value); + r->d()->type->setValue(copy->d()->value); } QQmlPropertyData local; QQmlPropertyData *result = 0; { - QQmlData *ddata = QQmlData::get(r->type, false); + QQmlData *ddata = QQmlData::get(r->d()->type, false); if (ddata && ddata->propertyCache) - result = ddata->propertyCache->property(name.getPointer(), 0, 0); + result = ddata->propertyCache->property(name, 0, 0); else - result = QQmlPropertyCache::property(r->v8->engine(), r->type, name, 0, local); + result = QQmlPropertyCache::property(r->d()->v8->engine(), r->d()->type, name, 0, local); } if (!result) @@ -307,31 +311,31 @@ ReturnedValue QmlValueTypeWrapper::get(Managed *m, const StringRef name, bool *h if (result->isFunction()) { // calling a Q_INVOKABLE function of a value type QQmlContextData *qmlContext = QV4::QmlContextWrapper::callingContext(v4); - return QV4::QObjectWrapper::getQmlProperty(v4->currentContext(), qmlContext, r->type, name.getPointer(), QV4::QObjectWrapper::IgnoreRevision); + return QV4::QObjectWrapper::getQmlProperty(v4->currentContext(), qmlContext, r->d()->type, name, QV4::QObjectWrapper::IgnoreRevision); } #define VALUE_TYPE_LOAD(metatype, cpptype, constructor) \ if (result->propType == metatype) { \ cpptype v; \ void *args[] = { &v, 0 }; \ - r->type->qt_metacall(QMetaObject::ReadProperty, result->coreIndex, args); \ + r->d()->type->qt_metacall(QMetaObject::ReadProperty, result->coreIndex, args); \ return constructor(v); \ } // These four types are the most common used by the value type wrappers VALUE_TYPE_LOAD(QMetaType::QReal, qreal, QV4::Encode); VALUE_TYPE_LOAD(QMetaType::Int, int, QV4::Encode); - VALUE_TYPE_LOAD(QMetaType::QString, QString, r->v8->toString); + VALUE_TYPE_LOAD(QMetaType::QString, QString, r->d()->v8->toString); VALUE_TYPE_LOAD(QMetaType::Bool, bool, QV4::Encode); QVariant v(result->propType, (void *)0); void *args[] = { v.data(), 0 }; - r->type->qt_metacall(QMetaObject::ReadProperty, result->coreIndex, args); - return r->v8->fromVariant(v); + r->d()->type->qt_metacall(QMetaObject::ReadProperty, result->coreIndex, args); + return r->d()->v8->fromVariant(v); #undef VALUE_TYPE_ACCESSOR } -void QmlValueTypeWrapper::put(Managed *m, const StringRef name, const ValueRef value) +void QmlValueTypeWrapper::put(Managed *m, String *name, const ValueRef value) { ExecutionEngine *v4 = m->engine(); Scope scope(v4); @@ -345,38 +349,38 @@ void QmlValueTypeWrapper::put(Managed *m, const StringRef name, const ValueRef v } QByteArray propName = name->toQString().toUtf8(); - if (r->objectType == QmlValueTypeWrapper::Reference) { + if (r->d()->objectType == QmlValueTypeWrapper::Reference) { QmlValueTypeReference *reference = static_cast<QmlValueTypeReference *>(r.getPointer()); - QMetaProperty writebackProperty = reference->object->metaObject()->property(reference->property); + QMetaProperty writebackProperty = reference->d()->object->metaObject()->property(reference->d()->property); - if (!reference->object || !writebackProperty.isWritable() || !readReferenceValue(reference)) + if (!reference->d()->object || !writebackProperty.isWritable() || !readReferenceValue(reference)) return; // we lookup the index after readReferenceValue() since it can change the reference->type. - int index = r->type->metaObject()->indexOfProperty(propName.constData()); + int index = r->d()->type->metaObject()->indexOfProperty(propName.constData()); if (index == -1) return; - QMetaProperty p = r->type->metaObject()->property(index); + QMetaProperty p = r->d()->type->metaObject()->property(index); QQmlBinding *newBinding = 0; QV4::ScopedFunctionObject f(scope, value); if (f) { - if (!f->bindingKeyFlag) { + if (!f->bindingKeyFlag()) { // assigning a JS function to a non-var-property is not allowed. QString error = QLatin1String("Cannot assign JavaScript function to value-type property"); - Scoped<String> e(scope, r->v8->toString(error)); + Scoped<String> e(scope, r->d()->v8->toString(error)); v4->currentContext()->throwError(e); return; } - QQmlContextData *context = r->v8->callingContext(); + QQmlContextData *context = r->d()->v8->callingContext(); QQmlPropertyData cacheData; cacheData.setFlags(QQmlPropertyData::IsWritable | QQmlPropertyData::IsValueTypeVirtual); - cacheData.propType = reference->object->metaObject()->property(reference->property).userType(); - cacheData.coreIndex = reference->property; + cacheData.propType = reference->d()->object->metaObject()->property(reference->d()->property).userType(); + cacheData.coreIndex = reference->d()->property; cacheData.valueTypeFlags = 0; cacheData.valueTypeCoreIndex = index; cacheData.valueTypePropType = p.userType(); @@ -384,46 +388,46 @@ void QmlValueTypeWrapper::put(Managed *m, const StringRef name, const ValueRef v QV4::Scoped<QQmlBindingFunction> bindingFunction(scope, f); bindingFunction->initBindingLocation(); - newBinding = new QQmlBinding(value, reference->object, context); - newBinding->setTarget(reference->object, cacheData, context); + newBinding = new QQmlBinding(value, reference->d()->object, context); + newBinding->setTarget(reference->d()->object, cacheData, context); } QQmlAbstractBinding *oldBinding = - QQmlPropertyPrivate::setBinding(reference->object, reference->property, index, newBinding); + QQmlPropertyPrivate::setBinding(reference->d()->object, reference->d()->property, index, newBinding); if (oldBinding) oldBinding->destroy(); if (!f) { - QVariant v = r->v8->toVariant(value, -1); + QVariant v = r->d()->v8->toVariant(value, -1); if (p.isEnumType() && (QMetaType::Type)v.type() == QMetaType::Double) v = v.toInt(); - p.write(reference->type, v); + p.write(reference->d()->type, v); if (writebackProperty.userType() == QMetaType::QVariant) { - QVariant variantReferenceValue = r->type->value(); - reference->type->writeVariantValue(reference->object, reference->property, 0, &variantReferenceValue); + QVariant variantReferenceValue = r->d()->type->value(); + reference->d()->type->writeVariantValue(reference->d()->object, reference->d()->property, 0, &variantReferenceValue); } else { - reference->type->write(reference->object, reference->property, 0); + reference->d()->type->write(reference->d()->object, reference->d()->property, 0); } } } else { - Q_ASSERT(r->objectType == QmlValueTypeWrapper::Copy); + Q_ASSERT(r->d()->objectType == QmlValueTypeWrapper::Copy); QmlValueTypeCopy *copy = static_cast<QmlValueTypeCopy *>(r.getPointer()); - int index = r->type->metaObject()->indexOfProperty(propName.constData()); + int index = r->d()->type->metaObject()->indexOfProperty(propName.constData()); if (index == -1) return; - QVariant v = r->v8->toVariant(value, -1); + QVariant v = r->d()->v8->toVariant(value, -1); - r->type->setValue(copy->value); - QMetaProperty p = r->type->metaObject()->property(index); - p.write(r->type, v); - copy->value = r->type->value(); + r->d()->type->setValue(copy->d()->value); + QMetaProperty p = r->d()->type->metaObject()->property(index); + p.write(r->d()->type, v); + copy->d()->value = r->d()->type->value(); } } diff --git a/src/qml/qml/qqmlvaluetypewrapper_p.h b/src/qml/qml/qqmlvaluetypewrapper_p.h index d66dbbba0c..53d5ae95af 100644 --- a/src/qml/qml/qqmlvaluetypewrapper_p.h +++ b/src/qml/qml/qqmlvaluetypewrapper_p.h @@ -68,11 +68,14 @@ namespace QV4 { struct Q_QML_EXPORT QmlValueTypeWrapper : Object { - V4_OBJECT -protected: enum ObjectType { Reference, Copy }; - QmlValueTypeWrapper(QV8Engine *engine, ObjectType type); - ~QmlValueTypeWrapper(); + struct Data : Object::Data { + Data(QV8Engine *engine, ObjectType type); + QV8Engine *v8; + ObjectType objectType; + mutable QQmlValueType *type; + }; + V4_OBJECT(Object) public: @@ -82,19 +85,14 @@ public: QVariant toVariant() const; bool isEqual(const QVariant& value); - - static ReturnedValue get(Managed *m, const StringRef name, bool *hasProperty); - static void put(Managed *m, const StringRef name, const ValueRef value); + static ReturnedValue get(Managed *m, String *name, bool *hasProperty); + static void put(Managed *m, String *name, const ValueRef value); static void destroy(Managed *that); static bool isEqualTo(Managed *m, Managed *other); - static PropertyAttributes query(const Managed *, StringRef name); + static PropertyAttributes query(const Managed *, String *name); static QV4::ReturnedValue method_toString(CallContext *ctx); - QV8Engine *v8; - ObjectType objectType; - mutable QQmlValueType *type; - static void initProto(ExecutionEngine *v4); }; diff --git a/src/qml/qml/qqmlvmemetaobject.cpp b/src/qml/qml/qqmlvmemetaobject.cpp index 1ff95a245d..2f04984264 100644 --- a/src/qml/qml/qqmlvmemetaobject.cpp +++ b/src/qml/qml/qqmlvmemetaobject.cpp @@ -1087,7 +1087,7 @@ void QQmlVMEMetaObject::writeProperty(int id, const QVariant &value) // And, if the new value is a scarce resource, we need to ensure that it does not get // automatically released by the engine until no other references to it exist. QV4::ScopedValue newv(scope, QQmlEnginePrivate::get(ctxt->engine)->v8engine()->fromVariant(value)); - QV4::VariantObjectRef v = newv; + QV4::Scoped<QV4::VariantObject> v(scope, newv); if (!!v) v->addVmePropertyReference(); diff --git a/src/qml/qml/qqmlxmlhttprequest.cpp b/src/qml/qml/qqmlxmlhttprequest.cpp index d89dc92b68..e7bea80a18 100644 --- a/src/qml/qml/qqmlxmlhttprequest.cpp +++ b/src/qml/qml/qqmlxmlhttprequest.cpp @@ -72,7 +72,7 @@ using namespace QV4; #ifndef QT_NO_XMLSTREAMREADER #define V4THROW_REFERENCE(string) { \ - Scoped<Object> error(scope, ctx->engine->newReferenceErrorObject(QStringLiteral(string))); \ + Scoped<Object> error(scope, ctx->engine()->newReferenceErrorObject(QStringLiteral(string))); \ return ctx->throwError(error); \ } @@ -105,9 +105,9 @@ static ReturnedValue constructMeObject(const ValueRef thisObj, QV8Engine *e) ExecutionEngine *v4 = QV8Engine::getV4(e); Scope scope(v4); Scoped<Object> meObj(scope, v4->newObject()); - meObj->put(ScopedString(scope, v4->newString(QStringLiteral("ThisObject"))), thisObj); + meObj->put(ScopedString(scope, v4->newString(QStringLiteral("ThisObject"))).getPointer(), thisObj); ScopedValue v(scope, QmlContextWrapper::qmlScope(e, e->callingContext(), 0)); - meObj->put(ScopedString(scope, v4->newString(QStringLiteral("ActivationObject"))), v); + meObj->put(ScopedString(scope, v4->newString(QStringLiteral("ActivationObject"))).getPointer(), v); return meObj.asReturnedValue(); } @@ -185,96 +185,101 @@ public: class NamedNodeMap : public Object { - V4_OBJECT public: - NamedNodeMap(ExecutionEngine *engine, NodeImpl *data, const QList<NodeImpl *> &list) - : Object(engine) - , list(list) - , d(data) - { - setVTable(staticVTable()); + struct Data : Object::Data { + Data(ExecutionEngine *engine, NodeImpl *data, const QList<NodeImpl *> &list) + : Object::Data(engine) + , list(list) + , d(data) + { + setVTable(staticVTable()); - if (d) - d->addref(); - } - ~NamedNodeMap() { - if (d) - d->release(); - } + if (d) + d->addref(); + } + ~Data() { + if (d) + d->release(); + } + QList<NodeImpl *> list; // Only used in NamedNodeMap + NodeImpl *d; + }; + V4_OBJECT(Object) // C++ API static ReturnedValue create(QV8Engine *, NodeImpl *, const QList<NodeImpl *> &); // JS API static void destroy(Managed *that) { - that->as<NamedNodeMap>()->~NamedNodeMap(); + that->as<NamedNodeMap>()->d()->~Data(); } - static ReturnedValue get(Managed *m, const StringRef name, bool *hasProperty); + static ReturnedValue get(Managed *m, String *name, bool *hasProperty); static ReturnedValue getIndexed(Managed *m, uint index, bool *hasProperty); - - QList<NodeImpl *> list; // Only used in NamedNodeMap - NodeImpl *d; }; DEFINE_OBJECT_VTABLE(NamedNodeMap); class NodeList : public Object { - V4_OBJECT public: - NodeList(ExecutionEngine *engine, NodeImpl *data) - : Object(engine) - , d(data) - { - setVTable(staticVTable()); + struct Data : Object::Data { + Data(ExecutionEngine *engine, NodeImpl *data) + : Object::Data(engine) + , d(data) + { + setVTable(staticVTable()); - if (d) - d->addref(); - } - ~NodeList() { - if (d) - d->release(); - } + if (d) + d->addref(); + } + ~Data() { + if (d) + d->release(); + } + NodeImpl *d; + }; + V4_OBJECT(Object) // JS API static void destroy(Managed *that) { - that->as<NodeList>()->~NodeList(); + that->as<NodeList>()->d()->~Data(); } - static ReturnedValue get(Managed *m, const StringRef name, bool *hasProperty); + static ReturnedValue get(Managed *m, String *name, bool *hasProperty); static ReturnedValue getIndexed(Managed *m, uint index, bool *hasProperty); // C++ API static ReturnedValue create(QV8Engine *, NodeImpl *); - NodeImpl *d; }; DEFINE_OBJECT_VTABLE(NodeList); class NodePrototype : public Object { - V4_OBJECT public: - NodePrototype(ExecutionEngine *engine) - : Object(engine) - { - setVTable(staticVTable()); - - Scope scope(engine); - ScopedObject protectThis(scope, this); - - defineAccessorProperty(QStringLiteral("nodeName"), method_get_nodeName, 0); - defineAccessorProperty(QStringLiteral("nodeValue"), method_get_nodeValue, 0); - defineAccessorProperty(QStringLiteral("nodeType"), method_get_nodeType, 0); - - defineAccessorProperty(QStringLiteral("parentNode"), method_get_parentNode, 0); - defineAccessorProperty(QStringLiteral("childNodes"), method_get_childNodes, 0); - defineAccessorProperty(QStringLiteral("firstChild"), method_get_firstChild, 0); - defineAccessorProperty(QStringLiteral("lastChild"), method_get_lastChild, 0); - defineAccessorProperty(QStringLiteral("previousSibling"), method_get_previousSibling, 0); - defineAccessorProperty(QStringLiteral("nextSibling"), method_get_nextSibling, 0); - defineAccessorProperty(QStringLiteral("attributes"), method_get_attributes, 0); - } + struct Data : Object::Data { + Data(ExecutionEngine *engine) + : Object::Data(engine) + { + setVTable(staticVTable()); + + Scope scope(engine); + ScopedObject o(scope, this); + + o->defineAccessorProperty(QStringLiteral("nodeName"), method_get_nodeName, 0); + o->defineAccessorProperty(QStringLiteral("nodeValue"), method_get_nodeValue, 0); + o->defineAccessorProperty(QStringLiteral("nodeType"), method_get_nodeType, 0); + + o->defineAccessorProperty(QStringLiteral("parentNode"), method_get_parentNode, 0); + o->defineAccessorProperty(QStringLiteral("childNodes"), method_get_childNodes, 0); + o->defineAccessorProperty(QStringLiteral("firstChild"), method_get_firstChild, 0); + o->defineAccessorProperty(QStringLiteral("lastChild"), method_get_lastChild, 0); + o->defineAccessorProperty(QStringLiteral("previousSibling"), method_get_previousSibling, 0); + o->defineAccessorProperty(QStringLiteral("nextSibling"), method_get_nextSibling, 0); + o->defineAccessorProperty(QStringLiteral("attributes"), method_get_attributes, 0); + } + }; + V4_OBJECT(Object) static void initClass(ExecutionEngine *engine); @@ -304,39 +309,40 @@ public: DEFINE_OBJECT_VTABLE(NodePrototype); -class Node : public Object +struct Node : public Object { - V4_OBJECT + struct Data : Object::Data { + Data(ExecutionEngine *engine, NodeImpl *data) + : Object::Data(engine) + , d(data) + { + setVTable(staticVTable()); - Node(ExecutionEngine *engine, NodeImpl *data) - : Object(engine) - , d(data) - { - setVTable(staticVTable()); + if (d) + d->addref(); + } + ~Data() { + if (d) + d->release(); + } + NodeImpl *d; + }; + V4_OBJECT(Object) - if (d) - d->addref(); - } - ~Node() { - if (d) - d->release(); - } // JS API static void destroy(Managed *that) { - that->as<Node>()->~Node(); + that->as<Node>()->d()->~Data(); } // C++ API static ReturnedValue create(QV8Engine *, NodeImpl *); - Node(const Node &o); bool isNull() const; - NodeImpl *d; - private: Node &operator=(const Node &); + Node(const Node &o); }; DEFINE_OBJECT_VTABLE(Node); @@ -420,12 +426,12 @@ void NodeImpl::release() ReturnedValue NodePrototype::method_get_nodeName(CallContext *ctx) { Scope scope(ctx); - Scoped<Node> r(scope, ctx->callData->thisObject.as<Node>()); + Scoped<Node> r(scope, ctx->d()->callData->thisObject.as<Node>()); if (!r) return ctx->throwTypeError(); QString name; - switch (r->d->type) { + switch (r->d()->d->type) { case NodeImpl::Document: name = QStringLiteral("#document"); break; @@ -436,52 +442,52 @@ ReturnedValue NodePrototype::method_get_nodeName(CallContext *ctx) name = QStringLiteral("#text"); break; default: - name = r->d->name; + name = r->d()->d->name; break; } - return Encode(ctx->engine->newString(name)); + return Encode(ctx->d()->engine->newString(name)); } ReturnedValue NodePrototype::method_get_nodeValue(CallContext *ctx) { Scope scope(ctx); - Scoped<Node> r(scope, ctx->callData->thisObject.as<Node>()); + Scoped<Node> r(scope, ctx->d()->callData->thisObject.as<Node>()); if (!r) return ctx->throwTypeError(); - if (r->d->type == NodeImpl::Document || - r->d->type == NodeImpl::DocumentFragment || - r->d->type == NodeImpl::DocumentType || - r->d->type == NodeImpl::Element || - r->d->type == NodeImpl::Entity || - r->d->type == NodeImpl::EntityReference || - r->d->type == NodeImpl::Notation) + if (r->d()->d->type == NodeImpl::Document || + r->d()->d->type == NodeImpl::DocumentFragment || + r->d()->d->type == NodeImpl::DocumentType || + r->d()->d->type == NodeImpl::Element || + r->d()->d->type == NodeImpl::Entity || + r->d()->d->type == NodeImpl::EntityReference || + r->d()->d->type == NodeImpl::Notation) return Encode::null(); - return Encode(ctx->engine->newString(r->d->data)); + return Encode(ctx->d()->engine->newString(r->d()->d->data)); } ReturnedValue NodePrototype::method_get_nodeType(CallContext *ctx) { Scope scope(ctx); - Scoped<Node> r(scope, ctx->callData->thisObject.as<Node>()); + Scoped<Node> r(scope, ctx->d()->callData->thisObject.as<Node>()); if (!r) return ctx->throwTypeError(); - return Encode(r->d->type); + return Encode(r->d()->d->type); } ReturnedValue NodePrototype::method_get_parentNode(CallContext *ctx) { Scope scope(ctx); - Scoped<Node> r(scope, ctx->callData->thisObject.as<Node>()); + Scoped<Node> r(scope, ctx->d()->callData->thisObject.as<Node>()); if (!r) return ctx->throwTypeError(); - QV8Engine *engine = ctx->engine->v8Engine; + QV8Engine *engine = ctx->d()->engine->v8Engine; - if (r->d->parent) - return Node::create(engine, r->d->parent); + if (r->d()->d->parent) + return Node::create(engine, r->d()->d->parent); else return Encode::null(); } @@ -489,63 +495,63 @@ ReturnedValue NodePrototype::method_get_parentNode(CallContext *ctx) ReturnedValue NodePrototype::method_get_childNodes(CallContext *ctx) { Scope scope(ctx); - Scoped<Node> r(scope, ctx->callData->thisObject.as<Node>()); + Scoped<Node> r(scope, ctx->d()->callData->thisObject.as<Node>()); if (!r) return ctx->throwTypeError(); - QV8Engine *engine = ctx->engine->v8Engine; + QV8Engine *engine = ctx->d()->engine->v8Engine; - return NodeList::create(engine, r->d); + return NodeList::create(engine, r->d()->d); } ReturnedValue NodePrototype::method_get_firstChild(CallContext *ctx) { Scope scope(ctx); - Scoped<Node> r(scope, ctx->callData->thisObject.as<Node>()); + Scoped<Node> r(scope, ctx->d()->callData->thisObject.as<Node>()); if (!r) return ctx->throwTypeError(); - QV8Engine *engine = ctx->engine->v8Engine; + QV8Engine *engine = ctx->d()->engine->v8Engine; - if (r->d->children.isEmpty()) + if (r->d()->d->children.isEmpty()) return Encode::null(); else - return Node::create(engine, r->d->children.first()); + return Node::create(engine, r->d()->d->children.first()); } ReturnedValue NodePrototype::method_get_lastChild(CallContext *ctx) { Scope scope(ctx); - Scoped<Node> r(scope, ctx->callData->thisObject.as<Node>()); + Scoped<Node> r(scope, ctx->d()->callData->thisObject.as<Node>()); if (!r) return ctx->throwTypeError(); - QV8Engine *engine = ctx->engine->v8Engine; + QV8Engine *engine = ctx->d()->engine->v8Engine; - if (r->d->children.isEmpty()) + if (r->d()->d->children.isEmpty()) return Encode::null(); else - return Node::create(engine, r->d->children.last()); + return Node::create(engine, r->d()->d->children.last()); } ReturnedValue NodePrototype::method_get_previousSibling(CallContext *ctx) { Scope scope(ctx); - Scoped<Node> r(scope, ctx->callData->thisObject.as<Node>()); + Scoped<Node> r(scope, ctx->d()->callData->thisObject.as<Node>()); if (!r) return ctx->throwTypeError(); - QV8Engine *engine = ctx->engine->v8Engine; + QV8Engine *engine = ctx->d()->engine->v8Engine; - if (!r->d->parent) + if (!r->d()->d->parent) return Encode::null(); - for (int ii = 0; ii < r->d->parent->children.count(); ++ii) { - if (r->d->parent->children.at(ii) == r->d) { + for (int ii = 0; ii < r->d()->d->parent->children.count(); ++ii) { + if (r->d()->d->parent->children.at(ii) == r->d()->d) { if (ii == 0) return Encode::null(); else - return Node::create(engine, r->d->parent->children.at(ii - 1)); + return Node::create(engine, r->d()->d->parent->children.at(ii - 1)); } } @@ -555,21 +561,21 @@ ReturnedValue NodePrototype::method_get_previousSibling(CallContext *ctx) ReturnedValue NodePrototype::method_get_nextSibling(CallContext *ctx) { Scope scope(ctx); - Scoped<Node> r(scope, ctx->callData->thisObject.as<Node>()); + Scoped<Node> r(scope, ctx->d()->callData->thisObject.as<Node>()); if (!r) return ctx->throwTypeError(); - QV8Engine *engine = ctx->engine->v8Engine; + QV8Engine *engine = ctx->d()->engine->v8Engine; - if (!r->d->parent) + if (!r->d()->d->parent) return Encode::null(); - for (int ii = 0; ii < r->d->parent->children.count(); ++ii) { - if (r->d->parent->children.at(ii) == r->d) { - if ((ii + 1) == r->d->parent->children.count()) + for (int ii = 0; ii < r->d()->d->parent->children.count(); ++ii) { + if (r->d()->d->parent->children.at(ii) == r->d()->d) { + if ((ii + 1) == r->d()->d->parent->children.count()) return Encode::null(); else - return Node::create(engine, r->d->parent->children.at(ii + 1)); + return Node::create(engine, r->d()->d->parent->children.at(ii + 1)); } } @@ -579,16 +585,16 @@ ReturnedValue NodePrototype::method_get_nextSibling(CallContext *ctx) ReturnedValue NodePrototype::method_get_attributes(CallContext *ctx) { Scope scope(ctx); - Scoped<Node> r(scope, ctx->callData->thisObject.as<Node>()); + Scoped<Node> r(scope, ctx->d()->callData->thisObject.as<Node>()); if (!r) return ctx->throwTypeError(); - QV8Engine *engine = ctx->engine->v8Engine; + QV8Engine *engine = ctx->d()->engine->v8Engine; - if (r->d->type != NodeImpl::Element) + if (r->d()->d->type != NodeImpl::Element) return Encode::null(); else - return NamedNodeMap::create(engine, r->d, r->d->attributes); + return NamedNodeMap::create(engine, r->d()->d, r->d()->d->attributes); } ReturnedValue NodePrototype::getProto(ExecutionEngine *v4) @@ -596,7 +602,7 @@ ReturnedValue NodePrototype::getProto(ExecutionEngine *v4) Scope scope(v4); QQmlXMLHttpRequestData *d = xhrdata(v4->v8Engine); if (d->nodePrototype.isUndefined()) { - ScopedObject p(scope, new (v4->memoryManager) NodePrototype(v4)); + ScopedObject p(scope, v4->memoryManager->alloc<NodePrototype>(v4)); d->nodePrototype = p; v4->v8Engine->freezeObject(p); } @@ -608,7 +614,7 @@ ReturnedValue Node::create(QV8Engine *engine, NodeImpl *data) ExecutionEngine *v4 = QV8Engine::getV4(engine); Scope scope(v4); - Scoped<Node> instance(scope, new (v4->memoryManager) Node(v4, data)); + Scoped<Node> instance(scope, v4->memoryManager->alloc<Node>(v4, data)); ScopedObject p(scope); switch (data->type) { @@ -673,45 +679,45 @@ ReturnedValue Attr::prototype(ExecutionEngine *engine) ReturnedValue Attr::method_name(CallContext *ctx) { Scope scope(ctx); - Scoped<Node> r(scope, ctx->callData->thisObject.as<Node>()); + Scoped<Node> r(scope, ctx->d()->callData->thisObject.as<Node>()); if (!r) return Encode::undefined(); - QV8Engine *engine = ctx->engine->v8Engine; + QV8Engine *engine = ctx->d()->engine->v8Engine; - return engine->toString(r->d->name); + return engine->toString(r->d()->d->name); } ReturnedValue Attr::method_value(CallContext *ctx) { Scope scope(ctx); - Scoped<Node> r(scope, ctx->callData->thisObject.as<Node>()); + Scoped<Node> r(scope, ctx->d()->callData->thisObject.as<Node>()); if (!r) return Encode::undefined(); - QV8Engine *engine = ctx->engine->v8Engine; + QV8Engine *engine = ctx->d()->engine->v8Engine; - return engine->toString(r->d->data); + return engine->toString(r->d()->d->data); } ReturnedValue Attr::method_ownerElement(CallContext *ctx) { Scope scope(ctx); - Scoped<Node> r(scope, ctx->callData->thisObject.as<Node>()); + Scoped<Node> r(scope, ctx->d()->callData->thisObject.as<Node>()); if (!r) return Encode::undefined(); - QV8Engine *engine = ctx->engine->v8Engine; + QV8Engine *engine = ctx->d()->engine->v8Engine; - return Node::create(engine, r->d->parent); + return Node::create(engine, r->d()->d->parent); } ReturnedValue CharacterData::method_length(CallContext *ctx) { Scope scope(ctx); - Scoped<Node> r(scope, ctx->callData->thisObject.as<Node>()); + Scoped<Node> r(scope, ctx->d()->callData->thisObject.as<Node>()); if (!r) return Encode::undefined(); - QV8Engine *engine = ctx->engine->v8Engine; + QV8Engine *engine = ctx->d()->engine->v8Engine; Q_UNUSED(engine) - return Encode(r->d->data.length()); + return Encode(r->d()->d->data.length()); } ReturnedValue CharacterData::prototype(ExecutionEngine *v4) @@ -733,21 +739,21 @@ ReturnedValue CharacterData::prototype(ExecutionEngine *v4) ReturnedValue Text::method_isElementContentWhitespace(CallContext *ctx) { Scope scope(ctx); - Scoped<Node> r(scope, ctx->callData->thisObject.as<Node>()); + Scoped<Node> r(scope, ctx->d()->callData->thisObject.as<Node>()); if (!r) return Encode::undefined(); - return Encode(r->d->data.trimmed().isEmpty()); + return Encode(r->d()->d->data.trimmed().isEmpty()); } ReturnedValue Text::method_wholeText(CallContext *ctx) { Scope scope(ctx); - Scoped<Node> r(scope, ctx->callData->thisObject.as<Node>()); + Scoped<Node> r(scope, ctx->d()->callData->thisObject.as<Node>()); if (!r) return Encode::undefined(); - QV8Engine *engine = ctx->engine->v8Engine; + QV8Engine *engine = ctx->d()->engine->v8Engine; - return engine->toString(r->d->data); + return engine->toString(r->d()->d->data); } ReturnedValue Text::prototype(ExecutionEngine *v4) @@ -883,22 +889,15 @@ ReturnedValue Document::load(QV8Engine *engine, const QByteArray &data) return Encode::null(); } - ScopedObject instance(scope, new (v4->memoryManager) Node(v4, document)); + ScopedObject instance(scope, v4->memoryManager->alloc<Node>(v4, document)); ScopedObject p(scope); instance->setPrototype((p = Document::prototype(v4)).getPointer()); return instance.asReturnedValue(); } -Node::Node(const Node &o) - : Object(o.engine()), d(o.d) -{ - if (d) - d->addref(); -} - bool Node::isNull() const { - return d == 0; + return d()->d == 0; } ReturnedValue NamedNodeMap::getIndexed(Managed *m, uint index, bool *hasProperty) @@ -913,17 +912,17 @@ ReturnedValue NamedNodeMap::getIndexed(Managed *m, uint index, bool *hasProperty QV8Engine *engine = v4->v8Engine; - if ((int)index < r->list.count()) { + if ((int)index < r->d()->list.count()) { if (hasProperty) *hasProperty = true; - return Node::create(engine, r->list.at(index)); + return Node::create(engine, r->d()->list.at(index)); } if (hasProperty) *hasProperty = false; return Encode::undefined(); } -ReturnedValue NamedNodeMap::get(Managed *m, const StringRef name, bool *hasProperty) +ReturnedValue NamedNodeMap::get(Managed *m, String *name, bool *hasProperty) { NamedNodeMap *r = m->as<NamedNodeMap>(); QV4::ExecutionEngine *v4 = m->engine(); @@ -932,16 +931,16 @@ ReturnedValue NamedNodeMap::get(Managed *m, const StringRef name, bool *hasPrope name->makeIdentifier(); if (name->equals(v4->id_length)) - return Primitive::fromInt32(r->list.count()).asReturnedValue(); + return Primitive::fromInt32(r->d()->list.count()).asReturnedValue(); QV8Engine *engine = v4->v8Engine; QString str = name->toQString(); - for (int ii = 0; ii < r->list.count(); ++ii) { - if (r->list.at(ii)->name == str) { + for (int ii = 0; ii < r->d()->list.count(); ++ii) { + if (r->d()->list.at(ii)->name == str) { if (hasProperty) *hasProperty = true; - return Node::create(engine, r->list.at(ii)); + return Node::create(engine, r->d()->list.at(ii)); } } @@ -953,10 +952,7 @@ ReturnedValue NamedNodeMap::get(Managed *m, const StringRef name, bool *hasPrope ReturnedValue NamedNodeMap::create(QV8Engine *engine, NodeImpl *data, const QList<NodeImpl *> &list) { ExecutionEngine *v4 = QV8Engine::getV4(engine); - Scope scope(v4); - - Scoped<NamedNodeMap> instance(scope, new (v4->memoryManager) NamedNodeMap(v4, data, list)); - return instance.asReturnedValue(); + return (v4->memoryManager->alloc<NamedNodeMap>(v4, data, list))->asReturnedValue(); } ReturnedValue NodeList::getIndexed(Managed *m, uint index, bool *hasProperty) @@ -971,17 +967,17 @@ ReturnedValue NodeList::getIndexed(Managed *m, uint index, bool *hasProperty) QV8Engine *engine = v4->v8Engine; - if ((int)index < r->d->children.count()) { + if ((int)index < r->d()->d->children.count()) { if (hasProperty) *hasProperty = true; - return Node::create(engine, r->d->children.at(index)); + return Node::create(engine, r->d()->d->children.at(index)); } if (hasProperty) *hasProperty = false; return Encode::undefined(); } -ReturnedValue NodeList::get(Managed *m, const StringRef name, bool *hasProperty) +ReturnedValue NodeList::get(Managed *m, String *name, bool *hasProperty) { QV4::ExecutionEngine *v4 = m->engine(); NodeList *r = m->as<NodeList>(); @@ -991,60 +987,58 @@ ReturnedValue NodeList::get(Managed *m, const StringRef name, bool *hasProperty) name->makeIdentifier(); if (name->equals(v4->id_length)) - return Primitive::fromInt32(r->d->children.count()).asReturnedValue(); + return Primitive::fromInt32(r->d()->d->children.count()).asReturnedValue(); return Object::get(m, name, hasProperty); } ReturnedValue NodeList::create(QV8Engine *engine, NodeImpl *data) { ExecutionEngine *v4 = QV8Engine::getV4(engine); - Scope scope(v4); - Scoped<NodeList> instance(scope, new (v4->memoryManager) NodeList(v4, data)); - return instance.asReturnedValue(); + return (v4->memoryManager->alloc<NodeList>(v4, data))->asReturnedValue(); } ReturnedValue Document::method_documentElement(CallContext *ctx) { Scope scope(ctx); - Scoped<Node> r(scope, ctx->callData->thisObject.as<Node>()); - if (!r || r->d->type != NodeImpl::Document) + Scoped<Node> r(scope, ctx->d()->callData->thisObject.as<Node>()); + if (!r || r->d()->d->type != NodeImpl::Document) return Encode::undefined(); - QV8Engine *engine = ctx->engine->v8Engine; + QV8Engine *engine = ctx->d()->engine->v8Engine; - return Node::create(engine, static_cast<DocumentImpl *>(r->d)->root); + return Node::create(engine, static_cast<DocumentImpl *>(r->d()->d)->root); } ReturnedValue Document::method_xmlStandalone(CallContext *ctx) { Scope scope(ctx); - Scoped<Node> r(scope, ctx->callData->thisObject.as<Node>()); - if (!r || r->d->type != NodeImpl::Document) + Scoped<Node> r(scope, ctx->d()->callData->thisObject.as<Node>()); + if (!r || r->d()->d->type != NodeImpl::Document) return Encode::undefined(); - QV8Engine *engine = ctx->engine->v8Engine; + QV8Engine *engine = ctx->d()->engine->v8Engine; Q_UNUSED(engine) - return Encode(static_cast<DocumentImpl *>(r->d)->isStandalone); + return Encode(static_cast<DocumentImpl *>(r->d()->d)->isStandalone); } ReturnedValue Document::method_xmlVersion(CallContext *ctx) { Scope scope(ctx); - Scoped<Node> r(scope, ctx->callData->thisObject.as<Node>()); - if (!r || r->d->type != NodeImpl::Document) + Scoped<Node> r(scope, ctx->d()->callData->thisObject.as<Node>()); + if (!r || r->d()->d->type != NodeImpl::Document) return Encode::undefined(); - QV8Engine *engine = ctx->engine->v8Engine; + QV8Engine *engine = ctx->d()->engine->v8Engine; - return engine->toString(static_cast<DocumentImpl *>(r->d)->version); + return engine->toString(static_cast<DocumentImpl *>(r->d()->d)->version); } ReturnedValue Document::method_xmlEncoding(CallContext *ctx) { Scope scope(ctx); - Scoped<Node> r(scope, ctx->callData->thisObject.as<Node>()); - if (!r || r->d->type != NodeImpl::Document) + Scoped<Node> r(scope, ctx->d()->callData->thisObject.as<Node>()); + if (!r || r->d()->d->type != NodeImpl::Document) return Encode::undefined(); - QV8Engine *engine = ctx->engine->v8Engine; + QV8Engine *engine = ctx->d()->engine->v8Engine; - return engine->toString(static_cast<DocumentImpl *>(r->d)->encoding); + return engine->toString(static_cast<DocumentImpl *>(r->d()->d)->encoding); } class QQmlXMLHttpRequest : public QObject @@ -1551,21 +1545,21 @@ void QQmlXMLHttpRequest::dispatchCallbackImpl(const ValueRef me) } ScopedString s(scope, v4->newString(QStringLiteral("ThisObject"))); - Scoped<Object> thisObj(scope, o->get(s)); + Scoped<Object> thisObj(scope, o->get(s.getPointer())); if (!thisObj) { ctx->throwError(QStringLiteral("QQmlXMLHttpRequest: internal error: empty ThisObject")); return; } s = v4->newString(QStringLiteral("onreadystatechange")); - Scoped<FunctionObject> callback(scope, thisObj->get(s)); + Scoped<FunctionObject> callback(scope, thisObj->get(s.getPointer())); if (!callback) { // not an error, but no onreadystatechange function to call. return; } s = v4->newString(QStringLiteral("ActivationObject")); - Scoped<Object> activationObject(scope, o->get(s)); + Scoped<Object> activationObject(scope, o->get(s.getPointer())); if (!activationObject) { v4->currentContext()->throwError(QStringLiteral("QQmlXMLHttpRequest: internal error: empty ActivationObject")); return; @@ -1607,56 +1601,54 @@ void QQmlXMLHttpRequest::destroyNetwork() struct QQmlXMLHttpRequestWrapper : public Object { - V4_OBJECT - QQmlXMLHttpRequestWrapper(ExecutionEngine *engine, QQmlXMLHttpRequest *request) - : Object(engine) - , request(request) - { - setVTable(staticVTable()); - } - ~QQmlXMLHttpRequestWrapper() { - delete request; - } + struct Data : Object::Data { + Data(ExecutionEngine *engine, QQmlXMLHttpRequest *request) + : Object::Data(engine) + , request(request) + { + setVTable(staticVTable()); + } + ~Data() { + delete request; + } + QQmlXMLHttpRequest *request; + }; + V4_OBJECT(Object) static void destroy(Managed *that) { - that->as<QQmlXMLHttpRequestWrapper>()->~QQmlXMLHttpRequestWrapper(); + that->as<QQmlXMLHttpRequestWrapper>()->d()->~Data(); } - - QQmlXMLHttpRequest *request; }; DEFINE_OBJECT_VTABLE(QQmlXMLHttpRequestWrapper); struct QQmlXMLHttpRequestCtor : public FunctionObject { - V4_OBJECT - QQmlXMLHttpRequestCtor(ExecutionEngine *engine) - : FunctionObject(engine->rootContext, QStringLiteral("XMLHttpRequest")) - { - setVTable(staticVTable()); - Scope scope(engine); - ScopedValue protectThis(scope, this); - - defineReadonlyProperty(QStringLiteral("UNSENT"), Primitive::fromInt32(0)); - defineReadonlyProperty(QStringLiteral("OPENED"), Primitive::fromInt32(1)); - defineReadonlyProperty(QStringLiteral("HEADERS_RECEIVED"), Primitive::fromInt32(2)); - defineReadonlyProperty(QStringLiteral("LOADING"), Primitive::fromInt32(3)); - defineReadonlyProperty(QStringLiteral("DONE"), Primitive::fromInt32(4)); - if (!proto) - setupProto(); - ScopedString s(scope, engine->id_prototype); - defineDefaultProperty(s, ScopedObject(scope, proto)); - } - ~QQmlXMLHttpRequestCtor() - {} - - static void destroy(Managed *that) { - that->as<QQmlXMLHttpRequestCtor>()->~QQmlXMLHttpRequestCtor(); - } + struct Data : FunctionObject::Data { + Data(ExecutionEngine *engine) + : FunctionObject::Data(engine->rootContext, QStringLiteral("XMLHttpRequest")) + { + setVTable(staticVTable()); + Scope scope(engine); + Scoped<QQmlXMLHttpRequestCtor> ctor(scope, this); + + ctor->defineReadonlyProperty(QStringLiteral("UNSENT"), Primitive::fromInt32(0)); + ctor->defineReadonlyProperty(QStringLiteral("OPENED"), Primitive::fromInt32(1)); + ctor->defineReadonlyProperty(QStringLiteral("HEADERS_RECEIVED"), Primitive::fromInt32(2)); + ctor->defineReadonlyProperty(QStringLiteral("LOADING"), Primitive::fromInt32(3)); + ctor->defineReadonlyProperty(QStringLiteral("DONE"), Primitive::fromInt32(4)); + if (!ctor->d()->proto) + ctor->setupProto(); + ScopedString s(scope, engine->id_prototype); + ctor->defineDefaultProperty(s.getPointer(), ScopedObject(scope, ctor->d()->proto)); + } + Object *proto; + }; + V4_OBJECT(FunctionObject) static void markObjects(Managed *that, ExecutionEngine *e) { QQmlXMLHttpRequestCtor *c = that->as<QQmlXMLHttpRequestCtor>(); - if (c->proto) - c->proto->mark(e); + if (c->d()->proto) + c->d()->proto->mark(e); FunctionObject::markObjects(that, e); } static ReturnedValue construct(Managed *that, QV4::CallData *) @@ -1668,8 +1660,8 @@ struct QQmlXMLHttpRequestCtor : public FunctionObject QV8Engine *engine = that->engine()->v8Engine; QQmlXMLHttpRequest *r = new QQmlXMLHttpRequest(engine, engine->networkAccessManager()); - Scoped<QQmlXMLHttpRequestWrapper> w(scope, new (that->engine()->memoryManager) QQmlXMLHttpRequestWrapper(that->engine(), r)); - w->setPrototype(ctor->proto); + Scoped<QQmlXMLHttpRequestWrapper> w(scope, that->engine()->memoryManager->alloc<QQmlXMLHttpRequestWrapper>(that->engine(), r)); + w->setPrototype(ctor->d()->proto); return w.asReturnedValue(); } @@ -1691,9 +1683,6 @@ struct QQmlXMLHttpRequestCtor : public FunctionObject static ReturnedValue method_get_statusText(CallContext *ctx); static ReturnedValue method_get_responseText(CallContext *ctx); static ReturnedValue method_get_responseXML(CallContext *ctx); - - - Object *proto; }; DEFINE_OBJECT_VTABLE(QQmlXMLHttpRequestCtor); @@ -1703,29 +1692,29 @@ void QQmlXMLHttpRequestCtor::setupProto() ExecutionEngine *v4 = engine(); Scope scope(v4); Scoped<Object> p(scope, v4->newObject()); - proto = p.getPointer(); + d()->proto = p.getPointer(); // Methods - proto->defineDefaultProperty(QStringLiteral("open"), method_open); - proto->defineDefaultProperty(QStringLiteral("setRequestHeader"), method_setRequestHeader); - proto->defineDefaultProperty(QStringLiteral("send"), method_send); - proto->defineDefaultProperty(QStringLiteral("abort"), method_abort); - proto->defineDefaultProperty(QStringLiteral("getResponseHeader"), method_getResponseHeader); - proto->defineDefaultProperty(QStringLiteral("getAllResponseHeaders"), method_getAllResponseHeaders); + d()->proto->defineDefaultProperty(QStringLiteral("open"), method_open); + d()->proto->defineDefaultProperty(QStringLiteral("setRequestHeader"), method_setRequestHeader); + d()->proto->defineDefaultProperty(QStringLiteral("send"), method_send); + d()->proto->defineDefaultProperty(QStringLiteral("abort"), method_abort); + d()->proto->defineDefaultProperty(QStringLiteral("getResponseHeader"), method_getResponseHeader); + d()->proto->defineDefaultProperty(QStringLiteral("getAllResponseHeaders"), method_getAllResponseHeaders); // Read-only properties - proto->defineAccessorProperty(QStringLiteral("readyState"), method_get_readyState, 0); - proto->defineAccessorProperty(QStringLiteral("status"),method_get_status, 0); - proto->defineAccessorProperty(QStringLiteral("statusText"),method_get_statusText, 0); - proto->defineAccessorProperty(QStringLiteral("responseText"),method_get_responseText, 0); - proto->defineAccessorProperty(QStringLiteral("responseXML"),method_get_responseXML, 0); + d()->proto->defineAccessorProperty(QStringLiteral("readyState"), method_get_readyState, 0); + d()->proto->defineAccessorProperty(QStringLiteral("status"),method_get_status, 0); + d()->proto->defineAccessorProperty(QStringLiteral("statusText"),method_get_statusText, 0); + d()->proto->defineAccessorProperty(QStringLiteral("responseText"),method_get_responseText, 0); + d()->proto->defineAccessorProperty(QStringLiteral("responseXML"),method_get_responseXML, 0); // State values - proto->defineReadonlyProperty(QStringLiteral("UNSENT"), Primitive::fromInt32(0)); - proto->defineReadonlyProperty(QStringLiteral("OPENED"), Primitive::fromInt32(1)); - proto->defineReadonlyProperty(QStringLiteral("HEADERS_RECEIVED"), Primitive::fromInt32(2)); - proto->defineReadonlyProperty(QStringLiteral("LOADING"), Primitive::fromInt32(3)); - proto->defineReadonlyProperty(QStringLiteral("DONE"), Primitive::fromInt32(4)); + d()->proto->defineReadonlyProperty(QStringLiteral("UNSENT"), Primitive::fromInt32(0)); + d()->proto->defineReadonlyProperty(QStringLiteral("OPENED"), Primitive::fromInt32(1)); + d()->proto->defineReadonlyProperty(QStringLiteral("HEADERS_RECEIVED"), Primitive::fromInt32(2)); + d()->proto->defineReadonlyProperty(QStringLiteral("LOADING"), Primitive::fromInt32(3)); + d()->proto->defineReadonlyProperty(QStringLiteral("DONE"), Primitive::fromInt32(4)); } @@ -1733,18 +1722,18 @@ void QQmlXMLHttpRequestCtor::setupProto() ReturnedValue QQmlXMLHttpRequestCtor::method_open(CallContext *ctx) { Scope scope(ctx); - Scoped<QQmlXMLHttpRequestWrapper> w(scope, ctx->callData->thisObject.as<QQmlXMLHttpRequestWrapper>()); + Scoped<QQmlXMLHttpRequestWrapper> w(scope, ctx->d()->callData->thisObject.as<QQmlXMLHttpRequestWrapper>()); if (!w) V4THROW_REFERENCE("Not an XMLHttpRequest object"); - QQmlXMLHttpRequest *r = w->request; + QQmlXMLHttpRequest *r = w->d()->request; - if (ctx->callData->argc < 2 || ctx->callData->argc > 5) + if (ctx->d()->callData->argc < 2 || ctx->d()->callData->argc > 5) V4THROW_DOM(DOMEXCEPTION_SYNTAX_ERR, "Incorrect argument count"); - QV8Engine *engine = ctx->engine->v8Engine; + QV8Engine *engine = ctx->d()->engine->v8Engine; // Argument 0 - Method - QString method = ctx->callData->args[0].toQStringNoThrow().toUpper(); + QString method = ctx->d()->callData->args[0].toQStringNoThrow().toUpper(); if (method != QLatin1String("GET") && method != QLatin1String("PUT") && method != QLatin1String("HEAD") && @@ -1753,21 +1742,21 @@ ReturnedValue QQmlXMLHttpRequestCtor::method_open(CallContext *ctx) V4THROW_DOM(DOMEXCEPTION_SYNTAX_ERR, "Unsupported HTTP method type"); // Argument 1 - URL - QUrl url = QUrl(ctx->callData->args[1].toQStringNoThrow()); + QUrl url = QUrl(ctx->d()->callData->args[1].toQStringNoThrow()); if (url.isRelative()) url = engine->callingContext()->resolvedUrl(url); // Argument 2 - async (optional) - if (ctx->callData->argc > 2 && !ctx->callData->args[2].booleanValue()) + if (ctx->d()->callData->argc > 2 && !ctx->d()->callData->args[2].booleanValue()) V4THROW_DOM(DOMEXCEPTION_NOT_SUPPORTED_ERR, "Synchronous XMLHttpRequest calls are not supported"); // Argument 3/4 - user/pass (optional) QString username, password; - if (ctx->callData->argc > 3) - username = ctx->callData->args[3].toQStringNoThrow(); - if (ctx->callData->argc > 4) - password = ctx->callData->args[4].toQStringNoThrow(); + if (ctx->d()->callData->argc > 3) + username = ctx->d()->callData->args[3].toQStringNoThrow(); + if (ctx->d()->callData->argc > 4) + password = ctx->d()->callData->args[4].toQStringNoThrow(); // Clear the fragment (if any) url.setFragment(QString()); @@ -1776,26 +1765,26 @@ ReturnedValue QQmlXMLHttpRequestCtor::method_open(CallContext *ctx) if (!username.isNull()) url.setUserName(username); if (!password.isNull()) url.setPassword(password); - ScopedValue meObject(scope, constructMeObject(ctx->callData->thisObject, engine)); + ScopedValue meObject(scope, constructMeObject(ctx->d()->callData->thisObject, engine)); return r->open(meObject, method, url); } ReturnedValue QQmlXMLHttpRequestCtor::method_setRequestHeader(CallContext *ctx) { Scope scope(ctx); - Scoped<QQmlXMLHttpRequestWrapper> w(scope, ctx->callData->thisObject.as<QQmlXMLHttpRequestWrapper>()); + Scoped<QQmlXMLHttpRequestWrapper> w(scope, ctx->d()->callData->thisObject.as<QQmlXMLHttpRequestWrapper>()); if (!w) V4THROW_REFERENCE("Not an XMLHttpRequest object"); - QQmlXMLHttpRequest *r = w->request; + QQmlXMLHttpRequest *r = w->d()->request; - if (ctx->callData->argc != 2) + if (ctx->d()->callData->argc != 2) V4THROW_DOM(DOMEXCEPTION_SYNTAX_ERR, "Incorrect argument count"); if (r->readyState() != QQmlXMLHttpRequest::Opened || r->sendFlag()) V4THROW_DOM(DOMEXCEPTION_INVALID_STATE_ERR, "Invalid state"); - QString name = ctx->callData->args[0].toQStringNoThrow(); - QString value = ctx->callData->args[1].toQStringNoThrow(); + QString name = ctx->d()->callData->args[0].toQStringNoThrow(); + QString value = ctx->d()->callData->args[1].toQStringNoThrow(); // ### Check that name and value are well formed @@ -1830,48 +1819,48 @@ ReturnedValue QQmlXMLHttpRequestCtor::method_setRequestHeader(CallContext *ctx) ReturnedValue QQmlXMLHttpRequestCtor::method_send(CallContext *ctx) { Scope scope(ctx); - Scoped<QQmlXMLHttpRequestWrapper> w(scope, ctx->callData->thisObject.as<QQmlXMLHttpRequestWrapper>()); + Scoped<QQmlXMLHttpRequestWrapper> w(scope, ctx->d()->callData->thisObject.as<QQmlXMLHttpRequestWrapper>()); if (!w) V4THROW_REFERENCE("Not an XMLHttpRequest object"); - QQmlXMLHttpRequest *r = w->request; + QQmlXMLHttpRequest *r = w->d()->request; - QV8Engine *engine = ctx->engine->v8Engine; + QV8Engine *engine = ctx->d()->engine->v8Engine; if (r->readyState() != QQmlXMLHttpRequest::Opened || r->sendFlag()) V4THROW_DOM(DOMEXCEPTION_INVALID_STATE_ERR, "Invalid state"); QByteArray data; - if (ctx->callData->argc > 0) - data = ctx->callData->args[0].toQStringNoThrow().toUtf8(); + if (ctx->d()->callData->argc > 0) + data = ctx->d()->callData->args[0].toQStringNoThrow().toUtf8(); - ScopedValue meObject(scope, constructMeObject(ctx->callData->thisObject, engine)); + ScopedValue meObject(scope, constructMeObject(ctx->d()->callData->thisObject, engine)); return r->send(meObject, data); } ReturnedValue QQmlXMLHttpRequestCtor::method_abort(CallContext *ctx) { Scope scope(ctx); - Scoped<QQmlXMLHttpRequestWrapper> w(scope, ctx->callData->thisObject.as<QQmlXMLHttpRequestWrapper>()); + Scoped<QQmlXMLHttpRequestWrapper> w(scope, ctx->d()->callData->thisObject.as<QQmlXMLHttpRequestWrapper>()); if (!w) V4THROW_REFERENCE("Not an XMLHttpRequest object"); - QQmlXMLHttpRequest *r = w->request; + QQmlXMLHttpRequest *r = w->d()->request; - ScopedValue meObject(scope, constructMeObject(ctx->callData->thisObject, ctx->engine->v8Engine)); + ScopedValue meObject(scope, constructMeObject(ctx->d()->callData->thisObject, ctx->d()->engine->v8Engine)); return r->abort(meObject); } ReturnedValue QQmlXMLHttpRequestCtor::method_getResponseHeader(CallContext *ctx) { Scope scope(ctx); - Scoped<QQmlXMLHttpRequestWrapper> w(scope, ctx->callData->thisObject.as<QQmlXMLHttpRequestWrapper>()); + Scoped<QQmlXMLHttpRequestWrapper> w(scope, ctx->d()->callData->thisObject.as<QQmlXMLHttpRequestWrapper>()); if (!w) V4THROW_REFERENCE("Not an XMLHttpRequest object"); - QQmlXMLHttpRequest *r = w->request; + QQmlXMLHttpRequest *r = w->d()->request; - QV8Engine *engine = ctx->engine->v8Engine; + QV8Engine *engine = ctx->d()->engine->v8Engine; - if (ctx->callData->argc != 1) + if (ctx->d()->callData->argc != 1) V4THROW_DOM(DOMEXCEPTION_SYNTAX_ERR, "Incorrect argument count"); if (r->readyState() != QQmlXMLHttpRequest::Loading && @@ -1879,20 +1868,20 @@ ReturnedValue QQmlXMLHttpRequestCtor::method_getResponseHeader(CallContext *ctx) r->readyState() != QQmlXMLHttpRequest::HeadersReceived) V4THROW_DOM(DOMEXCEPTION_INVALID_STATE_ERR, "Invalid state"); - return engine->toString(r->header(ctx->callData->args[0].toQStringNoThrow())); + return engine->toString(r->header(ctx->d()->callData->args[0].toQStringNoThrow())); } ReturnedValue QQmlXMLHttpRequestCtor::method_getAllResponseHeaders(CallContext *ctx) { Scope scope(ctx); - Scoped<QQmlXMLHttpRequestWrapper> w(scope, ctx->callData->thisObject.as<QQmlXMLHttpRequestWrapper>()); + Scoped<QQmlXMLHttpRequestWrapper> w(scope, ctx->d()->callData->thisObject.as<QQmlXMLHttpRequestWrapper>()); if (!w) V4THROW_REFERENCE("Not an XMLHttpRequest object"); - QQmlXMLHttpRequest *r = w->request; + QQmlXMLHttpRequest *r = w->d()->request; - QV8Engine *engine = ctx->engine->v8Engine; + QV8Engine *engine = ctx->d()->engine->v8Engine; - if (ctx->callData->argc != 0) + if (ctx->d()->callData->argc != 0) V4THROW_DOM(DOMEXCEPTION_SYNTAX_ERR, "Incorrect argument count"); if (r->readyState() != QQmlXMLHttpRequest::Loading && @@ -1907,10 +1896,10 @@ ReturnedValue QQmlXMLHttpRequestCtor::method_getAllResponseHeaders(CallContext * ReturnedValue QQmlXMLHttpRequestCtor::method_get_readyState(CallContext *ctx) { Scope scope(ctx); - Scoped<QQmlXMLHttpRequestWrapper> w(scope, ctx->callData->thisObject.as<QQmlXMLHttpRequestWrapper>()); + Scoped<QQmlXMLHttpRequestWrapper> w(scope, ctx->d()->callData->thisObject.as<QQmlXMLHttpRequestWrapper>()); if (!w) V4THROW_REFERENCE("Not an XMLHttpRequest object"); - QQmlXMLHttpRequest *r = w->request; + QQmlXMLHttpRequest *r = w->d()->request; return Encode(r->readyState()); } @@ -1918,10 +1907,10 @@ ReturnedValue QQmlXMLHttpRequestCtor::method_get_readyState(CallContext *ctx) ReturnedValue QQmlXMLHttpRequestCtor::method_get_status(CallContext *ctx) { Scope scope(ctx); - Scoped<QQmlXMLHttpRequestWrapper> w(scope, ctx->callData->thisObject.as<QQmlXMLHttpRequestWrapper>()); + Scoped<QQmlXMLHttpRequestWrapper> w(scope, ctx->d()->callData->thisObject.as<QQmlXMLHttpRequestWrapper>()); if (!w) V4THROW_REFERENCE("Not an XMLHttpRequest object"); - QQmlXMLHttpRequest *r = w->request; + QQmlXMLHttpRequest *r = w->d()->request; if (r->readyState() == QQmlXMLHttpRequest::Unsent || r->readyState() == QQmlXMLHttpRequest::Opened) @@ -1936,12 +1925,12 @@ ReturnedValue QQmlXMLHttpRequestCtor::method_get_status(CallContext *ctx) ReturnedValue QQmlXMLHttpRequestCtor::method_get_statusText(CallContext *ctx) { Scope scope(ctx); - Scoped<QQmlXMLHttpRequestWrapper> w(scope, ctx->callData->thisObject.as<QQmlXMLHttpRequestWrapper>()); + Scoped<QQmlXMLHttpRequestWrapper> w(scope, ctx->d()->callData->thisObject.as<QQmlXMLHttpRequestWrapper>()); if (!w) V4THROW_REFERENCE("Not an XMLHttpRequest object"); - QQmlXMLHttpRequest *r = w->request; + QQmlXMLHttpRequest *r = w->d()->request; - QV8Engine *engine = ctx->engine->v8Engine; + QV8Engine *engine = ctx->d()->engine->v8Engine; if (r->readyState() == QQmlXMLHttpRequest::Unsent || r->readyState() == QQmlXMLHttpRequest::Opened) @@ -1956,12 +1945,12 @@ ReturnedValue QQmlXMLHttpRequestCtor::method_get_statusText(CallContext *ctx) ReturnedValue QQmlXMLHttpRequestCtor::method_get_responseText(CallContext *ctx) { Scope scope(ctx); - Scoped<QQmlXMLHttpRequestWrapper> w(scope, ctx->callData->thisObject.as<QQmlXMLHttpRequestWrapper>()); + Scoped<QQmlXMLHttpRequestWrapper> w(scope, ctx->d()->callData->thisObject.as<QQmlXMLHttpRequestWrapper>()); if (!w) V4THROW_REFERENCE("Not an XMLHttpRequest object"); - QQmlXMLHttpRequest *r = w->request; + QQmlXMLHttpRequest *r = w->d()->request; - QV8Engine *engine = ctx->engine->v8Engine; + QV8Engine *engine = ctx->d()->engine->v8Engine; if (r->readyState() != QQmlXMLHttpRequest::Loading && r->readyState() != QQmlXMLHttpRequest::Done) @@ -1973,17 +1962,17 @@ ReturnedValue QQmlXMLHttpRequestCtor::method_get_responseText(CallContext *ctx) ReturnedValue QQmlXMLHttpRequestCtor::method_get_responseXML(CallContext *ctx) { Scope scope(ctx); - Scoped<QQmlXMLHttpRequestWrapper> w(scope, ctx->callData->thisObject.as<QQmlXMLHttpRequestWrapper>()); + Scoped<QQmlXMLHttpRequestWrapper> w(scope, ctx->d()->callData->thisObject.as<QQmlXMLHttpRequestWrapper>()); if (!w) V4THROW_REFERENCE("Not an XMLHttpRequest object"); - QQmlXMLHttpRequest *r = w->request; + QQmlXMLHttpRequest *r = w->d()->request; if (!r->receivedXml() || (r->readyState() != QQmlXMLHttpRequest::Loading && r->readyState() != QQmlXMLHttpRequest::Done)) { return Encode::null(); } else { - return Document::load(ctx->engine->v8Engine, r->rawResponseBody()); + return Document::load(ctx->d()->engine->v8Engine, r->rawResponseBody()); } } @@ -1998,9 +1987,9 @@ void *qt_add_qmlxmlhttprequest(QV8Engine *engine) ExecutionEngine *v4 = QV8Engine::getV4(engine); Scope scope(v4); - Scoped<QQmlXMLHttpRequestCtor> ctor(scope, new (v4->memoryManager) QQmlXMLHttpRequestCtor(v4)); + Scoped<QQmlXMLHttpRequestCtor> ctor(scope, v4->memoryManager->alloc<QQmlXMLHttpRequestCtor>(v4)); ScopedString s(scope, v4->newString(QStringLiteral("XMLHttpRequest"))); - v4->globalObject->defineReadonlyProperty(s, ctor); + v4->globalObject->defineReadonlyProperty(s.getPointer(), ctor); QQmlXMLHttpRequestData *data = new QQmlXMLHttpRequestData; return data; diff --git a/src/qml/qml/v8/qqmlbuiltinfunctions.cpp b/src/qml/qml/v8/qqmlbuiltinfunctions.cpp index a7db7d214e..e07d97e67c 100644 --- a/src/qml/qml/v8/qqmlbuiltinfunctions.cpp +++ b/src/qml/qml/v8/qqmlbuiltinfunctions.cpp @@ -47,6 +47,7 @@ #include <private/qqmlstringconverters_p.h> #include <private/qqmllocale_p.h> #include <private/qv8engine_p.h> +#include <QFileInfo> #include <private/qqmlprofilerservice_p.h> #include <private/qqmlglobal_p.h> @@ -85,15 +86,13 @@ struct StaticQtMetaObject : public QObject { return &staticQtMetaObject; } }; -QV4::QtObject::QtObject(ExecutionEngine *v4, QQmlEngine *qmlEngine) - : Object(v4) - , m_platform(0) - , m_application(0) +QV4::QtObject::Data::Data(ExecutionEngine *v4, QQmlEngine *qmlEngine) + : Object::Data(v4) { setVTable(staticVTable()); Scope scope(v4); - ScopedObject protectThis(scope, this); + ScopedObject o(scope, this); // Set all the enums from the "Qt" namespace const QMetaObject *qtMetaObject = StaticQtMetaObject::get(); @@ -102,54 +101,54 @@ QV4::QtObject::QtObject(ExecutionEngine *v4, QQmlEngine *qmlEngine) for (int ii = 0; ii < qtMetaObject->enumeratorCount(); ++ii) { QMetaEnum enumerator = qtMetaObject->enumerator(ii); for (int jj = 0; jj < enumerator.keyCount(); ++jj) { - put((str = v4->newString(QString::fromUtf8(enumerator.key(jj)))), (v = QV4::Primitive::fromInt32(enumerator.value(jj)))); + o->put((str = v4->newString(QString::fromUtf8(enumerator.key(jj)))).getPointer(), (v = QV4::Primitive::fromInt32(enumerator.value(jj)))); } } - put((str = v4->newString(QStringLiteral("Asynchronous"))), (v = QV4::Primitive::fromInt32(0))); - put((str = v4->newString(QStringLiteral("Synchronous"))), (v = QV4::Primitive::fromInt32(1))); - - defineDefaultProperty(QStringLiteral("include"), QV4Include::method_include); - defineDefaultProperty(QStringLiteral("isQtObject"), method_isQtObject); - defineDefaultProperty(QStringLiteral("rgba"), method_rgba); - defineDefaultProperty(QStringLiteral("hsla"), method_hsla); - defineDefaultProperty(QStringLiteral("colorEqual"), method_colorEqual); - defineDefaultProperty(QStringLiteral("rect"), method_rect); - defineDefaultProperty(QStringLiteral("point"), method_point); - defineDefaultProperty(QStringLiteral("size"), method_size); - defineDefaultProperty(QStringLiteral("font"), method_font); - - defineDefaultProperty(QStringLiteral("vector2d"), method_vector2d); - defineDefaultProperty(QStringLiteral("vector3d"), method_vector3d); - defineDefaultProperty(QStringLiteral("vector4d"), method_vector4d); - defineDefaultProperty(QStringLiteral("quaternion"), method_quaternion); - defineDefaultProperty(QStringLiteral("matrix4x4"), method_matrix4x4); - - defineDefaultProperty(QStringLiteral("formatDate"), method_formatDate); - defineDefaultProperty(QStringLiteral("formatTime"), method_formatTime); - defineDefaultProperty(QStringLiteral("formatDateTime"), method_formatDateTime); - - defineDefaultProperty(QStringLiteral("openUrlExternally"), method_openUrlExternally); - defineDefaultProperty(QStringLiteral("fontFamilies"), method_fontFamilies); - defineDefaultProperty(QStringLiteral("md5"), method_md5); - defineDefaultProperty(QStringLiteral("btoa"), method_btoa); - defineDefaultProperty(QStringLiteral("atob"), method_atob); - defineDefaultProperty(QStringLiteral("resolvedUrl"), method_resolvedUrl); - defineDefaultProperty(QStringLiteral("locale"), method_locale); - defineDefaultProperty(QStringLiteral("binding"), method_binding); + o->put((str = v4->newString(QStringLiteral("Asynchronous"))).getPointer(), (v = QV4::Primitive::fromInt32(0))); + o->put((str = v4->newString(QStringLiteral("Synchronous"))).getPointer(), (v = QV4::Primitive::fromInt32(1))); + + o->defineDefaultProperty(QStringLiteral("include"), QV4Include::method_include); + o->defineDefaultProperty(QStringLiteral("isQtObject"), method_isQtObject); + o->defineDefaultProperty(QStringLiteral("rgba"), method_rgba); + o->defineDefaultProperty(QStringLiteral("hsla"), method_hsla); + o->defineDefaultProperty(QStringLiteral("colorEqual"), method_colorEqual); + o->defineDefaultProperty(QStringLiteral("rect"), method_rect); + o->defineDefaultProperty(QStringLiteral("point"), method_point); + o->defineDefaultProperty(QStringLiteral("size"), method_size); + o->defineDefaultProperty(QStringLiteral("font"), method_font); + + o->defineDefaultProperty(QStringLiteral("vector2d"), method_vector2d); + o->defineDefaultProperty(QStringLiteral("vector3d"), method_vector3d); + o->defineDefaultProperty(QStringLiteral("vector4d"), method_vector4d); + o->defineDefaultProperty(QStringLiteral("quaternion"), method_quaternion); + o->defineDefaultProperty(QStringLiteral("matrix4x4"), method_matrix4x4); + + o->defineDefaultProperty(QStringLiteral("formatDate"), method_formatDate); + o->defineDefaultProperty(QStringLiteral("formatTime"), method_formatTime); + o->defineDefaultProperty(QStringLiteral("formatDateTime"), method_formatDateTime); + + o->defineDefaultProperty(QStringLiteral("openUrlExternally"), method_openUrlExternally); + o->defineDefaultProperty(QStringLiteral("fontFamilies"), method_fontFamilies); + o->defineDefaultProperty(QStringLiteral("md5"), method_md5); + o->defineDefaultProperty(QStringLiteral("btoa"), method_btoa); + o->defineDefaultProperty(QStringLiteral("atob"), method_atob); + o->defineDefaultProperty(QStringLiteral("resolvedUrl"), method_resolvedUrl); + o->defineDefaultProperty(QStringLiteral("locale"), method_locale); + o->defineDefaultProperty(QStringLiteral("binding"), method_binding); if (qmlEngine) { - defineDefaultProperty(QStringLiteral("lighter"), method_lighter); - defineDefaultProperty(QStringLiteral("darker"), method_darker); - defineDefaultProperty(QStringLiteral("tint"), method_tint); - defineDefaultProperty(QStringLiteral("quit"), method_quit); - defineDefaultProperty(QStringLiteral("createQmlObject"), method_createQmlObject); - defineDefaultProperty(QStringLiteral("createComponent"), method_createComponent); + o->defineDefaultProperty(QStringLiteral("lighter"), method_lighter); + o->defineDefaultProperty(QStringLiteral("darker"), method_darker); + o->defineDefaultProperty(QStringLiteral("tint"), method_tint); + o->defineDefaultProperty(QStringLiteral("quit"), method_quit); + o->defineDefaultProperty(QStringLiteral("createQmlObject"), method_createQmlObject); + o->defineDefaultProperty(QStringLiteral("createComponent"), method_createComponent); } - defineAccessorProperty(QStringLiteral("platform"), method_get_platform, 0); - defineAccessorProperty(QStringLiteral("application"), method_get_application, 0); + o->defineAccessorProperty(QStringLiteral("platform"), method_get_platform, 0); + o->defineAccessorProperty(QStringLiteral("application"), method_get_application, 0); #ifndef QT_NO_IM - defineAccessorProperty(QStringLiteral("inputMethod"), method_get_inputMethod, 0); + o->defineAccessorProperty(QStringLiteral("inputMethod"), method_get_inputMethod, 0); #endif } @@ -160,10 +159,10 @@ Returns true if \c object is a valid reference to a Qt or QML object, otherwise */ ReturnedValue QtObject::method_isQtObject(QV4::CallContext *ctx) { - if (ctx->callData->argc == 0) + if (ctx->d()->callData->argc == 0) return QV4::Encode(false); - return QV4::Encode(ctx->callData->args[0].as<QV4::QObjectWrapper>() != 0); + return QV4::Encode(ctx->d()->callData->args[0].as<QV4::QObjectWrapper>() != 0); } /*! @@ -174,14 +173,14 @@ All components should be in the range 0-1 inclusive. */ ReturnedValue QtObject::method_rgba(QV4::CallContext *ctx) { - int argCount = ctx->callData->argc; + int argCount = ctx->d()->callData->argc; if (argCount < 3 || argCount > 4) V4THROW_ERROR("Qt.rgba(): Invalid arguments"); - double r = ctx->callData->args[0].toNumber(); - double g = ctx->callData->args[1].toNumber(); - double b = ctx->callData->args[2].toNumber(); - double a = (argCount == 4) ? ctx->callData->args[3].toNumber() : 1; + double r = ctx->d()->callData->args[0].toNumber(); + double g = ctx->d()->callData->args[1].toNumber(); + double b = ctx->d()->callData->args[2].toNumber(); + double a = (argCount == 4) ? ctx->d()->callData->args[3].toNumber() : 1; if (r < 0.0) r=0.0; if (r > 1.0) r=1.0; @@ -192,7 +191,7 @@ ReturnedValue QtObject::method_rgba(QV4::CallContext *ctx) if (a < 0.0) a=0.0; if (a > 1.0) a=1.0; - return ctx->engine->v8Engine->fromVariant(QQml_colorProvider()->fromRgbF(r, g, b, a)); + return ctx->d()->engine->v8Engine->fromVariant(QQml_colorProvider()->fromRgbF(r, g, b, a)); } /*! @@ -203,14 +202,14 @@ All components should be in the range 0-1 inclusive. */ ReturnedValue QtObject::method_hsla(QV4::CallContext *ctx) { - int argCount = ctx->callData->argc; + int argCount = ctx->d()->callData->argc; if (argCount < 3 || argCount > 4) V4THROW_ERROR("Qt.hsla(): Invalid arguments"); - double h = ctx->callData->args[0].toNumber(); - double s = ctx->callData->args[1].toNumber(); - double l = ctx->callData->args[2].toNumber(); - double a = (argCount == 4) ? ctx->callData->args[3].toNumber() : 1; + double h = ctx->d()->callData->args[0].toNumber(); + double s = ctx->d()->callData->args[1].toNumber(); + double l = ctx->d()->callData->args[2].toNumber(); + double a = (argCount == 4) ? ctx->d()->callData->args[3].toNumber() : 1; if (h < 0.0) h=0.0; if (h > 1.0) h=1.0; @@ -221,7 +220,7 @@ ReturnedValue QtObject::method_hsla(QV4::CallContext *ctx) if (a < 0.0) a=0.0; if (a > 1.0) a=1.0; - return ctx->engine->v8Engine->fromVariant(QQml_colorProvider()->fromHslF(h, s, l, a)); + return ctx->d()->engine->v8Engine->fromVariant(QQml_colorProvider()->fromHslF(h, s, l, a)); } /*! @@ -234,14 +233,14 @@ basic type. */ ReturnedValue QtObject::method_colorEqual(QV4::CallContext *ctx) { - if (ctx->callData->argc != 2) + if (ctx->d()->callData->argc != 2) V4THROW_ERROR("Qt.colorEqual(): Invalid arguments"); bool ok = false; - QV8Engine *v8engine = ctx->engine->v8Engine; + QV8Engine *v8engine = ctx->d()->engine->v8Engine; - QVariant lhs = v8engine->toVariant(ctx->callData->args[0], -1); + QVariant lhs = v8engine->toVariant(ctx->d()->callData->args[0], -1); if (lhs.userType() == QVariant::String) { lhs = QQmlStringConverters::colorFromString(lhs.toString(), &ok); if (!ok) { @@ -251,7 +250,7 @@ ReturnedValue QtObject::method_colorEqual(QV4::CallContext *ctx) V4THROW_ERROR("Qt.colorEqual(): Invalid arguments"); } - QVariant rhs = v8engine->toVariant(ctx->callData->args[1], -1); + QVariant rhs = v8engine->toVariant(ctx->d()->callData->args[1], -1); if (rhs.userType() == QVariant::String) { rhs = QQmlStringConverters::colorFromString(rhs.toString(), &ok); if (!ok) { @@ -274,15 +273,15 @@ The returned object has \c x, \c y, \c width and \c height attributes with the g */ ReturnedValue QtObject::method_rect(QV4::CallContext *ctx) { - if (ctx->callData->argc != 4) + if (ctx->d()->callData->argc != 4) V4THROW_ERROR("Qt.rect(): Invalid arguments"); - double x = ctx->callData->args[0].toNumber(); - double y = ctx->callData->args[1].toNumber(); - double w = ctx->callData->args[2].toNumber(); - double h = ctx->callData->args[3].toNumber(); + double x = ctx->d()->callData->args[0].toNumber(); + double y = ctx->d()->callData->args[1].toNumber(); + double w = ctx->d()->callData->args[2].toNumber(); + double h = ctx->d()->callData->args[3].toNumber(); - return ctx->engine->v8Engine->fromVariant(QVariant::fromValue(QRectF(x, y, w, h))); + return ctx->d()->engine->v8Engine->fromVariant(QVariant::fromValue(QRectF(x, y, w, h))); } /*! @@ -291,13 +290,13 @@ Returns a Point with the specified \c x and \c y coordinates. */ ReturnedValue QtObject::method_point(QV4::CallContext *ctx) { - if (ctx->callData->argc != 2) + if (ctx->d()->callData->argc != 2) V4THROW_ERROR("Qt.point(): Invalid arguments"); - double x = ctx->callData->args[0].toNumber(); - double y = ctx->callData->args[1].toNumber(); + double x = ctx->d()->callData->args[0].toNumber(); + double y = ctx->d()->callData->args[1].toNumber(); - return ctx->engine->v8Engine->fromVariant(QVariant::fromValue(QPointF(x, y))); + return ctx->d()->engine->v8Engine->fromVariant(QVariant::fromValue(QPointF(x, y))); } /*! @@ -306,13 +305,13 @@ Returns a Size with the specified \c width and \c height. */ ReturnedValue QtObject::method_size(QV4::CallContext *ctx) { - if (ctx->callData->argc != 2) + if (ctx->d()->callData->argc != 2) V4THROW_ERROR("Qt.size(): Invalid arguments"); - double w = ctx->callData->args[0].toNumber(); - double h = ctx->callData->args[1].toNumber(); + double w = ctx->d()->callData->args[0].toNumber(); + double h = ctx->d()->callData->args[1].toNumber(); - return ctx->engine->v8Engine->fromVariant(QVariant::fromValue(QSizeF(w, h))); + return ctx->d()->engine->v8Engine->fromVariant(QVariant::fromValue(QSizeF(w, h))); } /*! @@ -325,12 +324,12 @@ Invalid keys will be ignored. */ ReturnedValue QtObject::method_font(QV4::CallContext *ctx) { - if (ctx->callData->argc != 1 || !ctx->callData->args[0].isObject()) + if (ctx->d()->callData->argc != 1 || !ctx->d()->callData->args[0].isObject()) V4THROW_ERROR("Qt.font(): Invalid arguments"); - QV8Engine *v8engine = ctx->engine->v8Engine; + QV8Engine *v8engine = ctx->d()->engine->v8Engine; bool ok = false; - QVariant v = QQml_valueTypeProvider()->createVariantFromJsObject(QMetaType::QFont, QQmlV4Handle(ctx->callData->args[0]), v8engine, &ok); + QVariant v = QQml_valueTypeProvider()->createVariantFromJsObject(QMetaType::QFont, QQmlV4Handle(ctx->d()->callData->args[0]), v8engine, &ok); if (!ok) V4THROW_ERROR("Qt.font(): Invalid argument: no valid font subproperties specified"); return v8engine->fromVariant(v); @@ -344,15 +343,15 @@ Returns a Vector2D with the specified \c x and \c y. */ ReturnedValue QtObject::method_vector2d(QV4::CallContext *ctx) { - if (ctx->callData->argc != 2) + if (ctx->d()->callData->argc != 2) V4THROW_ERROR("Qt.vector2d(): Invalid arguments"); float xy[3]; // qvector2d uses float internally - xy[0] = ctx->callData->args[0].toNumber(); - xy[1] = ctx->callData->args[1].toNumber(); + xy[0] = ctx->d()->callData->args[0].toNumber(); + xy[1] = ctx->d()->callData->args[1].toNumber(); const void *params[] = { xy }; - QV8Engine *v8engine = ctx->engine->v8Engine; + QV8Engine *v8engine = ctx->d()->engine->v8Engine; return v8engine->fromVariant(QQml_valueTypeProvider()->createValueType(QMetaType::QVector2D, 1, params)); } @@ -362,16 +361,16 @@ Returns a Vector3D with the specified \c x, \c y and \c z. */ ReturnedValue QtObject::method_vector3d(QV4::CallContext *ctx) { - if (ctx->callData->argc != 3) + if (ctx->d()->callData->argc != 3) V4THROW_ERROR("Qt.vector3d(): Invalid arguments"); float xyz[3]; // qvector3d uses float internally - xyz[0] = ctx->callData->args[0].toNumber(); - xyz[1] = ctx->callData->args[1].toNumber(); - xyz[2] = ctx->callData->args[2].toNumber(); + xyz[0] = ctx->d()->callData->args[0].toNumber(); + xyz[1] = ctx->d()->callData->args[1].toNumber(); + xyz[2] = ctx->d()->callData->args[2].toNumber(); const void *params[] = { xyz }; - QV8Engine *v8engine = ctx->engine->v8Engine; + QV8Engine *v8engine = ctx->d()->engine->v8Engine; return v8engine->fromVariant(QQml_valueTypeProvider()->createValueType(QMetaType::QVector3D, 1, params)); } @@ -381,17 +380,17 @@ Returns a Vector4D with the specified \c x, \c y, \c z and \c w. */ ReturnedValue QtObject::method_vector4d(QV4::CallContext *ctx) { - if (ctx->callData->argc != 4) + if (ctx->d()->callData->argc != 4) V4THROW_ERROR("Qt.vector4d(): Invalid arguments"); float xyzw[4]; // qvector4d uses float internally - xyzw[0] = ctx->callData->args[0].toNumber(); - xyzw[1] = ctx->callData->args[1].toNumber(); - xyzw[2] = ctx->callData->args[2].toNumber(); - xyzw[3] = ctx->callData->args[3].toNumber(); + xyzw[0] = ctx->d()->callData->args[0].toNumber(); + xyzw[1] = ctx->d()->callData->args[1].toNumber(); + xyzw[2] = ctx->d()->callData->args[2].toNumber(); + xyzw[3] = ctx->d()->callData->args[3].toNumber(); const void *params[] = { xyzw }; - QV8Engine *v8engine = ctx->engine->v8Engine; + QV8Engine *v8engine = ctx->d()->engine->v8Engine; return v8engine->fromVariant(QQml_valueTypeProvider()->createValueType(QMetaType::QVector4D, 1, params)); } @@ -401,17 +400,17 @@ Returns a Quaternion with the specified \c scalar, \c x, \c y, and \c z. */ ReturnedValue QtObject::method_quaternion(QV4::CallContext *ctx) { - if (ctx->callData->argc != 4) + if (ctx->d()->callData->argc != 4) V4THROW_ERROR("Qt.quaternion(): Invalid arguments"); qreal sxyz[4]; // qquaternion uses qreal internally - sxyz[0] = ctx->callData->args[0].toNumber(); - sxyz[1] = ctx->callData->args[1].toNumber(); - sxyz[2] = ctx->callData->args[2].toNumber(); - sxyz[3] = ctx->callData->args[3].toNumber(); + sxyz[0] = ctx->d()->callData->args[0].toNumber(); + sxyz[1] = ctx->d()->callData->args[1].toNumber(); + sxyz[2] = ctx->d()->callData->args[2].toNumber(); + sxyz[3] = ctx->d()->callData->args[3].toNumber(); const void *params[] = { sxyz }; - QV8Engine *v8engine = ctx->engine->v8Engine; + QV8Engine *v8engine = ctx->d()->engine->v8Engine; return v8engine->fromVariant(QQml_valueTypeProvider()->createValueType(QMetaType::QQuaternion, 1, params)); } @@ -424,36 +423,36 @@ matrix values. */ ReturnedValue QtObject::method_matrix4x4(QV4::CallContext *ctx) { - QV8Engine *v8engine = ctx->engine->v8Engine; + QV8Engine *v8engine = ctx->d()->engine->v8Engine; - if (ctx->callData->argc == 1 && ctx->callData->args[0].isObject()) { + if (ctx->d()->callData->argc == 1 && ctx->d()->callData->args[0].isObject()) { bool ok = false; - QVariant v = QQml_valueTypeProvider()->createVariantFromJsObject(QMetaType::QMatrix4x4, QQmlV4Handle(ctx->callData->args[0]), v8engine, &ok); + QVariant v = QQml_valueTypeProvider()->createVariantFromJsObject(QMetaType::QMatrix4x4, QQmlV4Handle(ctx->d()->callData->args[0]), v8engine, &ok); if (!ok) V4THROW_ERROR("Qt.matrix4x4(): Invalid argument: not a valid matrix4x4 values array"); return v8engine->fromVariant(v); } - if (ctx->callData->argc != 16) + if (ctx->d()->callData->argc != 16) V4THROW_ERROR("Qt.matrix4x4(): Invalid arguments"); qreal vals[16]; // qmatrix4x4 uses qreal internally - vals[0] = ctx->callData->args[0].toNumber(); - vals[1] = ctx->callData->args[1].toNumber(); - vals[2] = ctx->callData->args[2].toNumber(); - vals[3] = ctx->callData->args[3].toNumber(); - vals[4] = ctx->callData->args[4].toNumber(); - vals[5] = ctx->callData->args[5].toNumber(); - vals[6] = ctx->callData->args[6].toNumber(); - vals[7] = ctx->callData->args[7].toNumber(); - vals[8] = ctx->callData->args[8].toNumber(); - vals[9] = ctx->callData->args[9].toNumber(); - vals[10] = ctx->callData->args[10].toNumber(); - vals[11] = ctx->callData->args[11].toNumber(); - vals[12] = ctx->callData->args[12].toNumber(); - vals[13] = ctx->callData->args[13].toNumber(); - vals[14] = ctx->callData->args[14].toNumber(); - vals[15] = ctx->callData->args[15].toNumber(); + vals[0] = ctx->d()->callData->args[0].toNumber(); + vals[1] = ctx->d()->callData->args[1].toNumber(); + vals[2] = ctx->d()->callData->args[2].toNumber(); + vals[3] = ctx->d()->callData->args[3].toNumber(); + vals[4] = ctx->d()->callData->args[4].toNumber(); + vals[5] = ctx->d()->callData->args[5].toNumber(); + vals[6] = ctx->d()->callData->args[6].toNumber(); + vals[7] = ctx->d()->callData->args[7].toNumber(); + vals[8] = ctx->d()->callData->args[8].toNumber(); + vals[9] = ctx->d()->callData->args[9].toNumber(); + vals[10] = ctx->d()->callData->args[10].toNumber(); + vals[11] = ctx->d()->callData->args[11].toNumber(); + vals[12] = ctx->d()->callData->args[12].toNumber(); + vals[13] = ctx->d()->callData->args[13].toNumber(); + vals[14] = ctx->d()->callData->args[14].toNumber(); + vals[15] = ctx->d()->callData->args[15].toNumber(); const void *params[] = { vals }; return v8engine->fromVariant(QQml_valueTypeProvider()->createValueType(QMetaType::QMatrix4x4, 1, params)); @@ -475,11 +474,11 @@ If \c factor is not supplied, returns a color 50% lighter than \c baseColor (fac */ ReturnedValue QtObject::method_lighter(QV4::CallContext *ctx) { - if (ctx->callData->argc != 1 && ctx->callData->argc != 2) + if (ctx->d()->callData->argc != 1 && ctx->d()->callData->argc != 2) V4THROW_ERROR("Qt.lighter(): Invalid arguments"); - QV8Engine *v8engine = ctx->engine->v8Engine; - QVariant v = v8engine->toVariant(ctx->callData->args[0], -1); + QV8Engine *v8engine = ctx->d()->engine->v8Engine; + QVariant v = v8engine->toVariant(ctx->d()->callData->args[0], -1); if (v.userType() == QVariant::String) { bool ok = false; v = QQmlStringConverters::colorFromString(v.toString(), &ok); @@ -491,8 +490,8 @@ ReturnedValue QtObject::method_lighter(QV4::CallContext *ctx) } qreal factor = 1.5; - if (ctx->callData->argc == 2) - factor = ctx->callData->args[1].toNumber(); + if (ctx->d()->callData->argc == 2) + factor = ctx->d()->callData->args[1].toNumber(); return v8engine->fromVariant(QQml_colorProvider()->lighter(v, factor)); } @@ -514,11 +513,11 @@ If \c factor is not supplied, returns a color 50% darker than \c baseColor (fact */ ReturnedValue QtObject::method_darker(QV4::CallContext *ctx) { - if (ctx->callData->argc != 1 && ctx->callData->argc != 2) + if (ctx->d()->callData->argc != 1 && ctx->d()->callData->argc != 2) V4THROW_ERROR("Qt.darker(): Invalid arguments"); - QV8Engine *v8engine = ctx->engine->v8Engine; - QVariant v = v8engine->toVariant(ctx->callData->args[0], -1); + QV8Engine *v8engine = ctx->d()->engine->v8Engine; + QVariant v = v8engine->toVariant(ctx->d()->callData->args[0], -1); if (v.userType() == QVariant::String) { bool ok = false; v = QQmlStringConverters::colorFromString(v.toString(), &ok); @@ -530,8 +529,8 @@ ReturnedValue QtObject::method_darker(QV4::CallContext *ctx) } qreal factor = 2.0; - if (ctx->callData->argc == 2) - factor = ctx->callData->args[1].toNumber(); + if (ctx->d()->callData->argc == 2) + factor = ctx->d()->callData->args[1].toNumber(); return v8engine->fromVariant(QQml_colorProvider()->darker(v, factor)); } @@ -562,13 +561,13 @@ ReturnedValue QtObject::method_darker(QV4::CallContext *ctx) */ ReturnedValue QtObject::method_tint(QV4::CallContext *ctx) { - if (ctx->callData->argc != 2) + if (ctx->d()->callData->argc != 2) V4THROW_ERROR("Qt.tint(): Invalid arguments"); - QV8Engine *v8engine = ctx->engine->v8Engine; + QV8Engine *v8engine = ctx->d()->engine->v8Engine; // base color - QVariant v1 = v8engine->toVariant(ctx->callData->args[0], -1); + QVariant v1 = v8engine->toVariant(ctx->d()->callData->args[0], -1); if (v1.userType() == QVariant::String) { bool ok = false; v1 = QQmlStringConverters::colorFromString(v1.toString(), &ok); @@ -580,7 +579,7 @@ ReturnedValue QtObject::method_tint(QV4::CallContext *ctx) } // tint color - QVariant v2 = v8engine->toVariant(ctx->callData->args[1], -1); + QVariant v2 = v8engine->toVariant(ctx->d()->callData->args[1], -1); if (v2.userType() == QVariant::String) { bool ok = false; v2 = QQmlStringConverters::colorFromString(v2.toString(), &ok); @@ -612,22 +611,22 @@ If \a format is not specified, \a date is formatted using */ ReturnedValue QtObject::method_formatDate(QV4::CallContext *ctx) { - if (ctx->callData->argc < 1 || ctx->callData->argc > 2) + if (ctx->d()->callData->argc < 1 || ctx->d()->callData->argc > 2) V4THROW_ERROR("Qt.formatDate(): Invalid arguments"); QV4::Scope scope(ctx); - QV8Engine *v8engine = ctx->engine->v8Engine; + QV8Engine *v8engine = ctx->d()->engine->v8Engine; Qt::DateFormat enumFormat = Qt::DefaultLocaleShortDate; - QDate date = v8engine->toVariant(ctx->callData->args[0], -1).toDateTime().date(); + QDate date = v8engine->toVariant(ctx->d()->callData->args[0], -1).toDateTime().date(); QString formattedDate; - if (ctx->callData->argc == 2) { - QV4::ScopedString s(scope, ctx->callData->args[1]); + if (ctx->d()->callData->argc == 2) { + QV4::ScopedString s(scope, ctx->d()->callData->args[1]); if (s) { QString format = s->toQString(); formattedDate = date.toString(format); - } else if (ctx->callData->args[1].isNumber()) { - quint32 intFormat = ctx->callData->args[1].asDouble(); + } else if (ctx->d()->callData->args[1].isNumber()) { + quint32 intFormat = ctx->d()->callData->args[1].asDouble(); Qt::DateFormat format = Qt::DateFormat(intFormat); formattedDate = date.toString(format); } else { @@ -637,7 +636,7 @@ ReturnedValue QtObject::method_formatDate(QV4::CallContext *ctx) formattedDate = date.toString(enumFormat); } - return ctx->engine->newString(formattedDate)->asReturnedValue(); + return ctx->d()->engine->newString(formattedDate)->asReturnedValue(); } /*! @@ -657,28 +656,28 @@ If \a format is not specified, \a time is formatted using */ ReturnedValue QtObject::method_formatTime(QV4::CallContext *ctx) { - if (ctx->callData->argc < 1 || ctx->callData->argc > 2) + if (ctx->d()->callData->argc < 1 || ctx->d()->callData->argc > 2) V4THROW_ERROR("Qt.formatTime(): Invalid arguments"); QV4::Scope scope(ctx); - QV8Engine *v8engine = ctx->engine->v8Engine; + QV8Engine *v8engine = ctx->d()->engine->v8Engine; - QVariant argVariant = v8engine->toVariant(ctx->callData->args[0], -1); + QVariant argVariant = v8engine->toVariant(ctx->d()->callData->args[0], -1); QTime time; - if (ctx->callData->args[0].asDateObject() || (argVariant.type() == QVariant::String)) + if (ctx->d()->callData->args[0].asDateObject() || (argVariant.type() == QVariant::String)) time = argVariant.toDateTime().time(); else // if (argVariant.type() == QVariant::Time), or invalid. time = argVariant.toTime(); Qt::DateFormat enumFormat = Qt::DefaultLocaleShortDate; QString formattedTime; - if (ctx->callData->argc == 2) { - QV4::ScopedString s(scope, ctx->callData->args[1]); + if (ctx->d()->callData->argc == 2) { + QV4::ScopedString s(scope, ctx->d()->callData->args[1]); if (s) { QString format = s->toQString(); formattedTime = time.toString(format); - } else if (ctx->callData->args[1].isNumber()) { - quint32 intFormat = ctx->callData->args[1].asDouble(); + } else if (ctx->d()->callData->args[1].isNumber()) { + quint32 intFormat = ctx->d()->callData->args[1].asDouble(); Qt::DateFormat format = Qt::DateFormat(intFormat); formattedTime = time.toString(format); } else { @@ -688,7 +687,7 @@ ReturnedValue QtObject::method_formatTime(QV4::CallContext *ctx) formattedTime = time.toString(enumFormat); } - return ctx->engine->newString(formattedTime)->asReturnedValue(); + return ctx->d()->engine->newString(formattedTime)->asReturnedValue(); } /*! @@ -783,22 +782,22 @@ with the \a format values below to produce the following results: */ ReturnedValue QtObject::method_formatDateTime(QV4::CallContext *ctx) { - if (ctx->callData->argc < 1 || ctx->callData->argc > 2) + if (ctx->d()->callData->argc < 1 || ctx->d()->callData->argc > 2) V4THROW_ERROR("Qt.formatDateTime(): Invalid arguments"); QV4::Scope scope(ctx); - QV8Engine *v8engine = ctx->engine->v8Engine; + QV8Engine *v8engine = ctx->d()->engine->v8Engine; Qt::DateFormat enumFormat = Qt::DefaultLocaleShortDate; - QDateTime dt = v8engine->toVariant(ctx->callData->args[0], -1).toDateTime(); + QDateTime dt = v8engine->toVariant(ctx->d()->callData->args[0], -1).toDateTime(); QString formattedDt; - if (ctx->callData->argc == 2) { - QV4::ScopedString s(scope, ctx->callData->args[1]); + if (ctx->d()->callData->argc == 2) { + QV4::ScopedString s(scope, ctx->d()->callData->args[1]); if (s) { QString format = s->toQString(); formattedDt = dt.toString(format); - } else if (ctx->callData->args[1].isNumber()) { - quint32 intFormat = ctx->callData->args[1].asDouble(); + } else if (ctx->d()->callData->args[1].isNumber()) { + quint32 intFormat = ctx->d()->callData->args[1].asDouble(); Qt::DateFormat format = Qt::DateFormat(intFormat); formattedDt = dt.toString(format); } else { @@ -808,7 +807,7 @@ ReturnedValue QtObject::method_formatDateTime(QV4::CallContext *ctx) formattedDt = dt.toString(enumFormat); } - return ctx->engine->newString(formattedDt)->asReturnedValue(); + return ctx->d()->engine->newString(formattedDt)->asReturnedValue(); } /*! @@ -817,10 +816,10 @@ Attempts to open the specified \c target url in an external application, based o */ ReturnedValue QtObject::method_openUrlExternally(QV4::CallContext *ctx) { - if (ctx->callData->argc != 1) + if (ctx->d()->callData->argc != 1) return QV4::Encode(false); - QV8Engine *v8engine = ctx->engine->v8Engine; + QV8Engine *v8engine = ctx->d()->engine->v8Engine; QUrl url(Value::fromReturnedValue(method_resolvedUrl(ctx)).toQStringNoThrow()); return v8engine->fromVariant(QQml_guiProvider()->openUrlExternally(url)); @@ -832,21 +831,21 @@ ReturnedValue QtObject::method_openUrlExternally(QV4::CallContext *ctx) */ ReturnedValue QtObject::method_resolvedUrl(QV4::CallContext *ctx) { - QV8Engine *v8engine = ctx->engine->v8Engine; + QV8Engine *v8engine = ctx->d()->engine->v8Engine; - QUrl url = v8engine->toVariant(ctx->callData->args[0], -1).toUrl(); + QUrl url = v8engine->toVariant(ctx->d()->callData->args[0], -1).toUrl(); QQmlEngine *e = v8engine->engine(); QQmlEnginePrivate *p = 0; if (e) p = QQmlEnginePrivate::get(e); if (p) { QQmlContextData *ctxt = v8engine->callingContext(); if (ctxt) - return ctx->engine->newString(ctxt->resolvedUrl(url).toString())->asReturnedValue(); + return ctx->d()->engine->newString(ctxt->resolvedUrl(url).toString())->asReturnedValue(); else - return ctx->engine->newString(url.toString())->asReturnedValue(); + return ctx->d()->engine->newString(url.toString())->asReturnedValue(); } - return ctx->engine->newString(e->baseUrl().resolved(url).toString())->asReturnedValue(); + return ctx->d()->engine->newString(e->baseUrl().resolved(url).toString())->asReturnedValue(); } /*! @@ -855,10 +854,10 @@ Returns a list of the font families available to the application. */ ReturnedValue QtObject::method_fontFamilies(CallContext *ctx) { - if (ctx->callData->argc != 0) + if (ctx->d()->callData->argc != 0) V4THROW_ERROR("Qt.fontFamilies(): Invalid arguments"); - QV8Engine *v8engine = ctx->engine->v8Engine; + QV8Engine *v8engine = ctx->d()->engine->v8Engine; return v8engine->fromVariant(QVariant(QQml_guiProvider()->fontFamilies())); } @@ -868,12 +867,12 @@ Returns a hex string of the md5 hash of \c data. */ ReturnedValue QtObject::method_md5(CallContext *ctx) { - if (ctx->callData->argc != 1) + if (ctx->d()->callData->argc != 1) V4THROW_ERROR("Qt.md5(): Invalid arguments"); - QByteArray data = ctx->callData->args[0].toQStringNoThrow().toUtf8(); + QByteArray data = ctx->d()->callData->args[0].toQStringNoThrow().toUtf8(); QByteArray result = QCryptographicHash::hash(data, QCryptographicHash::Md5); - return ctx->engine->newString(QLatin1String(result.toHex()))->asReturnedValue(); + return ctx->d()->engine->newString(QLatin1String(result.toHex()))->asReturnedValue(); } /*! @@ -882,12 +881,12 @@ Binary to ASCII - this function returns a base64 encoding of \c data. */ ReturnedValue QtObject::method_btoa(CallContext *ctx) { - if (ctx->callData->argc != 1) + if (ctx->d()->callData->argc != 1) V4THROW_ERROR("Qt.btoa(): Invalid arguments"); - QByteArray data = ctx->callData->args[0].toQStringNoThrow().toUtf8(); + QByteArray data = ctx->d()->callData->args[0].toQStringNoThrow().toUtf8(); - return ctx->engine->newString(QLatin1String(data.toBase64()))->asReturnedValue(); + return ctx->d()->engine->newString(QLatin1String(data.toBase64()))->asReturnedValue(); } /*! @@ -896,12 +895,12 @@ ASCII to binary - this function returns a base64 decoding of \c data. */ ReturnedValue QtObject::method_atob(CallContext *ctx) { - if (ctx->callData->argc != 1) + if (ctx->d()->callData->argc != 1) V4THROW_ERROR("Qt.atob(): Invalid arguments"); - QByteArray data = ctx->callData->args[0].toQStringNoThrow().toLatin1(); + QByteArray data = ctx->d()->callData->args[0].toQStringNoThrow().toLatin1(); - return ctx->engine->newString(QString::fromUtf8(QByteArray::fromBase64(data)))->asReturnedValue(); + return ctx->d()->engine->newString(QString::fromUtf8(QByteArray::fromBase64(data)))->asReturnedValue(); } /*! @@ -913,7 +912,7 @@ QQmlEngine::quit() signal to the QCoreApplication::quit() slot. */ ReturnedValue QtObject::method_quit(CallContext *ctx) { - QV8Engine *v8engine = ctx->engine->v8Engine; + QV8Engine *v8engine = ctx->d()->engine->v8Engine; QQmlEnginePrivate::get(v8engine->engine())->sendQuit(); return QV4::Encode::undefined(); @@ -946,7 +945,7 @@ See \l {Dynamic QML Object Creation from JavaScript} for more information on usi ReturnedValue QtObject::method_createQmlObject(CallContext *ctx) { Scope scope(ctx); - if (ctx->callData->argc < 2 || ctx->callData->argc > 3) + if (ctx->d()->callData->argc < 2 || ctx->d()->callData->argc > 3) V4THROW_ERROR("Qt.createQmlObject(): Invalid arguments"); struct Error { @@ -962,21 +961,21 @@ ReturnedValue QtObject::method_createQmlObject(CallContext *ctx) const QQmlError &error = errors.at(ii); errorstr += QLatin1String("\n ") + error.toString(); qmlerror = v4->newObject(); - qmlerror->put((s = v4->newString(QStringLiteral("lineNumber"))), (v = QV4::Primitive::fromInt32(error.line()))); - qmlerror->put((s = v4->newString(QStringLiteral("columnNumber"))), (v = QV4::Primitive::fromInt32(error.column()))); - qmlerror->put((s = v4->newString(QStringLiteral("fileName"))), (v = v4->newString(error.url().toString()))); - qmlerror->put((s = v4->newString(QStringLiteral("message"))), (v = v4->newString(error.description()))); + qmlerror->put((s = v4->newString(QStringLiteral("lineNumber"))).getPointer(), (v = QV4::Primitive::fromInt32(error.line()))); + qmlerror->put((s = v4->newString(QStringLiteral("columnNumber"))).getPointer(), (v = QV4::Primitive::fromInt32(error.column()))); + qmlerror->put((s = v4->newString(QStringLiteral("fileName"))).getPointer(), (v = v4->newString(error.url().toString()))); + qmlerror->put((s = v4->newString(QStringLiteral("message"))).getPointer(), (v = v4->newString(error.description()))); qmlerrors->putIndexed(ii, qmlerror); } v = v4->newString(errorstr); Scoped<Object> errorObject(scope, v4->newErrorObject(v)); - errorObject->put((s = v4->newString(QStringLiteral("qmlErrors"))), qmlerrors); + errorObject->put((s = v4->newString(QStringLiteral("qmlErrors"))).getPointer(), qmlerrors); return errorObject.asReturnedValue(); } }; - QV8Engine *v8engine = ctx->engine->v8Engine; + QV8Engine *v8engine = ctx->d()->engine->v8Engine; QQmlEngine *engine = v8engine->engine(); QQmlContextData *context = v8engine->callingContext(); @@ -988,13 +987,13 @@ ReturnedValue QtObject::method_createQmlObject(CallContext *ctx) effectiveContext = context->asQQmlContext(); Q_ASSERT(effectiveContext); - QString qml = ctx->callData->args[0].toQStringNoThrow(); + QString qml = ctx->d()->callData->args[0].toQStringNoThrow(); if (qml.isEmpty()) return QV4::Encode::null(); QUrl url; - if (ctx->callData->argc > 2) - url = QUrl(ctx->callData->args[2].toQStringNoThrow()); + if (ctx->d()->callData->argc > 2) + url = QUrl(ctx->d()->callData->args[2].toQStringNoThrow()); else url = QUrl(QLatin1String("inline")); @@ -1002,7 +1001,7 @@ ReturnedValue QtObject::method_createQmlObject(CallContext *ctx) url = context->resolvedUrl(url); QObject *parentArg = 0; - QV4::Scoped<QV4::QObjectWrapper> qobjectWrapper(scope, ctx->callData->args[1]); + QV4::Scoped<QV4::QObjectWrapper> qobjectWrapper(scope, ctx->d()->callData->args[1]); if (!!qobjectWrapper) parentArg = qobjectWrapper->object(); if (!parentArg) @@ -1012,7 +1011,7 @@ ReturnedValue QtObject::method_createQmlObject(CallContext *ctx) component.setData(qml.toUtf8(), url); if (component.isError()) { - ScopedValue v(scope, Error::create(ctx->engine, component.errors())); + ScopedValue v(scope, Error::create(ctx->d()->engine, component.errors())); return ctx->throwError(v); } @@ -1036,13 +1035,13 @@ ReturnedValue QtObject::method_createQmlObject(CallContext *ctx) component.completeCreate(); if (component.isError()) { - ScopedValue v(scope, Error::create(ctx->engine, component.errors())); + ScopedValue v(scope, Error::create(ctx->d()->engine, component.errors())); return ctx->throwError(v); } Q_ASSERT(obj); - return QV4::QObjectWrapper::wrap(ctx->engine, obj); + return QV4::QObjectWrapper::wrap(ctx->d()->engine, obj); } /*! @@ -1078,12 +1077,12 @@ use \l{QtQml::Qt::createQmlObject()}{Qt.createQmlObject()}. */ ReturnedValue QtObject::method_createComponent(CallContext *ctx) { - if (ctx->callData->argc < 1 || ctx->callData->argc > 3) + if (ctx->d()->callData->argc < 1 || ctx->d()->callData->argc > 3) return ctx->throwError(QStringLiteral("Qt.createComponent(): Invalid arguments")); Scope scope(ctx); - QV8Engine *v8engine = ctx->engine->v8Engine; + QV8Engine *v8engine = ctx->d()->engine->v8Engine; QQmlEngine *engine = v8engine->engine(); QQmlContextData *context = v8engine->callingContext(); @@ -1092,7 +1091,7 @@ ReturnedValue QtObject::method_createComponent(CallContext *ctx) if (context->isPragmaLibraryContext) effectiveContext = 0; - QString arg = ctx->callData->args[0].toQStringNoThrow(); + QString arg = ctx->d()->callData->args[0].toQStringNoThrow(); if (arg.isEmpty()) return QV4::Encode::null(); @@ -1100,23 +1099,23 @@ ReturnedValue QtObject::method_createComponent(CallContext *ctx) QObject *parentArg = 0; int consumedCount = 1; - if (ctx->callData->argc > 1) { - ScopedValue lastArg(scope, ctx->callData->args[ctx->callData->argc-1]); + if (ctx->d()->callData->argc > 1) { + ScopedValue lastArg(scope, ctx->d()->callData->args[ctx->d()->callData->argc-1]); // The second argument could be the mode enum - if (ctx->callData->args[1].isInteger()) { - int mode = ctx->callData->args[1].integerValue(); + if (ctx->d()->callData->args[1].isInteger()) { + int mode = ctx->d()->callData->args[1].integerValue(); if (mode != int(QQmlComponent::PreferSynchronous) && mode != int(QQmlComponent::Asynchronous)) return ctx->throwError(QStringLiteral("Qt.createComponent(): Invalid arguments")); compileMode = QQmlComponent::CompilationMode(mode); consumedCount += 1; } else { // The second argument could be the parent only if there are exactly two args - if ((ctx->callData->argc != 2) || !(lastArg->isObject() || lastArg->isNull())) + if ((ctx->d()->callData->argc != 2) || !(lastArg->isObject() || lastArg->isNull())) return ctx->throwError(QStringLiteral("Qt.createComponent(): Invalid arguments")); } - if (consumedCount < ctx->callData->argc) { + if (consumedCount < ctx->d()->callData->argc) { if (lastArg->isObject()) { Scoped<QObjectWrapper> qobjectWrapper(scope, lastArg); if (qobjectWrapper) @@ -1137,7 +1136,7 @@ ReturnedValue QtObject::method_createComponent(CallContext *ctx) QQmlData::get(c, true)->explicitIndestructibleSet = false; QQmlData::get(c)->indestructible = false; - return QV4::QObjectWrapper::wrap(ctx->engine, c); + return QV4::QObjectWrapper::wrap(ctx->d()->engine, c); } /*! @@ -1163,20 +1162,20 @@ ReturnedValue QtObject::method_createComponent(CallContext *ctx) ReturnedValue QtObject::method_locale(CallContext *ctx) { QString code; - if (ctx->callData->argc > 1) + if (ctx->d()->callData->argc > 1) V4THROW_ERROR("locale() requires 0 or 1 argument"); - if (ctx->callData->argc == 1 && !ctx->callData->args[0].isString()) + if (ctx->d()->callData->argc == 1 && !ctx->d()->callData->args[0].isString()) V4THROW_TYPE("locale(): argument (locale code) must be a string"); - QV8Engine *v8engine = ctx->engine->v8Engine; - if (ctx->callData->argc == 1) - code = ctx->callData->args[0].toQStringNoThrow(); + QV8Engine *v8engine = ctx->d()->engine->v8Engine; + if (ctx->d()->callData->argc == 1) + code = ctx->d()->callData->args[0].toQStringNoThrow(); return QQmlLocale::locale(v8engine, code); } -QQmlBindingFunction::QQmlBindingFunction(FunctionObject *originalFunction) - : QV4::FunctionObject(originalFunction->scope, originalFunction->name()) +QQmlBindingFunction::Data::Data(FunctionObject *originalFunction) + : QV4::FunctionObject::Data(originalFunction->scope(), originalFunction->name()) , originalFunction(originalFunction) { setVTable(staticVTable()); @@ -1186,20 +1185,20 @@ QQmlBindingFunction::QQmlBindingFunction(FunctionObject *originalFunction) void QQmlBindingFunction::initBindingLocation() { QV4::StackFrame frame = engine()->currentStackFrame(); - bindingLocation.sourceFile = frame.source; - bindingLocation.line = frame.line; + d()->bindingLocation.sourceFile = frame.source; + d()->bindingLocation.line = frame.line; } ReturnedValue QQmlBindingFunction::call(Managed *that, CallData *callData) { QQmlBindingFunction *This = static_cast<QQmlBindingFunction*>(that); - return This->originalFunction->call(callData); + return This->d()->originalFunction->call(callData); } void QQmlBindingFunction::markObjects(Managed *that, ExecutionEngine *e) { QQmlBindingFunction *This = static_cast<QQmlBindingFunction*>(that); - This->originalFunction->mark(e); + This->d()->originalFunction->mark(e); QV4::FunctionObject::markObjects(that, e); } @@ -1251,48 +1250,48 @@ DEFINE_OBJECT_VTABLE(QQmlBindingFunction); */ ReturnedValue QtObject::method_binding(CallContext *ctx) { - if (ctx->callData->argc != 1) + if (ctx->d()->callData->argc != 1) V4THROW_ERROR("binding() requires 1 argument"); - QV4::FunctionObject *f = ctx->callData->args[0].asFunctionObject(); + QV4::FunctionObject *f = ctx->d()->callData->args[0].asFunctionObject(); if (!f) V4THROW_TYPE("binding(): argument (binding expression) must be a function"); - return (new (ctx->engine->memoryManager) QQmlBindingFunction(f))->asReturnedValue(); + return (ctx->d()->engine->memoryManager->alloc<QQmlBindingFunction>(f))->asReturnedValue(); } ReturnedValue QtObject::method_get_platform(CallContext *ctx) { // ### inefficient. Should be just a value based getter - Object *o = ctx->callData->thisObject.asObject(); + Object *o = ctx->d()->callData->thisObject.asObject(); if (!o) return ctx->throwTypeError(); QtObject *qt = o->as<QtObject>(); if (!qt) return ctx->throwTypeError(); - if (!qt->m_platform) + if (!qt->d()->platform) // Only allocate a platform object once - qt->m_platform = new QQmlPlatform(ctx->engine->v8Engine->publicEngine()); + qt->d()->platform = new QQmlPlatform(ctx->d()->engine->v8Engine->publicEngine()); - return QV4::QObjectWrapper::wrap(ctx->engine, qt->m_platform); + return QV4::QObjectWrapper::wrap(ctx->d()->engine, qt->d()->platform); } ReturnedValue QtObject::method_get_application(CallContext *ctx) { // ### inefficient. Should be just a value based getter - Object *o = ctx->callData->thisObject.asObject(); + Object *o = ctx->d()->callData->thisObject.asObject(); if (!o) return ctx->throwTypeError(); QtObject *qt = o->as<QtObject>(); if (!qt) return ctx->throwTypeError(); - if (!qt->m_application) + if (!qt->d()->application) // Only allocate an application object once - qt->m_application = QQml_guiProvider()->application(ctx->engine->v8Engine->publicEngine()); + qt->d()->application = QQml_guiProvider()->application(ctx->d()->engine->v8Engine->publicEngine()); - return QV4::QObjectWrapper::wrap(ctx->engine, qt->m_application); + return QV4::QObjectWrapper::wrap(ctx->d()->engine, qt->d()->application); } #ifndef QT_NO_IM @@ -1300,31 +1299,31 @@ ReturnedValue QtObject::method_get_inputMethod(CallContext *ctx) { QObject *o = QQml_guiProvider()->inputMethod(); QQmlEngine::setObjectOwnership(o, QQmlEngine::CppOwnership); - return QV4::QObjectWrapper::wrap(ctx->engine, o); + return QV4::QObjectWrapper::wrap(ctx->d()->engine, o); } #endif -QV4::ConsoleObject::ConsoleObject(ExecutionEngine *v4) - : Object(v4) +QV4::ConsoleObject::Data::Data(ExecutionEngine *v4) + : Object::Data(v4) { QV4::Scope scope(v4); - QV4::ScopedObject protectThis(scope, this); - - defineDefaultProperty(QStringLiteral("debug"), method_log); - defineDefaultProperty(QStringLiteral("log"), method_log); - defineDefaultProperty(QStringLiteral("info"), method_log); - defineDefaultProperty(QStringLiteral("warn"), method_warn); - defineDefaultProperty(QStringLiteral("error"), method_error); - defineDefaultProperty(QStringLiteral("assert"), method_assert); - - defineDefaultProperty(QStringLiteral("count"), method_count); - defineDefaultProperty(QStringLiteral("profile"), method_profile); - defineDefaultProperty(QStringLiteral("profileEnd"), method_profileEnd); - defineDefaultProperty(QStringLiteral("time"), method_time); - defineDefaultProperty(QStringLiteral("timeEnd"), method_timeEnd); - defineDefaultProperty(QStringLiteral("trace"), method_trace); - defineDefaultProperty(QStringLiteral("exception"), method_exception); + QV4::ScopedObject o(scope, this); + + o->defineDefaultProperty(QStringLiteral("debug"), method_log); + o->defineDefaultProperty(QStringLiteral("log"), method_log); + o->defineDefaultProperty(QStringLiteral("info"), method_log); + o->defineDefaultProperty(QStringLiteral("warn"), method_warn); + o->defineDefaultProperty(QStringLiteral("error"), method_error); + o->defineDefaultProperty(QStringLiteral("assert"), method_assert); + + o->defineDefaultProperty(QStringLiteral("count"), method_count); + o->defineDefaultProperty(QStringLiteral("profile"), method_profile); + o->defineDefaultProperty(QStringLiteral("profileEnd"), method_profileEnd); + o->defineDefaultProperty(QStringLiteral("time"), method_time); + o->defineDefaultProperty(QStringLiteral("timeEnd"), method_timeEnd); + o->defineDefaultProperty(QStringLiteral("trace"), method_trace); + o->defineDefaultProperty(QStringLiteral("exception"), method_exception); } @@ -1364,16 +1363,16 @@ static QV4::ReturnedValue writeToConsole(ConsoleLogTypes logType, CallContext *c bool printStack = false) { QString result; - QV4::ExecutionEngine *v4 = ctx->engine; + QV4::ExecutionEngine *v4 = ctx->d()->engine; - for (int i = 0; i < ctx->callData->argc; ++i) { + for (int i = 0; i < ctx->d()->callData->argc; ++i) { if (i != 0) result.append(QLatin1Char(' ')); - if (ctx->callData->args[i].asArrayObject()) - result.append(QStringLiteral("[") + ctx->callData->args[i].toQStringNoThrow() + QStringLiteral("]")); + if (ctx->d()->callData->args[i].asArrayObject()) + result.append(QStringLiteral("[") + ctx->d()->callData->args[i].toQStringNoThrow() + QStringLiteral("]")); else - result.append(ctx->callData->args[i].toQStringNoThrow()); + result.append(ctx->d()->callData->args[i].toQStringNoThrow()); } if (printStack) { @@ -1423,7 +1422,7 @@ QV4::ReturnedValue ConsoleObject::method_log(CallContext *ctx) QV4::ReturnedValue ConsoleObject::method_profile(CallContext *ctx) { - QV4::ExecutionEngine *v4 = ctx->engine; + QV4::ExecutionEngine *v4 = ctx->d()->engine; QV4::StackFrame frame = v4->currentStackFrame(); const QByteArray baSource = frame.source.toUtf8(); @@ -1441,7 +1440,7 @@ QV4::ReturnedValue ConsoleObject::method_profile(CallContext *ctx) QV4::ReturnedValue ConsoleObject::method_profileEnd(CallContext *ctx) { - QV4::ExecutionEngine *v4 = ctx->engine; + QV4::ExecutionEngine *v4 = ctx->d()->engine; QV4::StackFrame frame = v4->currentStackFrame(); const QByteArray baSource = frame.source.toUtf8(); @@ -1460,24 +1459,24 @@ QV4::ReturnedValue ConsoleObject::method_profileEnd(CallContext *ctx) QV4::ReturnedValue ConsoleObject::method_time(CallContext *ctx) { - if (ctx->callData->argc != 1) + if (ctx->d()->callData->argc != 1) V4THROW_ERROR("console.time(): Invalid arguments"); - QV8Engine *v8engine = ctx->engine->v8Engine; + QV8Engine *v8engine = ctx->d()->engine->v8Engine; - QString name = ctx->callData->args[0].toQStringNoThrow(); + QString name = ctx->d()->callData->args[0].toQStringNoThrow(); v8engine->startTimer(name); return QV4::Encode::undefined(); } QV4::ReturnedValue ConsoleObject::method_timeEnd(CallContext *ctx) { - if (ctx->callData->argc != 1) + if (ctx->d()->callData->argc != 1) V4THROW_ERROR("console.time(): Invalid arguments"); - QV8Engine *v8engine = ctx->engine->v8Engine; + QV8Engine *v8engine = ctx->d()->engine->v8Engine; - QString name = ctx->callData->args[0].toQStringNoThrow(); + QString name = ctx->d()->callData->args[0].toQStringNoThrow(); bool wasRunning; qint64 elapsed = v8engine->stopTimer(name, &wasRunning); if (wasRunning) { @@ -1490,11 +1489,11 @@ QV4::ReturnedValue ConsoleObject::method_count(CallContext *ctx) { // first argument: name to print. Ignore any additional arguments QString name; - if (ctx->callData->argc > 0) - name = ctx->callData->args[0].toQStringNoThrow(); + if (ctx->d()->callData->argc > 0) + name = ctx->d()->callData->args[0].toQStringNoThrow(); - QV4::ExecutionEngine *v4 = ctx->engine; - QV8Engine *v8engine = ctx->engine->v8Engine; + QV4::ExecutionEngine *v4 = ctx->d()->engine; + QV8Engine *v8engine = ctx->d()->engine->v8Engine; QV4::StackFrame frame = v4->currentStackFrame(); @@ -1512,10 +1511,10 @@ QV4::ReturnedValue ConsoleObject::method_count(CallContext *ctx) QV4::ReturnedValue ConsoleObject::method_trace(CallContext *ctx) { - if (ctx->callData->argc != 0) + if (ctx->d()->callData->argc != 0) V4THROW_ERROR("console.trace(): Invalid arguments"); - QV4::ExecutionEngine *v4 = ctx->engine; + QV4::ExecutionEngine *v4 = ctx->d()->engine; QString stack = jsStack(v4); @@ -1534,18 +1533,18 @@ QV4::ReturnedValue ConsoleObject::method_warn(CallContext *ctx) QV4::ReturnedValue ConsoleObject::method_assert(CallContext *ctx) { - if (ctx->callData->argc == 0) + if (ctx->d()->callData->argc == 0) V4THROW_ERROR("console.assert(): Missing argument"); - QV4::ExecutionEngine *v4 = ctx->engine; + QV4::ExecutionEngine *v4 = ctx->d()->engine; - if (!ctx->callData->args[0].toBoolean()) { + if (!ctx->d()->callData->args[0].toBoolean()) { QString message; - for (int i = 1; i < ctx->callData->argc; ++i) { + for (int i = 1; i < ctx->d()->callData->argc; ++i) { if (i != 1) message.append(QLatin1Char(' ')); - message.append(ctx->callData->args[i].toQStringNoThrow()); + message.append(ctx->d()->callData->args[i].toQStringNoThrow()); } QString stack = jsStack(v4); @@ -1561,7 +1560,7 @@ QV4::ReturnedValue ConsoleObject::method_assert(CallContext *ctx) QV4::ReturnedValue ConsoleObject::method_exception(CallContext *ctx) { - if (ctx->callData->argc == 0) + if (ctx->d()->callData->argc == 0) V4THROW_ERROR("console.exception(): Missing argument"); writeToConsole(Error, ctx, true); @@ -1588,10 +1587,10 @@ void QV4::GlobalExtensions::init(QQmlEngine *qmlEngine, Object *globalObject) globalObject->defineDefaultProperty(QStringLiteral("print"), ConsoleObject::method_log); globalObject->defineDefaultProperty(QStringLiteral("gc"), method_gc); - ScopedValue console(scope, new (v4->memoryManager) QV4::ConsoleObject(v4)); + ScopedObject console(scope, v4->memoryManager->alloc<QV4::ConsoleObject>(v4)); globalObject->defineDefaultProperty(QStringLiteral("console"), console); - ScopedValue qt(scope, new (v4->memoryManager) QV4::QtObject(v4, qmlEngine)); + ScopedObject qt(scope, v4->memoryManager->alloc<QV4::QtObject>(v4, qmlEngine)); globalObject->defineDefaultProperty(QStringLiteral("Qt"), qt); // string prototype extension @@ -1619,36 +1618,36 @@ void QV4::GlobalExtensions::init(QQmlEngine *qmlEngine, Object *globalObject) */ ReturnedValue GlobalExtensions::method_qsTranslate(CallContext *ctx) { - if (ctx->callData->argc < 2) + if (ctx->d()->callData->argc < 2) V4THROW_ERROR("qsTranslate() requires at least two arguments"); - if (!ctx->callData->args[0].isString()) + if (!ctx->d()->callData->args[0].isString()) V4THROW_ERROR("qsTranslate(): first argument (context) must be a string"); - if (!ctx->callData->args[1].isString()) + if (!ctx->d()->callData->args[1].isString()) V4THROW_ERROR("qsTranslate(): second argument (sourceText) must be a string"); - if ((ctx->callData->argc > 2) && !ctx->callData->args[2].isString()) + if ((ctx->d()->callData->argc > 2) && !ctx->d()->callData->args[2].isString()) V4THROW_ERROR("qsTranslate(): third argument (disambiguation) must be a string"); - QString context = ctx->callData->args[0].toQStringNoThrow(); - QString text = ctx->callData->args[1].toQStringNoThrow(); + QString context = ctx->d()->callData->args[0].toQStringNoThrow(); + QString text = ctx->d()->callData->args[1].toQStringNoThrow(); QString comment; - if (ctx->callData->argc > 2) comment = ctx->callData->args[2].toQStringNoThrow(); + if (ctx->d()->callData->argc > 2) comment = ctx->d()->callData->args[2].toQStringNoThrow(); int i = 3; - if (ctx->callData->argc > i && ctx->callData->args[i].isString()) { + if (ctx->d()->callData->argc > i && ctx->d()->callData->args[i].isString()) { qWarning("qsTranslate(): specifying the encoding as fourth argument is deprecated"); ++i; } int n = -1; - if (ctx->callData->argc > i) - n = ctx->callData->args[i].toInt32(); + if (ctx->d()->callData->argc > i) + n = ctx->d()->callData->args[i].toInt32(); QString result = QCoreApplication::translate(context.toUtf8().constData(), text.toUtf8().constData(), comment.toUtf8().constData(), n); - return ctx->engine->newString(result)->asReturnedValue(); + return ctx->d()->engine->newString(result)->asReturnedValue(); } /*! @@ -1675,9 +1674,9 @@ ReturnedValue GlobalExtensions::method_qsTranslate(CallContext *ctx) */ ReturnedValue GlobalExtensions::method_qsTranslateNoOp(CallContext *ctx) { - if (ctx->callData->argc < 2) + if (ctx->d()->callData->argc < 2) return QV4::Encode::undefined(); - return ctx->callData->args[1].asReturnedValue(); + return ctx->d()->callData->args[1].asReturnedValue(); } /*! @@ -1699,36 +1698,54 @@ ReturnedValue GlobalExtensions::method_qsTranslateNoOp(CallContext *ctx) */ ReturnedValue GlobalExtensions::method_qsTr(CallContext *ctx) { - if (ctx->callData->argc < 1) + if (ctx->d()->callData->argc < 1) V4THROW_ERROR("qsTr() requires at least one argument"); - if (!ctx->callData->args[0].isString()) + if (!ctx->d()->callData->args[0].isString()) V4THROW_ERROR("qsTr(): first argument (sourceText) must be a string"); - if ((ctx->callData->argc > 1) && !ctx->callData->args[1].isString()) + if ((ctx->d()->callData->argc > 1) && !ctx->d()->callData->args[1].isString()) V4THROW_ERROR("qsTr(): second argument (disambiguation) must be a string"); - if ((ctx->callData->argc > 2) && !ctx->callData->args[2].isNumber()) + if ((ctx->d()->callData->argc > 2) && !ctx->d()->callData->args[2].isNumber()) V4THROW_ERROR("qsTr(): third argument (n) must be a number"); - QV8Engine *v8engine = ctx->engine->v8Engine; - QQmlContextData *ctxt = v8engine->callingContext(); - - QString path = ctxt->url.toString(); - int lastSlash = path.lastIndexOf(QLatin1Char('/')); - int lastDot = path.lastIndexOf(QLatin1Char('.')); - int length = lastDot - (lastSlash + 1); - QString context = (lastSlash > -1) ? path.mid(lastSlash + 1, (length > -1) ? length : -1) : QString(); + QV8Engine *v8engine = ctx->d()->engine->v8Engine; + QString context; + if (QQmlContextData *ctxt = v8engine->callingContext()) { + QString path = ctxt->url.toString(); + int lastSlash = path.lastIndexOf(QLatin1Char('/')); + int lastDot = path.lastIndexOf(QLatin1Char('.')); + int length = lastDot - (lastSlash + 1); + context = (lastSlash > -1) ? path.mid(lastSlash + 1, (length > -1) ? length : -1) : QString(); + } else if (QV4::ExecutionContext *parentCtx = ctx->d()->parent) { + // The first non-empty source URL in the call stack determines the translation context. + while (parentCtx && context.isEmpty()) { + if (QV4::CompiledData::CompilationUnit *unit = parentCtx->d()->compilationUnit) { + QString fileName = unit->fileName(); + QUrl url(unit->fileName()); + if (url.isValid() && url.isRelative()) { + context = url.fileName(); + } else { + context = QQmlFile::urlToLocalFileOrQrc(fileName); + if (context.isEmpty() && fileName.startsWith(QLatin1String(":/"))) + context = fileName; + } + context = QFileInfo(context).baseName(); + } + parentCtx = parentCtx->d()->parent; + } + } - QString text = ctx->callData->args[0].toQStringNoThrow(); + QString text = ctx->d()->callData->args[0].toQStringNoThrow(); QString comment; - if (ctx->callData->argc > 1) - comment = ctx->callData->args[1].toQStringNoThrow(); + if (ctx->d()->callData->argc > 1) + comment = ctx->d()->callData->args[1].toQStringNoThrow(); int n = -1; - if (ctx->callData->argc > 2) - n = ctx->callData->args[2].toInt32(); + if (ctx->d()->callData->argc > 2) + n = ctx->d()->callData->args[2].toInt32(); QString result = QCoreApplication::translate(context.toUtf8().constData(), text.toUtf8().constData(), comment.toUtf8().constData(), n); - return ctx->engine->newString(result)->asReturnedValue(); + return ctx->d()->engine->newString(result)->asReturnedValue(); } /*! @@ -1755,9 +1772,9 @@ ReturnedValue GlobalExtensions::method_qsTr(CallContext *ctx) */ ReturnedValue GlobalExtensions::method_qsTrNoOp(CallContext *ctx) { - if (ctx->callData->argc < 1) + if (ctx->d()->callData->argc < 1) return QV4::Encode::undefined(); - return ctx->callData->args[0].asReturnedValue(); + return ctx->d()->callData->args[0].asReturnedValue(); } /*! @@ -1792,18 +1809,18 @@ ReturnedValue GlobalExtensions::method_qsTrNoOp(CallContext *ctx) */ ReturnedValue GlobalExtensions::method_qsTrId(CallContext *ctx) { - if (ctx->callData->argc < 1) + if (ctx->d()->callData->argc < 1) V4THROW_ERROR("qsTrId() requires at least one argument"); - if (!ctx->callData->args[0].isString()) + if (!ctx->d()->callData->args[0].isString()) V4THROW_TYPE("qsTrId(): first argument (id) must be a string"); - if (ctx->callData->argc > 1 && !ctx->callData->args[1].isNumber()) + if (ctx->d()->callData->argc > 1 && !ctx->d()->callData->args[1].isNumber()) V4THROW_TYPE("qsTrId(): second argument (n) must be a number"); int n = -1; - if (ctx->callData->argc > 1) - n = ctx->callData->args[1].toInt32(); + if (ctx->d()->callData->argc > 1) + n = ctx->d()->callData->args[1].toInt32(); - return ctx->engine->newString(qtTrId(ctx->callData->args[0].toQStringNoThrow().toUtf8().constData(), n))->asReturnedValue(); + return ctx->d()->engine->newString(qtTrId(ctx->d()->callData->args[0].toQStringNoThrow().toUtf8().constData(), n))->asReturnedValue(); } /*! @@ -1824,16 +1841,16 @@ ReturnedValue GlobalExtensions::method_qsTrId(CallContext *ctx) */ ReturnedValue GlobalExtensions::method_qsTrIdNoOp(CallContext *ctx) { - if (ctx->callData->argc < 1) + if (ctx->d()->callData->argc < 1) return QV4::Encode::undefined(); - return ctx->callData->args[0].asReturnedValue(); + return ctx->d()->callData->args[0].asReturnedValue(); } #endif // QT_NO_TRANSLATION QV4::ReturnedValue GlobalExtensions::method_gc(CallContext *ctx) { - ctx->engine->memoryManager->runGC(); + ctx->d()->engine->memoryManager->runGC(); return QV4::Encode::undefined(); } @@ -1842,21 +1859,21 @@ QV4::ReturnedValue GlobalExtensions::method_gc(CallContext *ctx) ReturnedValue GlobalExtensions::method_string_arg(CallContext *ctx) { - if (ctx->callData->argc != 1) + if (ctx->d()->callData->argc != 1) V4THROW_ERROR("String.arg(): Invalid arguments"); - QString value = ctx->callData->thisObject.toQString(); + QString value = ctx->d()->callData->thisObject.toQString(); QV4::Scope scope(ctx); - QV4::ScopedValue arg(scope, ctx->callData->args[0]); + QV4::ScopedValue arg(scope, ctx->d()->callData->args[0]); if (arg->isInteger()) - return ctx->engine->newString(value.arg(arg->integerValue()))->asReturnedValue(); + return ctx->d()->engine->newString(value.arg(arg->integerValue()))->asReturnedValue(); else if (arg->isDouble()) - return ctx->engine->newString(value.arg(arg->doubleValue()))->asReturnedValue(); + return ctx->d()->engine->newString(value.arg(arg->doubleValue()))->asReturnedValue(); else if (arg->isBoolean()) - return ctx->engine->newString(value.arg(arg->booleanValue()))->asReturnedValue(); + return ctx->d()->engine->newString(value.arg(arg->booleanValue()))->asReturnedValue(); - return ctx->engine->newString(value.arg(arg->toQString()))->asReturnedValue(); + return ctx->d()->engine->newString(value.arg(arg->toQString()))->asReturnedValue(); } diff --git a/src/qml/qml/v8/qqmlbuiltinfunctions_p.h b/src/qml/qml/v8/qqmlbuiltinfunctions_p.h index adc0c6ce4f..9732a468df 100644 --- a/src/qml/qml/v8/qqmlbuiltinfunctions_p.h +++ b/src/qml/qml/v8/qqmlbuiltinfunctions_p.h @@ -65,8 +65,13 @@ namespace QV4 { struct QtObject : Object { - V4_OBJECT - QtObject(ExecutionEngine *v4, QQmlEngine *qmlEngine); + struct Data : Object::Data { + Data(ExecutionEngine *v4, QQmlEngine *qmlEngine); + QObject *platform; + QObject *application; + }; + V4_OBJECT(Object) + static ReturnedValue method_isQtObject(CallContext *ctx); static ReturnedValue method_rgba(CallContext *ctx); @@ -104,14 +109,13 @@ struct QtObject : Object #ifndef QT_NO_IM static ReturnedValue method_get_inputMethod(CallContext *ctx); #endif - - QObject *m_platform; - QObject *m_application; }; struct ConsoleObject : Object { - ConsoleObject(ExecutionEngine *v4); + struct Data : Object::Data { + Data(ExecutionEngine *engine); + }; static ReturnedValue method_error(CallContext *ctx); static ReturnedValue method_log(CallContext *ctx); @@ -147,18 +151,23 @@ struct GlobalExtensions { struct QQmlBindingFunction : public QV4::FunctionObject { - V4_OBJECT - QQmlBindingFunction(FunctionObject *originalFunction); + struct Data : FunctionObject::Data { + Data(FunctionObject *originalFunction); + QV4::FunctionObject *originalFunction; + // Set when the binding is created later + QQmlSourceLocation bindingLocation; + }; + V4_OBJECT(QV4::FunctionObject) void initBindingLocation(); // from caller stack trace static ReturnedValue call(Managed *that, CallData *callData); static void markObjects(Managed *that, ExecutionEngine *e); + static void destroy(Managed *that) { + static_cast<QQmlBindingFunction *>(that)->d()->~Data(); + } - QV4::FunctionObject *originalFunction; - // Set when the binding is created later - QQmlSourceLocation bindingLocation; }; } diff --git a/src/qml/qml/v8/qv4domerrors_p.h b/src/qml/qml/v8/qv4domerrors_p.h index faf52ce1ad..30cbd61467 100644 --- a/src/qml/qml/v8/qv4domerrors_p.h +++ b/src/qml/qml/v8/qv4domerrors_p.h @@ -77,9 +77,9 @@ QT_BEGIN_NAMESPACE #define DOMEXCEPTION_TYPE_MISMATCH_ERR 17 #define V4THROW_DOM(error, string) { \ - QV4::ScopedValue v(scope, ctx->engine->newString(QStringLiteral(string))); \ - QV4::Scoped<Object> ex(scope, ctx->engine->newErrorObject(v)); \ - ex->put(QV4::ScopedString(scope, ctx->engine->newIdentifier(QStringLiteral("code"))), QV4::ScopedValue(scope, QV4::Primitive::fromInt32(error))); \ + QV4::ScopedValue v(scope, scope.engine->newString(QStringLiteral(string))); \ + QV4::Scoped<Object> ex(scope, scope.engine->newErrorObject(v)); \ + ex->put(QV4::ScopedString(scope, scope.engine->newIdentifier(QStringLiteral("code"))).getPointer(), QV4::ScopedValue(scope, QV4::Primitive::fromInt32(error))); \ return ctx->throwError(ex); \ } diff --git a/src/qml/qml/v8/qv8engine.cpp b/src/qml/qml/v8/qv8engine.cpp index 8305649177..68f312353a 100644 --- a/src/qml/qml/v8/qv8engine.cpp +++ b/src/qml/qml/v8/qv8engine.cpp @@ -130,7 +130,7 @@ QVariant QV8Engine::toVariant(const QV4::ValueRef value, int typeHint) QV4::Scope scope(m_v4Engine); if (QV4::VariantObject *v = value->as<QV4::VariantObject>()) - return v->data; + return v->d()->data; if (typeHint == QVariant::Bool) return QVariant(value->toBoolean()); @@ -229,9 +229,9 @@ static QV4::ReturnedValue objectFromVariantMap(QV8Engine *engine, const QVariant for (QVariantMap::ConstIterator iter = map.begin(); iter != map.end(); ++iter) { s = e->newString(iter.key()); uint idx = s->asArrayIndex(); - if (idx > 16 && (!o->arrayData || idx > o->arrayData->length() * 2)) + if (idx > 16 && (!o->arrayData() || idx > o->arrayData()->length() * 2)) o->initSparseArray(); - o->put(s, (v = engine->fromVariant(iter.value()))); + o->put(s.getPointer(), (v = engine->fromVariant(iter.value()))); } return o.asReturnedValue(); } @@ -261,7 +261,7 @@ QV4::ReturnedValue QV8Engine::fromVariant(const QVariant &variant) case QMetaType::Double: return QV4::Encode(*reinterpret_cast<const double*>(ptr)); case QMetaType::QString: - return m_v4Engine->currentContext()->engine->newString(*reinterpret_cast<const QString*>(ptr))->asReturnedValue(); + return m_v4Engine->currentContext()->d()->engine->newString(*reinterpret_cast<const QString*>(ptr))->asReturnedValue(); case QMetaType::Float: return QV4::Encode(*reinterpret_cast<const float*>(ptr)); case QMetaType::Short: @@ -398,7 +398,7 @@ QVariant QV8Engine::toBasicVariant(const QV4::ValueRef value) if (value->isString()) return value->stringValue()->toQString(); if (QQmlLocaleData *ld = value->as<QQmlLocaleData>()) - return ld->locale; + return ld->d()->locale; if (QV4::DateObject *d = value->asDateObject()) return d->toQDateTime(); // NOTE: since we convert QTime to JS Date, round trip will change the variant type (to QDateTime)! @@ -444,9 +444,9 @@ void QV8Engine::initializeGlobal() qt_add_sqlexceptions(m_v4Engine); { - for (uint i = 0; i < m_v4Engine->globalObject->internalClass->size; ++i) { - if (m_v4Engine->globalObject->internalClass->nameMap.at(i)) - m_illegalNames.insert(m_v4Engine->globalObject->internalClass->nameMap.at(i)->toQString()); + for (uint i = 0; i < m_v4Engine->globalObject->internalClass()->size; ++i) { + if (m_v4Engine->globalObject->internalClass()->nameMap.at(i)) + m_illegalNames.insert(m_v4Engine->globalObject->internalClass()->nameMap.at(i)->toQString()); } } @@ -469,7 +469,7 @@ void QV8Engine::initializeGlobal() " }"\ "})" - QV4::Scoped<QV4::FunctionObject> result(scope, QV4::Script::evaluate(m_v4Engine, QString::fromUtf8(FREEZE_SOURCE), QV4::ObjectRef::null())); + QV4::Scoped<QV4::FunctionObject> result(scope, QV4::Script::evaluate(m_v4Engine, QString::fromUtf8(FREEZE_SOURCE), 0)); Q_ASSERT(!!result); m_freezeObject = result; #undef FREEZE_SOURCE @@ -486,11 +486,6 @@ void QV8Engine::freezeObject(const QV4::ValueRef value) f->call(callData); } -void QV8Engine::gc() -{ - m_v4Engine->memoryManager->runGC(); -} - struct QV8EngineRegistrationData { QV8EngineRegistrationData() : extensionCount(0) {} @@ -560,8 +555,7 @@ QV4::ReturnedValue QV8Engine::variantListToJS(const QVariantList &lst) // The result is a QVariantList with length equal to the length // of the JS Array, and elements being the JS Array's elements // converted to QVariants, recursively. -QVariantList QV8Engine::variantListFromJS(QV4::ArrayObjectRef a, - V8ObjectSet &visitedObjects) +QVariantList QV8Engine::variantListFromJS(QV4::ArrayObject *a, V8ObjectSet &visitedObjects) { QVariantList result; if (!a) @@ -605,7 +599,7 @@ QV4::ReturnedValue QV8Engine::variantMapToJS(const QVariantMap &vmap) if (idx < UINT_MAX) o->arraySet(idx, v); else - o->insertMember(s, v); + o->insertMember(s.getPointer(), v); } return o.asReturnedValue(); } @@ -614,8 +608,7 @@ QV4::ReturnedValue QV8Engine::variantMapToJS(const QVariantMap &vmap) // The result is a QVariantMap with keys being the property names // of the object, and values being the values of the JS object's // properties converted to QVariants, recursively. -QVariantMap QV8Engine::variantMapFromJS(QV4::ObjectRef o, - V8ObjectSet &visitedObjects) +QVariantMap QV8Engine::variantMapFromJS(QV4::Object *o, V8ObjectSet &visitedObjects) { QVariantMap result; @@ -679,7 +672,7 @@ QV4::ReturnedValue QV8Engine::metaTypeToJS(int type, const void *data) case QMetaType::Double: return QV4::Encode(*reinterpret_cast<const double*>(data)); case QMetaType::QString: - return m_v4Engine->currentContext()->engine->newString(*reinterpret_cast<const QString*>(data))->asReturnedValue(); + return m_v4Engine->currentContext()->d()->engine->newString(*reinterpret_cast<const QString*>(data))->asReturnedValue(); case QMetaType::Float: return QV4::Encode(*reinterpret_cast<const float*>(data)); case QMetaType::Short: @@ -882,7 +875,7 @@ bool QV8Engine::metaTypeFromJS(const QV4::ValueRef value, int type, void *data) return true; if (value->as<QV4::VariantObject>() && name.endsWith('*')) { int valueType = QMetaType::type(name.left(name.size()-1)); - QVariant &var = value->as<QV4::VariantObject>()->data; + QVariant &var = value->as<QV4::VariantObject>()->d()->data; if (valueType == var.userType()) { // We have T t, T* is requested, so return &t. *reinterpret_cast<void* *>(data) = var.data(); @@ -893,12 +886,12 @@ bool QV8Engine::metaTypeFromJS(const QV4::ValueRef value, int type, void *data) while (proto) { bool canCast = false; if (QV4::VariantObject *vo = proto->as<QV4::VariantObject>()) { - const QVariant &v = vo->data; + const QVariant &v = vo->d()->data; canCast = (type == v.userType()) || (valueType && (valueType == v.userType())); } else if (proto->as<QV4::QObjectWrapper>()) { QByteArray className = name.left(name.size()-1); - QV4::ScopedObject p(scope, proto); + QV4::ScopedObject p(scope, proto.getPointer()); if (QObject *qobject = qtObjectFromJS(p)) canCast = qobject->qt_metacast(className) != 0; } @@ -969,7 +962,7 @@ QVariant QV8Engine::variantFromJS(const QV4::ValueRef value, if (QV4::RegExpObject *re = value->as<QV4::RegExpObject>()) return re->toQRegExp(); if (QV4::VariantObject *v = value->as<QV4::VariantObject>()) - return v->data; + return v->d()->data; if (value->as<QV4::QObjectWrapper>()) return qVariantFromValue(qtObjectFromJS(value)); if (QV4::QmlValueTypeWrapper *v = value->as<QV4::QmlValueTypeWrapper>()) @@ -1003,7 +996,7 @@ QObject *QV8Engine::qtObjectFromJS(const QV4::ValueRef value) QV4::Scoped<QV4::VariantObject> v(scope, value); if (v) { - QVariant variant = v->data; + QVariant variant = v->d()->data; int type = variant.userType(); if (type == QMetaType::QObjectStar) return *reinterpret_cast<QObject* const *>(variant.constData()); diff --git a/src/qml/qml/v8/qv8engine_p.h b/src/qml/qml/v8/qv8engine_p.h index 1295e671f0..a5b94e8bdf 100644 --- a/src/qml/qml/v8/qv8engine_p.h +++ b/src/qml/qml/v8/qv8engine_p.h @@ -219,8 +219,6 @@ public: // Return the list of illegal id names (the names of the properties on the global object) const QSet<QString> &illegalNames() const; - void gc(); - static QMutex *registrationMutex(); static int registerExtension(); @@ -228,11 +226,11 @@ public: void setExtensionData(int, Deletable *); QV4::ReturnedValue variantListToJS(const QVariantList &lst); - inline QVariantList variantListFromJS(QV4::ArrayObjectRef array) + inline QVariantList variantListFromJS(QV4::ArrayObject *array) { V8ObjectSet visitedObjects; return variantListFromJS(array, visitedObjects); } QV4::ReturnedValue variantMapToJS(const QVariantMap &vmap); - inline QVariantMap variantMapFromJS(QV4::ObjectRef object) + inline QVariantMap variantMapFromJS(QV4::Object *object) { V8ObjectSet visitedObjects; return variantMapFromJS(object, visitedObjects); } QV4::ReturnedValue variantToJS(const QVariant &value); @@ -280,8 +278,8 @@ protected: void initializeGlobal(); private: - QVariantList variantListFromJS(QV4::ArrayObjectRef array, V8ObjectSet &visitedObjects); - QVariantMap variantMapFromJS(QV4::ObjectRef object, V8ObjectSet &visitedObjects); + QVariantList variantListFromJS(QV4::ArrayObject *array, V8ObjectSet &visitedObjects); + QVariantMap variantMapFromJS(QV4::Object *object, V8ObjectSet &visitedObjects); QVariant variantFromJS(const QV4::ValueRef value, V8ObjectSet &visitedObjects); Q_DISABLE_COPY(QV8Engine) diff --git a/src/qml/types/qqmlconnections.cpp b/src/qml/types/qqmlconnections.cpp index 99ec0b55de..b0e814d285 100644 --- a/src/qml/types/qqmlconnections.cpp +++ b/src/qml/types/qqmlconnections.cpp @@ -68,8 +68,8 @@ public: bool ignoreUnknownSignals; bool componentcomplete; - QByteArray data; QQmlRefPointer<QQmlCompiledData> cdata; + QList<const QV4::CompiledData::Binding *> bindings; }; /*! @@ -205,18 +205,15 @@ void QQmlConnections::setIgnoreUnknownSignals(bool ignore) d->ignoreUnknownSignals = ignore; } -QByteArray QQmlConnectionsParser::compile(const QV4::CompiledData::QmlUnit *qmlUnit, const QList<const QV4::CompiledData::Binding *> &props) +void QQmlConnectionsParser::verifyBindings(const QV4::CompiledData::QmlUnit *qmlUnit, const QList<const QV4::CompiledData::Binding *> &props) { - QByteArray rv; - QDataStream ds(&rv, QIODevice::WriteOnly); - for (int ii = 0; ii < props.count(); ++ii) { const QV4::CompiledData::Binding *binding = props.at(ii); QString propName = qmlUnit->header.stringAt(binding->propertyNameIndex); if (!propName.startsWith(QLatin1String("on")) || !propName.at(2).isUpper()) { error(props.at(ii), QQmlConnections::tr("Cannot assign to non-existent property \"%1\"").arg(propName)); - return QByteArray(); + return; } @@ -226,56 +223,48 @@ QByteArray QQmlConnectionsParser::compile(const QV4::CompiledData::QmlUnit *qmlU error(binding, QQmlConnections::tr("Connections: nested objects not allowed")); else error(binding, QQmlConnections::tr("Connections: syntax error")); - return QByteArray(); + return; } if (binding->type != QV4::CompiledData::Binding::Type_Script) { error(binding, QQmlConnections::tr("Connections: script expected")); - return QByteArray(); - } else { - ds << propName; - ds << bindingIdentifier(binding); + return; } } - - return rv; } -void QQmlConnectionsParser::setCustomData(QObject *object, const QByteArray &data, QQmlCompiledData *cdata) +void QQmlConnectionsParser::applyBindings(QObject *object, QQmlCompiledData *cdata, const QList<const QV4::CompiledData::Binding *> &bindings) { QQmlConnectionsPrivate *p = static_cast<QQmlConnectionsPrivate *>(QObjectPrivate::get(object)); - p->data = data; p->cdata = cdata; + p->bindings = bindings; } - void QQmlConnections::connectSignals() { Q_D(QQmlConnections); if (!d->componentcomplete || (d->targetSet && !target())) return; - QDataStream ds(d->data); - while (!ds.atEnd()) { - QString propName; - ds >> propName; - int bindingId; - ds >> bindingId; + if (d->bindings.isEmpty()) + return; + QObject *target = this->target(); + QQmlData *ddata = QQmlData::get(this); + QQmlContextData *ctxtdata = ddata ? ddata->outerContext : 0; + + const QV4::CompiledData::QmlUnit *qmlUnit = d->cdata->qmlUnit; + foreach (const QV4::CompiledData::Binding *binding, d->bindings) { + Q_ASSERT(binding->type == QV4::CompiledData::Binding::Type_Script); + QString propName = qmlUnit->header.stringAt(binding->propertyNameIndex); - QQmlProperty prop(target(), propName); + QQmlProperty prop(target, propName); if (prop.isValid() && (prop.type() & QQmlProperty::SignalProperty)) { int signalIndex = QQmlPropertyPrivate::get(prop)->signalIndex(); QQmlBoundSignal *signal = - new QQmlBoundSignal(target(), signalIndex, this, qmlEngine(this)); - - QQmlContextData *ctxtdata = 0; - QQmlData *ddata = QQmlData::get(this); - if (ddata) { - ctxtdata = ddata->outerContext; - } + new QQmlBoundSignal(target, signalIndex, this, qmlEngine(this)); QQmlBoundSignalExpression *expression = ctxtdata ? - new QQmlBoundSignalExpression(target(), signalIndex, - ctxtdata, this, d->cdata->functionForBindingId(bindingId)) : 0; + new QQmlBoundSignalExpression(target, signalIndex, + ctxtdata, this, d->cdata->compilationUnit->runtimeFunctions[binding->value.compiledScriptIndex]) : 0; signal->takeExpression(expression); d->boundsignals += signal; } else { diff --git a/src/qml/types/qqmlconnections_p.h b/src/qml/types/qqmlconnections_p.h index f169eeb53f..e829828bd8 100644 --- a/src/qml/types/qqmlconnections_p.h +++ b/src/qml/types/qqmlconnections_p.h @@ -84,8 +84,8 @@ private: class QQmlConnectionsParser : public QQmlCustomParser { public: - virtual QByteArray compile(const QV4::CompiledData::QmlUnit *qmlUnit, const QList<const QV4::CompiledData::Binding *> &props); - virtual void setCustomData(QObject *, const QByteArray &, QQmlCompiledData *cdata); + virtual void verifyBindings(const QV4::CompiledData::QmlUnit *qmlUnit, const QList<const QV4::CompiledData::Binding *> &props); + virtual void applyBindings(QObject *object, QQmlCompiledData *cdata, const QList<const QV4::CompiledData::Binding *> &bindings); }; diff --git a/src/qml/types/qqmldelegatemodel.cpp b/src/qml/types/qqmldelegatemodel.cpp index 4591d42710..e2f1cffb16 100644 --- a/src/qml/types/qqmldelegatemodel.cpp +++ b/src/qml/types/qqmldelegatemodel.cpp @@ -61,17 +61,23 @@ class QQmlDelegateModelItem; struct DelegateModelGroupFunction: QV4::FunctionObject { - V4_OBJECT + struct Data : FunctionObject::Data { + Data(QV4::ExecutionContext *scope, uint flag, QV4::ReturnedValue (*code)(QQmlDelegateModelItem *item, uint flag, const QV4::ValueRef arg)) + : FunctionObject::Data(scope, QStringLiteral("DelegateModelGroupFunction")) + , flag(flag) + , code(code) + { + setVTable(staticVTable()); + } - QV4::ReturnedValue (*code)(QQmlDelegateModelItem *item, uint flag, const QV4::ValueRef arg); - uint flag; + uint flag; + QV4::ReturnedValue (*code)(QQmlDelegateModelItem *item, uint flag, const QV4::ValueRef arg); + }; + V4_OBJECT(QV4::FunctionObject) - DelegateModelGroupFunction(QV4::ExecutionContext *scope, uint flag, QV4::ReturnedValue (*code)(QQmlDelegateModelItem *item, uint flag, const QV4::ValueRef arg)) - : FunctionObject(scope, QStringLiteral("DelegateModelGroupFunction")) - , code(code) - , flag(flag) + static DelegateModelGroupFunction *create(QV4::ExecutionContext *scope, uint flag, QV4::ReturnedValue (*code)(QQmlDelegateModelItem *item, uint flag, const QV4::ValueRef arg)) { - setVTable(staticVTable()); + return scope->engine()->memoryManager->alloc<DelegateModelGroupFunction>(scope, flag, code); } static QV4::ReturnedValue construct(QV4::Managed *m, QV4::CallData *) @@ -89,7 +95,7 @@ struct DelegateModelGroupFunction: QV4::FunctionObject return v4->currentContext()->throwTypeError(QStringLiteral("Not a valid VisualData object")); QV4::ScopedValue v(scope, callData->argument(0)); - return f->code(o->item, f->flag, v); + return f->d()->code(o->d()->item, f->d()->flag, v); } }; @@ -103,8 +109,7 @@ public: QQmlDelegateModelEngineData(QV8Engine *engine); ~QQmlDelegateModelEngineData(); - QV4::ReturnedValue array(QV8Engine *engine, const QVector<QQmlChangeSet::Remove> &changes); - QV4::ReturnedValue array(QV8Engine *engine, const QVector<QQmlChangeSet::Insert> &changes); + QV4::ReturnedValue array(QV8Engine *engine, const QVector<QQmlChangeSet::Change> &changes); QV4::PersistentValue changeProto; }; @@ -722,8 +727,8 @@ void QQmlDelegateModelPrivate::updateFilterGroup() QQmlDelegateModelGroupPrivate::get(m_groups[m_compositorGroup])->emitters.insert(this); if (m_compositorGroup != previousGroup) { - QVector<QQmlChangeSet::Remove> removes; - QVector<QQmlChangeSet::Insert> inserts; + QVector<QQmlChangeSet::Change> removes; + QVector<QQmlChangeSet::Change> inserts; m_compositor.transition(previousGroup, m_compositorGroup, &removes, &inserts); QQmlChangeSet changeSet; @@ -903,7 +908,7 @@ QObject *QQmlDelegateModelPrivate::object(Compositor::Group group, int index, bo if (!m_delegate || index < 0 || index >= m_compositor.count(group)) { qWarning() << "DelegateModel::item: index out range" << index << m_compositor.count(group); return 0; - } else if (!m_context->isValid()) { + } else if (!m_context || !m_context->isValid()) { return 0; } @@ -946,7 +951,7 @@ QObject *QQmlDelegateModelPrivate::object(Compositor::Group group, int index, bo cacheItem->incubationTask->index[i] = it.index[i]; QQmlContextData *ctxt = new QQmlContextData; - ctxt->setParent(QQmlContextData::get(creationContext ? creationContext : m_context)); + ctxt->setParent(QQmlContextData::get(creationContext ? creationContext : m_context.data())); ctxt->contextObject = cacheItem; cacheItem->contextData = ctxt; @@ -1143,7 +1148,7 @@ static void incrementIndexes(QQmlDelegateModelItem *cacheItem, int count, const void QQmlDelegateModelPrivate::itemsInserted( const QVector<Compositor::Insert> &inserts, - QVarLengthArray<QVector<QQmlChangeSet::Insert>, Compositor::MaximumGroupCount> *translatedInserts, + QVarLengthArray<QVector<QQmlChangeSet::Change>, Compositor::MaximumGroupCount> *translatedInserts, QHash<int, QList<QQmlDelegateModelItem *> > *movedItems) { int cacheIndex = 0; @@ -1159,7 +1164,7 @@ void QQmlDelegateModelPrivate::itemsInserted( for (int i = 1; i < m_groupCount; ++i) { if (insert.inGroup(i)) { (*translatedInserts)[i].append( - QQmlChangeSet::Insert(insert.index[i], insert.count, insert.moveId)); + QQmlChangeSet::Change(insert.index[i], insert.count, insert.moveId)); inserted[i] += insert.count; } } @@ -1200,7 +1205,7 @@ void QQmlDelegateModelPrivate::itemsInserted( void QQmlDelegateModelPrivate::itemsInserted(const QVector<Compositor::Insert> &inserts) { - QVarLengthArray<QVector<QQmlChangeSet::Insert>, Compositor::MaximumGroupCount> translatedInserts(m_groupCount); + QVarLengthArray<QVector<QQmlChangeSet::Change>, Compositor::MaximumGroupCount> translatedInserts(m_groupCount); itemsInserted(inserts, &translatedInserts); Q_ASSERT(m_cache.count() == m_compositor.count(Compositor::Cache)); if (!m_delegate) @@ -1234,7 +1239,7 @@ void QQmlDelegateModel::_q_itemsInserted(int index, int count) void QQmlDelegateModelPrivate::itemsRemoved( const QVector<Compositor::Remove> &removes, - QVarLengthArray<QVector<QQmlChangeSet::Remove>, Compositor::MaximumGroupCount> *translatedRemoves, + QVarLengthArray<QVector<QQmlChangeSet::Change>, Compositor::MaximumGroupCount> *translatedRemoves, QHash<int, QList<QQmlDelegateModelItem *> > *movedItems) { int cacheIndex = 0; @@ -1251,7 +1256,7 @@ void QQmlDelegateModelPrivate::itemsRemoved( for (int i = 1; i < m_groupCount; ++i) { if (remove.inGroup(i)) { (*translatedRemoves)[i].append( - QQmlChangeSet::Remove(remove.index[i], remove.count, remove.moveId)); + QQmlChangeSet::Change(remove.index[i], remove.count, remove.moveId)); removed[i] -= remove.count; } } @@ -1318,7 +1323,7 @@ void QQmlDelegateModelPrivate::itemsRemoved( void QQmlDelegateModelPrivate::itemsRemoved(const QVector<Compositor::Remove> &removes) { - QVarLengthArray<QVector<QQmlChangeSet::Remove>, Compositor::MaximumGroupCount> translatedRemoves(m_groupCount); + QVarLengthArray<QVector<QQmlChangeSet::Change>, Compositor::MaximumGroupCount> translatedRemoves(m_groupCount); itemsRemoved(removes, &translatedRemoves); Q_ASSERT(m_cache.count() == m_compositor.count(Compositor::Cache)); if (!m_delegate) @@ -1356,10 +1361,10 @@ void QQmlDelegateModelPrivate::itemsMoved( { QHash<int, QList<QQmlDelegateModelItem *> > movedItems; - QVarLengthArray<QVector<QQmlChangeSet::Remove>, Compositor::MaximumGroupCount> translatedRemoves(m_groupCount); + QVarLengthArray<QVector<QQmlChangeSet::Change>, Compositor::MaximumGroupCount> translatedRemoves(m_groupCount); itemsRemoved(removes, &translatedRemoves, &movedItems); - QVarLengthArray<QVector<QQmlChangeSet::Insert>, Compositor::MaximumGroupCount> translatedInserts(m_groupCount); + QVarLengthArray<QVector<QQmlChangeSet::Change>, Compositor::MaximumGroupCount> translatedInserts(m_groupCount); itemsInserted(inserts, &translatedInserts, &movedItems); Q_ASSERT(m_cache.count() == m_compositor.count(Compositor::Cache)); Q_ASSERT(movedItems.isEmpty()); @@ -1409,7 +1414,7 @@ void QQmlDelegateModelPrivate::emitModelUpdated(const QQmlChangeSet &changeSet, void QQmlDelegateModelPrivate::emitChanges() { - if (m_transaction || !m_complete || !m_context->isValid()) + if (m_transaction || !m_complete || !m_context || !m_context->isValid()) return; m_transaction = true; @@ -1594,7 +1599,7 @@ QQmlDelegateModelAttached *QQmlDelegateModel::qmlAttachedProperties(QObject *obj bool QQmlDelegateModelPrivate::insert(Compositor::insert_iterator &before, const QV4::ValueRef object, int groups) { - if (!m_context->isValid()) + if (!m_context || !m_context->isValid()) return false; QQmlDelegateModelItem *cacheItem = m_adaptorModel.createItem(m_cacheMetaType, m_context->engine(), -1); @@ -1687,43 +1692,44 @@ void QQmlDelegateModelItemMetaType::initializePrototype() QV4::ScopedProperty p(scope); s = v4->newString(QStringLiteral("isUnresolved")); - p->setGetter(new (v4->memoryManager) DelegateModelGroupFunction(v4->rootContext, 30, QQmlDelegateModelItem::get_member)); + QV4::ScopedFunctionObject f(scope); + p->setGetter((f = DelegateModelGroupFunction::create(v4->rootContext, 30, QQmlDelegateModelItem::get_member))); p->setSetter(0); - proto->insertMember(s, p, QV4::Attr_Accessor|QV4::Attr_NotConfigurable|QV4::Attr_NotEnumerable); + proto->insertMember(s.getPointer(), p, QV4::Attr_Accessor|QV4::Attr_NotConfigurable|QV4::Attr_NotEnumerable); s = v4->newString(QStringLiteral("inItems")); - p->setGetter(new (v4->memoryManager) DelegateModelGroupFunction(v4->rootContext, QQmlListCompositor::Default, QQmlDelegateModelItem::get_member)); - p->setSetter(new (v4->memoryManager) DelegateModelGroupFunction(v4->rootContext, QQmlListCompositor::Default, QQmlDelegateModelItem::set_member)); - proto->insertMember(s, p, QV4::Attr_Accessor|QV4::Attr_NotConfigurable|QV4::Attr_NotEnumerable); + p->setGetter((f = DelegateModelGroupFunction::create(v4->rootContext, QQmlListCompositor::Default, QQmlDelegateModelItem::get_member))); + p->setSetter((f = DelegateModelGroupFunction::create(v4->rootContext, QQmlListCompositor::Default, QQmlDelegateModelItem::set_member))); + proto->insertMember(s.getPointer(), p, QV4::Attr_Accessor|QV4::Attr_NotConfigurable|QV4::Attr_NotEnumerable); s = v4->newString(QStringLiteral("inPersistedItems")); - p->setGetter(new (v4->memoryManager) DelegateModelGroupFunction(v4->rootContext, QQmlListCompositor::Persisted, QQmlDelegateModelItem::get_member)); - p->setSetter(new (v4->memoryManager) DelegateModelGroupFunction(v4->rootContext, QQmlListCompositor::Persisted, QQmlDelegateModelItem::set_member)); - proto->insertMember(s, p, QV4::Attr_Accessor|QV4::Attr_NotConfigurable|QV4::Attr_NotEnumerable); + p->setGetter((f = DelegateModelGroupFunction::create(v4->rootContext, QQmlListCompositor::Persisted, QQmlDelegateModelItem::get_member))); + p->setSetter((f = DelegateModelGroupFunction::create(v4->rootContext, QQmlListCompositor::Persisted, QQmlDelegateModelItem::set_member))); + proto->insertMember(s.getPointer(), p, QV4::Attr_Accessor|QV4::Attr_NotConfigurable|QV4::Attr_NotEnumerable); s = v4->newString(QStringLiteral("itemsIndex")); - p->setGetter(new (v4->memoryManager) DelegateModelGroupFunction(v4->rootContext, QQmlListCompositor::Default, QQmlDelegateModelItem::get_index)); - proto->insertMember(s, p, QV4::Attr_Accessor|QV4::Attr_NotConfigurable|QV4::Attr_NotEnumerable); + p->setGetter((f = DelegateModelGroupFunction::create(v4->rootContext, QQmlListCompositor::Default, QQmlDelegateModelItem::get_index))); + proto->insertMember(s.getPointer(), p, QV4::Attr_Accessor|QV4::Attr_NotConfigurable|QV4::Attr_NotEnumerable); s = v4->newString(QStringLiteral("persistedItemsIndex")); - p->setGetter(new (v4->memoryManager) DelegateModelGroupFunction(v4->rootContext, QQmlListCompositor::Persisted, QQmlDelegateModelItem::get_index)); + p->setGetter((f = DelegateModelGroupFunction::create(v4->rootContext, QQmlListCompositor::Persisted, QQmlDelegateModelItem::get_index))); p->setSetter(0); - proto->insertMember(s, p, QV4::Attr_Accessor|QV4::Attr_NotConfigurable|QV4::Attr_NotEnumerable); + proto->insertMember(s.getPointer(), p, QV4::Attr_Accessor|QV4::Attr_NotConfigurable|QV4::Attr_NotEnumerable); for (int i = 2; i < groupNames.count(); ++i) { QString propertyName = QStringLiteral("in") + groupNames.at(i); propertyName.replace(2, 1, propertyName.at(2).toUpper()); s = v4->newString(propertyName); - p->setGetter(new (v4->memoryManager) DelegateModelGroupFunction(v4->rootContext, i + 1, QQmlDelegateModelItem::get_member)); - p->setSetter(new (v4->memoryManager) DelegateModelGroupFunction(v4->rootContext, i + 1, QQmlDelegateModelItem::set_member)); - proto->insertMember(s, p, QV4::Attr_Accessor|QV4::Attr_NotConfigurable|QV4::Attr_NotEnumerable); + p->setGetter((f = DelegateModelGroupFunction::create(v4->rootContext, i + 1, QQmlDelegateModelItem::get_member))); + p->setSetter((f = DelegateModelGroupFunction::create(v4->rootContext, i + 1, QQmlDelegateModelItem::set_member))); + proto->insertMember(s.getPointer(), p, QV4::Attr_Accessor|QV4::Attr_NotConfigurable|QV4::Attr_NotEnumerable); } for (int i = 2; i < groupNames.count(); ++i) { const QString propertyName = groupNames.at(i) + QStringLiteral("Index"); s = v4->newString(propertyName); - p->setGetter(new (v4->memoryManager) DelegateModelGroupFunction(v4->rootContext, i + 1, QQmlDelegateModelItem::get_index)); + p->setGetter((f = DelegateModelGroupFunction::create(v4->rootContext, i + 1, QQmlDelegateModelItem::get_index))); p->setSetter(0); - proto->insertMember(s, p, QV4::Attr_Accessor|QV4::Attr_NotConfigurable|QV4::Attr_NotEnumerable); + proto->insertMember(s.getPointer(), p, QV4::Attr_Accessor|QV4::Attr_NotConfigurable|QV4::Attr_NotEnumerable); } modelItemProto = proto; } @@ -1771,46 +1777,46 @@ int QQmlDelegateModelItemMetaType::parseGroups(const QV4::ValueRef groups) const QV4::ReturnedValue QQmlDelegateModelItem::get_model(QV4::CallContext *ctx) { QV4::Scope scope(ctx); - QV4::Scoped<QQmlDelegateModelItemObject> o(scope, ctx->callData->thisObject.as<QQmlDelegateModelItemObject>()); + QV4::Scoped<QQmlDelegateModelItemObject> o(scope, ctx->d()->callData->thisObject.as<QQmlDelegateModelItemObject>()); if (!o) return ctx->throwTypeError(QStringLiteral("Not a valid VisualData object")); - if (!o->item->metaType->model) + if (!o->d()->item->metaType->model) return QV4::Encode::undefined(); - return o->item->get(); + return o->d()->item->get(); } QV4::ReturnedValue QQmlDelegateModelItem::get_groups(QV4::CallContext *ctx) { QV4::Scope scope(ctx); - QV4::Scoped<QQmlDelegateModelItemObject> o(scope, ctx->callData->thisObject.as<QQmlDelegateModelItemObject>()); + QV4::Scoped<QQmlDelegateModelItemObject> o(scope, ctx->d()->callData->thisObject.as<QQmlDelegateModelItemObject>()); if (!o) return ctx->throwTypeError(QStringLiteral("Not a valid VisualData object")); QStringList groups; - for (int i = 1; i < o->item->metaType->groupCount; ++i) { - if (o->item->groups & (1 << i)) - groups.append(o->item->metaType->groupNames.at(i - 1)); + for (int i = 1; i < o->d()->item->metaType->groupCount; ++i) { + if (o->d()->item->groups & (1 << i)) + groups.append(o->d()->item->metaType->groupNames.at(i - 1)); } - return ctx->engine->v8Engine->fromVariant(groups); + return scope.engine->v8Engine->fromVariant(groups); } QV4::ReturnedValue QQmlDelegateModelItem::set_groups(QV4::CallContext *ctx) { QV4::Scope scope(ctx); - QV4::Scoped<QQmlDelegateModelItemObject> o(scope, ctx->callData->thisObject.as<QQmlDelegateModelItemObject>()); + QV4::Scoped<QQmlDelegateModelItemObject> o(scope, ctx->d()->callData->thisObject.as<QQmlDelegateModelItemObject>()); if (!o) return ctx->throwTypeError(QStringLiteral("Not a valid VisualData object")); - if (!ctx->callData->argc) + if (!ctx->d()->callData->argc) return ctx->throwTypeError(); - if (!o->item->metaType->model) + if (!o->d()->item->metaType->model) return QV4::Encode::undefined(); - QQmlDelegateModelPrivate *model = QQmlDelegateModelPrivate::get(o->item->metaType->model); + QQmlDelegateModelPrivate *model = QQmlDelegateModelPrivate::get(o->d()->item->metaType->model); - const int groupFlags = model->m_cacheMetaType->parseGroups(ctx->callData->args[0]); - const int cacheIndex = model->m_cache.indexOf(o->item); + const int groupFlags = model->m_cacheMetaType->parseGroups(ctx->d()->callData->args[0]); + const int cacheIndex = model->m_cache.indexOf(o->d()->item); Compositor::iterator it = model->m_compositor.find(Compositor::Cache, cacheIndex); model->setGroups(it, 1, Compositor::Cache, groupFlags); return QV4::Encode::undefined(); @@ -1852,14 +1858,14 @@ QV4::ReturnedValue QQmlDelegateModelItem::get_index(QQmlDelegateModelItem *thisI DEFINE_OBJECT_VTABLE(QQmlDelegateModelItemObject); -QQmlDelegateModelItemObject::~QQmlDelegateModelItemObject() +QQmlDelegateModelItemObject::Data::~Data() { item->Dispose(); } void QQmlDelegateModelItemObject::destroy(Managed *that) { - static_cast<QQmlDelegateModelItemObject *>(that)->~QQmlDelegateModelItemObject(); + static_cast<QQmlDelegateModelItemObject *>(that)->d()->~Data(); } @@ -2433,7 +2439,7 @@ QQmlV4Handle QQmlDelegateModelGroup::get(int index) return QQmlV4Handle(QV4::Encode::undefined()); QQmlDelegateModelPrivate *model = QQmlDelegateModelPrivate::get(d->model); - if (!model->m_context->isValid()) { + if (!model->m_context || !model->m_context->isValid()) { return QQmlV4Handle(QV4::Encode::undefined()); } else if (index < 0 || index >= model->m_compositor.count(d->group)) { qmlInfo(this) << tr("get: index out of range"); @@ -2461,7 +2467,7 @@ QQmlV4Handle QQmlDelegateModelGroup::get(int index) QV8Engine *v8 = model->m_cacheMetaType->v8Engine; QV4::ExecutionEngine *v4 = QV8Engine::getV4(v8); QV4::Scope scope(v4); - QV4::ScopedObject o(scope, new (v4->memoryManager) QQmlDelegateModelItemObject(v4, cacheItem)); + QV4::ScopedObject o(scope, v4->memoryManager->alloc<QQmlDelegateModelItemObject>(v4, cacheItem)); QV4::ScopedObject p(scope, model->m_cacheMetaType->modelItemProto.value()); o->setPrototype(p.getPointer()); ++cacheItem->scriptRef; @@ -2484,7 +2490,7 @@ bool QQmlDelegateModelGroupPrivate::parseIndex(const QV4::ValueRef value, int *i QV4::Scoped<QQmlDelegateModelItemObject> object(scope, value); if (object) { - QQmlDelegateModelItem * const cacheItem = object->item; + QQmlDelegateModelItem * const cacheItem = object->d()->item; if (QQmlDelegateModelPrivate *model = cacheItem->metaType->model ? QQmlDelegateModelPrivate::get(cacheItem->metaType->model) : 0) { @@ -3061,8 +3067,8 @@ void QQmlPartsModel::updateFilterGroup() QQmlDelegateModelGroupPrivate::get(model->m_groups[m_compositorGroup])->emitters.insert(this); if (m_compositorGroup != previousGroup) { - QVector<QQmlChangeSet::Remove> removes; - QVector<QQmlChangeSet::Insert> inserts; + QVector<QQmlChangeSet::Change> removes; + QVector<QQmlChangeSet::Change> inserts; model->m_compositor.transition(previousGroup, m_compositorGroup, &removes, &inserts); QQmlChangeSet changeSet; @@ -3203,59 +3209,70 @@ void QQmlPartsModel::emitModelUpdated(const QQmlChangeSet &changeSet, bool reset struct QQmlDelegateModelGroupChange : QV4::Object { - V4_OBJECT - QQmlDelegateModelGroupChange(QV4::ExecutionEngine *engine) - : Object(engine) - { - setVTable(staticVTable()); + struct Data : QV4::Object::Data { + Data(QV4::ExecutionEngine *engine) + : Object::Data(engine) + { + setVTable(staticVTable()); + } + QQmlChangeSet::Change change; + }; + V4_OBJECT(QV4::Object) + + static QQmlDelegateModelGroupChange *create(QV4::ExecutionEngine *e) { + return e->memoryManager->alloc<QQmlDelegateModelGroupChange>(e); } static QV4::ReturnedValue method_get_index(QV4::CallContext *ctx) { QV4::Scope scope(ctx); - QV4::Scoped<QQmlDelegateModelGroupChange> that(scope, ctx->callData->thisObject.as<QQmlDelegateModelGroupChange>()); + QV4::Scoped<QQmlDelegateModelGroupChange> that(scope, ctx->d()->callData->thisObject.as<QQmlDelegateModelGroupChange>()); if (!that) return ctx->throwTypeError(); - return QV4::Encode(that->change.index); + return QV4::Encode(that->d()->change.index); } static QV4::ReturnedValue method_get_count(QV4::CallContext *ctx) { QV4::Scope scope(ctx); - QV4::Scoped<QQmlDelegateModelGroupChange> that(scope, ctx->callData->thisObject.as<QQmlDelegateModelGroupChange>()); + QV4::Scoped<QQmlDelegateModelGroupChange> that(scope, ctx->d()->callData->thisObject.as<QQmlDelegateModelGroupChange>()); if (!that) return ctx->throwTypeError(); - return QV4::Encode(that->change.count); + return QV4::Encode(that->d()->change.count); } static QV4::ReturnedValue method_get_moveId(QV4::CallContext *ctx) { QV4::Scope scope(ctx); - QV4::Scoped<QQmlDelegateModelGroupChange> that(scope, ctx->callData->thisObject.as<QQmlDelegateModelGroupChange>()); + QV4::Scoped<QQmlDelegateModelGroupChange> that(scope, ctx->d()->callData->thisObject.as<QQmlDelegateModelGroupChange>()); if (!that) return ctx->throwTypeError(); - if (that->change.moveId < 0) + if (that->d()->change.moveId < 0) return QV4::Encode::undefined(); - return QV4::Encode(that->change.moveId); + return QV4::Encode(that->d()->change.moveId); } - - QQmlChangeSet::Change change; }; DEFINE_OBJECT_VTABLE(QQmlDelegateModelGroupChange); -class QQmlDelegateModelGroupChangeArray : public QV4::Object -{ - V4_OBJECT +struct QQmlDelegateModelGroupChangeArray : public QV4::Object +{ + struct Data : QV4::Object::Data { + Data(QV4::ExecutionEngine *engine, const QVector<QQmlChangeSet::Change> &changes) + : Object::Data(engine) + , changes(changes) + { + setVTable(staticVTable()); + QV4::Scope scope(engine); + QV4::ScopedObject o(scope, this); + o->setArrayType(QV4::ArrayData::Custom); + } + QVector<QQmlChangeSet::Change> changes; + }; + V4_OBJECT(QV4::Object) public: - QQmlDelegateModelGroupChangeArray(QV4::ExecutionEngine *engine) - : Object(engine) + static QQmlDelegateModelGroupChangeArray *create(QV4::ExecutionEngine *engine, const QVector<QQmlChangeSet::Change> &changes) { - setVTable(staticVTable()); - QV4::Scope scope(engine); - QV4::ScopedObject protectThis(scope, this); - Q_UNUSED(protectThis); - setArrayType(QV4::ArrayData::Custom); + return engine->memoryManager->alloc<QQmlDelegateModelGroupChangeArray>(engine, changes); } - virtual ~QQmlDelegateModelGroupChangeArray() {} - virtual quint32 count() const = 0; - virtual const QQmlChangeSet::Change &at(int index) const = 0; + quint32 count() const { return d()->changes.count(); } + const QQmlChangeSet::Change &at(int index) const { return d()->changes.at(index); } static QV4::ReturnedValue getIndexed(QV4::Managed *m, uint index, bool *hasProperty) { @@ -3274,16 +3291,16 @@ public: const QQmlChangeSet::Change &change = array->at(index); QV4::ScopedObject changeProto(scope, engineData(v4->v8Engine)->changeProto.value()); - QV4::Scoped<QQmlDelegateModelGroupChange> object(scope, new (v4->memoryManager) QQmlDelegateModelGroupChange(v4)); + QV4::Scoped<QQmlDelegateModelGroupChange> object(scope, QQmlDelegateModelGroupChange::create(v4)); object->setPrototype(changeProto.getPointer()); - object->change = change; + object->d()->change = change; if (hasProperty) *hasProperty = true; return object.asReturnedValue(); } - static QV4::ReturnedValue get(QV4::Managed *m, const QV4::StringRef name, bool *hasProperty) + static QV4::ReturnedValue get(QV4::Managed *m, QV4::String *name, bool *hasProperty) { QQmlDelegateModelGroupChangeArray *array = m->as<QQmlDelegateModelGroupChangeArray>(); if (!array) @@ -3299,46 +3316,13 @@ public: } static void destroy(Managed *that) { QQmlDelegateModelGroupChangeArray *array = that->as<QQmlDelegateModelGroupChangeArray>(); - assert(array); - array->~QQmlDelegateModelGroupChangeArray(); + array->d()->~Data(); } }; DEFINE_OBJECT_VTABLE(QQmlDelegateModelGroupChangeArray); -class QQmlDelegateModelGroupRemoveArray : public QQmlDelegateModelGroupChangeArray -{ -public: - QQmlDelegateModelGroupRemoveArray(QV4::ExecutionEngine *engine, const QVector<QQmlChangeSet::Remove> &changes) - : QQmlDelegateModelGroupChangeArray(engine) - , changes(changes) - { - } - - quint32 count() const { return changes.count(); } - const QQmlChangeSet::Change &at(int index) const { return changes.at(index); } - -private: - QVector<QQmlChangeSet::Remove> changes; -}; - -class QQmlDelegateModelGroupInsertArray : public QQmlDelegateModelGroupChangeArray -{ -public: - QQmlDelegateModelGroupInsertArray(QV4::ExecutionEngine *engine, const QVector<QQmlChangeSet::Insert> &changes) - : QQmlDelegateModelGroupChangeArray(engine) - , changes(changes) - { - } - - quint32 count() const { return changes.count(); } - const QQmlChangeSet::Change &at(int index) const { return changes.at(index); } - -private: - QVector<QQmlChangeSet::Insert> changes; -}; - QQmlDelegateModelEngineData::QQmlDelegateModelEngineData(QV8Engine *e) { QV4::ExecutionEngine *v4 = QV8Engine::getV4(e); @@ -3355,16 +3339,12 @@ QQmlDelegateModelEngineData::~QQmlDelegateModelEngineData() { } -QV4::ReturnedValue QQmlDelegateModelEngineData::array(QV8Engine *engine, const QVector<QQmlChangeSet::Remove> &changes) +QV4::ReturnedValue QQmlDelegateModelEngineData::array(QV8Engine *engine, const QVector<QQmlChangeSet::Change> &changes) { QV4::ExecutionEngine *v4 = QV8Engine::getV4(engine); - return (new (v4->memoryManager) QQmlDelegateModelGroupRemoveArray(v4, changes))->asReturnedValue(); -} - -QV4::ReturnedValue QQmlDelegateModelEngineData::array(QV8Engine *engine, const QVector<QQmlChangeSet::Insert> &changes) -{ - QV4::ExecutionEngine *v4 = QV8Engine::getV4(engine); - return (new (v4->memoryManager) QQmlDelegateModelGroupInsertArray(v4, changes))->asReturnedValue(); + QV4::Scope scope(v4); + QV4::ScopedObject o(scope, QQmlDelegateModelGroupChangeArray::create(v4, changes)); + return o.asReturnedValue(); } QT_END_NAMESPACE diff --git a/src/qml/types/qqmldelegatemodel_p_p.h b/src/qml/types/qqmldelegatemodel_p_p.h index d64f641a1b..7846992e5d 100644 --- a/src/qml/types/qqmldelegatemodel_p_p.h +++ b/src/qml/types/qqmldelegatemodel_p_p.h @@ -161,16 +161,19 @@ protected: struct QQmlDelegateModelItemObject : QV4::Object { - V4_OBJECT; - QQmlDelegateModelItemObject(QV4::ExecutionEngine *engine, QQmlDelegateModelItem *item) - : Object(engine) - , item(item) - { setVTable(staticVTable()); } - ~QQmlDelegateModelItemObject(); + struct Data : QV4::Object::Data { + Data(QV4::ExecutionEngine *engine, QQmlDelegateModelItem *item) + : Object::Data(engine) + , item(item) + { + setVTable(staticVTable()); + } + ~Data(); + QQmlDelegateModelItem *item; + }; + V4_OBJECT(QV4::Object) static void destroy(Managed *that); - - QQmlDelegateModelItem *item; }; @@ -275,12 +278,12 @@ public: void itemsInserted( const QVector<Compositor::Insert> &inserts, - QVarLengthArray<QVector<QQmlChangeSet::Insert>, Compositor::MaximumGroupCount> *translatedInserts, + QVarLengthArray<QVector<QQmlChangeSet::Change>, Compositor::MaximumGroupCount> *translatedInserts, QHash<int, QList<QQmlDelegateModelItem *> > *movedItems = 0); void itemsInserted(const QVector<Compositor::Insert> &inserts); void itemsRemoved( const QVector<Compositor::Remove> &removes, - QVarLengthArray<QVector<QQmlChangeSet::Remove>, Compositor::MaximumGroupCount> *translatedRemoves, + QVarLengthArray<QVector<QQmlChangeSet::Change>, Compositor::MaximumGroupCount> *translatedRemoves, QHash<int, QList<QQmlDelegateModelItem *> > *movedItems = 0); void itemsRemoved(const QVector<Compositor::Remove> &removes); void itemsMoved( @@ -303,7 +306,7 @@ public: QQmlListCompositor m_compositor; QQmlComponent *m_delegate; QQmlDelegateModelItemMetaType *m_cacheMetaType; - QQmlContext *m_context; + QPointer<QQmlContext> m_context; QQmlDelegateModelParts *m_parts; QQmlDelegateModelGroupEmitterList m_pendingParts; diff --git a/src/qml/types/qqmlinstantiator.cpp b/src/qml/types/qqmlinstantiator.cpp index 724a76825b..73e4ba851a 100644 --- a/src/qml/types/qqmlinstantiator.cpp +++ b/src/qml/types/qqmlinstantiator.cpp @@ -137,7 +137,7 @@ void QQmlInstantiatorPrivate::_q_modelUpdated(const QQmlChangeSet &changeSet, bo int difference = 0; QHash<int, QVector<QPointer<QObject> > > moved; - foreach (const QQmlChangeSet::Remove &remove, changeSet.removes()) { + foreach (const QQmlChangeSet::Change &remove, changeSet.removes()) { int index = qMin(remove.index, objects.count()); int count = qMin(remove.index + remove.count, objects.count()) - index; if (remove.isMove()) { @@ -156,7 +156,7 @@ void QQmlInstantiatorPrivate::_q_modelUpdated(const QQmlChangeSet &changeSet, bo difference -= remove.count; } - foreach (const QQmlChangeSet::Insert &insert, changeSet.inserts()) { + foreach (const QQmlChangeSet::Change &insert, changeSet.inserts()) { int index = qMin(insert.index, objects.count()); if (insert.isMove()) { QVector<QPointer<QObject> > movedObjects = moved.value(insert.moveId); diff --git a/src/qml/types/qqmllistmodel.cpp b/src/qml/types/qqmllistmodel.cpp index be49b6e5a0..46916656b6 100644 --- a/src/qml/types/qqmllistmodel.cpp +++ b/src/qml/types/qqmllistmodel.cpp @@ -44,7 +44,7 @@ #include <private/qqmlopenmetaobject_p.h> #include <private/qqmljsast_p.h> #include <private/qqmljsengine_p.h> - +#include <private/qqmlcompiler_p.h> #include <private/qqmlcustomparser_p.h> #include <private/qqmlengine_p.h> @@ -103,9 +103,9 @@ const ListLayout::Role &ListLayout::getRoleOrCreate(const QString &key, Role::Da return createRole(key, type); } -const ListLayout::Role &ListLayout::getRoleOrCreate(const QV4::StringRef key, Role::DataType type) +const ListLayout::Role &ListLayout::getRoleOrCreate(QV4::String *key, Role::DataType type) { - QStringHash<Role *>::Node *node = roleHash.findNode(key.getPointer()); + QStringHash<Role *>::Node *node = roleHash.findNode(key); if (node) { const Role &r = *node->value; if (type != r.type) @@ -239,10 +239,10 @@ const ListLayout::Role *ListLayout::getExistingRole(const QString &key) return r; } -const ListLayout::Role *ListLayout::getExistingRole(const QV4::StringRef key) +const ListLayout::Role *ListLayout::getExistingRole(QV4::String *key) { Role *r = 0; - QStringHash<Role *>::Node *node = roleHash.findNode(key.getPointer()); + QStringHash<Role *>::Node *node = roleHash.findNode(key); if (node) r = node->value; return r; @@ -409,7 +409,7 @@ ListModel *ListModel::getListProperty(int elementIndex, const ListLayout::Role & return e->getListProperty(role); } -void ListModel::set(int elementIndex, QV4::ObjectRef object, QVector<int> *roles, QV8Engine *eng) +void ListModel::set(int elementIndex, QV4::Object *object, QVector<int> *roles, QV8Engine *eng) { ListElement *e = elements[elementIndex]; @@ -432,13 +432,13 @@ void ListModel::set(int elementIndex, QV4::ObjectRef object, QVector<int> *roles // Add the value now if ((s = propertyValue)) { - const ListLayout::Role &r = m_layout->getRoleOrCreate(propertyName, ListLayout::Role::String); + const ListLayout::Role &r = m_layout->getRoleOrCreate(propertyName.getPointer(), ListLayout::Role::String); roleIndex = e->setStringProperty(r, s->toQString()); } else if (propertyValue->isNumber()) { - const ListLayout::Role &r = m_layout->getRoleOrCreate(propertyName, ListLayout::Role::Number); + const ListLayout::Role &r = m_layout->getRoleOrCreate(propertyName.getPointer(), ListLayout::Role::Number); roleIndex = e->setDoubleProperty(r, propertyValue->asDouble()); } else if ((a = propertyValue)) { - const ListLayout::Role &r = m_layout->getRoleOrCreate(propertyName, ListLayout::Role::List); + const ListLayout::Role &r = m_layout->getRoleOrCreate(propertyName.getPointer(), ListLayout::Role::List); ListModel *subModel = new ListModel(r.subLayout, 0, -1); int arrayLength = a->getLength(); @@ -449,16 +449,16 @@ void ListModel::set(int elementIndex, QV4::ObjectRef object, QVector<int> *roles roleIndex = e->setListProperty(r, subModel); } else if (propertyValue->isBoolean()) { - const ListLayout::Role &r = m_layout->getRoleOrCreate(propertyName, ListLayout::Role::Bool); + const ListLayout::Role &r = m_layout->getRoleOrCreate(propertyName.getPointer(), ListLayout::Role::Bool); roleIndex = e->setBoolProperty(r, propertyValue->booleanValue()); } else if (QV4::DateObject *dd = propertyValue->asDateObject()) { - const ListLayout::Role &r = m_layout->getRoleOrCreate(propertyName, ListLayout::Role::DateTime); + const ListLayout::Role &r = m_layout->getRoleOrCreate(propertyName.getPointer(), ListLayout::Role::DateTime); QDateTime dt = dd->toQDateTime(); roleIndex = e->setDateTimeProperty(r, dt); } else if (QV4::Object *o = propertyValue->asObject()) { if (QV4::QObjectWrapper *wrapper = o->as<QV4::QObjectWrapper>()) { QObject *o = wrapper->object(); - const ListLayout::Role &role = m_layout->getRoleOrCreate(propertyName, ListLayout::Role::QObject); + const ListLayout::Role &role = m_layout->getRoleOrCreate(propertyName.getPointer(), ListLayout::Role::QObject); if (role.type == ListLayout::Role::QObject) roleIndex = e->setQObjectProperty(role, o); } else { @@ -483,7 +483,7 @@ void ListModel::set(int elementIndex, QV4::ObjectRef object, QVector<int> *roles } } -void ListModel::set(int elementIndex, QV4::ObjectRef object, QV8Engine *eng) +void ListModel::set(int elementIndex, QV4::Object *object, QV8Engine *eng) { if (!object) return; @@ -580,13 +580,13 @@ void ListModel::remove(int index, int count) updateCacheIndices(); } -void ListModel::insert(int elementIndex, QV4::ObjectRef object, QV8Engine *eng) +void ListModel::insert(int elementIndex, QV4::Object *object, QV8Engine *eng) { insertElement(elementIndex); set(elementIndex, object, eng); } -int ListModel::append(QV4::ObjectRef object, QV8Engine *eng) +int ListModel::append(QV4::Object *object, QV8Engine *eng) { int elementIndex = appendElement(); set(elementIndex, object, eng); @@ -883,7 +883,7 @@ int ListElement::setQObjectProperty(const ListLayout::Role &role, QObject *o) return roleIndex; } -int ListElement::setVariantMapProperty(const ListLayout::Role &role, QV4::ObjectRef o, QV8Engine *eng) +int ListElement::setVariantMapProperty(const ListLayout::Role &role, QV4::Object *o, QV8Engine *eng) { int roleIndex = -1; @@ -970,7 +970,7 @@ void ListElement::setListPropertyFast(const ListLayout::Role &role, ListModel *m *value = m; } -void ListElement::setVariantMapFast(const ListLayout::Role &role, QV4::ObjectRef o, QV8Engine *eng) +void ListElement::setVariantMapFast(const ListLayout::Role &role, QV4::Object *o, QV8Engine *eng) { char *mem = getPropertyMemory(role); QVariantMap *map = new (mem) QVariantMap; @@ -1430,11 +1430,6 @@ void DynamicRoleModelNodeMetaObject::propertyWritten(int index) } } -QQmlListModelParser::ListInstruction *QQmlListModelParser::ListModelData::instructions() const -{ - return (QQmlListModelParser::ListInstruction *)((char *)this + sizeof(ListModelData)); -} - /*! \qmltype ListModel \instantiates QQmlListModel @@ -2290,7 +2285,7 @@ void QQmlListModel::sync() qmlInfo(this) << "List sync() can only be called from a WorkerScript"; } -bool QQmlListModelParser::compileProperty(const QV4::CompiledData::QmlUnit *qmlUnit, const QV4::CompiledData::Binding *binding, QList<QQmlListModelParser::ListInstruction> &instr, QByteArray &data) +bool QQmlListModelParser::verifyProperty(const QV4::CompiledData::QmlUnit *qmlUnit, const QV4::CompiledData::Binding *binding) { if (binding->type >= QV4::CompiledData::Binding::Type_Object) { const quint32 targetObjectIndex = binding->value.objectIndex; @@ -2305,13 +2300,6 @@ bool QQmlListModelParser::compileProperty(const QV4::CompiledData::QmlUnit *qmlU listElementTypeName = objName; // cache right name for next time } - { - ListInstruction li; - li.type = ListInstruction::Push; - li.dataIdx = -1; - instr << li; - } - if (!qmlUnit->header.stringAt(target->idIndex).isEmpty()) { error(target->locationOfIdProperty, QQmlListModel::tr("ListElement: cannot use reserved \"id\" property")); return false; @@ -2324,208 +2312,116 @@ bool QQmlListModelParser::compileProperty(const QV4::CompiledData::QmlUnit *qmlU error(binding, QQmlListModel::tr("ListElement: cannot contain nested elements")); return false; } - ListInstruction li; - int ref = data.count(); - data.append(propName.toUtf8()); - data.append('\0'); - li.type = ListInstruction::Set; - li.dataIdx = ref; - instr << li; - - if (!compileProperty(qmlUnit, binding, instr, data)) + if (!verifyProperty(qmlUnit, binding)) + return false; + } + } else if (binding->type == QV4::CompiledData::Binding::Type_Script) { + QString scriptStr = binding->valueAsScriptString(&qmlUnit->header); + if (!definesEmptyList(scriptStr)) { + QByteArray script = scriptStr.toUtf8(); + bool ok; + evaluateEnum(script, &ok); + if (!ok) { + error(binding, QQmlListModel::tr("ListElement: cannot use script for property value")); return false; + } + } + } - li.type = ListInstruction::Pop; - li.dataIdx = -1; - instr << li; + return true; +} + +bool QQmlListModelParser::applyProperty(const QV4::CompiledData::QmlUnit *qmlUnit, const QV4::CompiledData::Binding *binding, ListModel *model, int outterElementIndex) +{ + const QString elementName = qmlUnit->header.stringAt(binding->propertyNameIndex); + + bool roleSet = false; + if (binding->type >= QV4::CompiledData::Binding::Type_Object) { + const quint32 targetObjectIndex = binding->value.objectIndex; + const QV4::CompiledData::Object *target = qmlUnit->objectAt(targetObjectIndex); + + ListModel *subModel = 0; + if (outterElementIndex == -1) { + subModel = model; + } else { + const ListLayout::Role &role = model->getOrCreateListRole(elementName); + if (role.type == ListLayout::Role::List) { + subModel = model->getListProperty(outterElementIndex, role); + if (subModel == 0) { + subModel = new ListModel(role.subLayout, 0, -1); + QVariant vModel = QVariant::fromValue(subModel); + model->setOrCreateProperty(outterElementIndex, elementName, vModel); + } + } } - { - ListInstruction li; - li.type = ListInstruction::Pop; - li.dataIdx = -1; - instr << li; + int elementIndex = subModel ? subModel->appendElement() : -1; + + const QV4::CompiledData::Binding *subBinding = target->bindingTable(); + for (quint32 i = 0; i < target->nBindings; ++i, ++subBinding) { + roleSet |= applyProperty(qmlUnit, subBinding, subModel, elementIndex); } } else { - int ref = data.count(); + QVariant value; - QByteArray d; - - if (binding->type == QV4::CompiledData::Binding::Type_String) { - d += char(String); - d += binding->valueAsString(&qmlUnit->header).toUtf8(); + if (binding->evaluatesToString()) { + value = binding->valueAsString(&qmlUnit->header); } else if (binding->type == QV4::CompiledData::Binding::Type_Number) { - d += char(Number); - d += QByteArray::number(binding->valueAsNumber(),'g',20); + value = binding->valueAsNumber(); } else if (binding->type == QV4::CompiledData::Binding::Type_Boolean) { - d += char(Boolean); - d += char(binding->valueAsBoolean()); - } else if (binding->type == QV4::CompiledData::Binding::Type_Translation - || binding->type == QV4::CompiledData::Binding::Type_TranslationById) { - error(binding, QQmlListModel::tr("ListElement: cannot use script for property value")); - return false; + value = binding->valueAsBoolean(); } else if (binding->type == QV4::CompiledData::Binding::Type_Script) { QString scriptStr = binding->valueAsScriptString(&qmlUnit->header); if (definesEmptyList(scriptStr)) { - d[0] = char(Invalid); // marks empty list + const ListLayout::Role &role = model->getOrCreateListRole(elementName); + ListModel *emptyModel = new ListModel(role.subLayout, 0, -1); + value = QVariant::fromValue(emptyModel); } else { QByteArray script = scriptStr.toUtf8(); bool ok; - int v = evaluateEnum(script, &ok); - if (!ok) { - error(binding, QQmlListModel::tr("ListElement: cannot use script for property value")); - return false; - } else { - d[0] = char(Number); - d += QByteArray::number(v); - } + value = evaluateEnum(script, &ok); } } else { Q_UNREACHABLE(); } - d.append('\0'); - data.append(d); - - ListInstruction li; - li.type = ListInstruction::Value; - li.dataIdx = ref; - instr << li; + model->setOrCreateProperty(outterElementIndex, elementName, value); + roleSet = true; } - - return true; + return roleSet; } -QByteArray QQmlListModelParser::compile(const QV4::CompiledData::QmlUnit *qmlUnit, const QList<const QV4::CompiledData::Binding *> &bindings) +void QQmlListModelParser::verifyBindings(const QV4::CompiledData::QmlUnit *qmlUnit, const QList<const QV4::CompiledData::Binding *> &bindings) { - QList<ListInstruction> instr; - QByteArray data; listElementTypeName = QString(); // unknown foreach (const QV4::CompiledData::Binding *binding, bindings) { QString propName = qmlUnit->header.stringAt(binding->propertyNameIndex); if (!propName.isEmpty()) { // isn't default property error(binding, QQmlListModel::tr("ListModel: undefined property '%1'").arg(propName)); - return QByteArray(); + return; } - if (!compileProperty(qmlUnit, binding, instr, data)) - return QByteArray(); + if (!verifyProperty(qmlUnit, binding)) + return; } - - int size = sizeof(ListModelData) + - instr.count() * sizeof(ListInstruction) + - data.count(); - - QByteArray rv; - rv.resize(size); - - ListModelData *lmd = (ListModelData *)rv.data(); - lmd->dataOffset = sizeof(ListModelData) + - instr.count() * sizeof(ListInstruction); - lmd->instrCount = instr.count(); - for (int ii = 0; ii < instr.count(); ++ii) - lmd->instructions()[ii] = instr.at(ii); - ::memcpy(rv.data() + lmd->dataOffset, data.constData(), data.count()); - - return rv; } -void QQmlListModelParser::setCustomData(QObject *obj, const QByteArray &d, QQmlCompiledData *) +void QQmlListModelParser::applyBindings(QObject *obj, QQmlCompiledData *cdata, const QList<const QV4::CompiledData::Binding *> &bindings) { QQmlListModel *rv = static_cast<QQmlListModel *>(obj); QV8Engine *engine = QQmlEnginePrivate::getV8Engine(qmlEngine(rv)); rv->m_engine = engine; - const ListModelData *lmd = (const ListModelData *)d.constData(); - const char *data = ((const char *)lmd) + lmd->dataOffset; + const QV4::CompiledData::QmlUnit *qmlUnit = cdata->qmlUnit; bool setRoles = false; - QStack<DataStackElement> stack; - - for (int ii = 0; ii < lmd->instrCount; ++ii) { - const ListInstruction &instr = lmd->instructions()[ii]; - - switch(instr.type) { - case ListInstruction::Push: - { - Q_ASSERT(!rv->m_dynamicRoles); - - ListModel *subModel = 0; - - if (stack.count() == 0) { - subModel = rv->m_listModel; - } else { - const DataStackElement &e0 = stack.at(stack.size() - 1); - DataStackElement &e1 = stack[stack.size() - 2]; - - const ListLayout::Role &role = e1.model->getOrCreateListRole(e0.name); - if (role.type == ListLayout::Role::List) { - subModel = e1.model->getListProperty(e1.elementIndex, role); - - if (subModel == 0) { - subModel = new ListModel(role.subLayout, 0, -1); - QVariant vModel = QVariant::fromValue(subModel); - e1.model->setOrCreateProperty(e1.elementIndex, e0.name, vModel); - } - } - } - - DataStackElement e; - e.model = subModel; - e.elementIndex = subModel ? subModel->appendElement() : -1; - stack.push(e); - } - break; - - case ListInstruction::Pop: - stack.pop(); - break; - - case ListInstruction::Value: - { - const DataStackElement &e0 = stack.at(stack.size() - 1); - DataStackElement &e1 = stack[stack.size() - 2]; - - QString name = e0.name; - QVariant value; - - switch (PropertyType(data[instr.dataIdx])) { - case Invalid: - { - const ListLayout::Role &role = e1.model->getOrCreateListRole(e0.name); - ListModel *emptyModel = new ListModel(role.subLayout, 0, -1); - value = QVariant::fromValue(emptyModel); - } - break; - case Boolean: - value = bool(data[1 + instr.dataIdx]); - break; - case Number: - value = QByteArray(data + 1 + instr.dataIdx).toDouble(); - break; - case String: - value = QString::fromUtf8(data + 1 + instr.dataIdx); - break; - default: - Q_ASSERT("Format error in ListInstruction"); - } - - e1.model->setOrCreateProperty(e1.elementIndex, name, value); - setRoles = true; - } - break; - - case ListInstruction::Set: - { - DataStackElement e; - e.name = QString::fromUtf8(data + instr.dataIdx); - stack.push(e); - } - break; - } + foreach (const QV4::CompiledData::Binding *binding, bindings) { + if (binding->type != QV4::CompiledData::Binding::Type_Object) + continue; + setRoles |= applyProperty(qmlUnit, binding, rv->m_listModel, /*outter element index*/-1); } if (setRoles == false) diff --git a/src/qml/types/qqmllistmodel_p.h b/src/qml/types/qqmllistmodel_p.h index 3d84e14698..8c12173425 100644 --- a/src/qml/types/qqmllistmodel_p.h +++ b/src/qml/types/qqmllistmodel_p.h @@ -171,41 +171,20 @@ public: QQmlListModelParser() : QQmlCustomParser(QQmlCustomParser::AcceptsSignalHandlers) {} - QByteArray compile(const QV4::CompiledData::QmlUnit *qmlUnit, const QList<const QV4::CompiledData::Binding *> &bindings); - void setCustomData(QObject *, const QByteArray &, QQmlCompiledData *); + + virtual void verifyBindings(const QV4::CompiledData::QmlUnit *qmlUnit, const QList<const QV4::CompiledData::Binding *> &bindings); + virtual void applyBindings(QObject *obj, QQmlCompiledData *cdata, const QList<const QV4::CompiledData::Binding *> &bindings); private: - struct ListInstruction - { - enum { Push, Pop, Value, Set } type; - int dataIdx; - }; - struct ListModelData - { - int dataOffset; - int instrCount; - ListInstruction *instructions() const; - }; - bool compileProperty(const QV4::CompiledData::QmlUnit *qmlUnit, const QV4::CompiledData::Binding *binding, QList<ListInstruction> &instr, QByteArray &data); + bool verifyProperty(const QV4::CompiledData::QmlUnit *qmlUnit, const QV4::CompiledData::Binding *binding); + // returns true if a role was set + bool applyProperty(const QV4::CompiledData::QmlUnit *qmlUnit, const QV4::CompiledData::Binding *binding, ListModel *model, int outterElementIndex); bool definesEmptyList(const QString &); QString listElementTypeName; - - struct DataStackElement - { - DataStackElement() : model(0), elementIndex(0) {} - - QString name; - ListModel *model; - int elementIndex; - }; - - friend class QTypeInfo<QQmlListModelParser::ListInstruction>; }; -Q_DECLARE_TYPEINFO(QQmlListModelParser::ListInstruction, Q_PRIMITIVE_TYPE); - QT_END_NAMESPACE QML_DECLARE_TYPE(QQmlListModel) diff --git a/src/qml/types/qqmllistmodel_p_p.h b/src/qml/types/qqmllistmodel_p_p.h index 924d89c52d..a27b8026d7 100644 --- a/src/qml/types/qqmllistmodel_p_p.h +++ b/src/qml/types/qqmllistmodel_p_p.h @@ -209,12 +209,12 @@ public: }; const Role *getRoleOrCreate(const QString &key, const QVariant &data); - const Role &getRoleOrCreate(const QV4::StringRef key, Role::DataType type); + const Role &getRoleOrCreate(QV4::String *key, Role::DataType type); const Role &getRoleOrCreate(const QString &key, Role::DataType type); const Role &getExistingRole(int index) { return *roles.at(index); } const Role *getExistingRole(const QString &key); - const Role *getExistingRole(const QV4::StringRef key); + const Role *getExistingRole(QV4::String *key); int roleCount() const { return roles.count(); } @@ -260,7 +260,7 @@ private: int setBoolProperty(const ListLayout::Role &role, bool b); int setListProperty(const ListLayout::Role &role, ListModel *m); int setQObjectProperty(const ListLayout::Role &role, QObject *o); - int setVariantMapProperty(const ListLayout::Role &role, QV4::ObjectRef o, QV8Engine *eng); + int setVariantMapProperty(const ListLayout::Role &role, QV4::Object *o, QV8Engine *eng); int setVariantMapProperty(const ListLayout::Role &role, QVariantMap *m); int setDateTimeProperty(const ListLayout::Role &role, const QDateTime &dt); @@ -269,7 +269,7 @@ private: void setBoolPropertyFast(const ListLayout::Role &role, bool b); void setQObjectPropertyFast(const ListLayout::Role &role, QObject *o); void setListPropertyFast(const ListLayout::Role &role, ListModel *m); - void setVariantMapFast(const ListLayout::Role &role, QV4::ObjectRef o, QV8Engine *eng); + void setVariantMapFast(const ListLayout::Role &role, QV4::Object *o, QV8Engine *eng); void setDateTimePropertyFast(const ListLayout::Role &role, const QDateTime &dt); void clearProperty(const ListLayout::Role &role); @@ -333,11 +333,11 @@ public: return elements.count(); } - void set(int elementIndex, QV4::ObjectRef object, QVector<int> *roles, QV8Engine *eng); - void set(int elementIndex, QV4::ObjectRef object, QV8Engine *eng); + void set(int elementIndex, QV4::Object *object, QVector<int> *roles, QV8Engine *eng); + void set(int elementIndex, QV4::Object *object, QV8Engine *eng); - int append(QV4::ObjectRef object, QV8Engine *eng); - void insert(int elementIndex, QV4::ObjectRef object, QV8Engine *eng); + int append(QV4::Object *object, QV8Engine *eng); + void insert(int elementIndex, QV4::Object *object, QV8Engine *eng); void clear(); void remove(int index, int count); diff --git a/src/qml/types/qquickworkerscript.cpp b/src/qml/types/qquickworkerscript.cpp index 4e842c5133..a9f748cde1 100644 --- a/src/qml/types/qquickworkerscript.cpp +++ b/src/qml/types/qquickworkerscript.cpp @@ -235,7 +235,7 @@ void QQuickWorkerScriptEnginePrivate::WorkerEngine::init() QV4::Scoped<QV4::FunctionObject> createsendconstructor(scope, createsendscript.run()); Q_ASSERT(!scope.engine->hasException); QV4::ScopedString name(scope, m_v4Engine->newString(QStringLiteral("sendMessage"))); - QV4::ScopedValue function(scope, m_v4Engine->newBuiltinFunction(m_v4Engine->rootContext, name, + QV4::ScopedValue function(scope, QV4::BuiltinFunction::create(m_v4Engine->rootContext, name.getPointer(), QQuickWorkerScriptEnginePrivate::method_sendMessage)); QV4::ScopedCallData callData(scope, 1); callData->args[0] = function; @@ -283,12 +283,12 @@ QQuickWorkerScriptEnginePrivate::QQuickWorkerScriptEnginePrivate(QQmlEngine *eng QV4::ReturnedValue QQuickWorkerScriptEnginePrivate::method_sendMessage(QV4::CallContext *ctx) { - WorkerEngine *engine = (WorkerEngine*)ctx->engine->v8Engine; + WorkerEngine *engine = (WorkerEngine*)ctx->engine()->v8Engine; - int id = ctx->callData->argc > 1 ? ctx->callData->args[1].toInt32() : 0; + int id = ctx->d()->callData->argc > 1 ? ctx->d()->callData->args[1].toInt32() : 0; QV4::Scope scope(ctx); - QV4::ScopedValue v(scope, ctx->callData->argument(2)); + QV4::ScopedValue v(scope, ctx->d()->callData->argument(2)); QByteArray data = QV4::Serialize::serialize(v, engine); QMutexLocker locker(&engine->p->m_lock); @@ -315,9 +315,9 @@ QV4::ReturnedValue QQuickWorkerScriptEnginePrivate::getWorker(WorkerScript *scri w->setReadOnly(false); QV4::Scoped<QV4::Object> api(scope, v4->newObject()); - api->put(QV4::ScopedString(scope, v4->newString(QStringLiteral("sendMessage"))), QV4::ScopedValue(scope, workerEngine->sendFunction(script->id))); + api->put(QV4::ScopedString(scope, v4->newString(QStringLiteral("sendMessage"))).getPointer(), QV4::ScopedValue(scope, workerEngine->sendFunction(script->id))); - w->QV4::Object::put(QV4::ScopedString(scope, v4->newString(QStringLiteral("WorkerScript"))), api); + w->QV4::Object::put(QV4::ScopedString(scope, v4->newString(QStringLiteral("WorkerScript"))).getPointer(), api); w->setReadOnly(true); } diff --git a/src/qml/util/qqmladaptormodel.cpp b/src/qml/util/qqmladaptormodel.cpp index c1c8bfa81d..6349c6fa31 100644 --- a/src/qml/util/qqmladaptormodel.cpp +++ b/src/qml/util/qqmladaptormodel.cpp @@ -66,11 +66,11 @@ V8_DEFINE_EXTENSION(QQmlAdaptorModelEngineData, engineData) static QV4::ReturnedValue get_index(QV4::CallContext *ctx) { QV4::Scope scope(ctx); - QV4::Scoped<QQmlDelegateModelItemObject> o(scope, ctx->callData->thisObject.as<QQmlDelegateModelItemObject>()); + QV4::Scoped<QQmlDelegateModelItemObject> o(scope, ctx->d()->callData->thisObject.as<QQmlDelegateModelItemObject>()); if (!o) return ctx->throwTypeError(QStringLiteral("Not a valid VisualData object")); - return QV4::Encode(o->item->index); + return QV4::Encode(o->d()->item->index); } template <typename T, typename M> static void setModelDataType(QMetaObjectBuilder *builder, M *metaType) @@ -198,14 +198,14 @@ public: static QV4::ReturnedValue get_hasModelChildren(QV4::CallContext *ctx) { QV4::Scope scope(ctx); - QV4::Scoped<QQmlDelegateModelItemObject> o(scope, ctx->callData->thisObject.as<QQmlDelegateModelItemObject>()); + QV4::Scoped<QQmlDelegateModelItemObject> o(scope, ctx->d()->callData->thisObject.as<QQmlDelegateModelItemObject>()); if (!o) return ctx->throwTypeError(QStringLiteral("Not a valid VisualData object")); - const QQmlAdaptorModel *const model = static_cast<QQmlDMCachedModelData *>(o->item)->type->model; - if (o->item->index >= 0 && *model) { + const QQmlAdaptorModel *const model = static_cast<QQmlDMCachedModelData *>(o->d()->item)->type->model; + if (o->d()->item->index >= 0 && *model) { const QAbstractItemModel * const aim = model->aim(); - return QV4::Encode(aim->hasChildren(aim->index(o->item->index, 0, model->rootIndex))); + return QV4::Encode(aim->hasChildren(aim->index(o->d()->item->index, 0, model->rootIndex))); } else { return QV4::Encode(false); } @@ -227,9 +227,11 @@ public: const QByteArray &propertyName = it.key(); QV4::ScopedString name(scope, v4->newString(QString::fromUtf8(propertyName))); - p->setGetter(new (v4->memoryManager) QV4::IndexedBuiltinFunction(v4->rootContext, propertyId, QQmlDMCachedModelData::get_property)); - p->setSetter(new (v4->memoryManager) QV4::IndexedBuiltinFunction(v4->rootContext, propertyId, QQmlDMCachedModelData::set_property)); - proto->insertMember(name, p, QV4::Attr_Accessor|QV4::Attr_NotEnumerable|QV4::Attr_NotConfigurable); + QV4::ScopedFunctionObject g(scope, v4->memoryManager->alloc<QV4::IndexedBuiltinFunction>(v4->rootContext, propertyId, QQmlDMCachedModelData::get_property)); + QV4::ScopedFunctionObject s(scope, v4->memoryManager->alloc<QV4::IndexedBuiltinFunction>(v4->rootContext, propertyId, QQmlDMCachedModelData::set_property)); + p->setGetter(g); + p->setSetter(s); + proto->insertMember(name.getPointer(), p, QV4::Attr_Accessor|QV4::Attr_NotEnumerable|QV4::Attr_NotConfigurable); } prototype = proto; } @@ -343,18 +345,18 @@ bool QQmlDMCachedModelData::resolveIndex(const QQmlAdaptorModel &, int idx) QV4::ReturnedValue QQmlDMCachedModelData::get_property(QV4::CallContext *ctx, uint propertyId) { QV4::Scope scope(ctx); - QV4::Scoped<QQmlDelegateModelItemObject> o(scope, ctx->callData->thisObject.as<QQmlDelegateModelItemObject>()); + QV4::Scoped<QQmlDelegateModelItemObject> o(scope, ctx->d()->callData->thisObject.as<QQmlDelegateModelItemObject>()); if (!o) return ctx->throwTypeError(QStringLiteral("Not a valid VisualData object")); - QQmlDMCachedModelData *modelData = static_cast<QQmlDMCachedModelData *>(o->item); - if (o->item->index == -1) { + QQmlDMCachedModelData *modelData = static_cast<QQmlDMCachedModelData *>(o->d()->item); + if (o->d()->item->index == -1) { if (!modelData->cachedData.isEmpty()) { - return ctx->engine->v8Engine->fromVariant( + return ctx->d()->engine->v8Engine->fromVariant( modelData->cachedData.at(modelData->type->hasModelData ? 0 : propertyId)); } } else if (*modelData->type->model) { - return ctx->engine->v8Engine->fromVariant( + return ctx->d()->engine->v8Engine->fromVariant( modelData->value(modelData->type->propertyRoles.at(propertyId))); } return QV4::Encode::undefined(); @@ -363,22 +365,22 @@ QV4::ReturnedValue QQmlDMCachedModelData::get_property(QV4::CallContext *ctx, ui QV4::ReturnedValue QQmlDMCachedModelData::set_property(QV4::CallContext *ctx, uint propertyId) { QV4::Scope scope(ctx); - QV4::Scoped<QQmlDelegateModelItemObject> o(scope, ctx->callData->thisObject.as<QQmlDelegateModelItemObject>()); + QV4::Scoped<QQmlDelegateModelItemObject> o(scope, ctx->d()->callData->thisObject.as<QQmlDelegateModelItemObject>()); if (!o) return ctx->throwTypeError(QStringLiteral("Not a valid VisualData object")); - if (!ctx->callData->argc) + if (!ctx->d()->callData->argc) return ctx->throwTypeError(); - if (o->item->index == -1) { - QQmlDMCachedModelData *modelData = static_cast<QQmlDMCachedModelData *>(o->item); + if (o->d()->item->index == -1) { + QQmlDMCachedModelData *modelData = static_cast<QQmlDMCachedModelData *>(o->d()->item); if (!modelData->cachedData.isEmpty()) { if (modelData->cachedData.count() > 1) { - modelData->cachedData[propertyId] = ctx->engine->v8Engine->toVariant(ctx->callData->args[0], QVariant::Invalid); - QMetaObject::activate(o->item, o->item->metaObject(), propertyId, 0); + modelData->cachedData[propertyId] = scope.engine->v8Engine->toVariant(ctx->d()->callData->args[0], QVariant::Invalid); + QMetaObject::activate(o->d()->item, o->d()->item->metaObject(), propertyId, 0); } else if (modelData->cachedData.count() == 1) { - modelData->cachedData[0] = ctx->engine->v8Engine->toVariant(ctx->callData->args[0], QVariant::Invalid); - QMetaObject::activate(o->item, o->item->metaObject(), 0, 0); - QMetaObject::activate(o->item, o->item->metaObject(), 1, 0); + modelData->cachedData[0] = scope.engine->v8Engine->toVariant(ctx->d()->callData->args[0], QVariant::Invalid); + QMetaObject::activate(o->d()->item, o->d()->item->metaObject(), 0, 0); + QMetaObject::activate(o->d()->item, o->d()->item->metaObject(), 1, 0); } } } @@ -431,7 +433,7 @@ public: } QV4::Scope scope(v4); QV4::ScopedObject proto(scope, type->prototype.value()); - QV4::ScopedObject o(scope, new (proto->engine()->memoryManager) QQmlDelegateModelItemObject(proto->engine(), this)); + QV4::ScopedObject o(scope, proto->engine()->memoryManager->alloc<QQmlDelegateModelItemObject>(proto->engine(), this)); o->setPrototype(proto.getPointer()); ++scriptRef; return o.asReturnedValue(); @@ -585,23 +587,23 @@ public: static QV4::ReturnedValue get_modelData(QV4::CallContext *ctx) { QV4::Scope scope(ctx); - QV4::Scoped<QQmlDelegateModelItemObject> o(scope, ctx->callData->thisObject.as<QQmlDelegateModelItemObject>()); + QV4::Scoped<QQmlDelegateModelItemObject> o(scope, ctx->d()->callData->thisObject.as<QQmlDelegateModelItemObject>()); if (!o) return ctx->throwTypeError(QStringLiteral("Not a valid VisualData object")); - return ctx->engine->v8Engine->fromVariant(static_cast<QQmlDMListAccessorData *>(o->item)->cachedData); + return scope.engine->v8Engine->fromVariant(static_cast<QQmlDMListAccessorData *>(o->d()->item)->cachedData); } static QV4::ReturnedValue set_modelData(QV4::CallContext *ctx) { QV4::Scope scope(ctx); - QV4::Scoped<QQmlDelegateModelItemObject> o(scope, ctx->callData->thisObject.as<QQmlDelegateModelItemObject>()); + QV4::Scoped<QQmlDelegateModelItemObject> o(scope, ctx->d()->callData->thisObject.as<QQmlDelegateModelItemObject>()); if (!o) return ctx->throwTypeError(QStringLiteral("Not a valid VisualData object")); - if (!ctx->callData->argc) + if (!ctx->d()->callData->argc) return ctx->throwTypeError(); - static_cast<QQmlDMListAccessorData *>(o->item)->setModelData(ctx->engine->v8Engine->toVariant(ctx->callData->args[0], QVariant::Invalid)); + static_cast<QQmlDMListAccessorData *>(o->d()->item)->setModelData(scope.engine->v8Engine->toVariant(ctx->d()->callData->args[0], QVariant::Invalid)); return QV4::Encode::undefined(); } @@ -609,7 +611,7 @@ public: { QQmlAdaptorModelEngineData *data = engineData(v4->v8Engine); QV4::Scope scope(v4); - QV4::ScopedObject o(scope, new (v4->memoryManager) QQmlDelegateModelItemObject(v4, this)); + QV4::ScopedObject o(scope, v4->memoryManager->alloc<QQmlDelegateModelItemObject>(v4, this)); QV4::ScopedObject p(scope, data->listItemProto.value()); o->setPrototype(p.getPointer()); ++scriptRef; diff --git a/src/qml/util/qqmlchangeset.cpp b/src/qml/util/qqmlchangeset.cpp index 831cb063a5..4e5e619d39 100644 --- a/src/qml/util/qqmlchangeset.cpp +++ b/src/qml/util/qqmlchangeset.cpp @@ -111,7 +111,7 @@ QQmlChangeSet &QQmlChangeSet::operator =(const QQmlChangeSet &changeSet) void QQmlChangeSet::insert(int index, int count) { - insert(QVector<Insert>() << Insert(index, count)); + insert(QVector<Change>() << Change(index, count)); } /*! @@ -120,8 +120,8 @@ void QQmlChangeSet::insert(int index, int count) void QQmlChangeSet::remove(int index, int count) { - QVector<Remove> removes; - removes.append(Remove(index, count)); + QVector<Change> removes; + removes.append(Change(index, count)); remove(&removes, 0); } @@ -134,10 +134,10 @@ void QQmlChangeSet::remove(int index, int count) void QQmlChangeSet::move(int from, int to, int count, int moveId) { - QVector<Remove> removes; - removes.append(Remove(from, count, moveId)); - QVector<Insert> inserts; - inserts.append(Insert(to, count, moveId)); + QVector<Change> removes; + removes.append(Change(from, count, moveId)); + QVector<Change> inserts; + inserts.append(Change(to, count, moveId)); remove(&removes, &inserts); insert(inserts); } @@ -159,8 +159,8 @@ void QQmlChangeSet::change(int index, int count) void QQmlChangeSet::apply(const QQmlChangeSet &changeSet) { - QVector<Remove> r = changeSet.m_removes; - QVector<Insert> i = changeSet.m_inserts; + QVector<Change> r = changeSet.m_removes; + QVector<Change> i = changeSet.m_inserts; QVector<Change> c = changeSet.m_changes; remove(&r, &i); insert(i); @@ -174,19 +174,19 @@ void QQmlChangeSet::apply(const QQmlChangeSet &changeSet) corresponding intersection in the optional \a inserts list. */ -void QQmlChangeSet::remove(const QVector<Remove> &removes, QVector<Insert> *inserts) +void QQmlChangeSet::remove(const QVector<Change> &removes, QVector<Change> *inserts) { - QVector<Remove> r = removes; + QVector<Change> r = removes; remove(&r, inserts); } -void QQmlChangeSet::remove(QVector<Remove> *removes, QVector<Insert> *inserts) +void QQmlChangeSet::remove(QVector<Change> *removes, QVector<Change> *inserts) { int removeCount = 0; int insertCount = 0; - QVector<Insert>::iterator insert = m_inserts.begin(); + QVector<Change>::iterator insert = m_inserts.begin(); QVector<Change>::iterator change = m_changes.begin(); - QVector<Remove>::iterator rit = removes->begin(); + QVector<Change>::iterator rit = removes->begin(); for (; rit != removes->end(); ++rit) { int index = rit->index + removeCount; int count = rit->count; @@ -223,7 +223,7 @@ void QQmlChangeSet::remove(QVector<Remove> *removes, QVector<Insert> *inserts) // a new delta for that portion and subtract the size of that delta from the current // one. if (offset < 0 && rit->moveId != -1) { - rit = removes->insert(rit, Remove( + rit = removes->insert(rit, Change( rit->index, -offset, rit->moveId, rit->offset)); ++rit; rit->count -= -offset; @@ -233,7 +233,7 @@ void QQmlChangeSet::remove(QVector<Remove> *removes, QVector<Insert> *inserts) removeCount += -offset; offset = 0; } else if (offset > 0 && insert->moveId != -1) { - insert = m_inserts.insert(insert, Insert( + insert = m_inserts.insert(insert, Change( insert->index - removeCount, offset, insert->moveId, insert->offset)); ++insert; insert->index += offset; @@ -246,7 +246,7 @@ void QQmlChangeSet::remove(QVector<Remove> *removes, QVector<Insert> *inserts) // If the current remove has a move id, find any inserts with the same move id and // replace the corresponding sections with the insert removed from the change set. if (rit->moveId != -1 && difference > 0 && inserts) { - for (QVector<Insert>::iterator iit = inserts->begin(); iit != inserts->end(); ++iit) { + for (QVector<Change>::iterator iit = inserts->begin(); iit != inserts->end(); ++iit) { if (iit->moveId != rit->moveId || rit->offset > iit->offset + iit->count || iit->offset > rit->offset + difference) { @@ -256,7 +256,7 @@ void QQmlChangeSet::remove(QVector<Remove> *removes, QVector<Insert> *inserts) // a new insert for the portion prior to the replacement insert. const int overlapOffset = rit->offset - iit->offset; if (overlapOffset > 0) { - iit = inserts->insert(iit, Insert( + iit = inserts->insert(iit, Change( iit->index, overlapOffset, iit->moveId, iit->offset)); ++iit; iit->index += overlapOffset; @@ -275,7 +275,7 @@ void QQmlChangeSet::remove(QVector<Remove> *removes, QVector<Insert> *inserts) const int count = qMin(iit->offset + iit->count, rit->offset + difference) - qMax(iit->offset, rit->offset); - iit = inserts->insert(iit, Insert( + iit = inserts->insert(iit, Change( iit->index, count, insert->moveId, @@ -316,12 +316,12 @@ void QQmlChangeSet::remove(QVector<Remove> *removes, QVector<Insert> *inserts) insert->index -= removeCount; removeCount = 0; - QVector<Remove>::iterator remove = m_removes.begin(); + QVector<Change>::iterator remove = m_removes.begin(); for (rit = removes->begin(); rit != removes->end(); ++rit) { if (rit->count == 0) continue; // Accumulate consecutive removes into a single delta before attempting to apply. - for (QVector<Remove>::iterator next = rit + 1; next != removes->end() + for (QVector<Change>::iterator next = rit + 1; next != removes->end() && next->index == rit->index && next->moveId == -1 && rit->moveId == -1; ++next) { @@ -336,7 +336,7 @@ void QQmlChangeSet::remove(QVector<Remove> *removes, QVector<Insert> *inserts) while (remove != m_removes.end() && index + rit->count >= remove->index) { int count = 0; const int offset = remove->index - index; - QVector<Remove>::iterator rend = remove; + QVector<Change>::iterator rend = remove; for (; rend != m_removes.end() && rit->moveId == -1 && rend->moveId == -1 @@ -366,7 +366,7 @@ void QQmlChangeSet::remove(QVector<Remove> *removes, QVector<Insert> *inserts) // Insert a remove for the portion of the unmergable current remove prior to the // point of intersection. if (offset > 0) { - remove = m_removes.insert(remove, Remove( + remove = m_removes.insert(remove, Change( rit->index, offset, rit->moveId, rit->offset)); ++remove; rit->count -= offset; @@ -395,19 +395,19 @@ void QQmlChangeSet::remove(QVector<Remove> *removes, QVector<Insert> *inserts) Applies a list of \a inserts to a change set. */ -void QQmlChangeSet::insert(const QVector<Insert> &inserts) +void QQmlChangeSet::insert(const QVector<Change> &inserts) { int insertCount = 0; - QVector<Insert>::iterator insert = m_inserts.begin(); + QVector<Change>::iterator insert = m_inserts.begin(); QVector<Change>::iterator change = m_changes.begin(); - for (QVector<Insert>::const_iterator iit = inserts.begin(); iit != inserts.end(); ++iit) { + for (QVector<Change>::const_iterator iit = inserts.begin(); iit != inserts.end(); ++iit) { if (iit->count == 0) continue; int index = iit->index - insertCount; - Insert current = *iit; + Change current = *iit; // Accumulate consecutive inserts into a single delta before attempting to insert. - for (QVector<Insert>::const_iterator next = iit + 1; next != inserts.end() + for (QVector<Change>::const_iterator next = iit + 1; next != inserts.end() && next->index == iit->index + iit->count && next->moveId == -1 && iit->moveId == -1; ++next) { @@ -459,7 +459,7 @@ void QQmlChangeSet::insert(const QVector<Insert> &inserts) // If either insert has a moveId then split the existing insert and insert the // current one in the middle. if (offset > 0) { - insert = m_inserts.insert(insert, Insert( + insert = m_inserts.insert(insert, Change( insert->index + insertCount, offset, insert->moveId, insert->offset)); ++insert; insert->index += offset; @@ -487,10 +487,10 @@ void QQmlChangeSet::insert(const QVector<Insert> &inserts) calling \l remove() followed by \l insert() with the same lists. */ -void QQmlChangeSet::move(const QVector<Remove> &removes, const QVector<Insert> &inserts) +void QQmlChangeSet::move(const QVector<Change> &removes, const QVector<Change> &inserts) { - QVector<Remove> r = removes; - QVector<Insert> i = inserts; + QVector<Change> r = removes; + QVector<Change> i = inserts; remove(&r, &i); insert(i); } @@ -507,7 +507,7 @@ void QQmlChangeSet::change(const QVector<Change> &changes) void QQmlChangeSet::change(QVector<Change> *changes) { - QVector<Insert>::iterator insert = m_inserts.begin(); + QVector<Change>::iterator insert = m_inserts.begin(); QVector<Change>::iterator change = m_changes.begin(); for (QVector<Change>::iterator cit = changes->begin(); cit != changes->end(); ++cit) { for (; insert != m_inserts.end() && insert->end() < cit->index; ++insert) {} @@ -560,55 +560,13 @@ void QQmlChangeSet::change(QVector<Change> *changes) QDebug operator <<(QDebug debug, const QQmlChangeSet &set) { debug.nospace() << "QQmlChangeSet("; - foreach (const QQmlChangeSet::Remove &remove, set.removes()) debug << remove; - foreach (const QQmlChangeSet::Insert &insert, set.inserts()) debug << insert; + foreach (const QQmlChangeSet::Change &remove, set.removes()) debug << remove; + foreach (const QQmlChangeSet::Change &insert, set.inserts()) debug << insert; foreach (const QQmlChangeSet::Change &change, set.changes()) debug << change; return debug.nospace() << ')'; } /*! - Prints a \a remove to the \a debug stream. -*/ - -QDebug operator <<(QDebug debug, const QQmlChangeSet::Remove &remove) -{ - if (remove.moveId == -1) { - return (debug.nospace() - << "Remove(" << remove.index - << ',' << remove.count - << ')').space(); - } else { - return (debug.nospace() - << "Remove(" << remove.index - << ',' << remove.count - << ',' << remove.moveId - << ',' << remove.offset - << ')').space(); - } -} - -/*! - Prints an \a insert to the \a debug stream. -*/ - -QDebug operator <<(QDebug debug, const QQmlChangeSet::Insert &insert) -{ - if (insert.moveId == -1) { - return (debug.nospace() - << "Insert(" << insert.index - << ',' << insert.count - << ')').space(); - } else { - return (debug.nospace() - << "Insert(" << insert.index - << ',' << insert.count - << ',' << insert.moveId - << ',' << insert.offset - << ')').space(); - } -} - -/*! Prints a \a change to the \a debug stream. */ diff --git a/src/qml/util/qqmlchangeset_p.h b/src/qml/util/qqmlchangeset_p.h index acafbd4eec..e79bc4a832 100644 --- a/src/qml/util/qqmlchangeset_p.h +++ b/src/qml/util/qqmlchangeset_p.h @@ -90,29 +90,14 @@ public: int end() const { return index + count; } }; - - struct Insert : public Change - { - Insert() {} - Insert(int index, int count, int moveId = -1, int offset = 0) - : Change(index, count, moveId, offset) {} - }; - - struct Remove : public Change - { - Remove() {} - Remove(int index, int count, int moveId = -1, int offset = 0) - : Change(index, count, moveId, offset) {} - }; - QQmlChangeSet(); QQmlChangeSet(const QQmlChangeSet &changeSet); ~QQmlChangeSet(); QQmlChangeSet &operator =(const QQmlChangeSet &changeSet); - const QVector<Remove> &removes() const { return m_removes; } - const QVector<Insert> &inserts() const { return m_inserts; } + const QVector<Change> &removes() const { return m_removes; } + const QVector<Change> &inserts() const { return m_inserts; } const QVector<Change> &changes() const { return m_changes; } void insert(int index, int count); @@ -120,9 +105,9 @@ public: void move(int from, int to, int count, int moveId); void change(int index, int count); - void insert(const QVector<Insert> &inserts); - void remove(const QVector<Remove> &removes, QVector<Insert> *inserts = 0); - void move(const QVector<Remove> &removes, const QVector<Insert> &inserts); + void insert(const QVector<Change> &inserts); + void remove(const QVector<Change> &removes, QVector<Change> *inserts = 0); + void move(const QVector<Change> &removes, const QVector<Change> &inserts); void change(const QVector<Change> &changes); void apply(const QQmlChangeSet &changeSet); @@ -139,26 +124,22 @@ public: int difference() const { return m_difference; } private: - void remove(QVector<Remove> *removes, QVector<Insert> *inserts); + void remove(QVector<Change> *removes, QVector<Change> *inserts); void change(QVector<Change> *changes); - QVector<Remove> m_removes; - QVector<Insert> m_inserts; + QVector<Change> m_removes; + QVector<Change> m_inserts; QVector<Change> m_changes; int m_difference; }; Q_DECLARE_TYPEINFO(QQmlChangeSet::Change, Q_PRIMITIVE_TYPE); -Q_DECLARE_TYPEINFO(QQmlChangeSet::Remove, Q_PRIMITIVE_TYPE); -Q_DECLARE_TYPEINFO(QQmlChangeSet::Insert, Q_PRIMITIVE_TYPE); Q_DECLARE_TYPEINFO(QQmlChangeSet::MoveKey, Q_PRIMITIVE_TYPE); inline uint qHash(const QQmlChangeSet::MoveKey &key) { return qHash(qMakePair(key.moveId, key.offset)); } inline bool operator ==(const QQmlChangeSet::MoveKey &l, const QQmlChangeSet::MoveKey &r) { return l.moveId == r.moveId && l.offset == r.offset; } -Q_QML_PRIVATE_EXPORT QDebug operator <<(QDebug debug, const QQmlChangeSet::Remove &remove); -Q_QML_PRIVATE_EXPORT QDebug operator <<(QDebug debug, const QQmlChangeSet::Insert &insert); Q_QML_PRIVATE_EXPORT QDebug operator <<(QDebug debug, const QQmlChangeSet::Change &change); Q_QML_PRIVATE_EXPORT QDebug operator <<(QDebug debug, const QQmlChangeSet &change); diff --git a/src/qml/util/qqmllistcompositor.cpp b/src/qml/util/qqmllistcompositor.cpp index 830a24e752..64528dafd2 100644 --- a/src/qml/util/qqmllistcompositor.cpp +++ b/src/qml/util/qqmllistcompositor.cpp @@ -951,7 +951,7 @@ void QQmlListCompositor::clear() void QQmlListCompositor::listItemsInserted( QVector<Insert> *translatedInsertions, void *list, - const QVector<QQmlChangeSet::Insert> &insertions, + const QVector<QQmlChangeSet::Change> &insertions, const QVector<MovedFlags> *movedFlags) { QT_QML_TRACE_LISTCOMPOSITOR(<< list << insertions) @@ -966,7 +966,7 @@ void QQmlListCompositor::listItemsInserted( it.incrementIndexes(it->count); continue; } - foreach (const QQmlChangeSet::Insert &insertion, insertions) { + foreach (const QQmlChangeSet::Change &insertion, insertions) { int offset = insertion.index - it->index; if ((offset > 0 && offset < it->count) || (offset == 0 && it->prepend()) @@ -1064,8 +1064,8 @@ void QQmlListCompositor::listItemsInserted( QT_QML_TRACE_LISTCOMPOSITOR(<< list << index << count) Q_ASSERT(count > 0); - QVector<QQmlChangeSet::Insert> insertions; - insertions.append(QQmlChangeSet::Insert(index, count)); + QVector<QQmlChangeSet::Change> insertions; + insertions.append(QQmlChangeSet::Change(index, count)); listItemsInserted(translatedInsertions, list, insertions); } @@ -1073,8 +1073,8 @@ void QQmlListCompositor::listItemsInserted( void QQmlListCompositor::listItemsRemoved( QVector<Remove> *translatedRemovals, void *list, - QVector<QQmlChangeSet::Remove> *removals, - QVector<QQmlChangeSet::Insert> *insertions, + QVector<QQmlChangeSet::Change> *removals, + QVector<QQmlChangeSet::Change> *insertions, QVector<MovedFlags> *movedFlags) { QT_QML_TRACE_LISTCOMPOSITOR(<< list << *removals) @@ -1086,7 +1086,7 @@ void QQmlListCompositor::listItemsRemoved( continue; } bool removed = false; - for (QVector<QQmlChangeSet::Remove>::iterator removal = removals->begin(); + for (QVector<QQmlChangeSet::Change>::iterator removal = removals->begin(); !removed && removal != removals->end(); ++removal) { int relativeIndex = removal->index - it->index; @@ -1104,7 +1104,7 @@ void QQmlListCompositor::listItemsRemoved( } if (removal->isMove()) { // If the removal was part of a move find the corresponding insert. - QVector<QQmlChangeSet::Insert>::iterator insertion = insertions->begin(); + QVector<QQmlChangeSet::Change>::iterator insertion = insertions->begin(); for (; insertion != insertions->end() && insertion->moveId != removal->moveId; ++insertion) {} Q_ASSERT(insertion != insertions->end()); @@ -1114,11 +1114,11 @@ void QQmlListCompositor::listItemsRemoved( // If the remove started before the current range, split it and the // corresponding insert so we're only working with intersecting part. int splitMoveId = ++m_moveId; - removal = removals->insert(removal, QQmlChangeSet::Remove( + removal = removals->insert(removal, QQmlChangeSet::Change( removal->index, -relativeIndex, splitMoveId)); ++removal; removal->count -= -relativeIndex; - insertion = insertions->insert(insertion, QQmlChangeSet::Insert( + insertion = insertions->insert(insertion, QQmlChangeSet::Change( insertion->index, -relativeIndex, splitMoveId)); ++insertion; insertion->index += -relativeIndex; @@ -1135,10 +1135,10 @@ void QQmlListCompositor::listItemsRemoved( if (removeCount < removal->count) { // If the remove doesn't encompass all of the current range, // split it and the corresponding insert. - removal = removals->insert(removal, QQmlChangeSet::Remove( + removal = removals->insert(removal, QQmlChangeSet::Change( removal->index, removeCount, translatedRemoval.moveId)); ++removal; - insertion = insertions->insert(insertion, QQmlChangeSet::Insert( + insertion = insertions->insert(insertion, QQmlChangeSet::Change( insertion->index, removeCount, translatedRemoval.moveId)); ++insertion; @@ -1253,8 +1253,8 @@ void QQmlListCompositor::listItemsRemoved( QT_QML_TRACE_LISTCOMPOSITOR(<< list << index << count) Q_ASSERT(count >= 0); - QVector<QQmlChangeSet::Remove> removals; - removals.append(QQmlChangeSet::Remove(index, count)); + QVector<QQmlChangeSet::Change> removals; + removals.append(QQmlChangeSet::Change(index, count)); listItemsRemoved(translatedRemovals, list, &removals, 0, 0); } @@ -1280,11 +1280,11 @@ void QQmlListCompositor::listItemsMoved( QT_QML_TRACE_LISTCOMPOSITOR(<< list << from << to << count) Q_ASSERT(count >= 0); - QVector<QQmlChangeSet::Remove> removals; - QVector<QQmlChangeSet::Insert> insertions; + QVector<QQmlChangeSet::Change> removals; + QVector<QQmlChangeSet::Change> insertions; QVector<MovedFlags> movedFlags; - removals.append(QQmlChangeSet::Remove(from, count, 0)); - insertions.append(QQmlChangeSet::Insert(to, count, 0)); + removals.append(QQmlChangeSet::Change(from, count, 0)); + insertions.append(QQmlChangeSet::Change(to, count, 0)); listItemsRemoved(translatedRemovals, list, &removals, &insertions, &movedFlags); listItemsInserted(translatedInsertions, list, insertions, &movedFlags); @@ -1342,16 +1342,16 @@ void QQmlListCompositor::listItemsChanged( void QQmlListCompositor::transition( Group from, Group to, - QVector<QQmlChangeSet::Remove> *removes, - QVector<QQmlChangeSet::Insert> *inserts) + QVector<QQmlChangeSet::Change> *removes, + QVector<QQmlChangeSet::Change> *inserts) { int removeCount = 0; for (iterator it(m_ranges.next, 0, Default, m_groupCount); *it != &m_ranges; *it = it->next) { if (it == from && it != to) { - removes->append(QQmlChangeSet::Remove(it.index[from]- removeCount, it->count)); + removes->append(QQmlChangeSet::Change(it.index[from]- removeCount, it->count)); removeCount += it->count; } else if (it != from && it == to) { - inserts->append(QQmlChangeSet::Insert(it.index[to], it->count)); + inserts->append(QQmlChangeSet::Change(it.index[to], it->count)); } it.incrementIndexes(it->count); } diff --git a/src/qml/util/qqmllistcompositor_p.h b/src/qml/util/qqmllistcompositor_p.h index 5d87051582..c26b62a38c 100644 --- a/src/qml/util/qqmllistcompositor_p.h +++ b/src/qml/util/qqmllistcompositor_p.h @@ -263,8 +263,8 @@ public: void transition( Group from, Group to, - QVector<QQmlChangeSet::Remove> *removes, - QVector<QQmlChangeSet::Insert> *inserts); + QVector<QQmlChangeSet::Change> *removes, + QVector<QQmlChangeSet::Change> *inserts); private: Range m_ranges; @@ -290,13 +290,13 @@ private: void listItemsRemoved( QVector<Remove> *translatedRemovals, void *list, - QVector<QQmlChangeSet::Remove> *removals, - QVector<QQmlChangeSet::Insert> *insertions = 0, + QVector<QQmlChangeSet::Change> *removals, + QVector<QQmlChangeSet::Change> *insertions = 0, QVector<MovedFlags> *movedFlags = 0); void listItemsInserted( QVector<Insert> *translatedInsertions, void *list, - const QVector<QQmlChangeSet::Insert> &insertions, + const QVector<QQmlChangeSet::Change> &insertions, const QVector<MovedFlags> *movedFlags = 0); void listItemsChanged( QVector<Change> *translatedChanges, |