diff options
Diffstat (limited to 'src/qml/jsruntime')
27 files changed, 169 insertions, 99 deletions
diff --git a/src/qml/jsruntime/qv4arrayobject.cpp b/src/qml/jsruntime/qv4arrayobject.cpp index 6c51b4cbcb..df9f117d04 100644 --- a/src/qml/jsruntime/qv4arrayobject.cpp +++ b/src/qml/jsruntime/qv4arrayobject.cpp @@ -362,7 +362,7 @@ ReturnedValue ArrayPrototype::method_toString(const FunctionObject *builtin, con ScopedString string(scope, scope.engine->newString(QStringLiteral("join"))); ScopedFunctionObject f(scope, that->get(string)); if (f) - return f->call(that, argv, argc); + return checkedResult(scope.engine, f->call(that, argv, argc)); return ObjectPrototype::method_toString(builtin, that, argv, argc); } @@ -1209,6 +1209,7 @@ ReturnedValue ArrayPrototype::method_every(const FunctionObject *b, const Value arguments[1] = Value::fromDouble(k); arguments[2] = instance; r = callback->call(that, arguments, 3); + CHECK_EXCEPTION(); ok = r->toBoolean(); } return Encode(ok); @@ -1276,6 +1277,7 @@ ReturnedValue ArrayPrototype::method_some(const FunctionObject *b, const Value * arguments[1] = Value::fromDouble(k); arguments[2] = instance; result = callback->call(that, arguments, 3); + CHECK_EXCEPTION(); if (result->toBoolean()) return Encode(true); } @@ -1345,6 +1347,7 @@ ReturnedValue ArrayPrototype::method_map(const FunctionObject *b, const Value *t arguments[1] = Value::fromDouble(k); arguments[2] = instance; mapped = callback->call(that, arguments, 3); + CHECK_EXCEPTION(); a->arraySet(k, mapped); } return a.asReturnedValue(); @@ -1380,6 +1383,7 @@ ReturnedValue ArrayPrototype::method_filter(const FunctionObject *b, const Value arguments[1] = Value::fromDouble(k); arguments[2] = instance; selected = callback->call(that, arguments, 3); + CHECK_EXCEPTION(); if (selected->toBoolean()) { a->arraySet(to, arguments[0]); ++to; @@ -1430,6 +1434,7 @@ ReturnedValue ArrayPrototype::method_reduce(const FunctionObject *b, const Value arguments[2] = Value::fromDouble(k); arguments[3] = instance; acc = callback->call(nullptr, arguments, 4); + CHECK_EXCEPTION(); } ++k; } @@ -1483,6 +1488,7 @@ ReturnedValue ArrayPrototype::method_reduceRight(const FunctionObject *b, const arguments[2] = Value::fromDouble(k - 1); arguments[3] = instance; acc = callback->call(nullptr, arguments, 4); + CHECK_EXCEPTION(); } --k; } diff --git a/src/qml/jsruntime/qv4dateobject.cpp b/src/qml/jsruntime/qv4dateobject.cpp index cc89947cec..bebcbd7e44 100644 --- a/src/qml/jsruntime/qv4dateobject.cpp +++ b/src/qml/jsruntime/qv4dateobject.cpp @@ -682,17 +682,17 @@ static inline QString ToTimeString(double t) static inline QString ToLocaleString(double t) { - return ToDateTime(t, Qt::LocalTime).toString(Qt::DefaultLocaleShortDate); + return QLocale().toString(ToDateTime(t, Qt::LocalTime), QLocale::ShortFormat); } static inline QString ToLocaleDateString(double t) { - return ToDateTime(t, Qt::LocalTime).date().toString(Qt::DefaultLocaleShortDate); + return QLocale().toString(ToDateTime(t, Qt::LocalTime).date(), QLocale::ShortFormat); } static inline QString ToLocaleTimeString(double t) { - return ToDateTime(t, Qt::LocalTime).time().toString(Qt::DefaultLocaleShortDate); + return QLocale().toString(ToDateTime(t, Qt::LocalTime).time(), QLocale::ShortFormat); } static double getLocalTZA() @@ -1561,7 +1561,7 @@ ReturnedValue DatePrototype::method_toJSON(const FunctionObject *b, const Value if (!toIso) return v4->throwTypeError(); - return toIso->call(O, nullptr, 0); + return checkedResult(v4, toIso->call(O, nullptr, 0)); } ReturnedValue DatePrototype::method_symbolToPrimitive(const FunctionObject *f, const Value *thisObject, const Value *argv, int argc) diff --git a/src/qml/jsruntime/qv4engine.cpp b/src/qml/jsruntime/qv4engine.cpp index 86e178d568..1efe09c59f 100644 --- a/src/qml/jsruntime/qv4engine.cpp +++ b/src/qml/jsruntime/qv4engine.cpp @@ -1266,20 +1266,15 @@ QUrl ExecutionEngine::resolvedUrl(const QString &file) void ExecutionEngine::markObjects(MarkStack *markStack) { - for (int i = 0; i < NClasses; ++i) - if (classes[i]) { - classes[i]->mark(markStack); - if (markStack->top >= markStack->limit) - markStack->drain(); - } - markStack->drain(); + for (int i = 0; i < NClasses; ++i) { + if (Heap::InternalClass *c = classes[i]) + c->mark(markStack); + } identifierTable->markObjects(markStack); - for (auto compilationUnit: compilationUnits) { + for (auto compilationUnit: compilationUnits) compilationUnit->markObjects(markStack); - markStack->drain(); - } } ReturnedValue ExecutionEngine::throwError(const Value &value) @@ -1512,12 +1507,41 @@ static QVariant toVariant(QV4::ExecutionEngine *e, const QV4::Value &value, int return QVariant::fromValue(QV4::JsonObject::toJsonArray(a)); } + QVariant retn; #if QT_CONFIG(qml_sequence_object) bool succeeded = false; - QVariant retn = QV4::SequencePrototype::toVariant(value, typeHint, &succeeded); + retn = QV4::SequencePrototype::toVariant(value, typeHint, &succeeded); if (succeeded) return retn; #endif + if (typeHint != -1) { + // the QVariant constructor will create a copy, so we have manually + // destroy the value returned by QMetaType::create + auto temp = QMetaType::create(typeHint); + retn = QVariant(typeHint, temp); + QMetaType::destroy(typeHint, temp); + auto retnAsIterable = retn.value<QtMetaTypePrivate::QSequentialIterableImpl>(); + if (retnAsIterable._iteratorCapabilities & QtMetaTypePrivate::ContainerIsAppendable) { + auto const length = a->getLength(); + QV4::ScopedValue arrayValue(scope); + for (qint64 i = 0; i < length; ++i) { + arrayValue = a->get(i); + QVariant asVariant = toVariant(e, arrayValue, retnAsIterable._metaType_id, false, visitedObjects); + auto originalType = asVariant.userType(); + bool couldConvert = asVariant.convert(retnAsIterable._metaType_id); + if (!couldConvert) { + qWarning() << QLatin1String("Could not convert array value at position %1 from %2 to %3") + .arg(QString::number(i), + QString::fromUtf8(QMetaType::typeName(originalType)), + QString::fromUtf8(QMetaType::typeName(retnAsIterable._metaType_id))); + // create default constructed value + asVariant = QVariant(retnAsIterable._metaType_id, nullptr); + } + retnAsIterable.append(asVariant.constData()); + } + return retn; + } + } } if (value.isUndefined()) @@ -1886,10 +1910,10 @@ QQmlRefPointer<ExecutableCompilationUnit> ExecutionEngine::compileModule( sourceCode, sourceTimeStamp, &diagnostics); for (const QQmlJS::DiagnosticMessage &m : diagnostics) { if (m.isError()) { - throwSyntaxError(m.message, url.toString(), m.line, m.column); + throwSyntaxError(m.message, url.toString(), m.loc.startLine, m.loc.startColumn); return nullptr; } else { - qWarning() << url << ':' << m.line << ':' << m.column + qWarning() << url << ':' << m.loc.startLine << ':' << m.loc.startColumn << ": warning: " << m.message; } } @@ -2331,9 +2355,11 @@ int ExecutionEngine::registerExtension() return registrationData()->extensionCount++; } +#if QT_CONFIG(qml_network) QNetworkAccessManager *QV4::detail::getNetworkAccessManager(ExecutionEngine *engine) { return engine->qmlEngine()->networkAccessManager(); } +#endif // qml_network QT_END_NAMESPACE diff --git a/src/qml/jsruntime/qv4engine_p.h b/src/qml/jsruntime/qv4engine_p.h index e0025feb00..efe44a324c 100644 --- a/src/qml/jsruntime/qv4engine_p.h +++ b/src/qml/jsruntime/qv4engine_p.h @@ -91,6 +91,7 @@ class PageAllocation; QT_BEGIN_NAMESPACE +#if QT_CONFIG(qml_network) class QNetworkAccessManager; namespace QV4 { @@ -99,6 +100,9 @@ namespace detail { QNetworkAccessManager *getNetworkAccessManager(ExecutionEngine *engine); } } +#else +namespace QV4 { struct QObjectMethod; } +#endif // qml_network // Used to allow a QObject method take and return raw V4 handles without having to expose // 48 in the public API. @@ -355,7 +359,9 @@ public: FunctionObject *getStackFunction() const { return reinterpret_cast<FunctionObject *>(jsObjects + GetStack_Function); } FunctionObject *thrower() const { return reinterpret_cast<FunctionObject *>(jsObjects + ThrowerObject); } +#if QT_CONFIG(qml_network) QNetworkAccessManager* (*networkAccessManager)(ExecutionEngine*) = detail::getNetworkAccessManager; +#endif enum JSStrings { String_Empty, diff --git a/src/qml/jsruntime/qv4executablecompilationunit.cpp b/src/qml/jsruntime/qv4executablecompilationunit.cpp index fa4a1f1ce4..962b23fad6 100644 --- a/src/qml/jsruntime/qv4executablecompilationunit.cpp +++ b/src/qml/jsruntime/qv4executablecompilationunit.cpp @@ -817,7 +817,7 @@ QQmlRefPointer<QQmlPropertyCache> ResolvedTypeReference::createPropertyCache(QQm if (typePropertyCache) { return typePropertyCache; } else if (type.isValid()) { - typePropertyCache = QQmlEnginePrivate::get(engine)->cache(type.metaObject(), minorVersion); + typePropertyCache = QQmlEnginePrivate::get(engine)->cache(type.metaObject(), version); return typePropertyCache; } else { Q_ASSERT(compilationUnit); diff --git a/src/qml/jsruntime/qv4executablecompilationunit_p.h b/src/qml/jsruntime/qv4executablecompilationunit_p.h index 8cad18a3dc..a748e0a762 100644 --- a/src/qml/jsruntime/qv4executablecompilationunit_p.h +++ b/src/qml/jsruntime/qv4executablecompilationunit_p.h @@ -182,8 +182,8 @@ public: CompositeMetaTypeIds typeIdsForComponent(int objectid = 0) const; - int metaTypeId = -1; - int listMetaTypeId = -1; + QMetaType metaTypeId; + QMetaType listMetaTypeId; bool isRegisteredWithEngine = false; QHash<int, InlineComponentData> inlineComponentData; @@ -326,17 +326,15 @@ private: struct ResolvedTypeReference { ResolvedTypeReference() - : majorVersion(0) - , minorVersion(0) - , isFullyDynamicType(false) + : version(QTypeRevision::zero()) + , isFullyDynamicType(false) {} QQmlType type; QQmlRefPointer<QQmlPropertyCache> typePropertyCache; QQmlRefPointer<QV4::ExecutableCompilationUnit> compilationUnit; - int majorVersion; - int minorVersion; + QTypeRevision version; // Types such as QQmlPropertyMap can add properties dynamically at run-time and // therefore cannot have a property cache installed when instantiated. bool isFullyDynamicType; diff --git a/src/qml/jsruntime/qv4functionobject.cpp b/src/qml/jsruntime/qv4functionobject.cpp index dfef52583e..cdb3b8942b 100644 --- a/src/qml/jsruntime/qv4functionobject.cpp +++ b/src/qml/jsruntime/qv4functionobject.cpp @@ -358,7 +358,7 @@ ReturnedValue FunctionPrototype::method_apply(const QV4::FunctionObject *b, cons return v4->throwTypeError(); thisObject = argc ? argv : nullptr; if (argc < 2 || argv[1].isNullOrUndefined()) - return f->call(thisObject, argv, 0); + return checkedResult(v4, f->call(thisObject, argv, 0)); Object *arr = argv[1].objectValue(); if (!arr) @@ -398,13 +398,14 @@ ReturnedValue FunctionPrototype::method_apply(const QV4::FunctionObject *b, cons } } - return f->call(thisObject, arguments, len); + return checkedResult(v4, f->call(thisObject, arguments, len)); } ReturnedValue FunctionPrototype::method_call(const QV4::FunctionObject *b, const Value *thisObject, const Value *argv, int argc) { + QV4::ExecutionEngine *v4 = b->engine(); if (!thisObject->isFunctionObject()) - return b->engine()->throwTypeError(); + return v4->throwTypeError(); const FunctionObject *f = static_cast<const FunctionObject *>(thisObject); @@ -413,7 +414,7 @@ ReturnedValue FunctionPrototype::method_call(const QV4::FunctionObject *b, const ++argv; --argc; } - return f->call(thisObject, argv, argc); + return checkedResult(v4, f->call(thisObject, argv, argc)); } ReturnedValue FunctionPrototype::method_bind(const FunctionObject *b, const Value *thisObject, const Value *argv, int argc) @@ -713,12 +714,12 @@ void Heap::BoundFunction::init(QV4::ExecutionContext *scope, QV4::FunctionObject ReturnedValue BoundFunction::virtualCall(const FunctionObject *fo, const Value *, const Value *argv, int argc) { - const BoundFunction *f = static_cast<const BoundFunction *>(fo); - Scope scope(f->engine()); - - if (scope.hasException()) + QV4::ExecutionEngine *v4 = fo->engine(); + if (v4->hasException) return Encode::undefined(); + const BoundFunction *f = static_cast<const BoundFunction *>(fo); + Scope scope(v4); Scoped<MemberData> boundArgs(scope, f->boundArgs()); ScopedFunctionObject target(scope, f->target()); JSCallData jsCallData(scope, (boundArgs ? boundArgs->size() : 0) + argc); @@ -729,7 +730,7 @@ ReturnedValue BoundFunction::virtualCall(const FunctionObject *fo, const Value * argp += boundArgs->size(); } memcpy(argp, argv, argc*sizeof(Value)); - return target->call(jsCallData); + return checkedResult(v4, target->call(jsCallData)); } ReturnedValue BoundFunction::virtualCallAsConstructor(const FunctionObject *fo, const Value *argv, int argc, const Value *) diff --git a/src/qml/jsruntime/qv4functionobject_p.h b/src/qml/jsruntime/qv4functionobject_p.h index c99cad8e33..78be58c60a 100644 --- a/src/qml/jsruntime/qv4functionobject_p.h +++ b/src/qml/jsruntime/qv4functionobject_p.h @@ -328,6 +328,10 @@ inline bool FunctionObject::isBoundFunction() const return d()->vtable() == BoundFunction::staticVTable(); } +inline ReturnedValue checkedResult(QV4::ExecutionEngine *v4, ReturnedValue result) +{ + return v4->hasException ? QV4::Encode::undefined() : result; +} } diff --git a/src/qml/jsruntime/qv4include.cpp b/src/qml/jsruntime/qv4include.cpp index 64ca719e29..92face6f94 100644 --- a/src/qml/jsruntime/qv4include.cpp +++ b/src/qml/jsruntime/qv4include.cpp @@ -163,7 +163,7 @@ void QV4Include::finished() QV4::Scope scope(v4); QV4::ScopedObject resultObj(scope, m_resultObject.value()); QV4::ScopedString status(scope, v4->newString(QStringLiteral("status"))); - if (m_reply->networkError() == QNetworkReply::NoError) { + if (m_reply->error() == QNetworkReply::NoError) { QByteArray data = m_reply->readAll(); QString code = QString::fromUtf8(data); diff --git a/src/qml/jsruntime/qv4jsonobject.cpp b/src/qml/jsruntime/qv4jsonobject.cpp index 936c032fad..ce759111f4 100644 --- a/src/qml/jsruntime/qv4jsonobject.cpp +++ b/src/qml/jsruntime/qv4jsonobject.cpp @@ -703,6 +703,8 @@ QString Stringify::Str(const QString &key, const Value &v) *jsCallData->thisObject = value; jsCallData->args[0] = v4->newString(key); value = toJSON->call(jsCallData); + if (v4->hasException) + return QString(); } } @@ -714,6 +716,8 @@ QString Stringify::Str(const QString &key, const Value &v) jsCallData->args[1] = value; *jsCallData->thisObject = holder; value = replacerFunction->call(jsCallData); + if (v4->hasException) + return QString(); } o = value->asReturnedValue(); diff --git a/src/qml/jsruntime/qv4lookup.cpp b/src/qml/jsruntime/qv4lookup.cpp index 0cda6b864a..d3ea50867a 100644 --- a/src/qml/jsruntime/qv4lookup.cpp +++ b/src/qml/jsruntime/qv4lookup.cpp @@ -309,7 +309,8 @@ ReturnedValue Lookup::getterAccessor(Lookup *l, ExecutionEngine *engine, const V if (!getter->isFunctionObject()) // ### catch at resolve time return Encode::undefined(); - return static_cast<const FunctionObject *>(getter)->call(&object, nullptr, 0); + return checkedResult(engine, static_cast<const FunctionObject *>(getter)->call( + &object, nullptr, 0)); } } l->getter = getterFallback; @@ -326,7 +327,8 @@ ReturnedValue Lookup::getterProtoAccessor(Lookup *l, ExecutionEngine *engine, co if (!getter->isFunctionObject()) // ### catch at resolve time return Encode::undefined(); - return static_cast<const FunctionObject *>(getter)->call(&object, nullptr, 0); + return checkedResult(engine, static_cast<const FunctionObject *>(getter)->call( + &object, nullptr, 0)); } return getterTwoClasses(l, engine, object); } @@ -346,7 +348,8 @@ ReturnedValue Lookup::getterProtoAccessorTwoClasses(Lookup *l, ExecutionEngine * if (!getter->isFunctionObject()) // ### catch at resolve time return Encode::undefined(); - return static_cast<const FunctionObject *>(getter)->call(&object, nullptr, 0); + return checkedResult(engine, static_cast<const FunctionObject *>(getter)->call( + &object, nullptr, 0)); } } l->getter = getterFallback; @@ -391,7 +394,8 @@ ReturnedValue Lookup::primitiveGetterAccessor(Lookup *l, ExecutionEngine *engine if (!getter->isFunctionObject()) // ### catch at resolve time return Encode::undefined(); - return static_cast<const FunctionObject *>(getter)->call(&object, nullptr, 0); + return checkedResult(engine, static_cast<const FunctionObject *>(getter)->call( + &object, nullptr, 0)); } } l->getter = getterGeneric; @@ -429,7 +433,8 @@ ReturnedValue Lookup::globalGetterProtoAccessor(Lookup *l, ExecutionEngine *engi if (!getter->isFunctionObject()) // ### catch at resolve time return Encode::undefined(); - return static_cast<const FunctionObject *>(getter)->call(engine->globalObject, nullptr, 0); + return checkedResult(engine, static_cast<const FunctionObject *>(getter)->call( + engine->globalObject, nullptr, 0)); } l->globalGetter = globalGetterGeneric; return globalGetterGeneric(l, engine); diff --git a/src/qml/jsruntime/qv4object.cpp b/src/qml/jsruntime/qv4object.cpp index 89161433ed..b723141caa 100644 --- a/src/qml/jsruntime/qv4object.cpp +++ b/src/qml/jsruntime/qv4object.cpp @@ -105,7 +105,7 @@ ReturnedValue Object::getValueAccessor(const Value *thisObject, const Value &v, JSCallData jsCallData(scope); if (thisObject) *jsCallData->thisObject = *thisObject; - return f->call(jsCallData); + return checkedResult(scope.engine, f->call(jsCallData)); } bool Object::putValue(uint memberIndex, PropertyAttributes attrs, const Value &value) diff --git a/src/qml/jsruntime/qv4objectproto.cpp b/src/qml/jsruntime/qv4objectproto.cpp index 7d910a1cbc..0c8cc192fc 100644 --- a/src/qml/jsruntime/qv4objectproto.cpp +++ b/src/qml/jsruntime/qv4objectproto.cpp @@ -667,7 +667,7 @@ ReturnedValue ObjectPrototype::method_toLocaleString(const FunctionObject *b, co if (!f) THROW_TYPE_ERROR(); - return f->call(thisObject, argv, argc); + return checkedResult(scope.engine, f->call(thisObject, argv, argc)); } ReturnedValue ObjectPrototype::method_valueOf(const FunctionObject *b, const Value *thisObject, const Value *, int) diff --git a/src/qml/jsruntime/qv4persistent.cpp b/src/qml/jsruntime/qv4persistent.cpp index 79c372348f..f4901e3e4d 100644 --- a/src/qml/jsruntime/qv4persistent.cpp +++ b/src/qml/jsruntime/qv4persistent.cpp @@ -240,7 +240,6 @@ void PersistentValueStorage::mark(MarkStack *markStack) if (Managed *m = p->values[i].as<Managed>()) m->mark(markStack); } - markStack->drain(); p = p->header.next; } diff --git a/src/qml/jsruntime/qv4promiseobject.cpp b/src/qml/jsruntime/qv4promiseobject.cpp index 17d218a6eb..ecaff72b22 100644 --- a/src/qml/jsruntime/qv4promiseobject.cpp +++ b/src/qml/jsruntime/qv4promiseobject.cpp @@ -618,7 +618,7 @@ ReturnedValue PromiseCtor::method_all(const FunctionObject *f, const Value *this } ScopedObject nextPromise(scope, Value::fromReturnedValue(resolve->call(thisObject, nextValue, 1))); - if (!nextPromise || scope.hasException()) { + if (scope.hasException() || !nextPromise) { ScopedValue completion(scope, Runtime::IteratorClose::call(e, iteratorObject, doneValue)); if (scope.hasException()) { completion = e->exceptionValue->asReturnedValue(); @@ -764,7 +764,7 @@ ReturnedValue PromiseCtor::method_race(const FunctionObject *f, const Value *thi } ScopedObject nextPromise(scope, Value::fromReturnedValue(resolve->call(thisObject, nextValue, 1))); - if (!nextPromise || scope.hasException()) { + if (scope.hasException() || !nextPromise) { ScopedValue completion(scope, Runtime::IteratorClose::call(e, iteratorObject, doneValue)); if (scope.hasException()) { completion = e->exceptionValue->asReturnedValue(); diff --git a/src/qml/jsruntime/qv4proxy.cpp b/src/qml/jsruntime/qv4proxy.cpp index 51f96b9003..24676ffd00 100644 --- a/src/qml/jsruntime/qv4proxy.cpp +++ b/src/qml/jsruntime/qv4proxy.cpp @@ -96,6 +96,8 @@ ReturnedValue ProxyObject::virtualGet(const Managed *m, PropertyKey id, const Va cdata.args[2] = *receiver; ScopedValue trapResult(scope, static_cast<const FunctionObject *>(trap.ptr)->call(cdata)); + if (scope.engine->hasException) + return Encode::undefined(); ScopedProperty targetDesc(scope); PropertyAttributes attributes = target->getOwnProperty(id, targetDesc); if (attributes != Attr_Invalid && !attributes.isConfigurable()) { @@ -136,7 +138,7 @@ bool ProxyObject::virtualPut(Managed *m, PropertyKey id, const Value &value, Val cdata.args[3] = *receiver; ScopedValue trapResult(scope, static_cast<const FunctionObject *>(trap.ptr)->call(cdata)); - if (!trapResult->toBoolean()) + if (scope.engine->hasException || !trapResult->toBoolean()) return false; ScopedProperty targetDesc(scope); PropertyAttributes attributes = target->getOwnProperty(id, targetDesc); @@ -176,7 +178,7 @@ bool ProxyObject::virtualDeleteProperty(Managed *m, PropertyKey id) cdata.args[2] = o->d(); // ### fix receiver handling ScopedValue trapResult(scope, static_cast<const FunctionObject *>(trap.ptr)->call(cdata)); - if (!trapResult->toBoolean()) + if (scope.engine->hasException || !trapResult->toBoolean()) return false; ScopedProperty targetDesc(scope); PropertyAttributes attributes = target->getOwnProperty(id, targetDesc); @@ -211,6 +213,8 @@ bool ProxyObject::virtualHasProperty(const Managed *m, PropertyKey id) cdata.args[1] = id.isArrayIndex() ? Value::fromUInt32(id.asArrayIndex()).toString(scope.engine) : id.asStringOrSymbol(); ScopedValue trapResult(scope, static_cast<const FunctionObject *>(trap.ptr)->call(cdata)); + if (scope.engine->hasException) + return false; bool result = trapResult->toBoolean(); if (!result) { ScopedProperty targetDesc(scope); @@ -251,6 +255,8 @@ PropertyAttributes ProxyObject::virtualGetOwnProperty(const Managed *m, Property cdata.args[1] = id.isArrayIndex() ? Value::fromUInt32(id.asArrayIndex()).toString(scope.engine) : id.asStringOrSymbol(); ScopedValue trapResult(scope, static_cast<const FunctionObject *>(trap.ptr)->call(cdata)); + if (scope.engine->hasException) + return Attr_Invalid; if (!trapResult->isObject() && !trapResult->isUndefined()) { scope.engine->throwTypeError(); return Attr_Invalid; @@ -323,7 +329,7 @@ bool ProxyObject::virtualDefineOwnProperty(Managed *m, PropertyKey id, const Pro cdata.args[2] = ObjectPrototype::fromPropertyDescriptor(scope.engine, p, attrs); ScopedValue trapResult(scope, static_cast<const FunctionObject *>(trap.ptr)->call(cdata)); - bool result = trapResult->toBoolean(); + bool result = !scope.engine->hasException && trapResult->toBoolean(); if (!result) return false; @@ -373,6 +379,8 @@ bool ProxyObject::virtualIsExtensible(const Managed *m) cdata.args[0] = target; ScopedValue trapResult(scope, static_cast<const FunctionObject *>(trap.ptr)->call(cdata)); + if (scope.engine->hasException) + return false; bool result = trapResult->toBoolean(); if (result != target->isExtensible()) { scope.engine->throwTypeError(); @@ -404,6 +412,8 @@ bool ProxyObject::virtualPreventExtensions(Managed *m) cdata.args[0] = target; ScopedValue trapResult(scope, static_cast<const FunctionObject *>(trap.ptr)->call(cdata)); + if (scope.engine->hasException) + return false; bool result = trapResult->toBoolean(); if (result && target->isExtensible()) { scope.engine->throwTypeError(); @@ -439,6 +449,8 @@ Heap::Object *ProxyObject::virtualGetPrototypeOf(const Managed *m) cdata.args[0] = target; ScopedValue trapResult(scope, static_cast<const FunctionObject *>(trap.ptr)->call(cdata)); + if (scope.engine->hasException) + return nullptr; if (!trapResult->isNull() && !trapResult->isObject()) { scope.engine->throwTypeError(); return nullptr; @@ -482,7 +494,7 @@ bool ProxyObject::virtualSetPrototypeOf(Managed *m, const Object *p) cdata.args[1] = p ? p->asReturnedValue() : Encode::null(); ScopedValue trapResult(scope, static_cast<const FunctionObject *>(trap.ptr)->call(cdata)); - bool result = trapResult->toBoolean(); + bool result = !scope.engine->hasException && trapResult->toBoolean(); if (!result) return false; if (!target->isExtensible()) { @@ -573,6 +585,8 @@ OwnPropertyKeyIterator *ProxyObject::virtualOwnPropertyKeys(const Object *m, Val JSCallData cdata(scope, 1, nullptr, handler); cdata.args[0] = target; ScopedObject trapResult(scope, static_cast<const FunctionObject *>(trap.ptr)->call(cdata)); + if (scope.engine->hasException) + return nullptr; if (!trapResult) { scope.engine->throwTypeError(); return nullptr; @@ -699,7 +713,7 @@ ReturnedValue ProxyFunctionObject::virtualCall(const FunctionObject *f, const Va if (scope.hasException()) return Encode::undefined(); if (trap->isNullOrUndefined()) - return target->call(thisObject, argv, argc); + return checkedResult(scope.engine, target->call(thisObject, argv, argc)); if (!trap->isFunctionObject()) return scope.engine->throwTypeError(); diff --git a/src/qml/jsruntime/qv4qobjectwrapper.cpp b/src/qml/jsruntime/qv4qobjectwrapper.cpp index 9613d064c4..66b79aa0e8 100644 --- a/src/qml/jsruntime/qv4qobjectwrapper.cpp +++ b/src/qml/jsruntime/qv4qobjectwrapper.cpp @@ -638,10 +638,11 @@ void QObjectWrapper::markWrapper(QObject *object, MarkStack *markStack) if (!ddata) return; - if (ddata->jsEngineId == markStack->engine->m_engineId) + const QV4::ExecutionEngine *engine = markStack->engine(); + if (ddata->jsEngineId == engine->m_engineId) ddata->jsWrapper.markOnce(markStack); - else if (markStack->engine->m_multiplyWrappedQObjects && ddata->hasTaintedV4Object) - markStack->engine->m_multiplyWrappedQObjects->mark(object, markStack); + else if (engine->m_multiplyWrappedQObjects && ddata->hasTaintedV4Object) + engine->m_multiplyWrappedQObjects->mark(object, markStack); } void QObjectWrapper::setProperty(ExecutionEngine *engine, int propertyIndex, const Value &value) diff --git a/src/qml/jsruntime/qv4reflect.cpp b/src/qml/jsruntime/qv4reflect.cpp index 0772770d63..2a6c61f044 100644 --- a/src/qml/jsruntime/qv4reflect.cpp +++ b/src/qml/jsruntime/qv4reflect.cpp @@ -98,7 +98,8 @@ ReturnedValue Reflect::method_apply(const FunctionObject *f, const Value *, cons if (scope.hasException()) return Encode::undefined(); - return static_cast<const FunctionObject &>(argv[0]).call(&argv[1], arguments.argv, arguments.argc); + return checkedResult(scope.engine, static_cast<const FunctionObject &>(argv[0]).call( + &argv[1], arguments.argv, arguments.argc)); } ReturnedValue Reflect::method_construct(const FunctionObject *f, const Value *, const Value *argv, int argc) diff --git a/src/qml/jsruntime/qv4regexpobject.cpp b/src/qml/jsruntime/qv4regexpobject.cpp index f1375e4ca4..a8a37cda37 100644 --- a/src/qml/jsruntime/qv4regexpobject.cpp +++ b/src/qml/jsruntime/qv4regexpobject.cpp @@ -481,6 +481,8 @@ ReturnedValue RegExpPrototype::exec(ExecutionEngine *engine, const Object *o, co ScopedFunctionObject exec(scope, o->get(key)); if (exec) { ScopedValue result(scope, exec->call(o, s, 1)); + if (scope.hasException()) + RETURN_UNDEFINED(); if (!result->isNull() && !result->isObject()) return scope.engine->throwTypeError(); return result->asReturnedValue(); @@ -737,6 +739,8 @@ ReturnedValue RegExpPrototype::method_replace(const FunctionObject *f, const Val cData->args[nCaptures + 1] = Encode(position); cData->args[nCaptures + 2] = s; ScopedValue replValue(scope, replaceFunction->call(cData)); + if (scope.hasException()) + return Encode::undefined(); replacement = replValue->toQString(); } else { replacement = RegExp::getSubstitution(matchString->toQString(), s->toQString(), position, cData.args, nCaptures, replaceValue->toQString()); diff --git a/src/qml/jsruntime/qv4runtime.cpp b/src/qml/jsruntime/qv4runtime.cpp index e47a7a0b46..5fc94b9ddd 100644 --- a/src/qml/jsruntime/qv4runtime.cpp +++ b/src/qml/jsruntime/qv4runtime.cpp @@ -390,7 +390,7 @@ QV4::ReturnedValue Runtime::Instanceof::call(ExecutionEngine *engine, const Valu return engine->throwTypeError(); ScopedValue result(scope, fHasInstance->call(&rval, &lval, 1)); - return Encode(result->toBoolean()); + return scope.hasException() ? Encode::undefined() : Encode(result->toBoolean()); } QV4::ReturnedValue Runtime::In::call(ExecutionEngine *engine, const Value &left, const Value &right) @@ -515,6 +515,8 @@ ReturnedValue RuntimeHelpers::ordinaryToPrimitive(ExecutionEngine *engine, const ScopedValue conv(scope, object->get(meth1)); if (FunctionObject *o = conv->as<FunctionObject>()) { result = o->call(object, nullptr, 0); + if (engine->hasException) + return Encode::undefined(); if (result->isPrimitive()) return result->asReturnedValue(); } @@ -525,6 +527,8 @@ ReturnedValue RuntimeHelpers::ordinaryToPrimitive(ExecutionEngine *engine, const conv = object->get(meth2); if (FunctionObject *o = conv->as<FunctionObject>()) { result = o->call(object, nullptr, 0); + if (engine->hasException) + return Encode::undefined(); if (result->isPrimitive()) return result->asReturnedValue(); } @@ -800,6 +804,8 @@ ReturnedValue Runtime::GetIterator::call(ExecutionEngine *engine, const Value &i return engine->throwTypeError(); JSCallData cData(scope, 0, nullptr, o); ScopedObject it(scope, f->call(cData)); + if (engine->hasException) + return Encode::undefined(); if (!it) return engine->throwTypeError(); return it->asReturnedValue(); @@ -1341,7 +1347,8 @@ ReturnedValue Runtime::CallGlobalLookup::call(ExecutionEngine *engine, uint inde engine->currentStackFrame->v4Function->compilationUnit->runtimeStrings[l->nameIndex]->toQString()); } - return static_cast<FunctionObject &>(function).call(&thisObject, argv, argc); + return checkedResult(engine, static_cast<FunctionObject &>(function).call( + &thisObject, argv, argc)); } ReturnedValue Runtime::CallQmlContextPropertyLookup::call(ExecutionEngine *engine, uint index, @@ -1356,7 +1363,8 @@ ReturnedValue Runtime::CallQmlContextPropertyLookup::call(ExecutionEngine *engin engine->currentStackFrame->v4Function->compilationUnit->runtimeStrings[l->nameIndex]->toQString()); } - return static_cast<FunctionObject &>(function).call(thisObject, argv, argc); + return checkedResult(engine, static_cast<FunctionObject &>(function).call( + thisObject, argv, argc)); } ReturnedValue Runtime::CallPossiblyDirectEval::call(ExecutionEngine *engine, Value *argv, int argc) @@ -1375,7 +1383,7 @@ ReturnedValue Runtime::CallPossiblyDirectEval::call(ExecutionEngine *engine, Val if (function->d() == engine->evalFunction()->d()) return static_cast<EvalFunction *>(function.getPointer())->evalCall(thisObject, argv, argc, true); - return function->call(thisObject, argv, argc); + return checkedResult(engine, function->call(thisObject, argv, argc)); } ReturnedValue Runtime::CallName::call(ExecutionEngine *engine, int nameIndex, Value *argv, int argc) @@ -1395,7 +1403,7 @@ ReturnedValue Runtime::CallName::call(ExecutionEngine *engine, int nameIndex, Va ->runtimeStrings[nameIndex]->toQString()); } - return f->call(thisObject, argv, argc); + return checkedResult(engine, f->call(thisObject, argv, argc)); } ReturnedValue Runtime::CallProperty::call(ExecutionEngine *engine, const Value &baseRef, int nameIndex, Value *argv, int argc) @@ -1437,7 +1445,7 @@ ReturnedValue Runtime::CallProperty::call(ExecutionEngine *engine, const Value & return engine->throwTypeError(error); } - return f->call(base, argv, argc); + return checkedResult(engine, f->call(base, argv, argc)); } ReturnedValue Runtime::CallPropertyLookup::call(ExecutionEngine *engine, const Value &base, uint index, Value *argv, int argc) @@ -1449,7 +1457,7 @@ ReturnedValue Runtime::CallPropertyLookup::call(ExecutionEngine *engine, const V if (!f.isFunctionObject()) return engine->throwTypeError(); - return static_cast<FunctionObject &>(f).call(&base, argv, argc); + return checkedResult(engine, static_cast<FunctionObject &>(f).call(&base, argv, argc)); } ReturnedValue Runtime::CallElement::call(ExecutionEngine *engine, const Value &baseRef, const Value &index, Value *argv, int argc) @@ -1467,7 +1475,7 @@ ReturnedValue Runtime::CallElement::call(ExecutionEngine *engine, const Value &b if (!f) return engine->throwTypeError(); - return f->call(base, argv, argc); + return checkedResult(engine, f->call(base, argv, argc)); } ReturnedValue Runtime::CallValue::call(ExecutionEngine *engine, const Value &func, Value *argv, int argc) @@ -1475,7 +1483,8 @@ ReturnedValue Runtime::CallValue::call(ExecutionEngine *engine, const Value &fun if (!func.isFunctionObject()) return engine->throwTypeError(QStringLiteral("%1 is not a function").arg(func.toQStringNoThrow())); Value undef = Value::undefinedValue(); - return static_cast<const FunctionObject &>(func).call(&undef, argv, argc); + return checkedResult(engine, static_cast<const FunctionObject &>(func).call( + &undef, argv, argc)); } ReturnedValue Runtime::CallWithReceiver::call(ExecutionEngine *engine, const Value &func, @@ -1483,7 +1492,8 @@ ReturnedValue Runtime::CallWithReceiver::call(ExecutionEngine *engine, const Val { if (!func.isFunctionObject()) return engine->throwTypeError(QStringLiteral("%1 is not a function").arg(func.toQStringNoThrow())); - return static_cast<const FunctionObject &>(func).call(&thisObject, argv, argc); + return checkedResult(engine, static_cast<const FunctionObject &>(func).call( + &thisObject, argv, argc)); } struct CallArgs { @@ -1537,7 +1547,8 @@ ReturnedValue Runtime::CallWithSpread::call(ExecutionEngine *engine, const Value if (engine->hasException) return Encode::undefined(); - return static_cast<const FunctionObject &>(function).call(&thisObject, arguments.argv, arguments.argc); + return checkedResult(engine, static_cast<const FunctionObject &>(function).call( + &thisObject, arguments.argv, arguments.argc)); } ReturnedValue Runtime::Construct::call(ExecutionEngine *engine, const Value &function, const Value &newTarget, Value *argv, int argc) @@ -1580,7 +1591,7 @@ ReturnedValue Runtime::TailCall::call(CppStackFrame *frame, ExecutionEngine *eng if (!frame->callerCanHandleTailCall || !fo.canBeTailCalled() || engine->debugger() || unsigned(argc) > fo.formalParameterCount()) { // Cannot tailcall, do a normal call: - return fo.call(&thisObject, argv, argc); + return checkedResult(engine, fo.call(&thisObject, argv, argc)); } memcpy(frame->jsFrame->args, argv, argc * sizeof(Value)); diff --git a/src/qml/jsruntime/qv4runtimecodegen.cpp b/src/qml/jsruntime/qv4runtimecodegen.cpp index 162d75db63..b7737982b7 100644 --- a/src/qml/jsruntime/qv4runtimecodegen.cpp +++ b/src/qml/jsruntime/qv4runtimecodegen.cpp @@ -67,7 +67,7 @@ void RuntimeCodegen::generateFromFunctionExpression(const QString &fileName, _module->rootContext = _module->functions.at(index); } -void RuntimeCodegen::throwSyntaxError(const AST::SourceLocation &loc, const QString &detail) +void RuntimeCodegen::throwSyntaxError(const SourceLocation &loc, const QString &detail) { if (hasError()) return; @@ -76,7 +76,7 @@ void RuntimeCodegen::throwSyntaxError(const AST::SourceLocation &loc, const QStr engine->throwSyntaxError(detail, _module->fileName, loc.startLine, loc.startColumn); } -void RuntimeCodegen::throwReferenceError(const AST::SourceLocation &loc, const QString &detail) +void RuntimeCodegen::throwReferenceError(const SourceLocation &loc, const QString &detail) { if (hasError()) return; diff --git a/src/qml/jsruntime/qv4runtimecodegen_p.h b/src/qml/jsruntime/qv4runtimecodegen_p.h index 71aaf1fb55..d3a30ce35d 100644 --- a/src/qml/jsruntime/qv4runtimecodegen_p.h +++ b/src/qml/jsruntime/qv4runtimecodegen_p.h @@ -69,8 +69,8 @@ public: QQmlJS::AST::FunctionExpression *ast, Compiler::Module *module); - void throwSyntaxError(const QQmlJS::AST::SourceLocation &loc, const QString &detail) override; - void throwReferenceError(const QQmlJS::AST::SourceLocation &loc, const QString &detail) override; + void throwSyntaxError(const QQmlJS::SourceLocation &loc, const QString &detail) override; + void throwReferenceError(const QQmlJS::SourceLocation &loc, const QString &detail) override; private: ExecutionEngine *engine; diff --git a/src/qml/jsruntime/qv4script.cpp b/src/qml/jsruntime/qv4script.cpp index 2fab9e4b7b..2add1222ea 100644 --- a/src/qml/jsruntime/qv4script.cpp +++ b/src/qml/jsruntime/qv4script.cpp @@ -52,6 +52,7 @@ #include <private/qqmljsparser_p.h> #include <private/qqmljsast_p.h> #include <private/qqmlengine_p.h> +#include <private/qqmlsourcecoordinate_p.h> #include <private/qv4profiling_p.h> #include <qv4runtimecodegen_p.h> @@ -109,10 +110,10 @@ void Script::parse() const auto diagnosticMessages = parser.diagnosticMessages(); for (const DiagnosticMessage &m : diagnosticMessages) { if (m.isError()) { - valueScope.engine->throwSyntaxError(m.message, sourceFile, m.line, m.column); + valueScope.engine->throwSyntaxError(m.message, sourceFile, m.loc.startLine, m.loc.startColumn); return; } else { - qWarning() << sourceFile << ':' << m.line << ':' << m.column + qWarning() << sourceFile << ':' << m.loc.startLine << ':' << m.loc.startColumn << ": warning: " << m.message; } } @@ -209,8 +210,8 @@ QV4::CompiledData::CompilationUnit Script::precompile( const auto v4Error = cg.error(); QQmlError error; error.setUrl(cg.url()); - error.setLine(v4Error.line); - error.setColumn(v4Error.column); + error.setLine(qmlConvertSourceCoordinate<quint32, int>(v4Error.loc.startLine)); + error.setColumn(qmlConvertSourceCoordinate<quint32, int>(v4Error.loc.startColumn)); error.setDescription(v4Error.message); reportedErrors->append(error); } diff --git a/src/qml/jsruntime/qv4stringobject.cpp b/src/qml/jsruntime/qv4stringobject.cpp index 9b4a2d575e..209a1b4e76 100644 --- a/src/qml/jsruntime/qv4stringobject.cpp +++ b/src/qml/jsruntime/qv4stringobject.cpp @@ -591,7 +591,7 @@ ReturnedValue StringPrototype::method_match(const FunctionObject *b, const Value ScopedFunctionObject match(scope, that->get(scope.engine->symbol_match())); if (!match) return scope.engine->throwTypeError(); - return match->call(that, s, 1); + return checkedResult(scope.engine, match->call(that, s, 1)); } ReturnedValue StringPrototype::method_normalize(const FunctionObject *f, const Value *thisObject, const Value *argv, int argc) diff --git a/src/qml/jsruntime/qv4typedarray.cpp b/src/qml/jsruntime/qv4typedarray.cpp index 40a434d301..f425c6c87f 100644 --- a/src/qml/jsruntime/qv4typedarray.cpp +++ b/src/qml/jsruntime/qv4typedarray.cpp @@ -763,6 +763,7 @@ ReturnedValue IntrinsicTypedArrayPrototype::method_every(const FunctionObject *b arguments[1] = Value::fromDouble(k); arguments[2] = v; r = callback->call(that, arguments, 3); + CHECK_EXCEPTION(); ok = r->toBoolean(); } return Encode(ok); @@ -862,6 +863,7 @@ ReturnedValue IntrinsicTypedArrayPrototype::method_filter(const FunctionObject * arguments[1] = Value::fromDouble(k); arguments[2] = instance; selected = callback->call(that, arguments, 3); + CHECK_EXCEPTION(); if (selected->toBoolean()) { ++arguments; scope.alloc(1); @@ -1194,6 +1196,7 @@ ReturnedValue IntrinsicTypedArrayPrototype::method_map(const FunctionObject *b, arguments[1] = Value::fromDouble(k); arguments[2] = instance; mapped = callback->call(that, arguments, 3); + CHECK_EXCEPTION(); a->put(k, mapped); } return a->asReturnedValue(); @@ -1243,6 +1246,7 @@ ReturnedValue IntrinsicTypedArrayPrototype::method_reduce(const FunctionObject * arguments[2] = Value::fromDouble(k); arguments[3] = instance; acc = callback->call(nullptr, arguments, 4); + CHECK_EXCEPTION(); } ++k; } @@ -1298,6 +1302,7 @@ ReturnedValue IntrinsicTypedArrayPrototype::method_reduceRight(const FunctionObj arguments[2] = Value::fromDouble(k - 1); arguments[3] = instance; acc = callback->call(nullptr, arguments, 4); + CHECK_EXCEPTION(); } --k; } @@ -1359,6 +1364,7 @@ ReturnedValue IntrinsicTypedArrayPrototype::method_some(const FunctionObject *b, arguments[1] = Value::fromDouble(k); arguments[2] = instance; result = callback->call(that, arguments, 3); + CHECK_EXCEPTION(); if (result->toBoolean()) return Encode(true); } diff --git a/src/qml/jsruntime/qv4value.cpp b/src/qml/jsruntime/qv4value.cpp index d29b060b9e..3449603a8a 100644 --- a/src/qml/jsruntime/qv4value.cpp +++ b/src/qml/jsruntime/qv4value.cpp @@ -250,6 +250,8 @@ bool Value::sameValue(Value other) const { if (isDouble() && other.isInteger()) return other.int_32() ? (doubleValue() == double(other.int_32())) : (doubleValue() == 0 && !std::signbit(doubleValue())); + if (isManaged()) + return other.isManaged() && cast<Managed>()->isEqualTo(other.cast<Managed>()); return false; } @@ -269,6 +271,8 @@ bool Value::sameValueZero(Value other) const { return true; } } + if (isManaged()) + return other.isManaged() && cast<Managed>()->isEqualTo(other.cast<Managed>()); return false; } diff --git a/src/qml/jsruntime/qv4value_p.h b/src/qml/jsruntime/qv4value_p.h index ae12033eb4..42e97b1d36 100644 --- a/src/qml/jsruntime/qv4value_p.h +++ b/src/qml/jsruntime/qv4value_p.h @@ -537,29 +537,8 @@ struct ValueArray { } void mark(MarkStack *markStack) { - Value *v = values; - const Value *end = v + alloc; - if (alloc > 32*1024) { - // drain from time to time to avoid overflows in the js stack - Value::HeapBasePtr *currentBase = markStack->top; - while (v < end) { - v->mark(markStack); - ++v; - if (markStack->top >= currentBase + 32*1024) { - Value::HeapBasePtr *oldBase = markStack->base; - markStack->base = currentBase; - markStack->drain(); - markStack->base = oldBase; - } - } - } else { - while (v < end) { - v->mark(markStack); - if (markStack->top >= markStack->limit) - markStack->drain(); - ++v; - } - } + for (Value *v = values, *end = values + alloc; v < end; ++v) + v->mark(markStack); } }; |