diff options
Diffstat (limited to 'src/qml')
124 files changed, 5034 insertions, 4104 deletions
diff --git a/src/qml/compiler/qqmltypecompiler.cpp b/src/qml/compiler/qqmltypecompiler.cpp index ab2b0553a9..85267225be 100644 --- a/src/qml/compiler/qqmltypecompiler.cpp +++ b/src/qml/compiler/qqmltypecompiler.cpp @@ -57,12 +57,12 @@ QT_BEGIN_NAMESPACE QQmlTypeCompiler::QQmlTypeCompiler(QQmlEnginePrivate *engine, QQmlTypeData *typeData, - QmlIR::Document *parsedQML, const QQmlRefPointer<QQmlTypeNameCache> &importCache, + QmlIR::Document *parsedQML, const QQmlRefPointer<QQmlTypeNameCache> &typeNameCache, const QV4::CompiledData::ResolvedTypeReferenceMap &resolvedTypeCache) : resolvedTypes(resolvedTypeCache) , engine(engine) , typeData(typeData) - , importCache(importCache) + , typeNameCache(typeNameCache) , document(parsedQML) { } @@ -138,7 +138,7 @@ QV4::CompiledData::CompilationUnit *QQmlTypeCompiler::compile() sss.scan(); } - QmlIR::JSCodeGen v4CodeGenerator(typeData->finalUrlString(), document->code, &document->jsModule, &document->jsParserEngine, document->program, importCache, &document->jsGenerator.stringTable); + QmlIR::JSCodeGen v4CodeGenerator(typeData->finalUrlString(), document->code, &document->jsModule, &document->jsParserEngine, document->program, typeNameCache, &document->jsGenerator.stringTable); QQmlJSCodeGenerator jsCodeGen(this, &v4CodeGenerator); if (!jsCodeGen.generateCodeForComponents()) return nullptr; @@ -164,7 +164,7 @@ QV4::CompiledData::CompilationUnit *QQmlTypeCompiler::compile() QV4::CompiledData::CompilationUnit *compilationUnit = document->javaScriptCompilationUnit; compilationUnit = document->javaScriptCompilationUnit; - compilationUnit->importCache = importCache; + compilationUnit->typeNameCache = typeNameCache; compilationUnit->resolvedTypes = resolvedTypes; compilationUnit->propertyCaches = std::move(m_propertyCaches); Q_ASSERT(compilationUnit->propertyCaches.count() == static_cast<int>(compilationUnit->data->nObjects)); diff --git a/src/qml/compiler/qqmltypecompiler_p.h b/src/qml/compiler/qqmltypecompiler_p.h index de6abb4ced..2b59e7e42f 100644 --- a/src/qml/compiler/qqmltypecompiler_p.h +++ b/src/qml/compiler/qqmltypecompiler_p.h @@ -89,7 +89,7 @@ struct QQmlTypeCompiler { Q_DECLARE_TR_FUNCTIONS(QQmlTypeCompiler) public: - QQmlTypeCompiler(QQmlEnginePrivate *engine, QQmlTypeData *typeData, QmlIR::Document *document, const QQmlRefPointer<QQmlTypeNameCache> &importCache, const QV4::CompiledData::ResolvedTypeReferenceMap &resolvedTypeCache); + QQmlTypeCompiler(QQmlEnginePrivate *engine, QQmlTypeData *typeData, QmlIR::Document *document, const QQmlRefPointer<QQmlTypeNameCache> &typeNameCache, const QV4::CompiledData::ResolvedTypeReferenceMap &resolvedTypeCache); // --- interface used by QQmlPropertyCacheCreator typedef QmlIR::Object CompiledObject; @@ -139,7 +139,7 @@ private: QList<QQmlError> errors; QQmlEnginePrivate *engine; QQmlTypeData *typeData; - QQmlRefPointer<QQmlTypeNameCache> importCache; + QQmlRefPointer<QQmlTypeNameCache> typeNameCache; QmlIR::Document *document; // index is string index of type name (use obj->inheritedTypeNameIndex) QHash<int, QQmlCustomParser*> customParsers; diff --git a/src/qml/compiler/qv4codegen.cpp b/src/qml/compiler/qv4codegen.cpp index e0def1021b..7d3ad38f97 100644 --- a/src/qml/compiler/qv4codegen.cpp +++ b/src/qml/compiler/qv4codegen.cpp @@ -526,21 +526,21 @@ IR::Expr *Codegen::subscript(IR::Expr *base, IR::Expr *index) if (hasError) return 0; - if (! base->asTemp() || base->asArgLocal()) { + if (! base->asTemp() && !base->asArgLocal()) { const unsigned t = _block->newTemp(); move(_block->TEMP(t), base); base = _block->TEMP(t); } - if (! index->asTemp() || index->asArgLocal()) { + if (! index->asTemp() && !index->asArgLocal() && !index->asConst()) { const unsigned t = _block->newTemp(); move(_block->TEMP(t), index); index = _block->TEMP(t); } Q_ASSERT(base->asTemp() || base->asArgLocal()); - Q_ASSERT(index->asTemp() || index->asArgLocal()); - return _block->SUBSCRIPT(base->asTemp(), index->asTemp()); + Q_ASSERT(index->asTemp() || index->asArgLocal() || index->asConst()); + return _block->SUBSCRIPT(base, index); } IR::Expr *Codegen::argument(IR::Expr *expr) @@ -611,7 +611,7 @@ IR::Expr *Codegen::binop(IR::AluOp op, IR::Expr *left, IR::Expr *right, const AS if (IR::Const *c1 = left->asConst()) { if (IR::Const *c2 = right->asConst()) { - if (c1->type == IR::NumberType && c2->type == IR::NumberType) { + if ((c1->type & IR::NumberType) && (c2->type & IR::NumberType)) { switch (op) { case IR::OpAdd: return _block->CONST(IR::NumberType, c1->value + c2->value); case IR::OpAnd: return _block->CONST(IR::BoolType, c1->value ? c2->value : 0); @@ -659,20 +659,20 @@ IR::Expr *Codegen::binop(IR::AluOp op, IR::Expr *left, IR::Expr *right, const AS } } - if (!left->asTemp() && !left->asArgLocal()) { + if (!left->asTemp() && !left->asArgLocal() && !left->asConst()) { const unsigned t = _block->newTemp(); setLocation(move(_block->TEMP(t), left), loc); left = _block->TEMP(t); } - if (!right->asTemp() && !right->asArgLocal()) { + if (!right->asTemp() && !right->asArgLocal() && !right->asConst()) { const unsigned t = _block->newTemp(); setLocation(move(_block->TEMP(t), right), loc); right = _block->TEMP(t); } - Q_ASSERT(left->asTemp() || left->asArgLocal()); - Q_ASSERT(right->asTemp() || right->asArgLocal()); + Q_ASSERT(left->asTemp() || left->asArgLocal() || left->asConst()); + Q_ASSERT(right->asTemp() || right->asArgLocal() || right->asConst()); return _block->BINOP(op, left, right); } @@ -842,9 +842,16 @@ void Codegen::variableDeclaration(VariableDeclaration *ast) Q_ASSERT(expr.code); initializer = *expr; - int initialized = _block->newTemp(); - move(_block->TEMP(initialized), initializer); - move(identifier(ast->name.toString(), ast->identifierToken.startLine, ast->identifierToken.startColumn), _block->TEMP(initialized)); + IR::Expr *lhs = identifier(ast->name.toString(), ast->identifierToken.startLine, + ast->identifierToken.startColumn); + + if (lhs->asArgLocal()) { + move(lhs, initializer); + } else { + int initialized = _block->newTemp(); + move(_block->TEMP(initialized), initializer); + move(lhs, _block->TEMP(initialized)); + } } void Codegen::variableDeclarationList(VariableDeclarationList *ast) diff --git a/src/qml/compiler/qv4compilationunitmapper_win.cpp b/src/qml/compiler/qv4compilationunitmapper_win.cpp index 457b702ac3..37cac846a0 100644 --- a/src/qml/compiler/qv4compilationunitmapper_win.cpp +++ b/src/qml/compiler/qv4compilationunitmapper_win.cpp @@ -75,7 +75,6 @@ CompiledData::Unit *CompilationUnitMapper::open(const QString &cacheFileName, co CloseHandle(handle); }); -#if !defined(Q_OS_WINRT) || _MSC_VER >= 1900 CompiledData::Unit header; DWORD bytesRead; if (!ReadFile(handle, reinterpret_cast<char *>(&header), sizeof(header), &bytesRead, nullptr)) { @@ -115,19 +114,12 @@ CompiledData::Unit *CompilationUnitMapper::open(const QString &cacheFileName, co } return reinterpret_cast<CompiledData::Unit*>(dataPtr); -#else - Q_UNUSED(sourcePath); - *errorString = QStringLiteral("Compilation unit mapping not supported on WinRT 8.1"); - return nullptr; -#endif } void CompilationUnitMapper::close() { -#if !defined(Q_OS_WINRT) || _MSC_VER >= 1900 if (dataPtr != nullptr) UnmapViewOfFile(dataPtr); -#endif dataPtr = nullptr; } diff --git a/src/qml/compiler/qv4compileddata.cpp b/src/qml/compiler/qv4compileddata.cpp index 8586c84c3d..25b090f555 100644 --- a/src/qml/compiler/qv4compileddata.cpp +++ b/src/qml/compiler/qv4compileddata.cpp @@ -207,7 +207,7 @@ void CompilationUnit::unlink() dependentScripts.at(ii)->release(); dependentScripts.clear(); - importCache = nullptr; + typeNameCache = nullptr; qDeleteAll(resolvedTypes); resolvedTypes.clear(); @@ -407,6 +407,11 @@ bool CompilationUnit::loadFromDisk(const QUrl &url, EvalISelFactory *iselFactory const Unit * const oldDataPtr = (data && !(data->flags & QV4::CompiledData::Unit::StaticData)) ? data : nullptr; QScopedValueRollback<const Unit *> dataPtrChange(data, mappedUnit); + if (sourcePath != QQmlFile::urlToLocalFileOrQrc(stringAt(data->sourceFileIndex))) { + *errorString = QStringLiteral("QML source file has moved to a different location."); + return false; + } + { const QString foundArchitecture = stringAt(data->architectureIndex); const QString expectedArchitecture = QSysInfo::buildAbi(); diff --git a/src/qml/compiler/qv4compileddata_p.h b/src/qml/compiler/qv4compileddata_p.h index 2682365182..97623b4d86 100644 --- a/src/qml/compiler/qv4compileddata_p.h +++ b/src/qml/compiler/qv4compileddata_p.h @@ -855,7 +855,7 @@ struct Q_QML_PRIVATE_EXPORT CompilationUnit : public QQmlRefCount QQmlPropertyCacheVector propertyCaches; QQmlPropertyCache *rootPropertyCache() const { return propertyCaches.at(data->indexOfRootObject); } - QQmlRefPointer<QQmlTypeNameCache> importCache; + QQmlRefPointer<QQmlTypeNameCache> typeNameCache; // index is object index. This allows fast access to the // property data when initializing bindings, avoiding expensive diff --git a/src/qml/compiler/qv4ssa.cpp b/src/qml/compiler/qv4ssa.cpp index 943700de44..1d512711b8 100644 --- a/src/qml/compiler/qv4ssa.cpp +++ b/src/qml/compiler/qv4ssa.cpp @@ -2758,7 +2758,7 @@ public: visit(s); } - foreach (const Conversion &conversion, _conversions) { + for (const Conversion &conversion : qAsConst(_conversions)) { IR::Move *move = conversion.stmt->asMove(); // Note: isel only supports move into member when source is a temp, so convert diff --git a/src/qml/debugger/qqmlprofiler_p.h b/src/qml/debugger/qqmlprofiler_p.h index 3a507bef74..41fb2c5b7b 100644 --- a/src/qml/debugger/qqmlprofiler_p.h +++ b/src/qml/debugger/qqmlprofiler_p.h @@ -73,7 +73,7 @@ struct QQmlProfiler {}; struct QQmlBindingProfiler { - QQmlBindingProfiler(quintptr, QQmlBinding *, QV4::FunctionObject *) {} + QQmlBindingProfiler(quintptr, QV4::Function *) {} }; struct QQmlHandlingSignalProfiler diff --git a/src/qml/doc/src/examples.qdoc b/src/qml/doc/src/examples.qdoc index f3550ae199..4f12d42f48 100644 --- a/src/qml/doc/src/examples.qdoc +++ b/src/qml/doc/src/examples.qdoc @@ -32,4 +32,40 @@ The list of examples demonstrating how to extend C++ to QML or the other way around. + +\noautolist + +\table + \row + \li \l {Extending QML - Adding Types Example} + \li Exporting C++ Classes + \row + \li \l {Extending QML - Object and List Property Types Example} + \li Exporting C++ Properties + \row + \li \l {Extending QML - Extension Objects Example} + \li Extension Objects + \row + \li \l {Extending QML - Inheritance and Coercion Example} + \li C++ Inheritance and Coercion + \row + \li \l {Extending QML - Methods Example} + \li Methods Support + \row + \li \l {Extending QML - Attached Properties Example} + \li Attached Properties + \row + \li \l {Extending QML - Signal Support Example} + \li Signal Support + \row + \li \l {Extending QML - Property Value Source Example} + \li Property Value Source + \row + \li \l {Extending QML - Default Property Example} + \li Default Property + \row + \li \l {Extending QML - Grouped Properties Example} + \li Grouped Properties +\endtable + */ diff --git a/src/qml/doc/src/qmllanguageref/documents/networktransparency.qdoc b/src/qml/doc/src/qmllanguageref/documents/networktransparency.qdoc index 7fa271c2d9..5cfd80f8a0 100644 --- a/src/qml/doc/src/qmllanguageref/documents/networktransparency.qdoc +++ b/src/qml/doc/src/qmllanguageref/documents/networktransparency.qdoc @@ -48,12 +48,8 @@ Image { } \endqml -Network transparency is supported throughout QML, for example: - -\list -\li Fonts - the \c source property of FontLoader is a URL -\li WebViews - the \c url property of WebView (obviously!) -\endlist +Network transparency is supported throughout QML, for example, both the FontLoader +and Image elements support loading resources from a remote server. Even QML types themselves can be on the network - if the \l {Prototyping with qmlscene} is used to load \tt http://example.com/mystuff/Hello.qml and that content refers to a type "World", the engine diff --git a/src/qml/doc/src/qmltypereference.qdoc b/src/qml/doc/src/qmltypereference.qdoc index f32574fcc1..b2bb9ebd18 100644 --- a/src/qml/doc/src/qmltypereference.qdoc +++ b/src/qml/doc/src/qmltypereference.qdoc @@ -89,7 +89,7 @@ provided: \ingroup qtquickbasictypes \brief a date value. -The \c date type refers to a date value. +The \c date type refers to a date value, including the time of the day. To create a \c date value, specify it as a "YYYY-MM-DD" string: @@ -100,7 +100,7 @@ MyDatePicker { minDate: "2000-01-01"; maxDate: "2020-12-31" } To read a date value returned from a C++ extension class, use \l{QtQml::Qt::formatDate()}{Qt.formatDate()} and \l{QtQml::Qt::formatDateTime()}{Qt.formatDateTime()}. -When integrating with C++, note that any QDate value +When integrating with C++, note that any QDate or QDateTime value \l{qtqml-cppintegration-data.html}{passed into QML from C++} is automatically converted into a \c date value, and vice-versa. diff --git a/src/qml/jit/qv4assembler.cpp b/src/qml/jit/qv4assembler.cpp index e1acc33f82..018396318e 100644 --- a/src/qml/jit/qv4assembler.cpp +++ b/src/qml/jit/qv4assembler.cpp @@ -52,6 +52,8 @@ #include <WTFStubs.h> #include <iostream> +#include <QBuffer> +#include <QCoreApplication> #if ENABLE(ASSEMBLER) @@ -146,11 +148,11 @@ bool CompilationUnit::memoryMapCode(QString *errorString) const Assembler::VoidType Assembler::Void; -Assembler::Assembler(InstructionSelection *isel, IR::Function* function, QV4::ExecutableAllocator *executableAllocator) +Assembler::Assembler(QV4::Compiler::JSUnitGenerator *jsGenerator, IR::Function* function, QV4::ExecutableAllocator *executableAllocator) : _function(function) , _nextBlock(0) , _executableAllocator(executableAllocator) - , _isel(isel) + , _jsGenerator(jsGenerator) { _addrs.resize(_function->basicBlockCount()); _patches.resize(_function->basicBlockCount()); @@ -301,7 +303,7 @@ Assembler::Pointer Assembler::loadStringAddress(RegisterID reg, const QString &s loadPtr(Address(Assembler::EngineRegister, qOffsetOf(QV4::ExecutionEngine, current)), Assembler::ScratchRegister); loadPtr(Address(Assembler::ScratchRegister, qOffsetOf(QV4::Heap::ExecutionContext, compilationUnit)), Assembler::ScratchRegister); loadPtr(Address(Assembler::ScratchRegister, qOffsetOf(QV4::CompiledData::CompilationUnit, runtimeStrings)), reg); - const int id = _isel->registerString(string); + const int id = _jsGenerator->registerString(string); return Pointer(reg, id * sizeof(QV4::String*)); } @@ -314,13 +316,13 @@ Assembler::Address Assembler::loadConstant(const Primitive &v, RegisterID baseRe { loadPtr(Address(Assembler::EngineRegister, qOffsetOf(QV4::ExecutionEngine, current)), baseReg); loadPtr(Address(baseReg, qOffsetOf(QV4::Heap::ExecutionContext, constantTable)), baseReg); - const int index = _isel->jsUnitGenerator()->registerConstant(v.asReturnedValue()); + const int index = _jsGenerator->registerConstant(v.asReturnedValue()); return Address(baseReg, index * sizeof(QV4::Value)); } void Assembler::loadStringRef(RegisterID reg, const QString &string) { - const int id = _isel->registerString(string); + const int id = _jsGenerator->registerString(string); move(TrustedImm32(id), reg); } @@ -496,4 +498,174 @@ void Assembler::setStackLayout(int maxArgCountForBuiltins, int regularRegistersT _stackLayout.reset(new StackLayout(_function, maxArgCountForBuiltins, regularRegistersToSave, fpRegistersToSave)); } + +namespace { +class QIODevicePrintStream: public FilePrintStream +{ + Q_DISABLE_COPY(QIODevicePrintStream) + +public: + explicit QIODevicePrintStream(QIODevice *dest) + : FilePrintStream(0) + , dest(dest) + , buf(4096, '0') + { + Q_ASSERT(dest); + } + + ~QIODevicePrintStream() + {} + + void vprintf(const char* format, va_list argList) WTF_ATTRIBUTE_PRINTF(2, 0) + { + const int written = qvsnprintf(buf.data(), buf.size(), format, argList); + if (written > 0) + dest->write(buf.constData(), written); + memset(buf.data(), 0, qMin(written, buf.size())); + } + + void flush() + {} + +private: + QIODevice *dest; + QByteArray buf; +}; +} // anonymous namespace + +static void printDisassembledOutputWithCalls(QByteArray processedOutput, const QHash<void*, const char*>& functions) +{ + for (QHash<void*, const char*>::ConstIterator it = functions.begin(), end = functions.end(); + it != end; ++it) { + const QByteArray ptrString = "0x" + QByteArray::number(quintptr(it.key()), 16); + int idx = processedOutput.indexOf(ptrString); + if (idx < 0) + continue; + idx = processedOutput.lastIndexOf('\n', idx); + if (idx < 0) + continue; + processedOutput = processedOutput.insert(idx, QByteArrayLiteral(" ; call ") + it.value()); + } + + qDebug("%s", processedOutput.constData()); +} + +#if defined(Q_OS_LINUX) +static FILE *pmap; + +static void qt_closePmap() +{ + if (pmap) { + fclose(pmap); + pmap = 0; + } +} + +#endif + +JSC::MacroAssemblerCodeRef Assembler::link(int *codeSize) +{ + Label endOfCode = label(); + + { + for (size_t i = 0, ei = _patches.size(); i != ei; ++i) { + Label target = _addrs.at(i); + Q_ASSERT(target.isSet()); + for (Jump jump : qAsConst(_patches.at(i))) + jump.linkTo(target, this); + } + } + + JSC::JSGlobalData dummy(_executableAllocator); + JSC::LinkBuffer linkBuffer(dummy, this, 0); + + for (const DataLabelPatch &p : qAsConst(_dataLabelPatches)) + linkBuffer.patch(p.dataLabel, linkBuffer.locationOf(p.target)); + + // link exception handlers + for (Jump jump : qAsConst(exceptionPropagationJumps)) + linkBuffer.link(jump, linkBuffer.locationOf(exceptionReturnLabel)); + + { + for (size_t i = 0, ei = _labelPatches.size(); i != ei; ++i) { + Label target = _addrs.at(i); + Q_ASSERT(target.isSet()); + for (DataLabelPtr label : _labelPatches.at(i)) + linkBuffer.patch(label, linkBuffer.locationOf(target)); + } + } + + *codeSize = linkBuffer.offsetOf(endOfCode); + + QByteArray name; + + JSC::MacroAssemblerCodeRef codeRef; + + static const bool showCode = qEnvironmentVariableIsSet("QV4_SHOW_ASM"); + if (showCode) { + QHash<void*, const char*> functions; +#ifndef QT_NO_DEBUG + for (CallInfo call : qAsConst(_callInfos)) + functions[linkBuffer.locationOf(call.label).dataLocation()] = call.functionName; +#endif + + QBuffer buf; + buf.open(QIODevice::WriteOnly); + WTF::setDataFile(new QIODevicePrintStream(&buf)); + + name = _function->name->toUtf8(); + if (name.isEmpty()) + name = "IR::Function(0x" + QByteArray::number(quintptr(_function), 16) + ')'; + codeRef = linkBuffer.finalizeCodeWithDisassembly("%s", name.data()); + + WTF::setDataFile(stderr); + printDisassembledOutputWithCalls(buf.data(), functions); + } else { + codeRef = linkBuffer.finalizeCodeWithoutDisassembly(); + } + +#if defined(Q_OS_LINUX) + // This implements writing of JIT'd addresses so that perf can find the + // symbol names. + // + // Perf expects the mapping to be in a certain place and have certain + // content, for more information, see: + // https://github.com/torvalds/linux/blob/master/tools/perf/Documentation/jit-interface.txt + static bool doProfile = !qEnvironmentVariableIsEmpty("QV4_PROFILE_WRITE_PERF_MAP"); + static bool profileInitialized = false; + if (doProfile && !profileInitialized) { + profileInitialized = true; + + char pname[PATH_MAX]; + snprintf(pname, PATH_MAX - 1, "/tmp/perf-%lu.map", + (unsigned long)QCoreApplication::applicationPid()); + + pmap = fopen(pname, "w"); + if (!pmap) + qWarning("QV4: Can't write %s, call stacks will not contain JavaScript function names", pname); + + // make sure we clean up nicely + std::atexit(qt_closePmap); + } + + if (pmap) { + // this may have been pre-populated, if QV4_SHOW_ASM was on + if (name.isEmpty()) { + name = _function->name->toUtf8(); + if (name.isEmpty()) + name = "IR::Function(0x" + QByteArray::number(quintptr(_function), 16) + ')'; + } + + fprintf(pmap, "%llx %x %.*s\n", + (long long unsigned int)codeRef.code().executableAddress(), + *codeSize, + name.length(), + name.constData()); + fflush(pmap); + } +#endif + + return codeRef; +} + #endif diff --git a/src/qml/jit/qv4assembler_p.h b/src/qml/jit/qv4assembler_p.h index 94478cd9cd..de9c246ed6 100644 --- a/src/qml/jit/qv4assembler_p.h +++ b/src/qml/jit/qv4assembler_p.h @@ -111,7 +111,7 @@ class Assembler : public JSC::MacroAssembler, public TargetPlatform Q_DISABLE_COPY(Assembler) public: - Assembler(InstructionSelection *isel, IR::Function* function, QV4::ExecutableAllocator *executableAllocator); + Assembler(QV4::Compiler::JSUnitGenerator *jsGenerator, IR::Function* function, QV4::ExecutableAllocator *executableAllocator); // Explicit type to allow distinguishing between // pushing an address itself or the value it points @@ -1092,7 +1092,7 @@ private: IR::BasicBlock *_nextBlock; QV4::ExecutableAllocator *_executableAllocator; - InstructionSelection *_isel; + QV4::Compiler::JSUnitGenerator *_jsGenerator; }; template <typename Result, typename Source> diff --git a/src/qml/jit/qv4binop.cpp b/src/qml/jit/qv4binop.cpp index 9c535bb0bb..d2758c4a47 100644 --- a/src/qml/jit/qv4binop.cpp +++ b/src/qml/jit/qv4binop.cpp @@ -112,7 +112,7 @@ void Binop::generate(IR::Expr *lhs, IR::Expr *rhs, IR::Expr *target) return; } - Assembler::Jump done; + Jump done; if (lhs->type != IR::StringType && rhs->type != IR::StringType) done = genInlineBinop(lhs, rhs, target); @@ -129,13 +129,13 @@ void Binop::generate(IR::Expr *lhs, IR::Expr *rhs, IR::Expr *target) RuntimeCall context(info.contextImplementation); if (fallBack.isValid()) { as->generateFunctionCallImp(info.needsExceptionCheck, target, info.name, fallBack, - Assembler::PointerToValue(lhs), - Assembler::PointerToValue(rhs)); + PointerToValue(lhs), + PointerToValue(rhs)); } else if (context.isValid()) { as->generateFunctionCallImp(info.needsExceptionCheck, target, info.name, context, Assembler::EngineRegister, - Assembler::PointerToValue(lhs), - Assembler::PointerToValue(rhs)); + PointerToValue(lhs), + PointerToValue(rhs)); } else { Q_ASSERT(!"unreachable"); } @@ -148,9 +148,9 @@ void Binop::generate(IR::Expr *lhs, IR::Expr *rhs, IR::Expr *target) void Binop::doubleBinop(IR::Expr *lhs, IR::Expr *rhs, IR::Expr *target) { IR::Temp *targetTemp = target->asTemp(); - Assembler::FPRegisterID targetReg; + FPRegisterID targetReg; if (targetTemp && targetTemp->kind == IR::Temp::PhysicalRegister) - targetReg = (Assembler::FPRegisterID) targetTemp->index; + targetReg = (FPRegisterID) targetTemp->index; else targetReg = Assembler::FPGpr0; @@ -162,7 +162,7 @@ void Binop::doubleBinop(IR::Expr *lhs, IR::Expr *rhs, IR::Expr *target) #if CPU(X86) if (IR::Const *c = rhs->asConst()) { // Y = X + constant -> Y = X; Y += [constant-address] as->moveDouble(as->toDoubleRegister(lhs, targetReg), targetReg); - Assembler::Address addr = as->loadConstant(c, Assembler::ScratchRegister); + Address addr = as->loadConstant(c, Assembler::ScratchRegister); as->addDouble(addr, targetReg); break; } @@ -184,7 +184,7 @@ void Binop::doubleBinop(IR::Expr *lhs, IR::Expr *rhs, IR::Expr *target) #if CPU(X86) if (IR::Const *c = rhs->asConst()) { // Y = X * constant -> Y = X; Y *= [constant-address] as->moveDouble(as->toDoubleRegister(lhs, targetReg), targetReg); - Assembler::Address addr = as->loadConstant(c, Assembler::ScratchRegister); + Address addr = as->loadConstant(c, Assembler::ScratchRegister); as->mulDouble(addr, targetReg); break; } @@ -203,7 +203,7 @@ void Binop::doubleBinop(IR::Expr *lhs, IR::Expr *rhs, IR::Expr *target) #if CPU(X86) if (IR::Const *c = rhs->asConst()) { // Y = X - constant -> Y = X; Y -= [constant-address] as->moveDouble(as->toDoubleRegister(lhs, targetReg), targetReg); - Assembler::Address addr = as->loadConstant(c, Assembler::ScratchRegister); + Address addr = as->loadConstant(c, Assembler::ScratchRegister); as->subDouble(addr, targetReg); break; } @@ -231,7 +231,7 @@ void Binop::doubleBinop(IR::Expr *lhs, IR::Expr *rhs, IR::Expr *target) #if CPU(X86) if (IR::Const *c = rhs->asConst()) { // Y = X / constant -> Y = X; Y /= [constant-address] as->moveDouble(as->toDoubleRegister(lhs, targetReg), targetReg); - Assembler::Address addr = as->loadConstant(c, Assembler::ScratchRegister); + Address addr = as->loadConstant(c, Assembler::ScratchRegister); as->divDouble(addr, targetReg); break; } @@ -258,9 +258,9 @@ void Binop::doubleBinop(IR::Expr *lhs, IR::Expr *rhs, IR::Expr *target) default: { Q_ASSERT(target->type == IR::BoolType); - Assembler::Jump trueCase = as->branchDouble(false, op, lhs, rhs); + Jump trueCase = as->branchDouble(false, op, lhs, rhs); as->storeBool(false, target); - Assembler::Jump done = as->jump(); + Jump done = as->jump(); trueCase.link(as); as->storeBool(true, target); done.link(as); @@ -305,13 +305,13 @@ bool Binop::int32Binop(IR::Expr *leftSource, IR::Expr *rightSource, IR::Expr *ta bool inplaceOpWithAddress = false; IR::Temp *targetTemp = target->asTemp(); - Assembler::RegisterID targetReg = Assembler::ReturnValueRegister; + RegisterID targetReg = Assembler::ReturnValueRegister; if (targetTemp && targetTemp->kind == IR::Temp::PhysicalRegister) { IR::Temp *rhs = rightSource->asTemp(); if (!rhs || rhs->kind != IR::Temp::PhysicalRegister || rhs->index != targetTemp->index) { // 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. - targetReg = (Assembler::RegisterID) targetTemp->index; + targetReg = (RegisterID) targetTemp->index; } else if (rhs && rhs->kind == IR::Temp::PhysicalRegister && targetTemp->index == rhs->index) { // However, if the target register is the same as the rightSource register, we can flip // the operands for certain operations. @@ -323,7 +323,7 @@ bool Binop::int32Binop(IR::Expr *leftSource, IR::Expr *rightSource, IR::Expr *ta case IR::OpMul: // X = Y op X -> X = X op Y (or rephrased: X op= Y (so an in-place operation)) std::swap(leftSource, rightSource); - targetReg = (Assembler::RegisterID) targetTemp->index; + targetReg = (RegisterID) targetTemp->index; break; case IR::OpLShift: @@ -368,7 +368,7 @@ bool Binop::int32Binop(IR::Expr *leftSource, IR::Expr *rightSource, IR::Expr *ta && targetTemp->kind == IR::Temp::PhysicalRegister && targetTemp->index == rightSource->asTemp()->index) { // X = Y - X -> Tmp = X; X = Y; X -= Tmp - targetReg = (Assembler::RegisterID) targetTemp->index; + targetReg = (RegisterID) targetTemp->index; as->move(targetReg, Assembler::ScratchRegister); as->move(as->toInt32Register(leftSource, targetReg), targetReg); as->sub32(Assembler::ScratchRegister, targetReg); @@ -384,7 +384,7 @@ bool Binop::int32Binop(IR::Expr *leftSource, IR::Expr *rightSource, IR::Expr *ta case IR::OpURShift: if (IR::Const *c = rightSource->asConst()) { if ((QV4::Primitive::toUInt32(c->value) & 0x1f) == 0) { - Assembler::RegisterID r = as->toInt32Register(leftSource, targetReg); + RegisterID r = as->toInt32Register(leftSource, targetReg); as->storeInt32(r, target); return true; } @@ -395,10 +395,10 @@ bool Binop::int32Binop(IR::Expr *leftSource, IR::Expr *rightSource, IR::Expr *ta break; } - Assembler::RegisterID l = as->toInt32Register(leftSource, targetReg); + RegisterID l = as->toInt32Register(leftSource, targetReg); if (IR::Const *c = rightSource->asConst()) { // All cases of Y = X op Const - Assembler::TrustedImm32 r(int(c->value)); - Assembler::TrustedImm32 ur(QV4::Primitive::toUInt32(c->value) & 0x1f); + TrustedImm32 r(int(c->value)); + TrustedImm32 ur(QV4::Primitive::toUInt32(c->value) & 0x1f); switch (op) { case IR::OpBitAnd: as->and32(r, l, targetReg); break; @@ -419,7 +419,7 @@ bool Binop::int32Binop(IR::Expr *leftSource, IR::Expr *rightSource, IR::Expr *ta return false; } } else if (inplaceOpWithAddress) { // All cases of X = X op [address-of-Y] - Assembler::Pointer rhsAddr = as->loadAddress(Assembler::ScratchRegister, rightSource); + Pointer rhsAddr = as->loadAddress(Assembler::ScratchRegister, rightSource); switch (op) { case IR::OpBitAnd: as->and32(rhsAddr, targetReg); break; case IR::OpBitOr: as->or32 (rhsAddr, targetReg); break; @@ -433,7 +433,7 @@ bool Binop::int32Binop(IR::Expr *leftSource, IR::Expr *rightSource, IR::Expr *ta return false; } } else { // All cases of Z = X op Y - Assembler::RegisterID r = as->toInt32Register(rightSource, Assembler::ScratchRegister); + RegisterID r = as->toInt32Register(rightSource, Assembler::ScratchRegister); switch (op) { case IR::OpBitAnd: as->and32(l, r, targetReg); break; case IR::OpBitOr: as->or32 (l, r, targetReg); break; @@ -452,10 +452,10 @@ bool Binop::int32Binop(IR::Expr *leftSource, IR::Expr *rightSource, IR::Expr *ta // Not all CPUs accept shifts over more than 31 bits, and some CPUs (like ARM) will do // surprising stuff when shifting over 0 bits. #define CHECK_RHS(op) { \ - as->and32(Assembler::TrustedImm32(0x1f), r, Assembler::ScratchRegister); \ - Assembler::Jump notZero = as->branch32(Assembler::NotEqual, Assembler::ScratchRegister, Assembler::TrustedImm32(0)); \ + as->and32(TrustedImm32(0x1f), r, Assembler::ScratchRegister); \ + Jump notZero = as->branch32(RelationalCondition::NotEqual, Assembler::ScratchRegister, TrustedImm32(0)); \ as->move(l, targetReg); \ - Assembler::Jump done = as->jump(); \ + Jump done = as->jump(); \ notZero.link(as); \ op; \ done.link(as); \ @@ -493,7 +493,7 @@ static inline Assembler::FPRegisterID getFreeFPReg(IR::Expr *shouldNotOverlap, u Assembler::Jump Binop::genInlineBinop(IR::Expr *leftSource, IR::Expr *rightSource, IR::Expr *target) { - Assembler::Jump done; + Jump done; // Try preventing a call for a few common binary operations. This is used in two cases: // - no register allocation was performed (not available for the platform, or the IR was @@ -505,10 +505,10 @@ Assembler::Jump Binop::genInlineBinop(IR::Expr *leftSource, IR::Expr *rightSourc // register. switch (op) { case IR::OpAdd: { - Assembler::FPRegisterID lReg = getFreeFPReg(rightSource, 2); - Assembler::FPRegisterID rReg = getFreeFPReg(leftSource, 4); - Assembler::Jump leftIsNoDbl = as->genTryDoubleConversion(leftSource, lReg); - Assembler::Jump rightIsNoDbl = as->genTryDoubleConversion(rightSource, rReg); + FPRegisterID lReg = getFreeFPReg(rightSource, 2); + FPRegisterID rReg = getFreeFPReg(leftSource, 4); + Jump leftIsNoDbl = as->genTryDoubleConversion(leftSource, lReg); + Jump rightIsNoDbl = as->genTryDoubleConversion(rightSource, rReg); as->addDouble(rReg, lReg); as->storeDouble(lReg, target); @@ -520,10 +520,10 @@ Assembler::Jump Binop::genInlineBinop(IR::Expr *leftSource, IR::Expr *rightSourc rightIsNoDbl.link(as); } break; case IR::OpMul: { - Assembler::FPRegisterID lReg = getFreeFPReg(rightSource, 2); - Assembler::FPRegisterID rReg = getFreeFPReg(leftSource, 4); - Assembler::Jump leftIsNoDbl = as->genTryDoubleConversion(leftSource, lReg); - Assembler::Jump rightIsNoDbl = as->genTryDoubleConversion(rightSource, rReg); + FPRegisterID lReg = getFreeFPReg(rightSource, 2); + FPRegisterID rReg = getFreeFPReg(leftSource, 4); + Jump leftIsNoDbl = as->genTryDoubleConversion(leftSource, lReg); + Jump rightIsNoDbl = as->genTryDoubleConversion(rightSource, rReg); as->mulDouble(rReg, lReg); as->storeDouble(lReg, target); @@ -535,10 +535,10 @@ Assembler::Jump Binop::genInlineBinop(IR::Expr *leftSource, IR::Expr *rightSourc rightIsNoDbl.link(as); } break; case IR::OpSub: { - Assembler::FPRegisterID lReg = getFreeFPReg(rightSource, 2); - Assembler::FPRegisterID rReg = getFreeFPReg(leftSource, 4); - Assembler::Jump leftIsNoDbl = as->genTryDoubleConversion(leftSource, lReg); - Assembler::Jump rightIsNoDbl = as->genTryDoubleConversion(rightSource, rReg); + FPRegisterID lReg = getFreeFPReg(rightSource, 2); + FPRegisterID rReg = getFreeFPReg(leftSource, 4); + Jump leftIsNoDbl = as->genTryDoubleConversion(leftSource, lReg); + Jump rightIsNoDbl = as->genTryDoubleConversion(rightSource, rReg); as->subDouble(rReg, lReg); as->storeDouble(lReg, target); @@ -550,10 +550,10 @@ Assembler::Jump Binop::genInlineBinop(IR::Expr *leftSource, IR::Expr *rightSourc rightIsNoDbl.link(as); } break; case IR::OpDiv: { - Assembler::FPRegisterID lReg = getFreeFPReg(rightSource, 2); - Assembler::FPRegisterID rReg = getFreeFPReg(leftSource, 4); - Assembler::Jump leftIsNoDbl = as->genTryDoubleConversion(leftSource, lReg); - Assembler::Jump rightIsNoDbl = as->genTryDoubleConversion(rightSource, rReg); + FPRegisterID lReg = getFreeFPReg(rightSource, 2); + FPRegisterID rReg = getFreeFPReg(leftSource, 4); + Jump leftIsNoDbl = as->genTryDoubleConversion(leftSource, lReg); + Jump rightIsNoDbl = as->genTryDoubleConversion(rightSource, rReg); as->divDouble(rReg, lReg); as->storeDouble(lReg, target); diff --git a/src/qml/jit/qv4binop_p.h b/src/qml/jit/qv4binop_p.h index 37601f54ba..3742e99e5a 100644 --- a/src/qml/jit/qv4binop_p.h +++ b/src/qml/jit/qv4binop_p.h @@ -67,13 +67,23 @@ struct Binop { , op(operation) {} + using Jump = Assembler::Jump; + using Address = Assembler::Address; + using RegisterID = Assembler::RegisterID; + using FPRegisterID = Assembler::FPRegisterID; + using TrustedImm32 = Assembler::TrustedImm32; + using ResultCondition = Assembler::ResultCondition; + using RelationalCondition = Assembler::RelationalCondition; + using Pointer = Assembler::Pointer; + using PointerToValue = Assembler::PointerToValue; + 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); + 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); + typedef Jump (Binop::*MemRegOp)(Address, RegisterID); + typedef Jump (Binop::*ImmRegOp)(TrustedImm32, RegisterID); struct OpInfo { const char *name; @@ -88,97 +98,97 @@ struct Binop { static const OpInfo &operation(IR::AluOp operation) { return operations[operation]; } - Assembler::Jump inline_add32(Assembler::Address addr, Assembler::RegisterID reg) + Jump inline_add32(Address addr, RegisterID reg) { #if HAVE(ALU_OPS_WITH_MEM_OPERAND) - return as->branchAdd32(Assembler::Overflow, addr, reg); + return as->branchAdd32(ResultCondition::Overflow, addr, reg); #else as->load32(addr, Assembler::ScratchRegister); - return as->branchAdd32(Assembler::Overflow, Assembler::ScratchRegister, reg); + return as->branchAdd32(ResultCondition::Overflow, Assembler::ScratchRegister, reg); #endif } - Assembler::Jump inline_add32(Assembler::TrustedImm32 imm, Assembler::RegisterID reg) + Jump inline_add32(TrustedImm32 imm, RegisterID reg) { - return as->branchAdd32(Assembler::Overflow, imm, reg); + return as->branchAdd32(ResultCondition::Overflow, imm, reg); } - Assembler::Jump inline_sub32(Assembler::Address addr, Assembler::RegisterID reg) + Jump inline_sub32(Address addr, RegisterID reg) { #if HAVE(ALU_OPS_WITH_MEM_OPERAND) - return as->branchSub32(Assembler::Overflow, addr, reg); + return as->branchSub32(ResultCondition::Overflow, addr, reg); #else as->load32(addr, Assembler::ScratchRegister); - return as->branchSub32(Assembler::Overflow, Assembler::ScratchRegister, reg); + return as->branchSub32(ResultCondition::Overflow, Assembler::ScratchRegister, reg); #endif } - Assembler::Jump inline_sub32(Assembler::TrustedImm32 imm, Assembler::RegisterID reg) + Jump inline_sub32(TrustedImm32 imm, RegisterID reg) { - return as->branchSub32(Assembler::Overflow, imm, reg); + return as->branchSub32(ResultCondition::Overflow, imm, reg); } - Assembler::Jump inline_mul32(Assembler::Address addr, Assembler::RegisterID reg) + Jump inline_mul32(Address addr, RegisterID reg) { #if HAVE(ALU_OPS_WITH_MEM_OPERAND) return as->branchMul32(Assembler::Overflow, addr, reg); #else as->load32(addr, Assembler::ScratchRegister); - return as->branchMul32(Assembler::Overflow, Assembler::ScratchRegister, reg); + return as->branchMul32(ResultCondition::Overflow, Assembler::ScratchRegister, reg); #endif } - Assembler::Jump inline_mul32(Assembler::TrustedImm32 imm, Assembler::RegisterID reg) + Jump inline_mul32(TrustedImm32 imm, RegisterID reg) { - return as->branchMul32(Assembler::Overflow, imm, reg, reg); + return as->branchMul32(ResultCondition::Overflow, imm, reg, reg); } - Assembler::Jump inline_shl32(Assembler::Address addr, Assembler::RegisterID reg) + Jump inline_shl32(Address addr, RegisterID reg) { as->load32(addr, Assembler::ScratchRegister); - as->and32(Assembler::TrustedImm32(0x1f), Assembler::ScratchRegister); + as->and32(TrustedImm32(0x1f), Assembler::ScratchRegister); as->lshift32(Assembler::ScratchRegister, reg); - return Assembler::Jump(); + return Jump(); } - Assembler::Jump inline_shl32(Assembler::TrustedImm32 imm, Assembler::RegisterID reg) + Jump inline_shl32(TrustedImm32 imm, RegisterID reg) { imm.m_value &= 0x1f; as->lshift32(imm, reg); - return Assembler::Jump(); + return Jump(); } - Assembler::Jump inline_shr32(Assembler::Address addr, Assembler::RegisterID reg) + Jump inline_shr32(Address addr, RegisterID reg) { as->load32(addr, Assembler::ScratchRegister); - as->and32(Assembler::TrustedImm32(0x1f), Assembler::ScratchRegister); + as->and32(TrustedImm32(0x1f), Assembler::ScratchRegister); as->rshift32(Assembler::ScratchRegister, reg); - return Assembler::Jump(); + return Jump(); } - Assembler::Jump inline_shr32(Assembler::TrustedImm32 imm, Assembler::RegisterID reg) + Jump inline_shr32(TrustedImm32 imm, RegisterID reg) { imm.m_value &= 0x1f; as->rshift32(imm, reg); - return Assembler::Jump(); + return Jump(); } - Assembler::Jump inline_ushr32(Assembler::Address addr, Assembler::RegisterID reg) + Jump inline_ushr32(Address addr, RegisterID reg) { as->load32(addr, Assembler::ScratchRegister); - as->and32(Assembler::TrustedImm32(0x1f), Assembler::ScratchRegister); + as->and32(TrustedImm32(0x1f), Assembler::ScratchRegister); as->urshift32(Assembler::ScratchRegister, reg); - return as->branchTest32(Assembler::Signed, reg, reg); + return as->branchTest32(ResultCondition::Signed, reg, reg); } - Assembler::Jump inline_ushr32(Assembler::TrustedImm32 imm, Assembler::RegisterID reg) + Jump inline_ushr32(TrustedImm32 imm, RegisterID reg) { imm.m_value &= 0x1f; as->urshift32(imm, reg); - return as->branchTest32(Assembler::Signed, reg, reg); + return as->branchTest32(ResultCondition::Signed, reg, reg); } - Assembler::Jump inline_and32(Assembler::Address addr, Assembler::RegisterID reg) + Jump inline_and32(Address addr, RegisterID reg) { #if HAVE(ALU_OPS_WITH_MEM_OPERAND) as->and32(addr, reg); @@ -186,16 +196,16 @@ struct Binop { as->load32(addr, Assembler::ScratchRegister); as->and32(Assembler::ScratchRegister, reg); #endif - return Assembler::Jump(); + return Jump(); } - Assembler::Jump inline_and32(Assembler::TrustedImm32 imm, Assembler::RegisterID reg) + Jump inline_and32(TrustedImm32 imm, RegisterID reg) { as->and32(imm, reg); - return Assembler::Jump(); + return Jump(); } - Assembler::Jump inline_or32(Assembler::Address addr, Assembler::RegisterID reg) + Jump inline_or32(Address addr, RegisterID reg) { #if HAVE(ALU_OPS_WITH_MEM_OPERAND) as->or32(addr, reg); @@ -203,16 +213,16 @@ struct Binop { as->load32(addr, Assembler::ScratchRegister); as->or32(Assembler::ScratchRegister, reg); #endif - return Assembler::Jump(); + return Jump(); } - Assembler::Jump inline_or32(Assembler::TrustedImm32 imm, Assembler::RegisterID reg) + Jump inline_or32(TrustedImm32 imm, RegisterID reg) { as->or32(imm, reg); - return Assembler::Jump(); + return Jump(); } - Assembler::Jump inline_xor32(Assembler::Address addr, Assembler::RegisterID reg) + Jump inline_xor32(Address addr, RegisterID reg) { #if HAVE(ALU_OPS_WITH_MEM_OPERAND) as->xor32(addr, reg); @@ -220,13 +230,13 @@ struct Binop { as->load32(addr, Assembler::ScratchRegister); as->xor32(Assembler::ScratchRegister, reg); #endif - return Assembler::Jump(); + return Jump(); } - Assembler::Jump inline_xor32(Assembler::TrustedImm32 imm, Assembler::RegisterID reg) + Jump inline_xor32(TrustedImm32 imm, RegisterID reg) { as->xor32(imm, reg); - return Assembler::Jump(); + return Jump(); } diff --git a/src/qml/jit/qv4isel_masm.cpp b/src/qml/jit/qv4isel_masm.cpp index c5d612ae65..279ccabf81 100644 --- a/src/qml/jit/qv4isel_masm.cpp +++ b/src/qml/jit/qv4isel_masm.cpp @@ -68,175 +68,6 @@ using namespace QV4; using namespace QV4::JIT; -namespace { -class QIODevicePrintStream: public FilePrintStream -{ - Q_DISABLE_COPY(QIODevicePrintStream) - -public: - explicit QIODevicePrintStream(QIODevice *dest) - : FilePrintStream(0) - , dest(dest) - , buf(4096, '0') - { - Q_ASSERT(dest); - } - - ~QIODevicePrintStream() - {} - - void vprintf(const char* format, va_list argList) WTF_ATTRIBUTE_PRINTF(2, 0) - { - const int written = qvsnprintf(buf.data(), buf.size(), format, argList); - if (written > 0) - dest->write(buf.constData(), written); - memset(buf.data(), 0, qMin(written, buf.size())); - } - - void flush() - {} - -private: - QIODevice *dest; - QByteArray buf; -}; -} // anonymous namespace - -static void printDisassembledOutputWithCalls(QByteArray processedOutput, const QHash<void*, const char*>& functions) -{ - for (QHash<void*, const char*>::ConstIterator it = functions.begin(), end = functions.end(); - it != end; ++it) { - const QByteArray ptrString = "0x" + QByteArray::number(quintptr(it.key()), 16); - int idx = processedOutput.indexOf(ptrString); - if (idx < 0) - continue; - idx = processedOutput.lastIndexOf('\n', idx); - if (idx < 0) - continue; - processedOutput = processedOutput.insert(idx, QByteArrayLiteral(" ; call ") + it.value()); - } - - qDebug("%s", processedOutput.constData()); -} - -#if defined(Q_OS_LINUX) -static FILE *pmap; - -static void qt_closePmap() -{ - if (pmap) { - fclose(pmap); - pmap = 0; - } -} - -#endif - -JSC::MacroAssemblerCodeRef Assembler::link(int *codeSize) -{ - Label endOfCode = label(); - - { - for (size_t i = 0, ei = _patches.size(); i != ei; ++i) { - Label target = _addrs.at(i); - Q_ASSERT(target.isSet()); - for (Jump jump : qAsConst(_patches.at(i))) - jump.linkTo(target, this); - } - } - - JSC::JSGlobalData dummy(_executableAllocator); - JSC::LinkBuffer linkBuffer(dummy, this, 0); - - for (const DataLabelPatch &p : qAsConst(_dataLabelPatches)) - linkBuffer.patch(p.dataLabel, linkBuffer.locationOf(p.target)); - - // link exception handlers - for (Jump jump : qAsConst(exceptionPropagationJumps)) - linkBuffer.link(jump, linkBuffer.locationOf(exceptionReturnLabel)); - - { - for (size_t i = 0, ei = _labelPatches.size(); i != ei; ++i) { - Label target = _addrs.at(i); - Q_ASSERT(target.isSet()); - for (DataLabelPtr label : _labelPatches.at(i)) - linkBuffer.patch(label, linkBuffer.locationOf(target)); - } - } - - *codeSize = linkBuffer.offsetOf(endOfCode); - - QByteArray name; - - JSC::MacroAssemblerCodeRef codeRef; - - static const bool showCode = qEnvironmentVariableIsSet("QV4_SHOW_ASM"); - if (showCode) { - QHash<void*, const char*> functions; -#ifndef QT_NO_DEBUG - for (CallInfo call : qAsConst(_callInfos)) - functions[linkBuffer.locationOf(call.label).dataLocation()] = call.functionName; -#endif - - QBuffer buf; - buf.open(QIODevice::WriteOnly); - WTF::setDataFile(new QIODevicePrintStream(&buf)); - - name = _function->name->toUtf8(); - if (name.isEmpty()) - name = "IR::Function(0x" + QByteArray::number(quintptr(_function), 16) + ')'; - codeRef = linkBuffer.finalizeCodeWithDisassembly("%s", name.data()); - - WTF::setDataFile(stderr); - printDisassembledOutputWithCalls(buf.data(), functions); - } else { - codeRef = linkBuffer.finalizeCodeWithoutDisassembly(); - } - -#if defined(Q_OS_LINUX) - // This implements writing of JIT'd addresses so that perf can find the - // symbol names. - // - // Perf expects the mapping to be in a certain place and have certain - // content, for more information, see: - // https://github.com/torvalds/linux/blob/master/tools/perf/Documentation/jit-interface.txt - static bool doProfile = !qEnvironmentVariableIsEmpty("QV4_PROFILE_WRITE_PERF_MAP"); - static bool profileInitialized = false; - if (doProfile && !profileInitialized) { - profileInitialized = true; - - char pname[PATH_MAX]; - snprintf(pname, PATH_MAX - 1, "/tmp/perf-%lu.map", - (unsigned long)QCoreApplication::applicationPid()); - - pmap = fopen(pname, "w"); - if (!pmap) - qWarning("QV4: Can't write %s, call stacks will not contain JavaScript function names", pname); - - // make sure we clean up nicely - std::atexit(qt_closePmap); - } - - if (pmap) { - // this may have been pre-populated, if QV4_SHOW_ASM was on - if (name.isEmpty()) { - name = _function->name->toUtf8(); - if (name.isEmpty()) - name = "IR::Function(0x" + QByteArray::number(quintptr(_function), 16) + ')'; - } - - fprintf(pmap, "%llx %x %.*s\n", - (long long unsigned int)codeRef.code().executableAddress(), - *codeSize, - name.length(), - name.constData()); - fflush(pmap); - } -#endif - - return codeRef; -} - InstructionSelection::InstructionSelection(QQmlEnginePrivate *qmlEngine, QV4::ExecutableAllocator *execAllocator, IR::Module *module, Compiler::JSUnitGenerator *jsGenerator, EvalISelFactory *iselFactory) : EvalInstructionSelection(execAllocator, module, jsGenerator, iselFactory) , _block(0) @@ -278,7 +109,7 @@ void InstructionSelection::run(int functionIndex) qSwap(_removableJumps, removableJumps); Assembler* oldAssembler = _as; - _as = new Assembler(this, _function, executableAllocator); + _as = new Assembler(jsGenerator, _function, executableAllocator); _as->setStackLayout(6, // 6 == max argc for calls to built-ins with an argument array regularRegistersToSave.size(), fpRegistersToSave.size()); @@ -1881,6 +1712,13 @@ bool InstructionSelection::visitCJumpStrictBool(IR::Binop *binop, IR::BasicBlock // neither operands are statically typed as bool, so bail out. return false; } + if (otherSrc->type == IR::UnknownType) { + // Ok, we really need to call into the runtime. + // (This case doesn't happen when the optimizer ran, because everything will be typed (yes, + // possibly as "var" meaning anything), but it does happen for $0===true, which is generated + // for things where the optimizer didn't run (like functions with a try block).) + return false; + } Assembler::RelationalCondition cond = binop->op == IR::OpStrictEqual ? Assembler::Equal : Assembler::NotEqual; diff --git a/src/qml/jit/qv4regalloc.cpp b/src/qml/jit/qv4regalloc.cpp index 63d542b5c8..f2ae7e117a 100644 --- a/src/qml/jit/qv4regalloc.cpp +++ b/src/qml/jit/qv4regalloc.cpp @@ -973,7 +973,15 @@ private: break; Q_ASSERT(!i->isFixedInterval()); - _liveIntervals.push_back(i); + auto it = _liveIntervals.begin(); + for (; it != _liveIntervals.end(); ++it) { + if ((*it)->temp() == i->temp()) { + *it = i; + break; + } + } + if (it == _liveIntervals.end()) + _liveIntervals.push_back(i); // qDebug() << "-- Activating interval for temp" << i->temp().index; _unprocessedReverseOrder.removeLast(); @@ -1087,12 +1095,12 @@ private: if (_info->def(it->temp()) != successorStart && !it->isSplitFromInterval()) { const int successorEnd = successor->terminator()->id(); const int idx = successor->in.indexOf(predecessor); - foreach (const Use &use, _info->uses(it->temp())) { + for (const Use &use : _info->uses(it->temp)) { if (use.pos == static_cast<unsigned>(successorStart)) { // only check the current edge, not all other possible ones. This is // important for phi nodes: they have uses that are only valid when // coming in over a specific edge. - foreach (Stmt *s, successor->statements()) { + for (Stmt *s : successor->statements()) { if (Phi *phi = s->asPhi()) { Q_ASSERT(it->temp().index != phi->targetTemp->index); Q_ASSERT(phi->d->incoming[idx]->asTemp() == 0 diff --git a/src/qml/jsapi/qjsvalue.cpp b/src/qml/jsapi/qjsvalue.cpp index b473e96286..bab2e633a7 100644 --- a/src/qml/jsapi/qjsvalue.cpp +++ b/src/qml/jsapi/qjsvalue.cpp @@ -73,7 +73,8 @@ For the object-based types (including Date and RegExp), use the newT() functions in QJSEngine (e.g. QJSEngine::newObject()) to create a QJSValue of the desired type. For the primitive types, - use one of the QJSValue constructor overloads. + use one of the QJSValue constructor overloads. For other types, e.g. + registered gadget types such as QPoint, you can use QJSEngine::toScriptValue. The methods named isT() (e.g. isBool(), isUndefined()) can be used to test if a value is of a certain type. The methods named diff --git a/src/qml/jsruntime/qv4argumentsobject.cpp b/src/qml/jsruntime/qv4argumentsobject.cpp index 5a190d6690..9354bcb1a3 100644 --- a/src/qml/jsruntime/qv4argumentsobject.cpp +++ b/src/qml/jsruntime/qv4argumentsobject.cpp @@ -88,10 +88,12 @@ void ArgumentsObject::fullyCreate() Scope scope(engine()); Scoped<MemberData> md(scope, d()->mappedArguments); - d()->mappedArguments = md->allocate(engine(), numAccessors); - for (uint i = 0; i < numAccessors; ++i) { - d()->mappedArguments->data[i] = context()->callData->args[i]; - arraySet(i, context()->engine->argumentsAccessors + i, Attr_Accessor); + if (numAccessors) { + d()->mappedArguments = md->allocate(engine(), numAccessors); + for (uint i = 0; i < numAccessors; ++i) { + d()->mappedArguments->data[i] = context()->callData->args[i]; + arraySet(i, context()->engine->argumentsAccessors + i, Attr_Accessor); + } } arrayPut(numAccessors, context()->callData->args + numAccessors, argCount - numAccessors); for (uint i = numAccessors; i < argCount; ++i) diff --git a/src/qml/jsruntime/qv4arraybuffer.cpp b/src/qml/jsruntime/qv4arraybuffer.cpp index 23075aa78c..ffe9aa846f 100644 --- a/src/qml/jsruntime/qv4arraybuffer.cpp +++ b/src/qml/jsruntime/qv4arraybuffer.cpp @@ -81,16 +81,19 @@ void ArrayBufferCtor::call(const Managed *that, Scope &scope, CallData *callData construct(that, scope, callData); } -ReturnedValue ArrayBufferCtor::method_isView(CallContext *ctx) +void ArrayBufferCtor::method_isView(const BuiltinFunction *, Scope &scope, CallData *callData) { - QV4::Scope scope(ctx); - QV4::Scoped<TypedArray> a(scope, ctx->argument(0)); - if (!!a) - return Encode(true); - QV4::Scoped<DataView> v(scope, ctx->argument(0)); - if (!!v) - return Encode(true); - return Encode(false); + QV4::Scoped<TypedArray> a(scope, callData->argument(0)); + if (!!a) { + scope.result = Encode(true); + return; + } + QV4::Scoped<DataView> v(scope, callData->argument(0)); + if (!!v) { + scope.result = Encode(true); + return; + } + scope.result = Encode(false); } @@ -160,54 +163,48 @@ void ArrayBufferPrototype::init(ExecutionEngine *engine, Object *ctor) defineDefaultProperty(QStringLiteral("toString"), method_toString, 0); } -ReturnedValue ArrayBufferPrototype::method_get_byteLength(CallContext *ctx) +void ArrayBufferPrototype::method_get_byteLength(const BuiltinFunction *, Scope &scope, CallData *callData) { - Scope scope(ctx); - Scoped<ArrayBuffer> v(scope, ctx->thisObject()); + Scoped<ArrayBuffer> v(scope, callData->thisObject); if (!v) - return scope.engine->throwTypeError(); + THROW_TYPE_ERROR(); - return Encode(v->d()->data->size); + scope.result = Encode(v->d()->data->size); } -ReturnedValue ArrayBufferPrototype::method_slice(CallContext *ctx) +void ArrayBufferPrototype::method_slice(const BuiltinFunction *, Scope &scope, CallData *callData) { - Scope scope(ctx); - Scoped<ArrayBuffer> a(scope, ctx->thisObject()); + Scoped<ArrayBuffer> a(scope, callData->thisObject); if (!a) - return scope.engine->throwTypeError(); + THROW_TYPE_ERROR(); - double start = ctx->argc() > 0 ? ctx->args()[0].toInteger() : 0; - double end = (ctx->argc() < 2 || ctx->args()[1].isUndefined()) ? - a->d()->data->size : ctx->args()[1].toInteger(); - if (scope.engine->hasException) - return Encode::undefined(); + double start = callData->argc > 0 ? callData->args[0].toInteger() : 0; + double end = (callData->argc < 2 || callData->args[1].isUndefined()) ? + a->d()->data->size : callData->args[1].toInteger(); + CHECK_EXCEPTION(); double first = (start < 0) ? qMax(a->d()->data->size + start, 0.) : qMin(start, (double)a->d()->data->size); double final = (end < 0) ? qMax(a->d()->data->size + end, 0.) : qMin(end, (double)a->d()->data->size); ScopedFunctionObject constructor(scope, a->get(scope.engine->id_constructor())); if (!constructor) - return scope.engine->throwTypeError(); + THROW_TYPE_ERROR(); - ScopedCallData callData(scope, 1); + ScopedCallData cData(scope, 1); double newLen = qMax(final - first, 0.); - callData->args[0] = QV4::Encode(newLen); - constructor->construct(scope, callData); - QV4::Scoped<ArrayBuffer> newBuffer(scope, scope.result.asReturnedValue()); + cData->args[0] = QV4::Encode(newLen); + constructor->construct(scope, cData); + QV4::Scoped<ArrayBuffer> newBuffer(scope, scope.result); if (!newBuffer || newBuffer->d()->data->size < (int)newLen) - return scope.engine->throwTypeError(); + THROW_TYPE_ERROR(); memcpy(newBuffer->d()->data->data(), a->d()->data->data() + (uint)first, newLen); - - return newBuffer.asReturnedValue(); } -ReturnedValue ArrayBufferPrototype::method_toString(CallContext *ctx) +void ArrayBufferPrototype::method_toString(const BuiltinFunction *, Scope &scope, CallData *callData) { - Scope scope(ctx); - Scoped<ArrayBuffer> a(scope, ctx->thisObject()); + Scoped<ArrayBuffer> a(scope, callData->thisObject); if (!a) - return Encode::undefined(); - return Encode(ctx->engine()->newString(QString::fromUtf8(a->asByteArray()))); + RETURN_UNDEFINED(); + scope.result = scope.engine->newString(QString::fromUtf8(a->asByteArray())); } diff --git a/src/qml/jsruntime/qv4arraybuffer_p.h b/src/qml/jsruntime/qv4arraybuffer_p.h index bc56d1ea31..4f7926d3dc 100644 --- a/src/qml/jsruntime/qv4arraybuffer_p.h +++ b/src/qml/jsruntime/qv4arraybuffer_p.h @@ -81,7 +81,7 @@ struct ArrayBufferCtor: FunctionObject static void construct(const Managed *m, Scope &scope, CallData *callData); static void call(const Managed *that, Scope &scope, CallData *callData); - static ReturnedValue method_isView(CallContext *ctx); + static void method_isView(const BuiltinFunction *, Scope &scope, CallData *callData); }; @@ -104,9 +104,9 @@ struct ArrayBufferPrototype: Object { void init(ExecutionEngine *engine, Object *ctor); - static ReturnedValue method_get_byteLength(CallContext *ctx); - static ReturnedValue method_slice(CallContext *ctx); - static ReturnedValue method_toString(CallContext *ctx); + static void method_get_byteLength(const BuiltinFunction *, Scope &scope, CallData *callData); + static void method_slice(const BuiltinFunction *, Scope &scope, CallData *callData); + static void method_toString(const BuiltinFunction *, Scope &scope, CallData *callData); }; diff --git a/src/qml/jsruntime/qv4arraydata.cpp b/src/qml/jsruntime/qv4arraydata.cpp index bfeb3d4699..d8a7de5466 100644 --- a/src/qml/jsruntime/qv4arraydata.cpp +++ b/src/qml/jsruntime/qv4arraydata.cpp @@ -237,8 +237,14 @@ void ArrayData::ensureAttributes(Object *o) void SimpleArrayData::markObjects(Heap::Base *d, ExecutionEngine *e) { Heap::SimpleArrayData *dd = static_cast<Heap::SimpleArrayData *>(d); - for (uint i = 0; i < dd->len; ++i) - dd->arrayData[dd->mappedIndex(i)].mark(e); + uint end = dd->offset + dd->len; + if (end > dd->alloc) { + for (uint i = 0; i < end - dd->alloc; ++i) + dd->arrayData[i].mark(e); + end = dd->alloc; + } + for (uint i = dd->offset; i < end; ++i) + dd->arrayData[i].mark(e); } ReturnedValue SimpleArrayData::get(const Heap::ArrayData *d, uint index) diff --git a/src/qml/jsruntime/qv4arrayobject.cpp b/src/qml/jsruntime/qv4arrayobject.cpp index 20ba11fd75..759354f4e2 100644 --- a/src/qml/jsruntime/qv4arrayobject.cpp +++ b/src/qml/jsruntime/qv4arrayobject.cpp @@ -44,6 +44,7 @@ #include "qv4argumentsobject_p.h" #include "qv4runtime_p.h" #include "qv4string_p.h" +#include <QtCore/qscopedvaluerollback.h> using namespace QV4; @@ -118,42 +119,40 @@ void ArrayPrototype::init(ExecutionEngine *engine, Object *ctor) defineDefaultProperty(QStringLiteral("reduceRight"), method_reduceRight, 1); } -ReturnedValue ArrayPrototype::method_isArray(CallContext *ctx) +void ArrayPrototype::method_isArray(const BuiltinFunction *, Scope &scope, CallData *callData) { - bool isArray = ctx->argc() && ctx->args()[0].as<ArrayObject>(); - return Encode(isArray); + bool isArray = callData->argc && callData->args[0].as<ArrayObject>(); + scope.result = Encode(isArray); } -ReturnedValue ArrayPrototype::method_toString(CallContext *ctx) +void ArrayPrototype::method_toString(const BuiltinFunction *builtin, Scope &scope, CallData *callData) { - Scope scope(ctx); - ScopedObject o(scope, ctx->thisObject(), ScopedObject::Convert); - if (ctx->d()->engine->hasException) - return Encode::undefined(); - ScopedString s(scope, ctx->d()->engine->newString(QStringLiteral("join"))); + ScopedObject o(scope, callData->thisObject, ScopedObject::Convert); + CHECK_EXCEPTION(); + ScopedString s(scope, scope.engine->newString(QStringLiteral("join"))); ScopedFunctionObject f(scope, o->get(s)); if (!!f) { ScopedCallData d(scope, 0); - d->thisObject = ctx->thisObject(); + d->thisObject = callData->thisObject; f->call(scope, d); - return scope.result.asReturnedValue(); + return; } - return ObjectPrototype::method_toString(ctx); + ObjectPrototype::method_toString(builtin, scope, callData); } -ReturnedValue ArrayPrototype::method_toLocaleString(CallContext *ctx) +void ArrayPrototype::method_toLocaleString(const BuiltinFunction *builtin, Scope &scope, CallData *callData) { - return method_toString(ctx); + return method_toString(builtin, scope, callData); } -ReturnedValue ArrayPrototype::method_concat(CallContext *ctx) +void ArrayPrototype::method_concat(const BuiltinFunction *, Scope &scope, CallData *callData) { - Scope scope(ctx); - ScopedObject result(scope, ctx->d()->engine->newArrayObject()); - - ScopedObject thisObject(scope, ctx->thisObject().toObject(scope.engine)); + ScopedObject thisObject(scope, callData->thisObject.toObject(scope.engine)); if (!thisObject) - return Encode::undefined(); + RETURN_UNDEFINED(); + + ScopedArrayObject result(scope, scope.engine->newArrayObject()); + if (thisObject->isArrayObject()) { result->copyArrayData(thisObject); } else { @@ -163,9 +162,9 @@ ReturnedValue ArrayPrototype::method_concat(CallContext *ctx) ScopedArrayObject elt(scope); ScopedObject eltAsObj(scope); ScopedValue entry(scope); - for (int i = 0; i < ctx->argc(); ++i) { - eltAsObj = ctx->args()[i]; - elt = ctx->args()[i]; + for (int i = 0; i < callData->argc; ++i) { + eltAsObj = callData->args[i]; + elt = callData->args[i]; if (elt) { uint n = elt->getLength(); uint newLen = ArrayData::append(result, elt, n); @@ -177,95 +176,90 @@ ReturnedValue ArrayPrototype::method_concat(CallContext *ctx) result->putIndexed(startIndex + i, entry); } } else { - result->arraySet(result->getLength(), ctx->args()[i]); + result->arraySet(result->getLength(), callData->args[i]); } } - return result.asReturnedValue(); + scope.result = result; } -ReturnedValue ArrayPrototype::method_find(CallContext *ctx) +void ArrayPrototype::method_find(const BuiltinFunction *, Scope &scope, CallData *callData) { - Scope scope(ctx); - ScopedObject instance(scope, ctx->thisObject().toObject(scope.engine)); + ScopedObject instance(scope, callData->thisObject.toObject(scope.engine)); if (!instance) - return Encode::undefined(); + RETURN_UNDEFINED(); uint len = instance->getLength(); - ScopedFunctionObject callback(scope, ctx->argument(0)); + ScopedFunctionObject callback(scope, callData->argument(0)); if (!callback) - return ctx->engine()->throwTypeError(); + THROW_TYPE_ERROR(); - ScopedCallData callData(scope, 3); - callData->thisObject = ctx->argument(1); - callData->args[2] = instance; + ScopedCallData cData(scope, 3); + cData->thisObject = callData->argument(1); + cData->args[2] = instance; ScopedValue v(scope); for (uint k = 0; k < len; ++k) { v = instance->getIndexed(k); - if (scope.hasException()) - return Encode::undefined(); + CHECK_EXCEPTION(); - callData->args[0] = v; - callData->args[1] = Primitive::fromDouble(k); - callback->call(scope, callData); + cData->args[0] = v; + cData->args[1] = Primitive::fromDouble(k); + callback->call(scope, cData); - if (scope.hasException()) - return Encode::undefined(); - else if (scope.result.toBoolean()) - return v->asReturnedValue(); + CHECK_EXCEPTION(); + if (scope.result.toBoolean()) + RETURN_RESULT(v); } - return Encode::undefined(); + RETURN_UNDEFINED(); } -ReturnedValue ArrayPrototype::method_findIndex(CallContext *ctx) +void ArrayPrototype::method_findIndex(const BuiltinFunction *, Scope &scope, CallData *callData) { - Scope scope(ctx); - ScopedObject instance(scope, ctx->thisObject().toObject(scope.engine)); + ScopedObject instance(scope, callData->thisObject.toObject(scope.engine)); if (!instance) - return Encode::undefined(); + RETURN_UNDEFINED(); uint len = instance->getLength(); - ScopedFunctionObject callback(scope, ctx->argument(0)); + ScopedFunctionObject callback(scope, callData->argument(0)); if (!callback) - return ctx->engine()->throwTypeError(); + THROW_TYPE_ERROR(); - ScopedCallData callData(scope, 3); - callData->thisObject = ctx->argument(1); - callData->args[2] = instance; + ScopedCallData cData(scope, 3); + cData->thisObject = callData->argument(1); + cData->args[2] = instance; ScopedValue v(scope); for (uint k = 0; k < len; ++k) { v = instance->getIndexed(k); - if (scope.hasException()) - return Encode::undefined(); + CHECK_EXCEPTION(); - callData->args[0] = v; - callData->args[1] = Primitive::fromDouble(k); - callback->call(scope, callData); + cData->args[0] = v; + cData->args[1] = Primitive::fromDouble(k); + callback->call(scope, cData); - if (scope.hasException()) - return Encode::undefined(); - else if (scope.result.toBoolean()) - return Encode(k); + CHECK_EXCEPTION(); + if (scope.result.toBoolean()) + RETURN_RESULT(Encode(k)); } - return Encode(-1); + RETURN_RESULT(Encode(-1)); } -ReturnedValue ArrayPrototype::method_join(CallContext *ctx) +void ArrayPrototype::method_join(const BuiltinFunction *, Scope &scope, CallData *callData) { - Scope scope(ctx); - ScopedValue arg(scope, ctx->argument(0)); - ScopedObject instance(scope, ctx->thisObject().toObject(scope.engine)); + ScopedValue arg(scope, callData->argument(0)); + ScopedObject instance(scope, callData->thisObject.toObject(scope.engine)); - if (!instance) - return ctx->d()->engine->newString()->asReturnedValue(); + if (!instance) { + scope.result = scope.engine->newString(); + return; + } QString r4; if (arg->isUndefined()) @@ -273,11 +267,13 @@ ReturnedValue ArrayPrototype::method_join(CallContext *ctx) else r4 = arg->toQString(); - ScopedValue length(scope, instance->get(ctx->d()->engine->id_length())); + ScopedValue length(scope, instance->get(scope.engine->id_length())); const quint32 r2 = length->isUndefined() ? 0 : length->toUInt32(); - if (!r2) - return ctx->d()->engine->newString()->asReturnedValue(); + if (!r2) { + scope.result = scope.engine->newString(); + return; + } QString R; @@ -289,8 +285,7 @@ ReturnedValue ArrayPrototype::method_join(CallContext *ctx) R += r4; e = a->getIndexed(i); - if (scope.hasException()) - return Encode::undefined(); + CHECK_EXCEPTION(); if (!e->isNullOrUndefined()) R += e->toQString(); } @@ -298,7 +293,7 @@ ReturnedValue ArrayPrototype::method_join(CallContext *ctx) // // crazy! // - ScopedString name(scope, ctx->d()->engine->newString(QStringLiteral("0"))); + ScopedString name(scope, scope.engine->newString(QStringLiteral("0"))); ScopedValue r6(scope, instance->get(name)); if (!r6->isNullOrUndefined()) R = r6->toQString(); @@ -309,99 +304,98 @@ ReturnedValue ArrayPrototype::method_join(CallContext *ctx) name = Primitive::fromDouble(k).toString(scope.engine); r12 = instance->get(name); - if (scope.hasException()) - return Encode::undefined(); + CHECK_EXCEPTION(); if (!r12->isNullOrUndefined()) R += r12->toQString(); } } - return ctx->d()->engine->newString(R)->asReturnedValue(); + scope.result = scope.engine->newString(R); } -ReturnedValue ArrayPrototype::method_pop(CallContext *ctx) +void ArrayPrototype::method_pop(const BuiltinFunction *, Scope &scope, CallData *callData) { - Scope scope(ctx); - ScopedObject instance(scope, ctx->thisObject().toObject(scope.engine)); + ScopedObject instance(scope, callData->thisObject.toObject(scope.engine)); if (!instance) - return Encode::undefined(); + RETURN_UNDEFINED(); + uint len = instance->getLength(); if (!len) { if (!instance->isArrayObject()) - instance->put(ctx->d()->engine->id_length(), ScopedValue(scope, Primitive::fromInt32(0))); - return Encode::undefined(); + instance->put(scope.engine->id_length(), ScopedValue(scope, Primitive::fromInt32(0))); + RETURN_UNDEFINED(); } ScopedValue result(scope, instance->getIndexed(len - 1)); - if (scope.hasException()) - return Encode::undefined(); + CHECK_EXCEPTION(); instance->deleteIndexedProperty(len - 1); - if (scope.hasException()) - return Encode::undefined(); + CHECK_EXCEPTION(); + if (instance->isArrayObject()) instance->setArrayLength(len - 1); else - instance->put(ctx->d()->engine->id_length(), ScopedValue(scope, Primitive::fromDouble(len - 1))); - return result->asReturnedValue(); + instance->put(scope.engine->id_length(), ScopedValue(scope, Primitive::fromDouble(len - 1))); + scope.result = result; } -ReturnedValue ArrayPrototype::method_push(CallContext *ctx) +void ArrayPrototype::method_push(const BuiltinFunction *, Scope &scope, CallData *callData) { - Scope scope(ctx); - ScopedObject instance(scope, ctx->thisObject().toObject(scope.engine)); + ScopedObject instance(scope, callData->thisObject.toObject(scope.engine)); if (!instance) - return Encode::undefined(); + RETURN_UNDEFINED(); instance->arrayCreate(); Q_ASSERT(instance->arrayData()); uint len = instance->getLength(); - if (len + ctx->argc() < len) { + if (len + callData->argc < len) { // ughh... double l = len; ScopedString s(scope); - for (int i = 0; i < ctx->argc(); ++i) { + for (int i = 0; i < callData->argc; ++i) { s = Primitive::fromDouble(l + i).toString(scope.engine); - instance->put(s, ctx->args()[i]); + instance->put(s, callData->args[i]); } - double newLen = l + ctx->argc(); + double newLen = l + callData->argc; if (!instance->isArrayObject()) - instance->put(ctx->d()->engine->id_length(), ScopedValue(scope, Primitive::fromDouble(newLen))); + instance->put(scope.engine->id_length(), ScopedValue(scope, Primitive::fromDouble(newLen))); else { - ScopedString str(scope, ctx->d()->engine->newString(QStringLiteral("Array.prototype.push: Overflow"))); - return ctx->engine()->throwRangeError(str); + ScopedString str(scope, scope.engine->newString(QStringLiteral("Array.prototype.push: Overflow"))); + scope.result = scope.engine->throwRangeError(str); + return; } - return Encode(newLen); + scope.result = Encode(newLen); + return; } - if (!ctx->argc()) + if (!callData->argc) ; else if (!instance->protoHasArray() && instance->arrayData()->length() <= len && instance->arrayData()->type == Heap::ArrayData::Simple) { - instance->arrayData()->vtable()->putArray(instance, len, ctx->args(), ctx->argc()); + instance->arrayData()->vtable()->putArray(instance, len, callData->args, callData->argc); len = instance->arrayData()->length(); } else { - for (int i = 0; i < ctx->argc(); ++i) - instance->putIndexed(len + i, ctx->args()[i]); - len += ctx->argc(); + for (int i = 0; i < callData->argc; ++i) + instance->putIndexed(len + i, callData->args[i]); + len += callData->argc; } if (instance->isArrayObject()) instance->setArrayLengthUnchecked(len); else - instance->put(ctx->d()->engine->id_length(), ScopedValue(scope, Primitive::fromDouble(len))); + instance->put(scope.engine->id_length(), ScopedValue(scope, Primitive::fromDouble(len))); - return Encode(len); + scope.result = Encode(len); } -ReturnedValue ArrayPrototype::method_reverse(CallContext *ctx) +void ArrayPrototype::method_reverse(const BuiltinFunction *, Scope &scope, CallData *callData) { - Scope scope(ctx); - ScopedObject instance(scope, ctx->thisObject().toObject(scope.engine)); + ScopedObject instance(scope, callData->thisObject.toObject(scope.engine)); if (!instance) - return Encode::undefined(); + RETURN_UNDEFINED(); + uint length = instance->getLength(); int lo = 0, hi = length - 1; @@ -412,28 +406,25 @@ ReturnedValue ArrayPrototype::method_reverse(CallContext *ctx) bool loExists, hiExists; lval = instance->getIndexed(lo, &loExists); hval = instance->getIndexed(hi, &hiExists); - if (scope.hasException()) - return Encode::undefined(); + CHECK_EXCEPTION(); if (hiExists) instance->putIndexed(lo, hval); else instance->deleteIndexedProperty(lo); - if (scope.hasException()) - return Encode::undefined(); + CHECK_EXCEPTION(); if (loExists) instance->putIndexed(hi, lval); else instance->deleteIndexedProperty(hi); } - return instance.asReturnedValue(); + scope.result = instance; } -ReturnedValue ArrayPrototype::method_shift(CallContext *ctx) +void ArrayPrototype::method_shift(const BuiltinFunction *, Scope &scope, CallData *callData) { - Scope scope(ctx); - ScopedObject instance(scope, ctx->thisObject().toObject(scope.engine)); + ScopedObject instance(scope, callData->thisObject.toObject(scope.engine)); if (!instance) - return Encode::undefined(); + RETURN_UNDEFINED(); instance->arrayCreate(); Q_ASSERT(instance->arrayData()); @@ -442,54 +433,46 @@ ReturnedValue ArrayPrototype::method_shift(CallContext *ctx) if (!len) { if (!instance->isArrayObject()) - instance->put(ctx->d()->engine->id_length(), ScopedValue(scope, Primitive::fromInt32(0))); - return Encode::undefined(); + instance->put(scope.engine->id_length(), ScopedValue(scope, Primitive::fromInt32(0))); + RETURN_UNDEFINED(); } - ScopedValue result(scope); - if (!instance->protoHasArray() && !instance->arrayData()->attrs && instance->arrayData()->length() <= len && instance->arrayData()->type != Heap::ArrayData::Custom) { - result = instance->arrayData()->vtable()->pop_front(instance); + scope.result = instance->arrayData()->vtable()->pop_front(instance); } else { - result = instance->getIndexed(0); - if (scope.hasException()) - return Encode::undefined(); + scope.result = instance->getIndexed(0); + CHECK_EXCEPTION(); ScopedValue v(scope); // do it the slow way for (uint k = 1; k < len; ++k) { bool exists; v = instance->getIndexed(k, &exists); - if (scope.hasException()) - return Encode::undefined(); + CHECK_EXCEPTION(); if (exists) instance->putIndexed(k - 1, v); else instance->deleteIndexedProperty(k - 1); - if (scope.hasException()) - return Encode::undefined(); + CHECK_EXCEPTION(); } instance->deleteIndexedProperty(len - 1); - if (scope.hasException()) - return Encode::undefined(); + CHECK_EXCEPTION(); } if (instance->isArrayObject()) instance->setArrayLengthUnchecked(len - 1); else - instance->put(ctx->d()->engine->id_length(), ScopedValue(scope, Primitive::fromDouble(len - 1))); - return result->asReturnedValue(); + instance->put(scope.engine->id_length(), ScopedValue(scope, Primitive::fromDouble(len - 1))); } -ReturnedValue ArrayPrototype::method_slice(CallContext *ctx) +void ArrayPrototype::method_slice(const BuiltinFunction *, Scope &scope, CallData *callData) { - Scope scope(ctx); - ScopedObject o(scope, ctx->thisObject().toObject(scope.engine)); + ScopedObject o(scope, callData->thisObject.toObject(scope.engine)); if (!o) - return Encode::undefined(); + RETURN_UNDEFINED(); - ScopedArrayObject result(scope, ctx->d()->engine->newArrayObject()); + ScopedArrayObject result(scope, scope.engine->newArrayObject()); uint len = o->getLength(); - double s = ScopedValue(scope, ctx->argument(0))->toInteger(); + double s = ScopedValue(scope, callData->argument(0))->toInteger(); uint start; if (s < 0) start = (uint)qMax(len + s, 0.); @@ -498,8 +481,8 @@ ReturnedValue ArrayPrototype::method_slice(CallContext *ctx) else start = (uint) s; uint end = len; - if (ctx->argc() > 1 && !ctx->args()[1].isUndefined()) { - double e = ctx->args()[1].toInteger(); + if (callData->argc > 1 && !callData->args[1].isUndefined()) { + double e = callData->args[1].toInteger(); if (e < 0) end = (uint)qMax(len + e, 0.); else if (e > len) @@ -513,115 +496,107 @@ ReturnedValue ArrayPrototype::method_slice(CallContext *ctx) for (uint i = start; i < end; ++i) { bool exists; v = o->getIndexed(i, &exists); - if (scope.hasException()) - return Encode::undefined(); + CHECK_EXCEPTION(); if (exists) result->arraySet(n, v); ++n; } - return result.asReturnedValue(); + scope.result = result; } -ReturnedValue ArrayPrototype::method_sort(CallContext *ctx) +void ArrayPrototype::method_sort(const BuiltinFunction *, Scope &scope, CallData *callData) { - Scope scope(ctx); - ScopedObject instance(scope, ctx->thisObject().toObject(scope.engine)); + ScopedObject instance(scope, callData->thisObject.toObject(scope.engine)); if (!instance) - return Encode::undefined(); + RETURN_UNDEFINED(); uint len = instance->getLength(); - ScopedValue comparefn(scope, ctx->argument(0)); + ScopedValue comparefn(scope, callData->argument(0)); ArrayData::sort(scope.engine, instance, comparefn, len); - return ctx->thisObject().asReturnedValue(); + scope.result = callData->thisObject; } -ReturnedValue ArrayPrototype::method_splice(CallContext *ctx) +void ArrayPrototype::method_splice(const BuiltinFunction *, Scope &scope, CallData *callData) { - Scope scope(ctx); - ScopedObject instance(scope, ctx->thisObject().toObject(scope.engine)); + ScopedObject instance(scope, callData->thisObject.toObject(scope.engine)); if (!instance) - return Encode::undefined(); + RETURN_UNDEFINED(); + uint len = instance->getLength(); - ScopedArrayObject newArray(scope, ctx->d()->engine->newArrayObject()); + ScopedArrayObject newArray(scope, scope.engine->newArrayObject()); - double rs = ScopedValue(scope, ctx->argument(0))->toInteger(); + double rs = ScopedValue(scope, callData->argument(0))->toInteger(); uint start; if (rs < 0) start = (uint) qMax(0., len + rs); else start = (uint) qMin(rs, (double)len); - uint deleteCount = (uint)qMin(qMax(ScopedValue(scope, ctx->argument(1))->toInteger(), 0.), (double)(len - start)); + uint deleteCount = (uint)qMin(qMax(ScopedValue(scope, callData->argument(1))->toInteger(), 0.), (double)(len - start)); newArray->arrayReserve(deleteCount); ScopedValue v(scope); for (uint i = 0; i < deleteCount; ++i) { bool exists; v = instance->getIndexed(start + i, &exists); - if (scope.hasException()) - return Encode::undefined(); + CHECK_EXCEPTION(); if (exists) newArray->arrayPut(i, v); } newArray->setArrayLengthUnchecked(deleteCount); - uint itemCount = ctx->argc() < 2 ? 0 : ctx->argc() - 2; + uint itemCount = callData->argc < 2 ? 0 : callData->argc - 2; if (itemCount < deleteCount) { for (uint k = start; k < len - deleteCount; ++k) { bool exists; v = instance->getIndexed(k + deleteCount, &exists); - if (scope.hasException()) - return Encode::undefined(); + CHECK_EXCEPTION(); if (exists) instance->putIndexed(k + itemCount, v); else instance->deleteIndexedProperty(k + itemCount); - if (scope.hasException()) - return Encode::undefined(); + CHECK_EXCEPTION(); } for (uint k = len; k > len - deleteCount + itemCount; --k) { instance->deleteIndexedProperty(k - 1); - if (scope.hasException()) - return Encode::undefined(); + CHECK_EXCEPTION(); } } else if (itemCount > deleteCount) { uint k = len - deleteCount; while (k > start) { bool exists; v = instance->getIndexed(k + deleteCount - 1, &exists); - if (scope.hasException()) - return Encode::undefined(); + CHECK_EXCEPTION(); if (exists) instance->putIndexed(k + itemCount - 1, v); else instance->deleteIndexedProperty(k + itemCount - 1); - if (scope.hasException()) - return Encode::undefined(); + CHECK_EXCEPTION(); --k; } } for (uint i = 0; i < itemCount; ++i) { - instance->putIndexed(start + i, ctx->args()[i + 2]); - if (scope.hasException()) - return Encode::undefined(); + instance->putIndexed(start + i, callData->args[i + 2]); + CHECK_EXCEPTION(); } - ctx->d()->strictMode = true; - instance->put(ctx->d()->engine->id_length(), ScopedValue(scope, Primitive::fromDouble(len - deleteCount + itemCount))); + bool wasStrict = scope.engine->current->strictMode; + scope.engine->current->strictMode = true; + instance->put(scope.engine->id_length(), ScopedValue(scope, Primitive::fromDouble(len - deleteCount + itemCount))); - return newArray.asReturnedValue(); + scope.result = newArray; + scope.engine->current->strictMode = wasStrict; } -ReturnedValue ArrayPrototype::method_unshift(CallContext *ctx) +void ArrayPrototype::method_unshift(const BuiltinFunction *, Scope &scope, CallData *callData) { - Scope scope(ctx); - ScopedObject instance(scope, ctx->thisObject().toObject(scope.engine)); + ScopedObject instance(scope, callData->thisObject.toObject(scope.engine)); if (!instance) - return Encode::undefined(); + RETURN_UNDEFINED(); instance->arrayCreate(); Q_ASSERT(instance->arrayData()); @@ -630,50 +605,52 @@ ReturnedValue ArrayPrototype::method_unshift(CallContext *ctx) if (!instance->protoHasArray() && !instance->arrayData()->attrs && instance->arrayData()->length() <= len && instance->arrayData()->type != Heap::ArrayData::Custom) { - instance->arrayData()->vtable()->push_front(instance, ctx->args(), ctx->argc()); + instance->arrayData()->vtable()->push_front(instance, callData->args, 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->argc() - 1, v); + instance->putIndexed(k + callData->argc - 1, v); else - instance->deleteIndexedProperty(k + ctx->argc() - 1); + instance->deleteIndexedProperty(k + callData->argc - 1); } - for (int i = 0; i < ctx->argc(); ++i) - instance->putIndexed(i, ctx->args()[i]); + for (int i = 0; i < callData->argc; ++i) + instance->putIndexed(i, callData->args[i]); } - uint newLen = len + ctx->argc(); + uint newLen = len + callData->argc; if (instance->isArrayObject()) instance->setArrayLengthUnchecked(newLen); else - instance->put(ctx->d()->engine->id_length(), ScopedValue(scope, Primitive::fromDouble(newLen))); + instance->put(scope.engine->id_length(), ScopedValue(scope, Primitive::fromDouble(newLen))); - return Encode(newLen); + scope.result = Encode(newLen); } -ReturnedValue ArrayPrototype::method_indexOf(CallContext *ctx) +void ArrayPrototype::method_indexOf(const BuiltinFunction *, Scope &scope, CallData *callData) { - Scope scope(ctx); - - ScopedObject instance(scope, ctx->thisObject().toObject(scope.engine)); + ScopedObject instance(scope, callData->thisObject.toObject(scope.engine)); if (!instance) - return Encode::undefined(); + RETURN_UNDEFINED(); + uint len = instance->getLength(); - if (!len) - return Encode(-1); + if (!len) { + scope.result = Encode(-1); + return; + } - ScopedValue searchValue(scope, ctx->argument(0)); + ScopedValue searchValue(scope, callData->argument(0)); uint fromIndex = 0; - if (ctx->argc() >= 2) { - double f = ctx->args()[1].toInteger(); - if (scope.hasException()) - return Encode::undefined(); - if (f >= len) - return Encode(-1); + if (callData->argc >= 2) { + double f = callData->args[1].toInteger(); + CHECK_EXCEPTION(); + if (f >= len) { + scope.result = Encode(-1); + return; + } if (f < 0) f = qMax(len + f, 0.); fromIndex = (uint) f; @@ -684,10 +661,13 @@ ReturnedValue ArrayPrototype::method_indexOf(CallContext *ctx) for (uint k = fromIndex; k < len; ++k) { bool exists; v = instance->getIndexed(k, &exists); - if (exists && RuntimeHelpers::strictEqual(v, searchValue)) - return Encode(k); + if (exists && RuntimeHelpers::strictEqual(v, searchValue)) { + scope.result = Encode(k); + return; + } } - return Encode(-1); + scope.result = Encode(-1); + return; } ScopedValue value(scope); @@ -698,13 +678,15 @@ ReturnedValue ArrayPrototype::method_indexOf(CallContext *ctx) for (uint i = fromIndex; i < len; ++i) { bool exists; value = instance->getIndexed(i, &exists); - if (scope.hasException()) - return Encode::undefined(); - if (exists && RuntimeHelpers::strictEqual(value, searchValue)) - return Encode(i); + CHECK_EXCEPTION(); + if (exists && RuntimeHelpers::strictEqual(value, searchValue)) { + scope.result = Encode(i); + return; + } } } else if (!instance->arrayData()) { - return Encode(-1); + scope.result = Encode(-1); + return; } else { Q_ASSERT(instance->arrayType() == Heap::ArrayData::Simple || instance->arrayType() == Heap::ArrayData::Complex); Heap::SimpleArrayData *sa = instance->d()->arrayData.cast<Heap::SimpleArrayData>(); @@ -713,45 +695,48 @@ ReturnedValue ArrayPrototype::method_indexOf(CallContext *ctx) uint idx = fromIndex; while (idx < len) { value = sa->data(idx); - if (scope.hasException()) - return Encode::undefined(); - if (RuntimeHelpers::strictEqual(value, searchValue)) - return Encode(idx); + CHECK_EXCEPTION(); + if (RuntimeHelpers::strictEqual(value, searchValue)) { + scope.result = Encode(idx); + return; + } ++idx; } } - return Encode(-1); + scope.result = Encode(-1); } -ReturnedValue ArrayPrototype::method_lastIndexOf(CallContext *ctx) +void ArrayPrototype::method_lastIndexOf(const BuiltinFunction *, Scope &scope, CallData *callData) { - Scope scope(ctx); - - ScopedObject instance(scope, ctx->thisObject().toObject(scope.engine)); + ScopedObject instance(scope, callData->thisObject.toObject(scope.engine)); if (!instance) - return Encode::undefined(); + RETURN_UNDEFINED(); + uint len = instance->getLength(); - if (!len) - return Encode(-1); + if (!len) { + scope.result = Encode(-1); + return; + } ScopedValue searchValue(scope); uint fromIndex = len; - if (ctx->argc() >= 1) - searchValue = ctx->argument(0); + if (callData->argc >= 1) + searchValue = callData->argument(0); else searchValue = Primitive::undefinedValue(); - if (ctx->argc() >= 2) { - double f = ctx->args()[1].toInteger(); - if (scope.hasException()) - return Encode::undefined(); + if (callData->argc >= 2) { + double f = callData->args[1].toInteger(); + CHECK_EXCEPTION(); if (f > 0) f = qMin(f, (double)(len - 1)); else if (f < 0) { f = len + f; - if (f < 0) - return Encode(-1); + if (f < 0) { + scope.result = Encode(-1); + return; + } } fromIndex = (uint) f + 1; } @@ -761,30 +746,30 @@ ReturnedValue ArrayPrototype::method_lastIndexOf(CallContext *ctx) --k; bool exists; v = instance->getIndexed(k, &exists); - if (scope.hasException()) - return Encode::undefined(); - if (exists && RuntimeHelpers::strictEqual(v, searchValue)) - return Encode(k); + CHECK_EXCEPTION(); + if (exists && RuntimeHelpers::strictEqual(v, searchValue)) { + scope.result = Encode(k); + return; + } } - return Encode(-1); + scope.result = Encode(-1); } -ReturnedValue ArrayPrototype::method_every(CallContext *ctx) +void ArrayPrototype::method_every(const BuiltinFunction *, Scope &scope, CallData *callData) { - Scope scope(ctx); - ScopedObject instance(scope, ctx->thisObject().toObject(scope.engine)); + ScopedObject instance(scope, callData->thisObject.toObject(scope.engine)); if (!instance) - return Encode::undefined(); + RETURN_UNDEFINED(); uint len = instance->getLength(); - ScopedFunctionObject callback(scope, ctx->argument(0)); + ScopedFunctionObject callback(scope, callData->argument(0)); if (!callback) - return ctx->engine()->throwTypeError(); + THROW_TYPE_ERROR(); - ScopedCallData callData(scope, 3); - callData->args[2] = instance; - callData->thisObject = ctx->argument(1); + ScopedCallData cData(scope, 3); + cData->args[2] = instance; + cData->thisObject = callData->argument(1); ScopedValue v(scope); bool ok = true; @@ -794,30 +779,29 @@ ReturnedValue ArrayPrototype::method_every(CallContext *ctx) if (!exists) continue; - callData->args[0] = v; - callData->args[1] = Primitive::fromDouble(k); - callback->call(scope, callData); + cData->args[0] = v; + cData->args[1] = Primitive::fromDouble(k); + callback->call(scope, cData); ok = scope.result.toBoolean(); } - return Encode(ok); + scope.result = Encode(ok); } -ReturnedValue ArrayPrototype::method_some(CallContext *ctx) +void ArrayPrototype::method_some(const BuiltinFunction *, Scope &scope, CallData *callData) { - Scope scope(ctx); - ScopedObject instance(scope, ctx->thisObject().toObject(scope.engine)); + ScopedObject instance(scope, callData->thisObject.toObject(scope.engine)); if (!instance) - return Encode::undefined(); + RETURN_UNDEFINED(); uint len = instance->getLength(); - ScopedFunctionObject callback(scope, ctx->argument(0)); + ScopedFunctionObject callback(scope, callData->argument(0)); if (!callback) - return ctx->engine()->throwTypeError(); + THROW_TYPE_ERROR(); - ScopedCallData callData(scope, 3); - callData->thisObject = ctx->argument(1); - callData->args[2] = instance; + ScopedCallData cData(scope, 3); + cData->thisObject = callData->argument(1); + cData->args[2] = instance; ScopedValue v(scope); for (uint k = 0; k < len; ++k) { @@ -826,31 +810,32 @@ ReturnedValue ArrayPrototype::method_some(CallContext *ctx) if (!exists) continue; - callData->args[0] = v; - callData->args[1] = Primitive::fromDouble(k); - callback->call(scope, callData); - if (scope.result.toBoolean()) - return Encode(true); + cData->args[0] = v; + cData->args[1] = Primitive::fromDouble(k); + callback->call(scope, cData); + if (scope.result.toBoolean()) { + scope.result = Encode(true); + return; + } } - return Encode(false); + scope.result = Encode(false); } -ReturnedValue ArrayPrototype::method_forEach(CallContext *ctx) +void ArrayPrototype::method_forEach(const BuiltinFunction *, Scope &scope, CallData *callData) { - Scope scope(ctx); - ScopedObject instance(scope, ctx->thisObject().toObject(scope.engine)); + ScopedObject instance(scope, callData->thisObject.toObject(scope.engine)); if (!instance) - return Encode::undefined(); + RETURN_UNDEFINED(); uint len = instance->getLength(); - ScopedFunctionObject callback(scope, ctx->argument(0)); + ScopedFunctionObject callback(scope, callData->argument(0)); if (!callback) - return ctx->engine()->throwTypeError(); + THROW_TYPE_ERROR(); - ScopedCallData callData(scope, 3); - callData->thisObject = ctx->argument(1); - callData->args[2] = instance; + ScopedCallData cData(scope, 3); + cData->thisObject = callData->argument(1); + cData->args[2] = instance; ScopedValue v(scope); for (uint k = 0; k < len; ++k) { @@ -859,33 +844,32 @@ ReturnedValue ArrayPrototype::method_forEach(CallContext *ctx) if (!exists) continue; - callData->args[0] = v; - callData->args[1] = Primitive::fromDouble(k); - callback->call(scope, callData); + cData->args[0] = v; + cData->args[1] = Primitive::fromDouble(k); + callback->call(scope, cData); } - return Encode::undefined(); + RETURN_UNDEFINED(); } -ReturnedValue ArrayPrototype::method_map(CallContext *ctx) +void ArrayPrototype::method_map(const BuiltinFunction *, Scope &scope, CallData *callData) { - Scope scope(ctx); - ScopedObject instance(scope, ctx->thisObject().toObject(scope.engine)); + ScopedObject instance(scope, callData->thisObject.toObject(scope.engine)); if (!instance) - return Encode::undefined(); + RETURN_UNDEFINED(); uint len = instance->getLength(); - ScopedFunctionObject callback(scope, ctx->argument(0)); + ScopedFunctionObject callback(scope, callData->argument(0)); if (!callback) - return ctx->engine()->throwTypeError(); + THROW_TYPE_ERROR(); - ScopedArrayObject a(scope, ctx->d()->engine->newArrayObject()); + ScopedArrayObject a(scope, scope.engine->newArrayObject()); a->arrayReserve(len); a->setArrayLengthUnchecked(len); - ScopedCallData callData(scope, 3); - callData->thisObject = ctx->argument(1); - callData->args[2] = instance; + ScopedCallData cData(scope, 3); + cData->thisObject = callData->argument(1); + cData->args[2] = instance; ScopedValue v(scope); for (uint k = 0; k < len; ++k) { @@ -894,33 +878,32 @@ ReturnedValue ArrayPrototype::method_map(CallContext *ctx) if (!exists) continue; - callData->args[0] = v; - callData->args[1] = Primitive::fromDouble(k); - callback->call(scope, callData); + cData->args[0] = v; + cData->args[1] = Primitive::fromDouble(k); + callback->call(scope, cData); a->arraySet(k, scope.result); } - return a.asReturnedValue(); + scope.result = a.asReturnedValue(); } -ReturnedValue ArrayPrototype::method_filter(CallContext *ctx) +void ArrayPrototype::method_filter(const BuiltinFunction *, Scope &scope, CallData *callData) { - Scope scope(ctx); - ScopedObject instance(scope, ctx->thisObject().toObject(scope.engine)); + ScopedObject instance(scope, callData->thisObject.toObject(scope.engine)); if (!instance) - return Encode::undefined(); + RETURN_UNDEFINED(); uint len = instance->getLength(); - ScopedFunctionObject callback(scope, ctx->argument(0)); + ScopedFunctionObject callback(scope, callData->argument(0)); if (!callback) - return ctx->engine()->throwTypeError(); + THROW_TYPE_ERROR(); - ScopedArrayObject a(scope, ctx->d()->engine->newArrayObject()); + ScopedArrayObject a(scope, scope.engine->newArrayObject()); a->arrayReserve(len); - ScopedCallData callData(scope, 3); - callData->thisObject = ctx->argument(1); - callData->args[2] = instance; + ScopedCallData cData(scope, 3); + cData->thisObject = callData->argument(1); + cData->args[2] = instance; ScopedValue v(scope); @@ -931,35 +914,34 @@ ReturnedValue ArrayPrototype::method_filter(CallContext *ctx) if (!exists) continue; - callData->args[0] = v; - callData->args[1] = Primitive::fromDouble(k); - callback->call(scope, callData); + cData->args[0] = v; + cData->args[1] = Primitive::fromDouble(k); + callback->call(scope, cData); if (scope.result.toBoolean()) { a->arraySet(to, v); ++to; } } - return a.asReturnedValue(); + scope.result = a.asReturnedValue(); } -ReturnedValue ArrayPrototype::method_reduce(CallContext *ctx) +void ArrayPrototype::method_reduce(const BuiltinFunction *, Scope &scope, CallData *callData) { - Scope scope(ctx); - ScopedObject instance(scope, ctx->thisObject().toObject(scope.engine)); + ScopedObject instance(scope, callData->thisObject.toObject(scope.engine)); if (!instance) - return Encode::undefined(); + RETURN_UNDEFINED(); uint len = instance->getLength(); - ScopedFunctionObject callback(scope, ctx->argument(0)); + ScopedFunctionObject callback(scope, callData->argument(0)); if (!callback) - return ctx->engine()->throwTypeError(); + THROW_TYPE_ERROR(); uint k = 0; ScopedValue v(scope); - if (ctx->argc() > 1) { - scope.result = ctx->argument(1); + if (callData->argc > 1) { + scope.result = callData->argument(1); } else { bool kPresent = false; while (k < len && !kPresent) { @@ -969,51 +951,50 @@ ReturnedValue ArrayPrototype::method_reduce(CallContext *ctx) ++k; } if (!kPresent) - return ctx->engine()->throwTypeError(); + THROW_TYPE_ERROR(); } - ScopedCallData callData(scope, 4); - callData->thisObject = Primitive::undefinedValue(); - callData->args[0] = scope.result; - callData->args[3] = instance; + ScopedCallData cData(scope, 4); + cData->thisObject = Primitive::undefinedValue(); + cData->args[0] = scope.result; + cData->args[3] = instance; while (k < len) { bool kPresent; v = instance->getIndexed(k, &kPresent); if (kPresent) { - callData->args[0] = scope.result; - callData->args[1] = v; - callData->args[2] = Primitive::fromDouble(k); - callback->call(scope, callData); + cData->args[0] = scope.result; + cData->args[1] = v; + cData->args[2] = Primitive::fromDouble(k); + callback->call(scope, cData); } ++k; } - return scope.result.asReturnedValue(); } -ReturnedValue ArrayPrototype::method_reduceRight(CallContext *ctx) +void ArrayPrototype::method_reduceRight(const BuiltinFunction *, Scope &scope, CallData *callData) { - Scope scope(ctx); - ScopedObject instance(scope, ctx->thisObject().toObject(scope.engine)); + ScopedObject instance(scope, callData->thisObject.toObject(scope.engine)); if (!instance) - return Encode::undefined(); + RETURN_UNDEFINED(); uint len = instance->getLength(); - ScopedFunctionObject callback(scope, ctx->argument(0)); + ScopedFunctionObject callback(scope, callData->argument(0)); if (!callback) - return ctx->engine()->throwTypeError(); + THROW_TYPE_ERROR(); if (len == 0) { - if (ctx->argc() == 1) - return ctx->engine()->throwTypeError(); - return ctx->argument(1); + if (callData->argc == 1) + THROW_TYPE_ERROR(); + scope.result = callData->argument(1); + return; } uint k = len; ScopedValue v(scope); - if (ctx->argc() > 1) { - scope.result = ctx->argument(1); + if (callData->argc > 1) { + scope.result = callData->argument(1); } else { bool kPresent = false; while (k > 0 && !kPresent) { @@ -1023,24 +1004,24 @@ ReturnedValue ArrayPrototype::method_reduceRight(CallContext *ctx) --k; } if (!kPresent) - return ctx->engine()->throwTypeError(); + THROW_TYPE_ERROR(); } - ScopedCallData callData(scope, 4); - callData->thisObject = Primitive::undefinedValue(); - callData->args[3] = instance; + ScopedCallData cData(scope, 4); + cData->thisObject = Primitive::undefinedValue(); + cData->args[3] = instance; while (k > 0) { bool kPresent; v = instance->getIndexed(k - 1, &kPresent); if (kPresent) { - callData->args[0] = scope.result; - callData->args[1] = v; - callData->args[2] = Primitive::fromDouble(k - 1); - callback->call(scope, callData); + cData->args[0] = scope.result; + cData->args[1] = v; + cData->args[2] = Primitive::fromDouble(k - 1); + callback->call(scope, cData); } --k; } - return scope.result.asReturnedValue(); + scope.result = scope.result.asReturnedValue(); } diff --git a/src/qml/jsruntime/qv4arrayobject_p.h b/src/qml/jsruntime/qv4arrayobject_p.h index f00c0c0249..689752433b 100644 --- a/src/qml/jsruntime/qv4arrayobject_p.h +++ b/src/qml/jsruntime/qv4arrayobject_p.h @@ -78,30 +78,30 @@ struct ArrayPrototype: ArrayObject { void init(ExecutionEngine *engine, Object *ctor); - static ReturnedValue method_isArray(CallContext *ctx); - static ReturnedValue method_toString(CallContext *ctx); - static ReturnedValue method_toLocaleString(CallContext *ctx); - static ReturnedValue method_concat(CallContext *ctx); - static ReturnedValue method_find(CallContext *ctx); - static ReturnedValue method_findIndex(CallContext *ctx); - static ReturnedValue method_join(CallContext *ctx); - static ReturnedValue method_pop(CallContext *ctx); - static ReturnedValue method_push(CallContext *ctx); - static ReturnedValue method_reverse(CallContext *ctx); - static ReturnedValue method_shift(CallContext *ctx); - static ReturnedValue method_slice(CallContext *ctx); - static ReturnedValue method_sort(CallContext *ctx); - static ReturnedValue method_splice(CallContext *ctx); - static ReturnedValue method_unshift(CallContext *ctx); - static ReturnedValue method_indexOf(CallContext *ctx); - static ReturnedValue method_lastIndexOf(CallContext *ctx); - static ReturnedValue method_every(CallContext *ctx); - static ReturnedValue method_some(CallContext *ctx); - static ReturnedValue method_forEach(CallContext *ctx); - static ReturnedValue method_map(CallContext *ctx); - static ReturnedValue method_filter(CallContext *ctx); - static ReturnedValue method_reduce(CallContext *ctx); - static ReturnedValue method_reduceRight(CallContext *ctx); + static void method_isArray(const BuiltinFunction *, Scope &, CallData *callData); + static void method_toString(const BuiltinFunction *, Scope &, CallData *callData); + static void method_toLocaleString(const BuiltinFunction *builtin, Scope &, CallData *callData); + static void method_concat(const BuiltinFunction *, Scope &, CallData *callData); + static void method_find(const BuiltinFunction *, Scope &scope, CallData *callData); + static void method_findIndex(const BuiltinFunction *, Scope &scope, CallData *callData); + static void method_join(const BuiltinFunction *, Scope &, CallData *callData); + static void method_pop(const BuiltinFunction *, Scope &, CallData *callData); + static void method_push(const BuiltinFunction *, Scope &, CallData *callData); + static void method_reverse(const BuiltinFunction *, Scope &, CallData *callData); + static void method_shift(const BuiltinFunction *, Scope &, CallData *callData); + static void method_slice(const BuiltinFunction *, Scope &, CallData *callData); + static void method_sort(const BuiltinFunction *, Scope &, CallData *callData); + static void method_splice(const BuiltinFunction *, Scope &, CallData *callData); + static void method_unshift(const BuiltinFunction *, Scope &, CallData *callData); + static void method_indexOf(const BuiltinFunction *, Scope &, CallData *callData); + static void method_lastIndexOf(const BuiltinFunction *, Scope &, CallData *callData); + static void method_every(const BuiltinFunction *, Scope &, CallData *callData); + static void method_some(const BuiltinFunction *, Scope &, CallData *callData); + static void method_forEach(const BuiltinFunction *, Scope &, CallData *callData); + static void method_map(const BuiltinFunction *, Scope &, CallData *callData); + static void method_filter(const BuiltinFunction *, Scope &, CallData *callData); + static void method_reduce(const BuiltinFunction *, Scope &, CallData *callData); + static void method_reduceRight(const BuiltinFunction *, Scope &, CallData *callData); }; diff --git a/src/qml/jsruntime/qv4booleanobject.cpp b/src/qml/jsruntime/qv4booleanobject.cpp index 8047993266..601066110f 100644 --- a/src/qml/jsruntime/qv4booleanobject.cpp +++ b/src/qml/jsruntime/qv4booleanobject.cpp @@ -73,29 +73,31 @@ void BooleanPrototype::init(ExecutionEngine *engine, Object *ctor) defineDefaultProperty(engine->id_valueOf(), method_valueOf); } -ReturnedValue BooleanPrototype::method_toString(CallContext *ctx) +void BooleanPrototype::method_toString(const BuiltinFunction *, Scope &scope, CallData *callData) { bool result; - if (ctx->thisObject().isBoolean()) { - result = ctx->thisObject().booleanValue(); + if (callData->thisObject.isBoolean()) { + result = callData->thisObject.booleanValue(); } else { - const BooleanObject *thisObject = ctx->thisObject().as<BooleanObject>(); + const BooleanObject *thisObject = callData->thisObject.as<BooleanObject>(); if (!thisObject) - return ctx->engine()->throwTypeError(); + THROW_TYPE_ERROR(); result = thisObject->value(); } - return Encode(ctx->d()->engine->newString(QLatin1String(result ? "true" : "false"))); + scope.result = scope.engine->newString(QLatin1String(result ? "true" : "false")); } -ReturnedValue BooleanPrototype::method_valueOf(CallContext *ctx) +void BooleanPrototype::method_valueOf(const BuiltinFunction *, Scope &scope, CallData *callData) { - if (ctx->thisObject().isBoolean()) - return ctx->thisObject().asReturnedValue(); + if (callData->thisObject.isBoolean()) { + scope.result = callData->thisObject.asReturnedValue(); + return; + } - const BooleanObject *thisObject = ctx->thisObject().as<BooleanObject>(); + const BooleanObject *thisObject = callData->thisObject.as<BooleanObject>(); if (!thisObject) - return ctx->engine()->throwTypeError(); + THROW_TYPE_ERROR(); - return Encode(thisObject->value()); + scope.result = Encode(thisObject->value()); } diff --git a/src/qml/jsruntime/qv4booleanobject_p.h b/src/qml/jsruntime/qv4booleanobject_p.h index 4c2f3c09e7..9c8b1d67f1 100644 --- a/src/qml/jsruntime/qv4booleanobject_p.h +++ b/src/qml/jsruntime/qv4booleanobject_p.h @@ -78,8 +78,8 @@ struct BooleanPrototype: BooleanObject { void init(ExecutionEngine *engine, Object *ctor); - static ReturnedValue method_toString(CallContext *ctx); - static ReturnedValue method_valueOf(CallContext *ctx); + static void method_toString(const BuiltinFunction *, Scope &scope, CallData *callData); + static void method_valueOf(const BuiltinFunction *, Scope &scope, CallData *callData); }; diff --git a/src/qml/jsruntime/qv4context.cpp b/src/qml/jsruntime/qv4context.cpp index 544d39339b..60b90e4bf0 100644 --- a/src/qml/jsruntime/qv4context.cpp +++ b/src/qml/jsruntime/qv4context.cpp @@ -95,6 +95,17 @@ Heap::CallContext *ExecutionContext::newCallContext(Function *function, CallData return c; } +Heap::CallContext *Heap::CallContext::createSimpleContext(ExecutionEngine *v4) +{ + Heap::CallContext *ctxt = v4->memoryManager->allocSimpleCallContext(v4); + return ctxt; +} + +void Heap::CallContext::freeSimpleCallContext() +{ + engine->memoryManager->freeSimpleCallContext(); +} + Heap::WithContext *ExecutionContext::newWithContext(Heap::Object *with) { return d()->engine->memoryManager->alloc<WithContext>(d(), with); @@ -325,26 +336,27 @@ void QV4::ExecutionContext::simpleCall(Scope &scope, CallData *callData, Functio ExecutionContextSaver ctxSaver(scope); - CallContext::Data ctx = CallContext::Data::createOnStack(scope.engine); + CallContext::Data *ctx = scope.engine->memoryManager->allocSimpleCallContext(scope.engine); - ctx.strictMode = function->isStrict(); - ctx.callData = callData; - ctx.v4Function = function; - ctx.compilationUnit = function->compilationUnit; - ctx.lookups = function->compilationUnit->runtimeLookups; - ctx.constantTable = function->compilationUnit->constants; - ctx.outer = this->d(); - ctx.locals = scope.alloc(function->compiledFunction->nLocals); + ctx->strictMode = function->isStrict(); + ctx->callData = callData; + ctx->v4Function = function; + ctx->compilationUnit = function->compilationUnit; + ctx->lookups = function->compilationUnit->runtimeLookups; + ctx->constantTable = function->compilationUnit->constants; + ctx->outer = this->d(); + ctx->locals = scope.alloc(function->compiledFunction->nLocals); for (int i = callData->argc; i < (int)function->nFormals; ++i) callData->args[i] = Encode::undefined(); - scope.engine->pushContext(&ctx); - Q_ASSERT(scope.engine->current == &ctx); + scope.engine->pushContext(ctx); + Q_ASSERT(scope.engine->current == ctx); scope.result = Q_V4_PROFILE(scope.engine, function); if (function->hasQmlDependencies) QQmlPropertyCapture::registerQmlDependencies(function->compiledFunction, scope); + scope.engine->memoryManager->freeSimpleCallContext(); } void ExecutionContext::setProperty(String *name, const Value &value) diff --git a/src/qml/jsruntime/qv4context_p.h b/src/qml/jsruntime/qv4context_p.h index c985fdb24d..bcfee2e1f8 100644 --- a/src/qml/jsruntime/qv4context_p.h +++ b/src/qml/jsruntime/qv4context_p.h @@ -109,14 +109,8 @@ struct ExecutionContext : Base { { Base::init(); - callData = nullptr; this->engine = engine; - outer = nullptr; - lookups = nullptr; - constantTable = nullptr; - compilationUnit = nullptr; type = t; - strictMode = false; lineNumber = -1; } @@ -135,15 +129,12 @@ struct ExecutionContext : Base { V4_ASSERT_IS_TRIVIAL(ExecutionContext) struct CallContext : ExecutionContext { - static CallContext createOnStack(ExecutionEngine *v4); + static CallContext *createSimpleContext(ExecutionEngine *v4); + void freeSimpleCallContext(); void init(ExecutionEngine *engine, ContextType t = Type_SimpleCallContext) { ExecutionContext::init(engine, t); - function = 0; - v4Function = 0; - locals = 0; - activation = 0; } inline unsigned int formalParameterCount() const; @@ -247,6 +238,7 @@ struct Q_QML_EXPORT CallContext : public ExecutionContext inline ReturnedValue argument(int i) const; bool needsOwnArguments() const; + }; inline ReturnedValue CallContext::argument(int i) const { @@ -289,16 +281,6 @@ inline const WithContext *ExecutionContext::asWithContext() const return d()->type == Heap::ExecutionContext::Type_WithContext ? static_cast<const WithContext *>(this) : 0; } -inline Heap::CallContext Heap::CallContext::createOnStack(ExecutionEngine *v4) -{ - Heap::CallContext ctxt; - memset(&ctxt, 0, sizeof(Heap::CallContext)); - ctxt.mm_data = 0; - ctxt.setVtable(QV4::CallContext::staticVTable()); - ctxt.init(v4); - return ctxt; -} - } // namespace QV4 QT_END_NAMESPACE diff --git a/src/qml/jsruntime/qv4dataview.cpp b/src/qml/jsruntime/qv4dataview.cpp index db8376272d..a810b38f24 100644 --- a/src/qml/jsruntime/qv4dataview.cpp +++ b/src/qml/jsruntime/qv4dataview.cpp @@ -129,90 +129,84 @@ void DataViewPrototype::init(ExecutionEngine *engine, Object *ctor) defineDefaultProperty(QStringLiteral("setUInt32"), method_set<unsigned int>, 0); } -ReturnedValue DataViewPrototype::method_get_buffer(CallContext *ctx) +void DataViewPrototype::method_get_buffer(const BuiltinFunction *, Scope &scope, CallData *callData) { - Scope scope(ctx); - Scoped<DataView> v(scope, ctx->thisObject()); + Scoped<DataView> v(scope, callData->thisObject); if (!v) - return scope.engine->throwTypeError(); + THROW_TYPE_ERROR(); - return Encode(v->d()->buffer->asReturnedValue()); + scope.result = v->d()->buffer; } -ReturnedValue DataViewPrototype::method_get_byteLength(CallContext *ctx) +void DataViewPrototype::method_get_byteLength(const BuiltinFunction *, Scope &scope, CallData *callData) { - Scope scope(ctx); - Scoped<DataView> v(scope, ctx->thisObject()); + Scoped<DataView> v(scope, callData->thisObject); if (!v) - return scope.engine->throwTypeError(); + THROW_TYPE_ERROR(); - return Encode(v->d()->byteLength); + scope.result = Encode(v->d()->byteLength); } -ReturnedValue DataViewPrototype::method_get_byteOffset(CallContext *ctx) +void DataViewPrototype::method_get_byteOffset(const BuiltinFunction *, Scope &scope, CallData *callData) { - Scope scope(ctx); - Scoped<DataView> v(scope, ctx->thisObject()); + Scoped<DataView> v(scope, callData->thisObject); if (!v) - return scope.engine->throwTypeError(); + THROW_TYPE_ERROR(); - return Encode(v->d()->byteOffset); + scope.result = Encode(v->d()->byteOffset); } template <typename T> -ReturnedValue DataViewPrototype::method_getChar(CallContext *ctx) +void DataViewPrototype::method_getChar(const BuiltinFunction *, Scope &scope, CallData *callData) { - Scope scope(ctx); - Scoped<DataView> v(scope, ctx->thisObject()); - if (!v || ctx->argc() < 1) - return scope.engine->throwTypeError(); - double l = ctx->args()[0].toNumber(); + Scoped<DataView> v(scope, callData->thisObject); + if (!v || callData->argc < 1) + THROW_TYPE_ERROR(); + double l = callData->args[0].toNumber(); uint idx = (uint)l; if (l != idx || idx + sizeof(T) > v->d()->byteLength) - return scope.engine->throwTypeError(); + THROW_TYPE_ERROR(); idx += v->d()->byteOffset; T t = T(v->d()->buffer->data->data()[idx]); - return Encode((int)t); + scope.result = Encode((int)t); } template <typename T> -ReturnedValue DataViewPrototype::method_get(CallContext *ctx) +void DataViewPrototype::method_get(const BuiltinFunction *, Scope &scope, CallData *callData) { - Scope scope(ctx); - Scoped<DataView> v(scope, ctx->thisObject()); - if (!v || ctx->argc() < 1) - return scope.engine->throwTypeError(); - double l = ctx->args()[0].toNumber(); + Scoped<DataView> v(scope, callData->thisObject); + if (!v || callData->argc < 1) + THROW_TYPE_ERROR(); + double l = callData->args[0].toNumber(); uint idx = (uint)l; if (l != idx || idx + sizeof(T) > v->d()->byteLength) - return scope.engine->throwTypeError(); + THROW_TYPE_ERROR(); idx += v->d()->byteOffset; - bool littleEndian = ctx->argc() < 2 ? false : ctx->args()[1].toBoolean(); + bool littleEndian = callData->argc < 2 ? false : callData->args[1].toBoolean(); T t = littleEndian ? qFromLittleEndian<T>((uchar *)v->d()->buffer->data->data() + idx) : qFromBigEndian<T>((uchar *)v->d()->buffer->data->data() + idx); - return Encode(t); + scope.result = Encode(t); } template <typename T> -ReturnedValue DataViewPrototype::method_getFloat(CallContext *ctx) +void DataViewPrototype::method_getFloat(const BuiltinFunction *, Scope &scope, CallData *callData) { - Scope scope(ctx); - Scoped<DataView> v(scope, ctx->thisObject()); - if (!v || ctx->argc() < 1) - return scope.engine->throwTypeError(); - double l = ctx->args()[0].toNumber(); + Scoped<DataView> v(scope, callData->thisObject); + if (!v || callData->argc < 1) + THROW_TYPE_ERROR(); + double l = callData->args[0].toNumber(); uint idx = (uint)l; if (l != idx || idx + sizeof(T) > v->d()->byteLength) - return scope.engine->throwTypeError(); + THROW_TYPE_ERROR(); idx += v->d()->byteOffset; - bool littleEndian = ctx->argc() < 2 ? false : ctx->args()[1].toBoolean(); + bool littleEndian = callData->argc < 2 ? false : callData->args[1].toBoolean(); if (sizeof(T) == 4) { // float @@ -223,7 +217,7 @@ ReturnedValue DataViewPrototype::method_getFloat(CallContext *ctx) u.i = littleEndian ? qFromLittleEndian<uint>((uchar *)v->d()->buffer->data->data() + idx) : qFromBigEndian<uint>((uchar *)v->d()->buffer->data->data() + idx); - return Encode(u.f); + scope.result = Encode(u.f); } else { Q_ASSERT(sizeof(T) == 8); union { @@ -233,69 +227,66 @@ ReturnedValue DataViewPrototype::method_getFloat(CallContext *ctx) u.i = littleEndian ? qFromLittleEndian<quint64>((uchar *)v->d()->buffer->data->data() + idx) : qFromBigEndian<quint64>((uchar *)v->d()->buffer->data->data() + idx); - return Encode(u.d); + scope.result = Encode(u.d); } } template <typename T> -ReturnedValue DataViewPrototype::method_setChar(CallContext *ctx) +void DataViewPrototype::method_setChar(const BuiltinFunction *, Scope &scope, CallData *callData) { - Scope scope(ctx); - Scoped<DataView> v(scope, ctx->thisObject()); - if (!v || ctx->argc() < 1) - return scope.engine->throwTypeError(); - double l = ctx->args()[0].toNumber(); + Scoped<DataView> v(scope, callData->thisObject); + if (!v || callData->argc < 1) + THROW_TYPE_ERROR(); + double l = callData->args[0].toNumber(); uint idx = (uint)l; if (l != idx || idx + sizeof(T) > v->d()->byteLength) - return scope.engine->throwTypeError(); + THROW_TYPE_ERROR(); idx += v->d()->byteOffset; - int val = ctx->argc() >= 2 ? ctx->args()[1].toInt32() : 0; + int val = callData->argc >= 2 ? callData->args[1].toInt32() : 0; v->d()->buffer->data->data()[idx] = (char)val; - return Encode::undefined(); + RETURN_UNDEFINED(); } template <typename T> -ReturnedValue DataViewPrototype::method_set(CallContext *ctx) +void DataViewPrototype::method_set(const BuiltinFunction *, Scope &scope, CallData *callData) { - Scope scope(ctx); - Scoped<DataView> v(scope, ctx->thisObject()); - if (!v || ctx->argc() < 1) - return scope.engine->throwTypeError(); - double l = ctx->args()[0].toNumber(); + Scoped<DataView> v(scope, callData->thisObject); + if (!v || callData->argc < 1) + THROW_TYPE_ERROR(); + double l = callData->args[0].toNumber(); uint idx = (uint)l; if (l != idx || idx + sizeof(T) > v->d()->byteLength) - return scope.engine->throwTypeError(); + THROW_TYPE_ERROR(); idx += v->d()->byteOffset; - int val = ctx->argc() >= 2 ? ctx->args()[1].toInt32() : 0; + int val = callData->argc >= 2 ? callData->args[1].toInt32() : 0; - bool littleEndian = ctx->argc() < 3 ? false : ctx->args()[2].toBoolean(); + bool littleEndian = callData->argc < 3 ? false : callData->args[2].toBoolean(); if (littleEndian) qToLittleEndian<T>(val, (uchar *)v->d()->buffer->data->data() + idx); else qToBigEndian<T>(val, (uchar *)v->d()->buffer->data->data() + idx); - return Encode::undefined(); + RETURN_UNDEFINED(); } template <typename T> -ReturnedValue DataViewPrototype::method_setFloat(CallContext *ctx) +void DataViewPrototype::method_setFloat(const BuiltinFunction *, Scope &scope, CallData *callData) { - Scope scope(ctx); - Scoped<DataView> v(scope, ctx->thisObject()); - if (!v || ctx->argc() < 1) - return scope.engine->throwTypeError(); - double l = ctx->args()[0].toNumber(); + Scoped<DataView> v(scope, callData->thisObject); + if (!v || callData->argc < 1) + THROW_TYPE_ERROR(); + double l = callData->args[0].toNumber(); uint idx = (uint)l; if (l != idx || idx + sizeof(T) > v->d()->byteLength) - return scope.engine->throwTypeError(); + THROW_TYPE_ERROR(); idx += v->d()->byteOffset; - double val = ctx->argc() >= 2 ? ctx->args()[1].toNumber() : qt_qnan(); - bool littleEndian = ctx->argc() < 3 ? false : ctx->args()[2].toBoolean(); + double val = callData->argc >= 2 ? callData->args[1].toNumber() : qt_qnan(); + bool littleEndian = callData->argc < 3 ? false : callData->args[2].toBoolean(); if (sizeof(T) == 4) { // float @@ -320,5 +311,5 @@ ReturnedValue DataViewPrototype::method_setFloat(CallContext *ctx) else qToBigEndian(u.i, (uchar *)v->d()->buffer->data->data() + idx); } - return Encode::undefined(); + RETURN_UNDEFINED(); } diff --git a/src/qml/jsruntime/qv4dataview_p.h b/src/qml/jsruntime/qv4dataview_p.h index 246124394a..11cc0a6bd9 100644 --- a/src/qml/jsruntime/qv4dataview_p.h +++ b/src/qml/jsruntime/qv4dataview_p.h @@ -92,21 +92,21 @@ struct DataViewPrototype: Object { void init(ExecutionEngine *engine, Object *ctor); - static ReturnedValue method_get_buffer(CallContext *ctx); - static ReturnedValue method_get_byteLength(CallContext *ctx); - static ReturnedValue method_get_byteOffset(CallContext *ctx); + static void method_get_buffer(const BuiltinFunction *, Scope &scope, CallData *callData); + static void method_get_byteLength(const BuiltinFunction *, Scope &scope, CallData *callData); + static void method_get_byteOffset(const BuiltinFunction *, Scope &scope, CallData *callData); template <typename T> - static ReturnedValue method_getChar(CallContext *ctx); + static void method_getChar(const BuiltinFunction *, Scope &scope, CallData *callData); template <typename T> - static ReturnedValue method_get(CallContext *ctx); + static void method_get(const BuiltinFunction *, Scope &scope, CallData *callData); template <typename T> - static ReturnedValue method_getFloat(CallContext *ctx); + static void method_getFloat(const BuiltinFunction *, Scope &scope, CallData *callData); template <typename T> - static ReturnedValue method_setChar(CallContext *ctx); + static void method_setChar(const BuiltinFunction *, Scope &scope, CallData *callData); template <typename T> - static ReturnedValue method_set(CallContext *ctx); + static void method_set(const BuiltinFunction *, Scope &scope, CallData *callData); template <typename T> - static ReturnedValue method_setFloat(CallContext *ctx); + static void method_setFloat(const BuiltinFunction *, Scope &scope, CallData *callData); }; diff --git a/src/qml/jsruntime/qv4dateobject.cpp b/src/qml/jsruntime/qv4dateobject.cpp index 8cc6a25fea..b90c335b1c 100644 --- a/src/qml/jsruntime/qv4dateobject.cpp +++ b/src/qml/jsruntime/qv4dateobject.cpp @@ -780,435 +780,435 @@ void DatePrototype::init(ExecutionEngine *engine, Object *ctor) defineDefaultProperty(QStringLiteral("toJSON"), method_toJSON, 1); } -double DatePrototype::getThisDate(ExecutionContext *ctx) +double DatePrototype::getThisDate(Scope &scope, CallData *callData) { - if (DateObject *thisObject = ctx->thisObject().as<DateObject>()) + if (DateObject *thisObject = callData->thisObject.as<DateObject>()) return thisObject->date(); else { - ctx->engine()->throwTypeError(); + scope.engine->throwTypeError(); return 0; } } -ReturnedValue DatePrototype::method_parse(CallContext *ctx) +void DatePrototype::method_parse(const BuiltinFunction *, Scope &scope, CallData *callData) { - if (!ctx->argc()) - return Encode(qt_qnan()); - return Encode(ParseString(ctx->args()[0].toQString())); + if (!callData->argc) + scope.result = Encode(qt_qnan()); + else + scope.result = Encode(ParseString(callData->args[0].toQString())); } -ReturnedValue DatePrototype::method_UTC(CallContext *ctx) +void DatePrototype::method_UTC(const BuiltinFunction *, Scope &scope, CallData *callData) { - const int numArgs = ctx->argc(); + const int numArgs = callData->argc; if (numArgs >= 2) { - double year = ctx->args()[0].toNumber(); - double month = ctx->args()[1].toNumber(); - double day = numArgs >= 3 ? ctx->args()[2].toNumber() : 1; - double hours = numArgs >= 4 ? ctx->args()[3].toNumber() : 0; - double mins = numArgs >= 5 ? ctx->args()[4].toNumber() : 0; - double secs = numArgs >= 6 ? ctx->args()[5].toNumber() : 0; - double ms = numArgs >= 7 ? ctx->args()[6].toNumber() : 0; + double year = callData->args[0].toNumber(); + double month = callData->args[1].toNumber(); + double day = numArgs >= 3 ? callData->args[2].toNumber() : 1; + double hours = numArgs >= 4 ? callData->args[3].toNumber() : 0; + double mins = numArgs >= 5 ? callData->args[4].toNumber() : 0; + double secs = numArgs >= 6 ? callData->args[5].toNumber() : 0; + double ms = numArgs >= 7 ? callData->args[6].toNumber() : 0; if (year >= 0 && year <= 99) year += 1900; double t = MakeDate(MakeDay(year, month, day), MakeTime(hours, mins, secs, ms)); - return Encode(TimeClip(t)); + scope.result = Encode(TimeClip(t)); + return; } - return Encode::undefined(); + RETURN_UNDEFINED(); } -ReturnedValue DatePrototype::method_now(CallContext *ctx) +void DatePrototype::method_now(const BuiltinFunction *, Scope &scope, CallData *callData) { - Q_UNUSED(ctx); + Q_UNUSED(callData); double t = currentTime(); - return Encode(t); + scope.result = Encode(t); } -ReturnedValue DatePrototype::method_toString(CallContext *ctx) +void DatePrototype::method_toString(const BuiltinFunction *, Scope &scope, CallData *callData) { - double t = getThisDate(ctx); - return ctx->d()->engine->newString(ToString(t))->asReturnedValue(); + double t = getThisDate(scope, callData); + scope.result = scope.engine->newString(ToString(t)); } -ReturnedValue DatePrototype::method_toDateString(CallContext *ctx) +void DatePrototype::method_toDateString(const BuiltinFunction *, Scope &scope, CallData *callData) { - double t = getThisDate(ctx); - return ctx->d()->engine->newString(ToDateString(t))->asReturnedValue(); + double t = getThisDate(scope, callData); + scope.result = scope.engine->newString(ToDateString(t)); } -ReturnedValue DatePrototype::method_toTimeString(CallContext *ctx) +void DatePrototype::method_toTimeString(const BuiltinFunction *, Scope &scope, CallData *callData) { - double t = getThisDate(ctx); - return ctx->d()->engine->newString(ToTimeString(t))->asReturnedValue(); + double t = getThisDate(scope, callData); + scope.result = scope.engine->newString(ToTimeString(t)); } -ReturnedValue DatePrototype::method_toLocaleString(CallContext *ctx) +void DatePrototype::method_toLocaleString(const BuiltinFunction *, Scope &scope, CallData *callData) { - double t = getThisDate(ctx); - return ctx->d()->engine->newString(ToLocaleString(t))->asReturnedValue(); + double t = getThisDate(scope, callData); + scope.result = scope.engine->newString(ToLocaleString(t)); } -ReturnedValue DatePrototype::method_toLocaleDateString(CallContext *ctx) +void DatePrototype::method_toLocaleDateString(const BuiltinFunction *, Scope &scope, CallData *callData) { - double t = getThisDate(ctx); - return ctx->d()->engine->newString(ToLocaleDateString(t))->asReturnedValue(); + double t = getThisDate(scope, callData); + scope.result = scope.engine->newString(ToLocaleDateString(t)); } -ReturnedValue DatePrototype::method_toLocaleTimeString(CallContext *ctx) +void DatePrototype::method_toLocaleTimeString(const BuiltinFunction *, Scope &scope, CallData *callData) { - double t = getThisDate(ctx); - return ctx->d()->engine->newString(ToLocaleTimeString(t))->asReturnedValue(); + double t = getThisDate(scope, callData); + scope.result = scope.engine->newString(ToLocaleTimeString(t)); } -ReturnedValue DatePrototype::method_valueOf(CallContext *ctx) +void DatePrototype::method_valueOf(const BuiltinFunction *, Scope &scope, CallData *callData) { - double t = getThisDate(ctx); - return Encode(t); + double t = getThisDate(scope, callData); + scope.result = Encode(t); } -ReturnedValue DatePrototype::method_getTime(CallContext *ctx) +void DatePrototype::method_getTime(const BuiltinFunction *, Scope &scope, CallData *callData) { - double t = getThisDate(ctx); - return Encode(t); + double t = getThisDate(scope, callData); + scope.result = Encode(t); } -ReturnedValue DatePrototype::method_getYear(CallContext *ctx) +void DatePrototype::method_getYear(const BuiltinFunction *, Scope &scope, CallData *callData) { - double t = getThisDate(ctx); - if (! std::isnan(t)) + double t = getThisDate(scope, callData); + if (!std::isnan(t)) t = YearFromTime(LocalTime(t)) - 1900; - return Encode(t); + scope.result = Encode(t); } -ReturnedValue DatePrototype::method_getFullYear(CallContext *ctx) +void DatePrototype::method_getFullYear(const BuiltinFunction *, Scope &scope, CallData *callData) { - double t = getThisDate(ctx); - if (! std::isnan(t)) + double t = getThisDate(scope, callData); + if (!std::isnan(t)) t = YearFromTime(LocalTime(t)); - return Encode(t); + scope.result = Encode(t); } -ReturnedValue DatePrototype::method_getUTCFullYear(CallContext *ctx) +void DatePrototype::method_getUTCFullYear(const BuiltinFunction *, Scope &scope, CallData *callData) { - double t = getThisDate(ctx); - if (! std::isnan(t)) + double t = getThisDate(scope, callData); + if (!std::isnan(t)) t = YearFromTime(t); - return Encode(t); + scope.result = Encode(t); } -ReturnedValue DatePrototype::method_getMonth(CallContext *ctx) +void DatePrototype::method_getMonth(const BuiltinFunction *, Scope &scope, CallData *callData) { - double t = getThisDate(ctx); - if (! std::isnan(t)) + double t = getThisDate(scope, callData); + if (!std::isnan(t)) t = MonthFromTime(LocalTime(t)); - return Encode(t); + scope.result = Encode(t); } -ReturnedValue DatePrototype::method_getUTCMonth(CallContext *ctx) +void DatePrototype::method_getUTCMonth(const BuiltinFunction *, Scope &scope, CallData *callData) { - double t = getThisDate(ctx); - if (! std::isnan(t)) + double t = getThisDate(scope, callData); + if (!std::isnan(t)) t = MonthFromTime(t); - return Encode(t); + scope.result = Encode(t); } -ReturnedValue DatePrototype::method_getDate(CallContext *ctx) +void DatePrototype::method_getDate(const BuiltinFunction *, Scope &scope, CallData *callData) { - double t = getThisDate(ctx); - if (! std::isnan(t)) + double t = getThisDate(scope, callData); + if (!std::isnan(t)) t = DateFromTime(LocalTime(t)); - return Encode(t); + scope.result = Encode(t); } -ReturnedValue DatePrototype::method_getUTCDate(CallContext *ctx) +void DatePrototype::method_getUTCDate(const BuiltinFunction *, Scope &scope, CallData *callData) { - double t = getThisDate(ctx); - if (! std::isnan(t)) + double t = getThisDate(scope, callData); + if (!std::isnan(t)) t = DateFromTime(t); - return Encode(t); + scope.result = Encode(t); } -ReturnedValue DatePrototype::method_getDay(CallContext *ctx) +void DatePrototype::method_getDay(const BuiltinFunction *, Scope &scope, CallData *callData) { - double t = getThisDate(ctx); - if (! std::isnan(t)) + double t = getThisDate(scope, callData); + if (!std::isnan(t)) t = WeekDay(LocalTime(t)); - return Encode(t); + scope.result = Encode(t); } -ReturnedValue DatePrototype::method_getUTCDay(CallContext *ctx) +void DatePrototype::method_getUTCDay(const BuiltinFunction *, Scope &scope, CallData *callData) { - double t = getThisDate(ctx); - if (! std::isnan(t)) + double t = getThisDate(scope, callData); + if (!std::isnan(t)) t = WeekDay(t); - return Encode(t); + scope.result = Encode(t); } -ReturnedValue DatePrototype::method_getHours(CallContext *ctx) +void DatePrototype::method_getHours(const BuiltinFunction *, Scope &scope, CallData *callData) { - double t = getThisDate(ctx); - if (! std::isnan(t)) + double t = getThisDate(scope, callData); + if (!std::isnan(t)) t = HourFromTime(LocalTime(t)); - return Encode(t); + scope.result = Encode(t); } -ReturnedValue DatePrototype::method_getUTCHours(CallContext *ctx) +void DatePrototype::method_getUTCHours(const BuiltinFunction *, Scope &scope, CallData *callData) { - double t = getThisDate(ctx); - if (! std::isnan(t)) + double t = getThisDate(scope, callData); + if (!std::isnan(t)) t = HourFromTime(t); - return Encode(t); + scope.result = Encode(t); } -ReturnedValue DatePrototype::method_getMinutes(CallContext *ctx) +void DatePrototype::method_getMinutes(const BuiltinFunction *, Scope &scope, CallData *callData) { - double t = getThisDate(ctx); - if (! std::isnan(t)) + double t = getThisDate(scope, callData); + if (!std::isnan(t)) t = MinFromTime(LocalTime(t)); - return Encode(t); + scope.result = Encode(t); } -ReturnedValue DatePrototype::method_getUTCMinutes(CallContext *ctx) +void DatePrototype::method_getUTCMinutes(const BuiltinFunction *, Scope &scope, CallData *callData) { - double t = getThisDate(ctx); - if (! std::isnan(t)) + double t = getThisDate(scope, callData); + if (!std::isnan(t)) t = MinFromTime(t); - return Encode(t); + scope.result = Encode(t); } -ReturnedValue DatePrototype::method_getSeconds(CallContext *ctx) +void DatePrototype::method_getSeconds(const BuiltinFunction *, Scope &scope, CallData *callData) { - double t = getThisDate(ctx); - if (! std::isnan(t)) + double t = getThisDate(scope, callData); + if (!std::isnan(t)) t = SecFromTime(LocalTime(t)); - return Encode(t); + scope.result = Encode(t); } -ReturnedValue DatePrototype::method_getUTCSeconds(CallContext *ctx) +void DatePrototype::method_getUTCSeconds(const BuiltinFunction *, Scope &scope, CallData *callData) { - double t = getThisDate(ctx); - if (! std::isnan(t)) + double t = getThisDate(scope, callData); + if (!std::isnan(t)) t = SecFromTime(t); - return Encode(t); + scope.result = Encode(t); } -ReturnedValue DatePrototype::method_getMilliseconds(CallContext *ctx) +void DatePrototype::method_getMilliseconds(const BuiltinFunction *, Scope &scope, CallData *callData) { - double t = getThisDate(ctx); - if (! std::isnan(t)) + double t = getThisDate(scope, callData); + if (!std::isnan(t)) t = msFromTime(LocalTime(t)); - return Encode(t); + scope.result = Encode(t); } -ReturnedValue DatePrototype::method_getUTCMilliseconds(CallContext *ctx) +void DatePrototype::method_getUTCMilliseconds(const BuiltinFunction *, Scope &scope, CallData *callData) { - double t = getThisDate(ctx); - if (! std::isnan(t)) + double t = getThisDate(scope, callData); + if (!std::isnan(t)) t = msFromTime(t); - return Encode(t); + scope.result = Encode(t); } -ReturnedValue DatePrototype::method_getTimezoneOffset(CallContext *ctx) +void DatePrototype::method_getTimezoneOffset(const BuiltinFunction *, Scope &scope, CallData *callData) { - double t = getThisDate(ctx); - if (! std::isnan(t)) + double t = getThisDate(scope, callData); + if (!std::isnan(t)) t = (t - LocalTime(t)) / msPerMinute; - return Encode(t); + scope.result = Encode(t); } -ReturnedValue DatePrototype::method_setTime(CallContext *ctx) +void DatePrototype::method_setTime(const BuiltinFunction *, Scope &scope, CallData *callData) { - Scope scope(ctx); - Scoped<DateObject> self(scope, ctx->thisObject()); + Scoped<DateObject> self(scope, callData->thisObject); if (!self) - return ctx->engine()->throwTypeError(); + THROW_TYPE_ERROR(); - double t = ctx->argc() ? ctx->args()[0].toNumber() : qt_qnan(); + double t = callData->argc ? callData->args[0].toNumber() : qt_qnan(); self->setDate(TimeClip(t)); - return Encode(self->date()); + scope.result = Encode(self->date()); } -ReturnedValue DatePrototype::method_setMilliseconds(CallContext *ctx) +void DatePrototype::method_setMilliseconds(const BuiltinFunction *, Scope &scope, CallData *callData) { - Scope scope(ctx); - Scoped<DateObject> self(scope, ctx->thisObject()); + Scoped<DateObject> self(scope, callData->thisObject); if (!self) - return ctx->engine()->throwTypeError(); + THROW_TYPE_ERROR(); double t = LocalTime(self->date()); - double ms = ctx->argc() ? ctx->args()[0].toNumber() : qt_qnan(); + double ms = callData->argc ? callData->args[0].toNumber() : qt_qnan(); self->setDate(TimeClip(UTC(MakeDate(Day(t), MakeTime(HourFromTime(t), MinFromTime(t), SecFromTime(t), ms))))); - return Encode(self->date()); + scope.result = Encode(self->date()); } -ReturnedValue DatePrototype::method_setUTCMilliseconds(CallContext *ctx) +void DatePrototype::method_setUTCMilliseconds(const BuiltinFunction *, Scope &scope, CallData *callData) { - DateObject *self = ctx->thisObject().as<DateObject>(); + DateObject *self = callData->thisObject.as<DateObject>(); if (!self) - return ctx->engine()->throwTypeError(); + THROW_TYPE_ERROR(); double t = self->date(); - double ms = ctx->argc() ? ctx->args()[0].toNumber() : qt_qnan(); + double ms = callData->argc ? callData->args[0].toNumber() : qt_qnan(); self->setDate(TimeClip(MakeDate(Day(t), MakeTime(HourFromTime(t), MinFromTime(t), SecFromTime(t), ms)))); - return Encode(self->date()); + scope.result = Encode(self->date()); } -ReturnedValue DatePrototype::method_setSeconds(CallContext *ctx) +void DatePrototype::method_setSeconds(const BuiltinFunction *, Scope &scope, CallData *callData) { - DateObject *self = ctx->thisObject().as<DateObject>(); + DateObject *self = callData->thisObject.as<DateObject>(); if (!self) - return ctx->engine()->throwTypeError(); + THROW_TYPE_ERROR(); double t = LocalTime(self->date()); - double sec = ctx->argc() ? ctx->args()[0].toNumber() : qt_qnan(); - double ms = (ctx->argc() < 2) ? msFromTime(t) : ctx->args()[1].toNumber(); + double sec = callData->argc ? callData->args[0].toNumber() : qt_qnan(); + double ms = (callData->argc < 2) ? msFromTime(t) : callData->args[1].toNumber(); t = TimeClip(UTC(MakeDate(Day(t), MakeTime(HourFromTime(t), MinFromTime(t), sec, ms)))); self->setDate(t); - return Encode(self->date()); + scope.result = Encode(self->date()); } -ReturnedValue DatePrototype::method_setUTCSeconds(CallContext *ctx) +void DatePrototype::method_setUTCSeconds(const BuiltinFunction *, Scope &scope, CallData *callData) { - DateObject *self = ctx->thisObject().as<DateObject>(); + DateObject *self = callData->thisObject.as<DateObject>(); if (!self) - return ctx->engine()->throwTypeError(); + THROW_TYPE_ERROR(); double t = self->date(); - double sec = ctx->argc() ? ctx->args()[0].toNumber() : qt_qnan(); - double ms = (ctx->argc() < 2) ? msFromTime(t) : ctx->args()[1].toNumber(); + double sec = callData->argc ? callData->args[0].toNumber() : qt_qnan(); + double ms = (callData->argc < 2) ? msFromTime(t) : callData->args[1].toNumber(); t = TimeClip(MakeDate(Day(t), MakeTime(HourFromTime(t), MinFromTime(t), sec, ms))); self->setDate(t); - return Encode(self->date()); + scope.result = Encode(self->date()); } -ReturnedValue DatePrototype::method_setMinutes(CallContext *ctx) +void DatePrototype::method_setMinutes(const BuiltinFunction *, Scope &scope, CallData *callData) { - DateObject *self = ctx->thisObject().as<DateObject>(); + DateObject *self = callData->thisObject.as<DateObject>(); if (!self) - return ctx->engine()->throwTypeError(); + THROW_TYPE_ERROR(); double t = LocalTime(self->date()); - double min = ctx->argc() ? ctx->args()[0].toNumber() : qt_qnan(); - double sec = (ctx->argc() < 2) ? SecFromTime(t) : ctx->args()[1].toNumber(); - double ms = (ctx->argc() < 3) ? msFromTime(t) : ctx->args()[2].toNumber(); + double min = callData->argc ? callData->args[0].toNumber() : qt_qnan(); + double sec = (callData->argc < 2) ? SecFromTime(t) : callData->args[1].toNumber(); + double ms = (callData->argc < 3) ? msFromTime(t) : callData->args[2].toNumber(); t = TimeClip(UTC(MakeDate(Day(t), MakeTime(HourFromTime(t), min, sec, ms)))); self->setDate(t); - return Encode(self->date()); + scope.result = Encode(self->date()); } -ReturnedValue DatePrototype::method_setUTCMinutes(CallContext *ctx) +void DatePrototype::method_setUTCMinutes(const BuiltinFunction *, Scope &scope, CallData *callData) { - DateObject *self = ctx->thisObject().as<DateObject>(); + DateObject *self = callData->thisObject.as<DateObject>(); if (!self) - return ctx->engine()->throwTypeError(); + THROW_TYPE_ERROR(); double t = self->date(); - double min = ctx->argc() ? ctx->args()[0].toNumber() : qt_qnan(); - double sec = (ctx->argc() < 2) ? SecFromTime(t) : ctx->args()[1].toNumber(); - double ms = (ctx->argc() < 3) ? msFromTime(t) : ctx->args()[2].toNumber(); + double min = callData->argc ? callData->args[0].toNumber() : qt_qnan(); + double sec = (callData->argc < 2) ? SecFromTime(t) : callData->args[1].toNumber(); + double ms = (callData->argc < 3) ? msFromTime(t) : callData->args[2].toNumber(); t = TimeClip(MakeDate(Day(t), MakeTime(HourFromTime(t), min, sec, ms))); self->setDate(t); - return Encode(self->date()); + scope.result = Encode(self->date()); } -ReturnedValue DatePrototype::method_setHours(CallContext *ctx) +void DatePrototype::method_setHours(const BuiltinFunction *, Scope &scope, CallData *callData) { - DateObject *self = ctx->thisObject().as<DateObject>(); + DateObject *self = callData->thisObject.as<DateObject>(); if (!self) - return ctx->engine()->throwTypeError(); + THROW_TYPE_ERROR(); double t = LocalTime(self->date()); - double hour = ctx->argc() ? ctx->args()[0].toNumber() : qt_qnan(); - double min = (ctx->argc() < 2) ? MinFromTime(t) : ctx->args()[1].toNumber(); - double sec = (ctx->argc() < 3) ? SecFromTime(t) : ctx->args()[2].toNumber(); - double ms = (ctx->argc() < 4) ? msFromTime(t) : ctx->args()[3].toNumber(); + double hour = callData->argc ? callData->args[0].toNumber() : qt_qnan(); + double min = (callData->argc < 2) ? MinFromTime(t) : callData->args[1].toNumber(); + double sec = (callData->argc < 3) ? SecFromTime(t) : callData->args[2].toNumber(); + double ms = (callData->argc < 4) ? msFromTime(t) : callData->args[3].toNumber(); t = TimeClip(UTC(MakeDate(Day(t), MakeTime(hour, min, sec, ms)))); self->setDate(t); - return Encode(self->date()); + scope.result = Encode(self->date()); } -ReturnedValue DatePrototype::method_setUTCHours(CallContext *ctx) +void DatePrototype::method_setUTCHours(const BuiltinFunction *, Scope &scope, CallData *callData) { - DateObject *self = ctx->thisObject().as<DateObject>(); + DateObject *self = callData->thisObject.as<DateObject>(); if (!self) - return ctx->engine()->throwTypeError(); + THROW_TYPE_ERROR(); double t = self->date(); - double hour = ctx->argc() ? ctx->args()[0].toNumber() : qt_qnan(); - double min = (ctx->argc() < 2) ? MinFromTime(t) : ctx->args()[1].toNumber(); - double sec = (ctx->argc() < 3) ? SecFromTime(t) : ctx->args()[2].toNumber(); - double ms = (ctx->argc() < 4) ? msFromTime(t) : ctx->args()[3].toNumber(); + double hour = callData->argc ? callData->args[0].toNumber() : qt_qnan(); + double min = (callData->argc < 2) ? MinFromTime(t) : callData->args[1].toNumber(); + double sec = (callData->argc < 3) ? SecFromTime(t) : callData->args[2].toNumber(); + double ms = (callData->argc < 4) ? msFromTime(t) : callData->args[3].toNumber(); t = TimeClip(MakeDate(Day(t), MakeTime(hour, min, sec, ms))); self->setDate(t); - return Encode(self->date()); + scope.result = Encode(self->date()); } -ReturnedValue DatePrototype::method_setDate(CallContext *ctx) +void DatePrototype::method_setDate(const BuiltinFunction *, Scope &scope, CallData *callData) { - DateObject *self = ctx->thisObject().as<DateObject>(); + DateObject *self = callData->thisObject.as<DateObject>(); if (!self) - return ctx->engine()->throwTypeError(); + THROW_TYPE_ERROR(); double t = LocalTime(self->date()); - double date = ctx->argc() ? ctx->args()[0].toNumber() : qt_qnan(); + double date = callData->argc ? callData->args[0].toNumber() : qt_qnan(); t = TimeClip(UTC(MakeDate(MakeDay(YearFromTime(t), MonthFromTime(t), date), TimeWithinDay(t)))); self->setDate(t); - return Encode(self->date()); + scope.result = Encode(self->date()); } -ReturnedValue DatePrototype::method_setUTCDate(CallContext *ctx) +void DatePrototype::method_setUTCDate(const BuiltinFunction *, Scope &scope, CallData *callData) { - DateObject *self = ctx->thisObject().as<DateObject>(); + DateObject *self = callData->thisObject.as<DateObject>(); if (!self) - return ctx->engine()->throwTypeError(); + THROW_TYPE_ERROR(); double t = self->date(); - double date = ctx->argc() ? ctx->args()[0].toNumber() : qt_qnan(); + double date = callData->argc ? callData->args[0].toNumber() : qt_qnan(); t = TimeClip(MakeDate(MakeDay(YearFromTime(t), MonthFromTime(t), date), TimeWithinDay(t))); self->setDate(t); - return Encode(self->date()); + scope.result = Encode(self->date()); } -ReturnedValue DatePrototype::method_setMonth(CallContext *ctx) +void DatePrototype::method_setMonth(const BuiltinFunction *, Scope &scope, CallData *callData) { - DateObject *self = ctx->thisObject().as<DateObject>(); + DateObject *self = callData->thisObject.as<DateObject>(); if (!self) - return ctx->engine()->throwTypeError(); + THROW_TYPE_ERROR(); double t = LocalTime(self->date()); - double month = ctx->argc() ? ctx->args()[0].toNumber() : qt_qnan(); - double date = (ctx->argc() < 2) ? DateFromTime(t) : ctx->args()[1].toNumber(); + double month = callData->argc ? callData->args[0].toNumber() : qt_qnan(); + double date = (callData->argc < 2) ? DateFromTime(t) : callData->args[1].toNumber(); t = TimeClip(UTC(MakeDate(MakeDay(YearFromTime(t), month, date), TimeWithinDay(t)))); self->setDate(t); - return Encode(self->date()); + scope.result = Encode(self->date()); } -ReturnedValue DatePrototype::method_setUTCMonth(CallContext *ctx) +void DatePrototype::method_setUTCMonth(const BuiltinFunction *, Scope &scope, CallData *callData) { - DateObject *self = ctx->thisObject().as<DateObject>(); + DateObject *self = callData->thisObject.as<DateObject>(); if (!self) - return ctx->engine()->throwTypeError(); + THROW_TYPE_ERROR(); double t = self->date(); - double month = ctx->argc() ? ctx->args()[0].toNumber() : qt_qnan(); - double date = (ctx->argc() < 2) ? DateFromTime(t) : ctx->args()[1].toNumber(); + double month = callData->argc ? callData->args[0].toNumber() : qt_qnan(); + double date = (callData->argc < 2) ? DateFromTime(t) : callData->args[1].toNumber(); t = TimeClip(MakeDate(MakeDay(YearFromTime(t), month, date), TimeWithinDay(t))); self->setDate(t); - return Encode(self->date()); + scope.result = Encode(self->date()); } -ReturnedValue DatePrototype::method_setYear(CallContext *ctx) +void DatePrototype::method_setYear(const BuiltinFunction *, Scope &scope, CallData *callData) { - DateObject *self = ctx->thisObject().as<DateObject>(); + DateObject *self = callData->thisObject.as<DateObject>(); if (!self) - return ctx->engine()->throwTypeError(); + THROW_TYPE_ERROR(); double t = self->date(); if (std::isnan(t)) t = 0; else t = LocalTime(t); - double year = ctx->argc() ? ctx->args()[0].toNumber() : qt_qnan(); + double year = callData->argc ? callData->args[0].toNumber() : qt_qnan(); double r; if (std::isnan(year)) { r = qt_qnan(); @@ -1220,49 +1220,49 @@ ReturnedValue DatePrototype::method_setYear(CallContext *ctx) r = TimeClip(r); } self->setDate(r); - return Encode(self->date()); + scope.result = Encode(self->date()); } -ReturnedValue DatePrototype::method_setUTCFullYear(CallContext *ctx) +void DatePrototype::method_setUTCFullYear(const BuiltinFunction *, Scope &scope, CallData *callData) { - DateObject *self = ctx->thisObject().as<DateObject>(); + DateObject *self = callData->thisObject.as<DateObject>(); if (!self) - return ctx->engine()->throwTypeError(); + THROW_TYPE_ERROR(); double t = self->date(); - double year = ctx->argc() ? ctx->args()[0].toNumber() : qt_qnan(); - double month = (ctx->argc() < 2) ? MonthFromTime(t) : ctx->args()[1].toNumber(); - double date = (ctx->argc() < 3) ? DateFromTime(t) : ctx->args()[2].toNumber(); + double year = callData->argc ? callData->args[0].toNumber() : qt_qnan(); + double month = (callData->argc < 2) ? MonthFromTime(t) : callData->args[1].toNumber(); + double date = (callData->argc < 3) ? DateFromTime(t) : callData->args[2].toNumber(); t = TimeClip(MakeDate(MakeDay(year, month, date), TimeWithinDay(t))); self->setDate(t); - return Encode(self->date()); + scope.result = Encode(self->date()); } -ReturnedValue DatePrototype::method_setFullYear(CallContext *ctx) +void DatePrototype::method_setFullYear(const BuiltinFunction *, Scope &scope, CallData *callData) { - DateObject *self = ctx->thisObject().as<DateObject>(); + DateObject *self = callData->thisObject.as<DateObject>(); if (!self) - return ctx->engine()->throwTypeError(); + THROW_TYPE_ERROR(); double t = LocalTime(self->date()); if (std::isnan(t)) t = 0; - double year = ctx->argc() ? ctx->args()[0].toNumber() : qt_qnan(); - double month = (ctx->argc() < 2) ? MonthFromTime(t) : ctx->args()[1].toNumber(); - double date = (ctx->argc() < 3) ? DateFromTime(t) : ctx->args()[2].toNumber(); + double year = callData->argc ? callData->args[0].toNumber() : qt_qnan(); + double month = (callData->argc < 2) ? MonthFromTime(t) : callData->args[1].toNumber(); + double date = (callData->argc < 3) ? DateFromTime(t) : callData->args[2].toNumber(); t = TimeClip(UTC(MakeDate(MakeDay(year, month, date), TimeWithinDay(t)))); self->setDate(t); - return Encode(self->date()); + scope.result = Encode(self->date()); } -ReturnedValue DatePrototype::method_toUTCString(CallContext *ctx) +void DatePrototype::method_toUTCString(const BuiltinFunction *, Scope &scope, CallData *callData) { - DateObject *self = ctx->thisObject().as<DateObject>(); + DateObject *self = callData->thisObject.as<DateObject>(); if (!self) - return ctx->engine()->throwTypeError(); + THROW_TYPE_ERROR(); double t = self->date(); - return ctx->d()->engine->newString(ToUTCString(t))->asReturnedValue(); + scope.result = scope.engine->newString(ToUTCString(t)); } static void addZeroPrefixedInt(QString &str, int num, int nDigits) @@ -1278,21 +1278,21 @@ static void addZeroPrefixedInt(QString &str, int num, int nDigits) } } -ReturnedValue DatePrototype::method_toISOString(CallContext *ctx) +void DatePrototype::method_toISOString(const BuiltinFunction *, Scope &scope, CallData *callData) { - DateObject *self = ctx->thisObject().as<DateObject>(); + DateObject *self = callData->thisObject.as<DateObject>(); if (!self) - return ctx->engine()->throwTypeError(); + THROW_TYPE_ERROR(); double t = self->date(); if (!std::isfinite(t)) - return ctx->engine()->throwRangeError(ctx->thisObject()); + RETURN_RESULT(scope.engine->throwRangeError(callData->thisObject)); QString result; int year = (int)YearFromTime(t); if (year < 0 || year > 9999) { if (qAbs(year) >= 1000000) - return ctx->d()->engine->newString(QStringLiteral("Invalid Date"))->asReturnedValue(); + RETURN_RESULT(scope.engine->newString(QStringLiteral("Invalid Date"))); result += year < 0 ? QLatin1Char('-') : QLatin1Char('+'); year = qAbs(year); addZeroPrefixedInt(result, year, 6); @@ -1313,32 +1313,29 @@ ReturnedValue DatePrototype::method_toISOString(CallContext *ctx) addZeroPrefixedInt(result, msFromTime(t), 3); result += QLatin1Char('Z'); - return ctx->d()->engine->newString(result)->asReturnedValue(); + scope.result = scope.engine->newString(result); } -ReturnedValue DatePrototype::method_toJSON(CallContext *ctx) +void DatePrototype::method_toJSON(const BuiltinFunction *, Scope &scope, CallData *callData) { - Scope scope(ctx); - ScopedObject O(scope, ctx->thisObject().toObject(scope.engine)); - if (scope.hasException()) - return Encode::undefined(); + ScopedObject O(scope, callData->thisObject.toObject(scope.engine)); + CHECK_EXCEPTION(); ScopedValue tv(scope, RuntimeHelpers::toPrimitive(O, NUMBER_HINT)); if (tv->isNumber() && !std::isfinite(tv->toNumber())) - return Encode::null(); + RETURN_RESULT(Encode::null()); - ScopedString s(scope, ctx->d()->engine->newString(QStringLiteral("toISOString"))); + ScopedString s(scope, scope.engine->newString(QStringLiteral("toISOString"))); ScopedValue v(scope, O->get(s)); FunctionObject *toIso = v->as<FunctionObject>(); if (!toIso) - return ctx->engine()->throwTypeError(); + THROW_TYPE_ERROR(); - ScopedCallData callData(scope); - callData->thisObject = ctx->thisObject(); - toIso->call(scope, callData); - return scope.result.asReturnedValue(); + ScopedCallData cData(scope); + cData->thisObject = callData->thisObject; + toIso->call(scope, cData); } void DatePrototype::timezoneUpdated() diff --git a/src/qml/jsruntime/qv4dateobject_p.h b/src/qml/jsruntime/qv4dateobject_p.h index 835f6adbe0..a56d17f9b1 100644 --- a/src/qml/jsruntime/qv4dateobject_p.h +++ b/src/qml/jsruntime/qv4dateobject_p.h @@ -116,57 +116,57 @@ struct DatePrototype: DateObject { void init(ExecutionEngine *engine, Object *ctor); - static double getThisDate(ExecutionContext *ctx); - - static ReturnedValue method_parse(CallContext *ctx); - static ReturnedValue method_UTC(CallContext *ctx); - static ReturnedValue method_now(CallContext *ctx); - - static ReturnedValue method_toString(CallContext *ctx); - static ReturnedValue method_toDateString(CallContext *ctx); - static ReturnedValue method_toTimeString(CallContext *ctx); - static ReturnedValue method_toLocaleString(CallContext *ctx); - static ReturnedValue method_toLocaleDateString(CallContext *ctx); - static ReturnedValue method_toLocaleTimeString(CallContext *ctx); - static ReturnedValue method_valueOf(CallContext *ctx); - static ReturnedValue method_getTime(CallContext *ctx); - static ReturnedValue method_getYear(CallContext *ctx); - static ReturnedValue method_getFullYear(CallContext *ctx); - static ReturnedValue method_getUTCFullYear(CallContext *ctx); - static ReturnedValue method_getMonth(CallContext *ctx); - static ReturnedValue method_getUTCMonth(CallContext *ctx); - static ReturnedValue method_getDate(CallContext *ctx); - static ReturnedValue method_getUTCDate(CallContext *ctx); - static ReturnedValue method_getDay(CallContext *ctx); - static ReturnedValue method_getUTCDay(CallContext *ctx); - static ReturnedValue method_getHours(CallContext *ctx); - static ReturnedValue method_getUTCHours(CallContext *ctx); - static ReturnedValue method_getMinutes(CallContext *ctx); - static ReturnedValue method_getUTCMinutes(CallContext *ctx); - static ReturnedValue method_getSeconds(CallContext *ctx); - static ReturnedValue method_getUTCSeconds(CallContext *ctx); - static ReturnedValue method_getMilliseconds(CallContext *ctx); - static ReturnedValue method_getUTCMilliseconds(CallContext *ctx); - static ReturnedValue method_getTimezoneOffset(CallContext *ctx); - static ReturnedValue method_setTime(CallContext *ctx); - static ReturnedValue method_setMilliseconds(CallContext *ctx); - static ReturnedValue method_setUTCMilliseconds(CallContext *ctx); - static ReturnedValue method_setSeconds(CallContext *ctx); - static ReturnedValue method_setUTCSeconds(CallContext *ctx); - static ReturnedValue method_setMinutes(CallContext *ctx); - static ReturnedValue method_setUTCMinutes(CallContext *ctx); - static ReturnedValue method_setHours(CallContext *ctx); - static ReturnedValue method_setUTCHours(CallContext *ctx); - static ReturnedValue method_setDate(CallContext *ctx); - static ReturnedValue method_setUTCDate(CallContext *ctx); - static ReturnedValue method_setMonth(CallContext *ctx); - static ReturnedValue method_setUTCMonth(CallContext *ctx); - static ReturnedValue method_setYear(CallContext *ctx); - static ReturnedValue method_setFullYear(CallContext *ctx); - static ReturnedValue method_setUTCFullYear(CallContext *ctx); - static ReturnedValue method_toUTCString(CallContext *ctx); - static ReturnedValue method_toISOString(CallContext *ctx); - static ReturnedValue method_toJSON(CallContext *ctx); + static double getThisDate(Scope &scope, CallData *callData); + + static void method_parse(const BuiltinFunction *, Scope &scope, CallData *callData); + static void method_UTC(const BuiltinFunction *, Scope &scope, CallData *callData); + static void method_now(const BuiltinFunction *, Scope &scope, CallData *callData); + + static void method_toString(const BuiltinFunction *, Scope &scope, CallData *callData); + static void method_toDateString(const BuiltinFunction *, Scope &scope, CallData *callData); + static void method_toTimeString(const BuiltinFunction *, Scope &scope, CallData *callData); + static void method_toLocaleString(const BuiltinFunction *, Scope &scope, CallData *callData); + static void method_toLocaleDateString(const BuiltinFunction *, Scope &scope, CallData *callData); + static void method_toLocaleTimeString(const BuiltinFunction *, Scope &scope, CallData *callData); + static void method_valueOf(const BuiltinFunction *, Scope &scope, CallData *callData); + static void method_getTime(const BuiltinFunction *, Scope &scope, CallData *callData); + static void method_getYear(const BuiltinFunction *, Scope &scope, CallData *callData); + static void method_getFullYear(const BuiltinFunction *, Scope &scope, CallData *callData); + static void method_getUTCFullYear(const BuiltinFunction *, Scope &scope, CallData *callData); + static void method_getMonth(const BuiltinFunction *, Scope &scope, CallData *callData); + static void method_getUTCMonth(const BuiltinFunction *, Scope &scope, CallData *callData); + static void method_getDate(const BuiltinFunction *, Scope &scope, CallData *callData); + static void method_getUTCDate(const BuiltinFunction *, Scope &scope, CallData *callData); + static void method_getDay(const BuiltinFunction *, Scope &scope, CallData *callData); + static void method_getUTCDay(const BuiltinFunction *, Scope &scope, CallData *callData); + static void method_getHours(const BuiltinFunction *, Scope &scope, CallData *callData); + static void method_getUTCHours(const BuiltinFunction *, Scope &scope, CallData *callData); + static void method_getMinutes(const BuiltinFunction *, Scope &scope, CallData *callData); + static void method_getUTCMinutes(const BuiltinFunction *, Scope &scope, CallData *callData); + static void method_getSeconds(const BuiltinFunction *, Scope &scope, CallData *callData); + static void method_getUTCSeconds(const BuiltinFunction *, Scope &scope, CallData *callData); + static void method_getMilliseconds(const BuiltinFunction *, Scope &scope, CallData *callData); + static void method_getUTCMilliseconds(const BuiltinFunction *, Scope &scope, CallData *callData); + static void method_getTimezoneOffset(const BuiltinFunction *, Scope &scope, CallData *callData); + static void method_setTime(const BuiltinFunction *, Scope &scope, CallData *callData); + static void method_setMilliseconds(const BuiltinFunction *, Scope &scope, CallData *callData); + static void method_setUTCMilliseconds(const BuiltinFunction *, Scope &scope, CallData *callData); + static void method_setSeconds(const BuiltinFunction *, Scope &scope, CallData *callData); + static void method_setUTCSeconds(const BuiltinFunction *, Scope &scope, CallData *callData); + static void method_setMinutes(const BuiltinFunction *, Scope &scope, CallData *callData); + static void method_setUTCMinutes(const BuiltinFunction *, Scope &scope, CallData *callData); + static void method_setHours(const BuiltinFunction *, Scope &scope, CallData *callData); + static void method_setUTCHours(const BuiltinFunction *, Scope &scope, CallData *callData); + static void method_setDate(const BuiltinFunction *, Scope &scope, CallData *callData); + static void method_setUTCDate(const BuiltinFunction *, Scope &scope, CallData *callData); + static void method_setMonth(const BuiltinFunction *, Scope &scope, CallData *callData); + static void method_setUTCMonth(const BuiltinFunction *, Scope &scope, CallData *callData); + static void method_setYear(const BuiltinFunction *, Scope &scope, CallData *callData); + static void method_setFullYear(const BuiltinFunction *, Scope &scope, CallData *callData); + static void method_setUTCFullYear(const BuiltinFunction *, Scope &scope, CallData *callData); + static void method_toUTCString(const BuiltinFunction *, Scope &scope, CallData *callData); + static void method_toISOString(const BuiltinFunction *, Scope &scope, CallData *callData); + static void method_toJSON(const BuiltinFunction *, Scope &scope, CallData *callData); static void timezoneUpdated(); }; diff --git a/src/qml/jsruntime/qv4engine.cpp b/src/qml/jsruntime/qv4engine.cpp index 8f2c5174da..a11f7f0875 100644 --- a/src/qml/jsruntime/qv4engine.cpp +++ b/src/qml/jsruntime/qv4engine.cpp @@ -158,8 +158,6 @@ ExecutionEngine::ExecutionEngine(EvalISelFactory *factory) } Q_ASSERT(maxCallDepth > 0); - MemoryManager::GCBlocker gcBlocker(memoryManager); - if (!factory) { #if QT_CONFIG(qml_interpreter) bool jitDisabled = true; diff --git a/src/qml/jsruntime/qv4errorobject.cpp b/src/qml/jsruntime/qv4errorobject.cpp index 597ded6ae1..f290bc5136 100644 --- a/src/qml/jsruntime/qv4errorobject.cpp +++ b/src/qml/jsruntime/qv4errorobject.cpp @@ -153,12 +153,11 @@ const char *ErrorObject::className(Heap::ErrorObject::ErrorType t) Q_UNREACHABLE(); } -ReturnedValue ErrorObject::method_get_stack(CallContext *ctx) +void ErrorObject::method_get_stack(const BuiltinFunction *, Scope &scope, CallData *callData) { - Scope scope(ctx); - Scoped<ErrorObject> This(scope, ctx->thisObject()); + Scoped<ErrorObject> This(scope, callData->thisObject); if (!This) - return ctx->engine()->throwTypeError(); + THROW_TYPE_ERROR(); if (!This->d()->stack) { QString trace; for (int i = 0; i < This->d()->stackTrace->count(); ++i) { @@ -169,9 +168,9 @@ ReturnedValue ErrorObject::method_get_stack(CallContext *ctx) if (frame.line >= 0) trace += QLatin1Char(':') + QString::number(frame.line); } - This->d()->stack = ctx->d()->engine->newString(trace); + This->d()->stack = scope.engine->newString(trace); } - return This->d()->stack->asReturnedValue(); + scope.result = This->d()->stack; } void ErrorObject::markObjects(Heap::Base *that, ExecutionEngine *e) @@ -335,22 +334,20 @@ void ErrorPrototype::init(ExecutionEngine *engine, Object *ctor, Object *obj, He obj->defineDefaultProperty(engine->id_toString(), method_toString, 0); } -ReturnedValue ErrorPrototype::method_toString(CallContext *ctx) +void ErrorPrototype::method_toString(const BuiltinFunction *, Scope &scope, CallData *callData) { - Scope scope(ctx); - - Object *o = ctx->thisObject().as<Object>(); + Object *o = callData->thisObject.as<Object>(); if (!o) - return ctx->engine()->throwTypeError(); + THROW_TYPE_ERROR(); - ScopedValue name(scope, o->get(ctx->d()->engine->id_name())); + ScopedValue name(scope, o->get(scope.engine->id_name())); QString qname; if (name->isUndefined()) qname = QStringLiteral("Error"); else qname = name->toQString(); - ScopedString s(scope, ctx->d()->engine->newString(QStringLiteral("message"))); + ScopedString s(scope, scope.engine->newString(QStringLiteral("message"))); ScopedValue message(scope, o->get(s)); QString qmessage; if (!message->isUndefined()) @@ -365,5 +362,5 @@ ReturnedValue ErrorPrototype::method_toString(CallContext *ctx) str = qname + QLatin1String(": ") + qmessage; } - return ctx->d()->engine->newString(str)->asReturnedValue(); + scope.result = scope.engine->newString(str)->asReturnedValue(); } diff --git a/src/qml/jsruntime/qv4errorobject_p.h b/src/qml/jsruntime/qv4errorobject_p.h index 2b3ab25e2d..9ba9f05234 100644 --- a/src/qml/jsruntime/qv4errorobject_p.h +++ b/src/qml/jsruntime/qv4errorobject_p.h @@ -172,7 +172,7 @@ struct ErrorObject: Object { static const char *className(Heap::ErrorObject::ErrorType t); - static ReturnedValue method_get_stack(CallContext *ctx); + static void method_get_stack(const BuiltinFunction *, Scope &scope, CallData *callData); static void markObjects(Heap::Base *that, ExecutionEngine *e); }; @@ -282,7 +282,7 @@ struct ErrorPrototype : ErrorObject void init(ExecutionEngine *engine, Object *ctor) { init(engine, ctor, this, Heap::ErrorObject::Error); } static void init(ExecutionEngine *engine, Object *ctor, Object *obj, Heap::ErrorObject::ErrorType t); - static ReturnedValue method_toString(CallContext *ctx); + static void method_toString(const BuiltinFunction *, Scope &scope, CallData *callData); }; struct EvalErrorPrototype : ErrorObject diff --git a/src/qml/jsruntime/qv4functionobject.cpp b/src/qml/jsruntime/qv4functionobject.cpp index 64f7b98618..b2d89220ea 100644 --- a/src/qml/jsruntime/qv4functionobject.cpp +++ b/src/qml/jsruntime/qv4functionobject.cpp @@ -270,23 +270,22 @@ void FunctionPrototype::init(ExecutionEngine *engine, Object *ctor) } -ReturnedValue FunctionPrototype::method_toString(CallContext *ctx) +void FunctionPrototype::method_toString(const BuiltinFunction *, Scope &scope, CallData *callData) { - FunctionObject *fun = ctx->thisObject().as<FunctionObject>(); + FunctionObject *fun = callData->thisObject.as<FunctionObject>(); if (!fun) - return ctx->engine()->throwTypeError(); + THROW_TYPE_ERROR(); - return ctx->d()->engine->newString(QStringLiteral("function() { [code] }"))->asReturnedValue(); + scope.result = scope.engine->newString(QStringLiteral("function() { [code] }")); } -ReturnedValue FunctionPrototype::method_apply(CallContext *ctx) +void FunctionPrototype::method_apply(const BuiltinFunction *, Scope &scope, CallData *callData) { - FunctionObject *o = ctx->thisObject().as<FunctionObject>(); + FunctionObject *o = callData->thisObject.as<FunctionObject>(); if (!o) - return ctx->engine()->throwTypeError(); + THROW_TYPE_ERROR(); - Scope scope(ctx); - ScopedValue arg(scope, ctx->argument(1)); + ScopedValue arg(scope, callData->argument(1)); ScopedObject arr(scope, arg); @@ -294,75 +293,71 @@ ReturnedValue FunctionPrototype::method_apply(CallContext *ctx) if (!arr) { len = 0; if (!arg->isNullOrUndefined()) - return ctx->engine()->throwTypeError(); + THROW_TYPE_ERROR(); } else { len = arr->getLength(); } - ScopedCallData callData(scope, len); + ScopedCallData cData(scope, len); if (len) { if (ArgumentsObject::isNonStrictArgumentsObject(arr) && !arr->cast<ArgumentsObject>()->fullyCreated()) { QV4::ArgumentsObject *a = arr->cast<ArgumentsObject>(); int l = qMin(len, (uint)a->d()->context->callData->argc); - memcpy(callData->args, a->d()->context->callData->args, l*sizeof(Value)); + memcpy(cData->args, a->d()->context->callData->args, l*sizeof(Value)); for (quint32 i = l; i < len; ++i) - callData->args[i] = Primitive::undefinedValue(); + cData->args[i] = Primitive::undefinedValue(); } else if (arr->arrayType() == Heap::ArrayData::Simple && !arr->protoHasArray()) { auto sad = static_cast<Heap::SimpleArrayData *>(arr->arrayData()); uint alen = sad ? sad->len : 0; if (alen > len) alen = len; for (uint i = 0; i < alen; ++i) - callData->args[i] = sad->data(i); + cData->args[i] = sad->data(i); for (quint32 i = alen; i < len; ++i) - callData->args[i] = Primitive::undefinedValue(); + cData->args[i] = Primitive::undefinedValue(); } else { for (quint32 i = 0; i < len; ++i) - callData->args[i] = arr->getIndexed(i); + cData->args[i] = arr->getIndexed(i); } } - callData->thisObject = ctx->argument(0); - o->call(scope, callData); - return scope.result.asReturnedValue(); + cData->thisObject = callData->argument(0); + o->call(scope, cData); } -ReturnedValue FunctionPrototype::method_call(CallContext *ctx) +void FunctionPrototype::method_call(const BuiltinFunction *, Scope &scope, CallData *callData) { - FunctionObject *o = ctx->thisObject().as<FunctionObject>(); + FunctionObject *o = callData->thisObject.as<FunctionObject>(); if (!o) - return ctx->engine()->throwTypeError(); + THROW_TYPE_ERROR(); - Scope scope(ctx); - ScopedCallData callData(scope, ctx->argc() ? ctx->argc() - 1 : 0); - if (ctx->argc()) { - for (int i = 1; i < ctx->argc(); ++i) - callData->args[i - 1] = ctx->args()[i]; + ScopedCallData cData(scope, callData->argc ? callData->argc - 1 : 0); + if (callData->argc) { + for (int i = 1; i < callData->argc; ++i) + cData->args[i - 1] = callData->args[i]; } - callData->thisObject = ctx->argument(0); + cData->thisObject = callData->argument(0); - o->call(scope, callData); - return scope.result.asReturnedValue(); + o->call(scope, cData); } -ReturnedValue FunctionPrototype::method_bind(CallContext *ctx) +void FunctionPrototype::method_bind(const BuiltinFunction *, Scope &scope, CallData *callData) { - FunctionObject *target = ctx->thisObject().as<FunctionObject>(); + FunctionObject *target = callData->thisObject.as<FunctionObject>(); if (!target) - return ctx->engine()->throwTypeError(); + THROW_TYPE_ERROR(); - Scope scope(ctx); - ScopedValue boundThis(scope, ctx->argument(0)); + ScopedValue boundThis(scope, callData->argument(0)); Scoped<MemberData> boundArgs(scope, (Heap::MemberData *)0); - if (ctx->argc() > 1) { - boundArgs = MemberData::allocate(scope.engine, ctx->argc() - 1); - boundArgs->d()->size = ctx->argc() - 1; - memcpy(boundArgs->data(), ctx->args() + 1, (ctx->argc() - 1)*sizeof(Value)); + if (callData->argc > 1) { + boundArgs = MemberData::allocate(scope.engine, callData->argc - 1); + boundArgs->d()->size = callData->argc - 1; + memcpy(boundArgs->data(), callData->args + 1, (callData->argc - 1)*sizeof(Value)); } ExecutionContext *global = scope.engine->rootContext(); - return BoundFunction::create(global, target, boundThis, boundArgs)->asReturnedValue(); + scope.result = BoundFunction::create(global, target, boundThis, boundArgs); } DEFINE_OBJECT_VTABLE(ScriptFunction); @@ -459,22 +454,22 @@ Heap::Object *ScriptFunction::protoForConstructor() const -DEFINE_OBJECT_VTABLE(BuiltinFunction); +DEFINE_OBJECT_VTABLE(OldBuiltinFunction); -void Heap::BuiltinFunction::init(QV4::ExecutionContext *scope, QV4::String *name, ReturnedValue (*code)(QV4::CallContext *)) +void Heap::OldBuiltinFunction::init(QV4::ExecutionContext *scope, QV4::String *name, ReturnedValue (*code)(QV4::CallContext *)) { Heap::FunctionObject::init(scope, name); this->code = code; } -void BuiltinFunction::construct(const Managed *f, Scope &scope, CallData *) +void OldBuiltinFunction::construct(const Managed *f, Scope &scope, CallData *) { - scope.result = static_cast<const BuiltinFunction *>(f)->internalClass()->engine->throwTypeError(); + scope.result = static_cast<const OldBuiltinFunction *>(f)->internalClass()->engine->throwTypeError(); } -void BuiltinFunction::call(const Managed *that, Scope &scope, CallData *callData) +void OldBuiltinFunction::call(const Managed *that, Scope &scope, CallData *callData) { - const BuiltinFunction *f = static_cast<const BuiltinFunction *>(that); + const OldBuiltinFunction *f = static_cast<const OldBuiltinFunction *>(that); ExecutionEngine *v4 = scope.engine; if (v4->hasException) { scope.result = Encode::undefined(); @@ -484,15 +479,41 @@ void BuiltinFunction::call(const Managed *that, Scope &scope, CallData *callData ExecutionContextSaver ctxSaver(scope); - CallContext::Data ctx = CallContext::Data::createOnStack(v4); - ctx.strictMode = f->scope()->strictMode; // ### needed? scope or parent context? - ctx.callData = callData; - v4->pushContext(&ctx); - Q_ASSERT(v4->current == &ctx); + CallContext::Data *ctx = v4->memoryManager->allocSimpleCallContext(v4); + ctx->strictMode = f->scope()->strictMode; // ### needed? scope or parent context? + ctx->callData = callData; + v4->pushContext(ctx); + Q_ASSERT(v4->current == ctx); scope.result = f->d()->code(static_cast<QV4::CallContext *>(v4->currentContext)); + v4->memoryManager->freeSimpleCallContext(); +} + +DEFINE_OBJECT_VTABLE(BuiltinFunction); + +void Heap::BuiltinFunction::init(QV4::ExecutionContext *scope, QV4::String *name, void (*code)(const QV4::BuiltinFunction *, Scope &, CallData *)) +{ + Heap::FunctionObject::init(scope, name); + this->code = code; +} + +void BuiltinFunction::construct(const Managed *f, Scope &scope, CallData *) +{ + scope.result = static_cast<const BuiltinFunction *>(f)->internalClass()->engine->throwTypeError(); +} + +void BuiltinFunction::call(const Managed *that, Scope &scope, CallData *callData) +{ + const BuiltinFunction *f = static_cast<const BuiltinFunction *>(that); + ExecutionEngine *v4 = scope.engine; + if (v4->hasException) { + scope.result = Encode::undefined(); + return; + } + f->d()->code(f, scope, callData); } + void IndexedBuiltinFunction::call(const Managed *that, Scope &scope, CallData *callData) { const IndexedBuiltinFunction *f = static_cast<const IndexedBuiltinFunction *>(that); @@ -505,13 +526,14 @@ void IndexedBuiltinFunction::call(const Managed *that, Scope &scope, CallData *c ExecutionContextSaver ctxSaver(scope); - CallContext::Data ctx = CallContext::Data::createOnStack(v4); - ctx.strictMode = f->scope()->strictMode; // ### needed? scope or parent context? - ctx.callData = callData; - v4->pushContext(&ctx); - Q_ASSERT(v4->current == &ctx); + CallContext::Data *ctx = v4->memoryManager->allocSimpleCallContext(v4); + ctx->strictMode = f->scope()->strictMode; // ### needed? scope or parent context? + ctx->callData = callData; + v4->pushContext(ctx); + Q_ASSERT(v4->current == ctx); scope.result = f->d()->code(static_cast<QV4::CallContext *>(v4->currentContext), f->d()->index); + v4->memoryManager->freeSimpleCallContext(); } DEFINE_OBJECT_VTABLE(IndexedBuiltinFunction); diff --git a/src/qml/jsruntime/qv4functionobject_p.h b/src/qml/jsruntime/qv4functionobject_p.h index a02e89e883..45d7485f1b 100644 --- a/src/qml/jsruntime/qv4functionobject_p.h +++ b/src/qml/jsruntime/qv4functionobject_p.h @@ -61,6 +61,8 @@ struct QQmlSourceLocation; namespace QV4 { +struct BuiltinFunction; + namespace Heap { struct Q_QML_PRIVATE_EXPORT FunctionObject : Object { @@ -93,11 +95,16 @@ struct FunctionPrototype : FunctionObject { void init(); }; -struct Q_QML_EXPORT BuiltinFunction : FunctionObject { +struct Q_QML_EXPORT OldBuiltinFunction : FunctionObject { void init(QV4::ExecutionContext *scope, QV4::String *name, ReturnedValue (*code)(QV4::CallContext *)); ReturnedValue (*code)(QV4::CallContext *); }; +struct Q_QML_EXPORT BuiltinFunction : FunctionObject { + void init(QV4::ExecutionContext *scope, QV4::String *name, void (*code)(const QV4::BuiltinFunction *, Scope &, CallData *)); + void (*code)(const QV4::BuiltinFunction *, Scope &, CallData *); +}; + struct IndexedBuiltinFunction : FunctionObject { inline void init(QV4::ExecutionContext *scope, uint index, ReturnedValue (*code)(QV4::CallContext *ctx, uint index)); ReturnedValue (*code)(QV4::CallContext *, uint index); @@ -177,16 +184,27 @@ struct FunctionPrototype: FunctionObject void init(ExecutionEngine *engine, Object *ctor); - static ReturnedValue method_toString(CallContext *ctx); - static ReturnedValue method_apply(CallContext *ctx); - static ReturnedValue method_call(CallContext *ctx); - static ReturnedValue method_bind(CallContext *ctx); + static void method_toString(const BuiltinFunction *, Scope &scope, CallData *callData); + static void method_apply(const BuiltinFunction *, Scope &scope, CallData *callData); + static void method_call(const BuiltinFunction *, Scope &scope, CallData *callData); + static void method_bind(const BuiltinFunction *, Scope &scope, CallData *callData); }; -struct Q_QML_EXPORT BuiltinFunction: FunctionObject { +struct Q_QML_EXPORT OldBuiltinFunction : FunctionObject { + V4_OBJECT2(OldBuiltinFunction, FunctionObject) + + static void construct(const Managed *, Scope &scope, CallData *); + static void call(const Managed *that, Scope &scope, CallData *callData); +}; + +struct Q_QML_EXPORT BuiltinFunction : FunctionObject { V4_OBJECT2(BuiltinFunction, FunctionObject) - static Heap::BuiltinFunction *create(ExecutionContext *scope, String *name, ReturnedValue (*code)(CallContext *)) + static Heap::OldBuiltinFunction *create(ExecutionContext *scope, String *name, ReturnedValue (*code)(CallContext *)) + { + return scope->engine()->memoryManager->allocObject<OldBuiltinFunction>(scope, name, code); + } + static Heap::BuiltinFunction *create(ExecutionContext *scope, String *name, void (*code)(const BuiltinFunction *, Scope &, CallData *)) { return scope->engine()->memoryManager->allocObject<BuiltinFunction>(scope, name, code); } diff --git a/src/qml/jsruntime/qv4global_p.h b/src/qml/jsruntime/qv4global_p.h index c37ad1668d..66861bf697 100644 --- a/src/qml/jsruntime/qv4global_p.h +++ b/src/qml/jsruntime/qv4global_p.h @@ -97,19 +97,19 @@ inline double trunc(double d) { return d > 0 ? floor(d) : ceil(d); } // // NOTE: This should match the logic in qv4targetplatform_p.h! -#if defined(Q_PROCESSOR_X86) && !defined(__ILP32__) \ +#if defined(Q_PROCESSOR_X86) && (QT_POINTER_SIZE == 4) \ && (defined(Q_OS_WIN) || defined(Q_OS_LINUX) || defined(Q_OS_QNX) || defined(Q_OS_FREEBSD)) # define V4_ENABLE_JIT -#elif defined(Q_PROCESSOR_X86_64) && !defined(__ILP32__) \ +#elif defined(Q_PROCESSOR_X86_64) && (QT_POINTER_SIZE == 8) \ && (defined(Q_OS_WIN) || defined(Q_OS_LINUX) || defined(Q_OS_MAC) || defined(Q_OS_FREEBSD)) # define V4_ENABLE_JIT -#elif defined(Q_PROCESSOR_ARM_32) +#elif defined(Q_PROCESSOR_ARM_32) && (QT_POINTER_SIZE == 4) # 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 -#elif defined(Q_PROCESSOR_ARM_64) +#elif defined(Q_PROCESSOR_ARM_64) && (QT_POINTER_SIZE == 8) # if defined(Q_OS_LINUX) # define V4_ENABLE_JIT # endif @@ -208,6 +208,7 @@ struct StringObject; struct ArrayObject; struct DateObject; struct FunctionObject; +struct BuiltinFunction; struct ErrorObject; struct ArgumentsObject; struct Managed; diff --git a/src/qml/jsruntime/qv4globalobject.cpp b/src/qml/jsruntime/qv4globalobject.cpp index af92ce1ad8..1bc91f832b 100644 --- a/src/qml/jsruntime/qv4globalobject.cpp +++ b/src/qml/jsruntime/qv4globalobject.cpp @@ -423,18 +423,15 @@ static inline int toInt(const QChar &qc, int R) } // parseInt [15.1.2.2] -ReturnedValue GlobalFunctions::method_parseInt(CallContext *ctx) +void GlobalFunctions::method_parseInt(const BuiltinFunction *, Scope &scope, CallData *callData) { - Scope scope(ctx); - ScopedValue inputString(scope, ctx->argument(0)); - ScopedValue radix(scope, ctx->argument(1)); + ScopedValue inputString(scope, callData->argument(0)); + ScopedValue radix(scope, callData->argument(1)); int R = radix->isUndefined() ? 0 : radix->toInt32(); // [15.1.2.2] step by step: QString trimmed = inputString->toQString().trimmed(); // 1 + 2 - - if (ctx->d()->engine->hasException) - return Encode::undefined(); + CHECK_EXCEPTION(); const QChar *pos = trimmed.constData(); const QChar *end = pos + trimmed.length(); @@ -449,7 +446,7 @@ ReturnedValue GlobalFunctions::method_parseInt(CallContext *ctx) bool stripPrefix = true; // 7 if (R) { // 8 if (R < 2 || R > 36) - return Encode(std::numeric_limits<double>::quiet_NaN()); // 8a + RETURN_RESULT(Encode(std::numeric_limits<double>::quiet_NaN())); // 8a if (R != 16) stripPrefix = false; // 8b } else { // 9 @@ -466,13 +463,13 @@ ReturnedValue GlobalFunctions::method_parseInt(CallContext *ctx) // 11: Z is progressively built below // 13: this is handled by the toInt function if (pos == end) // 12 - return Encode(std::numeric_limits<double>::quiet_NaN()); + RETURN_RESULT(Encode(std::numeric_limits<double>::quiet_NaN())); bool overflow = false; qint64 v_overflow = 0; unsigned overflow_digit_count = 0; int d = toInt(*pos++, R); if (d == -1) - return Encode(std::numeric_limits<double>::quiet_NaN()); + RETURN_RESULT(Encode(std::numeric_limits<double>::quiet_NaN())); qint64 v = d; while (pos != end) { d = toInt(*pos++, R); @@ -499,155 +496,148 @@ ReturnedValue GlobalFunctions::method_parseInt(CallContext *ctx) if (overflow) { double result = (double) v_overflow * pow(static_cast<double>(R), static_cast<double>(overflow_digit_count)); result += v; - return Encode(sign * result); + RETURN_RESULT(Encode(sign * result)); } else { - return Encode(sign * (double) v); // 15 + RETURN_RESULT(Encode(sign * (double) v)); // 15 } } // parseFloat [15.1.2.3] -ReturnedValue GlobalFunctions::method_parseFloat(CallContext *ctx) +void GlobalFunctions::method_parseFloat(const BuiltinFunction *, Scope &scope, CallData *callData) { - Scope scope(ctx); - // [15.1.2.3] step by step: - ScopedString inputString(scope, ctx->argument(0), ScopedString::Convert); - if (scope.engine->hasException) - return Encode::undefined(); + ScopedString inputString(scope, callData->argument(0), ScopedString::Convert); + CHECK_EXCEPTION(); QString trimmed = inputString->toQString().trimmed(); // 2 // 4: if (trimmed.startsWith(QLatin1String("Infinity")) || trimmed.startsWith(QLatin1String("+Infinity"))) - return Encode(Q_INFINITY); + RETURN_RESULT(Encode(Q_INFINITY)); if (trimmed.startsWith(QLatin1String("-Infinity"))) - return Encode(-Q_INFINITY); + RETURN_RESULT(Encode(-Q_INFINITY)); QByteArray ba = trimmed.toLatin1(); bool ok; const char *begin = ba.constData(); const char *end = 0; double d = qstrtod(begin, &end, &ok); if (end - begin == 0) - return Encode(std::numeric_limits<double>::quiet_NaN()); // 3 + RETURN_RESULT(Encode(std::numeric_limits<double>::quiet_NaN())); // 3 else - return Encode(d); + RETURN_RESULT(Encode(d)); } /// isNaN [15.1.2.4] -ReturnedValue GlobalFunctions::method_isNaN(CallContext *ctx) +void GlobalFunctions::method_isNaN(const BuiltinFunction *, Scope &scope, CallData *callData) { - if (!ctx->argc()) + if (!callData->argc) // undefined gets converted to NaN - return Encode(true); + RETURN_RESULT(Encode(true)); - if (ctx->args()[0].integerCompatible()) - return Encode(false); + if (callData->args[0].integerCompatible()) + RETURN_RESULT(Encode(false)); - double d = ctx->args()[0].toNumber(); - return Encode((bool)std::isnan(d)); + double d = callData->args[0].toNumber(); + RETURN_RESULT(Encode((bool)std::isnan(d))); } /// isFinite [15.1.2.5] -ReturnedValue GlobalFunctions::method_isFinite(CallContext *ctx) +void GlobalFunctions::method_isFinite(const BuiltinFunction *, Scope &scope, CallData *callData) { - if (!ctx->argc()) + if (!callData->argc) // undefined gets converted to NaN - return Encode(false); + RETURN_RESULT(Encode(false)); - if (ctx->args()[0].integerCompatible()) - return Encode(true); + if (callData->args[0].integerCompatible()) + RETURN_RESULT(Encode(true)); - double d = ctx->args()[0].toNumber(); - return Encode((bool)std::isfinite(d)); + double d = callData->args[0].toNumber(); + RETURN_RESULT(Encode((bool)std::isfinite(d))); } /// decodeURI [15.1.3.1] -ReturnedValue GlobalFunctions::method_decodeURI(CallContext *context) +void GlobalFunctions::method_decodeURI(const BuiltinFunction *, Scope &scope, CallData *callData) { - if (context->argc() == 0) - return Encode::undefined(); + if (callData->argc == 0) + RETURN_UNDEFINED(); - QString uriString = context->args()[0].toQString(); + QString uriString = callData->args[0].toQString(); bool ok; QString out = decode(uriString, DecodeNonReserved, &ok); if (!ok) { - Scope scope(context); - ScopedString s(scope, context->d()->engine->newString(QStringLiteral("malformed URI sequence"))); - return context->engine()->throwURIError(s); + ScopedString s(scope, scope.engine->newString(QStringLiteral("malformed URI sequence"))); + RETURN_RESULT(scope.engine->throwURIError(s)); } - return context->d()->engine->newString(out)->asReturnedValue(); + RETURN_RESULT(scope.engine->newString(out)); } /// decodeURIComponent [15.1.3.2] -ReturnedValue GlobalFunctions::method_decodeURIComponent(CallContext *context) +void GlobalFunctions::method_decodeURIComponent(const BuiltinFunction *, Scope &scope, CallData *callData) { - if (context->argc() == 0) - return Encode::undefined(); + if (callData->argc == 0) + RETURN_UNDEFINED(); - QString uriString = context->args()[0].toQString(); + QString uriString = callData->args[0].toQString(); bool ok; QString out = decode(uriString, DecodeAll, &ok); if (!ok) { - Scope scope(context); - ScopedString s(scope, context->d()->engine->newString(QStringLiteral("malformed URI sequence"))); - return context->engine()->throwURIError(s); + ScopedString s(scope, scope.engine->newString(QStringLiteral("malformed URI sequence"))); + RETURN_RESULT(scope.engine->throwURIError(s)); } - return context->d()->engine->newString(out)->asReturnedValue(); + RETURN_RESULT(scope.engine->newString(out)); } /// encodeURI [15.1.3.3] -ReturnedValue GlobalFunctions::method_encodeURI(CallContext *context) +void GlobalFunctions::method_encodeURI(const BuiltinFunction *, Scope &scope, CallData *callData) { - if (context->argc() == 0) - return Encode::undefined(); + if (callData->argc == 0) + RETURN_UNDEFINED(); - QString uriString = context->args()[0].toQString(); + QString uriString = callData->args[0].toQString(); bool ok; QString out = encode(uriString, uriUnescapedReserved, &ok); if (!ok) { - Scope scope(context); - ScopedString s(scope, context->d()->engine->newString(QStringLiteral("malformed URI sequence"))); - return context->engine()->throwURIError(s); + ScopedString s(scope, scope.engine->newString(QStringLiteral("malformed URI sequence"))); + RETURN_RESULT(scope.engine->throwURIError(s)); } - return context->d()->engine->newString(out)->asReturnedValue(); + RETURN_RESULT(scope.engine->newString(out)); } /// encodeURIComponent [15.1.3.4] -ReturnedValue GlobalFunctions::method_encodeURIComponent(CallContext *context) +void GlobalFunctions::method_encodeURIComponent(const BuiltinFunction *, Scope &scope, CallData *callData) { - if (context->argc() == 0) - return Encode::undefined(); + if (callData->argc == 0) + RETURN_UNDEFINED(); - QString uriString = context->args()[0].toQString(); + QString uriString = callData->args[0].toQString(); bool ok; QString out = encode(uriString, uriUnescaped, &ok); if (!ok) { - Scope scope(context); - ScopedString s(scope, context->d()->engine->newString(QStringLiteral("malformed URI sequence"))); - return context->engine()->throwURIError(s); + ScopedString s(scope, scope.engine->newString(QStringLiteral("malformed URI sequence"))); + RETURN_RESULT(scope.engine->throwURIError(s)); } - return context->d()->engine->newString(out)->asReturnedValue(); + RETURN_RESULT(scope.engine->newString(out)); } -ReturnedValue GlobalFunctions::method_escape(CallContext *context) +void GlobalFunctions::method_escape(const BuiltinFunction *, Scope &scope, CallData *callData) { - if (!context->argc()) - return context->d()->engine->newString(QStringLiteral("undefined"))->asReturnedValue(); + if (!callData->argc) + RETURN_RESULT(scope.engine->newString(QStringLiteral("undefined"))); - QString str = context->args()[0].toQString(); - return context->d()->engine->newString(escape(str))->asReturnedValue(); + QString str = callData->args[0].toQString(); + RETURN_RESULT(scope.engine->newString(escape(str))); } -ReturnedValue GlobalFunctions::method_unescape(CallContext *context) +void GlobalFunctions::method_unescape(const BuiltinFunction *, Scope &scope, CallData *callData) { - if (!context->argc()) - return context->d()->engine->newString(QStringLiteral("undefined"))->asReturnedValue(); + if (!callData->argc) + RETURN_RESULT(scope.engine->newString(QStringLiteral("undefined"))); - QString str = context->args()[0].toQString(); - return context->d()->engine->newString(unescape(str))->asReturnedValue(); + QString str = callData->args[0].toQString(); + RETURN_RESULT(scope.engine->newString(unescape(str))); } diff --git a/src/qml/jsruntime/qv4globalobject_p.h b/src/qml/jsruntime/qv4globalobject_p.h index e8b3a92d34..273f1ba7ea 100644 --- a/src/qml/jsruntime/qv4globalobject_p.h +++ b/src/qml/jsruntime/qv4globalobject_p.h @@ -76,16 +76,16 @@ struct Q_QML_EXPORT EvalFunction : FunctionObject struct GlobalFunctions { - static ReturnedValue method_parseInt(CallContext *context); - static ReturnedValue method_parseFloat(CallContext *context); - static ReturnedValue method_isNaN(CallContext *context); - static ReturnedValue method_isFinite(CallContext *ctx); - static ReturnedValue method_decodeURI(CallContext *context); - static ReturnedValue method_decodeURIComponent(CallContext *context); - static ReturnedValue method_encodeURI(CallContext *context); - static ReturnedValue method_encodeURIComponent(CallContext *context); - static ReturnedValue method_escape(CallContext *context); - static ReturnedValue method_unescape(CallContext *context); + static void method_parseInt(const BuiltinFunction *, Scope &scope, CallData *callData); + static void method_parseFloat(const BuiltinFunction *, Scope &scope, CallData *callData); + static void method_isNaN(const BuiltinFunction *, Scope &scope, CallData *callData); + static void method_isFinite(const BuiltinFunction *, Scope &scope, CallData *callData); + static void method_decodeURI(const BuiltinFunction *, Scope &scope, CallData *callData); + static void method_decodeURIComponent(const BuiltinFunction *, Scope &scope, CallData *callData); + static void method_encodeURI(const BuiltinFunction *, Scope &scope, CallData *callData); + static void method_encodeURIComponent(const BuiltinFunction *, Scope &scope, CallData *callData); + static void method_escape(const BuiltinFunction *, Scope &scope, CallData *callData); + static void method_unescape(const BuiltinFunction *, Scope &scope, CallData *callData); }; } diff --git a/src/qml/jsruntime/qv4include.cpp b/src/qml/jsruntime/qv4include.cpp index 1d393cf0aa..f033eb2d2d 100644 --- a/src/qml/jsruntime/qv4include.cpp +++ b/src/qml/jsruntime/qv4include.cpp @@ -195,23 +195,22 @@ void QV4Include::finished() /* Documented in qv8engine.cpp */ -QV4::ReturnedValue QV4Include::method_include(QV4::CallContext *ctx) +void QV4Include::method_include(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData) { - if (!ctx->argc()) - return QV4::Encode::undefined(); + if (!callData->argc) + RETURN_UNDEFINED(); - QV4::Scope scope(ctx->engine()); QQmlContextData *context = scope.engine->callingQmlContext(); if (!context || !context->isJSContext) - V4THROW_ERROR("Qt.include(): Can only be called from JavaScript files"); + RETURN_RESULT(scope.engine->throwError(QString::fromUtf8("Qt.include(): Can only be called from JavaScript files"))); QV4::ScopedValue callbackFunction(scope, QV4::Primitive::undefinedValue()); - if (ctx->argc() >= 2 && ctx->args()[1].as<QV4::FunctionObject>()) - callbackFunction = ctx->args()[1]; + if (callData->argc >= 2 && callData->args[1].as<QV4::FunctionObject>()) + callbackFunction = callData->args[1]; #if QT_CONFIG(qml_network) - QUrl url(scope.engine->resolvedUrl(ctx->args()[0].toQStringNoThrow())); + QUrl url(scope.engine->resolvedUrl(callData->args[0].toQStringNoThrow())); if (scope.engine->qmlEngine() && scope.engine->qmlEngine()->urlInterceptor()) url = scope.engine->qmlEngine()->urlInterceptor()->intercept(url, QQmlAbstractUrlInterceptor::JavaScriptFile); @@ -261,12 +260,12 @@ QV4::ReturnedValue QV4Include::method_include(QV4::CallContext *ctx) callback(callbackFunction, result); } - return result->asReturnedValue(); + scope.result = result; #else QV4::ScopedValue result(scope); result = resultValue(scope.engine, NetworkError); callback(callbackFunction, result); - return result->asReturnedValue(); + scope.result = result; #endif } diff --git a/src/qml/jsruntime/qv4include_p.h b/src/qml/jsruntime/qv4include_p.h index 4c601a5e7b..5908d6bfde 100644 --- a/src/qml/jsruntime/qv4include_p.h +++ b/src/qml/jsruntime/qv4include_p.h @@ -77,7 +77,7 @@ public: Exception = 3 }; - static QV4::ReturnedValue method_include(QV4::CallContext *ctx); + static void method_include(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData); private Q_SLOTS: void finished(); diff --git a/src/qml/jsruntime/qv4internalclass.cpp b/src/qml/jsruntime/qv4internalclass.cpp index d17da9af0c..bac71b4537 100644 --- a/src/qml/jsruntime/qv4internalclass.cpp +++ b/src/qml/jsruntime/qv4internalclass.cpp @@ -128,48 +128,22 @@ InternalClass::InternalClass(const QV4::InternalClass &other) static void insertHoleIntoPropertyData(Object *object, int idx) { - int inlineSize = object->d()->inlineMemberSize; int icSize = object->internalClass()->size; - int from = qMax(idx, inlineSize); + int from = idx; int to = from + 1; - if (from < icSize) { + if (from < icSize) memmove(object->propertyData(to), object->propertyData(from), (icSize - from - 1) * sizeof(Value)); - } - if (from == idx) - return; - if (inlineSize < icSize) - *object->propertyData(inlineSize) = *object->propertyData(inlineSize - 1); - from = idx; - to = from + 1; - if (from < inlineSize - 1) { - memmove(object->propertyData(to), object->propertyData(from), - (inlineSize - from - 1) * sizeof(Value)); - } } static void removeFromPropertyData(Object *object, int idx, bool accessor = false) { - int inlineSize = object->d()->inlineMemberSize; int delta = (accessor ? 2 : 1); int oldSize = object->internalClass()->size + delta; int to = idx; int from = to + delta; - if (from < inlineSize) { - memmove(object->propertyData(to), object->d()->propertyData(from), (inlineSize - from)*sizeof(Value)); - to = inlineSize - delta; - from = inlineSize; - } - if (to < inlineSize && from < oldSize) { - Q_ASSERT(from >= inlineSize); - memcpy(object->propertyData(to), object->d()->propertyData(from), (inlineSize - to)*sizeof(Value)); - to = inlineSize; - from = inlineSize + delta; - } - if (from < oldSize) { - Q_ASSERT(to >= inlineSize && from > to); + if (from < oldSize) memmove(object->propertyData(to), object->d()->propertyData(from), (oldSize - to)*sizeof(Value)); - } } void InternalClass::changeMember(Object *object, String *string, PropertyAttributes data, uint *index) diff --git a/src/qml/jsruntime/qv4internalclass_p.h b/src/qml/jsruntime/qv4internalclass_p.h index dcda949c97..1d8ef4b0fb 100644 --- a/src/qml/jsruntime/qv4internalclass_p.h +++ b/src/qml/jsruntime/qv4internalclass_p.h @@ -234,7 +234,7 @@ struct InternalClassTransition { return id == other.id && flags == other.flags; } bool operator<(const InternalClassTransition &other) const - { return id < other.id; } + { return id < other.id || (id == other.id && flags < other.flags); } }; struct InternalClass : public QQmlJS::Managed { diff --git a/src/qml/jsruntime/qv4jsonobject.cpp b/src/qml/jsruntime/qv4jsonobject.cpp index d79e6242ba..1d571f53f3 100644 --- a/src/qml/jsruntime/qv4jsonobject.cpp +++ b/src/qml/jsruntime/qv4jsonobject.cpp @@ -883,10 +883,9 @@ void Heap::JsonObject::init() } -ReturnedValue JsonObject::method_parse(CallContext *ctx) +void JsonObject::method_parse(const BuiltinFunction *, Scope &scope, CallData *callData) { - Scope scope(ctx); - ScopedValue v(scope, ctx->argument(0)); + ScopedValue v(scope, callData->argument(0)); QString jtext = v->toQString(); DEBUG << "parsing source = " << jtext; @@ -895,19 +894,17 @@ ReturnedValue JsonObject::method_parse(CallContext *ctx) ScopedValue result(scope, parser.parse(&error)); if (error.error != QJsonParseError::NoError) { DEBUG << "parse error" << error.errorString(); - return ctx->engine()->throwSyntaxError(QStringLiteral("JSON.parse: Parse error")); + RETURN_RESULT(scope.engine->throwSyntaxError(QStringLiteral("JSON.parse: Parse error"))); } - return result->asReturnedValue(); + scope.result = result; } -ReturnedValue JsonObject::method_stringify(CallContext *ctx) +void JsonObject::method_stringify(const BuiltinFunction *, Scope &scope, CallData *callData) { - Scope scope(ctx); - Stringify stringify(scope.engine); - ScopedObject o(scope, ctx->argument(1)); + ScopedObject o(scope, callData->argument(1)); if (o) { stringify.replacerFunction = o->as<FunctionObject>(); if (o->isArrayObject()) { @@ -932,7 +929,7 @@ ReturnedValue JsonObject::method_stringify(CallContext *ctx) } } - ScopedValue s(scope, ctx->argument(2)); + ScopedValue s(scope, callData->argument(2)); if (NumberObject *n = s->as<NumberObject>()) s = Encode(n->value()); else if (StringObject *so = s->as<StringObject>()) @@ -945,11 +942,11 @@ ReturnedValue JsonObject::method_stringify(CallContext *ctx) } - ScopedValue arg0(scope, ctx->argument(0)); + ScopedValue arg0(scope, callData->argument(0)); QString result = stringify.Str(QString(), arg0); if (result.isEmpty() || scope.engine->hasException) - return Encode::undefined(); - return ctx->d()->engine->newString(result)->asReturnedValue(); + RETURN_UNDEFINED(); + scope.result = scope.engine->newString(result); } diff --git a/src/qml/jsruntime/qv4jsonobject_p.h b/src/qml/jsruntime/qv4jsonobject_p.h index 43248a214d..a73ce1c74e 100644 --- a/src/qml/jsruntime/qv4jsonobject_p.h +++ b/src/qml/jsruntime/qv4jsonobject_p.h @@ -88,8 +88,8 @@ private: typedef QSet<ObjectItem> V4ObjectSet; public: - static ReturnedValue method_parse(CallContext *ctx); - static ReturnedValue method_stringify(CallContext *ctx); + static void method_parse(const BuiltinFunction *, Scope &scope, CallData *callData); + static void method_stringify(const BuiltinFunction *, Scope &scope, CallData *callData); static ReturnedValue fromJsonValue(ExecutionEngine *engine, const QJsonValue &value); static ReturnedValue fromJsonObject(ExecutionEngine *engine, const QJsonObject &object); diff --git a/src/qml/jsruntime/qv4mathobject.cpp b/src/qml/jsruntime/qv4mathobject.cpp index e03b2762cc..2d9d81c64b 100644 --- a/src/qml/jsruntime/qv4mathobject.cpp +++ b/src/qml/jsruntime/qv4mathobject.cpp @@ -92,160 +92,160 @@ static Q_ALWAYS_INLINE double copySign(double x, double y) return ::copysign(x, y); } -ReturnedValue MathObject::method_abs(CallContext *context) +void MathObject::method_abs(const BuiltinFunction *, Scope &scope, CallData *callData) { - if (!context->argc()) - return Encode(qt_qnan()); + if (!callData->argc) + RETURN_RESULT(Encode(qt_qnan())); - if (context->args()[0].isInteger()) { - int i = context->args()[0].integerValue(); - return Encode(i < 0 ? - i : i); + if (callData->args[0].isInteger()) { + int i = callData->args[0].integerValue(); + RETURN_RESULT(Encode(i < 0 ? - i : i)); } - double v = context->args()[0].toNumber(); + double v = callData->args[0].toNumber(); if (v == 0) // 0 | -0 - return Encode(0); + RETURN_RESULT(Encode(0)); - return Encode(v < 0 ? -v : v); + RETURN_RESULT(Encode(v < 0 ? -v : v)); } -ReturnedValue MathObject::method_acos(CallContext *context) +void MathObject::method_acos(const BuiltinFunction *, Scope &scope, CallData *callData) { - double v = context->argc() ? context->args()[0].toNumber() : 2; + double v = callData->argc ? callData->args[0].toNumber() : 2; if (v > 1) - return Encode(qt_qnan()); + RETURN_RESULT(Encode(qt_qnan())); - return Encode(std::acos(v)); + RETURN_RESULT(Encode(std::acos(v))); } -ReturnedValue MathObject::method_asin(CallContext *context) +void MathObject::method_asin(const BuiltinFunction *, Scope &scope, CallData *callData) { - double v = context->argc() ? context->args()[0].toNumber() : 2; + double v = callData->argc ? callData->args[0].toNumber() : 2; if (v > 1) - return Encode(qt_qnan()); + RETURN_RESULT(Encode(qt_qnan())); else - return Encode(std::asin(v)); + RETURN_RESULT(Encode(std::asin(v))); } -ReturnedValue MathObject::method_atan(CallContext *context) +void MathObject::method_atan(const BuiltinFunction *, Scope &scope, CallData *callData) { - double v = context->argc() ? context->args()[0].toNumber() : qt_qnan(); + double v = callData->argc ? callData->args[0].toNumber() : qt_qnan(); if (v == 0.0) - return Encode(v); + RETURN_RESULT(Encode(v)); else - return Encode(std::atan(v)); + RETURN_RESULT(Encode(std::atan(v))); } -ReturnedValue MathObject::method_atan2(CallContext *context) +void MathObject::method_atan2(const BuiltinFunction *, Scope &scope, CallData *callData) { - double v1 = context->argc() ? context->args()[0].toNumber() : qt_qnan(); - double v2 = context->argc() > 1 ? context->args()[1].toNumber() : qt_qnan(); + double v1 = callData->argc ? callData->args[0].toNumber() : qt_qnan(); + double v2 = callData->argc > 1 ? callData->args[1].toNumber() : qt_qnan(); if ((v1 < 0) && qt_is_finite(v1) && qt_is_inf(v2) && (copySign(1.0, v2) == 1.0)) - return Encode(copySign(0, -1.0)); + RETURN_RESULT(Encode(copySign(0, -1.0))); if ((v1 == 0.0) && (v2 == 0.0)) { if ((copySign(1.0, v1) == 1.0) && (copySign(1.0, v2) == -1.0)) { - return Encode(M_PI); + RETURN_RESULT(Encode(M_PI)); } else if ((copySign(1.0, v1) == -1.0) && (copySign(1.0, v2) == -1.0)) { - return Encode(-M_PI); + RETURN_RESULT(Encode(-M_PI)); } } - return Encode(std::atan2(v1, v2)); + RETURN_RESULT(Encode(std::atan2(v1, v2))); } -ReturnedValue MathObject::method_ceil(CallContext *context) +void MathObject::method_ceil(const BuiltinFunction *, Scope &scope, CallData *callData) { - double v = context->argc() ? context->args()[0].toNumber() : qt_qnan(); + double v = callData->argc ? callData->args[0].toNumber() : qt_qnan(); if (v < 0.0 && v > -1.0) - return Encode(copySign(0, -1.0)); + RETURN_RESULT(Encode(copySign(0, -1.0))); else - return Encode(std::ceil(v)); + RETURN_RESULT(Encode(std::ceil(v))); } -ReturnedValue MathObject::method_cos(CallContext *context) +void MathObject::method_cos(const BuiltinFunction *, Scope &scope, CallData *callData) { - double v = context->argc() ? context->args()[0].toNumber() : qt_qnan(); - return Encode(std::cos(v)); + double v = callData->argc ? callData->args[0].toNumber() : qt_qnan(); + RETURN_RESULT(Encode(std::cos(v))); } -ReturnedValue MathObject::method_exp(CallContext *context) +void MathObject::method_exp(const BuiltinFunction *, Scope &scope, CallData *callData) { - double v = context->argc() ? context->args()[0].toNumber() : qt_qnan(); + double v = callData->argc ? callData->args[0].toNumber() : qt_qnan(); if (qt_is_inf(v)) { if (copySign(1.0, v) == -1.0) - return Encode(0); + RETURN_RESULT(Encode(0)); else - return Encode(qt_inf()); + RETURN_RESULT(Encode(qt_inf())); } else { - return Encode(std::exp(v)); + RETURN_RESULT(Encode(std::exp(v))); } } -ReturnedValue MathObject::method_floor(CallContext *context) +void MathObject::method_floor(const BuiltinFunction *, Scope &scope, CallData *callData) { - double v = context->argc() ? context->args()[0].toNumber() : qt_qnan(); - return Encode(std::floor(v)); + double v = callData->argc ? callData->args[0].toNumber() : qt_qnan(); + RETURN_RESULT(Encode(std::floor(v))); } -ReturnedValue MathObject::method_log(CallContext *context) +void MathObject::method_log(const BuiltinFunction *, Scope &scope, CallData *callData) { - double v = context->argc() ? context->args()[0].toNumber() : qt_qnan(); + double v = callData->argc ? callData->args[0].toNumber() : qt_qnan(); if (v < 0) - return Encode(qt_qnan()); + RETURN_RESULT(Encode(qt_qnan())); else - return Encode(std::log(v)); + RETURN_RESULT(Encode(std::log(v))); } -ReturnedValue MathObject::method_max(CallContext *context) +void MathObject::method_max(const BuiltinFunction *, Scope &scope, CallData *callData) { double mx = -qt_inf(); - for (int i = 0; i < context->argc(); ++i) { - double x = context->args()[i].toNumber(); + for (int i = 0; i < callData->argc; ++i) { + double x = callData->args[i].toNumber(); if (x > mx || std::isnan(x)) mx = x; } - return Encode(mx); + RETURN_RESULT(Encode(mx)); } -ReturnedValue MathObject::method_min(CallContext *context) +void MathObject::method_min(const BuiltinFunction *, Scope &scope, CallData *callData) { double mx = qt_inf(); - for (int i = 0; i < context->argc(); ++i) { - double x = context->args()[i].toNumber(); + for (int i = 0; i < callData->argc; ++i) { + double x = callData->args[i].toNumber(); if ((x == 0 && mx == x && copySign(1.0, x) == -1.0) || (x < mx) || std::isnan(x)) { mx = x; } } - return Encode(mx); + RETURN_RESULT(Encode(mx)); } -ReturnedValue MathObject::method_pow(CallContext *context) +void MathObject::method_pow(const BuiltinFunction *, Scope &scope, CallData *callData) { - double x = context->argc() > 0 ? context->args()[0].toNumber() : qt_qnan(); - double y = context->argc() > 1 ? context->args()[1].toNumber() : qt_qnan(); + double x = callData->argc > 0 ? callData->args[0].toNumber() : qt_qnan(); + double y = callData->argc > 1 ? callData->args[1].toNumber() : qt_qnan(); if (std::isnan(y)) - return Encode(qt_qnan()); + RETURN_RESULT(Encode(qt_qnan())); if (y == 0) { - return Encode(1); + RETURN_RESULT(Encode(1)); } else if (((x == 1) || (x == -1)) && std::isinf(y)) { - return Encode(qt_qnan()); + RETURN_RESULT(Encode(qt_qnan())); } else if (((x == 0) && copySign(1.0, x) == 1.0) && (y < 0)) { - return Encode(qInf()); + RETURN_RESULT(Encode(qInf())); } else if ((x == 0) && copySign(1.0, x) == -1.0) { if (y < 0) { if (std::fmod(-y, 2.0) == 1.0) - return Encode(-qt_inf()); + RETURN_RESULT(Encode(-qt_inf())); else - return Encode(qt_inf()); + RETURN_RESULT(Encode(qt_inf())); } else if (y > 0) { if (std::fmod(y, 2.0) == 1.0) - return Encode(copySign(0, -1.0)); + RETURN_RESULT(Encode(copySign(0, -1.0))); else - return Encode(0); + RETURN_RESULT(Encode(0)); } } @@ -253,78 +253,78 @@ ReturnedValue MathObject::method_pow(CallContext *context) else if (qt_is_inf(x) && copySign(1.0, x) == -1.0) { if (y > 0) { if (std::fmod(y, 2.0) == 1.0) - return Encode(-qt_inf()); + RETURN_RESULT(Encode(-qt_inf())); else - return Encode(qt_inf()); + RETURN_RESULT(Encode(qt_inf())); } else if (y < 0) { if (std::fmod(-y, 2.0) == 1.0) - return Encode(copySign(0, -1.0)); + RETURN_RESULT(Encode(copySign(0, -1.0))); else - return Encode(0); + RETURN_RESULT(Encode(0)); } } #endif else { - return Encode(std::pow(x, y)); + RETURN_RESULT(Encode(std::pow(x, y))); } // ### - return Encode(qt_qnan()); + RETURN_RESULT(Encode(qt_qnan())); } Q_GLOBAL_STATIC(QThreadStorage<bool *>, seedCreatedStorage); -ReturnedValue MathObject::method_random(CallContext *context) +void MathObject::method_random(const BuiltinFunction *, Scope &scope, CallData *) { if (!seedCreatedStorage()->hasLocalData()) { int msecs = QTime(0,0,0).msecsTo(QTime::currentTime()); Q_ASSERT(msecs >= 0); - qsrand(uint(uint(msecs) ^ reinterpret_cast<quintptr>(context))); + qsrand(uint(uint(msecs) ^ reinterpret_cast<quintptr>(scope.engine))); seedCreatedStorage()->setLocalData(new bool(true)); } // rand()/qrand() return a value where the upperbound is RAND_MAX inclusive. So, instead of // dividing by RAND_MAX (which would return 0..RAND_MAX inclusive), we divide by RAND_MAX + 1. qint64 upperLimit = qint64(RAND_MAX) + 1; - return Encode(qrand() / double(upperLimit)); + RETURN_RESULT(Encode(qrand() / double(upperLimit))); } -ReturnedValue MathObject::method_round(CallContext *context) +void MathObject::method_round(const BuiltinFunction *, Scope &scope, CallData *callData) { - double v = context->argc() ? context->args()[0].toNumber() : qt_qnan(); + double v = callData->argc ? callData->args[0].toNumber() : qt_qnan(); v = copySign(std::floor(v + 0.5), v); - return Encode(v); + RETURN_RESULT(Encode(v)); } -ReturnedValue MathObject::method_sign(CallContext *context) +void MathObject::method_sign(const BuiltinFunction *, Scope &scope, CallData *callData) { - double v = context->argc() ? context->args()[0].toNumber() : qt_qnan(); + double v = callData->argc ? callData->args[0].toNumber() : qt_qnan(); if (std::isnan(v)) - return Encode(qt_qnan()); + RETURN_RESULT(Encode(qt_qnan())); if (qIsNull(v)) - return v; + RETURN_RESULT(Encode(v)); - return Encode(std::signbit(v) ? -1 : 1); + RETURN_RESULT(Encode(std::signbit(v) ? -1 : 1)); } -ReturnedValue MathObject::method_sin(CallContext *context) +void MathObject::method_sin(const BuiltinFunction *, Scope &scope, CallData *callData) { - double v = context->argc() ? context->args()[0].toNumber() : qt_qnan(); - return Encode(std::sin(v)); + double v = callData->argc ? callData->args[0].toNumber() : qt_qnan(); + RETURN_RESULT(Encode(std::sin(v))); } -ReturnedValue MathObject::method_sqrt(CallContext *context) +void MathObject::method_sqrt(const BuiltinFunction *, Scope &scope, CallData *callData) { - double v = context->argc() ? context->args()[0].toNumber() : qt_qnan(); - return Encode(std::sqrt(v)); + double v = callData->argc ? callData->args[0].toNumber() : qt_qnan(); + RETURN_RESULT(Encode(std::sqrt(v))); } -ReturnedValue MathObject::method_tan(CallContext *context) +void MathObject::method_tan(const BuiltinFunction *, Scope &scope, CallData *callData) { - double v = context->argc() ? context->args()[0].toNumber() : qt_qnan(); + double v = callData->argc ? callData->args[0].toNumber() : qt_qnan(); if (v == 0.0) - return Encode(v); + RETURN_RESULT(Encode(v)); else - return Encode(std::tan(v)); + RETURN_RESULT(Encode(std::tan(v))); } diff --git a/src/qml/jsruntime/qv4mathobject_p.h b/src/qml/jsruntime/qv4mathobject_p.h index f6b1a4395f..e617712905 100644 --- a/src/qml/jsruntime/qv4mathobject_p.h +++ b/src/qml/jsruntime/qv4mathobject_p.h @@ -69,25 +69,25 @@ struct MathObject: Object V4_OBJECT2(MathObject, Object) Q_MANAGED_TYPE(MathObject) - static ReturnedValue method_abs(CallContext *context); - static ReturnedValue method_acos(CallContext *context); - static ReturnedValue method_asin(CallContext *context); - static ReturnedValue method_atan(CallContext *context); - static ReturnedValue method_atan2(CallContext *context); - static ReturnedValue method_ceil(CallContext *context); - static ReturnedValue method_cos(CallContext *context); - static ReturnedValue method_exp(CallContext *context); - static ReturnedValue method_floor(CallContext *context); - static ReturnedValue method_log(CallContext *context); - static ReturnedValue method_max(CallContext *context); - static ReturnedValue method_min(CallContext *context); - static ReturnedValue method_pow(CallContext *context); - static ReturnedValue method_random(CallContext *context); - static ReturnedValue method_round(CallContext *context); - static ReturnedValue method_sign(CallContext *context); - static ReturnedValue method_sin(CallContext *context); - static ReturnedValue method_sqrt(CallContext *context); - static ReturnedValue method_tan(CallContext *context); + static void method_abs(const BuiltinFunction *, Scope &scope, CallData *callData); + static void method_acos(const BuiltinFunction *, Scope &scope, CallData *callData); + static void method_asin(const BuiltinFunction *, Scope &scope, CallData *callData); + static void method_atan(const BuiltinFunction *, Scope &scope, CallData *callData); + static void method_atan2(const BuiltinFunction *, Scope &scope, CallData *callData); + static void method_ceil(const BuiltinFunction *, Scope &scope, CallData *callData); + static void method_cos(const BuiltinFunction *, Scope &scope, CallData *callData); + static void method_exp(const BuiltinFunction *, Scope &scope, CallData *callData); + static void method_floor(const BuiltinFunction *, Scope &scope, CallData *callData); + static void method_log(const BuiltinFunction *, Scope &scope, CallData *callData); + static void method_max(const BuiltinFunction *, Scope &scope, CallData *callData); + static void method_min(const BuiltinFunction *, Scope &scope, CallData *callData); + static void method_pow(const BuiltinFunction *, Scope &scope, CallData *callData); + static void method_random(const BuiltinFunction *, Scope &scope, CallData *callData); + static void method_round(const BuiltinFunction *, Scope &scope, CallData *callData); + static void method_sign(const BuiltinFunction *, Scope &scope, CallData *callData); + static void method_sin(const BuiltinFunction *, Scope &scope, CallData *callData); + static void method_sqrt(const BuiltinFunction *, Scope &scope, CallData *callData); + static void method_tan(const BuiltinFunction *, Scope &scope, CallData *callData); }; } diff --git a/src/qml/jsruntime/qv4memberdata.cpp b/src/qml/jsruntime/qv4memberdata.cpp index d5f75415cc..db45c77472 100644 --- a/src/qml/jsruntime/qv4memberdata.cpp +++ b/src/qml/jsruntime/qv4memberdata.cpp @@ -55,13 +55,14 @@ void MemberData::markObjects(Heap::Base *that, ExecutionEngine *e) Heap::MemberData *MemberData::allocate(ExecutionEngine *e, uint n, Heap::MemberData *old) { Q_ASSERT(!old || old->size < n); + Q_ASSERT(n); - uint alloc = sizeof(Heap::MemberData) + (n)*sizeof(Value); + size_t alloc = MemoryManager::align(sizeof(Heap::MemberData) + (n - 1)*sizeof(Value)); Heap::MemberData *m = e->memoryManager->allocManaged<MemberData>(alloc); if (old) - memcpy(m, old, sizeof(Heap::MemberData) + old->size * sizeof(Value)); + memcpy(m, old, sizeof(Heap::MemberData) + (old->size - 1)* sizeof(Value)); else m->init(); - m->size = n; + m->size = static_cast<uint>((alloc - sizeof(Heap::MemberData) + sizeof(Value))/sizeof(Value)); return m; } diff --git a/src/qml/jsruntime/qv4numberobject.cpp b/src/qml/jsruntime/qv4numberobject.cpp index 3a6b9da763..09644c161d 100644 --- a/src/qml/jsruntime/qv4numberobject.cpp +++ b/src/qml/jsruntime/qv4numberobject.cpp @@ -120,61 +120,71 @@ QT_WARNING_POP defineDefaultProperty(QStringLiteral("toPrecision"), method_toPrecision); } -inline ReturnedValue thisNumberValue(ExecutionContext *ctx) +inline ReturnedValue thisNumberValue(Scope &scope, CallData *callData) { - if (ctx->thisObject().isNumber()) - return ctx->thisObject().asReturnedValue(); - NumberObject *n = ctx->thisObject().as<NumberObject>(); - if (!n) - return ctx->engine()->throwTypeError(); + if (callData->thisObject.isNumber()) + return callData->thisObject.asReturnedValue(); + NumberObject *n = callData->thisObject.as<NumberObject>(); + if (!n) { + scope.engine->throwTypeError(); + return Encode::undefined(); + } return Encode(n->value()); } -inline double thisNumber(ExecutionContext *ctx) +inline double thisNumber(Scope &scope, CallData *callData) { - if (ctx->thisObject().isNumber()) - return ctx->thisObject().asDouble(); - NumberObject *n = ctx->thisObject().as<NumberObject>(); - if (!n) - return ctx->engine()->throwTypeError(); + if (callData->thisObject.isNumber()) + return callData->thisObject.asDouble(); + NumberObject *n = callData->thisObject.as<NumberObject>(); + if (!n) { + scope.engine->throwTypeError(); + return 0; + } return n->value(); } -ReturnedValue NumberPrototype::method_isFinite(CallContext *ctx) +void NumberPrototype::method_isFinite(const BuiltinFunction *, Scope &scope, CallData *callData) { - if (!ctx->argc()) - return Encode(false); + if (!callData->argc) { + scope.result = Encode(false); + return; + } - double v = ctx->args()[0].toNumber(); - return Encode(!std::isnan(v) && !qt_is_inf(v)); + double v = callData->args[0].toNumber(); + scope.result = Encode(!std::isnan(v) && !qt_is_inf(v)); } -ReturnedValue NumberPrototype::method_isNaN(CallContext *ctx) +void NumberPrototype::method_isNaN(const BuiltinFunction *, Scope &scope, CallData *callData) { - if (!ctx->argc()) - return Encode(false); + if (!callData->argc) { + scope.result = Encode(false); + return; + } - double v = ctx->args()[0].toNumber(); - return Encode(std::isnan(v)); + double v = callData->args[0].toNumber(); + scope.result = Encode(std::isnan(v)); } -ReturnedValue NumberPrototype::method_toString(CallContext *ctx) +void NumberPrototype::method_toString(const BuiltinFunction *, Scope &scope, CallData *callData) { - Scope scope(ctx); - double num = thisNumber(ctx); - if (scope.engine->hasException) - return Encode::undefined(); + double num = thisNumber(scope, callData); + CHECK_EXCEPTION(); - if (ctx->argc() && !ctx->args()[0].isUndefined()) { - int radix = ctx->args()[0].toInt32(); - if (radix < 2 || radix > 36) - return ctx->engine()->throwError(QStringLiteral("Number.prototype.toString: %0 is not a valid radix") + if (callData->argc && !callData->args[0].isUndefined()) { + int radix = callData->args[0].toInt32(); + if (radix < 2 || radix > 36) { + scope.result = scope.engine->throwError(QStringLiteral("Number.prototype.toString: %0 is not a valid radix") .arg(radix)); + return; + } if (std::isnan(num)) { - return scope.engine->newString(QStringLiteral("NaN"))->asReturnedValue(); + scope.result = scope.engine->newString(QStringLiteral("NaN")); + return; } else if (qt_is_inf(num)) { - return scope.engine->newString(QLatin1String(num < 0 ? "-Infinity" : "Infinity"))->asReturnedValue(); + scope.result = scope.engine->newString(QLatin1String(num < 0 ? "-Infinity" : "Infinity")); + return; } if (radix != 10) { @@ -204,45 +214,43 @@ ReturnedValue NumberPrototype::method_toString(CallContext *ctx) } if (negative) str.prepend(QLatin1Char('-')); - return scope.engine->newString(str)->asReturnedValue(); + scope.result = scope.engine->newString(str); + return; } } - return Primitive::fromDouble(num).toString(scope.engine)->asReturnedValue(); + scope.result = Primitive::fromDouble(num).toString(scope.engine); } -ReturnedValue NumberPrototype::method_toLocaleString(CallContext *ctx) +void NumberPrototype::method_toLocaleString(const BuiltinFunction *, Scope &scope, CallData *callData) { - Scope scope(ctx); - ScopedValue v(scope, thisNumberValue(ctx)); - ScopedString str(scope, v->toString(scope.engine)); - if (scope.engine->hasException) - return Encode::undefined(); - return str.asReturnedValue(); + ScopedValue v(scope, thisNumberValue(scope, callData)); + scope.result = v->toString(scope.engine); + CHECK_EXCEPTION(); } -ReturnedValue NumberPrototype::method_valueOf(CallContext *ctx) +void NumberPrototype::method_valueOf(const BuiltinFunction *, Scope &scope, CallData *callData) { - return thisNumberValue(ctx); + scope.result = thisNumberValue(scope, callData); } -ReturnedValue NumberPrototype::method_toFixed(CallContext *ctx) +void NumberPrototype::method_toFixed(const BuiltinFunction *, Scope &scope, CallData *callData) { - Scope scope(ctx); - double v = thisNumber(ctx); - if (scope.engine->hasException) - return Encode::undefined(); + double v = thisNumber(scope, callData); + CHECK_EXCEPTION(); double fdigits = 0; - if (ctx->argc() > 0) - fdigits = ctx->args()[0].toInteger(); + if (callData->argc > 0) + fdigits = callData->args[0].toInteger(); if (std::isnan(fdigits)) fdigits = 0; - if (fdigits < 0 || fdigits > 20) - return ctx->engine()->throwRangeError(ctx->thisObject()); + if (fdigits < 0 || fdigits > 20) { + scope.result = scope.engine->throwRangeError(callData->thisObject); + return; + } QString str; if (std::isnan(v)) @@ -251,48 +259,50 @@ ReturnedValue NumberPrototype::method_toFixed(CallContext *ctx) str = QString::fromLatin1(v < 0 ? "-Infinity" : "Infinity"); else if (v < 1.e21) str = NumberLocale::instance()->toString(v, 'f', int(fdigits)); - else - return RuntimeHelpers::stringFromNumber(ctx->engine(), v)->asReturnedValue(); - return scope.engine->newString(str)->asReturnedValue(); + else { + scope.result = RuntimeHelpers::stringFromNumber(scope.engine, v); + return; + } + scope.result = scope.engine->newString(str); } -ReturnedValue NumberPrototype::method_toExponential(CallContext *ctx) +void NumberPrototype::method_toExponential(const BuiltinFunction *, Scope &scope, CallData *callData) { - Scope scope(ctx); - double d = thisNumber(ctx); - if (scope.engine->hasException) - return Encode::undefined(); + double d = thisNumber(scope, callData); + CHECK_EXCEPTION(); int fdigits = NumberLocale::instance()->defaultDoublePrecision; - if (ctx->argc() && !ctx->args()[0].isUndefined()) { - fdigits = ctx->args()[0].toInt32(); + if (callData->argc && !callData->args[0].isUndefined()) { + fdigits = callData->args[0].toInt32(); if (fdigits < 0 || fdigits > 20) { ScopedString error(scope, scope.engine->newString(QStringLiteral("Number.prototype.toExponential: fractionDigits out of range"))); - return ctx->engine()->throwRangeError(error); + scope.result = scope.engine->throwRangeError(error); + return; } } QString result = NumberLocale::instance()->toString(d, 'e', fdigits); - return scope.engine->newString(result)->asReturnedValue(); + scope.result = scope.engine->newString(result); } -ReturnedValue NumberPrototype::method_toPrecision(CallContext *ctx) +void NumberPrototype::method_toPrecision(const BuiltinFunction *, Scope &scope, CallData *callData) { - Scope scope(ctx); - ScopedValue v(scope, thisNumberValue(ctx)); - if (scope.engine->hasException) - return Encode::undefined(); + ScopedValue v(scope, thisNumberValue(scope, callData)); + CHECK_EXCEPTION(); - if (!ctx->argc() || ctx->args()[0].isUndefined()) - return Encode(v->toString(scope.engine)); + if (!callData->argc || callData->args[0].isUndefined()) { + scope.result = v->toString(scope.engine); + return; + } - int precision = ctx->args()[0].toInt32(); + int precision = callData->args[0].toInt32(); if (precision < 1 || precision > 21) { ScopedString error(scope, scope.engine->newString(QStringLiteral("Number.prototype.toPrecision: precision out of range"))); - return ctx->engine()->throwRangeError(error); + scope.result = scope.engine->throwRangeError(error); + return; } QString result = NumberLocale::instance()->toString(v->asDouble(), 'g', precision); - return scope.engine->newString(result)->asReturnedValue(); + scope.result = scope.engine->newString(result); } diff --git a/src/qml/jsruntime/qv4numberobject_p.h b/src/qml/jsruntime/qv4numberobject_p.h index 6022b3a029..364b866a16 100644 --- a/src/qml/jsruntime/qv4numberobject_p.h +++ b/src/qml/jsruntime/qv4numberobject_p.h @@ -87,14 +87,14 @@ struct NumberPrototype: NumberObject { void init(ExecutionEngine *engine, Object *ctor); - static ReturnedValue method_isFinite(CallContext *ctx); - static ReturnedValue method_isNaN(CallContext *ctx); - static ReturnedValue method_toString(CallContext *ctx); - static ReturnedValue method_toLocaleString(CallContext *ctx); - static ReturnedValue method_valueOf(CallContext *ctx); - static ReturnedValue method_toFixed(CallContext *ctx); - static ReturnedValue method_toExponential(CallContext *ctx); - static ReturnedValue method_toPrecision(CallContext *ctx); + static void method_isFinite(const BuiltinFunction *, Scope &scope, CallData *callData); + static void method_isNaN(const BuiltinFunction *, Scope &scope, CallData *callData); + static void method_toString(const BuiltinFunction *, Scope &scope, CallData *callData); + static void method_toLocaleString(const BuiltinFunction *, Scope &scope, CallData *callData); + static void method_valueOf(const BuiltinFunction *, Scope &scope, CallData *callData); + static void method_toFixed(const BuiltinFunction *, Scope &scope, CallData *callData); + static void method_toExponential(const BuiltinFunction *, Scope &scope, CallData *callData); + static void method_toPrecision(const BuiltinFunction *, Scope &scope, CallData *callData); }; diff --git a/src/qml/jsruntime/qv4object.cpp b/src/qml/jsruntime/qv4object.cpp index 8acca16dd0..eb9cb80cee 100644 --- a/src/qml/jsruntime/qv4object.cpp +++ b/src/qml/jsruntime/qv4object.cpp @@ -61,9 +61,8 @@ DEFINE_OBJECT_VTABLE(Object); void Object::setInternalClass(InternalClass *ic) { d()->internalClass = ic; - if ((ic->size > d()->inlineMemberSize && !d()->memberData) || - (d()->memberData && d()->memberData->size < ic->size - d()->inlineMemberSize)) - d()->memberData = MemberData::allocate(ic->engine, ic->size - d()->inlineMemberSize, d()->memberData); + if ((!d()->memberData && ic->size) || (d()->memberData->size < ic->size)) + d()->memberData = MemberData::allocate(ic->engine, ic->size, d()->memberData); } void Object::getProperty(uint index, Property *p, PropertyAttributes *attrs) const @@ -167,6 +166,17 @@ void Object::defineDefaultProperty(const QString &name, ReturnedValue (*code)(Ca defineDefaultProperty(s, function); } +void Object::defineDefaultProperty(const QString &name, void (*code)(const BuiltinFunction *, Scope &, CallData *), int argumentCount) +{ + ExecutionEngine *e = engine(); + Scope scope(e); + ScopedString s(scope, e->newIdentifier(name)); + ExecutionContext *global = e->rootContext(); + ScopedFunctionObject function(scope, BuiltinFunction::create(global, s, code)); + function->defineReadonlyProperty(e->id_length(), Primitive::fromInt32(argumentCount)); + defineDefaultProperty(s, function); +} + void Object::defineDefaultProperty(String *name, ReturnedValue (*code)(CallContext *), int argumentCount) { ExecutionEngine *e = engine(); @@ -177,6 +187,16 @@ void Object::defineDefaultProperty(String *name, ReturnedValue (*code)(CallConte defineDefaultProperty(name, function); } +void Object::defineDefaultProperty(String *name, void (*code)(const BuiltinFunction *, Scope &, CallData *), int argumentCount) +{ + ExecutionEngine *e = engine(); + Scope scope(e); + ExecutionContext *global = e->rootContext(); + ScopedFunctionObject function(scope, BuiltinFunction::create(global, name, code)); + function->defineReadonlyProperty(e->id_length(), Primitive::fromInt32(argumentCount)); + defineDefaultProperty(name, function); +} + void Object::defineAccessorProperty(const QString &name, ReturnedValue (*getter)(CallContext *), ReturnedValue (*setter)(CallContext *)) { ExecutionEngine *e = engine(); @@ -196,6 +216,27 @@ void Object::defineAccessorProperty(String *name, ReturnedValue (*getter)(CallCo insertMember(name, p, QV4::Attr_Accessor|QV4::Attr_NotConfigurable|QV4::Attr_NotEnumerable); } +void Object::defineAccessorProperty(const QString &name, void (*getter)(const BuiltinFunction *, Scope &, CallData *), + void (*setter)(const BuiltinFunction *, Scope &, CallData *)) +{ + ExecutionEngine *e = engine(); + Scope scope(e); + ScopedString s(scope, e->newIdentifier(name)); + defineAccessorProperty(s, getter, setter); +} + +void Object::defineAccessorProperty(String *name, void (*getter)(const BuiltinFunction *, Scope &, CallData *), + void (*setter)(const BuiltinFunction *, Scope &, CallData *)) +{ + ExecutionEngine *v4 = engine(); + QV4::Scope scope(v4); + ScopedProperty p(scope); + ExecutionContext *global = v4->rootContext(); + p->setGetter(ScopedFunctionObject(scope, (getter ? BuiltinFunction::create(global, name, getter) : 0))); + p->setSetter(ScopedFunctionObject(scope, (setter ? BuiltinFunction::create(global, name, setter) : 0))); + insertMember(name, p, QV4::Attr_Accessor|QV4::Attr_NotConfigurable|QV4::Attr_NotEnumerable); +} + void Object::defineReadonlyProperty(const QString &name, const Value &value) { QV4::ExecutionEngine *e = engine(); @@ -213,12 +254,6 @@ void Object::markObjects(Heap::Base *that, ExecutionEngine *e) { Heap::Object *o = static_cast<Heap::Object *>(that); - if (o->inlineMemberSize) { - Value *v = o->propertyData(0); - for (uint i = 0; i < o->inlineMemberSize; ++i) - v[i].mark(e); - } - if (o->memberData) o->memberData->mark(e); if (o->arrayData) diff --git a/src/qml/jsruntime/qv4object_p.h b/src/qml/jsruntime/qv4object_p.h index 6c679deb10..4a78690f47 100644 --- a/src/qml/jsruntime/qv4object_p.h +++ b/src/qml/jsruntime/qv4object_p.h @@ -63,17 +63,17 @@ QT_BEGIN_NAMESPACE namespace QV4 { +struct BuiltinFunction; + namespace Heap { struct Object : Base { void init() { Base::init(); } void destroy() { Base::destroy(); } - const Value *propertyData(uint index) const { if (index < inlineMemberSize) return reinterpret_cast<const Value *>(this) + inlineMemberOffset + index; return memberData->data + index - inlineMemberSize; } - Value *propertyData(uint index) { if (index < inlineMemberSize) return reinterpret_cast<Value *>(this) + inlineMemberOffset + index; return memberData->data + index - inlineMemberSize; } + const Value *propertyData(uint index) const { return memberData->data + index; } + Value *propertyData(uint index) { return memberData->data + index; } - uint inlineMemberOffset; - uint inlineMemberSize; InternalClass *internalClass; Pointer<Object> prototype; Pointer<MemberData> memberData; @@ -238,9 +238,15 @@ struct Q_QML_EXPORT Object: Managed { } void defineDefaultProperty(const QString &name, const Value &value); void defineDefaultProperty(const QString &name, ReturnedValue (*code)(CallContext *), int argumentCount = 0); + void defineDefaultProperty(const QString &name, void (*code)(const BuiltinFunction *, Scope &, CallData *), int argumentCount = 0); void defineDefaultProperty(String *name, ReturnedValue (*code)(CallContext *), int argumentCount = 0); + void defineDefaultProperty(String *name, void (*code)(const BuiltinFunction *, Scope &, CallData *), int argumentCount = 0); void defineAccessorProperty(const QString &name, ReturnedValue (*getter)(CallContext *), ReturnedValue (*setter)(CallContext *)); void defineAccessorProperty(String *name, ReturnedValue (*getter)(CallContext *), ReturnedValue (*setter)(CallContext *)); + void defineAccessorProperty(const QString &name, void (*getter)(const BuiltinFunction *, Scope &, CallData *), + void (*setter)(const BuiltinFunction *, Scope &, CallData *)); + void defineAccessorProperty(String *name, void (*getter)(const BuiltinFunction *, Scope &, CallData *), + void (*setter)(const BuiltinFunction *, Scope &, CallData *)); /* Fixed: Writable: false, Enumerable: false, Configurable: false */ void defineReadonlyProperty(const QString &name, const Value &value); void defineReadonlyProperty(String *name, const Value &value); diff --git a/src/qml/jsruntime/qv4objectproto.cpp b/src/qml/jsruntime/qv4objectproto.cpp index 8191083544..97dbe24339 100644 --- a/src/qml/jsruntime/qv4objectproto.cpp +++ b/src/qml/jsruntime/qv4objectproto.cpp @@ -121,100 +121,100 @@ void ObjectPrototype::init(ExecutionEngine *v4, Object *ctor) insertMember(v4->id___proto__(), p, Attr_Accessor|Attr_NotEnumerable); } -ReturnedValue ObjectPrototype::method_getPrototypeOf(CallContext *ctx) +void ObjectPrototype::method_getPrototypeOf(const BuiltinFunction *, Scope &scope, CallData *callData) { - Scope scope(ctx); - ScopedObject o(scope, ctx->argument(0)); + ScopedObject o(scope, callData->argument(0)); if (!o) - return ctx->engine()->throwTypeError(); + THROW_TYPE_ERROR(); ScopedObject p(scope, o->prototype()); - return !!p ? p->asReturnedValue() : Encode::null(); + scope.result = !!p ? p->asReturnedValue() : Encode::null(); } -ReturnedValue ObjectPrototype::method_getOwnPropertyDescriptor(CallContext *ctx) +void ObjectPrototype::method_getOwnPropertyDescriptor(const BuiltinFunction *, Scope &scope, CallData *callData) { - Scope scope(ctx); - ScopedObject O(scope, ctx->argument(0)); - if (!O) - return ctx->engine()->throwTypeError(); + ScopedObject O(scope, callData->argument(0)); + if (!O) { + scope.result = scope.engine->throwTypeError(); + return; + } if (ArgumentsObject::isNonStrictArgumentsObject(O)) static_cast<ArgumentsObject *>(O.getPointer())->fullyCreate(); - ScopedValue v(scope, ctx->argument(1)); + ScopedValue v(scope, callData->argument(1)); ScopedString name(scope, v->toString(scope.engine)); - if (scope.hasException()) - return Encode::undefined(); + CHECK_EXCEPTION(); + PropertyAttributes attrs; ScopedProperty desc(scope); O->getOwnProperty(name, &attrs, desc); - return fromPropertyDescriptor(scope.engine, desc, attrs); + scope.result = fromPropertyDescriptor(scope.engine, desc, attrs); } -ReturnedValue ObjectPrototype::method_getOwnPropertyNames(CallContext *context) +void ObjectPrototype::method_getOwnPropertyNames(const BuiltinFunction *, Scope &scope, CallData *callData) { - Scope scope(context); - ScopedObject O(scope, context->argument(0)); - if (!O) - return context->engine()->throwTypeError(); + ScopedObject O(scope, callData->argument(0)); + if (!O) { + scope.result = scope.engine->throwTypeError(); + return; + } - ScopedArrayObject array(scope, getOwnPropertyNames(context->d()->engine, context->args()[0])); - return array.asReturnedValue(); + scope.result = getOwnPropertyNames(scope.engine, callData->args[0]); } -ReturnedValue ObjectPrototype::method_create(CallContext *ctx) +void ObjectPrototype::method_create(const BuiltinFunction *builtin, Scope &scope, CallData *callData) { - Scope scope(ctx); - ScopedValue O(scope, ctx->argument(0)); - if (!O->isObject() && !O->isNull()) - return ctx->engine()->throwTypeError(); + ScopedValue O(scope, callData->argument(0)); + if (!O->isObject() && !O->isNull()) { + scope.result = scope.engine->throwTypeError(); + return; + } - ScopedObject newObject(scope, ctx->d()->engine->newObject()); + ScopedObject newObject(scope, scope.engine->newObject()); newObject->setPrototype(O->as<Object>()); - if (ctx->argc() > 1 && !ctx->args()[1].isUndefined()) { - ctx->d()->callData->args[0] = newObject.asReturnedValue(); - return method_defineProperties(ctx); + if (callData->argc > 1 && !callData->args[1].isUndefined()) { + callData->args[0] = newObject; + method_defineProperties(builtin, scope, callData); + return; } - return newObject.asReturnedValue(); + scope.result = newObject; } -ReturnedValue ObjectPrototype::method_defineProperty(CallContext *ctx) +void ObjectPrototype::method_defineProperty(const BuiltinFunction *, Scope &scope, CallData *callData) { - Scope scope(ctx); - ScopedObject O(scope, ctx->argument(0)); - if (!O) - return ctx->engine()->throwTypeError(); + ScopedObject O(scope, callData->argument(0)); + if (!O) { + scope.result = scope.engine->throwTypeError(); + return; + } - ScopedString name(scope, ctx->argument(1), ScopedString::Convert); - if (scope.engine->hasException) - return Encode::undefined(); + ScopedString name(scope, callData->argument(1), ScopedString::Convert); + CHECK_EXCEPTION(); - ScopedValue attributes(scope, ctx->argument(2)); + ScopedValue attributes(scope, callData->argument(2)); ScopedProperty pd(scope); PropertyAttributes attrs; toPropertyDescriptor(scope.engine, attributes, pd, &attrs); - if (scope.engine->hasException) - return Encode::undefined(); + CHECK_EXCEPTION(); if (!O->__defineOwnProperty__(scope.engine, name, pd, attrs)) - return ctx->engine()->throwTypeError(); + THROW_TYPE_ERROR(); - return O.asReturnedValue(); + scope.result = O; } -ReturnedValue ObjectPrototype::method_defineProperties(CallContext *ctx) +void ObjectPrototype::method_defineProperties(const BuiltinFunction *, Scope &scope, CallData *callData) { - Scope scope(ctx); - ScopedObject O(scope, ctx->argument(0)); + ScopedObject O(scope, callData->argument(0)); if (!O) - return ctx->engine()->throwTypeError(); + THROW_TYPE_ERROR(); + + ScopedObject o(scope, callData->argument(1), ScopedObject::Convert); + CHECK_EXCEPTION(); - ScopedObject o(scope, ctx->argument(1), ScopedObject::Convert); - if (scope.engine->hasException) - return Encode::undefined(); ScopedValue val(scope); ObjectIterator it(scope, o, ObjectIterator::EnumerableOnly); @@ -230,26 +230,24 @@ ReturnedValue ObjectPrototype::method_defineProperties(CallContext *ctx) PropertyAttributes nattrs; val = o->getValue(pd->value, attrs); toPropertyDescriptor(scope.engine, val, n, &nattrs); - if (scope.engine->hasException) - return Encode::undefined(); + CHECK_EXCEPTION(); bool ok; if (name) ok = O->__defineOwnProperty__(scope.engine, name, n, nattrs); else ok = O->__defineOwnProperty__(scope.engine, index, n, nattrs); if (!ok) - return ctx->engine()->throwTypeError(); + THROW_TYPE_ERROR(); } - return O.asReturnedValue(); + scope.result = O; } -ReturnedValue ObjectPrototype::method_seal(CallContext *ctx) +void ObjectPrototype::method_seal(const BuiltinFunction *, Scope &scope, CallData *callData) { - Scope scope(ctx); - ScopedObject o(scope, ctx->argument(0)); + ScopedObject o(scope, callData->argument(0)); if (!o) - return ctx->engine()->throwTypeError(); + THROW_TYPE_ERROR(); o->setInternalClass(o->internalClass()->sealed()); @@ -261,15 +259,14 @@ ReturnedValue ObjectPrototype::method_seal(CallContext *ctx) } } - return o.asReturnedValue(); + scope.result = o; } -ReturnedValue ObjectPrototype::method_freeze(CallContext *ctx) +void ObjectPrototype::method_freeze(const BuiltinFunction *, Scope &scope, CallData *callData) { - Scope scope(ctx); - ScopedObject o(scope, ctx->argument(0)); + ScopedObject o(scope, callData->argument(0)); if (!o) - return ctx->engine()->throwTypeError(); + THROW_TYPE_ERROR(); if (ArgumentsObject::isNonStrictArgumentsObject(o)) static_cast<ArgumentsObject *>(o.getPointer())->fullyCreate(); @@ -285,96 +282,111 @@ ReturnedValue ObjectPrototype::method_freeze(CallContext *ctx) o->arrayData()->attrs[i].setWritable(false); } } - return o.asReturnedValue(); + scope.result = o; } -ReturnedValue ObjectPrototype::method_preventExtensions(CallContext *ctx) +void ObjectPrototype::method_preventExtensions(const BuiltinFunction *, Scope &scope, CallData *callData) { - Scope scope(ctx); - ScopedObject o(scope, ctx->argument(0)); + ScopedObject o(scope, callData->argument(0)); if (!o) - return ctx->engine()->throwTypeError(); + THROW_TYPE_ERROR(); o->setInternalClass(o->internalClass()->nonExtensible()); - return o.asReturnedValue(); + scope.result = o; } -ReturnedValue ObjectPrototype::method_isSealed(CallContext *ctx) +void ObjectPrototype::method_isSealed(const BuiltinFunction *, Scope &scope, CallData *callData) { - Scope scope(ctx); - ScopedObject o(scope, ctx->argument(0)); + ScopedObject o(scope, callData->argument(0)); if (!o) - return ctx->engine()->throwTypeError(); + THROW_TYPE_ERROR(); - if (o->isExtensible()) - return Encode(false); + if (o->isExtensible()) { + scope.result = Encode(false); + return; + } - if (o->internalClass() != o->internalClass()->sealed()) - return Encode(false); + if (o->internalClass() != o->internalClass()->sealed()) { + scope.result = Encode(false); + return; + } - if (!o->arrayData() || !o->arrayData()->length()) - return Encode(true); + if (!o->arrayData() || !o->arrayData()->length()) { + scope.result = Encode(true); + return; + } Q_ASSERT(o->arrayData() && o->arrayData()->length()); - if (!o->arrayData()->attrs) - return Encode(false); + if (!o->arrayData()->attrs) { + scope.result = Encode(false); + return; + } for (uint i = 0; i < o->arrayData()->alloc; ++i) { if (!o->arrayData()->isEmpty(i)) - if (o->arrayData()->attributes(i).isConfigurable()) - return Encode(false); + if (o->arrayData()->attributes(i).isConfigurable()) { + scope.result = Encode(false); + return; + } } - return Encode(true); + scope.result = Encode(true); } -ReturnedValue ObjectPrototype::method_isFrozen(CallContext *ctx) +void ObjectPrototype::method_isFrozen(const BuiltinFunction *, Scope &scope, CallData *callData) { - Scope scope(ctx); - ScopedObject o(scope, ctx->argument(0)); + ScopedObject o(scope, callData->argument(0)); if (!o) - return ctx->engine()->throwTypeError(); + THROW_TYPE_ERROR(); - if (o->isExtensible()) - return Encode(false); + if (o->isExtensible()) { + scope.result = Encode(false); + return; + } - if (o->internalClass() != o->internalClass()->frozen()) - return Encode(false); + if (o->internalClass() != o->internalClass()->frozen()) { + scope.result = Encode(false); + return; + } - if (!o->arrayData() || !o->arrayData()->length()) - return Encode(true); + if (!o->arrayData() || !o->arrayData()->length()) { + scope.result = Encode(true); + return; + } Q_ASSERT(o->arrayData() && o->arrayData()->length()); - if (!o->arrayData()->attrs) - return Encode(false); + if (!o->arrayData()->attrs) { + scope.result = Encode(false); + return; + } for (uint i = 0; i < o->arrayData()->alloc; ++i) { if (!o->arrayData()->isEmpty(i)) - if (o->arrayData()->attributes(i).isConfigurable() || o->arrayData()->attributes(i).isWritable()) - return Encode(false); + if (o->arrayData()->attributes(i).isConfigurable() || o->arrayData()->attributes(i).isWritable()) { + scope.result = Encode(false); + return; + } } - return Encode(true); + scope.result = Encode(true); } -ReturnedValue ObjectPrototype::method_isExtensible(CallContext *ctx) +void ObjectPrototype::method_isExtensible(const BuiltinFunction *, Scope &scope, CallData *callData) { - Scope scope(ctx); - ScopedObject o(scope, ctx->argument(0)); + ScopedObject o(scope, callData->argument(0)); if (!o) - return ctx->engine()->throwTypeError(); + THROW_TYPE_ERROR(); - return Encode((bool)o->isExtensible()); + scope.result = Encode((bool)o->isExtensible()); } -ReturnedValue ObjectPrototype::method_keys(CallContext *ctx) +void ObjectPrototype::method_keys(const BuiltinFunction *, Scope &scope, CallData *callData) { - Scope scope(ctx); - ScopedObject o(scope, ctx->argument(0)); + ScopedObject o(scope, callData->argument(0)); if (!o) - return ctx->engine()->throwTypeError(); + THROW_TYPE_ERROR(); - ScopedArrayObject a(scope, ctx->d()->engine->newArrayObject()); + ScopedArrayObject a(scope, scope.engine->newArrayObject()); ObjectIterator it(scope, o, ObjectIterator::EnumerableOnly); ScopedValue name(scope); @@ -385,175 +397,159 @@ ReturnedValue ObjectPrototype::method_keys(CallContext *ctx) a->push_back(name); } - return a.asReturnedValue(); + scope.result = a; } -ReturnedValue ObjectPrototype::method_toString(CallContext *ctx) +void ObjectPrototype::method_toString(const BuiltinFunction *, Scope &scope, CallData *callData) { - Scope scope(ctx); - if (ctx->thisObject().isUndefined()) { - return ctx->d()->engine->newString(QStringLiteral("[object Undefined]"))->asReturnedValue(); - } else if (ctx->thisObject().isNull()) { - return ctx->d()->engine->newString(QStringLiteral("[object Null]"))->asReturnedValue(); + if (callData->thisObject.isUndefined()) { + scope.result = scope.engine->newString(QStringLiteral("[object Undefined]")); + } else if (callData->thisObject.isNull()) { + scope.result = scope.engine->newString(QStringLiteral("[object Null]")); } else { - ScopedObject obj(scope, ctx->thisObject().toObject(scope.engine)); + ScopedObject obj(scope, callData->thisObject.toObject(scope.engine)); QString className = obj->className(); - return ctx->d()->engine->newString(QStringLiteral("[object %1]").arg(className))->asReturnedValue(); + scope.result = scope.engine->newString(QStringLiteral("[object %1]").arg(className)); } } -ReturnedValue ObjectPrototype::method_toLocaleString(CallContext *ctx) +void ObjectPrototype::method_toLocaleString(const BuiltinFunction *, Scope &scope, CallData *callData) { - Scope scope(ctx); - ScopedObject o(scope, ctx->thisObject().toObject(scope.engine)); + ScopedObject o(scope, callData->thisObject.toObject(scope.engine)); if (!o) - return Encode::undefined(); - ScopedFunctionObject f(scope, o->get(ctx->d()->engine->id_toString())); + RETURN_UNDEFINED(); + + ScopedFunctionObject f(scope, o->get(scope.engine->id_toString())); if (!f) - return ctx->engine()->throwTypeError(); - ScopedCallData callData(scope); - callData->thisObject = o; + THROW_TYPE_ERROR(); + ScopedCallData cData(scope); + cData->thisObject = o; f->call(scope, callData); - return scope.result.asReturnedValue(); } -ReturnedValue ObjectPrototype::method_valueOf(CallContext *ctx) +void ObjectPrototype::method_valueOf(const BuiltinFunction *, Scope &scope, CallData *callData) { - Scope scope(ctx); - ScopedValue v(scope, ctx->thisObject().toObject(scope.engine)); - if (ctx->d()->engine->hasException) - return Encode::undefined(); - return v->asReturnedValue(); + scope.result = callData->thisObject.toObject(scope.engine); } -ReturnedValue ObjectPrototype::method_hasOwnProperty(CallContext *ctx) +void ObjectPrototype::method_hasOwnProperty(const BuiltinFunction *, Scope &scope, CallData *callData) { - Scope scope(ctx); - ScopedString P(scope, ctx->argument(0), ScopedString::Convert); - if (scope.engine->hasException) - return Encode::undefined(); - ScopedObject O(scope, ctx->thisObject(), ScopedObject::Convert); - if (scope.engine->hasException) - return Encode::undefined(); + ScopedString P(scope, callData->argument(0), ScopedString::Convert); + CHECK_EXCEPTION(); + ScopedObject O(scope, callData->thisObject, ScopedObject::Convert); + CHECK_EXCEPTION(); bool r = O->hasOwnProperty(P); if (!r) r = !O->query(P).isEmpty(); - return Encode(r); + scope.result = Encode(r); } -ReturnedValue ObjectPrototype::method_isPrototypeOf(CallContext *ctx) +void ObjectPrototype::method_isPrototypeOf(const BuiltinFunction *, Scope &scope, CallData *callData) { - Scope scope(ctx); - ScopedObject V(scope, ctx->argument(0)); - if (!V) - return Encode(false); + ScopedObject V(scope, callData->argument(0)); + if (!V) { + scope.result = Encode(false); + return; + } - ScopedObject O(scope, ctx->thisObject(), ScopedObject::Convert); - if (scope.engine->hasException) - return Encode::undefined(); + ScopedObject O(scope, callData->thisObject, ScopedObject::Convert); + CHECK_EXCEPTION(); ScopedObject proto(scope, V->prototype()); while (proto) { - if (O->d() == proto->d()) - return Encode(true); + if (O->d() == proto->d()) { + scope.result = Encode(true); + return; + } proto = proto->prototype(); } - return Encode(false); + scope.result = Encode(false); } -ReturnedValue ObjectPrototype::method_propertyIsEnumerable(CallContext *ctx) +void ObjectPrototype::method_propertyIsEnumerable(const BuiltinFunction *, Scope &scope, CallData *callData) { - Scope scope(ctx); - ScopedString p(scope, ctx->argument(0), ScopedString::Convert); - if (scope.engine->hasException) - return Encode::undefined(); + ScopedString p(scope, callData->argument(0), ScopedString::Convert); + CHECK_EXCEPTION(); - ScopedObject o(scope, ctx->thisObject(), ScopedObject::Convert); - if (scope.engine->hasException) - return Encode::undefined(); + ScopedObject o(scope, callData->thisObject, ScopedObject::Convert); + CHECK_EXCEPTION(); PropertyAttributes attrs; o->getOwnProperty(p, &attrs); - return Encode(attrs.isEnumerable()); + scope.result = Encode(attrs.isEnumerable()); } -ReturnedValue ObjectPrototype::method_defineGetter(CallContext *ctx) +void ObjectPrototype::method_defineGetter(const BuiltinFunction *, Scope &scope, CallData *callData) { - if (ctx->argc() < 2) - return ctx->engine()->throwTypeError(); + if (callData->argc < 2) + THROW_TYPE_ERROR(); - Scope scope(ctx); - ScopedFunctionObject f(scope, ctx->argument(1)); + ScopedFunctionObject f(scope, callData->argument(1)); if (!f) - return ctx->engine()->throwTypeError(); + THROW_TYPE_ERROR(); - ScopedString prop(scope, ctx->argument(0), ScopedString::Convert); - if (scope.engine->hasException) - return Encode::undefined(); + ScopedString prop(scope, callData->argument(0), ScopedString::Convert); + CHECK_EXCEPTION(); - ScopedObject o(scope, ctx->thisObject()); + ScopedObject o(scope, callData->thisObject); if (!o) { - if (!ctx->thisObject().isUndefined()) - return Encode::undefined(); - o = ctx->d()->engine->globalObject; + if (!callData->thisObject.isUndefined()) + RETURN_UNDEFINED(); + o = scope.engine->globalObject; } ScopedProperty pd(scope); pd->value = f; pd->set = Primitive::emptyValue(); o->__defineOwnProperty__(scope.engine, prop, pd, Attr_Accessor); - return Encode::undefined(); + RETURN_UNDEFINED(); } -ReturnedValue ObjectPrototype::method_defineSetter(CallContext *ctx) +void ObjectPrototype::method_defineSetter(const BuiltinFunction *, Scope &scope, CallData *callData) { - if (ctx->argc() < 2) - return ctx->engine()->throwTypeError(); + if (callData->argc < 2) + THROW_TYPE_ERROR(); - Scope scope(ctx); - ScopedFunctionObject f(scope, ctx->argument(1)); + ScopedFunctionObject f(scope, callData->argument(1)); if (!f) - return ctx->engine()->throwTypeError(); + THROW_TYPE_ERROR(); - ScopedString prop(scope, ctx->argument(0), ScopedString::Convert); - if (scope.engine->hasException) - return Encode::undefined(); + ScopedString prop(scope, callData->argument(0), ScopedString::Convert); + CHECK_EXCEPTION(); - ScopedObject o(scope, ctx->thisObject()); + ScopedObject o(scope, callData->thisObject); if (!o) { - if (!ctx->thisObject().isUndefined()) - return Encode::undefined(); - o = ctx->d()->engine->globalObject; + if (!callData->thisObject.isUndefined()) + RETURN_UNDEFINED(); + o = scope.engine->globalObject; } ScopedProperty pd(scope); pd->value = Primitive::emptyValue(); pd->set = f; o->__defineOwnProperty__(scope.engine, prop, pd, Attr_Accessor); - return Encode::undefined(); + RETURN_UNDEFINED(); } -ReturnedValue ObjectPrototype::method_get_proto(CallContext *ctx) +void ObjectPrototype::method_get_proto(const BuiltinFunction *, Scope &scope, CallData *callData) { - Scope scope(ctx); - ScopedObject o(scope, ctx->thisObject().as<Object>()); + ScopedObject o(scope, callData->thisObject.as<Object>()); if (!o) - return ctx->engine()->throwTypeError(); + THROW_TYPE_ERROR(); - return o->prototype()->asReturnedValue(); + scope.result = o->prototype(); } -ReturnedValue ObjectPrototype::method_set_proto(CallContext *ctx) +void ObjectPrototype::method_set_proto(const BuiltinFunction *, Scope &scope, CallData *callData) { - Scope scope(ctx); - ScopedObject o(scope, ctx->thisObject()); - if (!o || !ctx->argc()) - return ctx->engine()->throwTypeError(); + ScopedObject o(scope, callData->thisObject); + if (!o || !callData->argc) + THROW_TYPE_ERROR(); - if (ctx->args()[0].isNull()) { + if (callData->args[0].isNull()) { o->setPrototype(0); - return Encode::undefined(); + RETURN_UNDEFINED(); } - ScopedObject p(scope, ctx->args()[0]); + ScopedObject p(scope, callData->args[0]); bool ok = false; if (!!p) { if (o->prototype() == p->d()) { @@ -562,9 +558,11 @@ ReturnedValue ObjectPrototype::method_set_proto(CallContext *ctx) ok = o->setPrototype(p); } } - if (!ok) - return ctx->engine()->throwTypeError(QStringLiteral("Cyclic __proto__ value")); - return Encode::undefined(); + if (!ok) { + scope.result = scope.engine->throwTypeError(QStringLiteral("Cyclic __proto__ value")); + return; + } + RETURN_UNDEFINED(); } void ObjectPrototype::toPropertyDescriptor(ExecutionEngine *engine, const Value &v, Property *desc, PropertyAttributes *attrs) diff --git a/src/qml/jsruntime/qv4objectproto_p.h b/src/qml/jsruntime/qv4objectproto_p.h index e3d85782d5..1db8615511 100644 --- a/src/qml/jsruntime/qv4objectproto_p.h +++ b/src/qml/jsruntime/qv4objectproto_p.h @@ -78,32 +78,32 @@ struct ObjectPrototype: Object { void init(ExecutionEngine *engine, Object *ctor); - static ReturnedValue method_getPrototypeOf(CallContext *ctx); - static ReturnedValue method_getOwnPropertyDescriptor(CallContext *ctx); - static ReturnedValue method_getOwnPropertyNames(CallContext *context); - static ReturnedValue method_create(CallContext *ctx); - static ReturnedValue method_defineProperty(CallContext *ctx); - static ReturnedValue method_defineProperties(CallContext *ctx); - static ReturnedValue method_seal(CallContext *ctx); - static ReturnedValue method_freeze(CallContext *ctx); - static ReturnedValue method_preventExtensions(CallContext *ctx); - static ReturnedValue method_isSealed(CallContext *ctx); - static ReturnedValue method_isFrozen(CallContext *ctx); - static ReturnedValue method_isExtensible(CallContext *ctx); - static ReturnedValue method_keys(CallContext *ctx); - - static ReturnedValue method_toString(CallContext *ctx); - static ReturnedValue method_toLocaleString(CallContext *ctx); - static ReturnedValue method_valueOf(CallContext *ctx); - static ReturnedValue method_hasOwnProperty(CallContext *ctx); - static ReturnedValue method_isPrototypeOf(CallContext *ctx); - static ReturnedValue method_propertyIsEnumerable(CallContext *ctx); - - static ReturnedValue method_defineGetter(CallContext *ctx); - static ReturnedValue method_defineSetter(CallContext *ctx); - - static ReturnedValue method_get_proto(CallContext *ctx); - static ReturnedValue method_set_proto(CallContext *ctx); + static void method_getPrototypeOf(const BuiltinFunction *, Scope &scope, CallData *callData); + static void method_getOwnPropertyDescriptor(const BuiltinFunction *, Scope &scope, CallData *callData); + static void method_getOwnPropertyNames(const BuiltinFunction *, Scope &scope, CallData *callData); + static void method_create(const BuiltinFunction *, Scope &scope, CallData *callData); + static void method_defineProperty(const BuiltinFunction *, Scope &scope, CallData *callData); + static void method_defineProperties(const BuiltinFunction *, Scope &scope, CallData *callData); + static void method_seal(const BuiltinFunction *, Scope &scope, CallData *callData); + static void method_freeze(const BuiltinFunction *, Scope &scope, CallData *callData); + static void method_preventExtensions(const BuiltinFunction *, Scope &scope, CallData *callData); + static void method_isSealed(const BuiltinFunction *, Scope &scope, CallData *callData); + static void method_isFrozen(const BuiltinFunction *, Scope &scope, CallData *callData); + static void method_isExtensible(const BuiltinFunction *, Scope &scope, CallData *callData); + static void method_keys(const BuiltinFunction *, Scope &scope, CallData *callData); + + static void method_toString(const BuiltinFunction *, Scope &scope, CallData *callData); + static void method_toLocaleString(const BuiltinFunction *, Scope &scope, CallData *callData); + static void method_valueOf(const BuiltinFunction *, Scope &scope, CallData *callData); + static void method_hasOwnProperty(const BuiltinFunction *, Scope &scope, CallData *callData); + static void method_isPrototypeOf(const BuiltinFunction *, Scope &scope, CallData *callData); + static void method_propertyIsEnumerable(const BuiltinFunction *, Scope &scope, CallData *callData); + + static void method_defineGetter(const BuiltinFunction *, Scope &scope, CallData *callData); + static void method_defineSetter(const BuiltinFunction *, Scope &scope, CallData *callData); + + static void method_get_proto(const BuiltinFunction *, Scope &scope, CallData *callData); + static void method_set_proto(const BuiltinFunction *, Scope &scope, CallData *callData); static void toPropertyDescriptor(ExecutionEngine *engine, const Value &v, Property *desc, PropertyAttributes *attrs); static ReturnedValue fromPropertyDescriptor(ExecutionEngine *engine, const Property *desc, PropertyAttributes attrs); diff --git a/src/qml/jsruntime/qv4qobjectwrapper.cpp b/src/qml/jsruntime/qv4qobjectwrapper.cpp index 77dbb18b50..7260e71fab 100644 --- a/src/qml/jsruntime/qv4qobjectwrapper.cpp +++ b/src/qml/jsruntime/qv4qobjectwrapper.cpp @@ -826,40 +826,39 @@ struct QObjectSlotDispatcher : public QtPrivate::QSlotObjectBase } // namespace QV4 -ReturnedValue QObjectWrapper::method_connect(CallContext *ctx) +void QObjectWrapper::method_connect(const BuiltinFunction *, Scope &scope, CallData *callData) { - if (ctx->argc() == 0) - V4THROW_ERROR("Function.prototype.connect: no arguments given"); + if (callData->argc == 0) + THROW_GENERIC_ERROR("Function.prototype.connect: no arguments given"); - QPair<QObject *, int> signalInfo = extractQtSignal(ctx->thisObject()); + QPair<QObject *, int> signalInfo = extractQtSignal(callData->thisObject); QObject *signalObject = signalInfo.first; int signalIndex = signalInfo.second; // in method range, not signal range! if (signalIndex < 0) - V4THROW_ERROR("Function.prototype.connect: this object is not a signal"); + THROW_GENERIC_ERROR("Function.prototype.connect: this object is not a signal"); if (!signalObject) - V4THROW_ERROR("Function.prototype.connect: cannot connect to deleted QObject"); + THROW_GENERIC_ERROR("Function.prototype.connect: cannot connect to deleted QObject"); if (signalObject->metaObject()->method(signalIndex).methodType() != QMetaMethod::Signal) - V4THROW_ERROR("Function.prototype.connect: this object is not a signal"); + THROW_GENERIC_ERROR("Function.prototype.connect: this object is not a signal"); - QV4::Scope scope(ctx); QV4::ScopedFunctionObject f(scope); QV4::ScopedValue thisObject (scope, QV4::Encode::undefined()); - if (ctx->argc() == 1) { - f = ctx->args()[0]; - } else if (ctx->argc() >= 2) { - thisObject = ctx->args()[0]; - f = ctx->args()[1]; + if (callData->argc == 1) { + f = callData->args[0]; + } else if (callData->argc >= 2) { + thisObject = callData->args[0]; + f = callData->args[1]; } if (!f) - V4THROW_ERROR("Function.prototype.connect: target is not a function"); + THROW_GENERIC_ERROR("Function.prototype.connect: target is not a function"); if (!thisObject->isUndefined() && !thisObject->isObject()) - V4THROW_ERROR("Function.prototype.connect: target this is not an object"); + THROW_GENERIC_ERROR("Function.prototype.connect: target this is not an object"); QV4::QObjectSlotDispatcher *slot = new QV4::QObjectSlotDispatcher; slot->signalIndex = signalIndex; @@ -874,49 +873,47 @@ ReturnedValue QObjectWrapper::method_connect(CallContext *ctx) } QObjectPrivate::connect(signalObject, signalIndex, slot, Qt::AutoConnection); - return Encode::undefined(); + RETURN_UNDEFINED(); } -ReturnedValue QObjectWrapper::method_disconnect(CallContext *ctx) +void QObjectWrapper::method_disconnect(const BuiltinFunction *, Scope &scope, CallData *callData) { - if (ctx->argc() == 0) - V4THROW_ERROR("Function.prototype.disconnect: no arguments given"); - - QV4::Scope scope(ctx); + if (callData->argc == 0) + THROW_GENERIC_ERROR("Function.prototype.disconnect: no arguments given"); - QPair<QObject *, int> signalInfo = extractQtSignal(ctx->thisObject()); + QPair<QObject *, int> signalInfo = extractQtSignal(callData->thisObject); QObject *signalObject = signalInfo.first; int signalIndex = signalInfo.second; if (signalIndex == -1) - V4THROW_ERROR("Function.prototype.disconnect: this object is not a signal"); + THROW_GENERIC_ERROR("Function.prototype.disconnect: this object is not a signal"); if (!signalObject) - V4THROW_ERROR("Function.prototype.disconnect: cannot disconnect from deleted QObject"); + THROW_GENERIC_ERROR("Function.prototype.disconnect: cannot disconnect from deleted QObject"); if (signalIndex < 0 || signalObject->metaObject()->method(signalIndex).methodType() != QMetaMethod::Signal) - V4THROW_ERROR("Function.prototype.disconnect: this object is not a signal"); + THROW_GENERIC_ERROR("Function.prototype.disconnect: this object is not a signal"); QV4::ScopedFunctionObject functionValue(scope); QV4::ScopedValue functionThisValue(scope, QV4::Encode::undefined()); - if (ctx->argc() == 1) { - functionValue = ctx->args()[0]; - } else if (ctx->argc() >= 2) { - functionThisValue = ctx->args()[0]; - functionValue = ctx->args()[1]; + if (callData->argc == 1) { + functionValue = callData->args[0]; + } else if (callData->argc >= 2) { + functionThisValue = callData->args[0]; + functionValue = callData->args[1]; } if (!functionValue) - V4THROW_ERROR("Function.prototype.disconnect: target is not a function"); + THROW_GENERIC_ERROR("Function.prototype.disconnect: target is not a function"); if (!functionThisValue->isUndefined() && !functionThisValue->isObject()) - V4THROW_ERROR("Function.prototype.disconnect: target this is not an object"); + THROW_GENERIC_ERROR("Function.prototype.disconnect: target this is not an object"); QPair<QObject *, int> functionData = QObjectMethod::extractQtMethod(functionValue); void *a[] = { - ctx->d()->engine, + scope.engine, functionValue.ptr, functionThisValue.ptr, functionData.first, @@ -925,7 +922,7 @@ ReturnedValue QObjectWrapper::method_disconnect(CallContext *ctx) QObjectPrivate::disconnect(signalObject, signalIndex, reinterpret_cast<void**>(&a)); - return Encode::undefined(); + RETURN_UNDEFINED(); } static void markChildQObjectsRecursively(QObject *parent, QV4::ExecutionEngine *e) diff --git a/src/qml/jsruntime/qv4qobjectwrapper_p.h b/src/qml/jsruntime/qv4qobjectwrapper_p.h index c7c4f4dd77..b09e06cec5 100644 --- a/src/qml/jsruntime/qv4qobjectwrapper_p.h +++ b/src/qml/jsruntime/qv4qobjectwrapper_p.h @@ -197,8 +197,8 @@ protected: static void advanceIterator(Managed *m, ObjectIterator *it, Value *name, uint *index, Property *p, PropertyAttributes *attributes); static void markObjects(Heap::Base *that, QV4::ExecutionEngine *e); - static ReturnedValue method_connect(CallContext *ctx); - static ReturnedValue method_disconnect(CallContext *ctx); + static void method_connect(const BuiltinFunction *, Scope &scope, CallData *callData); + static void method_disconnect(const BuiltinFunction *, Scope &scope, CallData *callData); private: Q_NEVER_INLINE static ReturnedValue wrap_slowPath(ExecutionEngine *engine, QObject *object); diff --git a/src/qml/jsruntime/qv4regexpobject.cpp b/src/qml/jsruntime/qv4regexpobject.cpp index 218695624b..40682aaa4b 100644 --- a/src/qml/jsruntime/qv4regexpobject.cpp +++ b/src/qml/jsruntime/qv4regexpobject.cpp @@ -307,7 +307,8 @@ void RegExpCtor::markObjects(Heap::Base *that, ExecutionEngine *e) { RegExpCtor::Data *This = static_cast<RegExpCtor::Data *>(that); This->lastMatch.mark(e); - This->lastInput->mark(e); + if (This->lastInput) + This->lastInput->mark(e); FunctionObject::markObjects(that, e); } @@ -348,34 +349,33 @@ void RegExpPrototype::init(ExecutionEngine *engine, Object *constructor) defineDefaultProperty(QStringLiteral("compile"), method_compile, 2); } -ReturnedValue RegExpPrototype::method_exec(CallContext *ctx) +void RegExpPrototype::method_exec(const BuiltinFunction *, Scope &scope, CallData *callData) { - Scope scope(ctx); - Scoped<RegExpObject> r(scope, ctx->thisObject().as<RegExpObject>()); + Scoped<RegExpObject> r(scope, callData->thisObject.as<RegExpObject>()); if (!r) - return ctx->engine()->throwTypeError(); + THROW_TYPE_ERROR(); - ScopedValue arg(scope, ctx->argument(0)); + ScopedValue arg(scope, callData->argument(0)); ScopedString str(scope, arg->toString(scope.engine)); if (scope.hasException()) - return Encode::undefined(); + RETURN_UNDEFINED(); QString s = str->toQString(); int offset = r->global() ? r->lastIndexProperty()->toInt32() : 0; if (offset < 0 || offset > s.length()) { *r->lastIndexProperty() = Primitive::fromInt32(0); - return Encode::null(); + RETURN_RESULT(Encode::null()); } uint* matchOffsets = (uint*)alloca(r->value()->captureCount() * 2 * sizeof(uint)); const int result = Scoped<RegExp>(scope, r->value())->match(s, offset, matchOffsets); - Scoped<RegExpCtor> regExpCtor(scope, ctx->d()->engine->regExpCtor()); + Scoped<RegExpCtor> regExpCtor(scope, scope.engine->regExpCtor()); regExpCtor->d()->clearLastMatch(); if (result == -1) { *r->lastIndexProperty() = Primitive::fromInt32(0); - return Encode::null(); + RETURN_RESULT(Encode::null()); } // fill in result data @@ -386,7 +386,7 @@ ReturnedValue RegExpPrototype::method_exec(CallContext *ctx) for (int i = 0; i < len; ++i) { int start = matchOffsets[i * 2]; int end = matchOffsets[i * 2 + 1]; - v = (start != -1) ? ctx->d()->engine->newString(s.mid(start, end - start))->asReturnedValue() : Encode::undefined(); + v = (start != -1) ? scope.engine->newString(s.mid(start, end - start))->asReturnedValue() : Encode::undefined(); array->arrayPut(i, v); } array->setArrayLengthUnchecked(len); @@ -402,84 +402,75 @@ ReturnedValue RegExpPrototype::method_exec(CallContext *ctx) if (r->global()) *r->lastIndexProperty() = Primitive::fromInt32(matchOffsets[1]); - return array.asReturnedValue(); + scope.result = array; } -ReturnedValue RegExpPrototype::method_test(CallContext *ctx) +void RegExpPrototype::method_test(const BuiltinFunction *b, Scope &scope, CallData *callData) { - Scope scope(ctx); - ScopedValue r(scope, method_exec(ctx)); - return Encode(!r->isNull()); + method_exec(b, scope, callData); + scope.result = Encode(!scope.result.isNull()); } -ReturnedValue RegExpPrototype::method_toString(CallContext *ctx) +void RegExpPrototype::method_toString(const BuiltinFunction *, Scope &scope, CallData *callData) { - Scope scope(ctx); - Scoped<RegExpObject> r(scope, ctx->thisObject().as<RegExpObject>()); + Scoped<RegExpObject> r(scope, callData->thisObject.as<RegExpObject>()); if (!r) - return ctx->engine()->throwTypeError(); + THROW_TYPE_ERROR(); - return ctx->d()->engine->newString(r->toString())->asReturnedValue(); + scope.result = scope.engine->newString(r->toString()); } -ReturnedValue RegExpPrototype::method_compile(CallContext *ctx) +void RegExpPrototype::method_compile(const BuiltinFunction *, Scope &scope, CallData *callData) { - Scope scope(ctx); - Scoped<RegExpObject> r(scope, ctx->thisObject().as<RegExpObject>()); + Scoped<RegExpObject> r(scope, callData->thisObject.as<RegExpObject>()); if (!r) - return ctx->engine()->throwTypeError(); + THROW_TYPE_ERROR(); - ScopedCallData callData(scope, ctx->argc()); - memcpy(callData->args, ctx->args(), ctx->argc()*sizeof(Value)); + ScopedCallData cData(scope, callData->argc); + memcpy(cData->args, callData->args, callData->argc*sizeof(Value)); - ctx->d()->engine->regExpCtor()->as<FunctionObject>()->construct(scope, callData); + scope.engine->regExpCtor()->as<FunctionObject>()->construct(scope, cData); Scoped<RegExpObject> re(scope, scope.result.asReturnedValue()); r->d()->value = re->value(); r->d()->global = re->global(); - return Encode::undefined(); + RETURN_UNDEFINED(); } template <int index> -ReturnedValue RegExpPrototype::method_get_lastMatch_n(CallContext *ctx) +void RegExpPrototype::method_get_lastMatch_n(const BuiltinFunction *, Scope &scope, CallData *) { - Scope scope(ctx); - ScopedArrayObject lastMatch(scope, static_cast<RegExpCtor*>(ctx->d()->engine->regExpCtor())->lastMatch()); - ScopedValue result(scope, lastMatch ? lastMatch->getIndexed(index) : Encode::undefined()); - if (result->isUndefined()) - return ctx->d()->engine->newString()->asReturnedValue(); - return result->asReturnedValue(); + ScopedArrayObject lastMatch(scope, static_cast<RegExpCtor*>(scope.engine->regExpCtor())->lastMatch()); + scope.result = lastMatch ? lastMatch->getIndexed(index) : Encode::undefined(); + if (scope.result.isUndefined()) + scope.result = scope.engine->newString(); } -ReturnedValue RegExpPrototype::method_get_lastParen(CallContext *ctx) +void RegExpPrototype::method_get_lastParen(const BuiltinFunction *, Scope &scope, CallData *) { - Scope scope(ctx); - ScopedArrayObject lastMatch(scope, static_cast<RegExpCtor*>(ctx->d()->engine->regExpCtor())->lastMatch()); - ScopedValue result(scope, lastMatch ? lastMatch->getIndexed(lastMatch->getLength() - 1) : Encode::undefined()); - if (result->isUndefined()) - return ctx->d()->engine->newString()->asReturnedValue(); - return result->asReturnedValue(); + ScopedArrayObject lastMatch(scope, static_cast<RegExpCtor*>(scope.engine->regExpCtor())->lastMatch()); + scope.result = lastMatch ? lastMatch->getIndexed(lastMatch->getLength() - 1) : Encode::undefined(); + if (scope.result.isUndefined()) + scope.result = scope.engine->newString(); } -ReturnedValue RegExpPrototype::method_get_input(CallContext *ctx) +void RegExpPrototype::method_get_input(const BuiltinFunction *, Scope &scope, CallData *) { - return static_cast<RegExpCtor*>(ctx->d()->engine->regExpCtor())->lastInput()->asReturnedValue(); + scope.result = static_cast<RegExpCtor*>(scope.engine->regExpCtor())->lastInput(); } -ReturnedValue RegExpPrototype::method_get_leftContext(CallContext *ctx) +void RegExpPrototype::method_get_leftContext(const BuiltinFunction *, Scope &scope, CallData *) { - Scope scope(ctx); - Scoped<RegExpCtor> regExpCtor(scope, ctx->d()->engine->regExpCtor()); + Scoped<RegExpCtor> regExpCtor(scope, scope.engine->regExpCtor()); QString lastInput = regExpCtor->lastInput()->toQString(); - return ctx->d()->engine->newString(lastInput.left(regExpCtor->lastMatchStart()))->asReturnedValue(); + scope.result = scope.engine->newString(lastInput.left(regExpCtor->lastMatchStart())); } -ReturnedValue RegExpPrototype::method_get_rightContext(CallContext *ctx) +void RegExpPrototype::method_get_rightContext(const BuiltinFunction *, Scope &scope, CallData *) { - Scope scope(ctx); - Scoped<RegExpCtor> regExpCtor(scope, ctx->d()->engine->regExpCtor()); + Scoped<RegExpCtor> regExpCtor(scope, scope.engine->regExpCtor()); QString lastInput = regExpCtor->lastInput()->toQString(); - return ctx->d()->engine->newString(lastInput.mid(regExpCtor->lastMatchEnd()))->asReturnedValue(); + scope.result = scope.engine->newString(lastInput.mid(regExpCtor->lastMatchEnd())); } QT_END_NAMESPACE diff --git a/src/qml/jsruntime/qv4regexpobject_p.h b/src/qml/jsruntime/qv4regexpobject_p.h index 2c82cfdfd1..c0c7dfa78a 100644 --- a/src/qml/jsruntime/qv4regexpobject_p.h +++ b/src/qml/jsruntime/qv4regexpobject_p.h @@ -149,17 +149,17 @@ struct RegExpPrototype: RegExpObject { void init(ExecutionEngine *engine, Object *ctor); - static ReturnedValue method_exec(CallContext *ctx); - static ReturnedValue method_test(CallContext *ctx); - static ReturnedValue method_toString(CallContext *ctx); - static ReturnedValue method_compile(CallContext *ctx); + static void method_exec(const BuiltinFunction *, Scope &scope, CallData *callData); + static void method_test(const BuiltinFunction *, Scope &scope, CallData *callData); + static void method_toString(const BuiltinFunction *, Scope &scope, CallData *callData); + static void method_compile(const BuiltinFunction *, Scope &scope, CallData *callData); template <int index> - static ReturnedValue method_get_lastMatch_n(CallContext *ctx); - static ReturnedValue method_get_lastParen(CallContext *ctx); - static ReturnedValue method_get_input(CallContext *ctx); - static ReturnedValue method_get_leftContext(CallContext *ctx); - static ReturnedValue method_get_rightContext(CallContext *ctx); + static void method_get_lastMatch_n(const BuiltinFunction *, Scope &scope, CallData *callData); + static void method_get_lastParen(const BuiltinFunction *, Scope &scope, CallData *callData); + static void method_get_input(const BuiltinFunction *, Scope &scope, CallData *callData); + static void method_get_leftContext(const BuiltinFunction *, Scope &scope, CallData *callData); + static void method_get_rightContext(const BuiltinFunction *, Scope &scope, CallData *callData); }; } diff --git a/src/qml/jsruntime/qv4runtime.cpp b/src/qml/jsruntime/qv4runtime.cpp index d6c55926b1..023a739e33 100644 --- a/src/qml/jsruntime/qv4runtime.cpp +++ b/src/qml/jsruntime/qv4runtime.cpp @@ -499,6 +499,7 @@ Heap::String *RuntimeHelpers::convertToString(ExecutionEngine *engine, const Val { Scope scope(engine); ScopedValue prim(scope, RuntimeHelpers::toPrimitive(value, STRING_HINT)); + Q_ASSERT(!prim->isManaged() || prim->isString()); return RuntimeHelpers::convertToString(engine, prim); } case Value::Integer_Type: diff --git a/src/qml/jsruntime/qv4scopedvalue_p.h b/src/qml/jsruntime/qv4scopedvalue_p.h index 4e627e003f..6775028272 100644 --- a/src/qml/jsruntime/qv4scopedvalue_p.h +++ b/src/qml/jsruntime/qv4scopedvalue_p.h @@ -68,6 +68,38 @@ namespace QV4 { struct ScopedValue; +#define CHECK_EXCEPTION() \ + do { \ + if (scope.hasException()) { \ + scope.result = QV4::Encode::undefined(); \ + return; \ + } \ + } while (false) + +#define RETURN_UNDEFINED() \ + do { \ + scope.result = QV4::Encode::undefined(); \ + return; \ + } while (false) + +#define RETURN_RESULT(r) \ + do { \ + scope.result = r; \ + return; \ + } while (false) + +#define THROW_TYPE_ERROR() \ + do { \ + scope.result = scope.engine->throwTypeError(); \ + return; \ + } while (false) + +#define THROW_GENERIC_ERROR(str) \ + do { \ + scope.result = scope.engine->throwError(QString::fromUtf8(str)); \ + return; \ + } while (false) + struct Scope { inline Scope(ExecutionContext *ctx) : engine(ctx->d()->engine) diff --git a/src/qml/jsruntime/qv4script.cpp b/src/qml/jsruntime/qv4script.cpp index b54177bee9..62145f36cc 100644 --- a/src/qml/jsruntime/qv4script.cpp +++ b/src/qml/jsruntime/qv4script.cpp @@ -88,8 +88,6 @@ void Script::parse() ExecutionEngine *v4 = scope->engine(); Scope valueScope(v4); - MemoryManager::GCBlocker gcBlocker(v4->memoryManager); - IR::Module module(v4->debugger() != 0); QQmlJS::Engine ee, *engine = ⅇ diff --git a/src/qml/jsruntime/qv4sequenceobject.cpp b/src/qml/jsruntime/qv4sequenceobject.cpp index 58da7b9f68..8ce10e326d 100644 --- a/src/qml/jsruntime/qv4sequenceobject.cpp +++ b/src/qml/jsruntime/qv4sequenceobject.cpp @@ -404,28 +404,28 @@ public: struct CompareFunctor { - CompareFunctor(QV4::ExecutionContext *ctx, const QV4::Value &compareFn) - : m_ctx(ctx), m_compareFn(&compareFn) + CompareFunctor(QV4::ExecutionEngine *v4, const QV4::Value &compareFn) + : m_v4(v4), m_compareFn(&compareFn) {} bool operator()(typename Container::value_type lhs, typename Container::value_type rhs) { - QV4::Scope scope(m_ctx); + QV4::Scope scope(m_v4); ScopedObject compare(scope, m_compareFn); ScopedCallData callData(scope, 2); - 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; + callData->args[0] = convertElementToValue(m_v4, lhs); + callData->args[1] = convertElementToValue(m_v4, rhs); + callData->thisObject = m_v4->globalObject; compare->call(scope, callData); return scope.result.toNumber() < 0; } private: - QV4::ExecutionContext *m_ctx; + QV4::ExecutionEngine *m_v4; const QV4::Value *m_compareFn; }; - void sort(QV4::CallContext *ctx) + void sort(const BuiltinFunction *, Scope &scope, CallData *callData) { if (d()->isReference) { if (!d()->object) @@ -433,9 +433,8 @@ public: loadReference(); } - QV4::Scope scope(ctx); - if (ctx->argc() == 1 && ctx->args()[0].as<FunctionObject>()) { - CompareFunctor cf(ctx, ctx->args()[0]); + if (callData->argc == 1 && callData->args[0].as<FunctionObject>()) { + CompareFunctor cf(scope.engine, callData->args[0]); std::sort(d()->container->begin(), d()->container->end(), cf); } else { DefaultCompareFunctor cf; @@ -446,45 +445,43 @@ public: storeReference(); } - static QV4::ReturnedValue method_get_length(QV4::CallContext *ctx) + static void method_get_length(const BuiltinFunction *, Scope &scope, CallData *callData) { - QV4::Scope scope(ctx); - QV4::Scoped<QQmlSequence<Container> > This(scope, ctx->thisObject().as<QQmlSequence<Container> >()); + QV4::Scoped<QQmlSequence<Container> > This(scope, callData->thisObject.as<QQmlSequence<Container> >()); if (!This) - return ctx->engine()->throwTypeError(); + THROW_TYPE_ERROR(); if (This->d()->isReference) { if (!This->d()->object) - return QV4::Encode(0); + RETURN_RESULT(Encode(0)); This->loadReference(); } - return QV4::Encode(This->d()->container->count()); + RETURN_RESULT(Encode(This->d()->container->count())); } - static QV4::ReturnedValue method_set_length(QV4::CallContext* ctx) + static void method_set_length(const BuiltinFunction *, Scope &scope, CallData *callData) { - QV4::Scope scope(ctx); - QV4::Scoped<QQmlSequence<Container> > This(scope, ctx->thisObject().as<QQmlSequence<Container> >()); + QV4::Scoped<QQmlSequence<Container> > This(scope, callData->thisObject.as<QQmlSequence<Container> >()); if (!This) - return ctx->engine()->throwTypeError(); + THROW_TYPE_ERROR(); - quint32 newLength = ctx->args()[0].toUInt32(); + quint32 newLength = callData->args[0].toUInt32(); /* Qt containers have int (rather than uint) allowable indexes. */ if (newLength > INT_MAX) { generateWarning(scope.engine, QLatin1String("Index out of range during length set")); - return QV4::Encode::undefined(); + RETURN_UNDEFINED(); } /* Read the sequence from the QObject property if we're a reference */ if (This->d()->isReference) { if (!This->d()->object) - return QV4::Encode::undefined(); + RETURN_UNDEFINED(); This->loadReference(); } /* Determine whether we need to modify the sequence */ qint32 newCount = static_cast<qint32>(newLength); qint32 count = This->d()->container->count(); if (newCount == count) { - return QV4::Encode::undefined(); + RETURN_UNDEFINED(); } else if (newCount > count) { /* according to ECMA262r3 we need to insert */ /* undefined values increasing length to newLength. */ @@ -506,7 +503,7 @@ public: /* write back. already checked that object is non-null, so skip that check here. */ This->storeReference(); } - return QV4::Encode::undefined(); + RETURN_UNDEFINED(); } QVariant toVariant() const @@ -625,26 +622,25 @@ void SequencePrototype::init() } #undef REGISTER_QML_SEQUENCE_METATYPE -QV4::ReturnedValue SequencePrototype::method_sort(QV4::CallContext *ctx) +void SequencePrototype::method_sort(const BuiltinFunction *b, Scope &scope, CallData *callData) { - QV4::Scope scope(ctx); - QV4::ScopedObject o(scope, ctx->thisObject()); + QV4::ScopedObject o(scope, callData->thisObject); if (!o || !o->isListType()) - return ctx->engine()->throwTypeError(); + THROW_TYPE_ERROR(); - if (ctx->argc() >= 2) - return o.asReturnedValue(); + if (callData->argc >= 2) + RETURN_RESULT(o); #define CALL_SORT(SequenceElementType, SequenceElementTypeName, SequenceType, DefaultValue) \ if (QQml##SequenceElementTypeName##List *s = o->as<QQml##SequenceElementTypeName##List>()) { \ - s->sort(ctx); \ + s->sort(b, scope, callData); \ } else FOREACH_QML_SEQUENCE_TYPE(CALL_SORT) #undef CALL_SORT {} - return o.asReturnedValue(); + RETURN_RESULT(o); } #define IS_SEQUENCE(unused1, unused2, SequenceType, unused3) \ diff --git a/src/qml/jsruntime/qv4sequenceobject_p.h b/src/qml/jsruntime/qv4sequenceobject_p.h index c0416ad639..6f96b9f760 100644 --- a/src/qml/jsruntime/qv4sequenceobject_p.h +++ b/src/qml/jsruntime/qv4sequenceobject_p.h @@ -67,12 +67,12 @@ struct SequencePrototype : public QV4::Object { void init(); - static ReturnedValue method_valueOf(QV4::CallContext *ctx) + static void method_valueOf(const BuiltinFunction *, Scope &scope, CallData *callData) { - return ctx->thisObject().toString(ctx->engine())->asReturnedValue(); + scope.result = callData->thisObject.toString(scope.engine); } - static ReturnedValue method_sort(QV4::CallContext *ctx); + static void method_sort(const BuiltinFunction *, Scope &scope, CallData *callData); static bool isSequenceType(int sequenceTypeId); static ReturnedValue newSequence(QV4::ExecutionEngine *engine, int sequenceTypeId, QObject *object, int propertyIndex, bool *succeeded); diff --git a/src/qml/jsruntime/qv4string.cpp b/src/qml/jsruntime/qv4string.cpp index 1efd8cb714..cde2131aab 100644 --- a/src/qml/jsruntime/qv4string.cpp +++ b/src/qml/jsruntime/qv4string.cpp @@ -102,6 +102,7 @@ void Heap::String::init(MemoryManager *mm, String *l, String *r) stringHash = UINT_MAX; largestSubLength = qMax(l->largestSubLength, r->largestSubLength); len = l->len + r->len; + Q_ASSERT(largestSubLength <= len); if (!l->largestSubLength && l->len > largestSubLength) largestSubLength = l->len; @@ -113,6 +114,15 @@ void Heap::String::init(MemoryManager *mm, String *l, String *r) simplifyString(); } +void Heap::String::destroy() { + if (!largestSubLength) { + mm->changeUnmanagedHeapSizeUsage(qptrdiff(-text->size) * (int)sizeof(QChar)); + if (!text->ref.deref()) + QStringData::deallocate(text); + } + Base::destroy(); +} + uint String::toUInt(bool *ok) const { *ok = true; @@ -151,7 +161,7 @@ void Heap::String::simplifyString() const text->ref.ref(); identifier = 0; largestSubLength = 0; - mm->growUnmanagedHeapSizeUsage(size_t(text->size) * sizeof(QChar)); + mm->changeUnmanagedHeapSizeUsage(qptrdiff(text->size) * (qptrdiff)sizeof(QChar)); } void Heap::String::append(const String *data, QChar *ch) diff --git a/src/qml/jsruntime/qv4string_p.h b/src/qml/jsruntime/qv4string_p.h index 4890a85724..5b0fd292d6 100644 --- a/src/qml/jsruntime/qv4string_p.h +++ b/src/qml/jsruntime/qv4string_p.h @@ -73,11 +73,7 @@ struct Q_QML_PRIVATE_EXPORT String : Base { #ifndef V4_BOOTSTRAP void init(MemoryManager *mm, const QString &text); void init(MemoryManager *mm, String *l, String *n); - void destroy() { - if (!largestSubLength && !text->ref.deref()) - QStringData::deallocate(text); - Base::destroy(); - } + void destroy(); void simplifyString() const; int length() const { Q_ASSERT((largestSubLength && diff --git a/src/qml/jsruntime/qv4stringobject.cpp b/src/qml/jsruntime/qv4stringobject.cpp index 6fbf1c3c85..3c6a24e035 100644 --- a/src/qml/jsruntime/qv4stringobject.cpp +++ b/src/qml/jsruntime/qv4stringobject.cpp @@ -214,10 +214,9 @@ void StringPrototype::init(ExecutionEngine *engine, Object *ctor) defineDefaultProperty(QStringLiteral("trim"), method_trim); } -static QString getThisString(ExecutionContext *ctx) +static QString getThisString(Scope &scope, CallData *callData) { - Scope scope(ctx); - ScopedValue t(scope, ctx->thisObject()); + ScopedValue t(scope, callData->thisObject); if (String *s = t->stringValue()) return s->toQString(); if (StringObject *thisString = t->as<StringObject>()) @@ -229,158 +228,146 @@ static QString getThisString(ExecutionContext *ctx) return t->toQString(); } -ReturnedValue StringPrototype::method_toString(CallContext *context) +void StringPrototype::method_toString(const BuiltinFunction *, Scope &scope, CallData *callData) { - if (context->thisObject().isString()) - return context->thisObject().asReturnedValue(); + if (callData->thisObject.isString()) + RETURN_RESULT(callData->thisObject); - StringObject *o = context->thisObject().as<StringObject>(); + StringObject *o = callData->thisObject.as<StringObject>(); if (!o) - return context->engine()->throwTypeError(); - return Encode(o->d()->string); + THROW_TYPE_ERROR(); + scope.result = o->d()->string; } -ReturnedValue StringPrototype::method_charAt(CallContext *context) +void StringPrototype::method_charAt(const BuiltinFunction *, Scope &scope, CallData *callData) { - const QString str = getThisString(context); - if (context->d()->engine->hasException) - return Encode::undefined(); + const QString str = getThisString(scope, callData); + CHECK_EXCEPTION(); int pos = 0; - if (context->argc() > 0) - pos = (int) context->args()[0].toInteger(); + if (callData->argc > 0) + pos = (int) callData->args[0].toInteger(); QString result; if (pos >= 0 && pos < str.length()) result += str.at(pos); - return context->d()->engine->newString(result)->asReturnedValue(); + scope.result = scope.engine->newString(result); } -ReturnedValue StringPrototype::method_charCodeAt(CallContext *context) +void StringPrototype::method_charCodeAt(const BuiltinFunction *, Scope &scope, CallData *callData) { - const QString str = getThisString(context); - if (context->d()->engine->hasException) - return Encode::undefined(); + const QString str = getThisString(scope, callData); + CHECK_EXCEPTION(); int pos = 0; - if (context->argc() > 0) - pos = (int) context->args()[0].toInteger(); + if (callData->argc > 0) + pos = (int) callData->args[0].toInteger(); if (pos >= 0 && pos < str.length()) - return Encode(str.at(pos).unicode()); + RETURN_RESULT(Encode(str.at(pos).unicode())); - return Encode(qt_qnan()); + scope.result = Encode(qt_qnan()); } -ReturnedValue StringPrototype::method_concat(CallContext *context) +void StringPrototype::method_concat(const BuiltinFunction *, Scope &scope, CallData *callData) { - Scope scope(context); - - QString value = getThisString(context); - if (scope.engine->hasException) - return Encode::undefined(); + QString value = getThisString(scope, callData); + CHECK_EXCEPTION(); ScopedString s(scope); - for (int i = 0; i < context->argc(); ++i) { - s = context->args()[i].toString(scope.engine); - if (scope.hasException()) - return Encode::undefined(); + for (int i = 0; i < callData->argc; ++i) { + s = callData->args[i].toString(scope.engine); + CHECK_EXCEPTION(); + Q_ASSERT(s->isString()); value += s->toQString(); } - return context->d()->engine->newString(value)->asReturnedValue(); + scope.result = scope.engine->newString(value); } -ReturnedValue StringPrototype::method_endsWith(CallContext *context) +void StringPrototype::method_endsWith(const BuiltinFunction *, Scope &scope, CallData *callData) { - QString value = getThisString(context); - if (context->d()->engine->hasException) - return Encode::undefined(); + QString value = getThisString(scope, callData); + CHECK_EXCEPTION(); QString searchString; - if (context->argc()) { - if (context->args()[0].as<RegExpObject>()) - return context->engine()->throwTypeError(); - searchString = context->args()[0].toQString(); + if (callData->argc) { + if (callData->args[0].as<RegExpObject>()) + THROW_TYPE_ERROR(); + searchString = callData->args[0].toQString(); } int pos = value.length(); - if (context->argc() > 1) - pos = (int) context->args()[1].toInteger(); + if (callData->argc > 1) + pos = (int) callData->args[1].toInteger(); if (pos == value.length()) - return Encode(value.endsWith(searchString)); + RETURN_RESULT(Encode(value.endsWith(searchString))); QStringRef stringToSearch = value.leftRef(pos); - return Encode(stringToSearch.endsWith(searchString)); + scope.result = Encode(stringToSearch.endsWith(searchString)); } -ReturnedValue StringPrototype::method_indexOf(CallContext *context) +void StringPrototype::method_indexOf(const BuiltinFunction *, Scope &scope, CallData *callData) { - QString value = getThisString(context); - if (context->d()->engine->hasException) - return Encode::undefined(); + QString value = getThisString(scope, callData); + CHECK_EXCEPTION(); QString searchString; - if (context->argc()) - searchString = context->args()[0].toQString(); + if (callData->argc) + searchString = callData->args[0].toQString(); int pos = 0; - if (context->argc() > 1) - pos = (int) context->args()[1].toInteger(); + if (callData->argc > 1) + pos = (int) callData->args[1].toInteger(); int index = -1; if (! value.isEmpty()) index = value.indexOf(searchString, qMin(qMax(pos, 0), value.length())); - return Encode(index); + scope.result = Encode(index); } -ReturnedValue StringPrototype::method_includes(CallContext *context) +void StringPrototype::method_includes(const BuiltinFunction *, Scope &scope, CallData *callData) { - QString value = getThisString(context); - if (context->d()->engine->hasException) - return Encode::undefined(); + QString value = getThisString(scope, callData); + CHECK_EXCEPTION(); QString searchString; - if (context->argc()) { - if (context->args()[0].as<RegExpObject>()) - return context->engine()->throwTypeError(); - searchString = context->args()[0].toQString(); + if (callData->argc) { + if (callData->args[0].as<RegExpObject>()) + THROW_TYPE_ERROR(); + searchString = callData->args[0].toQString(); } int pos = 0; - if (context->argc() > 1) { - Scope scope(context); - ScopedValue posArg(scope, context->argument(1)); + if (callData->argc > 1) { + ScopedValue posArg(scope, callData->argument(1)); pos = (int) posArg->toInteger(); if (!posArg->isInteger() && posArg->isNumber() && qIsInf(posArg->toNumber())) pos = value.length(); } if (pos == 0) - return Encode(value.contains(searchString)); + RETURN_RESULT(Encode(value.contains(searchString))); QStringRef stringToSearch = value.midRef(pos); - return Encode(stringToSearch.contains(searchString)); + scope.result = Encode(stringToSearch.contains(searchString)); } -ReturnedValue StringPrototype::method_lastIndexOf(CallContext *context) +void StringPrototype::method_lastIndexOf(const BuiltinFunction *, Scope &scope, CallData *callData) { - Scope scope(context); - - const QString value = getThisString(context); - if (scope.engine->hasException) - return Encode::undefined(); + const QString value = getThisString(scope, callData); + CHECK_EXCEPTION(); QString searchString; - if (context->argc()) - searchString = context->args()[0].toQString(); + if (callData->argc) + searchString = callData->args[0].toQString(); - ScopedValue posArg(scope, context->argument(1)); + ScopedValue posArg(scope, callData->argument(1)); double position = RuntimeHelpers::toNumber(posArg); if (std::isnan(position)) position = +qInf(); @@ -391,43 +378,40 @@ ReturnedValue StringPrototype::method_lastIndexOf(CallContext *context) if (!searchString.isEmpty() && pos == value.length()) --pos; if (searchString.isNull() && pos == 0) - return Encode(-1); + RETURN_RESULT(Encode(-1)); int index = value.lastIndexOf(searchString, pos); - return Encode(index); + scope.result = Encode(index); } -ReturnedValue StringPrototype::method_localeCompare(CallContext *context) +void StringPrototype::method_localeCompare(const BuiltinFunction *, Scope &scope, CallData *callData) { - Scope scope(context); - const QString value = getThisString(context); - if (scope.engine->hasException) - return Encode::undefined(); + const QString value = getThisString(scope, callData); + CHECK_EXCEPTION(); - ScopedValue v(scope, context->argument(0)); + ScopedValue v(scope, callData->argument(0)); const QString that = v->toQString(); - return Encode(QString::localeAwareCompare(value, that)); + scope.result = Encode(QString::localeAwareCompare(value, that)); } -ReturnedValue StringPrototype::method_match(CallContext *context) +void StringPrototype::method_match(const BuiltinFunction *, Scope &scope, CallData *callData) { - if (context->thisObject().isUndefined() || context->thisObject().isNull()) - return context->engine()->throwTypeError(); + if (callData->thisObject.isUndefined() || callData->thisObject.isNull()) + THROW_TYPE_ERROR(); - Scope scope(context); - ScopedString s(scope, context->thisObject().toString(scope.engine)); + ScopedString s(scope, callData->thisObject.toString(scope.engine)); - ScopedValue regexp(scope, context->argument(0)); + ScopedValue regexp(scope, callData->argument(0)); Scoped<RegExpObject> rx(scope, regexp); if (!rx) { ScopedCallData callData(scope, 1); callData->args[0] = regexp; - context->d()->engine->regExpCtor()->construct(scope, callData); + scope.engine->regExpCtor()->construct(scope, callData); rx = scope.result.asReturnedValue(); } if (!rx) // ### CHECK - return context->engine()->throwTypeError(); + THROW_TYPE_ERROR(); bool global = rx->global(); @@ -435,24 +419,24 @@ ReturnedValue StringPrototype::method_match(CallContext *context) ScopedString execString(scope, scope.engine->newString(QStringLiteral("exec"))); ScopedFunctionObject exec(scope, scope.engine->regExpPrototype()->get(execString)); - ScopedCallData callData(scope, 1); - callData->thisObject = rx; - callData->args[0] = s; + ScopedCallData cData(scope, 1); + cData->thisObject = rx; + cData->args[0] = s; if (!global) { - exec->call(scope, callData); - return scope.result.asReturnedValue(); + exec->call(scope, cData); + return; } - ScopedString lastIndex(scope, context->d()->engine->newString(QStringLiteral("lastIndex"))); + ScopedString lastIndex(scope, scope.engine->newString(QStringLiteral("lastIndex"))); rx->put(lastIndex, ScopedValue(scope, Primitive::fromInt32(0))); - ScopedArrayObject a(scope, context->d()->engine->newArrayObject()); + ScopedArrayObject a(scope, scope.engine->newArrayObject()); double previousLastIndex = 0; uint n = 0; ScopedValue matchStr(scope); ScopedValue index(scope); while (1) { - exec->call(scope, callData); + exec->call(scope, cData); if (scope.result.isNull()) break; assert(scope.result.isObject()); @@ -469,10 +453,9 @@ ReturnedValue StringPrototype::method_match(CallContext *context) ++n; } if (!n) - return Encode::null(); - - return a.asReturnedValue(); - + scope.result = Encode::null(); + else + scope.result = a; } static void appendReplacementString(QString *result, const QString &input, const QString& replaceValue, uint* matchOffsets, int captureCount) @@ -521,14 +504,13 @@ static void appendReplacementString(QString *result, const QString &input, const } } -ReturnedValue StringPrototype::method_replace(CallContext *ctx) +void StringPrototype::method_replace(const BuiltinFunction *, Scope &scope, CallData *callData) { - Scope scope(ctx); QString string; - if (StringObject *thisString = ctx->thisObject().as<StringObject>()) + if (StringObject *thisString = callData->thisObject.as<StringObject>()) string = thisString->d()->string->toQString(); else - string = ctx->thisObject().toQString(); + string = callData->thisObject.toQString(); int numCaptures = 0; int numStringMatches = 0; @@ -537,7 +519,7 @@ ReturnedValue StringPrototype::method_replace(CallContext *ctx) uint _matchOffsets[64]; uint *matchOffsets = _matchOffsets; - ScopedValue searchValue(scope, ctx->argument(0)); + ScopedValue searchValue(scope, callData->argument(0)); Scoped<RegExpObject> regExp(scope, searchValue); if (regExp) { uint offset = 0; @@ -580,7 +562,7 @@ ReturnedValue StringPrototype::method_replace(CallContext *ctx) } QString result; - ScopedValue replaceValue(scope, ctx->argument(1)); + ScopedValue replaceValue(scope, callData->argument(1)); ScopedFunctionObject searchCallback(scope, replaceValue); if (!!searchCallback) { result.reserve(string.length() + 10*numStringMatches); @@ -595,14 +577,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->d()->engine->newString(string.mid(start, end - start)); + entry = scope.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->d()->engine->newString(string); + callData->args[numCaptures + 1] = scope.engine->newString(string); searchCallback->call(scope, callData); result += string.midRef(lastEnd, matchStart - lastEnd); @@ -632,23 +614,22 @@ ReturnedValue StringPrototype::method_replace(CallContext *ctx) if (matchOffsets != _matchOffsets) free(matchOffsets); - return ctx->d()->engine->newString(result)->asReturnedValue(); + scope.result = scope.engine->newString(result); } -ReturnedValue StringPrototype::method_search(CallContext *ctx) +void StringPrototype::method_search(const BuiltinFunction *, Scope &scope, CallData *callData) { - Scope scope(ctx); - QString string = getThisString(ctx); - scope.result = ctx->argument(0); - if (scope.engine->hasException) - return Encode::undefined(); + QString string = getThisString(scope, callData); + scope.result = callData->argument(0); + CHECK_EXCEPTION(); + Scoped<RegExpObject> regExp(scope, scope.result.as<RegExpObject>()); if (!regExp) { ScopedCallData callData(scope, 1); callData->args[0] = scope.result; - ctx->d()->engine->regExpCtor()->construct(scope, callData); - if (scope.engine->hasException) - return Encode::undefined(); + scope.engine->regExpCtor()->construct(scope, callData); + CHECK_EXCEPTION(); + regExp = scope.result.as<RegExpObject>(); Q_ASSERT(regExp); } @@ -656,21 +637,21 @@ ReturnedValue StringPrototype::method_search(CallContext *ctx) uint* matchOffsets = (uint*)alloca(regExp->value()->captureCount() * 2 * sizeof(uint)); uint result = re->match(string, /*offset*/0, matchOffsets); if (result == JSC::Yarr::offsetNoMatch) - return Encode(-1); - return Encode(result); + scope.result = Encode(-1); + else + scope.result = Encode(result); } -ReturnedValue StringPrototype::method_slice(CallContext *ctx) +void StringPrototype::method_slice(const BuiltinFunction *, Scope &scope, CallData *callData) { - const QString text = getThisString(ctx); - if (ctx->d()->engine->hasException) - return Encode::undefined(); + const QString text = getThisString(scope, callData); + CHECK_EXCEPTION(); const double length = text.length(); - double start = ctx->argc() ? ctx->args()[0].toInteger() : 0; - double end = (ctx->argc() < 2 || ctx->args()[1].isUndefined()) - ? length : ctx->args()[1].toInteger(); + double start = callData->argc ? callData->args[0].toInteger() : 0; + double end = (callData->argc < 2 || callData->args[1].isUndefined()) + ? length : callData->args[1].toInteger(); if (start < 0) start = qMax(length + start, 0.); @@ -686,40 +667,38 @@ ReturnedValue StringPrototype::method_slice(CallContext *ctx) const int intEnd = int(end); int count = qMax(0, intEnd - intStart); - return ctx->d()->engine->newString(text.mid(intStart, count))->asReturnedValue(); + scope.result = scope.engine->newString(text.mid(intStart, count)); } -ReturnedValue StringPrototype::method_split(CallContext *ctx) +void StringPrototype::method_split(const BuiltinFunction *, Scope &scope, CallData *callData) { - Scope scope(ctx); - QString text = getThisString(ctx); - if (scope.engine->hasException) - return Encode::undefined(); + QString text = getThisString(scope, callData); + CHECK_EXCEPTION(); - ScopedValue separatorValue(scope, ctx->argument(0)); - ScopedValue limitValue(scope, ctx->argument(1)); + ScopedValue separatorValue(scope, callData->argument(0)); + ScopedValue limitValue(scope, callData->argument(1)); - ScopedArrayObject array(scope, ctx->d()->engine->newArrayObject()); + ScopedArrayObject array(scope, scope.engine->newArrayObject()); if (separatorValue->isUndefined()) { if (limitValue->isUndefined()) { - ScopedString s(scope, ctx->d()->engine->newString(text)); + ScopedString s(scope, scope.engine->newString(text)); array->push_back(s); - return array.asReturnedValue(); + RETURN_RESULT(array); } - return ctx->d()->engine->newString(text.left(limitValue->toInteger()))->asReturnedValue(); + RETURN_RESULT(scope.engine->newString(text.left(limitValue->toInteger()))); } uint limit = limitValue->isUndefined() ? UINT_MAX : limitValue->toUInt32(); if (limit == 0) - return array.asReturnedValue(); + RETURN_RESULT(array); Scoped<RegExpObject> re(scope, separatorValue); if (re) { if (re->value()->pattern->isEmpty()) { re = (RegExpObject *)0; - separatorValue = ctx->d()->engine->newString(); + separatorValue = scope.engine->newString(); } } @@ -733,7 +712,7 @@ ReturnedValue StringPrototype::method_split(CallContext *ctx) if (result == JSC::Yarr::offsetNoMatch) break; - array->push_back((s = ctx->d()->engine->newString(text.mid(offset, matchOffsets[0] - offset)))); + array->push_back((s = scope.engine->newString(text.mid(offset, matchOffsets[0] - offset)))); offset = qMax(offset + 1, matchOffsets[1]); if (array->getLength() >= limit) @@ -742,72 +721,70 @@ ReturnedValue StringPrototype::method_split(CallContext *ctx) 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->d()->engine->newString(text.mid(start, end - start)))); + array->push_back((s = scope.engine->newString(text.mid(start, end - start)))); if (array->getLength() >= limit) break; } } if (array->getLength() < limit) - array->push_back((s = ctx->d()->engine->newString(text.mid(offset)))); + array->push_back((s = scope.engine->newString(text.mid(offset)))); } else { QString separator = separatorValue->toQString(); if (separator.isEmpty()) { for (uint i = 0; i < qMin(limit, uint(text.length())); ++i) - array->push_back((s = ctx->d()->engine->newString(text.mid(i, 1)))); - return array.asReturnedValue(); + array->push_back((s = scope.engine->newString(text.mid(i, 1)))); + RETURN_RESULT(array); } int start = 0; int end; while ((end = text.indexOf(separator, start)) != -1) { - array->push_back((s = ctx->d()->engine->newString(text.mid(start, end - start)))); + array->push_back((s = scope.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->d()->engine->newString(text.mid(start)))); + array->push_back((s = scope.engine->newString(text.mid(start)))); } - return array.asReturnedValue(); + RETURN_RESULT(array); } -ReturnedValue StringPrototype::method_startsWith(CallContext *context) +void StringPrototype::method_startsWith(const BuiltinFunction *, Scope &scope, CallData *callData) { - QString value = getThisString(context); - if (context->d()->engine->hasException) - return Encode::undefined(); + QString value = getThisString(scope, callData); + CHECK_EXCEPTION(); QString searchString; - if (context->argc()) { - if (context->args()[0].as<RegExpObject>()) - return context->engine()->throwTypeError(); - searchString = context->args()[0].toQString(); + if (callData->argc) { + if (callData->args[0].as<RegExpObject>()) + THROW_TYPE_ERROR(); + searchString = callData->args[0].toQString(); } int pos = 0; - if (context->argc() > 1) - pos = (int) context->args()[1].toInteger(); + if (callData->argc > 1) + pos = (int) callData->args[1].toInteger(); if (pos == 0) - return Encode(value.startsWith(searchString)); + RETURN_RESULT(Encode(value.startsWith(searchString))); QStringRef stringToSearch = value.midRef(pos); - return Encode(stringToSearch.startsWith(searchString)); + RETURN_RESULT(Encode(stringToSearch.startsWith(searchString))); } -ReturnedValue StringPrototype::method_substr(CallContext *context) +void StringPrototype::method_substr(const BuiltinFunction *, Scope &scope, CallData *callData) { - const QString value = getThisString(context); - if (context->d()->engine->hasException) - return Encode::undefined(); + const QString value = getThisString(scope, callData); + CHECK_EXCEPTION(); double start = 0; - if (context->argc() > 0) - start = context->args()[0].toInteger(); + if (callData->argc > 0) + start = callData->args[0].toInteger(); double length = +qInf(); - if (context->argc() > 1) - length = context->args()[1].toInteger(); + if (callData->argc > 1) + length = callData->args[1].toInteger(); double count = value.length(); if (start < 0) @@ -817,24 +794,23 @@ ReturnedValue StringPrototype::method_substr(CallContext *context) qint32 x = Primitive::toInt32(start); qint32 y = Primitive::toInt32(length); - return context->d()->engine->newString(value.mid(x, y))->asReturnedValue(); + scope.result = scope.engine->newString(value.mid(x, y)); } -ReturnedValue StringPrototype::method_substring(CallContext *context) +void StringPrototype::method_substring(const BuiltinFunction *, Scope &scope, CallData *callData) { - QString value = getThisString(context); - if (context->d()->engine->hasException) - return Encode::undefined(); + QString value = getThisString(scope, callData); + CHECK_EXCEPTION(); + int length = value.length(); double start = 0; double end = length; - if (context->argc() > 0) - start = context->args()[0].toInteger(); + if (callData->argc > 0) + start = callData->args[0].toInteger(); - Scope scope(context); - ScopedValue endValue(scope, context->argument(1)); + ScopedValue endValue(scope, callData->argument(1)); if (!endValue->isUndefined()) end = endValue->toInteger(); @@ -858,51 +834,50 @@ ReturnedValue StringPrototype::method_substring(CallContext *context) qint32 x = (int)start; qint32 y = (int)(end - start); - return context->d()->engine->newString(value.mid(x, y))->asReturnedValue(); + scope.result = scope.engine->newString(value.mid(x, y)); } -ReturnedValue StringPrototype::method_toLowerCase(CallContext *ctx) +void StringPrototype::method_toLowerCase(const BuiltinFunction *, Scope &scope, CallData *callData) { - QString value = getThisString(ctx); - if (ctx->d()->engine->hasException) - return Encode::undefined(); - return ctx->d()->engine->newString(value.toLower())->asReturnedValue(); + QString value = getThisString(scope, callData); + CHECK_EXCEPTION(); + + scope.result = scope.engine->newString(value.toLower()); } -ReturnedValue StringPrototype::method_toLocaleLowerCase(CallContext *ctx) +void StringPrototype::method_toLocaleLowerCase(const BuiltinFunction *b, Scope &scope, CallData *callData) { - return method_toLowerCase(ctx); + method_toLowerCase(b, scope, callData); } -ReturnedValue StringPrototype::method_toUpperCase(CallContext *ctx) +void StringPrototype::method_toUpperCase(const BuiltinFunction *, Scope &scope, CallData *callData) { - QString value = getThisString(ctx); - if (ctx->d()->engine->hasException) - return Encode::undefined(); - return ctx->d()->engine->newString(value.toUpper())->asReturnedValue(); + QString value = getThisString(scope, callData); + CHECK_EXCEPTION(); + + scope.result = scope.engine->newString(value.toUpper()); } -ReturnedValue StringPrototype::method_toLocaleUpperCase(CallContext *ctx) +void StringPrototype::method_toLocaleUpperCase(const BuiltinFunction *b, Scope &scope, CallData *callData) { - return method_toUpperCase(ctx); + return method_toUpperCase(b, scope, callData); } -ReturnedValue StringPrototype::method_fromCharCode(CallContext *context) +void StringPrototype::method_fromCharCode(const BuiltinFunction *, Scope &scope, CallData *callData) { - QString str(context->argc(), Qt::Uninitialized); + QString str(callData->argc, Qt::Uninitialized); QChar *ch = str.data(); - for (int i = 0; i < context->argc(); ++i) { - *ch = QChar(context->args()[i].toUInt16()); + for (int i = 0; i < callData->argc; ++i) { + *ch = QChar(callData->args[i].toUInt16()); ++ch; } - return context->d()->engine->newString(str)->asReturnedValue(); + scope.result = scope.engine->newString(str); } -ReturnedValue StringPrototype::method_trim(CallContext *ctx) +void StringPrototype::method_trim(const BuiltinFunction *, Scope &scope, CallData *callData) { - QString s = getThisString(ctx); - if (ctx->d()->engine->hasException) - return Encode::undefined(); + QString s = getThisString(scope, callData); + CHECK_EXCEPTION(); const QChar *chars = s.constData(); int start, end; @@ -915,5 +890,5 @@ ReturnedValue StringPrototype::method_trim(CallContext *ctx) break; } - return ctx->d()->engine->newString(QString(chars + start, end - start + 1))->asReturnedValue(); + scope.result = scope.engine->newString(QString(chars + start, end - start + 1)); } diff --git a/src/qml/jsruntime/qv4stringobject_p.h b/src/qml/jsruntime/qv4stringobject_p.h index b9f9d44fe8..0ee7a6ece9 100644 --- a/src/qml/jsruntime/qv4stringobject_p.h +++ b/src/qml/jsruntime/qv4stringobject_p.h @@ -111,29 +111,29 @@ struct StringPrototype: StringObject { void init(ExecutionEngine *engine, Object *ctor); - static ReturnedValue method_toString(CallContext *context); - static ReturnedValue method_charAt(CallContext *context); - static ReturnedValue method_charCodeAt(CallContext *context); - static ReturnedValue method_concat(CallContext *context); - static ReturnedValue method_endsWith(CallContext *ctx); - static ReturnedValue method_indexOf(CallContext *context); - static ReturnedValue method_includes(CallContext *context); - static ReturnedValue method_lastIndexOf(CallContext *context); - static ReturnedValue method_localeCompare(CallContext *context); - static ReturnedValue method_match(CallContext *context); - static ReturnedValue method_replace(CallContext *ctx); - static ReturnedValue method_search(CallContext *ctx); - static ReturnedValue method_slice(CallContext *ctx); - static ReturnedValue method_split(CallContext *ctx); - static ReturnedValue method_startsWith(CallContext *ctx); - static ReturnedValue method_substr(CallContext *context); - static ReturnedValue method_substring(CallContext *context); - static ReturnedValue method_toLowerCase(CallContext *ctx); - static ReturnedValue method_toLocaleLowerCase(CallContext *ctx); - static ReturnedValue method_toUpperCase(CallContext *ctx); - static ReturnedValue method_toLocaleUpperCase(CallContext *ctx); - static ReturnedValue method_fromCharCode(CallContext *context); - static ReturnedValue method_trim(CallContext *ctx); + static void method_toString(const BuiltinFunction *, Scope &scope, CallData *callData); + static void method_charAt(const BuiltinFunction *, Scope &scope, CallData *callData); + static void method_charCodeAt(const BuiltinFunction *, Scope &scope, CallData *callData); + static void method_concat(const BuiltinFunction *, Scope &scope, CallData *callData); + static void method_endsWith(const BuiltinFunction *, Scope &scope, CallData *callData); + static void method_indexOf(const BuiltinFunction *, Scope &scope, CallData *callData); + static void method_includes(const BuiltinFunction *, Scope &scope, CallData *callData); + static void method_lastIndexOf(const BuiltinFunction *, Scope &scope, CallData *callData); + static void method_localeCompare(const BuiltinFunction *, Scope &scope, CallData *callData); + static void method_match(const BuiltinFunction *, Scope &scope, CallData *callData); + static void method_replace(const BuiltinFunction *, Scope &scope, CallData *callData); + static void method_search(const BuiltinFunction *, Scope &scope, CallData *callData); + static void method_slice(const BuiltinFunction *, Scope &scope, CallData *callData); + static void method_split(const BuiltinFunction *, Scope &scope, CallData *callData); + static void method_startsWith(const BuiltinFunction *, Scope &scope, CallData *callData); + static void method_substr(const BuiltinFunction *, Scope &scope, CallData *callData); + static void method_substring(const BuiltinFunction *, Scope &scope, CallData *callData); + static void method_toLowerCase(const BuiltinFunction *, Scope &scope, CallData *callData); + static void method_toLocaleLowerCase(const BuiltinFunction *, Scope &scope, CallData *callData); + static void method_toUpperCase(const BuiltinFunction *, Scope &scope, CallData *callData); + static void method_toLocaleUpperCase(const BuiltinFunction *, Scope &scope, CallData *callData); + static void method_fromCharCode(const BuiltinFunction *, Scope &scope, CallData *callData); + static void method_trim(const BuiltinFunction *, Scope &scope, CallData *callData); }; } diff --git a/src/qml/jsruntime/qv4typedarray.cpp b/src/qml/jsruntime/qv4typedarray.cpp index 009c573bf8..cecd1e6958 100644 --- a/src/qml/jsruntime/qv4typedarray.cpp +++ b/src/qml/jsruntime/qv4typedarray.cpp @@ -438,79 +438,74 @@ void TypedArrayPrototype::init(ExecutionEngine *engine, TypedArrayCtor *ctor) defineDefaultProperty(QStringLiteral("subarray"), method_subarray, 0); } -ReturnedValue TypedArrayPrototype::method_get_buffer(CallContext *ctx) +void TypedArrayPrototype::method_get_buffer(const BuiltinFunction *, Scope &scope, CallData *callData) { - Scope scope(ctx); - Scoped<TypedArray> v(scope, ctx->thisObject()); + Scoped<TypedArray> v(scope, callData->thisObject); if (!v) - return scope.engine->throwTypeError(); + THROW_TYPE_ERROR(); - return Encode(v->d()->buffer->asReturnedValue()); + scope.result = v->d()->buffer; } -ReturnedValue TypedArrayPrototype::method_get_byteLength(CallContext *ctx) +void TypedArrayPrototype::method_get_byteLength(const BuiltinFunction *, Scope &scope, CallData *callData) { - Scope scope(ctx); - Scoped<TypedArray> v(scope, ctx->thisObject()); + Scoped<TypedArray> v(scope, callData->thisObject); if (!v) - return scope.engine->throwTypeError(); + THROW_TYPE_ERROR(); - return Encode(v->d()->byteLength); + scope.result = Encode(v->d()->byteLength); } -ReturnedValue TypedArrayPrototype::method_get_byteOffset(CallContext *ctx) +void TypedArrayPrototype::method_get_byteOffset(const BuiltinFunction *, Scope &scope, CallData *callData) { - Scope scope(ctx); - Scoped<TypedArray> v(scope, ctx->thisObject()); + Scoped<TypedArray> v(scope, callData->thisObject); if (!v) - return scope.engine->throwTypeError(); + THROW_TYPE_ERROR(); - return Encode(v->d()->byteOffset); + scope.result = Encode(v->d()->byteOffset); } -ReturnedValue TypedArrayPrototype::method_get_length(CallContext *ctx) +void TypedArrayPrototype::method_get_length(const BuiltinFunction *, Scope &scope, CallData *callData) { - Scope scope(ctx); - Scoped<TypedArray> v(scope, ctx->thisObject()); + Scoped<TypedArray> v(scope, callData->thisObject); if (!v) - return scope.engine->throwTypeError(); + THROW_TYPE_ERROR(); - return Encode(v->d()->byteLength/v->d()->type->bytesPerElement); + scope.result = Encode(v->d()->byteLength/v->d()->type->bytesPerElement); } -ReturnedValue TypedArrayPrototype::method_set(CallContext *ctx) +void TypedArrayPrototype::method_set(const BuiltinFunction *, Scope &scope, CallData *callData) { - Scope scope(ctx); - Scoped<TypedArray> a(scope, ctx->thisObject()); + Scoped<TypedArray> a(scope, callData->thisObject); if (!a) - return scope.engine->throwTypeError(); + THROW_TYPE_ERROR(); Scoped<ArrayBuffer> buffer(scope, a->d()->buffer); if (!buffer) scope.engine->throwTypeError(); - double doffset = ctx->argc() >= 2 ? ctx->args()[1].toInteger() : 0; + double doffset = callData->argc >= 2 ? callData->args[1].toInteger() : 0; if (scope.engine->hasException) - return Encode::undefined(); + RETURN_UNDEFINED(); if (doffset < 0 || doffset >= UINT_MAX) - return scope.engine->throwRangeError(QStringLiteral("TypedArray.set: out of range")); + RETURN_RESULT(scope.engine->throwRangeError(QStringLiteral("TypedArray.set: out of range"))); uint offset = (uint)doffset; uint elementSize = a->d()->type->bytesPerElement; - Scoped<TypedArray> srcTypedArray(scope, ctx->args()[0]); + Scoped<TypedArray> srcTypedArray(scope, callData->args[0]); if (!srcTypedArray) { // src is a regular object - ScopedObject o(scope, ctx->args()[0].toObject(scope.engine)); + ScopedObject o(scope, callData->args[0].toObject(scope.engine)); if (scope.engine->hasException || !o) - return scope.engine->throwTypeError(); + THROW_TYPE_ERROR(); double len = ScopedValue(scope, o->get(scope.engine->id_length()))->toNumber(); uint l = (uint)len; if (scope.engine->hasException || l != len) - return scope.engine->throwTypeError(); + THROW_TYPE_ERROR(); if (offset + l > a->length()) - return scope.engine->throwRangeError(QStringLiteral("TypedArray.set: out of range")); + RETURN_RESULT(scope.engine->throwRangeError(QStringLiteral("TypedArray.set: out of range"))); uint idx = 0; char *b = buffer->d()->data->data() + a->d()->byteOffset + offset*elementSize; @@ -519,28 +514,28 @@ ReturnedValue TypedArrayPrototype::method_set(CallContext *ctx) val = o->getIndexed(idx); a->d()->type->write(scope.engine, b, 0, val); if (scope.engine->hasException) - return Encode::undefined(); + RETURN_UNDEFINED(); ++idx; b += elementSize; } - return Encode::undefined(); + RETURN_UNDEFINED(); } // src is a typed array Scoped<ArrayBuffer> srcBuffer(scope, srcTypedArray->d()->buffer); if (!srcBuffer) - return scope.engine->throwTypeError(); + THROW_TYPE_ERROR(); uint l = srcTypedArray->length(); if (offset + l > a->length()) - return scope.engine->throwRangeError(QStringLiteral("TypedArray.set: out of range")); + RETURN_RESULT(scope.engine->throwRangeError(QStringLiteral("TypedArray.set: out of range"))); char *dest = buffer->d()->data->data() + a->d()->byteOffset + offset*elementSize; const char *src = srcBuffer->d()->data->data() + srcTypedArray->d()->byteOffset; if (srcTypedArray->d()->type == a->d()->type) { // same type of typed arrays, use memmove (as srcbuffer and buffer could be the same) memmove(dest, src, srcTypedArray->d()->byteLength); - return Encode::undefined(); + RETURN_UNDEFINED(); } char *srcCopy = 0; @@ -564,28 +559,27 @@ ReturnedValue TypedArrayPrototype::method_set(CallContext *ctx) if (srcCopy) delete [] srcCopy; - return Encode::undefined(); + RETURN_UNDEFINED(); } -ReturnedValue TypedArrayPrototype::method_subarray(CallContext *ctx) +void TypedArrayPrototype::method_subarray(const BuiltinFunction *, Scope &scope, CallData *callData) { - Scope scope(ctx); - Scoped<TypedArray> a(scope, ctx->thisObject()); + Scoped<TypedArray> a(scope, callData->thisObject); if (!a) - return scope.engine->throwTypeError(); + THROW_TYPE_ERROR(); Scoped<ArrayBuffer> buffer(scope, a->d()->buffer); if (!buffer) - return scope.engine->throwTypeError(); + THROW_TYPE_ERROR(); int len = a->length(); - double b = ctx->argc() > 0 ? ctx->args()[0].toInteger() : 0; + double b = callData->argc > 0 ? callData->args[0].toInteger() : 0; if (b < 0) b = len + b; uint begin = (uint)qBound(0., b, (double)len); - double e = ctx->argc() < 2 || ctx->args()[1].isUndefined() ? len : ctx->args()[1].toInteger(); + double e = callData->argc < 2 || callData->args[1].isUndefined() ? len : callData->args[1].toInteger(); if (e < 0) e = len + e; uint end = (uint)qBound(0., e, (double)len); @@ -593,18 +587,17 @@ ReturnedValue TypedArrayPrototype::method_subarray(CallContext *ctx) end = begin; if (scope.engine->hasException) - return Encode::undefined(); + RETURN_UNDEFINED(); int newLen = end - begin; ScopedFunctionObject constructor(scope, a->get(scope.engine->id_constructor())); if (!constructor) - return scope.engine->throwTypeError(); - - ScopedCallData callData(scope, 3); - callData->args[0] = buffer; - callData->args[1] = Encode(a->d()->byteOffset + begin*a->d()->type->bytesPerElement); - callData->args[2] = Encode(newLen); - constructor->construct(scope, callData); - return scope.result.asReturnedValue(); + THROW_TYPE_ERROR(); + + ScopedCallData cData(scope, 3); + cData->args[0] = buffer; + cData->args[1] = Encode(a->d()->byteOffset + begin*a->d()->type->bytesPerElement); + cData->args[2] = Encode(newLen); + constructor->construct(scope, cData); } diff --git a/src/qml/jsruntime/qv4typedarray_p.h b/src/qml/jsruntime/qv4typedarray_p.h index 0112d2e4a1..eefed2db4b 100644 --- a/src/qml/jsruntime/qv4typedarray_p.h +++ b/src/qml/jsruntime/qv4typedarray_p.h @@ -151,13 +151,13 @@ struct TypedArrayPrototype : Object void init(ExecutionEngine *engine, TypedArrayCtor *ctor); - static ReturnedValue method_get_buffer(CallContext *ctx); - static ReturnedValue method_get_byteLength(CallContext *ctx); - static ReturnedValue method_get_byteOffset(CallContext *ctx); - static ReturnedValue method_get_length(CallContext *ctx); + static void method_get_buffer(const BuiltinFunction *, Scope &scope, CallData *callData); + static void method_get_byteLength(const BuiltinFunction *, Scope &scope, CallData *callData); + static void method_get_byteOffset(const BuiltinFunction *, Scope &scope, CallData *callData); + static void method_get_length(const BuiltinFunction *, Scope &scope, CallData *callData); - static ReturnedValue method_set(CallContext *ctx); - static ReturnedValue method_subarray(CallContext *ctx); + static void method_set(const BuiltinFunction *, Scope &scope, CallData *callData); + static void method_subarray(const BuiltinFunction *, Scope &scope, CallData *callData); }; inline void diff --git a/src/qml/jsruntime/qv4value_p.h b/src/qml/jsruntime/qv4value_p.h index 816b8fb11b..64f0f3a86f 100644 --- a/src/qml/jsruntime/qv4value_p.h +++ b/src/qml/jsruntime/qv4value_p.h @@ -544,7 +544,7 @@ inline bool Value::asArrayIndex(uint &idx) const } double d = doubleValue(); idx = (uint)d; - return (idx == d); + return (idx == d && idx != UINT_MAX); } #endif diff --git a/src/qml/jsruntime/qv4variantobject.cpp b/src/qml/jsruntime/qv4variantobject.cpp index 455a7ccb65..5cab4c5386 100644 --- a/src/qml/jsruntime/qv4variantobject.cpp +++ b/src/qml/jsruntime/qv4variantobject.cpp @@ -113,67 +113,68 @@ void VariantPrototype::init() defineDefaultProperty(engine()->id_toString(), method_toString, 0); } -QV4::ReturnedValue VariantPrototype::method_preserve(CallContext *ctx) +void VariantPrototype::method_preserve(const BuiltinFunction *, Scope &scope, CallData *callData) { - Scope scope(ctx); - Scoped<VariantObject> o(scope, ctx->thisObject().as<QV4::VariantObject>()); + Scoped<VariantObject> o(scope, callData->thisObject.as<QV4::VariantObject>()); if (o && o->d()->isScarce()) o->d()->addVmePropertyReference(); - return Encode::undefined(); + RETURN_UNDEFINED(); } -QV4::ReturnedValue VariantPrototype::method_destroy(CallContext *ctx) +void VariantPrototype::method_destroy(const BuiltinFunction *, Scope &scope, CallData *callData) { - Scope scope(ctx); - Scoped<VariantObject> o(scope, ctx->thisObject().as<QV4::VariantObject>()); + Scoped<VariantObject> o(scope, callData->thisObject.as<QV4::VariantObject>()); if (o) { if (o->d()->isScarce()) o->d()->addVmePropertyReference(); o->d()->data() = QVariant(); } - return Encode::undefined(); + RETURN_UNDEFINED(); } -QV4::ReturnedValue VariantPrototype::method_toString(CallContext *ctx) +void VariantPrototype::method_toString(const BuiltinFunction *, Scope &scope, CallData *callData) { - Scope scope(ctx); - Scoped<VariantObject> o(scope, ctx->thisObject().as<QV4::VariantObject>()); + Scoped<VariantObject> o(scope, callData->thisObject.as<QV4::VariantObject>()); if (!o) - return Encode::undefined(); + RETURN_UNDEFINED(); QString result = o->d()->data().toString(); if (result.isEmpty() && !o->d()->data().canConvert(QVariant::String)) { result = QLatin1String("QVariant(") + QLatin1String(o->d()->data().typeName()) + QLatin1Char(')'); } - return Encode(ctx->d()->engine->newString(result)); + scope.result = scope.engine->newString(result); } -QV4::ReturnedValue VariantPrototype::method_valueOf(CallContext *ctx) +void VariantPrototype::method_valueOf(const BuiltinFunction *, Scope &scope, CallData *callData) { - Scope scope(ctx); - Scoped<VariantObject> o(scope, ctx->thisObject().as<QV4::VariantObject>()); + Scoped<VariantObject> o(scope, callData->thisObject.as<QV4::VariantObject>()); if (o) { QVariant v = o->d()->data(); switch (v.type()) { case QVariant::Invalid: - return Encode::undefined(); + scope.result = Encode::undefined(); + return; case QVariant::String: - return Encode(ctx->d()->engine->newString(v.toString())); + scope.result = scope.engine->newString(v.toString()); + return; case QVariant::Int: - return Encode(v.toInt()); + scope.result = Encode(v.toInt()); + return; case QVariant::Double: case QVariant::UInt: - return Encode(v.toDouble()); + scope.result = Encode(v.toDouble()); + return; case QVariant::Bool: - return Encode(v.toBool()); + scope.result = Encode(v.toBool()); + return; default: if (QMetaType::typeFlags(v.userType()) & QMetaType::IsEnumeration) - return Encode(v.toInt()); + RETURN_RESULT(Encode(v.toInt())); break; } } - return ctx->thisObject().asReturnedValue(); + scope.result = callData->thisObject; } QT_END_NAMESPACE diff --git a/src/qml/jsruntime/qv4variantobject_p.h b/src/qml/jsruntime/qv4variantobject_p.h index 9a04069c12..ef51b6632d 100644 --- a/src/qml/jsruntime/qv4variantobject_p.h +++ b/src/qml/jsruntime/qv4variantobject_p.h @@ -107,10 +107,10 @@ struct VariantPrototype : VariantObject public: void init(); - static ReturnedValue method_preserve(CallContext *ctx); - static ReturnedValue method_destroy(CallContext *ctx); - static ReturnedValue method_toString(CallContext *ctx); - static ReturnedValue method_valueOf(CallContext *ctx); + static void method_preserve(const BuiltinFunction *, Scope &scope, CallData *callData); + static void method_destroy(const BuiltinFunction *, Scope &scope, CallData *callData); + static void method_toString(const BuiltinFunction *, Scope &scope, CallData *callData); + static void method_valueOf(const BuiltinFunction *, Scope &scope, CallData *callData); }; } diff --git a/src/qml/jsruntime/qv4vme_moth.cpp b/src/qml/jsruntime/qv4vme_moth.cpp index 622359a7d9..b9183313cd 100644 --- a/src/qml/jsruntime/qv4vme_moth.cpp +++ b/src/qml/jsruntime/qv4vme_moth.cpp @@ -347,6 +347,10 @@ Param traceParam(const Param ¶m) goto catchException; \ VALUE(param) = tmp; \ } +// qv4scopedvalue_p.h also defines a CHECK_EXCEPTION macro +#ifdef CHECK_EXCEPTION +#undef CHECK_EXCEPTION +#endif #define CHECK_EXCEPTION \ if (engine->hasException) \ goto catchException diff --git a/src/qml/memory/memory.pri b/src/qml/memory/memory.pri index 04b7566ccc..38fadbf23f 100644 --- a/src/qml/memory/memory.pri +++ b/src/qml/memory/memory.pri @@ -6,8 +6,8 @@ SOURCES += \ $$PWD/qv4mm.cpp \ HEADERS += \ - $$PWD/qv4mm_p.h - + $$PWD/qv4mm_p.h \ + $$PWD/qv4mmdefs_p.h } HEADERS += \ diff --git a/src/qml/memory/qv4heap_p.h b/src/qml/memory/qv4heap_p.h index 5a3797f397..8285ef4de7 100644 --- a/src/qml/memory/qv4heap_p.h +++ b/src/qml/memory/qv4heap_p.h @@ -52,6 +52,7 @@ #include <QtCore/QString> #include <private/qv4global_p.h> +#include <private/qv4mmdefs_p.h> #include <QSharedPointer> // To check if Heap::Base::init is called (meaning, all subclasses did their init and called their @@ -90,43 +91,31 @@ namespace Heap { struct Q_QML_EXPORT Base { void *operator new(size_t) = delete; - quintptr mm_data; // vtable and markbit + const VTable *vt; inline ReturnedValue asReturnedValue() const; inline void mark(QV4::ExecutionEngine *engine); - enum { - MarkBit = 0x1, - NotInUse = 0x2, - PointerMask = ~0x3 - }; - - void setVtable(const VTable *v) { - Q_ASSERT(!(mm_data & MarkBit)); - mm_data = reinterpret_cast<quintptr>(v); - } - VTable *vtable() const { - return reinterpret_cast<VTable *>(mm_data & PointerMask); - } + void setVtable(const VTable *v) { vt = v; } + const VTable *vtable() const { return vt; } inline bool isMarked() const { - return mm_data & MarkBit; + const HeapItem *h = reinterpret_cast<const HeapItem *>(this); + Chunk *c = h->chunk(); + Q_ASSERT(!Chunk::testBit(c->extendsBitmap, h - c->realBase())); + return Chunk::testBit(c->blackBitmap, h - c->realBase()); } inline void setMarkBit() { - mm_data |= MarkBit; - } - inline void clearMarkBit() { - mm_data &= ~MarkBit; + const HeapItem *h = reinterpret_cast<const HeapItem *>(this); + Chunk *c = h->chunk(); + Q_ASSERT(!Chunk::testBit(c->extendsBitmap, h - c->realBase())); + return Chunk::setBit(c->blackBitmap, h - c->realBase()); } inline bool inUse() const { - return !(mm_data & NotInUse); - } - - Base *nextFree() { - return reinterpret_cast<Base *>(mm_data & PointerMask); - } - void setNextFree(Base *m) { - mm_data = (reinterpret_cast<quintptr>(m) | NotInUse); + const HeapItem *h = reinterpret_cast<const HeapItem *>(this); + Chunk *c = h->chunk(); + Q_ASSERT(!Chunk::testBit(c->extendsBitmap, h - c->realBase())); + return Chunk::testBit(c->objectBitmap, h - c->realBase()); } void *operator new(size_t, Managed *m) { return m; } diff --git a/src/qml/memory/qv4mm.cpp b/src/qml/memory/qv4mm.cpp index 606d3ec162..6330ef6038 100644 --- a/src/qml/memory/qv4mm.cpp +++ b/src/qml/memory/qv4mm.cpp @@ -42,8 +42,12 @@ #include "qv4objectproto_p.h" #include "qv4mm_p.h" #include "qv4qobjectwrapper_p.h" +#include <QtCore/qalgorithms.h> +#include <QtCore/private/qnumeric_p.h> #include <qqmlengine.h> +#include "PageReservation.h" #include "PageAllocation.h" +#include "PageAllocationAligned.h" #include "StdLibExtras.h" #include <QElapsedTimer> @@ -56,6 +60,14 @@ #include "qv4alloca_p.h" #include "qv4profiling_p.h" +#define MM_DEBUG 0 + +#if MM_DEBUG +#define DEBUG qDebug() << "MM:" +#else +#define DEBUG if (1) ; else qDebug() << "MM:" +#endif + #ifdef V4_USE_VALGRIND #include <valgrind/valgrind.h> #include <valgrind/memcheck.h> @@ -79,319 +91,616 @@ using namespace WTF; QT_BEGIN_NAMESPACE -static uint maxShiftValue() -{ - static uint result = 0; - if (!result) { - result = 6; - if (Q_UNLIKELY(qEnvironmentVariableIsSet(QV4_MM_MAXBLOCK_SHIFT))) { - bool ok; - const uint overrideValue = qgetenv(QV4_MM_MAXBLOCK_SHIFT).toUInt(&ok); - if (ok && overrideValue <= 11 && overrideValue > 0) - result = overrideValue; +namespace QV4 { + +enum { + MinSlotsGCLimit = QV4::Chunk::AvailableSlots*16, + GCOverallocation = 200 /* Max overallocation by the GC in % */ +}; + +struct MemorySegment { + enum { + NumChunks = 8*sizeof(quint64), + SegmentSize = NumChunks*Chunk::ChunkSize, + }; + + MemorySegment(size_t size) + { + size += Chunk::ChunkSize; // make sure we can get enough 64k aligment memory + if (size < SegmentSize) + size = SegmentSize; + + pageReservation = PageReservation::reserve(size, OSAllocator::JSGCHeapPages); + base = reinterpret_cast<Chunk *>((reinterpret_cast<quintptr>(pageReservation.base()) + Chunk::ChunkSize - 1) & ~(Chunk::ChunkSize - 1)); + nChunks = NumChunks; + if (base != pageReservation.base()) + --nChunks; + } + MemorySegment(MemorySegment &&other) { + qSwap(pageReservation, other.pageReservation); + qSwap(base, other.base); + qSwap(nChunks, other.nChunks); + qSwap(allocatedMap, other.allocatedMap); + } + + ~MemorySegment() { + if (base) + pageReservation.deallocate(); + } + + void setBit(size_t index) { + Q_ASSERT(index < nChunks); + quint64 bit = static_cast<quint64>(1) << index; +// qDebug() << " setBit" << hex << index << (index & (Bits - 1)) << bit; + allocatedMap |= bit; + } + void clearBit(size_t index) { + Q_ASSERT(index < nChunks); + quint64 bit = static_cast<quint64>(1) << index; +// qDebug() << " setBit" << hex << index << (index & (Bits - 1)) << bit; + allocatedMap &= ~bit; + } + bool testBit(size_t index) const { + Q_ASSERT(index < nChunks); + quint64 bit = static_cast<quint64>(1) << index; + return (allocatedMap & bit); + } + + Chunk *allocate(size_t size); + void free(Chunk *chunk, size_t size) { + DEBUG << "freeing chunk" << chunk; + size_t index = static_cast<size_t>(chunk - base); + size_t end = index + (size - 1)/Chunk::ChunkSize + 1; + while (index < end) { + Q_ASSERT(testBit(index)); + clearBit(index); + ++index; } + + size_t pageSize = WTF::pageSize(); + size = (size + pageSize - 1) & ~(pageSize - 1); + pageReservation.decommit(chunk, size); + } + + bool contains(Chunk *c) const { + return c >= base && c < base + nChunks; } - return result; -} -static std::size_t maxChunkSizeValue() + PageReservation pageReservation; + Chunk *base = 0; + quint64 allocatedMap = 0; + uint nChunks = 0; +}; + +Chunk *MemorySegment::allocate(size_t size) { - static std::size_t result = 0; - if (!result) { - result = 32 * 1024; - if (Q_UNLIKELY(qEnvironmentVariableIsSet(QV4_MM_MAX_CHUNK_SIZE))) { - bool ok; - const std::size_t overrideValue = qgetenv(QV4_MM_MAX_CHUNK_SIZE).toUInt(&ok); - if (ok) - result = overrideValue; + size_t requiredChunks = (size + sizeof(Chunk) - 1)/sizeof(Chunk); + uint sequence = 0; + Chunk *candidate = 0; + for (uint i = 0; i < nChunks; ++i) { + if (!testBit(i)) { + if (!candidate) + candidate = base + i; + ++sequence; + } else { + candidate = 0; + sequence = 0; + } + if (sequence == requiredChunks) { + pageReservation.commit(candidate, size); + for (uint i = 0; i < requiredChunks; ++i) + setBit(candidate - base + i); + DEBUG << "allocated chunk " << candidate << hex << size; + return candidate; } } - return result; + return 0; } -using namespace QV4; - -struct MemoryManager::Data -{ - const size_t pageSize; - - struct ChunkHeader { - Heap::Base freeItems; - ChunkHeader *nextNonFull; - char *itemStart; - char *itemEnd; - unsigned itemSize; - }; +struct ChunkAllocator { + ChunkAllocator() {} - ExecutionEngine *engine; + size_t requiredChunkSize(size_t size) { + size += Chunk::HeaderSize; // space required for the Chunk header + size_t pageSize = WTF::pageSize(); + size = (size + pageSize - 1) & ~(pageSize - 1); // align to page sizes + if (size < Chunk::ChunkSize) + size = Chunk::ChunkSize; + return size; + } - std::size_t maxChunkSize; - std::vector<PageAllocation> heapChunks; - std::size_t unmanagedHeapSize; // the amount of bytes of heap that is not managed by the memory manager, but which is held onto by managed items. - std::size_t unmanagedHeapSizeGCLimit; + Chunk *allocate(size_t size = 0); + void free(Chunk *chunk, size_t size = 0); - struct LargeItem { - LargeItem *next; - size_t size; - void *data; + std::vector<MemorySegment> memorySegments; +}; - Heap::Base *heapObject() { - return reinterpret_cast<Heap::Base *>(&data); +Chunk *ChunkAllocator::allocate(size_t size) +{ + size = requiredChunkSize(size); + for (auto &m : memorySegments) { + if (~m.allocatedMap) { + Chunk *c = m.allocate(size); + if (c) + return c; } - }; + } - LargeItem *largeItems; - std::size_t totalLargeItemsAllocated; + // allocate a new segment + memorySegments.push_back(MemorySegment(size)); + Chunk *c = memorySegments.back().allocate(size); + Q_ASSERT(c); + return c; +} - enum { MaxItemSize = 512 }; - ChunkHeader *nonFullChunks[MaxItemSize/16]; - uint nChunks[MaxItemSize/16]; - uint availableItems[MaxItemSize/16]; - uint allocCount[MaxItemSize/16]; - int totalItems; - int totalAlloc; - uint maxShift; +void ChunkAllocator::free(Chunk *chunk, size_t size) +{ + size = requiredChunkSize(size); + for (auto &m : memorySegments) { + if (m.contains(chunk)) { + m.free(chunk, size); + return; + } + } + Q_ASSERT(false); +} - bool gcBlocked; - bool aggressiveGC; - bool gcStats; - bool unused; // suppress padding warning - // statistics: -#ifdef DETAILED_MM_STATS - QVector<unsigned> allocSizeCounters; -#endif // DETAILED_MM_STATS +void Chunk::sweep() +{ + // DEBUG << "sweeping chunk" << this << (*freeList); + HeapItem *o = realBase(); + for (uint i = 0; i < Chunk::EntriesInBitmap; ++i) { + Q_ASSERT((grayBitmap[i] | blackBitmap[i]) == blackBitmap[i]); // check that we don't have gray only objects + quintptr toFree = objectBitmap[i] ^ blackBitmap[i]; + Q_ASSERT((toFree & objectBitmap[i]) == toFree); // check all black objects are marked as being used + quintptr e = extendsBitmap[i]; + // DEBUG << hex << " index=" << i << toFree; + while (toFree) { + uint index = qCountTrailingZeroBits(toFree); + quintptr bit = (static_cast<quintptr>(1) << index); + + toFree ^= bit; // mask out freed slot + // DEBUG << " index" << hex << index << toFree; + + // remove all extends slots that have been freed + // this is a bit of bit trickery. + quintptr mask = (bit << 1) - 1; // create a mask of 1's to the right of and up to the current bit + quintptr objmask = e | mask; // or'ing mask with e gives all ones until the end of the current object + quintptr result = objmask + 1; + Q_ASSERT(qCountTrailingZeroBits(result) - index != 0); // ensure we freed something + result |= mask; // ensure we don't clear stuff to the right of the current object + e &= result; + + HeapItem *itemToFree = o + index; + Heap::Base *b = *itemToFree; + if (b->vtable()->destroy) { + b->vtable()->destroy(b); + b->_checkIsDestroyed(); + } + } + objectBitmap[i] = blackBitmap[i]; + blackBitmap[i] = 0; + extendsBitmap[i] = e; + o += Chunk::Bits; + } + // DEBUG << "swept chunk" << this << "freed" << slotsFreed << "slots."; +} - Data() - : pageSize(WTF::pageSize()) - , engine(0) - , maxChunkSize(maxChunkSizeValue()) - , unmanagedHeapSize(0) - , unmanagedHeapSizeGCLimit(MIN_UNMANAGED_HEAPSIZE_GC_LIMIT) - , largeItems(0) - , totalLargeItemsAllocated(0) - , totalItems(0) - , totalAlloc(0) - , maxShift(maxShiftValue()) - , gcBlocked(false) - , aggressiveGC(!qEnvironmentVariableIsEmpty("QV4_MM_AGGRESSIVE_GC")) - , gcStats(!qEnvironmentVariableIsEmpty(QV4_MM_STATS)) - { - memset(nonFullChunks, 0, sizeof(nonFullChunks)); - memset(nChunks, 0, sizeof(nChunks)); - memset(availableItems, 0, sizeof(availableItems)); - memset(allocCount, 0, sizeof(allocCount)); +void Chunk::freeAll() +{ + // DEBUG << "sweeping chunk" << this << (*freeList); + HeapItem *o = realBase(); + for (uint i = 0; i < Chunk::EntriesInBitmap; ++i) { + quintptr toFree = objectBitmap[i]; + quintptr e = extendsBitmap[i]; + // DEBUG << hex << " index=" << i << toFree; + while (toFree) { + uint index = qCountTrailingZeroBits(toFree); + quintptr bit = (static_cast<quintptr>(1) << index); + + toFree ^= bit; // mask out freed slot + // DEBUG << " index" << hex << index << toFree; + + // remove all extends slots that have been freed + // this is a bit of bit trickery. + quintptr mask = (bit << 1) - 1; // create a mask of 1's to the right of and up to the current bit + quintptr objmask = e | mask; // or'ing mask with e gives all ones until the end of the current object + quintptr result = objmask + 1; + Q_ASSERT(qCountTrailingZeroBits(result) - index != 0); // ensure we freed something + result |= mask; // ensure we don't clear stuff to the right of the current object + e &= result; + + HeapItem *itemToFree = o + index; + Heap::Base *b = *itemToFree; + if (b->vtable()->destroy) { + b->vtable()->destroy(b); + b->_checkIsDestroyed(); + } + } + objectBitmap[i] = 0; + blackBitmap[i] = 0; + extendsBitmap[i] = e; + o += Chunk::Bits; } + // DEBUG << "swept chunk" << this << "freed" << slotsFreed << "slots."; +} - ~Data() - { - for (std::vector<PageAllocation>::iterator i = heapChunks.begin(), ei = heapChunks.end(); i != ei; ++i) { - Q_V4_PROFILE_DEALLOC(engine, i->size(), Profiling::HeapPage); - i->deallocate(); +void Chunk::sortIntoBins(HeapItem **bins, uint nBins) +{ + HeapItem *base = realBase(); +#if QT_POINTER_SIZE == 8 + const int start = 0; +#else + const int start = 1; +#endif + for (int i = start; i < EntriesInBitmap; ++i) { + quintptr usedSlots = (objectBitmap[i]|extendsBitmap[i]); +#if QT_POINTER_SIZE == 8 + if (!i) + usedSlots |= (static_cast<quintptr>(1) << (HeaderSize/SlotSize)) - 1; +#endif + uint index = qCountTrailingZeroBits(usedSlots + 1); + if (index == Bits) + continue; + uint freeStart = i*Bits + index; + usedSlots &= ~((static_cast<quintptr>(1) << index) - 1); + while (i < EntriesInBitmap && !usedSlots) { + ++i; + usedSlots = (objectBitmap[i]|extendsBitmap[i]); } + if (i == EntriesInBitmap) + usedSlots = 1; + HeapItem *freeItem = base + freeStart; + + uint freeEnd = i*Bits + qCountTrailingZeroBits(usedSlots); + uint nSlots = freeEnd - freeStart; + Q_ASSERT(freeEnd > freeStart && freeEnd <= NumSlots); + freeItem->freeData.availableSlots = nSlots; + uint bin = qMin(nBins - 1, nSlots); + freeItem->freeData.next = bins[bin]; + bins[bin] = freeItem; + // DEBUG << "binnig item" << freeItem << nSlots << bin << freeItem->freeData.availableSlots; } -}; +} -namespace { -bool sweepChunk(MemoryManager::Data::ChunkHeader *header, uint *itemsInUse, ExecutionEngine *engine, std::size_t *unmanagedHeapSize) +template<typename T> +StackAllocator<T>::StackAllocator(ChunkAllocator *chunkAlloc) + : chunkAllocator(chunkAlloc) { - Q_ASSERT(unmanagedHeapSize); + chunks.push_back(chunkAllocator->allocate()); + firstInChunk = chunks.back()->first(); + nextFree = firstInChunk; + lastInChunk = firstInChunk + (Chunk::AvailableSlots - 1)/requiredSlots*requiredSlots; +} - bool isEmpty = true; - Heap::Base *tail = &header->freeItems; -// qDebug("chunkStart @ %p, size=%x, pos=%x", header->itemStart, header->itemSize, header->itemSize>>4); -#ifdef V4_USE_VALGRIND - VALGRIND_DISABLE_ERROR_REPORTING; -#endif - for (char *item = header->itemStart; item <= header->itemEnd; item += header->itemSize) { - Heap::Base *m = reinterpret_cast<Heap::Base *>(item); -// qDebug("chunk @ %p, in use: %s, mark bit: %s", -// item, (m->inUse() ? "yes" : "no"), (m->isMarked() ? "true" : "false")); - - Q_ASSERT(qintptr(item) % 16 == 0); - - if (m->isMarked()) { - Q_ASSERT(m->inUse()); - m->clearMarkBit(); - isEmpty = false; - ++(*itemsInUse); - } else { - if (m->inUse()) { -// qDebug() << "-- collecting it." << m << tail << m->nextFree(); -#ifdef V4_USE_VALGRIND - VALGRIND_ENABLE_ERROR_REPORTING; -#endif - if (std::size_t(header->itemSize) == MemoryManager::align(sizeof(Heap::String)) && m->vtable()->isString) { - std::size_t heapBytes = static_cast<Heap::String *>(m)->retainedTextSize(); - Q_ASSERT(*unmanagedHeapSize >= heapBytes); -// qDebug() << "-- it's a string holding on to" << heapBytes << "bytes"; - *unmanagedHeapSize -= heapBytes; - } +template<typename T> +void StackAllocator<T>::freeAll() +{ + for (auto c : chunks) + chunkAllocator->free(c); +} - if (m->vtable()->destroy) { - m->vtable()->destroy(m); - m->_checkIsDestroyed(); - } +template<typename T> +void StackAllocator<T>::nextChunk() { + Q_ASSERT(nextFree == lastInChunk); + ++currentChunk; + if (currentChunk >= chunks.size()) { + Chunk *newChunk = chunkAllocator->allocate(); + chunks.push_back(newChunk); + } + firstInChunk = chunks.at(currentChunk)->first(); + nextFree = firstInChunk; + lastInChunk = firstInChunk + (Chunk::AvailableSlots - 1)/requiredSlots*requiredSlots; +} - memset(m, 0, sizeof(Heap::Base)); -#ifdef V4_USE_VALGRIND - VALGRIND_DISABLE_ERROR_REPORTING; - VALGRIND_MEMPOOL_FREE(engine->memoryManager, m); +template<typename T> +void QV4::StackAllocator<T>::prevChunk() { + Q_ASSERT(nextFree == firstInChunk); + Q_ASSERT(chunks.at(currentChunk) == nextFree->chunk()); + Q_ASSERT(currentChunk > 0); + --currentChunk; + firstInChunk = chunks.at(currentChunk)->first(); + lastInChunk = firstInChunk + (Chunk::AvailableSlots - 1)/requiredSlots*requiredSlots; + nextFree = lastInChunk; +} + +template struct StackAllocator<Heap::CallContext>; + + +HeapItem *BlockAllocator::allocate(size_t size, bool forceAllocation) { + Q_ASSERT((size % Chunk::SlotSize) == 0); + size_t slotsRequired = size >> Chunk::SlotSizeShift; +#if MM_DEBUG + ++allocations[bin]; #endif -#ifdef V4_USE_HEAPTRACK - heaptrack_report_free(m); + + HeapItem **last; + + HeapItem *m; + + if (slotsRequired < NumBins - 1) { + m = freeBins[slotsRequired]; + if (m) { + freeBins[slotsRequired] = m->freeData.next; + goto done; + } + } +#if 0 + for (uint b = bin + 1; b < NumBins - 1; ++b) { + if ((m = freeBins[b])) { + Q_ASSERT(binForSlots(m->freeData.availableSlots) == b); + freeBins[b] = m->freeData.next; + // DEBUG << "looking for empty bin" << bin << "size" << size << "found" << b; + uint remainingSlots = m->freeData.availableSlots - slotsRequired; + // DEBUG << "found free slots of size" << m->freeData.availableSlots << m << "remaining" << remainingSlots; + if (remainingSlots < 2) { + // avoid too much fragmentation and rather mark the memory as used + size += remainingSlots*Chunk::SlotSize; + goto done; + } + HeapItem *remainder = m + slotsRequired; + remainder->freeData.availableSlots = remainingSlots; + uint binForRemainder = binForSlots(remainingSlots); + remainder->freeData.next = freeBins[binForRemainder]; + freeBins[binForRemainder] = remainder; + goto done; + } + } #endif - Q_V4_PROFILE_DEALLOC(engine, header->itemSize, Profiling::SmallItem); - ++(*itemsInUse); + if (nFree >= slotsRequired) { + // use bump allocation + Q_ASSERT(nextFree); + m = nextFree; + nextFree += slotsRequired; + nFree -= slotsRequired; + goto done; + } + + // DEBUG << "No matching bin found for item" << size << bin; + // search last bin for a large enough item + last = &freeBins[NumBins - 1]; + while ((m = *last)) { + if (m->freeData.availableSlots >= slotsRequired) { + *last = m->freeData.next; // take it out of the list + + size_t remainingSlots = m->freeData.availableSlots - slotsRequired; + // DEBUG << "found large free slots of size" << m->freeData.availableSlots << m << "remaining" << remainingSlots; + if (remainingSlots < 2) { + // avoid too much fragmentation and rather mark the memory as used + size += remainingSlots*Chunk::SlotSize; + goto done; + } + HeapItem *remainder = m + slotsRequired; + if (remainingSlots >= 2*NumBins) { + if (nFree) { + size_t bin = binForSlots(nFree); + nextFree->freeData.next = freeBins[bin]; + nextFree->freeData.availableSlots = nFree; + freeBins[bin] = nextFree; + } + nextFree = remainder; + nFree = remainingSlots; + } else { + remainder->freeData.availableSlots = remainingSlots; + size_t binForRemainder = binForSlots(remainingSlots); + remainder->freeData.next = freeBins[binForRemainder]; + freeBins[binForRemainder] = remainder; } - // Relink all free blocks to rewrite references to any released chunk. - tail->setNextFree(m); - tail = m; + goto done; } + last = &m->freeData.next; } - tail->setNextFree(0); -#ifdef V4_USE_VALGRIND - VALGRIND_ENABLE_ERROR_REPORTING; + + if (!m) { + if (!forceAllocation) + return 0; + Chunk *newChunk = chunkAllocator->allocate(); + chunks.push_back(newChunk); + nextFree = newChunk->first(); + nFree = Chunk::AvailableSlots; + m = nextFree; + nextFree += slotsRequired; + nFree -= slotsRequired; + } + +done: + m->setAllocatedSlots(slotsRequired); + // DEBUG << " " << hex << m->chunk() << m->chunk()->objectBitmap[0] << m->chunk()->extendsBitmap[0] << (m - m->chunk()->realBase()); + return m; +} + +void BlockAllocator::sweep() +{ + nextFree = 0; + nFree = 0; + memset(freeBins, 0, sizeof(freeBins)); + +// qDebug() << "BlockAlloc: sweep"; + usedSlotsAfterLastSweep = 0; + for (auto c : chunks) { + c->sweep(); + c->sortIntoBins(freeBins, NumBins); +// qDebug() << "used slots in chunk" << c << ":" << c->nUsedSlots(); + usedSlotsAfterLastSweep += c->nUsedSlots(); + } +} + +void BlockAllocator::freeAll() +{ + for (auto c : chunks) { + c->freeAll(); + chunkAllocator->free(c); + } +} + +#if MM_DEBUG +void BlockAllocator::stats() { + DEBUG << "MM stats:"; + QString s; + for (int i = 0; i < 10; ++i) { + uint c = 0; + HeapItem *item = freeBins[i]; + while (item) { + ++c; + item = item->freeData.next; + } + s += QString::number(c) + QLatin1String(", "); + } + HeapItem *item = freeBins[NumBins - 1]; + uint c = 0; + while (item) { + ++c; + item = item->freeData.next; + } + s += QLatin1String("..., ") + QString::number(c); + DEBUG << "bins:" << s; + QString a; + for (int i = 0; i < 10; ++i) + a += QString::number(allocations[i]) + QLatin1String(", "); + a += QLatin1String("..., ") + QString::number(allocations[NumBins - 1]); + DEBUG << "allocs:" << a; + memset(allocations, 0, sizeof(allocations)); +} #endif - return isEmpty; + + +HeapItem *HugeItemAllocator::allocate(size_t size) { + Chunk *c = chunkAllocator->allocate(size); + chunks.push_back(HugeChunk{c, size}); + Chunk::setBit(c->objectBitmap, c->first() - c->realBase()); + return c->first(); +} + +static void freeHugeChunk(ChunkAllocator *chunkAllocator, const HugeItemAllocator::HugeChunk &c) +{ + HeapItem *itemToFree = c.chunk->first(); + Heap::Base *b = *itemToFree; + if (b->vtable()->destroy) { + b->vtable()->destroy(b); + b->_checkIsDestroyed(); + } + chunkAllocator->free(c.chunk, c.size); +} + +void HugeItemAllocator::sweep() { + auto isBlack = [this] (const HugeChunk &c) { + bool b = c.chunk->first()->isBlack(); + Chunk::clearBit(c.chunk->blackBitmap, c.chunk->first() - c.chunk->realBase()); + if (!b) + freeHugeChunk(chunkAllocator, c); + return !b; + }; + + auto newEnd = std::remove_if(chunks.begin(), chunks.end(), isBlack); + chunks.erase(newEnd, chunks.end()); +} + +void HugeItemAllocator::freeAll() +{ + for (auto &c : chunks) { + freeHugeChunk(chunkAllocator, c); + } } -} // namespace MemoryManager::MemoryManager(ExecutionEngine *engine) : engine(engine) - , m_d(new Data) + , chunkAllocator(new ChunkAllocator) + , stackAllocator(chunkAllocator) + , blockAllocator(chunkAllocator) + , hugeItemAllocator(chunkAllocator) , m_persistentValues(new PersistentValueStorage(engine)) , m_weakValues(new PersistentValueStorage(engine)) + , unmanagedHeapSizeGCLimit(MIN_UNMANAGED_HEAPSIZE_GC_LIMIT) + , aggressiveGC(!qEnvironmentVariableIsEmpty("QV4_MM_AGGRESSIVE_GC")) + , gcStats(!qEnvironmentVariableIsEmpty(QV4_MM_STATS)) { #ifdef V4_USE_VALGRIND VALGRIND_CREATE_MEMPOOL(this, 0, true); #endif - m_d->engine = engine; } -Heap::Base *MemoryManager::allocData(std::size_t size, std::size_t unmanagedSize) +Heap::Base *MemoryManager::allocString(std::size_t unmanagedSize) { - if (m_d->aggressiveGC) + if (aggressiveGC) runGC(); -#ifdef DETAILED_MM_STATS - willAllocate(size); -#endif // DETAILED_MM_STATS - Q_ASSERT(size >= 16); - Q_ASSERT(size % 16 == 0); - -// qDebug() << "unmanagedHeapSize:" << m_d->unmanagedHeapSize << "limit:" << m_d->unmanagedHeapSizeGCLimit << "unmanagedSize:" << unmanagedSize; - m_d->unmanagedHeapSize += unmanagedSize; + const size_t stringSize = align(sizeof(Heap::String)); + unmanagedHeapSize += unmanagedSize; bool didGCRun = false; - if (m_d->unmanagedHeapSize > m_d->unmanagedHeapSizeGCLimit) { + if (unmanagedHeapSize > unmanagedHeapSizeGCLimit) { runGC(); - if (3*m_d->unmanagedHeapSizeGCLimit <= 4*m_d->unmanagedHeapSize) + if (3*unmanagedHeapSizeGCLimit <= 4*unmanagedHeapSize) // more than 75% full, raise limit - m_d->unmanagedHeapSizeGCLimit = std::max(m_d->unmanagedHeapSizeGCLimit, m_d->unmanagedHeapSize) * 2; - else if (m_d->unmanagedHeapSize * 4 <= m_d->unmanagedHeapSizeGCLimit) + unmanagedHeapSizeGCLimit = std::max(unmanagedHeapSizeGCLimit, unmanagedHeapSize) * 2; + else if (unmanagedHeapSize * 4 <= unmanagedHeapSizeGCLimit) // less than 25% full, lower limit - m_d->unmanagedHeapSizeGCLimit = qMax(MIN_UNMANAGED_HEAPSIZE_GC_LIMIT, m_d->unmanagedHeapSizeGCLimit/2); + unmanagedHeapSizeGCLimit = qMax(MIN_UNMANAGED_HEAPSIZE_GC_LIMIT, unmanagedHeapSizeGCLimit/2); didGCRun = true; } - size_t pos = size >> 4; - - // doesn't fit into a small bucket - if (size >= MemoryManager::Data::MaxItemSize) { - if (!didGCRun && m_d->totalLargeItemsAllocated > 8 * 1024 * 1024) + HeapItem *m = blockAllocator.allocate(stringSize); + if (!m) { + if (!didGCRun && shouldRunGC()) runGC(); - - // we use malloc for this - const size_t totalSize = size + sizeof(MemoryManager::Data::LargeItem); - Q_V4_PROFILE_ALLOC(engine, totalSize, Profiling::LargeItem); - MemoryManager::Data::LargeItem *item = - static_cast<MemoryManager::Data::LargeItem *>(malloc(totalSize)); - memset(item, 0, totalSize); - item->next = m_d->largeItems; - item->size = size; - m_d->largeItems = item; - m_d->totalLargeItemsAllocated += size; - return item->heapObject(); + m = blockAllocator.allocate(stringSize, true); } - Heap::Base *m = 0; - Data::ChunkHeader *header = m_d->nonFullChunks[pos]; - if (header) { - m = header->freeItems.nextFree(); - goto found; - } + memset(m, 0, stringSize); + return *m; +} - // try to free up space, otherwise allocate - if (!didGCRun && m_d->allocCount[pos] > (m_d->availableItems[pos] >> 1) && m_d->totalAlloc > (m_d->totalItems >> 1) && !m_d->aggressiveGC) { +Heap::Base *MemoryManager::allocData(std::size_t size) +{ + if (aggressiveGC) runGC(); - header = m_d->nonFullChunks[pos]; - if (header) { - m = header->freeItems.nextFree(); - goto found; - } - } +#ifdef DETAILED_MM_STATS + willAllocate(size); +#endif // DETAILED_MM_STATS - // no free item available, allocate a new chunk - { - // allocate larger chunks at a time to avoid excessive GC, but cap at maximum chunk size (2MB by default) - uint shift = ++m_d->nChunks[pos]; - if (shift > m_d->maxShift) - shift = m_d->maxShift; - std::size_t allocSize = m_d->maxChunkSize*(size_t(1) << shift); - allocSize = roundUpToMultipleOf(m_d->pageSize, allocSize); - Q_V4_PROFILE_ALLOC(engine, allocSize, Profiling::HeapPage); - PageAllocation allocation = PageAllocation::allocate(allocSize, OSAllocator::JSGCHeapPages); - m_d->heapChunks.push_back(allocation); - - header = reinterpret_cast<Data::ChunkHeader *>(allocation.base()); - Q_ASSERT(size <= UINT_MAX); - header->itemSize = unsigned(size); - header->itemStart = reinterpret_cast<char *>(allocation.base()) + roundUpToMultipleOf(16, sizeof(Data::ChunkHeader)); - header->itemEnd = reinterpret_cast<char *>(allocation.base()) + allocation.size() - header->itemSize; - - header->nextNonFull = m_d->nonFullChunks[pos]; - m_d->nonFullChunks[pos] = header; - - Heap::Base *last = &header->freeItems; - for (char *item = header->itemStart; item <= header->itemEnd; item += header->itemSize) { - Heap::Base *o = reinterpret_cast<Heap::Base *>(item); - last->setNextFree(o); - last = o; + Q_ASSERT(size >= Chunk::SlotSize); + Q_ASSERT(size % Chunk::SlotSize == 0); - } - last->setNextFree(0); - m = header->freeItems.nextFree(); - Q_ASSERT(header->itemEnd >= header->itemStart); - const size_t increase = quintptr(header->itemEnd - header->itemStart) / header->itemSize; - m_d->availableItems[pos] += uint(increase); - m_d->totalItems += int(increase); -#ifdef V4_USE_VALGRIND - VALGRIND_MAKE_MEM_NOACCESS(allocation.base(), allocSize); - VALGRIND_MEMPOOL_ALLOC(this, header, sizeof(Data::ChunkHeader)); -#endif -#ifdef V4_USE_HEAPTRACK - heaptrack_report_alloc(header, sizeof(Data::ChunkHeader)); -#endif +// qDebug() << "unmanagedHeapSize:" << unmanagedHeapSize << "limit:" << unmanagedHeapSizeGCLimit << "unmanagedSize:" << unmanagedSize; + + if (size > Chunk::DataSize) + return *hugeItemAllocator.allocate(size); + + HeapItem *m = blockAllocator.allocate(size); + if (!m) { + if (shouldRunGC()) + runGC(); + m = blockAllocator.allocate(size, true); } - found: -#ifdef V4_USE_VALGRIND - VALGRIND_MEMPOOL_ALLOC(this, m, size); -#endif -#ifdef V4_USE_HEAPTRACK - heaptrack_report_alloc(m, size); -#endif - Q_V4_PROFILE_ALLOC(engine, size, Profiling::SmallItem); + memset(m, 0, size); + return *m; +} - ++m_d->allocCount[pos]; - ++m_d->totalAlloc; - header->freeItems.setNextFree(m->nextFree()); - if (!header->freeItems.nextFree()) - m_d->nonFullChunks[pos] = header->nextNonFull; - return m; +Heap::Object *MemoryManager::allocObjectWithMemberData(std::size_t size, uint nMembers) +{ + Heap::Object *o = static_cast<Heap::Object *>(allocData(size)); + + // ### Could optimize this and allocate both in one go through the block allocator + if (nMembers) { + std::size_t memberSize = align(sizeof(Heap::MemberData) + (nMembers - 1)*sizeof(Value)); +// qDebug() << "allocating member data for" << o << nMembers << memberSize; + Heap::Base *m; + if (memberSize > Chunk::DataSize) + m = *hugeItemAllocator.allocate(memberSize); + else + m = *blockAllocator.allocate(memberSize, true); + memset(m, 0, memberSize); + o->memberData = static_cast<Heap::MemberData *>(m); + o->memberData->setVtable(MemberData::staticVTable()); + o->memberData->size = static_cast<uint>((memberSize - sizeof(Heap::MemberData) + sizeof(Value))/sizeof(Value)); + o->memberData->init(); +// qDebug() << " got" << o->memberData << o->memberData->size; + } + return o; } static void drainMarkStack(QV4::ExecutionEngine *engine, Value *markBase) @@ -495,98 +804,34 @@ void MemoryManager::sweep(bool lastSweep) } } - bool *chunkIsEmpty = static_cast<bool *>(alloca(m_d->heapChunks.size() * sizeof(bool))); - uint itemsInUse[MemoryManager::Data::MaxItemSize/16]; - memset(itemsInUse, 0, sizeof(itemsInUse)); - memset(m_d->nonFullChunks, 0, sizeof(m_d->nonFullChunks)); - - for (size_t i = 0; i < m_d->heapChunks.size(); ++i) { - Data::ChunkHeader *header = reinterpret_cast<Data::ChunkHeader *>(m_d->heapChunks[i].base()); - chunkIsEmpty[i] = sweepChunk(header, &itemsInUse[header->itemSize >> 4], engine, &m_d->unmanagedHeapSize); - } - - std::vector<PageAllocation>::iterator chunkIter = m_d->heapChunks.begin(); - for (size_t i = 0; i < m_d->heapChunks.size(); ++i) { - Q_ASSERT(chunkIter != m_d->heapChunks.end()); - Data::ChunkHeader *header = reinterpret_cast<Data::ChunkHeader *>(chunkIter->base()); - const size_t pos = header->itemSize >> 4; - Q_ASSERT(header->itemEnd >= header->itemStart); - const size_t decrease = quintptr(header->itemEnd - header->itemStart) / header->itemSize; - - // Release that chunk if it could have been spared since the last GC run without any difference. - if (chunkIsEmpty[i] && m_d->availableItems[pos] - decrease >= itemsInUse[pos]) { - Q_V4_PROFILE_DEALLOC(engine, chunkIter->size(), Profiling::HeapPage); -#ifdef V4_USE_VALGRIND - VALGRIND_MEMPOOL_FREE(this, header); -#endif -#ifdef V4_USE_HEAPTRACK - heaptrack_report_free(header); -#endif - --m_d->nChunks[pos]; - m_d->availableItems[pos] -= uint(decrease); - m_d->totalItems -= int(decrease); - chunkIter->deallocate(); - chunkIter = m_d->heapChunks.erase(chunkIter); - continue; - } else if (header->freeItems.nextFree()) { - header->nextNonFull = m_d->nonFullChunks[pos]; - m_d->nonFullChunks[pos] = header; - } - ++chunkIter; - } - - Data::LargeItem *i = m_d->largeItems; - Data::LargeItem **last = &m_d->largeItems; - while (i) { - Heap::Base *m = i->heapObject(); - Q_ASSERT(m->inUse()); - if (m->isMarked()) { - m->clearMarkBit(); - last = &i->next; - i = i->next; - continue; - } - if (m->vtable()->destroy) - m->vtable()->destroy(m); - - *last = i->next; - Q_V4_PROFILE_DEALLOC(engine, i->size + sizeof(Data::LargeItem), Profiling::LargeItem); - free(i); - i = *last; - } - - // some execution contexts are allocated on the stack, make sure we clear their markBit as well - if (!lastSweep) { - QV4::ExecutionContext *ctx = engine->currentContext; - while (ctx) { - ctx->d()->clearMarkBit(); - ctx = engine->parentContext(ctx); - } - } + blockAllocator.sweep(); + hugeItemAllocator.sweep(); } -bool MemoryManager::isGCBlocked() const +bool MemoryManager::shouldRunGC() const { - return m_d->gcBlocked; + size_t total = blockAllocator.totalSlots(); + size_t usedSlots = blockAllocator.usedSlotsAfterLastSweep; + if (total > MinSlotsGCLimit && usedSlots * GCOverallocation < total * 100) + return true; + return false; } -void MemoryManager::setGCBlocked(bool blockGC) -{ - m_d->gcBlocked = blockGC; -} void MemoryManager::runGC() { - if (m_d->gcBlocked) { + if (gcBlocked) { // qDebug() << "Not running GC."; return; } - QScopedValueRollback<bool> gcBlocker(m_d->gcBlocked, true); + QScopedValueRollback<bool> gcBlocker(gcBlocked, true); - if (!m_d->gcStats) { + if (!gcStats) { +// uint oldUsed = allocator.usedMem(); mark(); sweep(); +// DEBUG << "RUN GC: allocated:" << allocator.allocatedMem() << "used before" << oldUsed << "used now" << allocator.usedMem(); } else { const size_t totalMem = getAllocatedMem(); @@ -596,7 +841,6 @@ void MemoryManager::runGC() qint64 markTime = t.restart(); const size_t usedBefore = getUsedMem(); const size_t largeItemsBefore = getLargeItemsMem(); - size_t chunksBefore = m_d->heapChunks.size(); sweep(); const size_t usedAfter = getUsedMem(); const size_t largeItemsAfter = getLargeItemsMem(); @@ -605,56 +849,30 @@ void MemoryManager::runGC() qDebug() << "========== GC =========="; qDebug() << "Marked object in" << markTime << "ms."; qDebug() << "Sweeped object in" << sweepTime << "ms."; - qDebug() << "Allocated" << totalMem << "bytes in" << m_d->heapChunks.size() << "chunks."; + qDebug() << "Allocated" << totalMem << "bytes"; qDebug() << "Used memory before GC:" << usedBefore; qDebug() << "Used memory after GC:" << usedAfter; qDebug() << "Freed up bytes:" << (usedBefore - usedAfter); - qDebug() << "Released chunks:" << (chunksBefore - m_d->heapChunks.size()); qDebug() << "Large item memory before GC:" << largeItemsBefore; qDebug() << "Large item memory after GC:" << largeItemsAfter; qDebug() << "Large item memory freed up:" << (largeItemsBefore - largeItemsAfter); qDebug() << "======== End GC ========"; } - - memset(m_d->allocCount, 0, sizeof(m_d->allocCount)); - m_d->totalAlloc = 0; - m_d->totalLargeItemsAllocated = 0; } size_t MemoryManager::getUsedMem() const { - size_t usedMem = 0; - for (std::vector<PageAllocation>::const_iterator i = m_d->heapChunks.cbegin(), ei = m_d->heapChunks.cend(); i != ei; ++i) { - Data::ChunkHeader *header = reinterpret_cast<Data::ChunkHeader *>(i->base()); - for (char *item = header->itemStart; item <= header->itemEnd; item += header->itemSize) { - Heap::Base *m = reinterpret_cast<Heap::Base *>(item); - Q_ASSERT(qintptr(item) % 16 == 0); - if (m->inUse()) - usedMem += header->itemSize; - } - } - return usedMem; + return blockAllocator.usedMem(); } size_t MemoryManager::getAllocatedMem() const { - size_t total = 0; - for (size_t i = 0; i < m_d->heapChunks.size(); ++i) - total += m_d->heapChunks.at(i).size(); - return total; + return blockAllocator.allocatedMem() + hugeItemAllocator.usedMem(); } 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; -} - -void MemoryManager::growUnmanagedHeapSizeUsage(size_t delta) -{ - m_d->unmanagedHeapSize += delta; + return hugeItemAllocator.usedMem(); } MemoryManager::~MemoryManager() @@ -662,23 +880,26 @@ MemoryManager::~MemoryManager() delete m_persistentValues; sweep(/*lastSweep*/true); + blockAllocator.freeAll(); + hugeItemAllocator.freeAll(); + stackAllocator.freeAll(); delete m_weakValues; #ifdef V4_USE_VALGRIND VALGRIND_DESTROY_MEMPOOL(this); #endif + delete chunkAllocator; } - void MemoryManager::dumpStats() const { #ifdef DETAILED_MM_STATS std::cerr << "=================" << std::endl; std::cerr << "Allocation stats:" << std::endl; std::cerr << "Requests for each chunk size:" << std::endl; - for (int i = 0; i < m_d->allocSizeCounters.size(); ++i) { - if (unsigned count = m_d->allocSizeCounters[i]) { + for (int i = 0; i < allocSizeCounters.size(); ++i) { + if (unsigned count = allocSizeCounters[i]) { std::cerr << "\t" << (i << 4) << " bytes chunks: " << count << std::endl; } } @@ -689,7 +910,7 @@ void MemoryManager::dumpStats() const void MemoryManager::willAllocate(std::size_t size) { unsigned alignedSize = (size + 15) >> 4; - QVector<unsigned> &counters = m_d->allocSizeCounters; + QVector<unsigned> &counters = allocSizeCounters; if ((unsigned) counters.size() < alignedSize + 1) counters.resize(alignedSize + 1); counters[alignedSize]++; @@ -709,4 +930,7 @@ void MemoryManager::collectFromJSStack() const ++v; } } + +} // namespace QV4 + QT_END_NAMESPACE diff --git a/src/qml/memory/qv4mm_p.h b/src/qml/memory/qv4mm_p.h index dfa0d85dff..00daf8a622 100644 --- a/src/qml/memory/qv4mm_p.h +++ b/src/qml/memory/qv4mm_p.h @@ -55,6 +55,7 @@ #include <private/qv4value_p.h> #include <private/qv4scopedvalue_p.h> #include <private/qv4object_p.h> +#include <private/qv4mmdefs_p.h> #include <QVector> //#define DETAILED_MM_STATS @@ -63,55 +64,166 @@ #define QV4_MM_MAX_CHUNK_SIZE "QV4_MM_MAX_CHUNK_SIZE" #define QV4_MM_STATS "QV4_MM_STATS" +#define MM_DEBUG 0 + QT_BEGIN_NAMESPACE namespace QV4 { -struct GCDeletable; +struct ChunkAllocator; -class Q_QML_EXPORT MemoryManager -{ - Q_DISABLE_COPY(MemoryManager); +template<typename T> +struct StackAllocator { + Q_STATIC_ASSERT(sizeof(T) < Chunk::DataSize); + static const uint requiredSlots = (sizeof(T) + sizeof(HeapItem) - 1)/sizeof(HeapItem); -public: - struct Data; + StackAllocator(ChunkAllocator *chunkAlloc); - class GCBlocker - { - public: - GCBlocker(MemoryManager *mm) - : mm(mm) - , wasBlocked(mm->isGCBlocked()) - { - mm->setGCBlocked(true); + T *allocate() { + T *m = nextFree->as<T>(); + if (Q_UNLIKELY(nextFree == lastInChunk)) { + nextChunk(); + } else { + nextFree += requiredSlots; } - - ~GCBlocker() - { - mm->setGCBlocked(wasBlocked); +#if MM_DEBUG + Chunk *c = m->chunk(); + Chunk::setBit(c->objectBitmap, m - c->realBase()); +#endif + return m; + } + void free() { +#if MM_DEBUG + Chunk::clearBit(item->chunk()->objectBitmap, item - item->chunk()->realBase()); +#endif + if (Q_UNLIKELY(nextFree == firstInChunk)) { + prevChunk(); + } else { + nextFree -= requiredSlots; } + } + + void nextChunk(); + void prevChunk(); + + void freeAll(); + + ChunkAllocator *chunkAllocator; + HeapItem *nextFree = 0; + HeapItem *firstInChunk = 0; + HeapItem *lastInChunk = 0; + std::vector<Chunk *> chunks; + uint currentChunk = 0; +}; + +struct BlockAllocator { + BlockAllocator(ChunkAllocator *chunkAllocator) + : chunkAllocator(chunkAllocator) + { + memset(freeBins, 0, sizeof(freeBins)); +#if MM_DEBUG + memset(allocations, 0, sizeof(allocations)); +#endif + } + + enum { NumBins = 8 }; + + static inline size_t binForSlots(size_t nSlots) { + return nSlots >= NumBins ? NumBins - 1 : nSlots; + } + +#if MM_DEBUG + void stats(); +#endif + + HeapItem *allocate(size_t size, bool forceAllocation = false); + + size_t totalSlots() const { + return Chunk::AvailableSlots*chunks.size(); + } + + size_t allocatedMem() const { + return chunks.size()*Chunk::DataSize; + } + size_t usedMem() const { + uint used = 0; + for (auto c : chunks) + used += c->nUsedSlots()*Chunk::SlotSize; + return used; + } - private: - MemoryManager *mm; - bool wasBlocked; + void sweep(); + void freeAll(); + + // bump allocations + HeapItem *nextFree = 0; + size_t nFree = 0; + size_t usedSlotsAfterLastSweep = 0; + HeapItem *freeBins[NumBins]; + ChunkAllocator *chunkAllocator; + std::vector<Chunk *> chunks; +#if MM_DEBUG + uint allocations[NumBins]; +#endif +}; + +struct HugeItemAllocator { + HugeItemAllocator(ChunkAllocator *chunkAllocator) + : chunkAllocator(chunkAllocator) + {} + + HeapItem *allocate(size_t size); + void sweep(); + void freeAll(); + + size_t usedMem() const { + size_t used = 0; + for (const auto &c : chunks) + used += c.size; + return used; + } + + ChunkAllocator *chunkAllocator; + struct HugeChunk { + Chunk *chunk; + size_t size; }; + std::vector<HugeChunk> chunks; +}; + + +class Q_QML_EXPORT MemoryManager +{ + Q_DISABLE_COPY(MemoryManager); + public: MemoryManager(ExecutionEngine *engine); ~MemoryManager(); // TODO: this is only for 64bit (and x86 with SSE/AVX), so exend it for other architectures to be slightly more efficient (meaning, align on 8-byte boundaries). // Note: all occurrences of "16" in alloc/dealloc are also due to the alignment. - static inline std::size_t align(std::size_t size) - { return (size + 15) & ~0xf; } + Q_DECL_CONSTEXPR static inline std::size_t align(std::size_t size) + { return (size + Chunk::SlotSize - 1) & ~(Chunk::SlotSize - 1); } + + QV4::Heap::CallContext *allocSimpleCallContext(QV4::ExecutionEngine *v4) + { + Heap::CallContext *ctxt = stackAllocator.allocate(); + memset(ctxt, 0, sizeof(Heap::CallContext)); + ctxt->setVtable(QV4::CallContext::staticVTable()); + ctxt->init(v4); + return ctxt; + + } + void freeSimpleCallContext() + { stackAllocator.free(); } template<typename ManagedType> - inline typename ManagedType::Data *allocManaged(std::size_t size, std::size_t unmanagedSize = 0) + inline typename ManagedType::Data *allocManaged(std::size_t size) { V4_ASSERT_IS_TRIVIAL(typename ManagedType::Data) size = align(size); - Heap::Base *o = allocData(size, unmanagedSize); - memset(o, 0, size); + Heap::Base *o = allocData(size); o->setVtable(ManagedType::staticVTable()); return static_cast<typename ManagedType::Data *>(o); } @@ -119,35 +231,31 @@ public: template <typename ObjectType> typename ObjectType::Data *allocateObject(InternalClass *ic) { - const int size = (sizeof(typename ObjectType::Data) + (sizeof(Value) - 1)) & ~(sizeof(Value) - 1); - typename ObjectType::Data *o = allocManaged<ObjectType>(size + ic->size*sizeof(Value)); + Heap::Object *o = allocObjectWithMemberData(align(sizeof(typename ObjectType::Data)), ic->size); + o->setVtable(ObjectType::staticVTable()); o->internalClass = ic; - o->inlineMemberSize = ic->size; - o->inlineMemberOffset = size/sizeof(Value); - return o; + return static_cast<typename ObjectType::Data *>(o); } template <typename ObjectType> typename ObjectType::Data *allocateObject() { InternalClass *ic = ObjectType::defaultInternalClass(engine); - const int size = (sizeof(typename ObjectType::Data) + (sizeof(Value) - 1)) & ~(sizeof(Value) - 1); - typename ObjectType::Data *o = allocManaged<ObjectType>(size + ic->size*sizeof(Value)); + Heap::Object *o = allocObjectWithMemberData(align(sizeof(typename ObjectType::Data)), ic->size); + o->setVtable(ObjectType::staticVTable()); Object *prototype = ObjectType::defaultPrototype(engine); o->internalClass = ic; o->prototype = prototype->d(); - o->inlineMemberSize = ic->size; - o->inlineMemberOffset = size/sizeof(Value); - return o; + return static_cast<typename ObjectType::Data *>(o); } template <typename ManagedType, typename Arg1> typename ManagedType::Data *allocWithStringData(std::size_t unmanagedSize, Arg1 arg1) { - Scope scope(engine); - Scoped<ManagedType> t(scope, allocManaged<ManagedType>(sizeof(typename ManagedType::Data), unmanagedSize)); - t->d_unchecked()->init(this, arg1); - return t->d(); + typename ManagedType::Data *o = reinterpret_cast<typename ManagedType::Data *>(allocString(unmanagedSize)); + o->setVtable(ManagedType::staticVTable()); + o->init(this, arg1); + return o; } template <typename ObjectType> @@ -309,8 +417,6 @@ public: return t->d(); } - bool isGCBlocked() const; - void setGCBlocked(bool blockGC); void runGC(); void dumpStats() const; @@ -319,12 +425,15 @@ public: size_t getAllocatedMem() const; size_t getLargeItemsMem() const; - void growUnmanagedHeapSizeUsage(size_t delta); // called when a JS object grows itself. Specifically: Heap::String::append + // called when a JS object grows itself. Specifically: Heap::String::append + void changeUnmanagedHeapSizeUsage(qptrdiff delta) { unmanagedHeapSize += delta; } + protected: /// expects size to be aligned - // TODO: try to inline - Heap::Base *allocData(std::size_t size, std::size_t unmanagedSize); + Heap::Base *allocString(std::size_t unmanagedSize); + Heap::Base *allocData(std::size_t size); + Heap::Object *allocObjectWithMemberData(std::size_t size, uint nMembers); #ifdef DETAILED_MM_STATS void willAllocate(std::size_t size); @@ -334,13 +443,24 @@ private: void collectFromJSStack() const; void mark(); void sweep(bool lastSweep = false); + bool shouldRunGC() const; public: QV4::ExecutionEngine *engine; - QScopedPointer<Data> m_d; + ChunkAllocator *chunkAllocator; + StackAllocator<Heap::CallContext> stackAllocator; + BlockAllocator blockAllocator; + HugeItemAllocator hugeItemAllocator; PersistentValueStorage *m_persistentValues; PersistentValueStorage *m_weakValues; QVector<Value *> m_pendingFreedObjectWrapperValue; + + std::size_t unmanagedHeapSize = 0; // the amount of bytes of heap that is not managed by the memory manager, but which is held onto by managed items. + std::size_t unmanagedHeapSizeGCLimit; + + bool gcBlocked = false; + bool aggressiveGC = false; + bool gcStats = false; }; } diff --git a/src/qml/memory/qv4mmdefs_p.h b/src/qml/memory/qv4mmdefs_p.h new file mode 100644 index 0000000000..588ae21ee0 --- /dev/null +++ b/src/qml/memory/qv4mmdefs_p.h @@ -0,0 +1,262 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtQml module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ +#ifndef QV4MMDEFS_P_H +#define QV4MMDEFS_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include <private/qv4global_p.h> +#include <QtCore/qalgorithms.h> +#include <qdebug.h> + +QT_BEGIN_NAMESPACE + +namespace QV4 { + +/* + * Chunks are the basic structure containing GC managed objects. + * + * Chunks are 64k aligned in memory, so that retrieving the Chunk pointer from a Heap object + * is a simple masking operation. Each Chunk has 4 bitmaps for managing purposes, + * and 32byte wide slots for the objects following afterwards. + * + * The gray and black bitmaps are used for mark/sweep. + * The object bitmap has a bit set if this location represents the start of a Heap object. + * The extends bitmap denotes the extend of an object. It has a cleared bit at the start of the object + * and a set bit for all following slots used by the object. + * + * Free memory has both used and extends bits set to 0. + * + * This gives the following operations when allocating an object of size s: + * Find s/Alignment consecutive free slots in the chunk. Set the object bit for the first + * slot to 1. Set the extends bits for all following slots to 1. + * + * All used slots can be found by object|extents. + * + * When sweeping, simply copy the black bits over to the object bits. + * + */ +struct HeapItem; +struct Chunk { + enum { + ChunkSize = 64*1024, + ChunkShift = 16, + SlotSize = 32, + SlotSizeShift = 5, + NumSlots = ChunkSize/SlotSize, + BitmapSize = NumSlots/8, + HeaderSize = 4*BitmapSize, + DataSize = ChunkSize - HeaderSize, + AvailableSlots = DataSize/SlotSize, +#if QT_POINTER_SIZE == 8 + Bits = 64, + BitShift = 6, +#else + Bits = 32, + BitShift = 5, +#endif + EntriesInBitmap = BitmapSize/sizeof(quintptr) + }; + quintptr grayBitmap[BitmapSize/sizeof(quintptr)]; + quintptr blackBitmap[BitmapSize/sizeof(quintptr)]; + quintptr objectBitmap[BitmapSize/sizeof(quintptr)]; + quintptr extendsBitmap[BitmapSize/sizeof(quintptr)]; + char data[ChunkSize - HeaderSize]; + + HeapItem *realBase(); + HeapItem *first(); + + static void setBit(quintptr *bitmap, size_t index) { +// Q_ASSERT(index >= HeaderSize/SlotSize && index < ChunkSize/SlotSize); + bitmap += index >> BitShift; + quintptr bit = static_cast<quintptr>(1) << (index & (Bits - 1)); + *bitmap |= bit; + } + static void clearBit(quintptr *bitmap, size_t index) { +// Q_ASSERT(index >= HeaderSize/SlotSize && index < ChunkSize/SlotSize); + bitmap += index >> BitShift; + quintptr bit = static_cast<quintptr>(1) << (index & (Bits - 1)); + *bitmap &= ~bit; + } + static bool testBit(quintptr *bitmap, size_t index) { +// Q_ASSERT(index >= HeaderSize/SlotSize && index < ChunkSize/SlotSize); + bitmap += index >> BitShift; + quintptr bit = static_cast<quintptr>(1) << (index & (Bits - 1)); + return (*bitmap & bit); + } + static void setBits(quintptr *bitmap, size_t index, size_t nBits) { +// Q_ASSERT(index >= HeaderSize/SlotSize && index + nBits <= ChunkSize/SlotSize); + if (!nBits) + return; + bitmap += index >> BitShift; + index &= (Bits - 1); + while (1) { + size_t bitsToSet = qMin(nBits, Bits - index); + quintptr mask = static_cast<quintptr>(-1) >> (Bits - bitsToSet) << index; + *bitmap |= mask; + nBits -= bitsToSet; + if (!nBits) + return; + index = 0; + ++bitmap; + } + } + static bool hasNonZeroBit(quintptr *bitmap) { + for (uint i = 0; i < EntriesInBitmap; ++i) + if (bitmap[i]) + return true; + return false; + } + static uint lowestNonZeroBit(quintptr *bitmap) { + for (uint i = 0; i < EntriesInBitmap; ++i) { + if (bitmap[i]) { + quintptr b = bitmap[i]; + return i*Bits + qCountTrailingZeroBits(b); + } + } + return 0; + } + + uint nFreeSlots() const { + return AvailableSlots - nUsedSlots(); + } + uint nUsedSlots() const { + uint usedSlots = 0; + for (uint i = 0; i < EntriesInBitmap; ++i) { + quintptr used = objectBitmap[i] | extendsBitmap[i]; + usedSlots += qPopulationCount(used); + } + return usedSlots; + } + + void sweep(); + void freeAll(); + + void sortIntoBins(HeapItem **bins, uint nBins); +}; + +struct HeapItem { + union { + struct { + HeapItem *next; + size_t availableSlots; + } freeData; + quint64 payload[Chunk::SlotSize/sizeof(quint64)]; + }; + operator Heap::Base *() { return reinterpret_cast<Heap::Base *>(this); } + + template<typename T> + T *as() { return static_cast<T *>(reinterpret_cast<Heap::Base *>(this)); } + + Chunk *chunk() const { + return reinterpret_cast<Chunk *>(reinterpret_cast<quintptr>(this) >> Chunk::ChunkShift << Chunk::ChunkShift); + } + + bool isGray() const { + Chunk *c = chunk(); + uint index = this - c->realBase(); + return Chunk::testBit(c->grayBitmap, index); + } + bool isBlack() const { + Chunk *c = chunk(); + uint index = this - c->realBase(); + return Chunk::testBit(c->blackBitmap, index); + } + bool isInUse() const { + Chunk *c = chunk(); + uint index = this - c->realBase(); + return Chunk::testBit(c->objectBitmap, index); + } + + void setAllocatedSlots(size_t nSlots) { +// Q_ASSERT(size && !(size % sizeof(HeapItem))); + Chunk *c = chunk(); + size_t index = this - c->realBase(); +// Q_ASSERT(!Chunk::testBit(c->objectBitmap, index)); + Chunk::setBit(c->objectBitmap, index); + Chunk::setBits(c->extendsBitmap, index + 1, nSlots - 1); +// for (uint i = index + 1; i < nBits - 1; ++i) +// Q_ASSERT(Chunk::testBit(c->extendsBitmap, i)); +// Q_ASSERT(!Chunk::testBit(c->extendsBitmap, index)); + } + + // Doesn't report correctly for huge items + size_t size() const { + Chunk *c = chunk(); + uint index = this - c->realBase(); + Q_ASSERT(Chunk::testBit(c->objectBitmap, index)); + // ### optimize me + uint end = index + 1; + while (end < Chunk::NumSlots && Chunk::testBit(c->extendsBitmap, end)) + ++end; + return (end - index)*sizeof(HeapItem); + } +}; + +inline HeapItem *Chunk::realBase() +{ + return reinterpret_cast<HeapItem *>(this); +} + +inline HeapItem *Chunk::first() +{ + return reinterpret_cast<HeapItem *>(data); +} + +Q_STATIC_ASSERT(sizeof(Chunk) == Chunk::ChunkSize); +Q_STATIC_ASSERT((1 << Chunk::ChunkShift) == Chunk::ChunkSize); +Q_STATIC_ASSERT(1 << Chunk::SlotSizeShift == Chunk::SlotSize); +Q_STATIC_ASSERT(sizeof(HeapItem) == Chunk::SlotSize); +Q_STATIC_ASSERT(QT_POINTER_SIZE*8 == Chunk::Bits); +Q_STATIC_ASSERT((1 << Chunk::BitShift) == Chunk::Bits); + +} + +QT_END_NAMESPACE + +#endif diff --git a/src/qml/qml.pro b/src/qml/qml.pro index 826a074701..8f9e4b7f83 100644 --- a/src/qml/qml.pro +++ b/src/qml/qml.pro @@ -14,6 +14,8 @@ solaris-cc*:QMAKE_CXXFLAGS_RELEASE -= -O2 # Ensure this gcc optimization is switched off for mips platforms to avoid trouble with JIT. gcc:isEqual(QT_ARCH, "mips"): QMAKE_CXXFLAGS += -fno-reorder-blocks +DEFINES += QT_NO_FOREACH + exists("qqml_enable_gcov") { QMAKE_CXXFLAGS = -fprofile-arcs -ftest-coverage -fno-elide-constructors LIBS_PRIVATE += -lgcov diff --git a/src/qml/qml/qqmlabstractbinding.cpp b/src/qml/qml/qqmlabstractbinding.cpp index 39d609454f..b1c320afd4 100644 --- a/src/qml/qml/qqmlabstractbinding.cpp +++ b/src/qml/qml/qqmlabstractbinding.cpp @@ -191,7 +191,7 @@ void QQmlAbstractBinding::removeFromObject() void QQmlAbstractBinding::printBindingLoopError(QQmlProperty &prop) { - qmlInfo(prop.object()) << QString(QLatin1String("Binding loop detected for property \"%1\"")).arg(prop.name()); + qmlWarning(prop.object()) << QString(QLatin1String("Binding loop detected for property \"%1\"")).arg(prop.name()); } QString QQmlAbstractBinding::expression() const diff --git a/src/qml/qml/qqmlabstracturlinterceptor.h b/src/qml/qml/qqmlabstracturlinterceptor.h index dfb8a46027..665b37fb3a 100644 --- a/src/qml/qml/qqmlabstracturlinterceptor.h +++ b/src/qml/qml/qqmlabstracturlinterceptor.h @@ -47,7 +47,6 @@ QT_BEGIN_NAMESPACE class Q_QML_EXPORT QQmlAbstractUrlInterceptor { - Q_FLAGS(InterceptionPoint) public: enum DataType { //Matches QQmlDataBlob::Type QmlFile = 0, diff --git a/src/qml/qml/qqmlapplicationengine.cpp b/src/qml/qml/qqmlapplicationengine.cpp index 8a97b7eba7..2a96d96302 100644 --- a/src/qml/qml/qqmlapplicationengine.cpp +++ b/src/qml/qml/qqmlapplicationengine.cpp @@ -190,9 +190,14 @@ void QQmlApplicationEnginePrivate::_q_finishLoad(QObject *o) /*! \fn QQmlApplicationEngine::objectCreated(QObject *object, const QUrl &url) - This signal is emitted when an object finishes loading. If loading was successful, \a object contains a pointer to the loaded object. - Otherwise the pointer is NULL. The \a url loaded is also provided, note that if a QString file path was initially passed to the - QQmlApplicationEngine, this url will be the equivalent of QUrl::fromLocalFile(filePath). + This signal is emitted when an object finishes loading. If loading was + successful, \a object contains a pointer to the loaded object, otherwise + the pointer is NULL. + + The \a url to the component the \a object came from is also provided. + + \note If the path to the component was provided as a QString containing a + relative path, the \a url will contain a fully resolved path to the file. */ /*! @@ -226,7 +231,7 @@ QQmlApplicationEngine::QQmlApplicationEngine(const QUrl &url, QObject *parent) This is provided as a convenience, and is the same as using the empty constructor and calling load afterwards. */ QQmlApplicationEngine::QQmlApplicationEngine(const QString &filePath, QObject *parent) - : QQmlApplicationEngine(QUrl::fromLocalFile(filePath), parent) + : QQmlApplicationEngine(QUrl::fromUserInput(filePath, QLatin1String("."), QUrl::AssumeLocalFile), parent) { } @@ -265,7 +270,7 @@ void QQmlApplicationEngine::load(const QUrl &url) void QQmlApplicationEngine::load(const QString &filePath) { Q_D(QQmlApplicationEngine); - d->startLoad(QUrl::fromLocalFile(filePath)); + d->startLoad(QUrl::fromUserInput(filePath, QLatin1String("."), QUrl::AssumeLocalFile)); } /*! diff --git a/src/qml/qml/qqmlboundsignal.cpp b/src/qml/qml/qqmlboundsignal.cpp index 254d5e1907..19ece44beb 100644 --- a/src/qml/qml/qqmlboundsignal.cpp +++ b/src/qml/qml/qqmlboundsignal.cpp @@ -91,7 +91,7 @@ QQmlBoundSignalExpression::QQmlBoundSignalExpression(QObject *target, int index, function += QQmlPropertyCache::signalParameterStringForJS(v4, signal.parameterNames(), &error); if (!error.isEmpty()) { - qmlInfo(scopeObject()) << error; + qmlWarning(scopeObject()) << error; return; } } else @@ -129,7 +129,7 @@ QQmlBoundSignalExpression::QQmlBoundSignalExpression(QObject *target, int index, QString error; QQmlPropertyCache::signalParameterStringForJS(engine, signalParameters, &error); if (!error.isEmpty()) { - qmlInfo(scopeObject()) << error; + qmlWarning(scopeObject()) << error; return; } runtimeFunction->updateInternalClass(engine, signalParameters); @@ -199,7 +199,10 @@ void QQmlBoundSignalExpression::evaluate(void **a) // for several cases (such as QVariant type and QObject-derived types) //args[ii] = engine->metaTypeToJS(type, a[ii + 1]); if (type == qMetaTypeId<QJSValue>()) { - callData->args[ii] = *QJSValuePrivate::getValue(reinterpret_cast<QJSValue *>(a[ii + 1])); + if (QV4::Value *v4Value = QJSValuePrivate::valueForData(reinterpret_cast<QJSValue *>(a[ii + 1]), &callData->args[ii])) + callData->args[ii] = *v4Value; + else + callData->args[ii] = QV4::Encode::undefined(); } else if (type == QMetaType::QVariant) { callData->args[ii] = scope.engine->fromVariant(*((QVariant *)a[ii + 1])); } else if (type == QMetaType::Int) { diff --git a/src/qml/qml/qqmlcomponent.cpp b/src/qml/qml/qqmlcomponent.cpp index 6ebcd142fb..a04f47e6a4 100644 --- a/src/qml/qml/qqmlcomponent.cpp +++ b/src/qml/qml/qqmlcomponent.cpp @@ -47,8 +47,6 @@ #include "qqml.h" #include "qqmlengine.h" #include "qqmlbinding_p.h" -#include <private/qqmldebugconnector_p.h> -#include <private/qqmldebugserviceinterfaces_p.h> #include "qqmlincubator.h" #include "qqmlincubator_p.h" #include <private/qqmljavascriptexpression_p.h> @@ -876,15 +874,6 @@ QQmlComponentPrivate::beginCreate(QQmlContextData *context) depthIncreased = false; } - if (rv) { - if (QQmlEngineDebugService *service = - QQmlDebugConnector::service<QQmlEngineDebugService>()) { - if (!context->isInternal) - context->asQQmlContextPrivate()->instances.append(rv); - service->objectCreated(engine, rv); - } - } - return rv; } @@ -1074,11 +1063,11 @@ struct QmlIncubatorObject : public QV4::Object V4_OBJECT2(QmlIncubatorObject, Object) V4_NEEDS_DESTROY - static QV4::ReturnedValue method_get_statusChanged(QV4::CallContext *ctx); - static QV4::ReturnedValue method_set_statusChanged(QV4::CallContext *ctx); - static QV4::ReturnedValue method_get_status(QV4::CallContext *ctx); - static QV4::ReturnedValue method_get_object(QV4::CallContext *ctx); - static QV4::ReturnedValue method_forceCompletion(QV4::CallContext *ctx); + static void method_get_statusChanged(const BuiltinFunction *, Scope &scope, CallData *callData); + static void method_set_statusChanged(const BuiltinFunction *, Scope &scope, CallData *callData); + static void method_get_status(const BuiltinFunction *, Scope &scope, CallData *callData); + static void method_get_object(const BuiltinFunction *, Scope &scope, CallData *callData); + static void method_forceCompletion(const BuiltinFunction *, Scope &scope, CallData *callData); static void markObjects(QV4::Heap::Base *that, QV4::ExecutionEngine *e); @@ -1244,7 +1233,7 @@ void QQmlComponent::createObject(QQmlV4Function *args) if (args->length() >= 2) { QV4::ScopedValue v(scope, (*args)[1]); if (!v->as<QV4::Object>() || v->as<QV4::ArrayObject>()) { - qmlInfo(this) << tr("createObject: value is not an object"); + qmlWarning(this) << tr("createObject: value is not an object"); args->setReturnValue(QV4::Encode::null()); return; } @@ -1361,7 +1350,7 @@ void QQmlComponent::incubateObject(QQmlV4Function *args) QV4::ScopedValue v(scope, (*args)[1]); if (v->isNull()) { } else if (!v->as<QV4::Object>() || v->as<QV4::ArrayObject>()) { - qmlInfo(this) << tr("createObject: value is not an object"); + qmlWarning(this) << tr("createObject: value is not an object"); args->setReturnValue(QV4::Encode::null()); return; } else { @@ -1426,58 +1415,53 @@ QQmlComponentExtension::QQmlComponentExtension(QV4::ExecutionEngine *v4) incubationProto.set(v4, proto); } -QV4::ReturnedValue QV4::QmlIncubatorObject::method_get_object(QV4::CallContext *ctx) +void QV4::QmlIncubatorObject::method_get_object(const BuiltinFunction *, Scope &scope, CallData *callData) { - QV4::Scope scope(ctx); - QV4::Scoped<QmlIncubatorObject> o(scope, ctx->thisObject().as<QmlIncubatorObject>()); + QV4::Scoped<QmlIncubatorObject> o(scope, callData->thisObject.as<QmlIncubatorObject>()); if (!o) - return ctx->engine()->throwTypeError(); + THROW_TYPE_ERROR(); - return QV4::QObjectWrapper::wrap(ctx->d()->engine, o->d()->incubator->object()); + scope.result = QV4::QObjectWrapper::wrap(scope.engine, o->d()->incubator->object()); } -QV4::ReturnedValue QV4::QmlIncubatorObject::method_forceCompletion(QV4::CallContext *ctx) +void QV4::QmlIncubatorObject::method_forceCompletion(const BuiltinFunction *, Scope &scope, CallData *callData) { - QV4::Scope scope(ctx); - QV4::Scoped<QmlIncubatorObject> o(scope, ctx->thisObject().as<QmlIncubatorObject>()); + QV4::Scoped<QmlIncubatorObject> o(scope, callData->thisObject.as<QmlIncubatorObject>()); if (!o) - return ctx->engine()->throwTypeError(); + THROW_TYPE_ERROR(); o->d()->incubator->forceCompletion(); - return QV4::Encode::undefined(); + RETURN_UNDEFINED(); } -QV4::ReturnedValue QV4::QmlIncubatorObject::method_get_status(QV4::CallContext *ctx) +void QV4::QmlIncubatorObject::method_get_status(const BuiltinFunction *, Scope &scope, CallData *callData) { - QV4::Scope scope(ctx); - QV4::Scoped<QmlIncubatorObject> o(scope, ctx->thisObject().as<QmlIncubatorObject>()); + QV4::Scoped<QmlIncubatorObject> o(scope, callData->thisObject.as<QmlIncubatorObject>()); if (!o) - return ctx->engine()->throwTypeError(); + THROW_TYPE_ERROR(); - return QV4::Encode(o->d()->incubator->status()); + scope.result = QV4::Encode(o->d()->incubator->status()); } -QV4::ReturnedValue QV4::QmlIncubatorObject::method_get_statusChanged(QV4::CallContext *ctx) +void QV4::QmlIncubatorObject::method_get_statusChanged(const BuiltinFunction *, Scope &scope, CallData *callData) { - QV4::Scope scope(ctx); - QV4::Scoped<QmlIncubatorObject> o(scope, ctx->thisObject().as<QmlIncubatorObject>()); + QV4::Scoped<QmlIncubatorObject> o(scope, callData->thisObject.as<QmlIncubatorObject>()); if (!o) - return ctx->engine()->throwTypeError(); + THROW_TYPE_ERROR(); - return o->d()->statusChanged.asReturnedValue(); + scope.result = o->d()->statusChanged; } -QV4::ReturnedValue QV4::QmlIncubatorObject::method_set_statusChanged(QV4::CallContext *ctx) +void QV4::QmlIncubatorObject::method_set_statusChanged(const BuiltinFunction *, Scope &scope, CallData *callData) { - QV4::Scope scope(ctx); - QV4::Scoped<QmlIncubatorObject> o(scope, ctx->thisObject().as<QmlIncubatorObject>()); - if (!o || ctx->argc() < 1) - return ctx->engine()->throwTypeError(); + QV4::Scoped<QmlIncubatorObject> o(scope, callData->thisObject.as<QmlIncubatorObject>()); + if (!o || callData->argc < 1) + THROW_TYPE_ERROR(); + o->d()->statusChanged = callData->args[0]; - o->d()->statusChanged = ctx->args()[0]; - return QV4::Encode::undefined(); + RETURN_UNDEFINED(); } QQmlComponentExtension::~QQmlComponentExtension() diff --git a/src/qml/qml/qqmlcustomparser.cpp b/src/qml/qml/qqmlcustomparser.cpp index 85c91a592a..0b0bbef795 100644 --- a/src/qml/qml/qqmlcustomparser.cpp +++ b/src/qml/qml/qqmlcustomparser.cpp @@ -83,7 +83,7 @@ QT_BEGIN_NAMESPACE by \a data, which is a block of data previously returned by a call to compile(). - Errors should be reported using qmlInfo(object). + Errors should be reported using qmlWarning(object). The \a object will be an instance of the TypeClass specified by QML_REGISTER_CUSTOM_TYPE. */ diff --git a/src/qml/qml/qqmldelayedcallqueue.cpp b/src/qml/qml/qqmldelayedcallqueue.cpp index 7552e1e82b..d5d2c9a28d 100644 --- a/src/qml/qml/qqmldelayedcallqueue.cpp +++ b/src/qml/qml/qqmldelayedcallqueue.cpp @@ -105,17 +105,15 @@ void QQmlDelayedCallQueue::init(QV4::ExecutionEngine* engine) m_tickedMethod = metaObject.method(methodIndex); } -QV4::ReturnedValue QQmlDelayedCallQueue::addUniquelyAndExecuteLater(QV4::CallContext *ctx) +void QQmlDelayedCallQueue::addUniquelyAndExecuteLater(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData) { - const QV4::CallData *callData = ctx->d()->callData; - if (callData->argc == 0) - V4THROW_ERROR("Qt.callLater: no arguments given"); + THROW_GENERIC_ERROR("Qt.callLater: no arguments given"); const QV4::FunctionObject *func = callData->args[0].as<QV4::FunctionObject>(); if (!func) - V4THROW_ERROR("Qt.callLater: first argument not a function or signal"); + THROW_GENERIC_ERROR("Qt.callLater: first argument not a function or signal"); QPair<QObject *, int> functionData = QV4::QObjectMethod::extractQtMethod(func); @@ -171,7 +169,7 @@ QV4::ReturnedValue QQmlDelayedCallQueue::addUniquelyAndExecuteLater(QV4::CallCon m_tickedMethod.invoke(this, Qt::QueuedConnection); m_callbackOutstanding = true; } - return QV4::Encode::undefined(); + scope.result = QV4::Encode::undefined(); } void QQmlDelayedCallQueue::storeAnyArguments(DelayedFunctionCall &dfc, const QV4::CallData *callData, int offset, QV4::ExecutionEngine *engine) diff --git a/src/qml/qml/qqmldelayedcallqueue_p.h b/src/qml/qml/qqmldelayedcallqueue_p.h index ef899170a2..cffde4f0c0 100644 --- a/src/qml/qml/qqmldelayedcallqueue_p.h +++ b/src/qml/qml/qqmldelayedcallqueue_p.h @@ -70,7 +70,7 @@ public: void init(QV4::ExecutionEngine *); - QV4::ReturnedValue addUniquelyAndExecuteLater(QV4::CallContext *ctx); + void addUniquelyAndExecuteLater(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData); public Q_SLOTS: void ticked(); diff --git a/src/qml/qml/qqmldirparser.cpp b/src/qml/qml/qqmldirparser.cpp index fde7cc4cef..4cca8a4d58 100644 --- a/src/qml/qml/qqmldirparser.cpp +++ b/src/qml/qml/qqmldirparser.cpp @@ -188,6 +188,15 @@ bool QQmlDirParser::parse(const QString &source) _plugins.append(entry); + } else if (sections[0] == QLatin1String("classname")) { + if (sectionCount < 2) { + reportError(lineNumber, 0, + QStringLiteral("classname directive requires an argument, but %1 were provided").arg(sectionCount - 1)); + + continue; + } + + // Ignore these. qmlimportscanner uses them. } else if (sections[0] == QLatin1String("internal")) { if (sectionCount != 3) { reportError(lineNumber, 0, diff --git a/src/qml/qml/qqmlengine.cpp b/src/qml/qml/qqmlengine.cpp index c2915c840b..e1fa97b52f 100644 --- a/src/qml/qml/qqmlengine.cpp +++ b/src/qml/qml/qqmlengine.cpp @@ -436,7 +436,6 @@ The following functions are also on the Qt object. \list \li \c "android" - Android - \li \c "blackberry" - BlackBerry OS \li \c "ios" - iOS \li \c "tvos" - tvOS \li \c "linux" - Linux @@ -444,7 +443,6 @@ The following functions are also on the Qt object. \li \c "unix" - Other Unix-based OS \li \c "windows" - Windows \li \c "winrt" - WinRT / UWP - \li \c "winphone" - Windows Phone \endlist \endtable */ @@ -1914,9 +1912,29 @@ void QQmlEnginePrivate::sendExit(int retCode) static void dumpwarning(const QQmlError &error) { - QMessageLogger(error.url().toString().toLatin1().constData(), - error.line(), 0).warning().nospace() - << qPrintable(error.toString()); + switch (error.messageType()) { + case QtDebugMsg: + QMessageLogger(error.url().toString().toLatin1().constData(), + error.line(), 0).debug().nospace() + << qPrintable(error.toString()); + break; + case QtInfoMsg: + QMessageLogger(error.url().toString().toLatin1().constData(), + error.line(), 0).info().nospace() + << qPrintable(error.toString()); + break; + case QtWarningMsg: + case QtFatalMsg: // fatal does not support streaming, and furthermore, is actually fatal. Probably not desirable for QML. + QMessageLogger(error.url().toString().toLatin1().constData(), + error.line(), 0).warning().nospace() + << qPrintable(error.toString()); + break; + case QtCriticalMsg: + QMessageLogger(error.url().toString().toLatin1().constData(), + error.line(), 0).critical().nospace() + << qPrintable(error.toString()); + break; + } } static void dumpwarning(const QList<QQmlError> &errors) @@ -2129,8 +2147,7 @@ bool QQmlEngine::importPlugin(const QString &filePath, const QString &uri, QList Returns the directory where SQL and other offline storage is placed. - QQuickWebView and the SQL databases created with openDatabase() - are stored here. + The SQL databases created with openDatabase() are stored here. The default is QML/OfflineStorage in the platform-standard user application data directory. diff --git a/src/qml/qml/qqmlerror.cpp b/src/qml/qml/qqmlerror.cpp index 0a6c7b4960..7a1e02eec6 100644 --- a/src/qml/qml/qqmlerror.cpp +++ b/src/qml/qml/qqmlerror.cpp @@ -85,11 +85,12 @@ public: QString description; quint16 line; quint16 column; + QtMsgType messageType; QObject *object; }; QQmlErrorPrivate::QQmlErrorPrivate() -: line(0), column(0), object() +: line(0), column(0), messageType(QtMsgType::QtWarningMsg), object() { } @@ -119,12 +120,14 @@ QQmlError &QQmlError::operator=(const QQmlError &other) delete d; d = 0; } else { - if (!d) d = new QQmlErrorPrivate; + if (!d) + d = new QQmlErrorPrivate; d->url = other.d->url; d->description = other.d->description; d->line = other.d->line; d->column = other.d->column; d->object = other.d->object; + d->messageType = other.d->messageType; } return *this; } @@ -150,8 +153,9 @@ bool QQmlError::isValid() const */ QUrl QQmlError::url() const { - if (d) return d->url; - else return QUrl(); + if (d) + return d->url; + return QUrl(); } /*! @@ -159,7 +163,8 @@ QUrl QQmlError::url() const */ void QQmlError::setUrl(const QUrl &url) { - if (!d) d = new QQmlErrorPrivate; + if (!d) + d = new QQmlErrorPrivate; d->url = url; } @@ -168,8 +173,9 @@ void QQmlError::setUrl(const QUrl &url) */ QString QQmlError::description() const { - if (d) return d->description; - else return QString(); + if (d) + return d->description; + return QString(); } /*! @@ -177,7 +183,8 @@ QString QQmlError::description() const */ void QQmlError::setDescription(const QString &description) { - if (!d) d = new QQmlErrorPrivate; + if (!d) + d = new QQmlErrorPrivate; d->description = description; } @@ -186,8 +193,9 @@ void QQmlError::setDescription(const QString &description) */ int QQmlError::line() const { - if (d) return qmlSourceCoordinate(d->line); - else return -1; + if (d) + return qmlSourceCoordinate(d->line); + return -1; } /*! @@ -195,7 +203,8 @@ int QQmlError::line() const */ void QQmlError::setLine(int line) { - if (!d) d = new QQmlErrorPrivate; + if (!d) + d = new QQmlErrorPrivate; d->line = qmlSourceCoordinate(line); } @@ -204,8 +213,9 @@ void QQmlError::setLine(int line) */ int QQmlError::column() const { - if (d) return qmlSourceCoordinate(d->column); - else return -1; + if (d) + return qmlSourceCoordinate(d->column); + return -1; } /*! @@ -213,7 +223,8 @@ int QQmlError::column() const */ void QQmlError::setColumn(int column) { - if (!d) d = new QQmlErrorPrivate; + if (!d) + d = new QQmlErrorPrivate; d->column = qmlSourceCoordinate(column); } @@ -225,8 +236,9 @@ void QQmlError::setColumn(int column) */ QObject *QQmlError::object() const { - if (d) return d->object; - else return 0; + if (d) + return d->object; + return 0; } /*! @@ -234,11 +246,37 @@ QObject *QQmlError::object() const */ void QQmlError::setObject(QObject *object) { - if (!d) d = new QQmlErrorPrivate; + if (!d) + d = new QQmlErrorPrivate; d->object = object; } /*! + \since 5.9 + + Returns the message type. + */ +QtMsgType QQmlError::messageType() const +{ + if (d) + return d->messageType; + return QtMsgType::QtWarningMsg; +} + +/*! + \since 5.9 + + Sets the \a messageType for this message. The message type determines which + QDebug handlers are responsible for recieving the message. + */ +void QQmlError::setMessageType(QtMsgType messageType) +{ + if (!d) + d = new QQmlErrorPrivate; + d->messageType = messageType; +} + +/*! Returns the error as a human readable string. */ QString QQmlError::toString() const diff --git a/src/qml/qml/qqmlerror.h b/src/qml/qml/qqmlerror.h index e4c42223cf..ef529e3828 100644 --- a/src/qml/qml/qqmlerror.h +++ b/src/qml/qml/qqmlerror.h @@ -47,6 +47,7 @@ QT_BEGIN_NAMESPACE +// ### Qt 6: should this be called QQmlMessage, since it can have a message type? class QDebug; class QQmlErrorPrivate; class Q_QML_EXPORT QQmlError @@ -69,6 +70,8 @@ public: void setColumn(int); QObject *object() const; void setObject(QObject *); + QtMsgType messageType() const; + void setMessageType(QtMsgType messageType); QString toString() const; private: diff --git a/src/qml/qml/qqmlextensionplugin.cpp b/src/qml/qml/qqmlextensionplugin.cpp index ca19691e93..097fa71200 100644 --- a/src/qml/qml/qqmlextensionplugin.cpp +++ b/src/qml/qml/qqmlextensionplugin.cpp @@ -117,4 +117,14 @@ void QQmlExtensionPlugin::initializeEngine(QQmlEngine *engine, const char *uri) Q_UNUSED(uri); } +/*! + \class QQmlExtensionInterface + \internal + \inmodule QtQml + + \class QQmlTypesExtensionInterface + \internal + \inmodule QtQml +*/ + QT_END_NAMESPACE diff --git a/src/qml/qml/qqmlimport.cpp b/src/qml/qml/qqmlimport.cpp index 8712b638c5..bd41659f27 100644 --- a/src/qml/qml/qqmlimport.cpp +++ b/src/qml/qml/qqmlimport.cpp @@ -130,42 +130,74 @@ bool isPathAbsolute(const QString &path) #endif } -// If the type does not already exist as a file import, add the type and return the new type -QQmlType *getTypeForUrl(const QString &urlString, const QHashedStringRef& typeName, +/* + \internal + + Fetches the QQmlType instance registered for \a urlString, creating a + registration for it if it is not already registered, using the associated + \a typeName, \a isCompositeSingleton, \a majorVersion and \a minorVersion + details. + + Errors (if there are any) are placed into \a errors, if it is nonzero. Note + that errors are treated as fatal if \a errors is not set. +*/ +QQmlType *fetchOrCreateTypeForUrl(const QString &urlString, const QHashedStringRef& typeName, bool isCompositeSingleton, QList<QQmlError> *errors, int majorVersion=-1, int minorVersion=-1) { - QUrl url(urlString); + QUrl url(urlString); // ### unfortunate (costly) conversion QQmlType *ret = QQmlMetaType::qmlType(url); - if (!ret) { //QQmlType not yet existing for composite or composite singleton type - int dot = typeName.indexOf(QLatin1Char('.')); - QHashedStringRef unqualifiedtype = dot < 0 ? typeName : QHashedStringRef(typeName.constData() + dot + 1, typeName.length() - dot - 1); - - //XXX: The constData of the string ref is pointing somewhere unsafe in qmlregister, so we need to create a temporary copy - QByteArray buf(unqualifiedtype.toString().toUtf8()); - - if (isCompositeSingleton) { - QQmlPrivate::RegisterCompositeSingletonType reg = { - url, - "", //Empty URI indicates loaded via file imports - majorVersion, - minorVersion, - buf.constData() - }; - ret = QQmlMetaType::qmlTypeFromIndex(QQmlPrivate::qmlregister(QQmlPrivate::CompositeSingletonRegistration, ®)); - } else { - QQmlPrivate::RegisterCompositeType reg = { - url, - "", //Empty URI indicates loaded via file imports - majorVersion, - minorVersion, - buf.constData() - }; - ret = QQmlMetaType::qmlTypeFromIndex(QQmlPrivate::qmlregister(QQmlPrivate::CompositeRegistration, ®)); - } + if (ret) + return ret; + + int dot = typeName.indexOf(QLatin1Char('.')); + QHashedStringRef unqualifiedtype = dot < 0 ? typeName : QHashedStringRef(typeName.constData() + dot + 1, typeName.length() - dot - 1); + + // We need a pointer, but we were passed a string. Take a copy so we + // can guarentee it will live long enough to reach qmlregister. + QByteArray buf(unqualifiedtype.toString().toUtf8()); + + // Register the type. Note that the URI parameters here are empty; for + // file type imports, we do not place them in a URI as we don't + // necessarily have a good and unique one (picture a library import, + // which may be found in multiple plugin locations on disk), but there + // are other reasons for this too. + // + // By not putting them in a URI, we prevent the types from being + // registered on a QQmlTypeModule; this is important, as once types are + // placed on there, they cannot be easily removed, meaning if the + // developer subsequently loads a different import (meaning different + // types) with the same URI (using, say, a different plugin path), it is + // very undesirable that we continue to associate the types from the + // "old" URI with that new module. + // + // Not having URIs also means that the types cannot be found by name + // etc, the only way to look them up is through QQmlImports -- for + // better or worse. + if (isCompositeSingleton) { + QQmlPrivate::RegisterCompositeSingletonType reg = { + url, + "", // uri + majorVersion, + minorVersion, + buf.constData() + }; + ret = QQmlMetaType::qmlTypeFromIndex(QQmlPrivate::qmlregister(QQmlPrivate::CompositeSingletonRegistration, ®)); + } else { + QQmlPrivate::RegisterCompositeType reg = { + url, + "", // uri + majorVersion, + minorVersion, + buf.constData() + }; + ret = QQmlMetaType::qmlTypeFromIndex(QQmlPrivate::qmlregister(QQmlPrivate::CompositeRegistration, ®)); } - if (!ret) {//Usually when a type name is "found" but invalid - //qDebug() << ret << urlString << QQmlMetaType::qmlType(url); + + // This means that the type couldn't be found by URL, but could not be + // registered either, meaning we most likely were passed some kind of bad + // data. + if (!ret) { if (!errors) // Cannot list errors properly, just quit qFatal("%s", QQmlMetaType::typeRegistrationFailures().join('\n').toLatin1().constData()); QQmlError error; @@ -204,20 +236,49 @@ void qmlClearEnginePlugins() typedef QPair<QStaticPlugin, QJsonArray> StaticPluginPair; #endif +/*! + \internal + + A QQmlImportNamespace is a way of seperating imports into a local namespace. + + Within a QML document, there is at least one namespace (the + "unqualified set") where imports without a qualifier are placed, i.e: + + import QtQuick 2.6 + + will have a single namespace (the unqualified set) containing a single import + for QtQuick 2.6. However, there may be others if an import statement gives + a qualifier, i.e the following will result in an additional new + QQmlImportNamespace in the qualified set: + + import MyFoo 1.0 as Foo +*/ class QQmlImportNamespace { public: QQmlImportNamespace() : nextNamespace(0) {} ~QQmlImportNamespace() { qDeleteAll(imports); } + /*! + \internal + + A QQmlImportNamespace::Import represents an actual instance of an import + within a namespace. + + \note The uri here may not necessarily be unique (e.g. for file imports). + + \note Version numbers may be -1 for file imports: this means that no + version was specified as part of the import. Type resolution will be + responsible for attempting to find the "best" possible version. + */ struct Import { - QString uri; - QString url; - int majversion; - int minversion; - bool isLibrary; - QQmlDirComponents qmlDirComponents; - QQmlDirScripts qmlDirScripts; + QString uri; // e.g. QtQuick + QString url; // the base path of the import + int majversion; // the major version imported + int minversion; // the minor version imported + bool isLibrary; // true means that this is not a file import + QQmlDirComponents qmlDirComponents; // a copy of the components listed in the qmldir + QQmlDirScripts qmlDirScripts; // a copy of the scripts in the qmldir bool setQmldirContent(const QString &resolvedUrl, const QQmlTypeLoader::QmldirContent *qmldir, QQmlImportNamespace *nameSpace, QList<QQmlError> *errors); @@ -273,9 +334,12 @@ public: QString base; int ref; + // storage of data related to imports without a namespace mutable QQmlImportNamespace unqualifiedset; QQmlImportNamespace *findQualifiedNamespace(const QHashedStringRef &) const; + + // storage of data related to imports with a namespace mutable QFieldList<QQmlImportNamespace, &QQmlImportNamespace::nextNamespace> qualifiedSets; QQmlTypeLoader *typeLoader; @@ -683,15 +747,17 @@ bool QQmlImportNamespace::Import::resolveType(QQmlTypeLoader *typeLoader, if ((candidate == end) || (c.majorVersion > candidate->majorVersion) || ((c.majorVersion == candidate->majorVersion) && (c.minorVersion > candidate->minorVersion))) { - componentUrl = resolveLocalUrl(QString(url + c.typeName + dotqml_string), c.fileName); - if (c.internal && base) { - if (resolveLocalUrl(*base, c.fileName) != componentUrl) - continue; // failed attempt to access an internal type - } - if (base && (*base == componentUrl)) { - if (typeRecursionDetected) - *typeRecursionDetected = true; - continue; // no recursion + if (base) { + componentUrl = resolveLocalUrl(QString(url + c.typeName + dotqml_string), c.fileName); + if (c.internal) { + if (resolveLocalUrl(*base, c.fileName) != componentUrl) + continue; // failed attempt to access an internal type + } + if (*base == componentUrl) { + if (typeRecursionDetected) + *typeRecursionDetected = true; + continue; // no recursion + } } // This is our best candidate so far @@ -702,9 +768,11 @@ bool QQmlImportNamespace::Import::resolveType(QQmlTypeLoader *typeLoader, } if (candidate != end) { + if (!base) // ensure we have a componentUrl + componentUrl = resolveLocalUrl(QString(url + candidate->typeName + dotqml_string), candidate->fileName); int major = vmajor ? *vmajor : -1; int minor = vminor ? *vminor : -1; - QQmlType *returnType = getTypeForUrl(componentUrl, type, isCompositeSingleton, 0, + QQmlType *returnType = fetchOrCreateTypeForUrl(componentUrl, type, isCompositeSingleton, 0, major, minor); if (type_return) *type_return = returnType; @@ -732,7 +800,7 @@ bool QQmlImportNamespace::Import::resolveType(QQmlTypeLoader *typeLoader, if (typeRecursionDetected) *typeRecursionDetected = true; } else { - QQmlType *returnType = getTypeForUrl(qmlUrl, type, false, 0); + QQmlType *returnType = fetchOrCreateTypeForUrl(qmlUrl, type, false, 0); if (type_return) *type_return = returnType; return returnType != 0; @@ -777,7 +845,7 @@ bool QQmlImportsPrivate::resolveType(const QHashedStringRef& type, int *vmajor, return true; if (s->imports.count() == 1 && !s->imports.at(0)->isLibrary && type_return && s != &unqualifiedset) { // qualified, and only 1 url - *type_return = getTypeForUrl(resolveLocalUrl(s->imports.at(0)->url, unqualifiedtype.toString() + QLatin1String(".qml")), type, false, errors); + *type_return = fetchOrCreateTypeForUrl(resolveLocalUrl(s->imports.at(0)->url, unqualifiedtype.toString() + QLatin1String(".qml")), type, false, errors); return (*type_return != 0); } } diff --git a/src/qml/qml/qqmlincubator.cpp b/src/qml/qml/qqmlincubator.cpp index 963638ca34..54d0b240f5 100644 --- a/src/qml/qml/qqmlincubator.cpp +++ b/src/qml/qml/qqmlincubator.cpp @@ -380,6 +380,23 @@ finishIncubate: } } +void QQmlIncubatorPrivate::cancel(QObject *object, QQmlContext *context) +{ + if (!context) + context = qmlContext(object); + if (!context) + return; + + QQmlContextData *data = QQmlContextData::get(context); + QQmlIncubatorPrivate *p = (QQmlIncubatorPrivate *)data->activeVMEData; + if (!p) + return; + + p->vmeGuard.unguard(object); + if (!p->creator.isNull()) + p->creator->cancel(object); +} + /*! Incubate objects for \a msecs, or until there are no more objects to incubate. */ diff --git a/src/qml/qml/qqmlincubator_p.h b/src/qml/qml/qqmlincubator_p.h index ecf3b6d2ca..758e0a29f6 100644 --- a/src/qml/qml/qqmlincubator_p.h +++ b/src/qml/qml/qqmlincubator_p.h @@ -40,6 +40,8 @@ #ifndef QQMLINCUBATOR_P_H #define QQMLINCUBATOR_P_H +#include "qqmlincubator.h" + #include <private/qintrusivelist_p.h> #include <private/qqmlvme_p.h> #include <private/qrecursionwatcher_p.h> @@ -100,6 +102,9 @@ public: void forceCompletion(QQmlInstantiationInterrupt &i); void incubate(QQmlInstantiationInterrupt &i); + + // used by Qt Quick Controls 2 + Q_QML_PRIVATE_EXPORT static void cancel(QObject *object, QQmlContext *context = 0); }; QT_END_NAMESPACE diff --git a/src/qml/qml/qqmlinfo.cpp b/src/qml/qml/qqmlinfo.cpp index 5b6e02d5b1..dae15e2eca 100644 --- a/src/qml/qml/qqmlinfo.cpp +++ b/src/qml/qml/qqmlinfo.cpp @@ -50,13 +50,45 @@ QT_BEGIN_NAMESPACE /*! + \fn QQmlInfo QtQml::qmlDebug(const QObject *object) + \relates QQmlEngine + \since 5.9 + + Prints debug messages that include the file and line number for the + specified QML \a object. + + When QML types produce logging messages, it improves traceability + if they include the QML file and line number on which the + particular instance was instantiated. + + To include the file and line number, an object must be passed. If + the file and line number is not available for that instance + (either it was not instantiated by the QML engine or location + information is disabled), "unknown location" will be used instead. + + For example, + + \code + qmlDebug(object) << "Internal state: 42"; + \endcode + + prints + + \code + QML MyCustomType (unknown location): Internal state: 42 + \endcode + + \sa QtQml::qmlInfo, QtQml::qmlWarning +*/ + +/*! \fn QQmlInfo QtQml::qmlInfo(const QObject *object) \relates QQmlEngine - Prints warning messages that include the file and line number for the + Prints informational messages that include the file and line number for the specified QML \a object. - When QML types display warning messages, it improves traceability + When QML types produce logging messages, it improves traceability if they include the QML file and line number on which the particular instance was instantiated. @@ -76,14 +108,58 @@ QT_BEGIN_NAMESPACE \code QML MyCustomType (unknown location): component property is a write-once property \endcode + + \note In versions prior to Qt 5.9, qmlInfo reported messages using a warning + QtMsgType. For Qt 5.9 and above, qmlInfo uses an info QtMsgType. To send + warnings, use qmlWarning. + + \sa QtQml::qmlDebug, QtQml::qmlWarning +*/ + + +/*! + \fn QQmlInfo QtQml::qmlWarning(const QObject *object) + \relates QQmlEngine + \since 5.9 + + Prints warning messages that include the file and line number for the + specified QML \a object. + + When QML types produce logging messages, it improves traceability + if they include the QML file and line number on which the + particular instance was instantiated. + + To include the file and line number, an object must be passed. If + the file and line number is not available for that instance + (either it was not instantiated by the QML engine or location + information is disabled), "unknown location" will be used instead. + + For example, + + \code + qmlInfo(object) << tr("property cannot be set to 0"); + \endcode + + prints + + \code + QML MyCustomType (unknown location): property cannot be set to 0 + \endcode + + \sa QtQml::qmlDebug, QtQml::qmlInfo */ class QQmlInfoPrivate { public: - QQmlInfoPrivate() : ref (1), object(0) {} + QQmlInfoPrivate(QtMsgType type) + : ref (1) + , msgType(type) + , object(nullptr) + {} int ref; + QtMsgType msgType; const QObject *object; QString buffer; QList<QQmlError> errors; @@ -110,6 +186,7 @@ QQmlInfo::~QQmlInfo() if (!d->buffer.isEmpty()) { QQmlError error; + error.setMessageType(d->msgType); QObject *object = const_cast<QObject *>(d->object); @@ -139,28 +216,32 @@ QQmlInfo::~QQmlInfo() namespace QtQml { -QQmlInfo qmlInfo(const QObject *me) -{ - QQmlInfoPrivate *d = new QQmlInfoPrivate; - d->object = me; - return QQmlInfo(d); -} +#define MESSAGE_FUNCS(FuncName, MessageLevel) \ + QQmlInfo FuncName(const QObject *me) \ + { \ + QQmlInfoPrivate *d = new QQmlInfoPrivate(MessageLevel); \ + d->object = me; \ + return QQmlInfo(d); \ + } \ + QQmlInfo FuncName(const QObject *me, const QQmlError &error) \ + { \ + QQmlInfoPrivate *d = new QQmlInfoPrivate(MessageLevel); \ + d->object = me; \ + d->errors << error; \ + return QQmlInfo(d); \ + } \ + QQmlInfo FuncName(const QObject *me, const QList<QQmlError> &errors) \ + { \ + QQmlInfoPrivate *d = new QQmlInfoPrivate(MessageLevel); \ + d->object = me; \ + d->errors = errors; \ + return QQmlInfo(d); \ + } -QQmlInfo qmlInfo(const QObject *me, const QQmlError &error) -{ - QQmlInfoPrivate *d = new QQmlInfoPrivate; - d->object = me; - d->errors << error; - return QQmlInfo(d); -} +MESSAGE_FUNCS(qmlDebug, QtMsgType::QtDebugMsg) +MESSAGE_FUNCS(qmlInfo, QtMsgType::QtInfoMsg) +MESSAGE_FUNCS(qmlWarning, QtMsgType::QtWarningMsg) -QQmlInfo qmlInfo(const QObject *me, const QList<QQmlError> &errors) -{ - QQmlInfoPrivate *d = new QQmlInfoPrivate; - d->object = me; - d->errors = errors; - return QQmlInfo(d); -} } // namespace QtQml diff --git a/src/qml/qml/qqmlinfo.h b/src/qml/qml/qqmlinfo.h index ab0281a688..673125632e 100644 --- a/src/qml/qml/qqmlinfo.h +++ b/src/qml/qml/qqmlinfo.h @@ -48,11 +48,19 @@ QT_BEGIN_NAMESPACE class QQmlInfo; +// declared in namespace to avoid symbol conflicts with QtDeclarative namespace QtQml { - // declared in namespace to avoid symbol conflicts with QtDeclarative + Q_QML_EXPORT QQmlInfo qmlDebug(const QObject *me); + Q_QML_EXPORT QQmlInfo qmlDebug(const QObject *me, const QQmlError &error); + Q_QML_EXPORT QQmlInfo qmlDebug(const QObject *me, const QList<QQmlError> &errors); + Q_QML_EXPORT QQmlInfo qmlInfo(const QObject *me); Q_QML_EXPORT QQmlInfo qmlInfo(const QObject *me, const QQmlError &error); Q_QML_EXPORT QQmlInfo qmlInfo(const QObject *me, const QList<QQmlError> &errors); + + Q_QML_EXPORT QQmlInfo qmlWarning(const QObject *me); + Q_QML_EXPORT QQmlInfo qmlWarning(const QObject *me, const QQmlError &error); + Q_QML_EXPORT QQmlInfo qmlWarning(const QObject *me, const QList<QQmlError> &errors); } QT_WARNING_PUSH QT_WARNING_DISABLE_CLANG("-Wheader-hygiene") @@ -93,9 +101,15 @@ public: #endif private: + friend Q_QML_EXPORT QQmlInfo QtQml::qmlDebug(const QObject *me); + friend Q_QML_EXPORT QQmlInfo QtQml::qmlDebug(const QObject *me, const QQmlError &error); + friend Q_QML_EXPORT QQmlInfo QtQml::qmlDebug(const QObject *me, const QList<QQmlError> &errors); friend Q_QML_EXPORT QQmlInfo QtQml::qmlInfo(const QObject *me); friend Q_QML_EXPORT QQmlInfo QtQml::qmlInfo(const QObject *me, const QQmlError &error); friend Q_QML_EXPORT QQmlInfo QtQml::qmlInfo(const QObject *me, const QList<QQmlError> &errors); + friend Q_QML_EXPORT QQmlInfo QtQml::qmlWarning(const QObject *me); + friend Q_QML_EXPORT QQmlInfo QtQml::qmlWarning(const QObject *me, const QQmlError &error); + friend Q_QML_EXPORT QQmlInfo QtQml::qmlWarning(const QObject *me, const QList<QQmlError> &errors); QQmlInfo(QQmlInfoPrivate *); QQmlInfoPrivate *d; diff --git a/src/qml/qml/qqmllist.cpp b/src/qml/qml/qqmllist.cpp index a719956483..edd93ef03d 100644 --- a/src/qml/qml/qqmllist.cpp +++ b/src/qml/qml/qqmllist.cpp @@ -335,7 +335,7 @@ int QQmlListReference::count() const \since 5.0 \inmodule QtQml \brief The QQmlListProperty class allows applications to expose list-like -properties to QML. +properties of QObject-derived classes to QML. QML has many list properties, where more than one object value can be assigned. The use of a list property from QML looks like this: @@ -369,7 +369,8 @@ QML list properties are type-safe - in this case \c {Fruit} is a QObject type th The \l {Qt Quick 1} version of this class is named QDeclarativeListProperty. -\note QQmlListProperty can only be used for lists of QObject-derived object pointers. +\sa {Extending QML - Object and List Property Types Example} + */ /*! diff --git a/src/qml/qml/qqmllocale.cpp b/src/qml/qml/qqmllocale.cpp index 3876e774c3..712da78807 100644 --- a/src/qml/qml/qqmllocale.cpp +++ b/src/qml/qml/qqmllocale.cpp @@ -56,10 +56,17 @@ using namespace QV4; DEFINE_OBJECT_VTABLE(QQmlLocaleData); +#define THROW_ERROR(string) \ + do { \ + scope.result = scope.engine->throwError(QString::fromUtf8(string)); \ + return; \ + } while (false) + + #define GET_LOCALE_DATA_RESOURCE(OBJECT) \ QV4::Scoped<QQmlLocaleData> r(scope, OBJECT.as<QQmlLocaleData>()); \ if (!r) \ - V4THROW_ERROR("Not a valid Locale object") + THROW_ERROR("Not a valid Locale object") static bool isLocaleObject(const QV4::Value &val) { @@ -80,215 +87,219 @@ void QQmlDateExtension::registerExtension(QV4::ExecutionEngine *engine) engine->dateCtor()->defineDefaultProperty(QStringLiteral("timeZoneUpdated"), method_timeZoneUpdated); } -QV4::ReturnedValue QQmlDateExtension::method_toLocaleString(QV4::CallContext *ctx) +void QQmlDateExtension::method_toLocaleString(const BuiltinFunction *b, Scope &scope, CallData *callData) { - if (ctx->argc() > 2) - return QV4::DatePrototype::method_toLocaleString(ctx); - - QV4::Scope scope(ctx); + if (callData->argc > 2) { + QV4::DatePrototype::method_toLocaleString(b, scope, callData); + return; + } - QV4::DateObject *date = ctx->thisObject().as<DateObject>(); - if (!date) - return QV4::DatePrototype::method_toLocaleString(ctx); + QV4::DateObject *date = callData->thisObject.as<DateObject>(); + if (!date) { + QV4::DatePrototype::method_toLocaleString(b, scope, callData); + return; + } QDateTime dt = date->toQDateTime(); - if (ctx->argc() == 0) { + if (callData->argc == 0) { // Use QLocale for standard toLocaleString() function QLocale locale; - return ctx->d()->engine->newString(locale.toString(dt))->asReturnedValue(); + RETURN_RESULT(scope.engine->newString(locale.toString(dt))); } - if (!isLocaleObject(ctx->args()[0])) - return QV4::DatePrototype::method_toLocaleString(ctx); // Use the default Date toLocaleString() + if (!isLocaleObject(callData->args[0])) { + QV4::DatePrototype::method_toLocaleString(b, scope, callData); // Use the default Date toLocaleString() + return; + } - GET_LOCALE_DATA_RESOURCE(ctx->args()[0]); + GET_LOCALE_DATA_RESOURCE(callData->args[0]); QLocale::FormatType enumFormat = QLocale::LongFormat; QString formattedDt; - if (ctx->argc() == 2) { - if (String *s = ctx->args()[1].stringValue()) { + if (callData->argc == 2) { + if (String *s = callData->args[1].stringValue()) { QString format = s->toQString(); formattedDt = r->d()->locale->toString(dt, format); - } else if (ctx->args()[1].isNumber()) { - quint32 intFormat = ctx->args()[1].toNumber(); + } else if (callData->args[1].isNumber()) { + quint32 intFormat = callData->args[1].toNumber(); QLocale::FormatType format = QLocale::FormatType(intFormat); formattedDt = r->d()->locale->toString(dt, format); } else { - V4THROW_ERROR("Locale: Date.toLocaleString(): Invalid datetime format"); + THROW_ERROR("Locale: Date.toLocaleString(): Invalid datetime format"); } } else { formattedDt = r->d()->locale->toString(dt, enumFormat); } - return ctx->d()->engine->newString(formattedDt)->asReturnedValue(); + scope.result = scope.engine->newString(formattedDt); } -QV4::ReturnedValue QQmlDateExtension::method_toLocaleTimeString(QV4::CallContext *ctx) +void QQmlDateExtension::method_toLocaleTimeString(const BuiltinFunction *b, Scope &scope, CallData *callData) { - if (ctx->argc() > 2) - return QV4::DatePrototype::method_toLocaleTimeString(ctx); - - QV4::Scope scope(ctx); + if (callData->argc > 2) { + QV4::DatePrototype::method_toLocaleTimeString(b, scope, callData); + return; + } - QV4::DateObject *date = ctx->thisObject().as<DateObject>(); - if (!date) - return QV4::DatePrototype::method_toLocaleTimeString(ctx); + QV4::DateObject *date = callData->thisObject.as<DateObject>(); + if (!date) { + QV4::DatePrototype::method_toLocaleTimeString(b, scope, callData); + return; + } QDateTime dt = date->toQDateTime(); QTime time = dt.time(); - if (ctx->argc() == 0) { + if (callData->argc == 0) { // Use QLocale for standard toLocaleString() function QLocale locale; - return ctx->d()->engine->newString(locale.toString(time))->asReturnedValue(); + RETURN_RESULT(scope.engine->newString(locale.toString(time))); } - if (!isLocaleObject(ctx->args()[0])) - return QV4::DatePrototype::method_toLocaleTimeString(ctx); // Use the default Date toLocaleTimeString() + if (!isLocaleObject(callData->args[0])) + return QV4::DatePrototype::method_toLocaleTimeString(b, scope, callData); // Use the default Date toLocaleTimeString() - GET_LOCALE_DATA_RESOURCE(ctx->args()[0]); + GET_LOCALE_DATA_RESOURCE(callData->args[0]); QLocale::FormatType enumFormat = QLocale::LongFormat; QString formattedTime; - if (ctx->argc() == 2) { - if (String *s = ctx->args()[1].stringValue()) { + if (callData->argc == 2) { + if (String *s = callData->args[1].stringValue()) { QString format = s->toQString(); formattedTime = r->d()->locale->toString(time, format); - } else if (ctx->args()[1].isNumber()) { - quint32 intFormat = ctx->args()[1].toNumber(); + } else if (callData->args[1].isNumber()) { + quint32 intFormat = callData->args[1].toNumber(); QLocale::FormatType format = QLocale::FormatType(intFormat); formattedTime = r->d()->locale->toString(time, format); } else { - V4THROW_ERROR("Locale: Date.toLocaleTimeString(): Invalid time format"); + THROW_ERROR("Locale: Date.toLocaleTimeString(): Invalid time format"); } } else { formattedTime = r->d()->locale->toString(time, enumFormat); } - return ctx->d()->engine->newString(formattedTime)->asReturnedValue(); + scope.result = scope.engine->newString(formattedTime); } -QV4::ReturnedValue QQmlDateExtension::method_toLocaleDateString(QV4::CallContext *ctx) +void QQmlDateExtension::method_toLocaleDateString(const BuiltinFunction *b, Scope &scope, CallData *callData) { - if (ctx->argc() > 2) - return QV4::DatePrototype::method_toLocaleDateString(ctx); - - QV4::Scope scope(ctx); + if (callData->argc > 2) { + QV4::DatePrototype::method_toLocaleDateString(b, scope, callData); + return; + } - QV4::DateObject *dateObj = ctx->thisObject().as<DateObject>(); - if (!dateObj) - return QV4::DatePrototype::method_toLocaleDateString(ctx); + QV4::DateObject *dateObj = callData->thisObject.as<DateObject>(); + if (!dateObj) { + QV4::DatePrototype::method_toLocaleDateString(b, scope, callData); + return; + } QDateTime dt = dateObj->toQDateTime(); QDate date = dt.date(); - if (ctx->argc() == 0) { + if (callData->argc == 0) { // Use QLocale for standard toLocaleString() function QLocale locale; - return ctx->d()->engine->newString(locale.toString(date))->asReturnedValue(); + RETURN_RESULT(scope.engine->newString(locale.toString(date))); } - if (!isLocaleObject(ctx->args()[0])) - return QV4::DatePrototype::method_toLocaleDateString(ctx); // Use the default Date toLocaleDateString() + if (!isLocaleObject(callData->args[0])) + return QV4::DatePrototype::method_toLocaleDateString(b, scope, callData); // Use the default Date toLocaleDateString() - GET_LOCALE_DATA_RESOURCE(ctx->args()[0]); + GET_LOCALE_DATA_RESOURCE(callData->args[0]); QLocale::FormatType enumFormat = QLocale::LongFormat; QString formattedDate; - if (ctx->argc() == 2) { - if (String *s = ctx->args()[1].stringValue()) { + if (callData->argc == 2) { + if (String *s = callData->args[1].stringValue()) { QString format = s->toQString(); formattedDate = r->d()->locale->toString(date, format); - } else if (ctx->args()[1].isNumber()) { - quint32 intFormat = ctx->args()[1].toNumber(); + } else if (callData->args[1].isNumber()) { + quint32 intFormat = callData->args[1].toNumber(); QLocale::FormatType format = QLocale::FormatType(intFormat); formattedDate = r->d()->locale->toString(date, format); } else { - V4THROW_ERROR("Locale: Date.loLocaleDateString(): Invalid date format"); + THROW_ERROR("Locale: Date.loLocaleDateString(): Invalid date format"); } } else { formattedDate = r->d()->locale->toString(date, enumFormat); } - return ctx->d()->engine->newString(formattedDate)->asReturnedValue(); + scope.result = scope.engine->newString(formattedDate); } -QV4::ReturnedValue QQmlDateExtension::method_fromLocaleString(QV4::CallContext *ctx) +void QQmlDateExtension::method_fromLocaleString(const BuiltinFunction *, Scope &scope, CallData *callData) { - QV4::ExecutionEngine * const engine = ctx->d()->engine; - if (ctx->argc() == 1) { - if (String *s = ctx->args()[0].stringValue()) { + QV4::ExecutionEngine * const engine = scope.engine; + if (callData->argc == 1) { + if (String *s = callData->args[0].stringValue()) { QLocale locale; QString dateString = s->toQString(); QDateTime dt = locale.toDateTime(dateString); - return QV4::Encode(engine->newDateObject(dt)); + RETURN_RESULT(engine->newDateObject(dt)); } } - QV4::Scope scope(ctx); - - if (ctx->argc() < 1 || ctx->argc() > 3 || !isLocaleObject(ctx->args()[0])) - V4THROW_ERROR("Locale: Date.fromLocaleString(): Invalid arguments"); + if (callData->argc < 1 || callData->argc > 3 || !isLocaleObject(callData->args[0])) + THROW_ERROR("Locale: Date.fromLocaleString(): Invalid arguments"); - GET_LOCALE_DATA_RESOURCE(ctx->args()[0]); + GET_LOCALE_DATA_RESOURCE(callData->args[0]); QLocale::FormatType enumFormat = QLocale::LongFormat; QDateTime dt; - QString dateString = ctx->args()[1].toQStringNoThrow(); - if (ctx->argc() == 3) { - if (String *s = ctx->args()[2].stringValue()) { + QString dateString = callData->args[1].toQStringNoThrow(); + if (callData->argc == 3) { + if (String *s = callData->args[2].stringValue()) { QString format = s->toQString(); dt = r->d()->locale->toDateTime(dateString, format); - } else if (ctx->args()[2].isNumber()) { - quint32 intFormat = ctx->args()[2].toNumber(); + } else if (callData->args[2].isNumber()) { + quint32 intFormat = callData->args[2].toNumber(); QLocale::FormatType format = QLocale::FormatType(intFormat); dt = r->d()->locale->toDateTime(dateString, format); } else { - V4THROW_ERROR("Locale: Date.fromLocaleString(): Invalid datetime format"); + THROW_ERROR("Locale: Date.fromLocaleString(): Invalid datetime format"); } } else { dt = r->d()->locale->toDateTime(dateString, enumFormat); } - return QV4::Encode(engine->newDateObject(dt)); + scope.result = engine->newDateObject(dt); } -QV4::ReturnedValue QQmlDateExtension::method_fromLocaleTimeString(QV4::CallContext *ctx) +void QQmlDateExtension::method_fromLocaleTimeString(const BuiltinFunction *, Scope &scope, CallData *callData) { - QV4::ExecutionEngine * const engine = ctx->d()->engine; + QV4::ExecutionEngine * const engine = scope.engine; - if (ctx->argc() == 1) { - if (String *s = ctx->args()[0].stringValue()) { + if (callData->argc == 1) { + if (String *s = callData->args[0].stringValue()) { QLocale locale; QString timeString = s->toQString(); QTime time = locale.toTime(timeString); QDateTime dt = QDateTime::currentDateTime(); dt.setTime(time); - return QV4::Encode(engine->newDateObject(dt)); + RETURN_RESULT(engine->newDateObject(dt)); } } - if (ctx->argc() < 1 || ctx->argc() > 3 || !isLocaleObject(ctx->args()[0])) - V4THROW_ERROR("Locale: Date.fromLocaleTimeString(): Invalid arguments"); - - QV4::Scope scope(ctx); + if (callData->argc < 1 || callData->argc > 3 || !isLocaleObject(callData->args[0])) + THROW_ERROR("Locale: Date.fromLocaleTimeString(): Invalid arguments"); - GET_LOCALE_DATA_RESOURCE(ctx->args()[0]); + GET_LOCALE_DATA_RESOURCE(callData->args[0]); QLocale::FormatType enumFormat = QLocale::LongFormat; QTime tm; - QString dateString = ctx->args()[1].toQStringNoThrow(); - if (ctx->argc() == 3) { - if (String *s = ctx->args()[2].stringValue()) { + QString dateString = callData->args[1].toQStringNoThrow(); + if (callData->argc == 3) { + if (String *s = callData->args[2].stringValue()) { QString format = s->toQString(); tm = r->d()->locale->toTime(dateString, format); - } else if (ctx->args()[2].isNumber()) { - quint32 intFormat = ctx->args()[2].toNumber(); + } else if (callData->args[2].isNumber()) { + quint32 intFormat = callData->args[2].toNumber(); QLocale::FormatType format = QLocale::FormatType(intFormat); tm = r->d()->locale->toTime(dateString, format); } else { - V4THROW_ERROR("Locale: Date.fromLocaleTimeString(): Invalid datetime format"); + THROW_ERROR("Locale: Date.fromLocaleTimeString(): Invalid datetime format"); } } else { tm = r->d()->locale->toTime(dateString, enumFormat); @@ -300,58 +311,56 @@ QV4::ReturnedValue QQmlDateExtension::method_fromLocaleTimeString(QV4::CallConte dt.setTime(tm); } - return QV4::Encode(engine->newDateObject(dt)); + RETURN_RESULT(engine->newDateObject(dt)); } -QV4::ReturnedValue QQmlDateExtension::method_fromLocaleDateString(QV4::CallContext *ctx) +void QQmlDateExtension::method_fromLocaleDateString(const BuiltinFunction *, Scope &scope, CallData *callData) { - QV4::ExecutionEngine * const engine = ctx->d()->engine; + QV4::ExecutionEngine * const engine = scope.engine; - if (ctx->argc() == 1) { - if (String *s = ctx->args()[0].stringValue()) { + if (callData->argc == 1) { + if (String *s = callData->args[0].stringValue()) { QLocale locale; QString dateString = s->toQString(); QDate date = locale.toDate(dateString); - return QV4::Encode(engine->newDateObject(QDateTime(date))); + RETURN_RESULT(engine->newDateObject(QDateTime(date))); } } - if (ctx->argc() < 1 || ctx->argc() > 3 || !isLocaleObject(ctx->args()[0])) - V4THROW_ERROR("Locale: Date.fromLocaleDateString(): Invalid arguments"); + if (callData->argc < 1 || callData->argc > 3 || !isLocaleObject(callData->args[0])) + THROW_ERROR("Locale: Date.fromLocaleDateString(): Invalid arguments"); - QV4::Scope scope(ctx); - - GET_LOCALE_DATA_RESOURCE(ctx->args()[0]); + GET_LOCALE_DATA_RESOURCE(callData->args[0]); QLocale::FormatType enumFormat = QLocale::LongFormat; QDate dt; - QString dateString = ctx->args()[1].toQStringNoThrow(); - if (ctx->argc() == 3) { - if (String *s = ctx->args()[2].stringValue()) { + QString dateString = callData->args[1].toQStringNoThrow(); + if (callData->argc == 3) { + if (String *s = callData->args[2].stringValue()) { QString format = s->toQString(); dt = r->d()->locale->toDate(dateString, format); - } else if (ctx->args()[2].isNumber()) { - quint32 intFormat = ctx->args()[2].toNumber(); + } else if (callData->args[2].isNumber()) { + quint32 intFormat = callData->args[2].toNumber(); QLocale::FormatType format = QLocale::FormatType(intFormat); dt = r->d()->locale->toDate(dateString, format); } else { - V4THROW_ERROR("Locale: Date.fromLocaleDateString(): Invalid datetime format"); + THROW_ERROR("Locale: Date.fromLocaleDateString(): Invalid datetime format"); } } else { dt = r->d()->locale->toDate(dateString, enumFormat); } - return QV4::Encode(engine->newDateObject(QDateTime(dt))); + RETURN_RESULT(engine->newDateObject(QDateTime(dt))); } -QV4::ReturnedValue QQmlDateExtension::method_timeZoneUpdated(QV4::CallContext *ctx) +void QQmlDateExtension::method_timeZoneUpdated(const BuiltinFunction *, Scope &scope, CallData *callData) { - if (ctx->argc() != 0) - V4THROW_ERROR("Locale: Date.timeZoneUpdated(): Invalid arguments"); + if (callData->argc != 0) + THROW_ERROR("Locale: Date.timeZoneUpdated(): Invalid arguments"); QV4::DatePrototype::timezoneUpdated(); - return QV4::Encode::undefined(); + RETURN_UNDEFINED(); } //----------------- @@ -364,148 +373,143 @@ void QQmlNumberExtension::registerExtension(QV4::ExecutionEngine *engine) engine->numberCtor()->defineDefaultProperty(QStringLiteral("fromLocaleString"), method_fromLocaleString); } -QV4::ReturnedValue QQmlNumberExtension::method_toLocaleString(QV4::CallContext *ctx) +void QQmlNumberExtension::method_toLocaleString(const BuiltinFunction *b, Scope &scope, CallData *callData) { - if (ctx->argc() > 3) - V4THROW_ERROR("Locale: Number.toLocaleString(): Invalid arguments"); + if (callData->argc > 3) + THROW_ERROR("Locale: Number.toLocaleString(): Invalid arguments"); - double number = ctx->thisObject().toNumber(); + double number = callData->thisObject.toNumber(); - if (ctx->argc() == 0) { + if (callData->argc == 0) { // Use QLocale for standard toLocaleString() function QLocale locale; - return ctx->d()->engine->newString(locale.toString(number))->asReturnedValue(); + RETURN_RESULT(scope.engine->newString(locale.toString(number))); } - if (!isLocaleObject(ctx->args()[0])) - return QV4::NumberPrototype::method_toLocaleString(ctx); // Use the default Number toLocaleString() - - QV4::Scope scope(ctx); + if (!isLocaleObject(callData->args[0])) { + QV4::NumberPrototype::method_toLocaleString(b, scope, callData); // Use the default Number toLocaleString() + return; + } - GET_LOCALE_DATA_RESOURCE(ctx->args()[0]); + GET_LOCALE_DATA_RESOURCE(callData->args[0]); quint16 format = 'f'; - if (ctx->argc() > 1) { - if (!ctx->args()[1].isString()) - V4THROW_ERROR("Locale: Number.toLocaleString(): Invalid arguments"); - QString fs = ctx->args()[1].toQString(); + if (callData->argc > 1) { + if (!callData->args[1].isString()) + THROW_ERROR("Locale: Number.toLocaleString(): Invalid arguments"); + QString fs = callData->args[1].toQString(); if (fs.length()) format = fs.at(0).unicode(); } int prec = 2; - if (ctx->argc() > 2) { - if (!ctx->args()[2].isNumber()) - V4THROW_ERROR("Locale: Number.toLocaleString(): Invalid arguments"); - prec = ctx->args()[2].toInt32(); + if (callData->argc > 2) { + if (!callData->args[2].isNumber()) + THROW_ERROR("Locale: Number.toLocaleString(): Invalid arguments"); + prec = callData->args[2].toInt32(); } - return ctx->d()->engine->newString(r->d()->locale->toString(number, (char)format, prec))->asReturnedValue(); + scope.result = scope.engine->newString(r->d()->locale->toString(number, (char)format, prec)); } -QV4::ReturnedValue QQmlNumberExtension::method_toLocaleCurrencyString(QV4::CallContext *ctx) +void QQmlNumberExtension::method_toLocaleCurrencyString(const BuiltinFunction *, Scope &scope, CallData *callData) { - if (ctx->argc() > 2) - V4THROW_ERROR("Locale: Number.toLocaleCurrencyString(): Invalid arguments"); + if (callData->argc > 2) + THROW_ERROR("Locale: Number.toLocaleCurrencyString(): Invalid arguments"); - double number = ctx->thisObject().toNumber(); + double number = callData->thisObject.toNumber(); - if (ctx->argc() == 0) { + if (callData->argc == 0) { // Use QLocale for standard toLocaleString() function QLocale locale; - return ctx->d()->engine->newString(locale.toString(number))->asReturnedValue(); + RETURN_RESULT(scope.engine->newString(locale.toString(number))); } - if (!isLocaleObject(ctx->args()[0])) - V4THROW_ERROR("Locale: Number.toLocaleCurrencyString(): Invalid arguments"); - - QV4::Scope scope(ctx); + if (!isLocaleObject(callData->args[0])) + THROW_ERROR("Locale: Number.toLocaleCurrencyString(): Invalid arguments"); - GET_LOCALE_DATA_RESOURCE(ctx->args()[0]); + GET_LOCALE_DATA_RESOURCE(callData->args[0]); QString symbol; - if (ctx->argc() > 1) { - if (!ctx->args()[1].isString()) - V4THROW_ERROR("Locale: Number.toLocaleString(): Invalid arguments"); - symbol = ctx->args()[1].toQStringNoThrow(); + if (callData->argc > 1) { + if (!callData->args[1].isString()) + THROW_ERROR("Locale: Number.toLocaleString(): Invalid arguments"); + symbol = callData->args[1].toQStringNoThrow(); } - return ctx->d()->engine->newString(r->d()->locale->toCurrencyString(number, symbol))->asReturnedValue(); + RETURN_RESULT(scope.engine->newString(r->d()->locale->toCurrencyString(number, symbol))); } -QV4::ReturnedValue QQmlNumberExtension::method_fromLocaleString(QV4::CallContext *ctx) +void QQmlNumberExtension::method_fromLocaleString(const BuiltinFunction *, Scope &scope, CallData *callData) { - if (ctx->argc() < 1 || ctx->argc() > 2) - V4THROW_ERROR("Locale: Number.fromLocaleString(): Invalid arguments"); + if (callData->argc < 1 || callData->argc > 2) + THROW_ERROR("Locale: Number.fromLocaleString(): Invalid arguments"); int numberIdx = 0; QLocale locale; - QV4::Scope scope(ctx); - - if (ctx->argc() == 2) { - if (!isLocaleObject(ctx->args()[0])) - V4THROW_ERROR("Locale: Number.fromLocaleString(): Invalid arguments"); + if (callData->argc == 2) { + if (!isLocaleObject(callData->args[0])) + THROW_ERROR("Locale: Number.fromLocaleString(): Invalid arguments"); - GET_LOCALE_DATA_RESOURCE(ctx->args()[0]); + GET_LOCALE_DATA_RESOURCE(callData->args[0]); locale = *r->d()->locale; numberIdx = 1; } - QString ns = ctx->args()[numberIdx].toQString(); + QString ns = callData->args[numberIdx].toQString(); if (!ns.length()) - return QV4::Encode(Q_QNAN); + RETURN_RESULT(QV4::Encode(Q_QNAN)); bool ok = false; double val = locale.toDouble(ns, &ok); if (!ok) - V4THROW_ERROR("Locale: Number.fromLocaleString(): Invalid format") + THROW_ERROR("Locale: Number.fromLocaleString(): Invalid format"); - return QV4::Encode(val); + scope.result = QV4::Encode(val); } //-------------- // Locale object -QV4::ReturnedValue QQmlLocaleData::method_get_firstDayOfWeek(QV4::CallContext *ctx) +void QQmlLocaleData::method_get_firstDayOfWeek(const BuiltinFunction *, Scope &scope, CallData *callData) { - QLocale *locale = getThisLocale(ctx); + QLocale *locale = getThisLocale(scope, callData); if (!locale) - return QV4::Encode::undefined(); + return; int fdow = int(locale->firstDayOfWeek()); if (fdow == 7) fdow = 0; // Qt::Sunday = 7, but Sunday is 0 in JS Date - return QV4::Encode(fdow); + scope.result = QV4::Encode(fdow); } -QV4::ReturnedValue QQmlLocaleData::method_get_measurementSystem(QV4::CallContext *ctx) +void QQmlLocaleData::method_get_measurementSystem(const BuiltinFunction *, Scope &scope, CallData *callData) { - QLocale *locale = getThisLocale(ctx); + QLocale *locale = getThisLocale(scope, callData); if (!locale) - return QV4::Encode::undefined(); - return QV4::Encode(locale->measurementSystem()); + return; + scope.result = QV4::Encode(locale->measurementSystem()); } -QV4::ReturnedValue QQmlLocaleData::method_get_textDirection(QV4::CallContext *ctx) +void QQmlLocaleData::method_get_textDirection(const BuiltinFunction *, Scope &scope, CallData *callData) { - QLocale *locale = getThisLocale(ctx); + QLocale *locale = getThisLocale(scope, callData); if (!locale) - return QV4::Encode::undefined(); + return; - return QV4::Encode(locale->textDirection()); + scope.result = QV4::Encode(locale->textDirection()); } -QV4::ReturnedValue QQmlLocaleData::method_get_weekDays(QV4::CallContext *ctx) +void QQmlLocaleData::method_get_weekDays(const BuiltinFunction *, Scope &scope, CallData *callData) { - QV4::Scope scope(ctx); - QLocale *locale = getThisLocale(ctx); + QLocale *locale = getThisLocale(scope, callData); if (!locale) - return QV4::Encode::undefined(); + return; QList<Qt::DayOfWeek> days = locale->weekdays(); - QV4::ScopedArrayObject result(scope, ctx->d()->engine->newArrayObject()); + QV4::ScopedArrayObject result(scope, scope.engine->newArrayObject()); result->arrayReserve(days.size()); for (int i = 0; i < days.size(); ++i) { int day = days.at(i); @@ -515,59 +519,58 @@ QV4::ReturnedValue QQmlLocaleData::method_get_weekDays(QV4::CallContext *ctx) } result->setArrayLengthUnchecked(days.size()); - return result.asReturnedValue(); + scope.result = result.asReturnedValue(); } -QV4::ReturnedValue QQmlLocaleData::method_get_uiLanguages(QV4::CallContext *ctx) +void QQmlLocaleData::method_get_uiLanguages(const BuiltinFunction *, Scope &scope, CallData *callData) { - QV4::Scope scope(ctx); - QLocale *locale = getThisLocale(ctx); + QLocale *locale = getThisLocale(scope, callData); if (!locale) - return QV4::Encode::undefined(); + return; QStringList langs = locale->uiLanguages(); - QV4::ScopedArrayObject result(scope, ctx->d()->engine->newArrayObject()); + QV4::ScopedArrayObject result(scope, scope.engine->newArrayObject()); result->arrayReserve(langs.size()); QV4::ScopedValue v(scope); for (int i = 0; i < langs.size(); ++i) - result->arrayPut(i, (v = ctx->d()->engine->newString(langs.at(i)))); + result->arrayPut(i, (v = scope.engine->newString(langs.at(i)))); result->setArrayLengthUnchecked(langs.size()); - return result.asReturnedValue(); + scope.result = result.asReturnedValue(); } -QV4::ReturnedValue QQmlLocaleData::method_currencySymbol(QV4::CallContext *ctx) +void QQmlLocaleData::method_currencySymbol(const BuiltinFunction *, Scope &scope, CallData *callData) { - QLocale *locale = getThisLocale(ctx); + QLocale *locale = getThisLocale(scope, callData); if (!locale) - return QV4::Encode::undefined(); + return; - if (ctx->argc() > 1) - V4THROW_ERROR("Locale: currencySymbol(): Invalid arguments"); + if (callData->argc > 1) + THROW_ERROR("Locale: currencySymbol(): Invalid arguments"); QLocale::CurrencySymbolFormat format = QLocale::CurrencySymbol; - if (ctx->argc() == 1) { - quint32 intFormat = ctx->args()[0].toNumber(); + if (callData->argc == 1) { + quint32 intFormat = callData->args[0].toNumber(); format = QLocale::CurrencySymbolFormat(intFormat); } - return ctx->d()->engine->newString(locale->currencySymbol(format))->asReturnedValue(); + scope.result = scope.engine->newString(locale->currencySymbol(format)); } #define LOCALE_FORMAT(FUNC) \ -QV4::ReturnedValue QQmlLocaleData::method_ ##FUNC (QV4::CallContext *ctx) { \ - QLocale *locale = getThisLocale(ctx); \ +void QQmlLocaleData::method_ ##FUNC (const BuiltinFunction *, Scope &scope, CallData *callData) { \ + QLocale *locale = getThisLocale(scope, callData); \ if (!locale) \ - return QV4::Encode::undefined(); \ - if (ctx->argc() > 1) \ - V4THROW_ERROR("Locale: " #FUNC "(): Invalid arguments"); \ + return; \ + if (callData->argc > 1) \ + THROW_ERROR("Locale: " #FUNC "(): Invalid arguments"); \ QLocale::FormatType format = QLocale::LongFormat;\ - if (ctx->argc() == 1) { \ - quint32 intFormat = ctx->args()[0].toUInt32(); \ + if (callData->argc == 1) { \ + quint32 intFormat = callData->args[0].toUInt32(); \ format = QLocale::FormatType(intFormat); \ } \ - return ctx->engine()->newString(locale-> FUNC (format))->asReturnedValue(); \ + scope.result = scope.engine->newString(locale-> FUNC (format)); \ } LOCALE_FORMAT(dateTimeFormat) @@ -576,57 +579,57 @@ LOCALE_FORMAT(dateFormat) // +1 added to idx because JS is 0-based, whereas QLocale months begin at 1. #define LOCALE_FORMATTED_MONTHNAME(VARIABLE) \ -QV4::ReturnedValue QQmlLocaleData::method_ ## VARIABLE (QV4::CallContext *ctx) {\ - QLocale *locale = getThisLocale(ctx); \ +void QQmlLocaleData::method_ ## VARIABLE (const BuiltinFunction *, Scope &scope, CallData *callData) {\ + QLocale *locale = getThisLocale(scope, callData); \ if (!locale) \ - return QV4::Encode::undefined(); \ - if (ctx->argc() < 1 || ctx->argc() > 2) \ - V4THROW_ERROR("Locale: " #VARIABLE "(): Invalid arguments"); \ + return; \ + if (callData->argc < 1 || callData->argc > 2) \ + THROW_ERROR("Locale: " #VARIABLE "(): Invalid arguments"); \ QLocale::FormatType enumFormat = QLocale::LongFormat; \ - int idx = ctx->args()[0].toInt32() + 1; \ + int idx = callData->args[0].toInt32() + 1; \ if (idx < 1 || idx > 12) \ - V4THROW_ERROR("Locale: Invalid month"); \ + THROW_ERROR("Locale: Invalid month"); \ QString name; \ - if (ctx->argc() == 2) { \ - if (ctx->args()[1].isNumber()) { \ - quint32 intFormat = ctx->args()[1].toUInt32(); \ + if (callData->argc == 2) { \ + if (callData->args[1].isNumber()) { \ + quint32 intFormat = callData->args[1].toUInt32(); \ QLocale::FormatType format = QLocale::FormatType(intFormat); \ name = locale-> VARIABLE(idx, format); \ } else { \ - V4THROW_ERROR("Locale: Invalid datetime format"); \ + THROW_ERROR("Locale: Invalid datetime format"); \ } \ } else { \ name = locale-> VARIABLE(idx, enumFormat); \ } \ - return ctx->engine()->newString(name)->asReturnedValue(); \ + scope.result = scope.engine->newString(name); \ } // 0 -> 7 as Qt::Sunday is 7, but Sunday is 0 in JS Date #define LOCALE_FORMATTED_DAYNAME(VARIABLE) \ -QV4::ReturnedValue QQmlLocaleData::method_ ## VARIABLE (QV4::CallContext *ctx) {\ - QLocale *locale = getThisLocale(ctx); \ +void QQmlLocaleData::method_ ## VARIABLE (const BuiltinFunction *, Scope &scope, CallData *callData) {\ + QLocale *locale = getThisLocale(scope, callData); \ if (!locale) \ - return QV4::Encode::undefined(); \ - if (ctx->argc() < 1 || ctx->argc() > 2) \ - V4THROW_ERROR("Locale: " #VARIABLE "(): Invalid arguments"); \ + return; \ + if (callData->argc < 1 || callData->argc > 2) \ + THROW_ERROR("Locale: " #VARIABLE "(): Invalid arguments"); \ QLocale::FormatType enumFormat = QLocale::LongFormat; \ - int idx = ctx->args()[0].toInt32(); \ + int idx = callData->args[0].toInt32(); \ if (idx < 0 || idx > 7) \ - V4THROW_ERROR("Locale: Invalid day"); \ + THROW_ERROR("Locale: Invalid day"); \ if (idx == 0) idx = 7; \ QString name; \ - if (ctx->argc() == 2) { \ - if (ctx->args()[1].isNumber()) { \ - quint32 intFormat = ctx->args()[1].toUInt32(); \ + if (callData->argc == 2) { \ + if (callData->args[1].isNumber()) { \ + quint32 intFormat = callData->args[1].toUInt32(); \ QLocale::FormatType format = QLocale::FormatType(intFormat); \ name = locale-> VARIABLE(idx, format); \ } else { \ - V4THROW_ERROR("Locale: Invalid datetime format"); \ + THROW_ERROR("Locale: Invalid datetime format"); \ } \ } else { \ name = locale-> VARIABLE(idx, enumFormat); \ } \ - return ctx->engine()->newString(name)->asReturnedValue(); \ + scope.result = scope.engine->newString(name); \ } LOCALE_FORMATTED_MONTHNAME(monthName) @@ -634,12 +637,12 @@ LOCALE_FORMATTED_MONTHNAME(standaloneMonthName) LOCALE_FORMATTED_DAYNAME(dayName) LOCALE_FORMATTED_DAYNAME(standaloneDayName) -#define LOCALE_STRING_PROPERTY(VARIABLE) QV4::ReturnedValue QQmlLocaleData::method_get_ ## VARIABLE (QV4::CallContext* ctx) \ +#define LOCALE_STRING_PROPERTY(VARIABLE) void QQmlLocaleData::method_get_ ## VARIABLE (const BuiltinFunction *, Scope &scope, CallData *callData) \ { \ - QLocale *locale = getThisLocale(ctx); \ + QLocale *locale = getThisLocale(scope, callData); \ if (!locale) \ - return QV4::Encode::undefined(); \ - return ctx->engine()->newString(locale-> VARIABLE())->asReturnedValue();\ + return; \ + scope.result = scope.engine->newString(locale-> VARIABLE());\ } LOCALE_STRING_PROPERTY(name) @@ -830,18 +833,22 @@ void QQmlLocale::registerStringLocaleCompare(QV4::ExecutionEngine *engine) engine->stringPrototype()->defineDefaultProperty(QStringLiteral("localeCompare"), method_localeCompare); } -QV4::ReturnedValue QQmlLocale::method_localeCompare(QV4::CallContext *ctx) +void QQmlLocale::method_localeCompare(const BuiltinFunction *b, Scope &scope, CallData *callData) { - if (ctx->argc() != 1 || (!ctx->args()[0].isString() && !ctx->args()[0].as<StringObject>())) - return QV4::StringPrototype::method_localeCompare(ctx); + if (callData->argc != 1 || (!callData->args[0].isString() && !callData->args[0].as<StringObject>())) { + QV4::StringPrototype::method_localeCompare(b, scope, callData); + return; + } - if (!ctx->thisObject().isString() && !ctx->thisObject().as<StringObject>()) - return QV4::StringPrototype::method_localeCompare(ctx); + if (!callData->thisObject.isString() && !callData->thisObject.as<StringObject>()) { + QV4::StringPrototype::method_localeCompare(b, scope, callData); + return; + } - QString thisString = ctx->thisObject().toQStringNoThrow(); - QString thatString = ctx->args()[0].toQStringNoThrow(); + QString thisString = callData->thisObject.toQStringNoThrow(); + QString thatString = callData->args[0].toQStringNoThrow(); - return QV4::Encode(QString::localeAwareCompare(thisString, thatString)); + scope.result = QV4::Encode(QString::localeAwareCompare(thisString, thatString)); } /*! diff --git a/src/qml/qml/qqmllocale_p.h b/src/qml/qml/qqmllocale_p.h index 275f58db7d..1a2ffc72b0 100644 --- a/src/qml/qml/qqmllocale_p.h +++ b/src/qml/qml/qqmllocale_p.h @@ -67,13 +67,13 @@ public: static void registerExtension(QV4::ExecutionEngine *engine); private: - static QV4::ReturnedValue method_toLocaleString(QV4::CallContext *ctx); - static QV4::ReturnedValue method_toLocaleTimeString(QV4::CallContext *ctx); - static QV4::ReturnedValue method_toLocaleDateString(QV4::CallContext *ctx); - static QV4::ReturnedValue method_fromLocaleString(QV4::CallContext *ctx); - static QV4::ReturnedValue method_fromLocaleTimeString(QV4::CallContext *ctx); - static QV4::ReturnedValue method_fromLocaleDateString(QV4::CallContext *ctx); - static QV4::ReturnedValue method_timeZoneUpdated(QV4::CallContext *ctx); + static void method_toLocaleString(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData); + static void method_toLocaleTimeString(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData); + static void method_toLocaleDateString(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData); + static void method_fromLocaleString(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData); + static void method_fromLocaleTimeString(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData); + static void method_fromLocaleDateString(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData); + static void method_timeZoneUpdated(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData); }; @@ -83,9 +83,9 @@ public: static void registerExtension(QV4::ExecutionEngine *engine); private: - static QV4::ReturnedValue method_toLocaleString(QV4::CallContext *ctx); - static QV4::ReturnedValue method_fromLocaleString(QV4::CallContext *ctx); - static QV4::ReturnedValue method_toLocaleCurrencyString(QV4::CallContext *ctx); + static void method_toLocaleString(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData); + static void method_fromLocaleString(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData); + static void method_toLocaleCurrencyString(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData); }; @@ -135,7 +135,7 @@ public: private: QQmlLocale(); - static QV4::ReturnedValue method_localeCompare(QV4::CallContext *ctx); + static void method_localeCompare(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData); }; namespace QV4 { @@ -158,43 +158,43 @@ struct QQmlLocaleData : public QV4::Object V4_OBJECT2(QQmlLocaleData, Object) V4_NEEDS_DESTROY - static QLocale *getThisLocale(QV4::CallContext *ctx) { - QV4::Object *o = ctx->thisObject().as<Object>(); + static QLocale *getThisLocale(QV4::Scope &scope, QV4::CallData *callData) { + QV4::Object *o = callData->thisObject.as<Object>(); QQmlLocaleData *thisObject = o ? o->as<QQmlLocaleData>() : 0; if (!thisObject) { - ctx->engine()->throwTypeError(); + scope.engine->throwTypeError(); return 0; } return thisObject->d()->locale; } - static QV4::ReturnedValue method_currencySymbol(QV4::CallContext *ctx); - static QV4::ReturnedValue method_dateTimeFormat(QV4::CallContext *ctx); - static QV4::ReturnedValue method_timeFormat(QV4::CallContext *ctx); - static QV4::ReturnedValue method_dateFormat(QV4::CallContext *ctx); - static QV4::ReturnedValue method_monthName(QV4::CallContext *ctx); - static QV4::ReturnedValue method_standaloneMonthName(QV4::CallContext *ctx); - static QV4::ReturnedValue method_dayName(QV4::CallContext *ctx); - static QV4::ReturnedValue method_standaloneDayName(QV4::CallContext *ctx); - - static QV4::ReturnedValue method_get_firstDayOfWeek(QV4::CallContext *ctx); - static QV4::ReturnedValue method_get_measurementSystem(QV4::CallContext *ctx); - static QV4::ReturnedValue method_get_textDirection(QV4::CallContext *ctx); - static QV4::ReturnedValue method_get_weekDays(QV4::CallContext *ctx); - static QV4::ReturnedValue method_get_uiLanguages(QV4::CallContext *ctx); - - static QV4::ReturnedValue method_get_name(QV4::CallContext *ctx); - static QV4::ReturnedValue method_get_nativeLanguageName(QV4::CallContext *ctx); - static QV4::ReturnedValue method_get_nativeCountryName(QV4::CallContext *ctx); - static QV4::ReturnedValue method_get_decimalPoint(QV4::CallContext *ctx); - static QV4::ReturnedValue method_get_groupSeparator(QV4::CallContext *ctx); - static QV4::ReturnedValue method_get_percent(QV4::CallContext *ctx); - static QV4::ReturnedValue method_get_zeroDigit(QV4::CallContext *ctx); - static QV4::ReturnedValue method_get_negativeSign(QV4::CallContext *ctx); - static QV4::ReturnedValue method_get_positiveSign(QV4::CallContext *ctx); - static QV4::ReturnedValue method_get_exponential(QV4::CallContext *ctx); - static QV4::ReturnedValue method_get_amText(QV4::CallContext *ctx); - static QV4::ReturnedValue method_get_pmText(QV4::CallContext *ctx); + static void method_currencySymbol(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData); + static void method_dateTimeFormat(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData); + static void method_timeFormat(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData); + static void method_dateFormat(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData); + static void method_monthName(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData); + static void method_standaloneMonthName(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData); + static void method_dayName(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData); + static void method_standaloneDayName(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData); + + static void method_get_firstDayOfWeek(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData); + static void method_get_measurementSystem(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData); + static void method_get_textDirection(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData); + static void method_get_weekDays(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData); + static void method_get_uiLanguages(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData); + + static void method_get_name(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData); + static void method_get_nativeLanguageName(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData); + static void method_get_nativeCountryName(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData); + static void method_get_decimalPoint(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData); + static void method_get_groupSeparator(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData); + static void method_get_percent(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData); + static void method_get_zeroDigit(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData); + static void method_get_negativeSign(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData); + static void method_get_positiveSign(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData); + static void method_get_exponential(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData); + static void method_get_amText(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData); + static void method_get_pmText(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData); }; } diff --git a/src/qml/qml/qqmlloggingcategory.cpp b/src/qml/qml/qqmlloggingcategory.cpp index 70e59db07b..764b874131 100644 --- a/src/qml/qml/qqmlloggingcategory.cpp +++ b/src/qml/qml/qqmlloggingcategory.cpp @@ -112,13 +112,13 @@ void QQmlLoggingCategory::componentComplete() { m_initialized = true; if (m_name.isNull()) - qmlInfo(this) << QLatin1String("Declaring the name of the LoggingCategory is mandatory and cannot be changed later !"); + qmlWarning(this) << QLatin1String("Declaring the name of the LoggingCategory is mandatory and cannot be changed later !"); } void QQmlLoggingCategory::setName(const QString &name) { if (m_initialized) { - qmlInfo(this) << QLatin1String("The name of a LoggingCategory cannot be changed after the Item is created"); + qmlWarning(this) << QLatin1String("The name of a LoggingCategory cannot be changed after the Item is created"); return; } diff --git a/src/qml/qml/qqmlmetatype.cpp b/src/qml/qml/qqmlmetatype.cpp index 520c44f4da..bd6b9a1599 100644 --- a/src/qml/qml/qqmlmetatype.cpp +++ b/src/qml/qml/qqmlmetatype.cpp @@ -79,7 +79,7 @@ struct QQmlMetaTypeData Files urlToNonFileImportType; // For non-file imported composite and composite // singleton types. This way we can locate any // of them by url, even if it was registered as - // a module via qmlRegisterCompositeType. + // a module via QQmlPrivate::RegisterCompositeType typedef QHash<const QMetaObject *, QQmlType *> MetaObjects; MetaObjects metaObjectToType; typedef QHash<int, QQmlMetaType::StringConverter> StringConverters; diff --git a/src/qml/qml/qqmlobjectcreator.cpp b/src/qml/qml/qqmlobjectcreator.cpp index 2e2a3fb303..85fbd86dc4 100644 --- a/src/qml/qml/qqmlobjectcreator.cpp +++ b/src/qml/qml/qqmlobjectcreator.cpp @@ -53,6 +53,8 @@ #include <private/qqmlscriptstring_p.h> #include <private/qqmlpropertyvalueinterceptor_p.h> #include <private/qqmlvaluetypeproxybinding_p.h> +#include <private/qqmldebugconnector_p.h> +#include <private/qqmldebugserviceinterfaces_p.h> QT_USE_NAMESPACE @@ -168,7 +170,7 @@ QObject *QQmlObjectCreator::create(int subComponentIndex, QObject *parent, QQmlI context = new QQmlContextData; context->isInternal = true; - context->imports = compilationUnit->importCache; + context->imports = compilationUnit->typeNameCache; context->initFromTypeCompilationUnit(compilationUnit, subComponentIndex); context->setParent(parentContext); @@ -216,6 +218,17 @@ QObject *QQmlObjectCreator::create(int subComponentIndex, QObject *parent, QQmlI phase = ObjectsCreated; + if (instance) { + if (QQmlEngineDebugService *service + = QQmlDebugConnector::service<QQmlEngineDebugService>()) { + if (!parentContext->isInternal) + parentContext->asQQmlContextPrivate()->instances.append(instance); + service->objectCreated(engine, instance); + } else if (!parentContext->isInternal && QQmlDebugConnector::service<QV4DebugService>()) { + parentContext->asQQmlContextPrivate()->instances.append(instance); + } + } + return instance; } @@ -1137,7 +1150,7 @@ QObject *QQmlObjectCreator::createInstance(int index, QObject *parent, bool isCo if (customParser && obj->flags & QV4::CompiledData::Object::HasCustomParserBindings) { customParser->engine = QQmlEnginePrivate::get(engine); - customParser->imports = compilationUnit->importCache; + customParser->imports = compilationUnit->typeNameCache; QList<const QV4::CompiledData::Binding *> bindings; const QV4::CompiledData::Object *obj = qmlUnit->objectAt(index); @@ -1257,6 +1270,21 @@ QQmlContextData *QQmlObjectCreator::finalize(QQmlInstantiationInterrupt &interru return sharedState->rootContext; } +void QQmlObjectCreator::cancel(QObject *object) +{ + int last = sharedState->allCreatedObjects.count() - 1; + int i = last; + while (i >= 0) { + if (sharedState->allCreatedObjects.at(i) == object) { + if (i < last) + qSwap(sharedState->allCreatedObjects[i], sharedState->allCreatedObjects[last]); + sharedState->allCreatedObjects.pop(); + break; + } + --i; + } +} + void QQmlObjectCreator::clear() { if (phase == Done || phase == Finalizing || phase == Startup) diff --git a/src/qml/qml/qqmlobjectcreator_p.h b/src/qml/qml/qqmlobjectcreator_p.h index caee7b9d1d..982324be3c 100644 --- a/src/qml/qml/qqmlobjectcreator_p.h +++ b/src/qml/qml/qqmlobjectcreator_p.h @@ -90,6 +90,7 @@ public: QObject *create(int subComponentIndex = -1, QObject *parent = 0, QQmlInstantiationInterrupt *interrupt = 0); bool populateDeferredProperties(QObject *instance); QQmlContextData *finalize(QQmlInstantiationInterrupt &interrupt); + void cancel(QObject *object); void clear(); QQmlComponentAttached **componentAttachment() const { return &sharedState->componentAttached; } diff --git a/src/qml/qml/qqmlplatform.cpp b/src/qml/qml/qqmlplatform.cpp index a47a0ab4a4..64ca208f1b 100644 --- a/src/qml/qml/qqmlplatform.cpp +++ b/src/qml/qml/qqmlplatform.cpp @@ -59,16 +59,12 @@ QString QQmlPlatform::os() { #if defined(Q_OS_ANDROID) return QStringLiteral("android"); -#elif defined(Q_OS_BLACKBERRY) - return QStringLiteral("blackberry"); #elif defined(Q_OS_IOS) return QStringLiteral("ios"); #elif defined(Q_OS_TVOS) return QStringLiteral("tvos"); #elif defined(Q_OS_MAC) return QStringLiteral("osx"); -#elif defined(Q_OS_WINPHONE) - return QStringLiteral("winphone"); #elif defined(Q_OS_WINRT) return QStringLiteral("winrt"); #elif defined(Q_OS_WIN) diff --git a/src/qml/qml/qqmltypeloader.cpp b/src/qml/qml/qqmltypeloader.cpp index 76ac15e2f1..13ad02f7cb 100644 --- a/src/qml/qml/qqmltypeloader.cpp +++ b/src/qml/qml/qqmltypeloader.cpp @@ -2127,11 +2127,11 @@ bool QQmlTypeData::tryLoadFromDiskCache() return true; } -void QQmlTypeData::createTypeAndPropertyCaches(const QQmlRefPointer<QQmlTypeNameCache> &importCache, +void QQmlTypeData::createTypeAndPropertyCaches(const QQmlRefPointer<QQmlTypeNameCache> &typeNameCache, const QV4::CompiledData::ResolvedTypeReferenceMap &resolvedTypeCache) { Q_ASSERT(m_compiledData); - m_compiledData->importCache = importCache; + m_compiledData->typeNameCache = typeNameCache; m_compiledData->resolvedTypes = resolvedTypeCache; QQmlEnginePrivate * const engine = QQmlEnginePrivate::get(typeLoader()->engine()); @@ -2217,10 +2217,10 @@ void QQmlTypeData::done() } } - QQmlRefPointer<QQmlTypeNameCache> importCache; + QQmlRefPointer<QQmlTypeNameCache> typeNameCache; QV4::CompiledData::ResolvedTypeReferenceMap resolvedTypeCache; { - QQmlCompileError error = buildTypeResolutionCaches(&importCache, &resolvedTypeCache); + QQmlCompileError error = buildTypeResolutionCaches(&typeNameCache, &resolvedTypeCache); if (error.isSet()) { setError(error); return; @@ -2240,9 +2240,9 @@ void QQmlTypeData::done() if (!m_document.isNull()) { // Compile component - compile(importCache, resolvedTypeCache); + compile(typeNameCache, resolvedTypeCache); } else { - createTypeAndPropertyCaches(importCache, resolvedTypeCache); + createTypeAndPropertyCaches(typeNameCache, resolvedTypeCache); } if (isError()) @@ -2303,7 +2303,7 @@ void QQmlTypeData::done() qualifier = qualifier.mid(lastDotIndex+1); } - m_compiledData->importCache->add(qualifier.toString(), scriptIndex, enclosingNamespace); + m_compiledData->typeNameCache->add(qualifier.toString(), scriptIndex, enclosingNamespace); QQmlScriptData *scriptData = script.script->scriptData(); scriptData->addref(); m_compiledData->dependentScripts << scriptData; @@ -2428,7 +2428,7 @@ void QQmlTypeData::continueLoadFromIR() QList<QQmlError> errors; - foreach (const QV4::CompiledData::Import *import, m_document->imports) { + for (const QV4::CompiledData::Import *import : qAsConst(m_document->imports)) { if (!addImport(import, &errors)) { Q_ASSERT(errors.size()); QQmlError error(errors.takeFirst()); @@ -2489,12 +2489,12 @@ QString QQmlTypeData::stringAt(int index) const return m_document->jsGenerator.stringTable.stringForIndex(index); } -void QQmlTypeData::compile(const QQmlRefPointer<QQmlTypeNameCache> &importCache, const QV4::CompiledData::ResolvedTypeReferenceMap &resolvedTypeCache) +void QQmlTypeData::compile(const QQmlRefPointer<QQmlTypeNameCache> &typeNameCache, const QV4::CompiledData::ResolvedTypeReferenceMap &resolvedTypeCache) { Q_ASSERT(m_compiledData.isNull()); QQmlEnginePrivate * const enginePrivate = QQmlEnginePrivate::get(typeLoader()->engine()); - QQmlTypeCompiler compiler(enginePrivate, this, m_document.data(), importCache, resolvedTypeCache); + QQmlTypeCompiler compiler(enginePrivate, this, m_document.data(), typeNameCache, resolvedTypeCache); m_compiledData = compiler.compile(); if (!m_compiledData) { setError(compiler.compilationErrors()); @@ -2575,50 +2575,11 @@ void QQmlTypeData::resolveTypes() int majorVersion = -1; int minorVersion = -1; - QQmlImportNamespace *typeNamespace = 0; - QList<QQmlError> errors; const QString name = stringAt(unresolvedRef.key()); - bool typeFound = m_importCache.resolveType(name, &ref.type, - &majorVersion, &minorVersion, &typeNamespace, &errors); - if (!typeNamespace && !typeFound && !m_implicitImportLoaded) { - // Lazy loading of implicit import - if (loadImplicitImport()) { - // Try again to find the type - errors.clear(); - typeFound = m_importCache.resolveType(name, &ref.type, - &majorVersion, &minorVersion, &typeNamespace, &errors); - } else { - return; //loadImplicitImport() hit an error, and called setError already - } - } - - if ((!typeFound || typeNamespace) && reportErrors) { - // Known to not be a type: - // - known to be a namespace (Namespace {}) - // - type with unknown namespace (UnknownNamespace.SomeType {}) - QQmlError error; - if (typeNamespace) { - error.setDescription(QQmlTypeLoader::tr("Namespace %1 cannot be used as a type").arg(name)); - } else { - if (errors.size()) { - error = errors.takeFirst(); - } else { - // this should not be possible! - // Description should come from error provided by addImport() function. - error.setDescription(QQmlTypeLoader::tr("Unreported error adding script import to import database")); - } - error.setUrl(m_importCache.baseUrl()); - error.setDescription(QQmlTypeLoader::tr("%1 %2").arg(name).arg(error.description())); - } - error.setLine(unresolvedRef->location.line); - error.setColumn(unresolvedRef->location.column); - - errors.prepend(error); - setError(errors); + if (!resolveType(name, majorVersion, minorVersion, ref, unresolvedRef->location.line, unresolvedRef->location.column, reportErrors) && reportErrors) return; - } if (ref.type && ref.type->isComposite()) { ref.typeData = typeLoader()->getType(ref.type->sourceUrl()); @@ -2637,20 +2598,20 @@ void QQmlTypeData::resolveTypes() } QQmlCompileError QQmlTypeData::buildTypeResolutionCaches( - QQmlRefPointer<QQmlTypeNameCache> *importCache, + QQmlRefPointer<QQmlTypeNameCache> *typeNameCache, QV4::CompiledData::ResolvedTypeReferenceMap *resolvedTypeCache ) const { - importCache->adopt(new QQmlTypeNameCache); + typeNameCache->adopt(new QQmlTypeNameCache); for (const QString &ns: m_namespaces) - (*importCache)->add(ns); + (*typeNameCache)->add(ns); // Add any Composite Singletons that were used to the import cache for (const QQmlTypeData::TypeReference &singleton: m_compositeSingletons) - (*importCache)->add(singleton.type->qmlTypeName(), singleton.type->sourceUrl(), singleton.prefix); + (*typeNameCache)->add(singleton.type->qmlTypeName(), singleton.type->sourceUrl(), singleton.prefix); - m_importCache.populateCache(*importCache); + m_importCache.populateCache(*typeNameCache); QQmlEnginePrivate * const engine = QQmlEnginePrivate::get(typeLoader()->engine()); @@ -2687,7 +2648,7 @@ QQmlCompileError QQmlTypeData::buildTypeResolutionCaches( return noError; } -bool QQmlTypeData::resolveType(const QString &typeName, int &majorVersion, int &minorVersion, TypeReference &ref) +bool QQmlTypeData::resolveType(const QString &typeName, int &majorVersion, int &minorVersion, TypeReference &ref, int lineNumber, int columnNumber, bool reportErrors) { QQmlImportNamespace *typeNamespace = 0; QList<QQmlError> errors; @@ -2706,7 +2667,7 @@ bool QQmlTypeData::resolveType(const QString &typeName, int &majorVersion, int & } } - if (!typeFound || typeNamespace) { + if ((!typeFound || typeNamespace) && reportErrors) { // Known to not be a type: // - known to be a namespace (Namespace {}) // - type with unknown namespace (UnknownNamespace.SomeType {}) @@ -2725,6 +2686,11 @@ bool QQmlTypeData::resolveType(const QString &typeName, int &majorVersion, int & error.setDescription(QQmlTypeLoader::tr("%1 %2").arg(typeName).arg(error.description())); } + if (lineNumber != -1) + error.setLine(lineNumber); + if (columnNumber != -1) + error.setColumn(columnNumber); + errors.prepend(error); setError(errors); return false; @@ -2744,7 +2710,7 @@ void QQmlTypeData::scriptImported(QQmlScriptBlob *blob, const QV4::CompiledData: } QQmlScriptData::QQmlScriptData() - : importCache(0) + : typeNameCache(0) , m_loaded(false) , m_program(0) { @@ -2801,8 +2767,8 @@ QV4::ReturnedValue QQmlScriptData::scriptValueForContext(QQmlContextData *parent // For backward compatibility, if there are no imports, we need to use the // imports from the parent context. See QTBUG-17518. - if (!importCache->isEmpty()) { - ctxt->imports = importCache; + if (!typeNameCache->isEmpty()) { + ctxt->imports = typeNameCache; } else if (effectiveCtxt) { ctxt->imports = effectiveCtxt->imports; ctxt->importedScripts = effectiveCtxt->importedScripts; @@ -2857,9 +2823,9 @@ QV4::ReturnedValue QQmlScriptData::scriptValueForContext(QQmlContextData *parent void QQmlScriptData::clear() { - if (importCache) { - importCache->release(); - importCache = 0; + if (typeNameCache) { + typeNameCache->release(); + typeNameCache = 0; } for (int ii = 0; ii < scripts.count(); ++ii) @@ -2980,7 +2946,7 @@ void QQmlScriptBlob::done() } } - m_scriptData->importCache = new QQmlTypeNameCache(); + m_scriptData->typeNameCache = new QQmlTypeNameCache(); QSet<QString> ns; @@ -2992,13 +2958,13 @@ void QQmlScriptBlob::done() if (!script.nameSpace.isNull()) { if (!ns.contains(script.nameSpace)) { ns.insert(script.nameSpace); - m_scriptData->importCache->add(script.nameSpace); + m_scriptData->typeNameCache->add(script.nameSpace); } } - m_scriptData->importCache->add(script.qualifier, scriptIndex, script.nameSpace); + m_scriptData->typeNameCache->add(script.qualifier, scriptIndex, script.nameSpace); } - m_importCache.populateCache(m_scriptData->importCache); + m_importCache.populateCache(m_scriptData->typeNameCache); } QString QQmlScriptBlob::stringAt(int index) const diff --git a/src/qml/qml/qqmltypeloader_p.h b/src/qml/qml/qqmltypeloader_p.h index b1d6451974..14141db180 100644 --- a/src/qml/qml/qqmltypeloader_p.h +++ b/src/qml/qml/qqmltypeloader_p.h @@ -449,14 +449,14 @@ private: void continueLoadFromIR(); void resolveTypes(); QQmlCompileError buildTypeResolutionCaches( - QQmlRefPointer<QQmlTypeNameCache> *importCache, + QQmlRefPointer<QQmlTypeNameCache> *typeNameCache, QV4::CompiledData::ResolvedTypeReferenceMap *resolvedTypeCache ) const; - void compile(const QQmlRefPointer<QQmlTypeNameCache> &importCache, + void compile(const QQmlRefPointer<QQmlTypeNameCache> &typeNameCache, const QV4::CompiledData::ResolvedTypeReferenceMap &resolvedTypeCache); - void createTypeAndPropertyCaches(const QQmlRefPointer<QQmlTypeNameCache> &importCache, + void createTypeAndPropertyCaches(const QQmlRefPointer<QQmlTypeNameCache> &typeNameCache, const QV4::CompiledData::ResolvedTypeReferenceMap &resolvedTypeCache); - bool resolveType(const QString &typeName, int &majorVersion, int &minorVersion, TypeReference &ref); + bool resolveType(const QString &typeName, int &majorVersion, int &minorVersion, TypeReference &ref, int lineNumber = -1, int columnNumber = -1, bool reportErrors = true); void scriptImported(QQmlScriptBlob *blob, const QV4::CompiledData::Location &location, const QString &qualifier, const QString &nameSpace) override; @@ -504,7 +504,7 @@ public: QUrl url; QString urlString; - QQmlTypeNameCache *importCache; + QQmlTypeNameCache *typeNameCache; QList<QQmlScriptBlob *> scripts; QV4::ReturnedValue scriptValueForContext(QQmlContextData *parentCtxt); diff --git a/src/qml/qml/qqmlvaluetypewrapper.cpp b/src/qml/qml/qqmlvaluetypewrapper.cpp index 6ce52bb9e5..44b612e7d2 100644 --- a/src/qml/qml/qqmlvaluetypewrapper.cpp +++ b/src/qml/qml/qqmlvaluetypewrapper.cpp @@ -312,18 +312,18 @@ bool QQmlValueTypeWrapper::write(QObject *target, int propertyIndex) const return true; } -ReturnedValue QQmlValueTypeWrapper::method_toString(CallContext *ctx) +void QQmlValueTypeWrapper::method_toString(const BuiltinFunction *, Scope &scope, CallData *callData) { - Object *o = ctx->thisObject().as<Object>(); + Object *o = callData->thisObject.as<Object>(); if (!o) - return ctx->engine()->throwTypeError(); + THROW_TYPE_ERROR(); QQmlValueTypeWrapper *w = o->as<QQmlValueTypeWrapper>(); if (!w) - return ctx->engine()->throwTypeError(); + THROW_TYPE_ERROR(); if (QQmlValueTypeReference *ref = w->as<QQmlValueTypeReference>()) if (!ref->readReferenceValue()) - return Encode::undefined(); + RETURN_UNDEFINED(); QString result; // Prepare a buffer to pass to QMetaType::convert() @@ -346,7 +346,7 @@ ReturnedValue QQmlValueTypeWrapper::method_toString(CallContext *ctx) } result += QLatin1Char(')'); } - return Encode(ctx->engine()->newString(result)); + scope.result = scope.engine->newString(result); } ReturnedValue QQmlValueTypeWrapper::get(const Managed *m, String *name, bool *hasProperty) diff --git a/src/qml/qml/qqmlvaluetypewrapper_p.h b/src/qml/qml/qqmlvaluetypewrapper_p.h index fec54df770..87f9116056 100644 --- a/src/qml/qml/qqmlvaluetypewrapper_p.h +++ b/src/qml/qml/qqmlvaluetypewrapper_p.h @@ -111,7 +111,7 @@ public: static PropertyAttributes query(const Managed *, String *name); static void advanceIterator(Managed *m, ObjectIterator *it, Value *name, uint *index, Property *p, PropertyAttributes *attributes); - static QV4::ReturnedValue method_toString(CallContext *ctx); + static void method_toString(const BuiltinFunction *, Scope &scope, CallData *callData); static void initProto(ExecutionEngine *v4); }; diff --git a/src/qml/qml/qqmlvme.cpp b/src/qml/qml/qqmlvme.cpp index 72d4ab7e8f..c60f4edc80 100644 --- a/src/qml/qml/qqmlvme.cpp +++ b/src/qml/qml/qqmlvme.cpp @@ -120,6 +120,18 @@ void QQmlVMEGuard::guard(QQmlObjectCreator *creator) m_contexts[0] = creator->parentContextData(); } +void QQmlVMEGuard::unguard(QObject *object) +{ + for (int ii = 0; ii < m_objectCount; ++ii) { + if (m_objects[ii] == object) { + if (ii < m_objectCount - 1) + ::memmove((void *) m_objects[ii], (void *) m_objects[ii + 1], sizeof(QPointer<QObject> *)); + delete m_objects[--m_objectCount]; + break; + } + } +} + void QQmlVMEGuard::clear() { delete [] m_objects; diff --git a/src/qml/qml/qqmlvme_p.h b/src/qml/qml/qqmlvme_p.h index 99d63380ad..9585b5b6df 100644 --- a/src/qml/qml/qqmlvme_p.h +++ b/src/qml/qml/qqmlvme_p.h @@ -131,6 +131,7 @@ public: ~QQmlVMEGuard(); void guard(QQmlObjectCreator *); + void unguard(QObject *); void clear(); bool isOK() const; diff --git a/src/qml/qml/qqmlvmemetaobject.cpp b/src/qml/qml/qqmlvmemetaobject.cpp index 545daa96f8..490a4e19ab 100644 --- a/src/qml/qml/qqmlvmemetaobject.cpp +++ b/src/qml/qml/qqmlvmemetaobject.cpp @@ -325,9 +325,12 @@ QQmlVMEMetaObject::QQmlVMEMetaObject(QObject *obj, if (compiledObject->nProperties || compiledObject->nFunctions) { Q_ASSERT(cache && cache->engine); QV4::ExecutionEngine *v4 = cache->engine; - QV4::Heap::MemberData *data = QV4::MemberData::allocate(v4, compiledObject->nProperties + compiledObject->nFunctions); - propertyAndMethodStorage.set(v4, data); - std::fill(data->data, data->data + data->size, QV4::Encode::undefined()); + uint size = compiledObject->nProperties + compiledObject->nFunctions; + if (size) { + QV4::Heap::MemberData *data = QV4::MemberData::allocate(v4, size); + propertyAndMethodStorage.set(v4, data); + std::fill(data->data, data->data + data->size, QV4::Encode::undefined()); + } // Need JS wrapper to ensure properties/methods are marked. ensureQObjectWrapper(); diff --git a/src/qml/qml/qqmlxmlhttprequest.cpp b/src/qml/qml/qqmlxmlhttprequest.cpp index 22c3c49c58..d0d9f080da 100644 --- a/src/qml/qml/qqmlxmlhttprequest.cpp +++ b/src/qml/qml/qqmlxmlhttprequest.cpp @@ -71,10 +71,12 @@ using namespace QV4; #if QT_CONFIG(xmlstreamreader) && QT_CONFIG(qml_network) -#define V4THROW_REFERENCE(string) { \ - ScopedObject error(scope, ctx->engine()->newReferenceErrorObject(QStringLiteral(string))); \ - return ctx->engine()->throwError(error); \ - } +#define V4THROW_REFERENCE(string) \ + do { \ + ScopedObject error(scope, scope.engine->newReferenceErrorObject(QStringLiteral(string))); \ + scope.result = scope.engine->throwError(error); \ + return; \ + } while (false) QT_BEGIN_NAMESPACE @@ -274,25 +276,25 @@ public: static void initClass(ExecutionEngine *engine); // JS API - static ReturnedValue method_get_nodeName(CallContext *ctx); - static ReturnedValue method_get_nodeValue(CallContext *ctx); - static ReturnedValue method_get_nodeType(CallContext *ctx); - static ReturnedValue method_get_namespaceUri(CallContext *ctx); - - static ReturnedValue method_get_parentNode(CallContext *ctx); - static ReturnedValue method_get_childNodes(CallContext *ctx); - static ReturnedValue method_get_firstChild(CallContext *ctx); - static ReturnedValue method_get_lastChild(CallContext *ctx); - static ReturnedValue method_get_previousSibling(CallContext *ctx); - static ReturnedValue method_get_nextSibling(CallContext *ctx); - static ReturnedValue method_get_attributes(CallContext *ctx); - - //static ReturnedValue ownerDocument(CallContext *ctx); - //static ReturnedValue namespaceURI(CallContext *ctx); - //static ReturnedValue prefix(CallContext *ctx); - //static ReturnedValue localName(CallContext *ctx); - //static ReturnedValue baseURI(CallContext *ctx); - //static ReturnedValue textContent(CallContext *ctx); + static void method_get_nodeName(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData); + static void method_get_nodeValue(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData); + static void method_get_nodeType(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData); + static void method_get_namespaceUri(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData); + + static void method_get_parentNode(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData); + static void method_get_childNodes(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData); + static void method_get_firstChild(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData); + static void method_get_lastChild(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData); + static void method_get_previousSibling(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData); + static void method_get_nextSibling(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData); + static void method_get_attributes(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData); + + //static void ownerDocument(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData); + //static void namespaceURI(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData); + //static void prefix(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData); + //static void localName(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData); + //static void baseURI(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData); + //static void textContent(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData); static ReturnedValue getProto(ExecutionEngine *v4); @@ -353,12 +355,12 @@ class Attr : public Node { public: // JS API - static ReturnedValue method_name(CallContext *ctx); -// static ReturnedValue specified(CallContext *); - static ReturnedValue method_value(CallContext *ctx); - static ReturnedValue method_ownerElement(CallContext *ctx); -// static ReturnedValue schemaTypeInfo(CallContext *); -// static ReturnedValue isId(CallContext *c); + static void method_name(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData); +// static void specified(CallContext *); + static void method_value(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData); + static void method_ownerElement(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData); +// static void schemaTypeInfo(CallContext *); +// static void isId(CallContext *c); // C++ API static ReturnedValue prototype(ExecutionEngine *); @@ -368,7 +370,7 @@ class CharacterData : public Node { public: // JS API - static ReturnedValue method_length(CallContext *ctx); + static void method_length(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData); // C++ API static ReturnedValue prototype(ExecutionEngine *v4); @@ -378,8 +380,8 @@ class Text : public CharacterData { public: // JS API - static ReturnedValue method_isElementContentWhitespace(CallContext *ctx); - static ReturnedValue method_wholeText(CallContext *ctx); + static void method_isElementContentWhitespace(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData); + static void method_wholeText(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData); // C++ API static ReturnedValue prototype(ExecutionEngine *); @@ -396,10 +398,10 @@ class Document : public Node { public: // JS API - static ReturnedValue method_xmlVersion(CallContext *ctx); - static ReturnedValue method_xmlEncoding(CallContext *ctx); - static ReturnedValue method_xmlStandalone(CallContext *ctx); - static ReturnedValue method_documentElement(CallContext *ctx); + static void method_xmlVersion(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData); + static void method_xmlEncoding(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData); + static void method_xmlStandalone(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData); + static void method_documentElement(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData); // C++ API static ReturnedValue prototype(ExecutionEngine *); @@ -418,12 +420,11 @@ void NodeImpl::release() document->release(); } -ReturnedValue NodePrototype::method_get_nodeName(CallContext *ctx) +void NodePrototype::method_get_nodeName(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData) { - Scope scope(ctx); - Scoped<Node> r(scope, ctx->thisObject().as<Node>()); + Scoped<Node> r(scope, callData->thisObject.as<Node>()); if (!r) - return ctx->engine()->throwTypeError(); + THROW_TYPE_ERROR(); QString name; switch (r->d()->d->type) { @@ -440,15 +441,14 @@ ReturnedValue NodePrototype::method_get_nodeName(CallContext *ctx) name = r->d()->d->name; break; } - return Encode(ctx->d()->engine->newString(name)); + scope.result = Encode(scope.engine->newString(name)); } -ReturnedValue NodePrototype::method_get_nodeValue(CallContext *ctx) +void NodePrototype::method_get_nodeValue(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData) { - Scope scope(ctx); - Scoped<Node> r(scope, ctx->thisObject().as<Node>()); + Scoped<Node> r(scope, callData->thisObject.as<Node>()); if (!r) - return ctx->engine()->throwTypeError(); + THROW_TYPE_ERROR(); if (r->d()->d->type == NodeImpl::Document || r->d()->d->type == NodeImpl::DocumentFragment || @@ -457,135 +457,128 @@ ReturnedValue NodePrototype::method_get_nodeValue(CallContext *ctx) r->d()->d->type == NodeImpl::Entity || r->d()->d->type == NodeImpl::EntityReference || r->d()->d->type == NodeImpl::Notation) - return Encode::null(); + RETURN_RESULT(Encode::null()); - return Encode(ctx->d()->engine->newString(r->d()->d->data)); + scope.result = Encode(scope.engine->newString(r->d()->d->data)); } -ReturnedValue NodePrototype::method_get_nodeType(CallContext *ctx) +void NodePrototype::method_get_nodeType(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData) { - Scope scope(ctx); - Scoped<Node> r(scope, ctx->thisObject().as<Node>()); + Scoped<Node> r(scope, callData->thisObject.as<Node>()); if (!r) - return ctx->engine()->throwTypeError(); + THROW_TYPE_ERROR(); - return Encode(r->d()->d->type); + scope.result = Encode(r->d()->d->type); } -ReturnedValue NodePrototype::method_get_namespaceUri(CallContext *ctx) +void NodePrototype::method_get_namespaceUri(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData) { - Scope scope(ctx); - Scoped<Node> r(scope, ctx->thisObject().as<Node>()); + Scoped<Node> r(scope, callData->thisObject.as<Node>()); if (!r) - return ctx->engine()->throwTypeError(); + THROW_TYPE_ERROR(); - return Encode(ctx->d()->engine->newString(r->d()->d->namespaceUri)); + scope.result = Encode(scope.engine->newString(r->d()->d->namespaceUri)); } -ReturnedValue NodePrototype::method_get_parentNode(CallContext *ctx) +void NodePrototype::method_get_parentNode(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData) { - Scope scope(ctx); - Scoped<Node> r(scope, ctx->thisObject().as<Node>()); + Scoped<Node> r(scope, callData->thisObject.as<Node>()); if (!r) - return ctx->engine()->throwTypeError(); + THROW_TYPE_ERROR(); if (r->d()->d->parent) - return Node::create(scope.engine, r->d()->d->parent); + scope.result = Node::create(scope.engine, r->d()->d->parent); else - return Encode::null(); + scope.result = Encode::null(); } -ReturnedValue NodePrototype::method_get_childNodes(CallContext *ctx) +void NodePrototype::method_get_childNodes(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData) { - Scope scope(ctx); - Scoped<Node> r(scope, ctx->thisObject().as<Node>()); + Scoped<Node> r(scope, callData->thisObject.as<Node>()); if (!r) - return ctx->engine()->throwTypeError(); + THROW_TYPE_ERROR(); - return NodeList::create(scope.engine, r->d()->d); + scope.result = NodeList::create(scope.engine, r->d()->d); } -ReturnedValue NodePrototype::method_get_firstChild(CallContext *ctx) +void NodePrototype::method_get_firstChild(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData) { - Scope scope(ctx); - Scoped<Node> r(scope, ctx->thisObject().as<Node>()); + Scoped<Node> r(scope, callData->thisObject.as<Node>()); if (!r) - return ctx->engine()->throwTypeError(); + THROW_TYPE_ERROR(); if (r->d()->d->children.isEmpty()) - return Encode::null(); + scope.result = Encode::null(); else - return Node::create(scope.engine, r->d()->d->children.constFirst()); + scope.result = Node::create(scope.engine, r->d()->d->children.constFirst()); } -ReturnedValue NodePrototype::method_get_lastChild(CallContext *ctx) +void NodePrototype::method_get_lastChild(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData) { - Scope scope(ctx); - Scoped<Node> r(scope, ctx->thisObject().as<Node>()); + Scoped<Node> r(scope, callData->thisObject.as<Node>()); if (!r) - return ctx->engine()->throwTypeError(); + THROW_TYPE_ERROR(); if (r->d()->d->children.isEmpty()) - return Encode::null(); + scope.result = Encode::null(); else - return Node::create(scope.engine, r->d()->d->children.constLast()); + scope.result = Node::create(scope.engine, r->d()->d->children.constLast()); } -ReturnedValue NodePrototype::method_get_previousSibling(CallContext *ctx) +void NodePrototype::method_get_previousSibling(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData) { - Scope scope(ctx); - Scoped<Node> r(scope, ctx->thisObject().as<Node>()); + Scoped<Node> r(scope, callData->thisObject.as<Node>()); if (!r) - return ctx->engine()->throwTypeError(); + THROW_TYPE_ERROR(); if (!r->d()->d->parent) - return Encode::null(); + RETURN_RESULT(Encode::null()); 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(); + scope.result = Encode::null(); else - return Node::create(scope.engine, r->d()->d->parent->children.at(ii - 1)); + scope.result = Node::create(scope.engine, r->d()->d->parent->children.at(ii - 1)); + return; } } - return Encode::null(); + scope.result = Encode::null(); } -ReturnedValue NodePrototype::method_get_nextSibling(CallContext *ctx) +void NodePrototype::method_get_nextSibling(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData) { - Scope scope(ctx); - Scoped<Node> r(scope, ctx->thisObject().as<Node>()); + Scoped<Node> r(scope, callData->thisObject.as<Node>()); if (!r) - return ctx->engine()->throwTypeError(); + THROW_TYPE_ERROR(); if (!r->d()->d->parent) - return Encode::null(); + RETURN_RESULT(Encode::null()); 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(); + scope.result = Encode::null(); else - return Node::create(scope.engine, r->d()->d->parent->children.at(ii + 1)); + scope.result = Node::create(scope.engine, r->d()->d->parent->children.at(ii + 1)); + return; } } - return Encode::null(); + scope.result = Encode::null(); } -ReturnedValue NodePrototype::method_get_attributes(CallContext *ctx) +void NodePrototype::method_get_attributes(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData) { - Scope scope(ctx); - Scoped<Node> r(scope, ctx->thisObject().as<Node>()); + Scoped<Node> r(scope, callData->thisObject.as<Node>()); if (!r) - return ctx->engine()->throwTypeError(); + THROW_TYPE_ERROR(); if (r->d()->d->type != NodeImpl::Element) - return Encode::null(); + scope.result = Encode::null(); else - return NamedNodeMap::create(scope.engine, r->d()->d, r->d()->d->attributes); + scope.result = NamedNodeMap::create(scope.engine, r->d()->d, r->d()->d->attributes); } ReturnedValue NodePrototype::getProto(ExecutionEngine *v4) @@ -666,44 +659,40 @@ ReturnedValue Attr::prototype(ExecutionEngine *engine) return d->attrPrototype.value(); } -ReturnedValue Attr::method_name(CallContext *ctx) +void Attr::method_name(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData) { - Scope scope(ctx); - Scoped<Node> r(scope, ctx->thisObject().as<Node>()); + Scoped<Node> r(scope, callData->thisObject.as<Node>()); if (!r) - return Encode::undefined(); + RETURN_UNDEFINED(); - return QV4::Encode(scope.engine->newString(r->d()->d->name)); + scope.result = scope.engine->newString(r->d()->d->name); } -ReturnedValue Attr::method_value(CallContext *ctx) +void Attr::method_value(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData) { - Scope scope(ctx); - Scoped<Node> r(scope, ctx->thisObject().as<Node>()); + Scoped<Node> r(scope, callData->thisObject.as<Node>()); if (!r) - return Encode::undefined(); + RETURN_UNDEFINED(); - return QV4::Encode(scope.engine->newString(r->d()->d->data)); + scope.result = scope.engine->newString(r->d()->d->data); } -ReturnedValue Attr::method_ownerElement(CallContext *ctx) +void Attr::method_ownerElement(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData) { - Scope scope(ctx); - Scoped<Node> r(scope, ctx->thisObject().as<Node>()); + Scoped<Node> r(scope, callData->thisObject.as<Node>()); if (!r) - return Encode::undefined(); + RETURN_UNDEFINED(); - return Node::create(scope.engine, r->d()->d->parent); + scope.result = Node::create(scope.engine, r->d()->d->parent); } -ReturnedValue CharacterData::method_length(CallContext *ctx) +void CharacterData::method_length(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData) { - Scope scope(ctx); - Scoped<Node> r(scope, ctx->thisObject().as<Node>()); + Scoped<Node> r(scope, callData->thisObject.as<Node>()); if (!r) - return Encode::undefined(); + RETURN_UNDEFINED(); - return Encode(r->d()->d->data.length()); + scope.result = Encode(r->d()->d->data.length()); } ReturnedValue CharacterData::prototype(ExecutionEngine *v4) @@ -722,23 +711,22 @@ ReturnedValue CharacterData::prototype(ExecutionEngine *v4) return d->characterDataPrototype.value(); } -ReturnedValue Text::method_isElementContentWhitespace(CallContext *ctx) +void Text::method_isElementContentWhitespace(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData) { - Scope scope(ctx); - Scoped<Node> r(scope, ctx->thisObject().as<Node>()); - if (!r) return Encode::undefined(); + Scoped<Node> r(scope, callData->thisObject.as<Node>()); + if (!r) + RETURN_UNDEFINED(); - return Encode(QStringRef(&r->d()->d->data).trimmed().isEmpty()); + scope.result = Encode(QStringRef(&r->d()->d->data).trimmed().isEmpty()); } -ReturnedValue Text::method_wholeText(CallContext *ctx) +void Text::method_wholeText(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData) { - Scope scope(ctx); - Scoped<Node> r(scope, ctx->thisObject().as<Node>()); + Scoped<Node> r(scope, callData->thisObject.as<Node>()); if (!r) - return Encode::undefined(); + RETURN_UNDEFINED(); - return QV4::Encode(scope.engine->newString(r->d()->d->data)); + scope.result = scope.engine->newString(r->d()->d->data); } ReturnedValue Text::prototype(ExecutionEngine *v4) @@ -964,44 +952,40 @@ ReturnedValue NodeList::create(ExecutionEngine *v4, NodeImpl *data) return (v4->memoryManager->allocObject<NodeList>(data))->asReturnedValue(); } -ReturnedValue Document::method_documentElement(CallContext *ctx) +void Document::method_documentElement(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData) { - Scope scope(ctx); - Scoped<Node> r(scope, ctx->thisObject().as<Node>()); + Scoped<Node> r(scope, callData->thisObject.as<Node>()); if (!r || r->d()->d->type != NodeImpl::Document) - return Encode::undefined(); + RETURN_UNDEFINED(); - return Node::create(scope.engine, static_cast<DocumentImpl *>(r->d()->d)->root); + scope.result = Node::create(scope.engine, static_cast<DocumentImpl *>(r->d()->d)->root); } -ReturnedValue Document::method_xmlStandalone(CallContext *ctx) +void Document::method_xmlStandalone(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData) { - Scope scope(ctx); - Scoped<Node> r(scope, ctx->thisObject().as<Node>()); + Scoped<Node> r(scope, callData->thisObject.as<Node>()); if (!r || r->d()->d->type != NodeImpl::Document) - return Encode::undefined(); + RETURN_UNDEFINED(); - return Encode(static_cast<DocumentImpl *>(r->d()->d)->isStandalone); + scope.result = Encode(static_cast<DocumentImpl *>(r->d()->d)->isStandalone); } -ReturnedValue Document::method_xmlVersion(CallContext *ctx) +void Document::method_xmlVersion(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData) { - Scope scope(ctx); - Scoped<Node> r(scope, ctx->thisObject().as<Node>()); + Scoped<Node> r(scope, callData->thisObject.as<Node>()); if (!r || r->d()->d->type != NodeImpl::Document) - return Encode::undefined(); + RETURN_UNDEFINED(); - return QV4::Encode(scope.engine->newString(static_cast<DocumentImpl *>(r->d()->d)->version)); + scope.result = scope.engine->newString(static_cast<DocumentImpl *>(r->d()->d)->version); } -ReturnedValue Document::method_xmlEncoding(CallContext *ctx) +void Document::method_xmlEncoding(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData) { - Scope scope(ctx); - Scoped<Node> r(scope, ctx->thisObject().as<Node>()); + Scoped<Node> r(scope, callData->thisObject.as<Node>()); if (!r || r->d()->d->type != NodeImpl::Document) - return Encode::undefined(); + RETURN_UNDEFINED(); - return QV4::Encode(scope.engine->newString(static_cast<DocumentImpl *>(r->d()->d)->encoding)); + scope.result = scope.engine->newString(static_cast<DocumentImpl *>(r->d()->d)->encoding); } class QQmlXMLHttpRequest : public QObject @@ -1657,21 +1641,21 @@ struct QQmlXMLHttpRequestCtor : public FunctionObject void setupProto(); - static ReturnedValue method_open(CallContext *ctx); - static ReturnedValue method_setRequestHeader(CallContext *ctx); - static ReturnedValue method_send(CallContext *ctx); - static ReturnedValue method_abort(CallContext *ctx); - static ReturnedValue method_getResponseHeader(CallContext *ctx); - static ReturnedValue method_getAllResponseHeaders(CallContext *ctx); - - static ReturnedValue method_get_readyState(CallContext *ctx); - static ReturnedValue method_get_status(CallContext *ctx); - static ReturnedValue method_get_statusText(CallContext *ctx); - static ReturnedValue method_get_responseText(CallContext *ctx); - static ReturnedValue method_get_responseXML(CallContext *ctx); - static ReturnedValue method_get_response(CallContext *ctx); - static ReturnedValue method_get_responseType(CallContext *ctx); - static ReturnedValue method_set_responseType(CallContext *ctx); + static void method_open(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData); + static void method_setRequestHeader(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData); + static void method_send(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData); + static void method_abort(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData); + static void method_getResponseHeader(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData); + static void method_getAllResponseHeaders(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData); + + static void method_get_readyState(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData); + static void method_get_status(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData); + static void method_get_statusText(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData); + static void method_get_responseText(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData); + static void method_get_responseXML(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData); + static void method_get_response(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData); + static void method_get_responseType(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData); + static void method_set_responseType(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData); }; } @@ -1733,19 +1717,18 @@ void QQmlXMLHttpRequestCtor::setupProto() // XMLHttpRequest methods -ReturnedValue QQmlXMLHttpRequestCtor::method_open(CallContext *ctx) +void QQmlXMLHttpRequestCtor::method_open(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData) { - Scope scope(ctx); - Scoped<QQmlXMLHttpRequestWrapper> w(scope, ctx->thisObject().as<QQmlXMLHttpRequestWrapper>()); + Scoped<QQmlXMLHttpRequestWrapper> w(scope, callData->thisObject.as<QQmlXMLHttpRequestWrapper>()); if (!w) V4THROW_REFERENCE("Not an XMLHttpRequest object"); QQmlXMLHttpRequest *r = w->d()->request; - if (ctx->argc() < 2 || ctx->argc() > 5) - V4THROW_DOM(DOMEXCEPTION_SYNTAX_ERR, "Incorrect argument count"); + if (callData->argc < 2 || callData->argc > 5) + THROW_DOM(DOMEXCEPTION_SYNTAX_ERR, "Incorrect argument count"); // Argument 0 - Method - QString method = ctx->args()[0].toQStringNoThrow().toUpper(); + QString method = callData->args[0].toQStringNoThrow().toUpper(); if (method != QLatin1String("GET") && method != QLatin1String("PUT") && method != QLatin1String("HEAD") && @@ -1754,26 +1737,26 @@ ReturnedValue QQmlXMLHttpRequestCtor::method_open(CallContext *ctx) method != QLatin1String("OPTIONS") && method != QLatin1String("PROPFIND") && method != QLatin1String("PATCH")) - V4THROW_DOM(DOMEXCEPTION_SYNTAX_ERR, "Unsupported HTTP method type"); + THROW_DOM(DOMEXCEPTION_SYNTAX_ERR, "Unsupported HTTP method type"); // Argument 1 - URL - QUrl url = QUrl(ctx->args()[1].toQStringNoThrow()); + QUrl url = QUrl(callData->args[1].toQStringNoThrow()); if (url.isRelative()) url = scope.engine->callingQmlContext()->resolvedUrl(url); bool async = true; // Argument 2 - async (optional) - if (ctx->argc() > 2) { - async = ctx->args()[2].booleanValue(); + if (callData->argc > 2) { + async = callData->args[2].booleanValue(); } // Argument 3/4 - user/pass (optional) QString username, password; - if (ctx->argc() > 3) - username = ctx->args()[3].toQStringNoThrow(); - if (ctx->argc() > 4) - password = ctx->args()[4].toQStringNoThrow(); + if (callData->argc > 3) + username = callData->args[3].toQStringNoThrow(); + if (callData->argc > 4) + password = callData->args[4].toQStringNoThrow(); // Clear the fragment (if any) url.setFragment(QString()); @@ -1782,25 +1765,24 @@ ReturnedValue QQmlXMLHttpRequestCtor::method_open(CallContext *ctx) if (!username.isNull()) url.setUserName(username); if (!password.isNull()) url.setPassword(password); - return r->open(w, scope.engine->callingQmlContext(), method, url, async ? QQmlXMLHttpRequest::AsynchronousLoad : QQmlXMLHttpRequest::SynchronousLoad); + scope.result = r->open(w, scope.engine->callingQmlContext(), method, url, async ? QQmlXMLHttpRequest::AsynchronousLoad : QQmlXMLHttpRequest::SynchronousLoad); } -ReturnedValue QQmlXMLHttpRequestCtor::method_setRequestHeader(CallContext *ctx) +void QQmlXMLHttpRequestCtor::method_setRequestHeader(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData) { - Scope scope(ctx); - Scoped<QQmlXMLHttpRequestWrapper> w(scope, ctx->thisObject().as<QQmlXMLHttpRequestWrapper>()); + Scoped<QQmlXMLHttpRequestWrapper> w(scope, callData->thisObject.as<QQmlXMLHttpRequestWrapper>()); if (!w) V4THROW_REFERENCE("Not an XMLHttpRequest object"); QQmlXMLHttpRequest *r = w->d()->request; - if (ctx->argc() != 2) - V4THROW_DOM(DOMEXCEPTION_SYNTAX_ERR, "Incorrect argument count"); + if (callData->argc != 2) + THROW_DOM(DOMEXCEPTION_SYNTAX_ERR, "Incorrect argument count"); if (r->readyState() != QQmlXMLHttpRequest::Opened || r->sendFlag()) - V4THROW_DOM(DOMEXCEPTION_INVALID_STATE_ERR, "Invalid state"); + THROW_DOM(DOMEXCEPTION_INVALID_STATE_ERR, "Invalid state"); - QString name = ctx->args()[0].toQStringNoThrow(); - QString value = ctx->args()[1].toQStringNoThrow(); + QString name = callData->args[0].toQStringNoThrow(); + QString value = callData->args[1].toQStringNoThrow(); // ### Check that name and value are well formed @@ -1825,148 +1807,139 @@ ReturnedValue QQmlXMLHttpRequestCtor::method_setRequestHeader(CallContext *ctx) nameUpper == QLatin1String("VIA") || nameUpper.startsWith(QLatin1String("PROXY-")) || nameUpper.startsWith(QLatin1String("SEC-"))) - return Encode::undefined(); + RETURN_UNDEFINED(); r->addHeader(name, value); - return Encode::undefined(); + RETURN_UNDEFINED(); } -ReturnedValue QQmlXMLHttpRequestCtor::method_send(CallContext *ctx) +void QQmlXMLHttpRequestCtor::method_send(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData) { - Scope scope(ctx); - Scoped<QQmlXMLHttpRequestWrapper> w(scope, ctx->thisObject().as<QQmlXMLHttpRequestWrapper>()); + Scoped<QQmlXMLHttpRequestWrapper> w(scope, callData->thisObject.as<QQmlXMLHttpRequestWrapper>()); if (!w) V4THROW_REFERENCE("Not an XMLHttpRequest object"); QQmlXMLHttpRequest *r = w->d()->request; if (r->readyState() != QQmlXMLHttpRequest::Opened || r->sendFlag()) - V4THROW_DOM(DOMEXCEPTION_INVALID_STATE_ERR, "Invalid state"); + THROW_DOM(DOMEXCEPTION_INVALID_STATE_ERR, "Invalid state"); QByteArray data; - if (ctx->argc() > 0) - data = ctx->args()[0].toQStringNoThrow().toUtf8(); + if (callData->argc > 0) + data = callData->args[0].toQStringNoThrow().toUtf8(); - return r->send(w, scope.engine->callingQmlContext(), data); + scope.result = r->send(w, scope.engine->callingQmlContext(), data); } -ReturnedValue QQmlXMLHttpRequestCtor::method_abort(CallContext *ctx) +void QQmlXMLHttpRequestCtor::method_abort(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData) { - Scope scope(ctx); - Scoped<QQmlXMLHttpRequestWrapper> w(scope, ctx->thisObject().as<QQmlXMLHttpRequestWrapper>()); + Scoped<QQmlXMLHttpRequestWrapper> w(scope, callData->thisObject.as<QQmlXMLHttpRequestWrapper>()); if (!w) V4THROW_REFERENCE("Not an XMLHttpRequest object"); QQmlXMLHttpRequest *r = w->d()->request; - return r->abort(w, scope.engine->callingQmlContext()); + scope.result = r->abort(w, scope.engine->callingQmlContext()); } -ReturnedValue QQmlXMLHttpRequestCtor::method_getResponseHeader(CallContext *ctx) +void QQmlXMLHttpRequestCtor::method_getResponseHeader(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData) { - Scope scope(ctx); - Scoped<QQmlXMLHttpRequestWrapper> w(scope, ctx->thisObject().as<QQmlXMLHttpRequestWrapper>()); + Scoped<QQmlXMLHttpRequestWrapper> w(scope, callData->thisObject.as<QQmlXMLHttpRequestWrapper>()); if (!w) V4THROW_REFERENCE("Not an XMLHttpRequest object"); QQmlXMLHttpRequest *r = w->d()->request; - if (ctx->argc() != 1) - V4THROW_DOM(DOMEXCEPTION_SYNTAX_ERR, "Incorrect argument count"); + if (callData->argc != 1) + THROW_DOM(DOMEXCEPTION_SYNTAX_ERR, "Incorrect argument count"); if (r->readyState() != QQmlXMLHttpRequest::Loading && r->readyState() != QQmlXMLHttpRequest::Done && r->readyState() != QQmlXMLHttpRequest::HeadersReceived) - V4THROW_DOM(DOMEXCEPTION_INVALID_STATE_ERR, "Invalid state"); + THROW_DOM(DOMEXCEPTION_INVALID_STATE_ERR, "Invalid state"); - return QV4::Encode(scope.engine->newString(r->header(ctx->args()[0].toQStringNoThrow()))); + scope.result = scope.engine->newString(r->header(callData->args[0].toQStringNoThrow())); } -ReturnedValue QQmlXMLHttpRequestCtor::method_getAllResponseHeaders(CallContext *ctx) +void QQmlXMLHttpRequestCtor::method_getAllResponseHeaders(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData) { - Scope scope(ctx); - Scoped<QQmlXMLHttpRequestWrapper> w(scope, ctx->thisObject().as<QQmlXMLHttpRequestWrapper>()); + Scoped<QQmlXMLHttpRequestWrapper> w(scope, callData->thisObject.as<QQmlXMLHttpRequestWrapper>()); if (!w) V4THROW_REFERENCE("Not an XMLHttpRequest object"); QQmlXMLHttpRequest *r = w->d()->request; - if (ctx->argc() != 0) - V4THROW_DOM(DOMEXCEPTION_SYNTAX_ERR, "Incorrect argument count"); + if (callData->argc != 0) + THROW_DOM(DOMEXCEPTION_SYNTAX_ERR, "Incorrect argument count"); if (r->readyState() != QQmlXMLHttpRequest::Loading && r->readyState() != QQmlXMLHttpRequest::Done && r->readyState() != QQmlXMLHttpRequest::HeadersReceived) - V4THROW_DOM(DOMEXCEPTION_INVALID_STATE_ERR, "Invalid state"); + THROW_DOM(DOMEXCEPTION_INVALID_STATE_ERR, "Invalid state"); - return QV4::Encode(scope.engine->newString(r->headers())); + scope.result = scope.engine->newString(r->headers()); } // XMLHttpRequest properties -ReturnedValue QQmlXMLHttpRequestCtor::method_get_readyState(CallContext *ctx) +void QQmlXMLHttpRequestCtor::method_get_readyState(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData) { - Scope scope(ctx); - Scoped<QQmlXMLHttpRequestWrapper> w(scope, ctx->thisObject().as<QQmlXMLHttpRequestWrapper>()); + Scoped<QQmlXMLHttpRequestWrapper> w(scope, callData->thisObject.as<QQmlXMLHttpRequestWrapper>()); if (!w) V4THROW_REFERENCE("Not an XMLHttpRequest object"); QQmlXMLHttpRequest *r = w->d()->request; - return Encode(r->readyState()); + scope.result = Encode(r->readyState()); } -ReturnedValue QQmlXMLHttpRequestCtor::method_get_status(CallContext *ctx) +void QQmlXMLHttpRequestCtor::method_get_status(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData) { - Scope scope(ctx); - Scoped<QQmlXMLHttpRequestWrapper> w(scope, ctx->thisObject().as<QQmlXMLHttpRequestWrapper>()); + Scoped<QQmlXMLHttpRequestWrapper> w(scope, callData->thisObject.as<QQmlXMLHttpRequestWrapper>()); if (!w) V4THROW_REFERENCE("Not an XMLHttpRequest object"); QQmlXMLHttpRequest *r = w->d()->request; if (r->readyState() == QQmlXMLHttpRequest::Unsent || r->readyState() == QQmlXMLHttpRequest::Opened) - V4THROW_DOM(DOMEXCEPTION_INVALID_STATE_ERR, "Invalid state"); + THROW_DOM(DOMEXCEPTION_INVALID_STATE_ERR, "Invalid state"); if (r->errorFlag()) - return Encode(0); + scope.result = Encode(0); else - return Encode(r->replyStatus()); + scope.result = Encode(r->replyStatus()); } -ReturnedValue QQmlXMLHttpRequestCtor::method_get_statusText(CallContext *ctx) +void QQmlXMLHttpRequestCtor::method_get_statusText(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData) { - Scope scope(ctx); - Scoped<QQmlXMLHttpRequestWrapper> w(scope, ctx->thisObject().as<QQmlXMLHttpRequestWrapper>()); + Scoped<QQmlXMLHttpRequestWrapper> w(scope, callData->thisObject.as<QQmlXMLHttpRequestWrapper>()); if (!w) V4THROW_REFERENCE("Not an XMLHttpRequest object"); QQmlXMLHttpRequest *r = w->d()->request; if (r->readyState() == QQmlXMLHttpRequest::Unsent || r->readyState() == QQmlXMLHttpRequest::Opened) - V4THROW_DOM(DOMEXCEPTION_INVALID_STATE_ERR, "Invalid state"); + THROW_DOM(DOMEXCEPTION_INVALID_STATE_ERR, "Invalid state"); if (r->errorFlag()) - return QV4::Encode(scope.engine->newString(QString())); + scope.result = scope.engine->newString(QString()); else - return QV4::Encode(scope.engine->newString(r->replyStatusText())); + scope.result = scope.engine->newString(r->replyStatusText()); } -ReturnedValue QQmlXMLHttpRequestCtor::method_get_responseText(CallContext *ctx) +void QQmlXMLHttpRequestCtor::method_get_responseText(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData) { - Scope scope(ctx); - Scoped<QQmlXMLHttpRequestWrapper> w(scope, ctx->thisObject().as<QQmlXMLHttpRequestWrapper>()); + Scoped<QQmlXMLHttpRequestWrapper> w(scope, callData->thisObject.as<QQmlXMLHttpRequestWrapper>()); if (!w) V4THROW_REFERENCE("Not an XMLHttpRequest object"); QQmlXMLHttpRequest *r = w->d()->request; if (r->readyState() != QQmlXMLHttpRequest::Loading && r->readyState() != QQmlXMLHttpRequest::Done) - return QV4::Encode(scope.engine->newString(QString())); + scope.result = scope.engine->newString(QString()); else - return QV4::Encode(scope.engine->newString(r->responseBody())); + scope.result = scope.engine->newString(r->responseBody()); } -ReturnedValue QQmlXMLHttpRequestCtor::method_get_responseXML(CallContext *ctx) +void QQmlXMLHttpRequestCtor::method_get_responseXML(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData) { - Scope scope(ctx); - Scoped<QQmlXMLHttpRequestWrapper> w(scope, ctx->thisObject().as<QQmlXMLHttpRequestWrapper>()); + Scoped<QQmlXMLHttpRequestWrapper> w(scope, callData->thisObject.as<QQmlXMLHttpRequestWrapper>()); if (!w) V4THROW_REFERENCE("Not an XMLHttpRequest object"); QQmlXMLHttpRequest *r = w->d()->request; @@ -1974,66 +1947,63 @@ ReturnedValue QQmlXMLHttpRequestCtor::method_get_responseXML(CallContext *ctx) if (!r->receivedXml() || (r->readyState() != QQmlXMLHttpRequest::Loading && r->readyState() != QQmlXMLHttpRequest::Done)) { - return Encode::null(); + scope.result = Encode::null(); } else { if (r->responseType().isEmpty()) r->setResponseType(QLatin1String("document")); - return r->xmlResponseBody(scope.engine); + scope.result = r->xmlResponseBody(scope.engine); } } -ReturnedValue QQmlXMLHttpRequestCtor::method_get_response(CallContext *ctx) +void QQmlXMLHttpRequestCtor::method_get_response(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData) { - Scope scope(ctx); - Scoped<QQmlXMLHttpRequestWrapper> w(scope, ctx->thisObject().as<QQmlXMLHttpRequestWrapper>()); + Scoped<QQmlXMLHttpRequestWrapper> w(scope, callData->thisObject.as<QQmlXMLHttpRequestWrapper>()); if (!w) V4THROW_REFERENCE("Not an XMLHttpRequest object"); QQmlXMLHttpRequest *r = w->d()->request; if (r->readyState() != QQmlXMLHttpRequest::Loading && r->readyState() != QQmlXMLHttpRequest::Done) - return QV4::Encode(scope.engine->newString(QString())); + RETURN_RESULT(scope.engine->newString(QString())); const QString& responseType = r->responseType(); if (responseType.compare(QLatin1String("text"), Qt::CaseInsensitive) == 0 || responseType.isEmpty()) { - return QV4::Encode(scope.engine->newString(r->responseBody())); + RETURN_RESULT(scope.engine->newString(r->responseBody())); } else if (responseType.compare(QLatin1String("arraybuffer"), Qt::CaseInsensitive) == 0) { - return QV4::Encode(scope.engine->newArrayBuffer(r->rawResponseBody())); + RETURN_RESULT(scope.engine->newArrayBuffer(r->rawResponseBody())); } else if (responseType.compare(QLatin1String("json"), Qt::CaseInsensitive) == 0) { - return r->jsonResponseBody(scope.engine); + RETURN_RESULT(r->jsonResponseBody(scope.engine)); } else if (responseType.compare(QLatin1String("document"), Qt::CaseInsensitive) == 0) { - return r->xmlResponseBody(scope.engine); + RETURN_RESULT(r->xmlResponseBody(scope.engine)); } else { - return QV4::Encode(scope.engine->newString(QString())); + RETURN_RESULT(scope.engine->newString(QString())); } } -ReturnedValue QQmlXMLHttpRequestCtor::method_get_responseType(CallContext *ctx) +void QQmlXMLHttpRequestCtor::method_get_responseType(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData) { - Scope scope(ctx); - Scoped<QQmlXMLHttpRequestWrapper> w(scope, ctx->thisObject().as<QQmlXMLHttpRequestWrapper>()); + Scoped<QQmlXMLHttpRequestWrapper> w(scope, callData->thisObject.as<QQmlXMLHttpRequestWrapper>()); if (!w) V4THROW_REFERENCE("Not an XMLHttpRequest object"); QQmlXMLHttpRequest *r = w->d()->request; - return QV4::Encode(scope.engine->newString(r->responseType())); + scope.result = scope.engine->newString(r->responseType()); } -ReturnedValue QQmlXMLHttpRequestCtor::method_set_responseType(CallContext *ctx) +void QQmlXMLHttpRequestCtor::method_set_responseType(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData) { - Scope scope(ctx); - Scoped<QQmlXMLHttpRequestWrapper> w(scope, ctx->thisObject().as<QQmlXMLHttpRequestWrapper>()); + Scoped<QQmlXMLHttpRequestWrapper> w(scope, callData->thisObject.as<QQmlXMLHttpRequestWrapper>()); if (!w) V4THROW_REFERENCE("Not an XMLHttpRequest object"); QQmlXMLHttpRequest *r = w->d()->request; - if (ctx->argc() < 1) - V4THROW_DOM(DOMEXCEPTION_SYNTAX_ERR, "Incorrect argument count"); + if (callData->argc < 1) + THROW_DOM(DOMEXCEPTION_SYNTAX_ERR, "Incorrect argument count"); // Argument 0 - response type - r->setResponseType(ctx->args()[0].toQStringNoThrow()); + r->setResponseType(callData->args[0].toQStringNoThrow()); - return Encode::undefined(); + scope.result = Encode::undefined(); } void qt_rem_qmlxmlhttprequest(ExecutionEngine * /* engine */, void *d) diff --git a/src/qml/qml/v8/qqmlbuiltinfunctions.cpp b/src/qml/qml/v8/qqmlbuiltinfunctions.cpp index 19dc100f40..d359a0f62f 100644 --- a/src/qml/qml/v8/qqmlbuiltinfunctions.cpp +++ b/src/qml/qml/v8/qqmlbuiltinfunctions.cpp @@ -85,6 +85,12 @@ using namespace QV4; DEFINE_OBJECT_VTABLE(QtObject); +#define THROW_TYPE_ERROR_WITH_MESSAGE(msg) \ + do { \ + scope.result = scope.engine->throwTypeError(QString::fromUtf8(msg)); \ + return; \ + } while (false) + struct StaticQtMetaObject : public QObject { static const QMetaObject *get() @@ -223,12 +229,12 @@ void QtObject::advanceIterator(Managed *m, ObjectIterator *it, Value *name, uint \qmlmethod bool Qt::isQtObject(object) Returns true if \c object is a valid reference to a Qt or QML object, otherwise false. */ -ReturnedValue QtObject::method_isQtObject(QV4::CallContext *ctx) +void QtObject::method_isQtObject(const BuiltinFunction *, Scope &scope, CallData *callData) { - if (ctx->argc() == 0) - return QV4::Encode(false); + if (callData->argc == 0) + RETURN_RESULT(QV4::Encode(false)); - return QV4::Encode(ctx->args()[0].as<QV4::QObjectWrapper>() != 0); + scope.result = QV4::Encode(callData->args[0].as<QV4::QObjectWrapper>() != 0); } /*! @@ -237,16 +243,16 @@ ReturnedValue QtObject::method_isQtObject(QV4::CallContext *ctx) Returns a color with the specified \c red, \c green, \c blue and \c alpha components. All components should be in the range 0-1 inclusive. */ -ReturnedValue QtObject::method_rgba(QV4::CallContext *ctx) +void QtObject::method_rgba(const BuiltinFunction *, Scope &scope, CallData *callData) { - int argCount = ctx->argc(); + int argCount = callData->argc; if (argCount < 3 || argCount > 4) - V4THROW_ERROR("Qt.rgba(): Invalid arguments"); + THROW_GENERIC_ERROR("Qt.rgba(): Invalid arguments"); - double r = ctx->args()[0].toNumber(); - double g = ctx->args()[1].toNumber(); - double b = ctx->args()[2].toNumber(); - double a = (argCount == 4) ? ctx->args()[3].toNumber() : 1; + double r = callData->args[0].toNumber(); + double g = callData->args[1].toNumber(); + double b = callData->args[2].toNumber(); + double a = (argCount == 4) ? callData->args[3].toNumber() : 1; if (r < 0.0) r=0.0; if (r > 1.0) r=1.0; @@ -257,7 +263,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()->fromVariant(QQml_colorProvider()->fromRgbF(r, g, b, a)); + scope.result = scope.engine->fromVariant(QQml_colorProvider()->fromRgbF(r, g, b, a)); } /*! @@ -266,16 +272,16 @@ ReturnedValue QtObject::method_rgba(QV4::CallContext *ctx) Returns a color with the specified \c hue, \c saturation, \c lightness and \c alpha components. All components should be in the range 0-1 inclusive. */ -ReturnedValue QtObject::method_hsla(QV4::CallContext *ctx) +void QtObject::method_hsla(const BuiltinFunction *, Scope &scope, CallData *callData) { - int argCount = ctx->argc(); + int argCount = callData->argc; if (argCount < 3 || argCount > 4) - V4THROW_ERROR("Qt.hsla(): Invalid arguments"); + THROW_GENERIC_ERROR("Qt.hsla(): Invalid arguments"); - double h = ctx->args()[0].toNumber(); - double s = ctx->args()[1].toNumber(); - double l = ctx->args()[2].toNumber(); - double a = (argCount == 4) ? ctx->args()[3].toNumber() : 1; + double h = callData->args[0].toNumber(); + double s = callData->args[1].toNumber(); + double l = callData->args[2].toNumber(); + double a = (argCount == 4) ? callData->args[3].toNumber() : 1; if (h < 0.0) h=0.0; if (h > 1.0) h=1.0; @@ -286,7 +292,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()->fromVariant(QQml_colorProvider()->fromHslF(h, s, l, a)); + scope.result = scope.engine->fromVariant(QQml_colorProvider()->fromHslF(h, s, l, a)); } /*! @@ -297,23 +303,23 @@ All components should be in the range 0-1 inclusive. \since 5.5 */ -ReturnedValue QtObject::method_hsva(QV4::CallContext *ctx) +void QtObject::method_hsva(const BuiltinFunction *, Scope &scope, CallData *callData) { - int argCount = ctx->argc(); + int argCount = callData->argc; if (argCount < 3 || argCount > 4) - V4THROW_ERROR("Qt.hsva(): Invalid arguments"); + THROW_GENERIC_ERROR("Qt.hsva(): Invalid arguments"); - double h = ctx->args()[0].toNumber(); - double s = ctx->args()[1].toNumber(); - double v = ctx->args()[2].toNumber(); - double a = (argCount == 4) ? ctx->args()[3].toNumber() : 1; + double h = callData->args[0].toNumber(); + double s = callData->args[1].toNumber(); + double v = callData->args[2].toNumber(); + double a = (argCount == 4) ? callData->args[3].toNumber() : 1; h = qBound(0.0, h, 1.0); s = qBound(0.0, s, 1.0); v = qBound(0.0, v, 1.0); a = qBound(0.0, a, 1.0); - return ctx->engine()->fromVariant(QQml_colorProvider()->fromHsvF(h, s, v, a)); + scope.result = scope.engine->fromVariant(QQml_colorProvider()->fromHsvF(h, s, v, a)); } /*! @@ -324,35 +330,35 @@ may be either color values or string values. If a string value is supplied it must be convertible to a color, as described for the \l{colorbasictypedocs}{color} basic type. */ -ReturnedValue QtObject::method_colorEqual(QV4::CallContext *ctx) +void QtObject::method_colorEqual(const BuiltinFunction *, Scope &scope, CallData *callData) { - if (ctx->argc() != 2) - V4THROW_ERROR("Qt.colorEqual(): Invalid arguments"); + if (callData->argc != 2) + THROW_GENERIC_ERROR("Qt.colorEqual(): Invalid arguments"); bool ok = false; - QVariant lhs = ctx->d()->engine->toVariant(ctx->args()[0], -1); + QVariant lhs = scope.engine->toVariant(callData->args[0], -1); if (lhs.userType() == QVariant::String) { lhs = QQmlStringConverters::colorFromString(lhs.toString(), &ok); if (!ok) { - V4THROW_ERROR("Qt.colorEqual(): Invalid color name"); + THROW_GENERIC_ERROR("Qt.colorEqual(): Invalid color name"); } } else if (lhs.userType() != QVariant::Color) { - V4THROW_ERROR("Qt.colorEqual(): Invalid arguments"); + THROW_GENERIC_ERROR("Qt.colorEqual(): Invalid arguments"); } - QVariant rhs = ctx->engine()->toVariant(ctx->args()[1], -1); + QVariant rhs = scope.engine->toVariant(callData->args[1], -1); if (rhs.userType() == QVariant::String) { rhs = QQmlStringConverters::colorFromString(rhs.toString(), &ok); if (!ok) { - V4THROW_ERROR("Qt.colorEqual(): Invalid color name"); + THROW_GENERIC_ERROR("Qt.colorEqual(): Invalid color name"); } } else if (rhs.userType() != QVariant::Color) { - V4THROW_ERROR("Qt.colorEqual(): Invalid arguments"); + THROW_GENERIC_ERROR("Qt.colorEqual(): Invalid arguments"); } bool equal = (lhs == rhs); - return QV4::Encode(equal); + scope.result = QV4::Encode(equal); } /*! @@ -362,47 +368,47 @@ Returns a \c rect with the top-left corner at \c x, \c y and the specified \c wi The returned object has \c x, \c y, \c width and \c height attributes with the given values. */ -ReturnedValue QtObject::method_rect(QV4::CallContext *ctx) +void QtObject::method_rect(const BuiltinFunction *, Scope &scope, CallData *callData) { - if (ctx->argc() != 4) - V4THROW_ERROR("Qt.rect(): Invalid arguments"); + if (callData->argc != 4) + THROW_GENERIC_ERROR("Qt.rect(): Invalid arguments"); - double x = ctx->args()[0].toNumber(); - double y = ctx->args()[1].toNumber(); - double w = ctx->args()[2].toNumber(); - double h = ctx->args()[3].toNumber(); + double x = callData->args[0].toNumber(); + double y = callData->args[1].toNumber(); + double w = callData->args[2].toNumber(); + double h = callData->args[3].toNumber(); - return ctx->engine()->fromVariant(QVariant::fromValue(QRectF(x, y, w, h))); + scope.result = scope.engine->fromVariant(QVariant::fromValue(QRectF(x, y, w, h))); } /*! \qmlmethod point Qt::point(int x, int y) Returns a Point with the specified \c x and \c y coordinates. */ -ReturnedValue QtObject::method_point(QV4::CallContext *ctx) +void QtObject::method_point(const BuiltinFunction *, Scope &scope, CallData *callData) { - if (ctx->argc() != 2) - V4THROW_ERROR("Qt.point(): Invalid arguments"); + if (callData->argc != 2) + THROW_GENERIC_ERROR("Qt.point(): Invalid arguments"); - double x = ctx->args()[0].toNumber(); - double y = ctx->args()[1].toNumber(); + double x = callData->args[0].toNumber(); + double y = callData->args[1].toNumber(); - return ctx->engine()->fromVariant(QVariant::fromValue(QPointF(x, y))); + scope.result = scope.engine->fromVariant(QVariant::fromValue(QPointF(x, y))); } /*! \qmlmethod Qt::size(int width, int height) Returns a Size with the specified \c width and \c height. */ -ReturnedValue QtObject::method_size(QV4::CallContext *ctx) +void QtObject::method_size(const BuiltinFunction *, Scope &scope, CallData *callData) { - if (ctx->argc() != 2) - V4THROW_ERROR("Qt.size(): Invalid arguments"); + if (callData->argc != 2) + THROW_GENERIC_ERROR("Qt.size(): Invalid arguments"); - double w = ctx->args()[0].toNumber(); - double h = ctx->args()[1].toNumber(); + double w = callData->args[0].toNumber(); + double h = callData->args[1].toNumber(); - return ctx->engine()->fromVariant(QVariant::fromValue(QSizeF(w, h))); + scope.result = scope.engine->fromVariant(QVariant::fromValue(QSizeF(w, h))); } /*! @@ -413,17 +419,17 @@ key-value pairs where valid keys are the \l{fontbasictypedocs}{font} type's subproperty names, and the values are valid values for each subproperty. Invalid keys will be ignored. */ -ReturnedValue QtObject::method_font(QV4::CallContext *ctx) +void QtObject::method_font(const BuiltinFunction *, Scope &scope, CallData *callData) { - if (ctx->argc() != 1 || !ctx->args()[0].isObject()) - V4THROW_ERROR("Qt.font(): Invalid arguments"); + if (callData->argc != 1 || !callData->args[0].isObject()) + THROW_GENERIC_ERROR("Qt.font(): Invalid arguments"); - QV4::ExecutionEngine *v4 = ctx->d()->engine; + QV4::ExecutionEngine *v4 = scope.engine; bool ok = false; - QVariant v = QQml_valueTypeProvider()->createVariantFromJsObject(QMetaType::QFont, QQmlV4Handle(ctx->args()[0]), v4, &ok); + QVariant v = QQml_valueTypeProvider()->createVariantFromJsObject(QMetaType::QFont, QQmlV4Handle(callData->args[0]), v4, &ok); if (!ok) - V4THROW_ERROR("Qt.font(): Invalid argument: no valid font subproperties specified"); - return ctx->engine()->fromVariant(v); + THROW_GENERIC_ERROR("Qt.font(): Invalid argument: no valid font subproperties specified"); + scope.result = scope.engine->fromVariant(v); } @@ -432,73 +438,73 @@ ReturnedValue QtObject::method_font(QV4::CallContext *ctx) \qmlmethod Qt::vector2d(real x, real y) Returns a Vector2D with the specified \c x and \c y. */ -ReturnedValue QtObject::method_vector2d(QV4::CallContext *ctx) +void QtObject::method_vector2d(const BuiltinFunction *, Scope &scope, CallData *callData) { - if (ctx->argc() != 2) - V4THROW_ERROR("Qt.vector2d(): Invalid arguments"); + if (callData->argc != 2) + THROW_GENERIC_ERROR("Qt.vector2d(): Invalid arguments"); float xy[3]; // qvector2d uses float internally - xy[0] = ctx->args()[0].toNumber(); - xy[1] = ctx->args()[1].toNumber(); + xy[0] = callData->args[0].toNumber(); + xy[1] = callData->args[1].toNumber(); const void *params[] = { xy }; - return ctx->engine()->fromVariant(QQml_valueTypeProvider()->createValueType(QMetaType::QVector2D, 1, params)); + scope.result = scope.engine->fromVariant(QQml_valueTypeProvider()->createValueType(QMetaType::QVector2D, 1, params)); } /*! \qmlmethod Qt::vector3d(real x, real y, real z) Returns a Vector3D with the specified \c x, \c y and \c z. */ -ReturnedValue QtObject::method_vector3d(QV4::CallContext *ctx) +void QtObject::method_vector3d(const BuiltinFunction *, Scope &scope, CallData *callData) { - if (ctx->argc() != 3) - V4THROW_ERROR("Qt.vector3d(): Invalid arguments"); + if (callData->argc != 3) + THROW_GENERIC_ERROR("Qt.vector3d(): Invalid arguments"); float xyz[3]; // qvector3d uses float internally - xyz[0] = ctx->args()[0].toNumber(); - xyz[1] = ctx->args()[1].toNumber(); - xyz[2] = ctx->args()[2].toNumber(); + xyz[0] = callData->args[0].toNumber(); + xyz[1] = callData->args[1].toNumber(); + xyz[2] = callData->args[2].toNumber(); const void *params[] = { xyz }; - return ctx->engine()->fromVariant(QQml_valueTypeProvider()->createValueType(QMetaType::QVector3D, 1, params)); + scope.result = scope.engine->fromVariant(QQml_valueTypeProvider()->createValueType(QMetaType::QVector3D, 1, params)); } /*! \qmlmethod Qt::vector4d(real x, real y, real z, real w) Returns a Vector4D with the specified \c x, \c y, \c z and \c w. */ -ReturnedValue QtObject::method_vector4d(QV4::CallContext *ctx) +void QtObject::method_vector4d(const BuiltinFunction *, Scope &scope, CallData *callData) { - if (ctx->argc() != 4) - V4THROW_ERROR("Qt.vector4d(): Invalid arguments"); + if (callData->argc != 4) + THROW_GENERIC_ERROR("Qt.vector4d(): Invalid arguments"); float xyzw[4]; // qvector4d uses float internally - xyzw[0] = ctx->args()[0].toNumber(); - xyzw[1] = ctx->args()[1].toNumber(); - xyzw[2] = ctx->args()[2].toNumber(); - xyzw[3] = ctx->args()[3].toNumber(); + xyzw[0] = callData->args[0].toNumber(); + xyzw[1] = callData->args[1].toNumber(); + xyzw[2] = callData->args[2].toNumber(); + xyzw[3] = callData->args[3].toNumber(); const void *params[] = { xyzw }; - return ctx->engine()->fromVariant(QQml_valueTypeProvider()->createValueType(QMetaType::QVector4D, 1, params)); + scope.result = scope.engine->fromVariant(QQml_valueTypeProvider()->createValueType(QMetaType::QVector4D, 1, params)); } /*! \qmlmethod Qt::quaternion(real scalar, real x, real y, real z) Returns a Quaternion with the specified \c scalar, \c x, \c y, and \c z. */ -ReturnedValue QtObject::method_quaternion(QV4::CallContext *ctx) +void QtObject::method_quaternion(const BuiltinFunction *, Scope &scope, CallData *callData) { - if (ctx->argc() != 4) - V4THROW_ERROR("Qt.quaternion(): Invalid arguments"); + if (callData->argc != 4) + THROW_GENERIC_ERROR("Qt.quaternion(): Invalid arguments"); qreal sxyz[4]; // qquaternion uses qreal internally - sxyz[0] = ctx->args()[0].toNumber(); - sxyz[1] = ctx->args()[1].toNumber(); - sxyz[2] = ctx->args()[2].toNumber(); - sxyz[3] = ctx->args()[3].toNumber(); + sxyz[0] = callData->args[0].toNumber(); + sxyz[1] = callData->args[1].toNumber(); + sxyz[2] = callData->args[2].toNumber(); + sxyz[3] = callData->args[3].toNumber(); const void *params[] = { sxyz }; - return ctx->engine()->fromVariant(QQml_valueTypeProvider()->createValueType(QMetaType::QQuaternion, 1, params)); + scope.result = scope.engine->fromVariant(QQml_valueTypeProvider()->createValueType(QMetaType::QQuaternion, 1, params)); } /*! @@ -510,44 +516,47 @@ matrix values. Finally, the function may be called with no arguments and the resulting matrix will be the identity matrix. */ -ReturnedValue QtObject::method_matrix4x4(QV4::CallContext *ctx) +void QtObject::method_matrix4x4(const BuiltinFunction *, Scope &scope, CallData *callData) { - QV4::ExecutionEngine *v4 = ctx->d()->engine; + QV4::ExecutionEngine *v4 = scope.engine; - if (ctx->argc() == 0) - return ctx->engine()->fromVariant(QQml_valueTypeProvider()->createValueType(QMetaType::QMatrix4x4, 0, Q_NULLPTR)); + if (callData->argc == 0) { + scope.result = scope.engine->fromVariant(QQml_valueTypeProvider()->createValueType(QMetaType::QMatrix4x4, 0, Q_NULLPTR)); + return; + } - if (ctx->argc() == 1 && ctx->args()[0].isObject()) { + if (callData->argc == 1 && callData->args[0].isObject()) { bool ok = false; - QVariant v = QQml_valueTypeProvider()->createVariantFromJsObject(QMetaType::QMatrix4x4, QQmlV4Handle(ctx->args()[0]), v4, &ok); + QVariant v = QQml_valueTypeProvider()->createVariantFromJsObject(QMetaType::QMatrix4x4, QQmlV4Handle(callData->args[0]), v4, &ok); if (!ok) - V4THROW_ERROR("Qt.matrix4x4(): Invalid argument: not a valid matrix4x4 values array"); - return ctx->engine()->fromVariant(v); + THROW_GENERIC_ERROR("Qt.matrix4x4(): Invalid argument: not a valid matrix4x4 values array"); + scope.result = scope.engine->fromVariant(v); + return; } - if (ctx->argc() != 16) - V4THROW_ERROR("Qt.matrix4x4(): Invalid arguments"); + if (callData->argc != 16) + THROW_GENERIC_ERROR("Qt.matrix4x4(): Invalid arguments"); qreal vals[16]; // qmatrix4x4 uses qreal internally - vals[0] = ctx->args()[0].toNumber(); - vals[1] = ctx->args()[1].toNumber(); - vals[2] = ctx->args()[2].toNumber(); - vals[3] = ctx->args()[3].toNumber(); - vals[4] = ctx->args()[4].toNumber(); - vals[5] = ctx->args()[5].toNumber(); - vals[6] = ctx->args()[6].toNumber(); - vals[7] = ctx->args()[7].toNumber(); - vals[8] = ctx->args()[8].toNumber(); - vals[9] = ctx->args()[9].toNumber(); - vals[10] = ctx->args()[10].toNumber(); - vals[11] = ctx->args()[11].toNumber(); - vals[12] = ctx->args()[12].toNumber(); - vals[13] = ctx->args()[13].toNumber(); - vals[14] = ctx->args()[14].toNumber(); - vals[15] = ctx->args()[15].toNumber(); + vals[0] = callData->args[0].toNumber(); + vals[1] = callData->args[1].toNumber(); + vals[2] = callData->args[2].toNumber(); + vals[3] = callData->args[3].toNumber(); + vals[4] = callData->args[4].toNumber(); + vals[5] = callData->args[5].toNumber(); + vals[6] = callData->args[6].toNumber(); + vals[7] = callData->args[7].toNumber(); + vals[8] = callData->args[8].toNumber(); + vals[9] = callData->args[9].toNumber(); + vals[10] = callData->args[10].toNumber(); + vals[11] = callData->args[11].toNumber(); + vals[12] = callData->args[12].toNumber(); + vals[13] = callData->args[13].toNumber(); + vals[14] = callData->args[14].toNumber(); + vals[15] = callData->args[15].toNumber(); const void *params[] = { vals }; - return ctx->engine()->fromVariant(QQml_valueTypeProvider()->createValueType(QMetaType::QMatrix4x4, 1, params)); + scope.result = scope.engine->fromVariant(QQml_valueTypeProvider()->createValueType(QMetaType::QMatrix4x4, 1, params)); } /*! @@ -564,27 +573,29 @@ by factor and converts the color back to RGB. If \c factor is not supplied, returns a color 50% lighter than \c baseColor (factor 1.5). */ -ReturnedValue QtObject::method_lighter(QV4::CallContext *ctx) +void QtObject::method_lighter(const BuiltinFunction *, Scope &scope, CallData *callData) { - if (ctx->argc() != 1 && ctx->argc() != 2) - V4THROW_ERROR("Qt.lighter(): Invalid arguments"); + if (callData->argc != 1 && callData->argc != 2) + THROW_GENERIC_ERROR("Qt.lighter(): Invalid arguments"); - QVariant v = ctx->engine()->toVariant(ctx->args()[0], -1); + QVariant v = scope.engine->toVariant(callData->args[0], -1); if (v.userType() == QVariant::String) { bool ok = false; v = QQmlStringConverters::colorFromString(v.toString(), &ok); if (!ok) { - return QV4::Encode::null(); + scope.result = QV4::Encode::null(); + return; } } else if (v.userType() != QVariant::Color) { - return QV4::Encode::null(); + scope.result = QV4::Encode::null(); + return; } qreal factor = 1.5; - if (ctx->argc() == 2) - factor = ctx->args()[1].toNumber(); + if (callData->argc == 2) + factor = callData->args[1].toNumber(); - return ctx->engine()->fromVariant(QQml_colorProvider()->lighter(v, factor)); + scope.result = scope.engine->fromVariant(QQml_colorProvider()->lighter(v, factor)); } /*! @@ -602,27 +613,29 @@ by factor and converts the color back to RGB. If \c factor is not supplied, returns a color 50% darker than \c baseColor (factor 2.0). */ -ReturnedValue QtObject::method_darker(QV4::CallContext *ctx) +void QtObject::method_darker(const BuiltinFunction *, Scope &scope, CallData *callData) { - if (ctx->argc() != 1 && ctx->argc() != 2) - V4THROW_ERROR("Qt.darker(): Invalid arguments"); + if (callData->argc != 1 && callData->argc != 2) + THROW_GENERIC_ERROR("Qt.darker(): Invalid arguments"); - QVariant v = ctx->engine()->toVariant(ctx->args()[0], -1); + QVariant v = scope.engine->toVariant(callData->args[0], -1); if (v.userType() == QVariant::String) { bool ok = false; v = QQmlStringConverters::colorFromString(v.toString(), &ok); if (!ok) { - return QV4::Encode::null(); + scope.result = QV4::Encode::null(); + return; } } else if (v.userType() != QVariant::Color) { - return QV4::Encode::null(); + scope.result = QV4::Encode::null(); + return; } qreal factor = 2.0; - if (ctx->argc() == 2) - factor = ctx->args()[1].toNumber(); + if (callData->argc == 2) + factor = callData->args[1].toNumber(); - return ctx->engine()->fromVariant(QQml_colorProvider()->darker(v, factor)); + scope.result = scope.engine->fromVariant(QQml_colorProvider()->darker(v, factor)); } /*! @@ -649,36 +662,40 @@ ReturnedValue QtObject::method_darker(QV4::CallContext *ctx) Tint is most useful when a subtle change is intended to be conveyed due to some event; you can then use tinting to more effectively tune the visible color. */ -ReturnedValue QtObject::method_tint(QV4::CallContext *ctx) +void QtObject::method_tint(const BuiltinFunction *, Scope &scope, CallData *callData) { - if (ctx->argc() != 2) - V4THROW_ERROR("Qt.tint(): Invalid arguments"); + if (callData->argc != 2) + THROW_GENERIC_ERROR("Qt.tint(): Invalid arguments"); // base color - QVariant v1 = ctx->engine()->toVariant(ctx->args()[0], -1); + QVariant v1 = scope.engine->toVariant(callData->args[0], -1); if (v1.userType() == QVariant::String) { bool ok = false; v1 = QQmlStringConverters::colorFromString(v1.toString(), &ok); if (!ok) { - return QV4::Encode::null(); + scope.result = QV4::Encode::null(); + return; } } else if (v1.userType() != QVariant::Color) { - return QV4::Encode::null(); + scope.result = QV4::Encode::null(); + return; } // tint color - QVariant v2 = ctx->engine()->toVariant(ctx->args()[1], -1); + QVariant v2 = scope.engine->toVariant(callData->args[1], -1); if (v2.userType() == QVariant::String) { bool ok = false; v2 = QQmlStringConverters::colorFromString(v2.toString(), &ok); if (!ok) { - return QV4::Encode::null(); + scope.result = QV4::Encode::null(); + return; } } else if (v2.userType() != QVariant::Color) { - return QV4::Encode::null(); + scope.result = QV4::Encode::null(); + return; } - return ctx->engine()->fromVariant(QQml_colorProvider()->tint(v1, v2)); + scope.result = scope.engine->fromVariant(QQml_colorProvider()->tint(v1, v2)); } /*! @@ -697,32 +714,31 @@ If \a format is not specified, \a date is formatted using \sa Locale */ -ReturnedValue QtObject::method_formatDate(QV4::CallContext *ctx) +void QtObject::method_formatDate(const BuiltinFunction *, Scope &scope, CallData *callData) { - if (ctx->argc() < 1 || ctx->argc() > 2) - V4THROW_ERROR("Qt.formatDate(): Invalid arguments"); - QV4::Scope scope(ctx); + if (callData->argc < 1 || callData->argc > 2) + THROW_GENERIC_ERROR("Qt.formatDate(): Invalid arguments"); Qt::DateFormat enumFormat = Qt::DefaultLocaleShortDate; - QDate date = ctx->engine()->toVariant(ctx->args()[0], -1).toDateTime().date(); + QDate date = scope.engine->toVariant(callData->args[0], -1).toDateTime().date(); QString formattedDate; - if (ctx->argc() == 2) { - QV4::ScopedString s(scope, ctx->args()[1]); + if (callData->argc == 2) { + QV4::ScopedString s(scope, callData->args[1]); if (s) { QString format = s->toQString(); formattedDate = date.toString(format); - } else if (ctx->args()[1].isNumber()) { - quint32 intFormat = ctx->args()[1].asDouble(); + } else if (callData->args[1].isNumber()) { + quint32 intFormat = callData->args[1].asDouble(); Qt::DateFormat format = Qt::DateFormat(intFormat); formattedDate = date.toString(format); } else { - V4THROW_ERROR("Qt.formatDate(): Invalid date format"); + THROW_GENERIC_ERROR("Qt.formatDate(): Invalid date format"); } } else { formattedDate = date.toString(enumFormat); } - return ctx->d()->engine->newString(formattedDate)->asReturnedValue(); + scope.result = scope.engine->newString(formattedDate); } /*! @@ -740,38 +756,37 @@ If \a format is not specified, \a time is formatted using \sa Locale */ -ReturnedValue QtObject::method_formatTime(QV4::CallContext *ctx) +void QtObject::method_formatTime(const BuiltinFunction *, Scope &scope, CallData *callData) { - if (ctx->argc() < 1 || ctx->argc() > 2) - V4THROW_ERROR("Qt.formatTime(): Invalid arguments"); - QV4::Scope scope(ctx); + if (callData->argc < 1 || callData->argc > 2) + THROW_GENERIC_ERROR("Qt.formatTime(): Invalid arguments"); - QVariant argVariant = ctx->engine()->toVariant(ctx->args()[0], -1); + QVariant argVariant = scope.engine->toVariant(callData->args[0], -1); QTime time; - if (ctx->args()[0].as<DateObject>() || (argVariant.type() == QVariant::String)) + if (callData->args[0].as<DateObject>() || (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->argc() == 2) { - QV4::ScopedString s(scope, ctx->args()[1]); + if (callData->argc == 2) { + QV4::ScopedString s(scope, callData->args[1]); if (s) { QString format = s->toQString(); formattedTime = time.toString(format); - } else if (ctx->args()[1].isNumber()) { - quint32 intFormat = ctx->args()[1].asDouble(); + } else if (callData->args[1].isNumber()) { + quint32 intFormat = callData->args[1].asDouble(); Qt::DateFormat format = Qt::DateFormat(intFormat); formattedTime = time.toString(format); } else { - V4THROW_ERROR("Qt.formatTime(): Invalid time format"); + THROW_GENERIC_ERROR("Qt.formatTime(): Invalid time format"); } } else { formattedTime = time.toString(enumFormat); } - return ctx->d()->engine->newString(formattedTime)->asReturnedValue(); + scope.result = scope.engine->newString(formattedTime); } /*! @@ -864,32 +879,31 @@ with the \a format values below to produce the following results: \sa Locale */ -ReturnedValue QtObject::method_formatDateTime(QV4::CallContext *ctx) +void QtObject::method_formatDateTime(const BuiltinFunction *, Scope &scope, CallData *callData) { - if (ctx->argc() < 1 || ctx->argc() > 2) - V4THROW_ERROR("Qt.formatDateTime(): Invalid arguments"); - QV4::Scope scope(ctx); + if (callData->argc < 1 || callData->argc > 2) + THROW_GENERIC_ERROR("Qt.formatDateTime(): Invalid arguments"); Qt::DateFormat enumFormat = Qt::DefaultLocaleShortDate; - QDateTime dt = ctx->engine()->toVariant(ctx->args()[0], -1).toDateTime(); + QDateTime dt = scope.engine->toVariant(callData->args[0], -1).toDateTime(); QString formattedDt; - if (ctx->argc() == 2) { - QV4::ScopedString s(scope, ctx->args()[1]); + if (callData->argc == 2) { + QV4::ScopedString s(scope, callData->args[1]); if (s) { QString format = s->toQString(); formattedDt = dt.toString(format); - } else if (ctx->args()[1].isNumber()) { - quint32 intFormat = ctx->args()[1].asDouble(); + } else if (callData->args[1].isNumber()) { + quint32 intFormat = callData->args[1].asDouble(); Qt::DateFormat format = Qt::DateFormat(intFormat); formattedDt = dt.toString(format); } else { - V4THROW_ERROR("Qt.formatDateTime(): Invalid datetime format"); + THROW_GENERIC_ERROR("Qt.formatDateTime(): Invalid datetime format"); } } else { formattedDt = dt.toString(enumFormat); } - return ctx->d()->engine->newString(formattedDt)->asReturnedValue(); + scope.result = scope.engine->newString(formattedDt); } /*! @@ -903,90 +917,94 @@ ReturnedValue QtObject::method_formatDateTime(QV4::CallContext *ctx) still fail to launch or fail to open the requested URL. This result will not be reported back to the application. */ -ReturnedValue QtObject::method_openUrlExternally(QV4::CallContext *ctx) +void QtObject::method_openUrlExternally(const BuiltinFunction *b, Scope &scope, CallData *callData) { - if (ctx->argc() != 1) - return QV4::Encode(false); + if (callData->argc != 1) { + scope.result = QV4::Encode(false); + return; + } - QUrl url(Value::fromReturnedValue(method_resolvedUrl(ctx)).toQStringNoThrow()); - return ctx->engine()->fromVariant(QQml_guiProvider()->openUrlExternally(url)); + method_resolvedUrl(b, scope, callData); + QUrl url(scope.result.toQStringNoThrow()); + scope.result = scope.engine->fromVariant(QQml_guiProvider()->openUrlExternally(url)); } /*! \qmlmethod url Qt::resolvedUrl(url url) Returns \a url resolved relative to the URL of the caller. */ -ReturnedValue QtObject::method_resolvedUrl(QV4::CallContext *ctx) +void QtObject::method_resolvedUrl(const BuiltinFunction *, Scope &scope, CallData *callData) { - ExecutionEngine *v4 = ctx->engine(); + ExecutionEngine *v4 = scope.engine; - QUrl url = v4->toVariant(ctx->args()[0], -1).toUrl(); + QUrl url = v4->toVariant(callData->args[0], -1).toUrl(); QQmlEngine *e = v4->qmlEngine(); QQmlEnginePrivate *p = 0; if (e) p = QQmlEnginePrivate::get(e); if (p) { QQmlContextData *ctxt = v4->callingQmlContext(); if (ctxt) - return v4->newString(ctxt->resolvedUrl(url).toString())->asReturnedValue(); + scope.result = v4->newString(ctxt->resolvedUrl(url).toString()); else - return v4->newString(url.toString())->asReturnedValue(); + scope.result = v4->newString(url.toString()); + return; } - return v4->newString(e->baseUrl().resolved(url).toString())->asReturnedValue(); + scope.result = v4->newString(e->baseUrl().resolved(url).toString()); } /*! \qmlmethod list<string> Qt::fontFamilies() Returns a list of the font families available to the application. */ -ReturnedValue QtObject::method_fontFamilies(CallContext *ctx) +void QtObject::method_fontFamilies(const BuiltinFunction *, Scope &scope, CallData *callData) { - if (ctx->argc() != 0) - V4THROW_ERROR("Qt.fontFamilies(): Invalid arguments"); + if (callData->argc != 0) + THROW_GENERIC_ERROR("Qt.fontFamilies(): Invalid arguments"); - return ctx->engine()->fromVariant(QVariant(QQml_guiProvider()->fontFamilies())); + scope.result = scope.engine->fromVariant(QVariant(QQml_guiProvider()->fontFamilies())); } /*! \qmlmethod string Qt::md5(data) Returns a hex string of the md5 hash of \c data. */ -ReturnedValue QtObject::method_md5(CallContext *ctx) +void QtObject::method_md5(const BuiltinFunction *, Scope &scope, CallData *callData) { - if (ctx->argc() != 1) - V4THROW_ERROR("Qt.md5(): Invalid arguments"); + if (callData->argc != 1) + THROW_GENERIC_ERROR("Qt.md5(): Invalid arguments"); - QByteArray data = ctx->args()[0].toQStringNoThrow().toUtf8(); + QByteArray data = callData->args[0].toQStringNoThrow().toUtf8(); QByteArray result = QCryptographicHash::hash(data, QCryptographicHash::Md5); - return ctx->d()->engine->newString(QLatin1String(result.toHex()))->asReturnedValue(); + scope.result = scope.engine->newString(QLatin1String(result.toHex())); } /*! \qmlmethod string Qt::btoa(data) Binary to ASCII - this function returns a base64 encoding of \c data. */ -ReturnedValue QtObject::method_btoa(CallContext *ctx) +void QtObject::method_btoa(const BuiltinFunction *, Scope &scope, CallData *callData) { - if (ctx->argc() != 1) - V4THROW_ERROR("Qt.btoa(): Invalid arguments"); + if (callData->argc != 1) + THROW_GENERIC_ERROR("Qt.btoa(): Invalid arguments"); - QByteArray data = ctx->args()[0].toQStringNoThrow().toUtf8(); + QByteArray data = callData->args[0].toQStringNoThrow().toUtf8(); - return ctx->d()->engine->newString(QLatin1String(data.toBase64()))->asReturnedValue(); + scope.result = scope.engine->newString(QLatin1String(data.toBase64())); } /*! \qmlmethod string Qt::atob(data) ASCII to binary - this function decodes the base64 encoded \a data string and returns it. */ -ReturnedValue QtObject::method_atob(CallContext *ctx) +void QtObject::method_atob(const BuiltinFunction *, Scope &scope, CallData *callData) { - if (ctx->argc() != 1) - V4THROW_ERROR("Qt.atob(): Invalid arguments"); + if (callData->argc != 1) + THROW_GENERIC_ERROR("Qt.atob(): Invalid arguments"); - QByteArray data = ctx->args()[0].toQStringNoThrow().toLatin1(); + QByteArray data = callData->args[0].toQStringNoThrow().toLatin1(); - return ctx->d()->engine->newString(QString::fromUtf8(QByteArray::fromBase64(data)))->asReturnedValue(); + scope.result = scope.engine->newString(QString::fromUtf8(QByteArray::fromBase64(data))); } /*! @@ -998,10 +1016,10 @@ QQmlEngine::quit() signal to the QCoreApplication::quit() slot. \sa exit() */ -ReturnedValue QtObject::method_quit(CallContext *ctx) +void QtObject::method_quit(const BuiltinFunction *, Scope &scope, CallData *) { - QQmlEnginePrivate::get(ctx->engine()->qmlEngine())->sendQuit(); - return QV4::Encode::undefined(); + QQmlEnginePrivate::get(scope.engine->qmlEngine())->sendQuit(); + scope.result = Encode::undefined(); } /*! @@ -1015,15 +1033,15 @@ ReturnedValue QtObject::method_quit(CallContext *ctx) \sa quit() */ -ReturnedValue QtObject::method_exit(CallContext *ctx) +void QtObject::method_exit(const BuiltinFunction *, Scope &scope, CallData *callData) { - if (ctx->argc() != 1) - V4THROW_ERROR("Qt.exit(): Invalid arguments"); + if (callData->argc != 1) + THROW_GENERIC_ERROR("Qt.exit(): Invalid arguments"); - int retCode = ctx->args()[0].toNumber(); + int retCode = callData->args[0].toNumber(); - QQmlEnginePrivate::get(ctx->engine()->qmlEngine())->sendExit(retCode); - return QV4::Encode::undefined(); + QQmlEnginePrivate::get(scope.engine->qmlEngine())->sendExit(retCode); + scope.result = QV4::Encode::undefined(); } /*! @@ -1050,11 +1068,10 @@ If this is the case, consider using \l{QtQml::Qt::createComponent()}{Qt.createCo See \l {Dynamic QML Object Creation from JavaScript} for more information on using this function. */ -ReturnedValue QtObject::method_createQmlObject(CallContext *ctx) +void QtObject::method_createQmlObject(const BuiltinFunction *, Scope &scope, CallData *callData) { - Scope scope(ctx); - if (ctx->argc() < 2 || ctx->argc() > 3) - V4THROW_ERROR("Qt.createQmlObject(): Invalid arguments"); + if (callData->argc < 2 || callData->argc > 3) + THROW_GENERIC_ERROR("Qt.createQmlObject(): Invalid arguments"); struct Error { static ReturnedValue create(QV4::ExecutionEngine *v4, const QList<QQmlError> &errors) { @@ -1085,7 +1102,7 @@ ReturnedValue QtObject::method_createQmlObject(CallContext *ctx) } }; - QV8Engine *v8engine = ctx->d()->engine->v8Engine; + QV8Engine *v8engine = scope.engine->v8Engine; QQmlEngine *engine = v8engine->engine(); QQmlContextData *context = scope.engine->callingQmlContext(); @@ -1097,13 +1114,13 @@ ReturnedValue QtObject::method_createQmlObject(CallContext *ctx) effectiveContext = context->asQQmlContext(); Q_ASSERT(effectiveContext); - QString qml = ctx->args()[0].toQStringNoThrow(); + QString qml = callData->args[0].toQStringNoThrow(); if (qml.isEmpty()) - return QV4::Encode::null(); + RETURN_RESULT(Encode::null()); QUrl url; - if (ctx->argc() > 2) - url = QUrl(ctx->args()[2].toQStringNoThrow()); + if (callData->argc > 2) + url = QUrl(callData->args[2].toQStringNoThrow()); else url = QUrl(QLatin1String("inline")); @@ -1111,11 +1128,11 @@ ReturnedValue QtObject::method_createQmlObject(CallContext *ctx) url = context->resolvedUrl(url); QObject *parentArg = 0; - QV4::Scoped<QV4::QObjectWrapper> qobjectWrapper(scope, ctx->args()[1]); + QV4::Scoped<QV4::QObjectWrapper> qobjectWrapper(scope, callData->args[1]); if (!!qobjectWrapper) parentArg = qobjectWrapper->object(); if (!parentArg) - V4THROW_ERROR("Qt.createQmlObject(): Missing parent object"); + THROW_GENERIC_ERROR("Qt.createQmlObject(): Missing parent object"); QQmlTypeData *typeData = QQmlEnginePrivate::get(engine)->typeLoader.getType( qml.toUtf8(), url, QQmlTypeLoader::Synchronous); @@ -1126,12 +1143,12 @@ ReturnedValue QtObject::method_createQmlObject(CallContext *ctx) componentPrivate->progress = 1.0; if (component.isError()) { - ScopedValue v(scope, Error::create(ctx->d()->engine, component.errors())); - return ctx->engine()->throwError(v); + ScopedValue v(scope, Error::create(scope.engine, component.errors())); + RETURN_RESULT(scope.engine->throwError(v)); } if (!component.isReady()) - V4THROW_ERROR("Qt.createQmlObject(): Component is not ready"); + THROW_GENERIC_ERROR("Qt.createQmlObject(): Component is not ready"); QObject *obj = component.beginCreate(effectiveContext); if (obj) { @@ -1150,13 +1167,14 @@ ReturnedValue QtObject::method_createQmlObject(CallContext *ctx) component.completeCreate(); if (component.isError()) { - ScopedValue v(scope, Error::create(ctx->d()->engine, component.errors())); - return ctx->engine()->throwError(v); + ScopedValue v(scope, Error::create(scope.engine, component.errors())); + scope.result = scope.engine->throwError(v); + return; } Q_ASSERT(obj); - return QV4::QObjectWrapper::wrap(ctx->d()->engine, obj); + scope.result = QV4::QObjectWrapper::wrap(scope.engine, obj); } /*! @@ -1203,14 +1221,12 @@ See \l {Dynamic QML Object Creation from JavaScript} for more information on usi To create a QML object from an arbitrary string of QML (instead of a file), use \l{QtQml::Qt::createQmlObject()}{Qt.createQmlObject()}. */ -ReturnedValue QtObject::method_createComponent(CallContext *ctx) +void QtObject::method_createComponent(const BuiltinFunction *, Scope &scope, CallData *callData) { - if (ctx->argc() < 1 || ctx->argc() > 3) - return ctx->engine()->throwError(QStringLiteral("Qt.createComponent(): Invalid arguments")); + if (callData->argc < 1 || callData->argc > 3) + THROW_GENERIC_ERROR("Qt.createComponent(): Invalid arguments"); - Scope scope(ctx); - - QV8Engine *v8engine = ctx->d()->engine->v8Engine; + QV8Engine *v8engine = scope.engine->v8Engine; QQmlEngine *engine = v8engine->engine(); QQmlContextData *context = scope.engine->callingQmlContext(); @@ -1219,41 +1235,41 @@ ReturnedValue QtObject::method_createComponent(CallContext *ctx) if (context->isPragmaLibraryContext) effectiveContext = 0; - QString arg = ctx->args()[0].toQStringNoThrow(); + QString arg = callData->args[0].toQStringNoThrow(); if (arg.isEmpty()) - return QV4::Encode::null(); + RETURN_RESULT(QV4::Encode::null()); QQmlComponent::CompilationMode compileMode = QQmlComponent::PreferSynchronous; QObject *parentArg = 0; int consumedCount = 1; - if (ctx->argc() > 1) { - ScopedValue lastArg(scope, ctx->args()[ctx->argc()-1]); + if (callData->argc > 1) { + ScopedValue lastArg(scope, callData->args[callData->argc-1]); // The second argument could be the mode enum - if (ctx->args()[1].isInteger()) { - int mode = ctx->args()[1].integerValue(); + if (callData->args[1].isInteger()) { + int mode = callData->args[1].integerValue(); if (mode != int(QQmlComponent::PreferSynchronous) && mode != int(QQmlComponent::Asynchronous)) - return ctx->engine()->throwError(QStringLiteral("Qt.createComponent(): Invalid arguments")); + THROW_GENERIC_ERROR("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->argc() != 2) || !(lastArg->isObject() || lastArg->isNull())) - return ctx->engine()->throwError(QStringLiteral("Qt.createComponent(): Invalid arguments")); + if ((callData->argc != 2) || !(lastArg->isObject() || lastArg->isNull())) + THROW_GENERIC_ERROR("Qt.createComponent(): Invalid arguments"); } - if (consumedCount < ctx->argc()) { + if (consumedCount < callData->argc) { if (lastArg->isObject()) { Scoped<QObjectWrapper> qobjectWrapper(scope, lastArg); if (qobjectWrapper) parentArg = qobjectWrapper->object(); if (!parentArg) - return ctx->engine()->throwError(QStringLiteral("Qt.createComponent(): Invalid parent object")); + THROW_GENERIC_ERROR("Qt.createComponent(): Invalid parent object"); } else if (lastArg->isNull()) { parentArg = 0; } else { - return ctx->engine()->throwError(QStringLiteral("Qt.createComponent(): Invalid parent object")); + THROW_GENERIC_ERROR("Qt.createComponent(): Invalid parent object"); } } } @@ -1264,7 +1280,7 @@ ReturnedValue QtObject::method_createComponent(CallContext *ctx) QQmlData::get(c, true)->explicitIndestructibleSet = false; QQmlData::get(c)->indestructible = false; - return QV4::QObjectWrapper::wrap(ctx->d()->engine, c); + scope.result = QV4::QObjectWrapper::wrap(scope.engine, c); } /*! @@ -1287,18 +1303,18 @@ ReturnedValue QtObject::method_createComponent(CallContext *ctx) \sa Locale */ -ReturnedValue QtObject::method_locale(CallContext *ctx) +void QtObject::method_locale(const BuiltinFunction *, Scope &scope, CallData *callData) { QString code; - if (ctx->argc() > 1) - V4THROW_ERROR("locale() requires 0 or 1 argument"); - if (ctx->argc() == 1 && !ctx->args()[0].isString()) - V4THROW_TYPE("locale(): argument (locale code) must be a string"); + if (callData->argc > 1) + THROW_GENERIC_ERROR("locale() requires 0 or 1 argument"); + if (callData->argc == 1 && !callData->args[0].isString()) + THROW_TYPE_ERROR_WITH_MESSAGE("locale(): argument (locale code) must be a string"); - if (ctx->argc() == 1) - code = ctx->args()[0].toQStringNoThrow(); + if (callData->argc == 1) + code = callData->args[0].toQStringNoThrow(); - return QQmlLocale::locale(ctx->engine(), code); + scope.result = QQmlLocale::locale(scope.engine, code); } void Heap::QQmlBindingFunction::init(const QV4::FunctionObject *originalFunction) @@ -1360,62 +1376,62 @@ DEFINE_OBJECT_VTABLE(QQmlBindingFunction); \since 5.0 */ -ReturnedValue QtObject::method_binding(CallContext *ctx) +void QtObject::method_binding(const BuiltinFunction *, Scope &scope, CallData *callData) { - if (ctx->argc() != 1) - V4THROW_ERROR("binding() requires 1 argument"); - const QV4::FunctionObject *f = ctx->args()[0].as<FunctionObject>(); + if (callData->argc != 1) + THROW_GENERIC_ERROR("binding() requires 1 argument"); + const QV4::FunctionObject *f = callData->args[0].as<FunctionObject>(); if (!f) - V4THROW_TYPE("binding(): argument (binding expression) must be a function"); + THROW_TYPE_ERROR_WITH_MESSAGE("binding(): argument (binding expression) must be a function"); - return (ctx->d()->engine->memoryManager->allocObject<QQmlBindingFunction>(f))->asReturnedValue(); + scope.result = scope.engine->memoryManager->allocObject<QQmlBindingFunction>(f); } -ReturnedValue QtObject::method_get_platform(CallContext *ctx) +void QtObject::method_get_platform(const BuiltinFunction *, Scope &scope, CallData *callData) { // ### inefficient. Should be just a value based getter - Object *o = ctx->thisObject().as<Object>(); + Object *o = callData->thisObject.as<Object>(); if (!o) - return ctx->engine()->throwTypeError(); + THROW_TYPE_ERROR(); QtObject *qt = o->as<QtObject>(); if (!qt) - return ctx->engine()->throwTypeError(); + THROW_TYPE_ERROR(); if (!qt->d()->platform) // Only allocate a platform object once - qt->d()->platform = new QQmlPlatform(ctx->d()->engine->jsEngine()); + qt->d()->platform = new QQmlPlatform(scope.engine->jsEngine()); - return QV4::QObjectWrapper::wrap(ctx->d()->engine, qt->d()->platform); + scope.result = QV4::QObjectWrapper::wrap(scope.engine, qt->d()->platform); } -ReturnedValue QtObject::method_get_application(CallContext *ctx) +void QtObject::method_get_application(const BuiltinFunction *, Scope &scope, CallData *callData) { // ### inefficient. Should be just a value based getter - Object *o = ctx->thisObject().as<Object>(); + Object *o = callData->thisObject.as<Object>(); if (!o) - return ctx->engine()->throwTypeError(); + THROW_TYPE_ERROR(); QtObject *qt = o->as<QtObject>(); if (!qt) - return ctx->engine()->throwTypeError(); + THROW_TYPE_ERROR(); if (!qt->d()->application) // Only allocate an application object once - qt->d()->application = QQml_guiProvider()->application(ctx->d()->engine->jsEngine()); + qt->d()->application = QQml_guiProvider()->application(scope.engine->jsEngine()); - return QV4::QObjectWrapper::wrap(ctx->d()->engine, qt->d()->application); + scope.result = QV4::QObjectWrapper::wrap(scope.engine, qt->d()->application); } -ReturnedValue QtObject::method_get_inputMethod(CallContext *ctx) +void QtObject::method_get_inputMethod(const BuiltinFunction *, Scope &scope, CallData *) { QObject *o = QQml_guiProvider()->inputMethod(); - return QV4::QObjectWrapper::wrap(ctx->d()->engine, o); + scope.result = QV4::QObjectWrapper::wrap(scope.engine, o); } -ReturnedValue QtObject::method_get_styleHints(CallContext *ctx) +void QtObject::method_get_styleHints(const BuiltinFunction *, Scope &scope, CallData *) { QObject *o = QQml_guiProvider()->styleHints(); - return QV4::QObjectWrapper::wrap(ctx->d()->engine, o); + scope.result = QV4::QObjectWrapper::wrap(scope.engine, o); } @@ -1475,35 +1491,35 @@ static QString jsStack(QV4::ExecutionEngine *engine) { return stack; } -static QV4::ReturnedValue writeToConsole(ConsoleLogTypes logType, CallContext *ctx, - bool printStack = false) +static void writeToConsole(const BuiltinFunction *, Scope &scope, CallData *callData, + ConsoleLogTypes logType, bool printStack = false) { QLoggingCategory *loggingCategory = 0; QString result; - QV4::ExecutionEngine *v4 = ctx->d()->engine; + QV4::ExecutionEngine *v4 = scope.engine; int start = 0; - if (ctx->argc() > 0) { - if (const QObjectWrapper* wrapper = ctx->args()[0].as<QObjectWrapper>()) { + if (callData->argc > 0) { + if (const QObjectWrapper* wrapper = callData->args[0].as<QObjectWrapper>()) { if (QQmlLoggingCategory* category = qobject_cast<QQmlLoggingCategory*>(wrapper->object())) { if (category->category()) loggingCategory = category->category(); else - V4THROW_ERROR("A QmlLoggingCatgory was provided without a valid name"); + THROW_GENERIC_ERROR("A QmlLoggingCatgory was provided without a valid name"); start = 1; } } } - for (int i = start; i < ctx->argc(); ++i) { + for (int i = start; i < callData->argc; ++i) { if (i != start) result.append(QLatin1Char(' ')); - if (ctx->args()[i].as<ArrayObject>()) - result += QLatin1Char('[') + ctx->args()[i].toQStringNoThrow() + QLatin1Char(']'); + if (callData->args[i].as<ArrayObject>()) + result += QLatin1Char('[') + callData->args[i].toQStringNoThrow() + QLatin1Char(']'); else - result.append(ctx->args()[i].toQStringNoThrow()); + result.append(callData->args[i].toQStringNoThrow()); } if (printStack) @@ -1540,32 +1556,32 @@ static QV4::ReturnedValue writeToConsole(ConsoleLogTypes logType, CallContext *c break; } - return QV4::Encode::undefined(); + scope.result = QV4::Encode::undefined(); } DEFINE_OBJECT_VTABLE(ConsoleObject); -QV4::ReturnedValue ConsoleObject::method_error(CallContext *ctx) +void ConsoleObject::method_error(const BuiltinFunction *b, Scope &scope, CallData *callData) { - return writeToConsole(Error, ctx); + writeToConsole(b, scope, callData, Error); } -QV4::ReturnedValue ConsoleObject::method_log(CallContext *ctx) +void ConsoleObject::method_log(const BuiltinFunction *b, Scope &scope, CallData *callData) { //console.log //console.debug //print - return writeToConsole(Log, ctx); + writeToConsole(b, scope, callData, Log); } -QV4::ReturnedValue ConsoleObject::method_info(CallContext *ctx) +void ConsoleObject::method_info(const BuiltinFunction *b, Scope &scope, CallData *callData) { - return writeToConsole(Info, ctx); + writeToConsole(b, scope, callData, Info); } -QV4::ReturnedValue ConsoleObject::method_profile(CallContext *ctx) +void ConsoleObject::method_profile(const BuiltinFunction *, Scope &scope, CallData *) { - QV4::ExecutionEngine *v4 = ctx->d()->engine; + QV4::ExecutionEngine *v4 = scope.engine; QV4::StackFrame frame = v4->currentStackFrame(); const QByteArray baSource = frame.source.toUtf8(); @@ -1579,12 +1595,12 @@ QV4::ReturnedValue ConsoleObject::method_profile(CallContext *ctx) logger.debug("Profiling started."); } - return QV4::Encode::undefined(); + scope.result = QV4::Encode::undefined(); } -QV4::ReturnedValue ConsoleObject::method_profileEnd(CallContext *ctx) +void ConsoleObject::method_profileEnd(const BuiltinFunction *, Scope &scope, CallData *) { - QV4::ExecutionEngine *v4 = ctx->d()->engine; + QV4::ExecutionEngine *v4 = scope.engine; QV4::StackFrame frame = v4->currentStackFrame(); const QByteArray baSource = frame.source.toUtf8(); @@ -1599,46 +1615,46 @@ QV4::ReturnedValue ConsoleObject::method_profileEnd(CallContext *ctx) logger.debug("Profiling ended."); } - return QV4::Encode::undefined(); + scope.result = QV4::Encode::undefined(); } -QV4::ReturnedValue ConsoleObject::method_time(CallContext *ctx) +void ConsoleObject::method_time(const BuiltinFunction *, Scope &scope, CallData *callData) { - if (ctx->argc() != 1) - V4THROW_ERROR("console.time(): Invalid arguments"); + if (callData->argc != 1) + THROW_GENERIC_ERROR("console.time(): Invalid arguments"); - QV8Engine *v8engine = ctx->d()->engine->v8Engine; + QV8Engine *v8engine = scope.engine->v8Engine; - QString name = ctx->args()[0].toQStringNoThrow(); + QString name = callData->args[0].toQStringNoThrow(); v8engine->startTimer(name); - return QV4::Encode::undefined(); + scope.result = QV4::Encode::undefined(); } -QV4::ReturnedValue ConsoleObject::method_timeEnd(CallContext *ctx) +void ConsoleObject::method_timeEnd(const BuiltinFunction *, Scope &scope, CallData *callData) { - if (ctx->argc() != 1) - V4THROW_ERROR("console.timeEnd(): Invalid arguments"); + if (callData->argc != 1) + THROW_GENERIC_ERROR("console.timeEnd(): Invalid arguments"); - QV8Engine *v8engine = ctx->d()->engine->v8Engine; + QV8Engine *v8engine = scope.engine->v8Engine; - QString name = ctx->args()[0].toQStringNoThrow(); + QString name = callData->args[0].toQStringNoThrow(); bool wasRunning; qint64 elapsed = v8engine->stopTimer(name, &wasRunning); if (wasRunning) { qDebug("%s: %llims", qPrintable(name), elapsed); } - return QV4::Encode::undefined(); + scope.result = QV4::Encode::undefined(); } -QV4::ReturnedValue ConsoleObject::method_count(CallContext *ctx) +void ConsoleObject::method_count(const BuiltinFunction *, Scope &scope, CallData *callData) { // first argument: name to print. Ignore any additional arguments QString name; - if (ctx->argc() > 0) - name = ctx->args()[0].toQStringNoThrow(); + if (callData->argc > 0) + name = callData->args[0].toQStringNoThrow(); - QV4::ExecutionEngine *v4 = ctx->d()->engine; - QV8Engine *v8engine = ctx->d()->engine->v8Engine; + QV4::ExecutionEngine *v4 = scope.engine; + QV8Engine *v8engine = scope.engine->v8Engine; QV4::StackFrame frame = v4->currentStackFrame(); @@ -1651,15 +1667,15 @@ QV4::ReturnedValue ConsoleObject::method_count(CallContext *ctx) qPrintable(frame.function)) .debug("%s", qPrintable(message)); - return QV4::Encode::undefined(); + scope.result = QV4::Encode::undefined(); } -QV4::ReturnedValue ConsoleObject::method_trace(CallContext *ctx) +void ConsoleObject::method_trace(const BuiltinFunction *, Scope &scope, CallData *callData) { - if (ctx->argc() != 0) - V4THROW_ERROR("console.trace(): Invalid arguments"); + if (callData->argc != 0) + THROW_GENERIC_ERROR("console.trace(): Invalid arguments"); - QV4::ExecutionEngine *v4 = ctx->d()->engine; + QV4::ExecutionEngine *v4 = scope.engine; QString stack = jsStack(v4); @@ -1668,28 +1684,28 @@ QV4::ReturnedValue ConsoleObject::method_trace(CallContext *ctx) frame.function.toUtf8().constData()) .debug("%s", qPrintable(stack)); - return QV4::Encode::undefined(); + scope.result = QV4::Encode::undefined(); } -QV4::ReturnedValue ConsoleObject::method_warn(CallContext *ctx) +void ConsoleObject::method_warn(const BuiltinFunction *b, Scope &scope, CallData *callData) { - return writeToConsole(Warn, ctx); + return writeToConsole(b, scope, callData, Warn); } -QV4::ReturnedValue ConsoleObject::method_assert(CallContext *ctx) +void ConsoleObject::method_assert(const BuiltinFunction *, Scope &scope, CallData *callData) { - if (ctx->argc() == 0) - V4THROW_ERROR("console.assert(): Missing argument"); + if (callData->argc == 0) + THROW_GENERIC_ERROR("console.assert(): Missing argument"); - QV4::ExecutionEngine *v4 = ctx->d()->engine; + QV4::ExecutionEngine *v4 = scope.engine; - if (!ctx->args()[0].toBoolean()) { + if (!callData->args[0].toBoolean()) { QString message; - for (int i = 1; i < ctx->argc(); ++i) { + for (int i = 1; i < callData->argc; ++i) { if (i != 1) message.append(QLatin1Char(' ')); - message.append(ctx->args()[i].toQStringNoThrow()); + message.append(callData->args[i].toQStringNoThrow()); } QString stack = jsStack(v4); @@ -1700,17 +1716,17 @@ QV4::ReturnedValue ConsoleObject::method_assert(CallContext *ctx) .critical("%s\n%s",qPrintable(message), qPrintable(stack)); } - return QV4::Encode::undefined(); + scope.result = QV4::Encode::undefined(); } -QV4::ReturnedValue ConsoleObject::method_exception(CallContext *ctx) +void ConsoleObject::method_exception(const BuiltinFunction *b, Scope &scope, CallData *callData) { - if (ctx->argc() == 0) - V4THROW_ERROR("console.exception(): Missing argument"); + if (callData->argc == 0) + THROW_GENERIC_ERROR("console.exception(): Missing argument"); - writeToConsole(Error, ctx, true); + writeToConsole(b, scope, callData, Error, true); - return QV4::Encode::undefined(); + scope.result = QV4::Encode::undefined(); } @@ -1766,38 +1782,38 @@ void QV4::GlobalExtensions::init(Object *globalObject, QJSEngine::Extensions ext \sa {Internationalization and Localization with Qt Quick} */ -ReturnedValue GlobalExtensions::method_qsTranslate(CallContext *ctx) -{ - if (ctx->argc() < 2) - V4THROW_ERROR("qsTranslate() requires at least two arguments"); - if (!ctx->args()[0].isString()) - V4THROW_ERROR("qsTranslate(): first argument (context) must be a string"); - if (!ctx->args()[1].isString()) - V4THROW_ERROR("qsTranslate(): second argument (sourceText) must be a string"); - if ((ctx->argc() > 2) && !ctx->args()[2].isString()) - V4THROW_ERROR("qsTranslate(): third argument (disambiguation) must be a string"); - - QString context = ctx->args()[0].toQStringNoThrow(); - QString text = ctx->args()[1].toQStringNoThrow(); +void GlobalExtensions::method_qsTranslate(const BuiltinFunction *, Scope &scope, CallData *callData) +{ + if (callData->argc < 2) + THROW_GENERIC_ERROR("qsTranslate() requires at least two arguments"); + if (!callData->args[0].isString()) + THROW_GENERIC_ERROR("qsTranslate(): first argument (context) must be a string"); + if (!callData->args[1].isString()) + THROW_GENERIC_ERROR("qsTranslate(): second argument (sourceText) must be a string"); + if ((callData->argc > 2) && !callData->args[2].isString()) + THROW_GENERIC_ERROR("qsTranslate(): third argument (disambiguation) must be a string"); + + QString context = callData->args[0].toQStringNoThrow(); + QString text = callData->args[1].toQStringNoThrow(); QString comment; - if (ctx->argc() > 2) comment = ctx->args()[2].toQStringNoThrow(); + if (callData->argc > 2) comment = callData->args[2].toQStringNoThrow(); int i = 3; - if (ctx->argc() > i && ctx->args()[i].isString()) { + if (callData->argc > i && callData->args[i].isString()) { qWarning("qsTranslate(): specifying the encoding as fourth argument is deprecated"); ++i; } int n = -1; - if (ctx->argc() > i) - n = ctx->args()[i].toInt32(); + if (callData->argc > i) + n = callData->args[i].toInt32(); QString result = QCoreApplication::translate(context.toUtf8().constData(), text.toUtf8().constData(), comment.toUtf8().constData(), n); - return ctx->d()->engine->newString(result)->asReturnedValue(); + scope.result = scope.engine->newString(result); } /*! @@ -1822,11 +1838,12 @@ ReturnedValue GlobalExtensions::method_qsTranslate(CallContext *ctx) \sa {Internationalization and Localization with Qt Quick} */ -ReturnedValue GlobalExtensions::method_qsTranslateNoOp(CallContext *ctx) +void GlobalExtensions::method_qsTranslateNoOp(const BuiltinFunction *, Scope &scope, CallData *callData) { - if (ctx->argc() < 2) - return QV4::Encode::undefined(); - return ctx->args()[1].asReturnedValue(); + if (callData->argc < 2) + scope.result = QV4::Encode::undefined(); + else + scope.result = callData->args[1]; } /*! @@ -1846,18 +1863,17 @@ ReturnedValue GlobalExtensions::method_qsTranslateNoOp(CallContext *ctx) \sa {Internationalization and Localization with Qt Quick} */ -ReturnedValue GlobalExtensions::method_qsTr(CallContext *ctx) -{ - if (ctx->argc() < 1) - V4THROW_ERROR("qsTr() requires at least one argument"); - if (!ctx->args()[0].isString()) - V4THROW_ERROR("qsTr(): first argument (sourceText) must be a string"); - if ((ctx->argc() > 1) && !ctx->args()[1].isString()) - V4THROW_ERROR("qsTr(): second argument (disambiguation) must be a string"); - if ((ctx->argc() > 2) && !ctx->args()[2].isNumber()) - V4THROW_ERROR("qsTr(): third argument (n) must be a number"); - - Scope scope(ctx); +void GlobalExtensions::method_qsTr(const BuiltinFunction *, Scope &scope, CallData *callData) +{ + if (callData->argc < 1) + THROW_GENERIC_ERROR("qsTr() requires at least one argument"); + if (!callData->args[0].isString()) + THROW_GENERIC_ERROR("qsTr(): first argument (sourceText) must be a string"); + if ((callData->argc > 1) && !callData->args[1].isString()) + THROW_GENERIC_ERROR("qsTr(): second argument (disambiguation) must be a string"); + if ((callData->argc > 2) && !callData->args[2].isNumber()) + THROW_GENERIC_ERROR("qsTr(): third argument (n) must be a number"); + QString context; if (QQmlContextData *ctxt = scope.engine->callingQmlContext()) { QString path = ctxt->urlString(); @@ -1866,7 +1882,7 @@ ReturnedValue GlobalExtensions::method_qsTr(CallContext *ctx) int length = lastDot - (lastSlash + 1); context = (lastSlash > -1) ? path.mid(lastSlash + 1, (length > -1) ? length : -1) : QString(); } else { - ExecutionContext *parentCtx = scope.engine->parentContext(ctx); + ExecutionContext *parentCtx = scope.engine->currentContext; // 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) { @@ -1885,18 +1901,18 @@ ReturnedValue GlobalExtensions::method_qsTr(CallContext *ctx) } } - QString text = ctx->args()[0].toQStringNoThrow(); + QString text = callData->args[0].toQStringNoThrow(); QString comment; - if (ctx->argc() > 1) - comment = ctx->args()[1].toQStringNoThrow(); + if (callData->argc > 1) + comment = callData->args[1].toQStringNoThrow(); int n = -1; - if (ctx->argc() > 2) - n = ctx->args()[2].toInt32(); + if (callData->argc > 2) + n = callData->args[2].toInt32(); QString result = QCoreApplication::translate(context.toUtf8().constData(), text.toUtf8().constData(), comment.toUtf8().constData(), n); - return ctx->d()->engine->newString(result)->asReturnedValue(); + scope.result = scope.engine->newString(result); } /*! @@ -1921,11 +1937,12 @@ ReturnedValue GlobalExtensions::method_qsTr(CallContext *ctx) \sa {Internationalization and Localization with Qt Quick} */ -ReturnedValue GlobalExtensions::method_qsTrNoOp(CallContext *ctx) +void GlobalExtensions::method_qsTrNoOp(const BuiltinFunction *, Scope &scope, CallData *callData) { - if (ctx->argc() < 1) - return QV4::Encode::undefined(); - return ctx->args()[0].asReturnedValue(); + if (callData->argc < 1) + scope.result = QV4::Encode::undefined(); + else + scope.result = callData->args[0]; } /*! @@ -1958,20 +1975,20 @@ ReturnedValue GlobalExtensions::method_qsTrNoOp(CallContext *ctx) \sa QT_TRID_NOOP(), {Internationalization and Localization with Qt Quick} */ -ReturnedValue GlobalExtensions::method_qsTrId(CallContext *ctx) +void GlobalExtensions::method_qsTrId(const BuiltinFunction *, Scope &scope, CallData *callData) { - if (ctx->argc() < 1) - V4THROW_ERROR("qsTrId() requires at least one argument"); - if (!ctx->args()[0].isString()) - V4THROW_TYPE("qsTrId(): first argument (id) must be a string"); - if (ctx->argc() > 1 && !ctx->args()[1].isNumber()) - V4THROW_TYPE("qsTrId(): second argument (n) must be a number"); + if (callData->argc < 1) + THROW_GENERIC_ERROR("qsTrId() requires at least one argument"); + if (!callData->args[0].isString()) + THROW_TYPE_ERROR_WITH_MESSAGE("qsTrId(): first argument (id) must be a string"); + if (callData->argc > 1 && !callData->args[1].isNumber()) + THROW_TYPE_ERROR_WITH_MESSAGE("qsTrId(): second argument (n) must be a number"); int n = -1; - if (ctx->argc() > 1) - n = ctx->args()[1].toInt32(); + if (callData->argc > 1) + n = callData->args[1].toInt32(); - return ctx->d()->engine->newString(qtTrId(ctx->args()[0].toQStringNoThrow().toUtf8().constData(), n))->asReturnedValue(); + scope.result = scope.engine->newString(qtTrId(callData->args[0].toQStringNoThrow().toUtf8().constData(), n)); } /*! @@ -1990,41 +2007,41 @@ ReturnedValue GlobalExtensions::method_qsTrId(CallContext *ctx) \sa qsTrId(), {Internationalization and Localization with Qt Quick} */ -ReturnedValue GlobalExtensions::method_qsTrIdNoOp(CallContext *ctx) +void GlobalExtensions::method_qsTrIdNoOp(const BuiltinFunction *, Scope &scope, CallData *callData) { - if (ctx->argc() < 1) - return QV4::Encode::undefined(); - return ctx->args()[0].asReturnedValue(); + if (callData->argc < 1) + scope.result = QV4::Encode::undefined(); + else + scope.result = callData->args[0]; } #endif // translation -QV4::ReturnedValue GlobalExtensions::method_gc(CallContext *ctx) +void GlobalExtensions::method_gc(const BuiltinFunction *, Scope &scope, CallData *) { - ctx->d()->engine->memoryManager->runGC(); + scope.engine->memoryManager->runGC(); - return QV4::Encode::undefined(); + scope.result = QV4::Encode::undefined(); } -ReturnedValue GlobalExtensions::method_string_arg(CallContext *ctx) +void GlobalExtensions::method_string_arg(const BuiltinFunction *, Scope &scope, CallData *callData) { - if (ctx->argc() != 1) - V4THROW_ERROR("String.arg(): Invalid arguments"); + if (callData->argc != 1) + THROW_GENERIC_ERROR("String.arg(): Invalid arguments"); - QString value = ctx->thisObject().toQString(); + QString value = callData->thisObject.toQString(); - QV4::Scope scope(ctx); - QV4::ScopedValue arg(scope, ctx->args()[0]); + QV4::ScopedValue arg(scope, callData->args[0]); if (arg->isInteger()) - return ctx->d()->engine->newString(value.arg(arg->integerValue()))->asReturnedValue(); + RETURN_RESULT(scope.engine->newString(value.arg(arg->integerValue()))); else if (arg->isDouble()) - return ctx->d()->engine->newString(value.arg(arg->doubleValue()))->asReturnedValue(); + RETURN_RESULT(scope.engine->newString(value.arg(arg->doubleValue()))); else if (arg->isBoolean()) - return ctx->d()->engine->newString(value.arg(arg->booleanValue()))->asReturnedValue(); + RETURN_RESULT(scope.engine->newString(value.arg(arg->booleanValue()))); - return ctx->d()->engine->newString(value.arg(arg->toQString()))->asReturnedValue(); + RETURN_RESULT(scope.engine->newString(value.arg(arg->toQString()))); } /*! @@ -2047,10 +2064,10 @@ be passed on to the function invoked. Note that if redundant calls are eliminated, then only the last set of arguments will be passed to the function. */ -ReturnedValue QtObject::method_callLater(CallContext *ctx) +void QtObject::method_callLater(const BuiltinFunction *b, Scope &scope, CallData *callData) { - QV8Engine *v8engine = ctx->engine()->v8Engine; - return v8engine->delayedCallQueue()->addUniquelyAndExecuteLater(ctx); + QV8Engine *v8engine = scope.engine->v8Engine; + v8engine->delayedCallQueue()->addUniquelyAndExecuteLater(b, scope, callData); } QT_END_NAMESPACE diff --git a/src/qml/qml/v8/qqmlbuiltinfunctions_p.h b/src/qml/qml/v8/qqmlbuiltinfunctions_p.h index fe43532647..21613b7c10 100644 --- a/src/qml/qml/v8/qqmlbuiltinfunctions_p.h +++ b/src/qml/qml/v8/qqmlbuiltinfunctions_p.h @@ -93,45 +93,45 @@ struct QtObject : Object static ReturnedValue get(const Managed *m, String *name, bool *hasProperty); static void advanceIterator(Managed *m, ObjectIterator *it, Value *name, uint *index, Property *p, PropertyAttributes *attributes); - static ReturnedValue method_isQtObject(CallContext *ctx); - static ReturnedValue method_rgba(CallContext *ctx); - static ReturnedValue method_hsla(CallContext *ctx); - static ReturnedValue method_hsva(CallContext *ctx); - static ReturnedValue method_colorEqual(CallContext *ctx); - static ReturnedValue method_font(CallContext *ctx); - static ReturnedValue method_rect(CallContext *ctx); - static ReturnedValue method_point(CallContext *ctx); - static ReturnedValue method_size(CallContext *ctx); - static ReturnedValue method_vector2d(CallContext *ctx); - static ReturnedValue method_vector3d(CallContext *ctx); - static ReturnedValue method_vector4d(CallContext *ctx); - static ReturnedValue method_quaternion(CallContext *ctx); - static ReturnedValue method_matrix4x4(CallContext *ctx); - static ReturnedValue method_lighter(CallContext *ctx); - static ReturnedValue method_darker(CallContext *ctx); - static ReturnedValue method_tint(CallContext *ctx); - static ReturnedValue method_formatDate(CallContext *ctx); - static ReturnedValue method_formatTime(CallContext *ctx); - static ReturnedValue method_formatDateTime(CallContext *ctx); - static ReturnedValue method_openUrlExternally(CallContext *ctx); - static ReturnedValue method_fontFamilies(CallContext *ctx); - static ReturnedValue method_md5(CallContext *ctx); - static ReturnedValue method_btoa(CallContext *ctx); - static ReturnedValue method_atob(CallContext *ctx); - static ReturnedValue method_quit(CallContext *ctx); - static ReturnedValue method_exit(CallContext *ctx); - static ReturnedValue method_resolvedUrl(CallContext *ctx); - static ReturnedValue method_createQmlObject(CallContext *ctx); - static ReturnedValue method_createComponent(CallContext *ctx); - static ReturnedValue method_locale(CallContext *ctx); - static ReturnedValue method_binding(CallContext *ctx); - - static ReturnedValue method_get_platform(CallContext *ctx); - static ReturnedValue method_get_application(CallContext *ctx); - static ReturnedValue method_get_inputMethod(CallContext *ctx); - static ReturnedValue method_get_styleHints(CallContext *ctx); - - static ReturnedValue method_callLater(CallContext *ctx); + static void method_isQtObject(const BuiltinFunction *, Scope &scope, CallData *callData); + static void method_rgba(const BuiltinFunction *, Scope &scope, CallData *callData); + static void method_hsla(const BuiltinFunction *, Scope &scope, CallData *callData); + static void method_hsva(const BuiltinFunction *, Scope &scope, CallData *callData); + static void method_colorEqual(const BuiltinFunction *, Scope &scope, CallData *callData); + static void method_font(const BuiltinFunction *, Scope &scope, CallData *callData); + static void method_rect(const BuiltinFunction *, Scope &scope, CallData *callData); + static void method_point(const BuiltinFunction *, Scope &scope, CallData *callData); + static void method_size(const BuiltinFunction *, Scope &scope, CallData *callData); + static void method_vector2d(const BuiltinFunction *, Scope &scope, CallData *callData); + static void method_vector3d(const BuiltinFunction *, Scope &scope, CallData *callData); + static void method_vector4d(const BuiltinFunction *, Scope &scope, CallData *callData); + static void method_quaternion(const BuiltinFunction *, Scope &scope, CallData *callData); + static void method_matrix4x4(const BuiltinFunction *, Scope &scope, CallData *callData); + static void method_lighter(const BuiltinFunction *, Scope &scope, CallData *callData); + static void method_darker(const BuiltinFunction *, Scope &scope, CallData *callData); + static void method_tint(const BuiltinFunction *, Scope &scope, CallData *callData); + static void method_formatDate(const BuiltinFunction *, Scope &scope, CallData *callData); + static void method_formatTime(const BuiltinFunction *, Scope &scope, CallData *callData); + static void method_formatDateTime(const BuiltinFunction *, Scope &scope, CallData *callData); + static void method_openUrlExternally(const BuiltinFunction *, Scope &scope, CallData *callData); + static void method_fontFamilies(const BuiltinFunction *, Scope &scope, CallData *callData); + static void method_md5(const BuiltinFunction *, Scope &scope, CallData *callData); + static void method_btoa(const BuiltinFunction *, Scope &scope, CallData *callData); + static void method_atob(const BuiltinFunction *, Scope &scope, CallData *callData); + static void method_quit(const BuiltinFunction *, Scope &scope, CallData *callData); + static void method_exit(const BuiltinFunction *, Scope &scope, CallData *callData); + static void method_resolvedUrl(const BuiltinFunction *, Scope &scope, CallData *callData); + static void method_createQmlObject(const BuiltinFunction *, Scope &scope, CallData *callData); + static void method_createComponent(const BuiltinFunction *, Scope &scope, CallData *callData); + static void method_locale(const BuiltinFunction *, Scope &scope, CallData *callData); + static void method_binding(const BuiltinFunction *, Scope &scope, CallData *callData); + + static void method_get_platform(const BuiltinFunction *, Scope &scope, CallData *callData); + static void method_get_application(const BuiltinFunction *, Scope &scope, CallData *callData); + static void method_get_inputMethod(const BuiltinFunction *, Scope &scope, CallData *callData); + static void method_get_styleHints(const BuiltinFunction *, Scope &scope, CallData *callData); + + static void method_callLater(const BuiltinFunction *, Scope &scope, CallData *callData); private: void addAll(); @@ -142,18 +142,18 @@ struct ConsoleObject : Object { V4_OBJECT2(ConsoleObject, Object) - static ReturnedValue method_error(CallContext *ctx); - static ReturnedValue method_log(CallContext *ctx); - static ReturnedValue method_info(CallContext *ctx); - static ReturnedValue method_profile(CallContext *ctx); - static ReturnedValue method_profileEnd(CallContext *ctx); - static ReturnedValue method_time(CallContext *ctx); - static ReturnedValue method_timeEnd(CallContext *ctx); - static ReturnedValue method_count(CallContext *ctx); - static ReturnedValue method_trace(CallContext *ctx); - static ReturnedValue method_warn(CallContext *ctx); - static ReturnedValue method_assert(CallContext *ctx); - static ReturnedValue method_exception(CallContext *ctx); + static void method_error(const BuiltinFunction *, Scope &scope, CallData *callData); + static void method_log(const BuiltinFunction *, Scope &scope, CallData *callData); + static void method_info(const BuiltinFunction *, Scope &scope, CallData *callData); + static void method_profile(const BuiltinFunction *, Scope &scope, CallData *callData); + static void method_profileEnd(const BuiltinFunction *, Scope &scope, CallData *callData); + static void method_time(const BuiltinFunction *, Scope &scope, CallData *callData); + static void method_timeEnd(const BuiltinFunction *, Scope &scope, CallData *callData); + static void method_count(const BuiltinFunction *, Scope &scope, CallData *callData); + static void method_trace(const BuiltinFunction *, Scope &scope, CallData *callData); + static void method_warn(const BuiltinFunction *, Scope &scope, CallData *callData); + static void method_assert(const BuiltinFunction *, Scope &scope, CallData *callData); + static void method_exception(const BuiltinFunction *, Scope &scope, CallData *callData); }; @@ -161,17 +161,17 @@ struct Q_QML_PRIVATE_EXPORT GlobalExtensions { static void init(Object *globalObject, QJSEngine::Extensions extensions); #if QT_CONFIG(translation) - static ReturnedValue method_qsTranslate(CallContext *ctx); - static ReturnedValue method_qsTranslateNoOp(CallContext *ctx); - static ReturnedValue method_qsTr(CallContext *ctx); - static ReturnedValue method_qsTrNoOp(CallContext *ctx); - static ReturnedValue method_qsTrId(CallContext *ctx); - static ReturnedValue method_qsTrIdNoOp(CallContext *ctx); + static void method_qsTranslate(const BuiltinFunction *, Scope &scope, CallData *callData); + static void method_qsTranslateNoOp(const BuiltinFunction *, Scope &scope, CallData *callData); + static void method_qsTr(const BuiltinFunction *, Scope &scope, CallData *callData); + static void method_qsTrNoOp(const BuiltinFunction *, Scope &scope, CallData *callData); + static void method_qsTrId(const BuiltinFunction *, Scope &scope, CallData *callData); + static void method_qsTrIdNoOp(const BuiltinFunction *, Scope &scope, CallData *callData); #endif - static ReturnedValue method_gc(CallContext *ctx); + static void method_gc(const BuiltinFunction *, Scope &scope, CallData *callData); // on String:prototype - static ReturnedValue method_string_arg(CallContext *ctx); + static void method_string_arg(const BuiltinFunction *, Scope &scope, CallData *callData); }; diff --git a/src/qml/qml/v8/qv4domerrors_p.h b/src/qml/qml/v8/qv4domerrors_p.h index faa9dd8bc7..a9bdbe01ae 100644 --- a/src/qml/qml/v8/qv4domerrors_p.h +++ b/src/qml/qml/v8/qv4domerrors_p.h @@ -74,11 +74,12 @@ QT_BEGIN_NAMESPACE #define DOMEXCEPTION_VALIDATION_ERR 16 #define DOMEXCEPTION_TYPE_MISMATCH_ERR 17 -#define V4THROW_DOM(error, string) { \ +#define THROW_DOM(error, string) { \ QV4::ScopedValue v(scope, scope.engine->newString(QStringLiteral(string))); \ QV4::ScopedObject ex(scope, scope.engine->newErrorObject(v)); \ ex->put(QV4::ScopedString(scope, scope.engine->newIdentifier(QStringLiteral("code"))), QV4::ScopedValue(scope, QV4::Primitive::fromInt32(error))); \ - return ctx->engine()->throwError(ex); \ + scope.result = scope.engine->throwError(ex); \ + return; \ } namespace QV4 { diff --git a/src/qml/types/qqmlbind.cpp b/src/qml/types/qqmlbind.cpp index a545fe57ca..2ded9c13c8 100644 --- a/src/qml/types/qqmlbind.cpp +++ b/src/qml/types/qqmlbind.cpp @@ -82,12 +82,12 @@ void QQmlBindPrivate::validate(QObject *binding) const return; if (!prop.isValid()) { - qmlInfo(binding) << "Property '" << propName << "' does not exist on " << QQmlMetaType::prettyTypeName(obj) << "."; + qmlWarning(binding) << "Property '" << propName << "' does not exist on " << QQmlMetaType::prettyTypeName(obj) << "."; return; } if (!prop.isWritable()) { - qmlInfo(binding) << "Property '" << propName << "' on " << QQmlMetaType::prettyTypeName(obj) << " is read-only."; + qmlWarning(binding) << "Property '" << propName << "' on " << QQmlMetaType::prettyTypeName(obj) << " is read-only."; return; } } diff --git a/src/qml/types/qqmlconnections.cpp b/src/qml/types/qqmlconnections.cpp index 2aed4d9972..870aeaa6e2 100644 --- a/src/qml/types/qqmlconnections.cpp +++ b/src/qml/types/qqmlconnections.cpp @@ -168,7 +168,7 @@ void QQmlConnections::setTarget(QObject *obj) if (d->targetSet && d->target == obj) return; d->targetSet = true; // even if setting to 0, it is *set* - foreach (QQmlBoundSignal *s, d->boundsignals) { + for (QQmlBoundSignal *s : qAsConst(d->boundsignals)) { // It is possible that target is being changed due to one of our signal // handlers -> use deleteLater(). if (s->isNotifying()) @@ -278,7 +278,7 @@ void QQmlConnections::connectSignals() QQmlContextData *ctxtdata = ddata ? ddata->outerContext : 0; const QV4::CompiledData::Unit *qmlUnit = d->compilationUnit->data; - foreach (const QV4::CompiledData::Binding *binding, d->bindings) { + for (const QV4::CompiledData::Binding *binding : qAsConst(d->bindings)) { Q_ASSERT(binding->type == QV4::CompiledData::Binding::Type_Script); QString propName = qmlUnit->stringAt(binding->propertyNameIndex); @@ -295,7 +295,7 @@ void QQmlConnections::connectSignals() d->boundsignals += signal; } else { if (!d->ignoreUnknownSignals) - qmlInfo(this) << tr("Cannot assign to non-existent property \"%1\"").arg(propName); + qmlWarning(this) << tr("Cannot assign to non-existent property \"%1\"").arg(propName); } } } diff --git a/src/qml/types/qqmldelegatemodel.cpp b/src/qml/types/qqmldelegatemodel.cpp index be10b270ae..a5878dcffd 100644 --- a/src/qml/types/qqmldelegatemodel.cpp +++ b/src/qml/types/qqmldelegatemodel.cpp @@ -264,7 +264,7 @@ QQmlDelegateModel::~QQmlDelegateModel() { Q_D(QQmlDelegateModel); - foreach (QQmlDelegateModelItem *cacheItem, d->m_cache) { + for (QQmlDelegateModelItem *cacheItem : qAsConst(d->m_cache)) { if (cacheItem->object) { delete cacheItem->object; @@ -310,7 +310,7 @@ void QQmlDelegateModel::componentComplete() --d->m_groupCount; --i; } else if (name.at(0).isUpper()) { - qmlInfo(d->m_groups[i]) << QQmlDelegateModelGroup::tr("Group names must start with a lower case letter"); + qmlWarning(d->m_groups[i]) << QQmlDelegateModelGroup::tr("Group names must start with a lower case letter"); d->m_groups[i] = d->m_groups[d->m_groupCount - 1]; --d->m_groupCount; --i; @@ -404,7 +404,7 @@ void QQmlDelegateModel::setDelegate(QQmlComponent *delegate) { Q_D(QQmlDelegateModel); if (d->m_transaction) { - qmlInfo(this) << tr("The delegate of a DelegateModel cannot be changed within onUpdated."); + qmlWarning(this) << tr("The delegate of a DelegateModel cannot be changed within onUpdated."); return; } bool wasValid = d->m_delegate != 0; @@ -610,7 +610,7 @@ void QQmlDelegateModelPrivate::group_append( if (d->m_complete) return; if (d->m_groupCount == Compositor::MaximumGroupCount) { - qmlInfo(d->q_func()) << QQmlDelegateModel::tr("The maximum number of supported DelegateModelGroups is 8"); + qmlWarning(d->q_func()) << QQmlDelegateModel::tr("The maximum number of supported DelegateModelGroups is 8"); return; } d->m_groups[d->m_groupCount] = group; @@ -719,7 +719,7 @@ void QQmlDelegateModel::setFilterGroup(const QString &group) Q_D(QQmlDelegateModel); if (d->m_transaction) { - qmlInfo(this) << tr("The group of a DelegateModel cannot be changed within onChanged"); + qmlWarning(this) << tr("The group of a DelegateModel cannot be changed within onChanged"); return; } @@ -764,7 +764,8 @@ void QQmlDelegateModelPrivate::updateFilterGroup() emit q->countChanged(); if (m_parts) { - foreach (QQmlPartsModel *model, m_parts->models) + auto partsCopy = m_parts->models; // deliberate; this may alter m_parts + for (QQmlPartsModel *model : qAsConst(partsCopy)) model->updateFilterGroup(m_compositorGroup, changeSet); } } @@ -889,7 +890,7 @@ void QQmlDelegateModelPrivate::incubatorStatusChanged(QQDMIncubationTask *incuba emitCreatedItem(incubationTask, cacheItem->object); cacheItem->releaseObject(); } else if (status == QQmlIncubator::Error) { - qmlInfo(q, m_delegate->errors()) << "Error creating delegate"; + qmlWarning(q, m_delegate->errors()) << "Error creating delegate"; } if (!cacheItem->isObjectReferenced()) { @@ -1472,7 +1473,8 @@ void QQmlDelegateModelPrivate::emitChanges() for (int i = 1; i < m_groupCount; ++i) QQmlDelegateModelGroupPrivate::get(m_groups[i])->emitModelUpdated(reset); - foreach (QQmlDelegateModelItem *cacheItem, m_cache) { + auto cacheCopy = m_cache; // deliberate; emitChanges may alter m_cache + for (QQmlDelegateModelItem *cacheItem : qAsConst(cacheCopy)) { if (cacheItem->attached) cacheItem->attached->emitChanges(); } @@ -1793,24 +1795,26 @@ int QQmlDelegateModelItemMetaType::parseGroups(const QV4::Value &groups) const return groupFlags; } -QV4::ReturnedValue QQmlDelegateModelItem::get_model(QV4::CallContext *ctx) +void QQmlDelegateModelItem::get_model(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData) { - QV4::Scope scope(ctx); - QV4::Scoped<QQmlDelegateModelItemObject> o(scope, ctx->thisObject().as<QQmlDelegateModelItemObject>()); - if (!o) - return ctx->engine()->throwTypeError(QStringLiteral("Not a valid VisualData object")); + QV4::Scoped<QQmlDelegateModelItemObject> o(scope, callData->thisObject.as<QQmlDelegateModelItemObject>()); + if (!o) { + scope.result = scope.engine->throwTypeError(QStringLiteral("Not a valid VisualData object")); + return; + } if (!o->d()->item->metaType->model) - return QV4::Encode::undefined(); + RETURN_UNDEFINED(); - return o->d()->item->get(); + scope.result = o->d()->item->get(); } -QV4::ReturnedValue QQmlDelegateModelItem::get_groups(QV4::CallContext *ctx) +void QQmlDelegateModelItem::get_groups(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData) { - QV4::Scope scope(ctx); - QV4::Scoped<QQmlDelegateModelItemObject> o(scope, ctx->thisObject().as<QQmlDelegateModelItemObject>()); - if (!o) - return ctx->engine()->throwTypeError(QStringLiteral("Not a valid VisualData object")); + QV4::Scoped<QQmlDelegateModelItemObject> o(scope, callData->thisObject.as<QQmlDelegateModelItemObject>()); + if (!o) { + scope.result = scope.engine->throwTypeError(QStringLiteral("Not a valid VisualData object")); + return; + } QStringList groups; for (int i = 1; i < o->d()->item->metaType->groupCount; ++i) { @@ -1818,27 +1822,29 @@ QV4::ReturnedValue QQmlDelegateModelItem::get_groups(QV4::CallContext *ctx) groups.append(o->d()->item->metaType->groupNames.at(i - 1)); } - return scope.engine->fromVariant(groups); + scope.result = scope.engine->fromVariant(groups); } -QV4::ReturnedValue QQmlDelegateModelItem::set_groups(QV4::CallContext *ctx) +void QQmlDelegateModelItem::set_groups(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData) { - QV4::Scope scope(ctx); - QV4::Scoped<QQmlDelegateModelItemObject> o(scope, ctx->thisObject().as<QQmlDelegateModelItemObject>()); - if (!o) - return ctx->engine()->throwTypeError(QStringLiteral("Not a valid VisualData object")); - if (!ctx->argc()) - return ctx->engine()->throwTypeError(); + QV4::Scoped<QQmlDelegateModelItemObject> o(scope, callData->thisObject.as<QQmlDelegateModelItemObject>()); + if (!o) { + scope.result = scope.engine->throwTypeError(QStringLiteral("Not a valid VisualData object")); + return; + } + + if (!callData->argc) + THROW_TYPE_ERROR(); if (!o->d()->item->metaType->model) - return QV4::Encode::undefined(); + RETURN_UNDEFINED(); QQmlDelegateModelPrivate *model = QQmlDelegateModelPrivate::get(o->d()->item->metaType->model); - const int groupFlags = model->m_cacheMetaType->parseGroups(ctx->args()[0]); + const int groupFlags = model->m_cacheMetaType->parseGroups(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(); + scope.result = QV4::Encode::undefined(); } QV4::ReturnedValue QQmlDelegateModelItem::get_member(QQmlDelegateModelItem *thisItem, uint flag, const QV4::Value &) @@ -2459,7 +2465,7 @@ QQmlV4Handle QQmlDelegateModelGroup::get(int index) 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"); + qmlWarning(this) << tr("get: index out of range"); return QQmlV4Handle(QV4::Encode::undefined()); } @@ -2552,7 +2558,7 @@ void QQmlDelegateModelGroup::insert(QQmlV4Function *args) QV4::ScopedValue v(scope, (*args)[i]); if (d->parseIndex(v, &index, &group)) { if (index < 0 || index > model->m_compositor.count(group)) { - qmlInfo(this) << tr("insert: index out of range"); + qmlWarning(this) << tr("insert: index out of range"); return; } if (++i == args->length()) @@ -2637,7 +2643,7 @@ void QQmlDelegateModelGroup::create(QQmlV4Function *args) } } if (index < 0 || index >= model->m_compositor.count(group)) { - qmlInfo(this) << tr("create: index out of range"); + qmlWarning(this) << tr("create: index out of range"); return; } @@ -2690,22 +2696,22 @@ void QQmlDelegateModelGroup::resolve(QQmlV4Function *args) QV4::ScopedValue v(scope, (*args)[0]); if (d->parseIndex(v, &from, &fromGroup)) { if (from < 0 || from >= model->m_compositor.count(fromGroup)) { - qmlInfo(this) << tr("resolve: from index out of range"); + qmlWarning(this) << tr("resolve: from index out of range"); return; } } else { - qmlInfo(this) << tr("resolve: from index invalid"); + qmlWarning(this) << tr("resolve: from index invalid"); return; } v = (*args)[1]; if (d->parseIndex(v, &to, &toGroup)) { if (to < 0 || to >= model->m_compositor.count(toGroup)) { - qmlInfo(this) << tr("resolve: to index out of range"); + qmlWarning(this) << tr("resolve: to index out of range"); return; } } else { - qmlInfo(this) << tr("resolve: to index invalid"); + qmlWarning(this) << tr("resolve: to index invalid"); return; } @@ -2713,11 +2719,11 @@ void QQmlDelegateModelGroup::resolve(QQmlV4Function *args) Compositor::iterator toIt = model->m_compositor.find(toGroup, to); if (!fromIt->isUnresolved()) { - qmlInfo(this) << tr("resolve: from is not an unresolved item"); + qmlWarning(this) << tr("resolve: from is not an unresolved item"); return; } if (!toIt->list) { - qmlInfo(this) << tr("resolve: to is not a model item"); + qmlWarning(this) << tr("resolve: to is not a model item"); return; } @@ -2787,7 +2793,7 @@ void QQmlDelegateModelGroup::remove(QQmlV4Function *args) QV4::Scope scope(args->v4engine()); QV4::ScopedValue v(scope, (*args)[0]); if (!d->parseIndex(v, &index, &group)) { - qmlInfo(this) << tr("remove: invalid index"); + qmlWarning(this) << tr("remove: invalid index"); return; } @@ -2799,11 +2805,11 @@ void QQmlDelegateModelGroup::remove(QQmlV4Function *args) QQmlDelegateModelPrivate *model = QQmlDelegateModelPrivate::get(d->model); if (index < 0 || index >= model->m_compositor.count(group)) { - qmlInfo(this) << tr("remove: index out of range"); + qmlWarning(this) << tr("remove: index out of range"); } else if (count != 0) { Compositor::iterator it = model->m_compositor.find(group, index); if (count < 0 || count > model->m_compositor.count(d->group) - it.index[d->group]) { - qmlInfo(this) << tr("remove: invalid count"); + qmlWarning(this) << tr("remove: invalid count"); } else { model->removeGroups(it, count, d->group, 1 << d->group); } @@ -2858,11 +2864,11 @@ void QQmlDelegateModelGroup::addGroups(QQmlV4Function *args) QQmlDelegateModelPrivate *model = QQmlDelegateModelPrivate::get(d->model); if (index < 0 || index >= model->m_compositor.count(group)) { - qmlInfo(this) << tr("addGroups: index out of range"); + qmlWarning(this) << tr("addGroups: index out of range"); } else if (count != 0) { Compositor::iterator it = model->m_compositor.find(group, index); if (count < 0 || count > model->m_compositor.count(d->group) - it.index[d->group]) { - qmlInfo(this) << tr("addGroups: invalid count"); + qmlWarning(this) << tr("addGroups: invalid count"); } else { model->addGroups(it, count, d->group, groups); } @@ -2888,11 +2894,11 @@ void QQmlDelegateModelGroup::removeGroups(QQmlV4Function *args) QQmlDelegateModelPrivate *model = QQmlDelegateModelPrivate::get(d->model); if (index < 0 || index >= model->m_compositor.count(group)) { - qmlInfo(this) << tr("removeGroups: index out of range"); + qmlWarning(this) << tr("removeGroups: index out of range"); } else if (count != 0) { Compositor::iterator it = model->m_compositor.find(group, index); if (count < 0 || count > model->m_compositor.count(d->group) - it.index[d->group]) { - qmlInfo(this) << tr("removeGroups: invalid count"); + qmlWarning(this) << tr("removeGroups: invalid count"); } else { model->removeGroups(it, count, d->group, groups); } @@ -2918,11 +2924,11 @@ void QQmlDelegateModelGroup::setGroups(QQmlV4Function *args) QQmlDelegateModelPrivate *model = QQmlDelegateModelPrivate::get(d->model); if (index < 0 || index >= model->m_compositor.count(group)) { - qmlInfo(this) << tr("setGroups: index out of range"); + qmlWarning(this) << tr("setGroups: index out of range"); } else if (count != 0) { Compositor::iterator it = model->m_compositor.find(group, index); if (count < 0 || count > model->m_compositor.count(d->group) - it.index[d->group]) { - qmlInfo(this) << tr("setGroups: invalid count"); + qmlWarning(this) << tr("setGroups: invalid count"); } else { model->setGroups(it, count, d->group, groups); } @@ -2957,13 +2963,13 @@ void QQmlDelegateModelGroup::move(QQmlV4Function *args) QV4::Scope scope(args->v4engine()); QV4::ScopedValue v(scope, (*args)[0]); if (!d->parseIndex(v, &from, &fromGroup)) { - qmlInfo(this) << tr("move: invalid from index"); + qmlWarning(this) << tr("move: invalid from index"); return; } v = (*args)[1]; if (!d->parseIndex(v, &to, &toGroup)) { - qmlInfo(this) << tr("move: invalid to index"); + qmlWarning(this) << tr("move: invalid to index"); return; } @@ -2976,11 +2982,11 @@ void QQmlDelegateModelGroup::move(QQmlV4Function *args) QQmlDelegateModelPrivate *model = QQmlDelegateModelPrivate::get(d->model); if (count < 0) { - qmlInfo(this) << tr("move: invalid count"); + qmlWarning(this) << tr("move: invalid count"); } else if (from < 0 || from + count > model->m_compositor.count(fromGroup)) { - qmlInfo(this) << tr("move: from index out of range"); + qmlWarning(this) << tr("move: from index out of range"); } else if (!model->m_compositor.verifyMoveTo(fromGroup, from, toGroup, to, count, d->group)) { - qmlInfo(this) << tr("move: to index out of range"); + qmlWarning(this) << tr("move: to index out of range"); } else if (count > 0) { QVector<Compositor::Remove> removes; QVector<Compositor::Insert> inserts; @@ -3038,7 +3044,7 @@ QString QQmlPartsModel::filterGroup() const void QQmlPartsModel::setFilterGroup(const QString &group) { if (QQmlDelegateModelPrivate::get(m_model)->m_transaction) { - qmlInfo(this) << tr("The group of a DelegateModel cannot be changed within onChanged"); + qmlWarning(this) << tr("The group of a DelegateModel cannot be changed within onChanged"); return; } @@ -3151,7 +3157,7 @@ QObject *QQmlPartsModel::object(int index, bool asynchronous) model->release(object); if (!model->m_delegateValidated) { if (object) - qmlInfo(model->m_delegate) << tr("Delegate component must be Package type."); + qmlWarning(model->m_delegate) << tr("Delegate component must be Package type."); model->m_delegateValidated = true; } @@ -3232,28 +3238,25 @@ struct QQmlDelegateModelGroupChange : QV4::Object return e->memoryManager->allocObject<QQmlDelegateModelGroupChange>(); } - static QV4::ReturnedValue method_get_index(QV4::CallContext *ctx) { - QV4::Scope scope(ctx); - QV4::Scoped<QQmlDelegateModelGroupChange> that(scope, ctx->thisObject().as<QQmlDelegateModelGroupChange>()); + static void method_get_index(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData) { + QV4::Scoped<QQmlDelegateModelGroupChange> that(scope, callData->thisObject.as<QQmlDelegateModelGroupChange>()); if (!that) - return ctx->engine()->throwTypeError(); - return QV4::Encode(that->d()->change.index); + THROW_TYPE_ERROR(); + scope.result = 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->thisObject().as<QQmlDelegateModelGroupChange>()); + static void method_get_count(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData) { + QV4::Scoped<QQmlDelegateModelGroupChange> that(scope, callData->thisObject.as<QQmlDelegateModelGroupChange>()); if (!that) - return ctx->engine()->throwTypeError(); - return QV4::Encode(that->d()->change.count); + THROW_TYPE_ERROR(); + scope.result = 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->thisObject().as<QQmlDelegateModelGroupChange>()); + static void method_get_moveId(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData) { + QV4::Scoped<QQmlDelegateModelGroupChange> that(scope, callData->thisObject.as<QQmlDelegateModelGroupChange>()); if (!that) - return ctx->engine()->throwTypeError(); + THROW_TYPE_ERROR(); if (that->d()->change.moveId < 0) - return QV4::Encode::undefined(); - return QV4::Encode(that->d()->change.moveId); + RETURN_UNDEFINED(); + scope.result = QV4::Encode(that->d()->change.moveId); } }; diff --git a/src/qml/types/qqmldelegatemodel_p_p.h b/src/qml/types/qqmldelegatemodel_p_p.h index 4c2841b8ba..cb4a1f79ba 100644 --- a/src/qml/types/qqmldelegatemodel_p_p.h +++ b/src/qml/types/qqmldelegatemodel_p_p.h @@ -131,9 +131,9 @@ public: virtual void setValue(const QString &role, const QVariant &value) { Q_UNUSED(role); Q_UNUSED(value); } virtual bool resolveIndex(const QQmlAdaptorModel &, int) { return false; } - static QV4::ReturnedValue get_model(QV4::CallContext *ctx); - static QV4::ReturnedValue get_groups(QV4::CallContext *ctx); - static QV4::ReturnedValue set_groups(QV4::CallContext *ctx); + static void get_model(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData); + static void get_groups(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData); + static void set_groups(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData); static QV4::ReturnedValue get_member(QQmlDelegateModelItem *thisItem, uint flag, const QV4::Value &); static QV4::ReturnedValue set_member(QQmlDelegateModelItem *thisItem, uint flag, const QV4::Value &arg); static QV4::ReturnedValue get_index(QQmlDelegateModelItem *thisItem, uint flag, const QV4::Value &arg); diff --git a/src/qml/types/qqmllistmodel.cpp b/src/qml/types/qqmllistmodel.cpp index 1a2e4c7f6f..cc4ccbaeb1 100644 --- a/src/qml/types/qqmllistmodel.cpp +++ b/src/qml/types/qqmllistmodel.cpp @@ -99,7 +99,7 @@ const ListLayout::Role &ListLayout::getRoleOrCreate(const QString &key, Role::Da if (node) { const Role &r = *node->value; if (type != r.type) - qmlInfo(0) << QStringLiteral("Can't assign to existing role '%1' of different type [%2 -> %3]").arg(r.name).arg(roleTypeName(type)).arg(roleTypeName(r.type)); + qmlWarning(0) << QStringLiteral("Can't assign to existing role '%1' of different type [%2 -> %3]").arg(r.name).arg(roleTypeName(type)).arg(roleTypeName(r.type)); return r; } @@ -112,7 +112,7 @@ const ListLayout::Role &ListLayout::getRoleOrCreate(QV4::String *key, Role::Data if (node) { const Role &r = *node->value; if (type != r.type) - qmlInfo(0) << QStringLiteral("Can't assign to existing role '%1' of different type [%2 -> %3]").arg(r.name).arg(roleTypeName(type)).arg(roleTypeName(r.type)); + qmlWarning(0) << QStringLiteral("Can't assign to existing role '%1' of different type [%2 -> %3]").arg(r.name).arg(roleTypeName(type)).arg(roleTypeName(r.type)); return r; } @@ -226,7 +226,7 @@ const ListLayout::Role *ListLayout::getRoleOrCreate(const QString &key, const QV } if (type == Role::Invalid) { - qmlInfo(0) << "Can't create role for unsupported data type"; + qmlWarning(0) << "Can't create role for unsupported data type"; return 0; } @@ -1201,7 +1201,7 @@ int ListElement::setJsProperty(const ListLayout::Role &role, const QV4::Value &d } roleIndex = setListProperty(role, subModel); } else { - qmlInfo(0) << QStringLiteral("Can't assign to existing role '%1' of different type [%2 -> %3]").arg(role.name).arg(roleTypeName(role.type)).arg(roleTypeName(ListLayout::Role::List)); + qmlWarning(0) << QStringLiteral("Can't assign to existing role '%1' of different type [%2 -> %3]").arg(role.name).arg(roleTypeName(role.type)).arg(roleTypeName(ListLayout::Role::List)); } } else if (d.isBoolean()) { roleIndex = setBoolProperty(role, d.booleanValue()); @@ -1267,10 +1267,12 @@ void ModelNodeMetaObject::updateValues() { const int roleCount = m_model->m_listModel->roleCount(); if (!m_initialized) { - int *changedRoles = reinterpret_cast<int *>(alloca(roleCount * sizeof(int))); - for (int i = 0; i < roleCount; ++i) - changedRoles[i] = i; - emitDirectNotifies(changedRoles, roleCount); + if (roleCount) { + int *changedRoles = reinterpret_cast<int *>(alloca(roleCount * sizeof(int))); + for (int i = 0; i < roleCount; ++i) + changedRoles[i] = i; + emitDirectNotifies(changedRoles, roleCount); + } return; } for (int i=0 ; i < roleCount ; ++i) { @@ -1984,18 +1986,18 @@ void QQmlListModel::setDynamicRoles(bool enableDynamicRoles) if (m_mainThread && m_agent == 0) { if (enableDynamicRoles) { if (m_layout->roleCount()) - qmlInfo(this) << tr("unable to enable dynamic roles as this model is not empty!"); + qmlWarning(this) << tr("unable to enable dynamic roles as this model is not empty!"); else m_dynamicRoles = true; } else { if (m_roles.count()) { - qmlInfo(this) << tr("unable to enable static roles as this model is not empty!"); + qmlWarning(this) << tr("unable to enable static roles as this model is not empty!"); } else { m_dynamicRoles = false; } } } else { - qmlInfo(this) << tr("dynamic role setting must be made from the main thread, before any worker scripts are created"); + qmlWarning(this) << tr("dynamic role setting must be made from the main thread, before any worker scripts are created"); } } @@ -2048,7 +2050,7 @@ void QQmlListModel::remove(QQmlV4Function *args) int removeCount = (argLength == 2 ? QV4::ScopedValue(scope, (*args)[1])->toInt32() : 1); if (index < 0 || index+removeCount > count() || removeCount <= 0) { - qmlInfo(this) << tr("remove: indices [%1 - %2] out of range [0 - %3]").arg(index).arg(index+removeCount).arg(count()); + qmlWarning(this) << tr("remove: indices [%1 - %2] out of range [0 - %3]").arg(index).arg(index+removeCount).arg(count()); return; } @@ -2064,7 +2066,7 @@ void QQmlListModel::remove(QQmlV4Function *args) emitItemsRemoved(index, removeCount); } else { - qmlInfo(this) << tr("remove: incorrect number of arguments"); + qmlWarning(this) << tr("remove: incorrect number of arguments"); } } @@ -2092,7 +2094,7 @@ void QQmlListModel::insert(QQmlV4Function *args) int index = arg0->toInt32(); if (index < 0 || index > count()) { - qmlInfo(this) << tr("insert: index %1 out of range").arg(index); + qmlWarning(this) << tr("insert: index %1 out of range").arg(index); return; } @@ -2124,10 +2126,10 @@ void QQmlListModel::insert(QQmlV4Function *args) emitItemsInserted(index, 1); } else { - qmlInfo(this) << tr("insert: value is not an object"); + qmlWarning(this) << tr("insert: value is not an object"); } } else { - qmlInfo(this) << tr("insert: value is not an object"); + qmlWarning(this) << tr("insert: value is not an object"); } } @@ -2150,7 +2152,7 @@ void QQmlListModel::move(int from, int to, int n) if (n==0 || from==to) return; if (!canMove(from, to, n)) { - qmlInfo(this) << tr("move: out of range"); + qmlWarning(this) << tr("move: out of range"); return; } @@ -2239,10 +2241,10 @@ void QQmlListModel::append(QQmlV4Function *args) emitItemsInserted(index, 1); } else { - qmlInfo(this) << tr("append: value is not an object"); + qmlWarning(this) << tr("append: value is not an object"); } } else { - qmlInfo(this) << tr("append: value is not an object"); + qmlWarning(this) << tr("append: value is not an object"); } } @@ -2321,11 +2323,11 @@ void QQmlListModel::set(int index, const QQmlV4Handle &handle) QV4::ScopedObject object(scope, handle); if (!object) { - qmlInfo(this) << tr("set: value is not an object"); + qmlWarning(this) << tr("set: value is not an object"); return; } if (index > count() || index < 0) { - qmlInfo(this) << tr("set: index %1 out of range").arg(index); + qmlWarning(this) << tr("set: index %1 out of range").arg(index); return; } @@ -2371,7 +2373,7 @@ void QQmlListModel::set(int index, const QQmlV4Handle &handle) void QQmlListModel::setProperty(int index, const QString& property, const QVariant& value) { if (count() == 0 || index >= count() || index < 0) { - qmlInfo(this) << tr("set: index %1 out of range").arg(index); + qmlWarning(this) << tr("set: index %1 out of range").arg(index); return; } @@ -2401,7 +2403,7 @@ void QQmlListModel::sync() // This is just a dummy method to make it look like sync() exists in // ListModel (and not just QQmlListModelWorkerAgent) and to let // us document sync(). - qmlInfo(this) << "List sync() can only be called from a WorkerScript"; + qmlWarning(this) << "List sync() can only be called from a WorkerScript"; } bool QQmlListModelParser::verifyProperty(const QV4::CompiledData::Unit *qmlUnit, const QV4::CompiledData::Binding *binding) @@ -2543,7 +2545,7 @@ void QQmlListModelParser::applyBindings(QObject *obj, QV4::CompiledData::Compila } if (setRoles == false) - qmlInfo(obj) << "All ListElement declarations are empty, no roles can be created unless dynamicRoles is set."; + qmlWarning(obj) << "All ListElement declarations are empty, no roles can be created unless dynamicRoles is set."; } bool QQmlListModelParser::definesEmptyList(const QString &s) diff --git a/src/qml/types/qqmlobjectmodel.cpp b/src/qml/types/qqmlobjectmodel.cpp index 695043b592..21205f4490 100644 --- a/src/qml/types/qqmlobjectmodel.cpp +++ b/src/qml/types/qqmlobjectmodel.cpp @@ -373,7 +373,7 @@ void QQmlObjectModel::insert(int index, QObject *object) { Q_D(QQmlObjectModel); if (index < 0 || index > count()) { - qmlInfo(this) << tr("insert: index %1 out of range").arg(index); + qmlWarning(this) << tr("insert: index %1 out of range").arg(index); return; } d->insert(index, object); @@ -400,7 +400,7 @@ void QQmlObjectModel::move(int from, int to, int n) if (n <= 0 || from == to) return; if (from < 0 || to < 0 || from + n > count() || to + n > count()) { - qmlInfo(this) << tr("move: out of range"); + qmlWarning(this) << tr("move: out of range"); return; } d->move(from, to, n); @@ -418,7 +418,7 @@ void QQmlObjectModel::remove(int index, int n) { Q_D(QQmlObjectModel); if (index < 0 || n <= 0 || index + n > count()) { - qmlInfo(this) << tr("remove: indices [%1 - %2] out of range [0 - %3]").arg(index).arg(index+n).arg(count()); + qmlWarning(this) << tr("remove: indices [%1 - %2] out of range [0 - %3]").arg(index).arg(index+n).arg(count()); return; } d->remove(index, n); diff --git a/src/qml/types/qquickworkerscript.cpp b/src/qml/types/qquickworkerscript.cpp index 5f716da17a..f35e17c34d 100644 --- a/src/qml/types/qquickworkerscript.cpp +++ b/src/qml/types/qquickworkerscript.cpp @@ -185,7 +185,7 @@ public: int m_nextId; - static QV4::ReturnedValue method_sendMessage(QV4::CallContext *ctx); + static void method_sendMessage(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData); signals: void stopThread(); @@ -292,14 +292,13 @@ QQuickWorkerScriptEnginePrivate::QQuickWorkerScriptEnginePrivate(QQmlEngine *eng { } -QV4::ReturnedValue QQuickWorkerScriptEnginePrivate::method_sendMessage(QV4::CallContext *ctx) +void QQuickWorkerScriptEnginePrivate::method_sendMessage(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData) { - WorkerEngine *engine = (WorkerEngine*)ctx->engine()->v8Engine; + WorkerEngine *engine = (WorkerEngine*)scope.engine->v8Engine; - int id = ctx->argc() > 1 ? ctx->args()[1].toInt32() : 0; + int id = callData->argc > 1 ? callData->args[1].toInt32() : 0; - QV4::Scope scope(ctx); - QV4::ScopedValue v(scope, ctx->argument(2)); + QV4::ScopedValue v(scope, callData->argument(2)); QByteArray data = QV4::Serialize::serialize(v, scope.engine); QMutexLocker locker(&engine->p->m_lock); @@ -307,7 +306,7 @@ QV4::ReturnedValue QQuickWorkerScriptEnginePrivate::method_sendMessage(QV4::Call if (script && script->owner) QCoreApplication::postEvent(script->owner, new WorkerDataEvent(0, data)); - return QV4::Encode::undefined(); + scope.result = QV4::Encode::undefined(); } QV4::ReturnedValue QQuickWorkerScriptEnginePrivate::getWorker(WorkerScript *script) |