diff options
Diffstat (limited to 'src/qml/jsruntime')
52 files changed, 1641 insertions, 1706 deletions
diff --git a/src/qml/jsruntime/jsruntime.pri b/src/qml/jsruntime/jsruntime.pri index a24ee0a188..e6f1079aa7 100644 --- a/src/qml/jsruntime/jsruntime.pri +++ b/src/qml/jsruntime/jsruntime.pri @@ -3,6 +3,7 @@ INCLUDEPATH += $$OUT_PWD !qmldevtools_build { SOURCES += \ + $$PWD/qv4engine.cpp \ $$PWD/qv4context.cpp \ $$PWD/qv4persistent.cpp \ $$PWD/qv4lookup.cpp \ @@ -36,13 +37,13 @@ SOURCES += \ $$PWD/qv4reflect.cpp \ $$PWD/qv4regexpobject.cpp \ $$PWD/qv4stackframe.cpp \ + $$PWD/qv4string.cpp \ $$PWD/qv4stringiterator.cpp \ $$PWD/qv4stringobject.cpp \ $$PWD/qv4variantobject.cpp \ $$PWD/qv4objectiterator.cpp \ $$PWD/qv4regexp.cpp \ $$PWD/qv4runtimecodegen.cpp \ - $$PWD/qv4serialize.cpp \ $$PWD/qv4script.cpp \ $$PWD/qv4symbol.cpp \ $$PWD/qv4setobject.cpp \ @@ -103,13 +104,13 @@ HEADERS += \ $$PWD/qv4regexpobject_p.h \ $$PWD/qv4runtimecodegen_p.h \ $$PWD/qv4stackframe_p.h \ + $$PWD/qv4string_p.h \ $$PWD/qv4stringiterator_p.h \ $$PWD/qv4stringobject_p.h \ $$PWD/qv4variantobject_p.h \ $$PWD/qv4property_p.h \ $$PWD/qv4objectiterator_p.h \ $$PWD/qv4regexp_p.h \ - $$PWD/qv4serialize_p.h \ $$PWD/qv4script_p.h \ $$PWD/qv4symbol_p.h \ $$PWD/qv4setobject_p.h \ @@ -142,18 +143,17 @@ qtConfig(qml-sequence-object) { HEADERS += \ + $$PWD/qv4calldata_p.h \ $$PWD/qv4runtime_p.h \ $$PWD/qv4runtimeapi_p.h \ $$PWD/qv4value_p.h \ - $$PWD/qv4string_p.h \ + $$PWD/qv4stringtoarrayindex_p.h \ $$PWD/qv4util_p.h \ $$PWD/qv4value_p.h \ $$PWD/qv4functiontable_p.h SOURCES += \ - $$PWD/qv4engine.cpp \ $$PWD/qv4runtime.cpp \ - $$PWD/qv4string.cpp \ $$PWD/qv4value.cpp \ $$PWD/qv4executableallocator.cpp diff --git a/src/qml/jsruntime/qv4argumentsobject.cpp b/src/qml/jsruntime/qv4argumentsobject.cpp index 4a21f62cf2..98e0ef9e70 100644 --- a/src/qml/jsruntime/qv4argumentsobject.cpp +++ b/src/qml/jsruntime/qv4argumentsobject.cpp @@ -116,6 +116,9 @@ bool ArgumentsObject::virtualDefineOwnProperty(Managed *m, PropertyKey id, const { ArgumentsObject *args = static_cast<ArgumentsObject *>(m); args->fullyCreate(); + if (!id.isArrayIndex()) + return Object::virtualDefineOwnProperty(m, id, desc, attrs); + uint index = id.asArrayIndex(); if (!args->isMapped(index)) @@ -148,36 +151,42 @@ bool ArgumentsObject::virtualDefineOwnProperty(Managed *m, PropertyKey id, const ReturnedValue ArgumentsObject::virtualGet(const Managed *m, PropertyKey id, const Value *receiver, bool *hasProperty) { - const ArgumentsObject *args = static_cast<const ArgumentsObject *>(m); - uint index = id.asArrayIndex(); - if (index < args->d()->argCount && !args->d()->fullyCreated) { - if (hasProperty) - *hasProperty = true; - return args->context()->args()[index].asReturnedValue(); + if (id.isArrayIndex()) { + const ArgumentsObject *args = static_cast<const ArgumentsObject *>(m); + uint index = id.asArrayIndex(); + if (index < args->d()->argCount && !args->d()->fullyCreated) { + if (hasProperty) + *hasProperty = true; + return args->context()->args()[index].asReturnedValue(); + } + + if (args->isMapped(index)) { + Q_ASSERT(index < static_cast<uint>(args->context()->function->formalParameterCount())); + if (hasProperty) + *hasProperty = true; + return args->context()->args()[index].asReturnedValue(); + } } - if (!args->isMapped(index)) - return Object::virtualGet(m, id, receiver, hasProperty); - Q_ASSERT(index < static_cast<uint>(args->context()->function->formalParameterCount())); - if (hasProperty) - *hasProperty = true; - return args->context()->args()[index].asReturnedValue(); + return Object::virtualGet(m, id, receiver, hasProperty); } bool ArgumentsObject::virtualPut(Managed *m, PropertyKey id, const Value &value, Value *receiver) { - ArgumentsObject *args = static_cast<ArgumentsObject *>(m); - uint index = id.asArrayIndex(); - - if (args == receiver && index < args->d()->argCount && !args->d()->fullyCreated) { - args->context()->setArg(index, value); - return true; + if (id.isArrayIndex()) { + ArgumentsObject *args = static_cast<ArgumentsObject *>(m); + uint index = id.asArrayIndex(); + + if (args == receiver && index < args->d()->argCount && !args->d()->fullyCreated) { + args->context()->setArg(index, value); + return true; + } + + bool isMapped = (args == receiver && args->isMapped(index)); + if (isMapped) + args->context()->setArg(index, value); } - bool isMapped = (args == receiver && args->isMapped(index)); - if (isMapped) - args->context()->setArg(index, value); - return Object::virtualPut(m, id, value, receiver); } @@ -186,13 +195,16 @@ bool ArgumentsObject::virtualDeleteProperty(Managed *m, PropertyKey id) ArgumentsObject *args = static_cast<ArgumentsObject *>(m); args->fullyCreate(); bool result = Object::virtualDeleteProperty(m, id); - if (result) + if (result && id.isArrayIndex()) args->removeMapping(id.asArrayIndex()); return result; } PropertyAttributes ArgumentsObject::virtualGetOwnProperty(const Managed *m, PropertyKey id, Property *p) { + if (!id.isArrayIndex()) + return Object::virtualGetOwnProperty(m, id, p); + const ArgumentsObject *args = static_cast<const ArgumentsObject *>(m); uint index = id.asArrayIndex(); if (index < args->d()->argCount && !args->d()->fullyCreated) { diff --git a/src/qml/jsruntime/qv4arrayobject.cpp b/src/qml/jsruntime/qv4arrayobject.cpp index b5b421fa39..b3e607d74a 100644 --- a/src/qml/jsruntime/qv4arrayobject.cpp +++ b/src/qml/jsruntime/qv4arrayobject.cpp @@ -219,7 +219,7 @@ ReturnedValue ArrayPrototype::method_from(const FunctionObject *builtin, const V // Item iteration supported, so let's go ahead and try use that. ScopedObject a(createObjectFromCtorOrArray(scope, thatCtor, false, 0)); CHECK_EXCEPTION(); - ScopedObject iterator(scope, Runtime::method_getIterator(scope.engine, itemsObject, true)); + ScopedObject iterator(scope, Runtime::GetIterator::call(scope.engine, itemsObject, true)); CHECK_EXCEPTION(); // symbol_iterator threw; whoops. if (!iterator) { return scope.engine->throwTypeError(); // symbol_iterator wasn't an object. @@ -236,11 +236,11 @@ ReturnedValue ArrayPrototype::method_from(const FunctionObject *builtin, const V if (k > (static_cast<qint64>(1) << 53) - 1) { ScopedValue falsey(scope, Encode(false)); ScopedValue error(scope, scope.engine->throwTypeError()); - return Runtime::method_iteratorClose(scope.engine, iterator, falsey); + return Runtime::IteratorClose::call(scope.engine, iterator, falsey); } // Retrieve the next value. If the iteration ends, we're done here. - done = Value::fromReturnedValue(Runtime::method_iteratorNext(scope.engine, iterator, nextValue)); + done = Value::fromReturnedValue(Runtime::IteratorNext::call(scope.engine, iterator, nextValue)); CHECK_EXCEPTION(); if (done->toBoolean()) { if (ArrayObject *ao = a->as<ArrayObject>()) { @@ -257,7 +257,7 @@ ReturnedValue ArrayPrototype::method_from(const FunctionObject *builtin, const V mapArguments[1] = Value::fromDouble(k); mappedValue = mapfn->call(thisArg, mapArguments, 2); if (scope.engine->hasException) - return Runtime::method_iteratorClose(scope.engine, iterator, Value::fromBoolean(false)); + return Runtime::IteratorClose::call(scope.engine, iterator, Value::fromBoolean(false)); } else { mappedValue = *nextValue; } @@ -271,7 +271,7 @@ ReturnedValue ArrayPrototype::method_from(const FunctionObject *builtin, const V if (scope.engine->hasException) { ScopedValue falsey(scope, Encode(false)); - return Runtime::method_iteratorClose(scope.engine, iterator, falsey); + return Runtime::IteratorClose::call(scope.engine, iterator, falsey); } k++; @@ -387,7 +387,7 @@ ReturnedValue ArrayPrototype::method_toLocaleString(const FunctionObject *b, con v = instance->get(k); if (v->isNullOrUndefined()) continue; - v = Runtime::method_callElement(scope.engine, v, *scope.engine->id_toLocaleString(), nullptr, 0); + v = Runtime::CallElement::call(scope.engine, v, *scope.engine->id_toLocaleString(), nullptr, 0); s = v->toString(scope.engine); if (scope.hasException()) return Encode::undefined(); diff --git a/src/qml/jsruntime/qv4calldata_p.h b/src/qml/jsruntime/qv4calldata_p.h new file mode 100644 index 0000000000..8487872bf5 --- /dev/null +++ b/src/qml/jsruntime/qv4calldata_p.h @@ -0,0 +1,113 @@ +/**************************************************************************** +** +** Copyright (C) 2019 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 QV4CALLDATA_P_H +#define QV4CALLDATA_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/qv4value_p.h> + +QT_BEGIN_NAMESPACE + +namespace QV4 { + +struct CallData +{ + enum Offsets { + Function = 0, + Context = 1, + Accumulator = 2, + This = 3, + NewTarget = 4, + Argc = 5, + + LastOffset = Argc, + OffsetCount = LastOffset + 1 + }; + + Value function; + Value context; + Value accumulator; + Value thisObject; + Value newTarget; + Value _argc; + + int argc() const { + Q_ASSERT(_argc.isInteger()); + return _argc.int_32(); + } + + void setArgc(int argc) { + Q_ASSERT(argc >= 0); + _argc.setInt_32(argc); + } + + inline ReturnedValue argument(int i) const { + return i < argc() ? args[i].asReturnedValue() : Value::undefinedValue().asReturnedValue(); + } + + Value args[1]; + + static Q_DECL_CONSTEXPR int HeaderSize() { return offsetof(CallData, args) / sizeof(QV4::Value); } +}; + +Q_STATIC_ASSERT(std::is_standard_layout<CallData>::value); +Q_STATIC_ASSERT(offsetof(CallData, function ) == CallData::Function * sizeof(Value)); +Q_STATIC_ASSERT(offsetof(CallData, context ) == CallData::Context * sizeof(Value)); +Q_STATIC_ASSERT(offsetof(CallData, accumulator) == CallData::Accumulator * sizeof(Value)); +Q_STATIC_ASSERT(offsetof(CallData, thisObject ) == CallData::This * sizeof(Value)); +Q_STATIC_ASSERT(offsetof(CallData, newTarget ) == CallData::NewTarget * sizeof(Value)); +Q_STATIC_ASSERT(offsetof(CallData, _argc ) == CallData::Argc * sizeof(Value)); +Q_STATIC_ASSERT(offsetof(CallData, args ) == 6 * sizeof(Value)); + +} // namespace QV4 + +QT_END_NAMESPACE + +#endif // QV4CALLDATA_P_H diff --git a/src/qml/jsruntime/qv4context.cpp b/src/qml/jsruntime/qv4context.cpp index 94b1a9fb73..b3bcfe21d5 100644 --- a/src/qml/jsruntime/qv4context.cpp +++ b/src/qml/jsruntime/qv4context.cpp @@ -81,17 +81,17 @@ Heap::CallContext *ExecutionContext::newBlockContext(CppStackFrame *frame, int b return c; } -Heap::CallContext *ExecutionContext::cloneBlockContext(Heap::CallContext *context) +Heap::CallContext *ExecutionContext::cloneBlockContext(ExecutionEngine *engine, + Heap::CallContext *callContext) { - uint nLocals = context->locals.alloc; + uint nLocals = callContext->locals.alloc; size_t requiredMemory = sizeof(CallContext::Data) - sizeof(Value) + sizeof(Value) * nLocals; - ExecutionEngine *v4 = context->internalClass->engine; - Heap::CallContext *c = v4->memoryManager->allocManaged<CallContext>(requiredMemory, context->internalClass); - memcpy(c, context, requiredMemory); + Heap::CallContext *c = engine->memoryManager->allocManaged<CallContext>( + requiredMemory, callContext->internalClass); + memcpy(c, callContext, requiredMemory); return c; - } Heap::CallContext *ExecutionContext::newCallContext(CppStackFrame *frame) @@ -128,7 +128,7 @@ Heap::CallContext *ExecutionContext::newCallContext(CppStackFrame *frame) return c; } -Heap::ExecutionContext *ExecutionContext::newWithContext(Heap::Object *with) +Heap::ExecutionContext *ExecutionContext::newWithContext(Heap::Object *with) const { Heap::ExecutionContext *c = engine()->memoryManager->alloc<ExecutionContext>(Heap::ExecutionContext::Type_WithContext); c->outer.set(engine(), d()); diff --git a/src/qml/jsruntime/qv4context_p.h b/src/qml/jsruntime/qv4context_p.h index 5cd2f9ddf0..75fa2d08e6 100644 --- a/src/qml/jsruntime/qv4context_p.h +++ b/src/qml/jsruntime/qv4context_p.h @@ -150,9 +150,10 @@ struct Q_QML_EXPORT ExecutionContext : public Managed V4_INTERNALCLASS(ExecutionContext) static Heap::CallContext *newBlockContext(QV4::CppStackFrame *frame, int blockIndex); - static Heap::CallContext *cloneBlockContext(Heap::CallContext *context); + static Heap::CallContext *cloneBlockContext(ExecutionEngine *engine, + Heap::CallContext *callContext); static Heap::CallContext *newCallContext(QV4::CppStackFrame *frame); - Heap::ExecutionContext *newWithContext(Heap::Object *with); + Heap::ExecutionContext *newWithContext(Heap::Object *with) const; static Heap::ExecutionContext *newCatchContext(CppStackFrame *frame, int blockIndex, Heap::String *exceptionVarName); void createMutableBinding(String *name, bool deletable); diff --git a/src/qml/jsruntime/qv4dateobject_p.h b/src/qml/jsruntime/qv4dateobject_p.h index 5b9934282c..a87eb92caf 100644 --- a/src/qml/jsruntime/qv4dateobject_p.h +++ b/src/qml/jsruntime/qv4dateobject_p.h @@ -96,7 +96,7 @@ struct DateObject: Object { double date() const { return d()->date; } void setDate(double date) { d()->date = date; } - QDateTime toQDateTime() const; + Q_QML_PRIVATE_EXPORT QDateTime toQDateTime() const; }; template<> diff --git a/src/qml/jsruntime/qv4engine.cpp b/src/qml/jsruntime/qv4engine.cpp index f5c5c49f56..b04a879c7f 100644 --- a/src/qml/jsruntime/qv4engine.cpp +++ b/src/qml/jsruntime/qv4engine.cpp @@ -38,9 +38,6 @@ ****************************************************************************/ #include <qv4engine_p.h> -#include <private/qqmljslexer_p.h> -#include <private/qqmljsparser_p.h> -#include <private/qqmljsast_p.h> #include <private/qv4compileddata_p.h> #include <private/qv4compiler_p.h> #include <private/qv4compilercontext_p.h> @@ -51,8 +48,9 @@ #include <QDir> #include <QFileInfo> #include <QLoggingCategory> - -#ifndef V4_BOOTSTRAP +#if QT_CONFIG(regularexpression) +#include <QRegularExpression> +#endif #include <qv4qmlcontext_p.h> #include <qv4value_p.h> @@ -104,7 +102,6 @@ #include "qv4dataview_p.h" #include "qv4promiseobject_p.h" #include "qv4typedarray_p.h" -#include <private/qv8engine_p.h> #include <private/qjsvalue_p.h> #include <private/qqmltypewrapper_p.h> #include <private/qqmlvaluetypewrapper_p.h> @@ -112,9 +109,16 @@ #include <private/qqmllistwrapper_p.h> #include <private/qqmllist_p.h> #include <private/qqmltypeloader_p.h> +#include <private/qqmlmemoryprofiler_p.h> +#include <private/qqmlbuiltinfunctions_p.h> #if QT_CONFIG(qml_locale) #include <private/qqmllocale_p.h> #endif +#if QT_CONFIG(qml_xml_http_request) +#include <private/qv4domerrors_p.h> +#include <private/qqmlxmlhttprequest_p.h> +#endif +#include <private/qv4sqlerrors_p.h> #include <qqmlfile.h> #if USE(PTHREADS) @@ -131,16 +135,12 @@ #include <valgrind/memcheck.h> #endif -#endif // #ifndef V4_BOOTSTRAP +Q_DECLARE_METATYPE(QList<int>) QT_BEGIN_NAMESPACE -Q_LOGGING_CATEGORY(lcTracingAll, "qt.v4.tracing.all") - using namespace QV4; -#ifndef V4_BOOTSTRAP - static QBasicAtomicInt engineSerial = Q_BASIC_ATOMIC_INITIALIZER(1); ReturnedValue throwTypeError(const FunctionObject *b, const QV4::Value *, const QV4::Value *, int) @@ -150,6 +150,43 @@ ReturnedValue throwTypeError(const FunctionObject *b, const QV4::Value *, const qint32 ExecutionEngine::maxCallDepth = -1; +template <typename ReturnType> +ReturnType convertJSValueToVariantType(const QJSValue &value) +{ + return value.toVariant().value<ReturnType>(); +} + +static void saveJSValue(QDataStream &stream, const void *data) +{ + const QJSValue *jsv = reinterpret_cast<const QJSValue *>(data); + quint32 isNullOrUndefined = 0; + if (jsv->isNull()) + isNullOrUndefined |= 0x1; + if (jsv->isUndefined()) + isNullOrUndefined |= 0x2; + stream << isNullOrUndefined; + if (!isNullOrUndefined) + reinterpret_cast<const QJSValue*>(data)->toVariant().save(stream); +} + +static void restoreJSValue(QDataStream &stream, void *data) +{ + QJSValue *jsv = reinterpret_cast<QJSValue*>(data); + + quint32 isNullOrUndefined; + stream >> isNullOrUndefined; + + if (isNullOrUndefined & 0x1) { + *jsv = QJSValue(QJSValue::NullValue); + } else if (isNullOrUndefined & 0x2) { + *jsv = QJSValue(); + } else { + QVariant v; + v.load(stream); + QJSValuePrivate::setVariant(jsv, v); + } +} + ExecutionEngine::ExecutionEngine(QJSEngine *jsEngine) : executableAllocator(new QV4::ExecutableAllocator) , regExpAllocator(new QV4::ExecutableAllocator) @@ -157,14 +194,17 @@ ExecutionEngine::ExecutionEngine(QJSEngine *jsEngine) , jsStack(new WTF::PageAllocation) , gcStack(new WTF::PageAllocation) , globalCode(nullptr) - , v8Engine(nullptr) , publicEngine(jsEngine) , m_engineId(engineSerial.fetchAndAddOrdered(1)) , regExpCache(nullptr) , m_multiplyWrappedQObjects(nullptr) -#if defined(V4_ENABLE_JIT) && !defined(V4_BOOTSTRAP) +#if QT_CONFIG(qml_jit) , m_canAllocateExecutableMemory(OSAllocator::canAllocateExecutableMemory()) #endif +#if QT_CONFIG(qml_xml_http_request) + , m_xmlHttpRequestData(nullptr) +#endif + , m_qmlEngine(nullptr) { memoryManager = new QV4::MemoryManager(this); @@ -651,18 +691,28 @@ ExecutionEngine::ExecutionEngine(QJSEngine *jsEngine) pd->set = thrower(); functionPrototype()->insertMember(id_caller(), pd, Attr_Accessor|Attr_ReadOnly_ButConfigurable); functionPrototype()->insertMember(id_arguments(), pd, Attr_Accessor|Attr_ReadOnly_ButConfigurable); + + QML_MEMORY_SCOPE_STRING("QV4Engine::QV4Engine"); + qMetaTypeId<QJSValue>(); + qMetaTypeId<QList<int> >(); + + if (!QMetaType::hasRegisteredConverterFunction<QJSValue, QVariantMap>()) + QMetaType::registerConverter<QJSValue, QVariantMap>(convertJSValueToVariantType<QVariantMap>); + if (!QMetaType::hasRegisteredConverterFunction<QJSValue, QVariantList>()) + QMetaType::registerConverter<QJSValue, QVariantList>(convertJSValueToVariantType<QVariantList>); + if (!QMetaType::hasRegisteredConverterFunction<QJSValue, QStringList>()) + QMetaType::registerConverter<QJSValue, QStringList>(convertJSValueToVariantType<QStringList>); + QMetaType::registerStreamOperators(qMetaTypeId<QJSValue>(), saveJSValue, restoreJSValue); + + QV4::QObjectWrapper::initializeBindings(this); + + m_delayedCallQueue.init(this); } ExecutionEngine::~ExecutionEngine() { - if (Q_UNLIKELY(lcTracingAll().isDebugEnabled())) { - for (auto cu : compilationUnits) { - for (auto f : qAsConst(cu->runtimeFunctions)) - qCDebug(lcTracingAll).noquote().nospace() << f->traceInfoToString(); - } - } - modules.clear(); + qDeleteAll(m_extensionData); delete m_multiplyWrappedQObjects; m_multiplyWrappedQObjects = nullptr; delete identifierTable; @@ -679,6 +729,11 @@ ExecutionEngine::~ExecutionEngine() delete jsStack; gcStack->deallocate(); delete gcStack; + +#if QT_CONFIG(qml_xml_http_request) + qt_rem_qmlxmlhttprequest(this, m_xmlHttpRequestData); + m_xmlHttpRequestData = nullptr; +#endif } ExecutionContext *ExecutionEngine::currentContext() const @@ -860,6 +915,13 @@ Heap::RegExpObject *ExecutionEngine::newRegExpObject(const QRegExp &re) return memoryManager->allocate<RegExpObject>(re); } +#if QT_CONFIG(regularexpression) +Heap::RegExpObject *ExecutionEngine::newRegExpObject(const QRegularExpression &re) +{ + return memoryManager->allocate<RegExpObject>(re); +} +#endif + Heap::Object *ExecutionEngine::newErrorObject(const Value &value) { return ErrorObject::create<ErrorObject>(this, value, errorCtor()); @@ -1072,6 +1134,12 @@ extern "C" Q_QML_EXPORT char *qt_v4StackTrace(void *executionContext) return v4StackTrace(reinterpret_cast<const ExecutionContext *>(executionContext)); } +extern "C" Q_QML_EXPORT char *qt_v4StackTraceForEngine(void *executionEngine) +{ + auto engine = (reinterpret_cast<const ExecutionEngine *>(executionEngine)); + return v4StackTrace(engine->currentContext()); +} + QUrl ExecutionEngine::resolvedUrl(const QString &file) { QUrl src(file); @@ -1269,6 +1337,7 @@ static bool convertToNativeQObject(QV4::ExecutionEngine *e, const QV4::Value &va const QByteArray &targetType, void **result); static QV4::ReturnedValue variantListToJS(QV4::ExecutionEngine *v4, const QVariantList &lst); +static QV4::ReturnedValue sequentialIterableToJS(QV4::ExecutionEngine *v4, const QSequentialIterable &lst); static QV4::ReturnedValue variantMapToJS(QV4::ExecutionEngine *v4, const QVariantMap &vmap); static QV4::ReturnedValue variantToJS(QV4::ExecutionEngine *v4, const QVariant &value) { @@ -1305,7 +1374,7 @@ static QVariant toVariant(QV4::ExecutionEngine *e, const QV4::Value &value, int && !value.as<ArrayObject>() && !value.as<FunctionObject>()) { return QVariant::fromValue(QV4::JsonObject::toJsonObject(object)); } else if (QV4::QObjectWrapper *wrapper = object->as<QV4::QObjectWrapper>()) { - return qVariantFromValue<QObject *>(wrapper->object()); + return QVariant::fromValue<QObject *>(wrapper->object()); } else if (object->as<QV4::QQmlContextWrapper>()) { return QVariant(); } else if (QV4::QQmlTypeWrapper *w = object->as<QV4::QQmlTypeWrapper>()) { @@ -1336,7 +1405,7 @@ static QVariant toVariant(QV4::ExecutionEngine *e, const QV4::Value &value, int } } - return qVariantFromValue<QList<QObject*> >(list); + return QVariant::fromValue<QList<QObject*> >(list); } else if (typeHint == QMetaType::QJsonArray) { return QVariant::fromValue(QV4::JsonObject::toJsonArray(a)); } @@ -1379,8 +1448,13 @@ static QVariant toVariant(QV4::ExecutionEngine *e, const QV4::Value &value, int QV4::ScopedObject o(scope, value); Q_ASSERT(o); - if (QV4::RegExpObject *re = o->as<QV4::RegExpObject>()) + if (QV4::RegExpObject *re = o->as<QV4::RegExpObject>()) { +#if QT_CONFIG(regularexpression) + if (typeHint != QMetaType::QRegExp) + return re->toQRegularExpression(); +#endif return re->toQRegExp(); + } if (createJSValueForObjects) return QVariant::fromValue(QJSValue(scope.engine, o->asReturnedValue())); @@ -1442,35 +1516,6 @@ static QVariant objectToVariant(QV4::ExecutionEngine *e, const QV4::Object *o, V return result; } -static QV4::ReturnedValue arrayFromVariantList(QV4::ExecutionEngine *e, const QVariantList &list) -{ - QV4::Scope scope(e); - QV4::ScopedArrayObject a(scope, e->newArrayObject()); - int len = list.count(); - a->arrayReserve(len); - QV4::ScopedValue v(scope); - for (int ii = 0; ii < len; ++ii) - a->arrayPut(ii, (v = scope.engine->fromVariant(list.at(ii)))); - - a->setArrayLengthUnchecked(len); - return a.asReturnedValue(); -} - -static QV4::ReturnedValue objectFromVariantMap(QV4::ExecutionEngine *e, const QVariantMap &map) -{ - QV4::Scope scope(e); - QV4::ScopedObject o(scope, e->newObject()); - QV4::ScopedString s(scope); - QV4::ScopedValue v(scope); - for (QVariantMap::const_iterator iter = map.begin(), cend = map.end(); iter != cend; ++iter) { - s = e->newString(iter.key()); - o->put(s, (v = e->fromVariant(iter.value()))); - } - return o.asReturnedValue(); -} - -Q_CORE_EXPORT QString qt_regexp_toCanonical(const QString &, QRegExp::PatternSyntax); - QV4::ReturnedValue QV4::ExecutionEngine::fromVariant(const QVariant &variant) { int type = variant.userType(); @@ -1520,6 +1565,10 @@ QV4::ReturnedValue QV4::ExecutionEngine::fromVariant(const QVariant &variant) return QV4::Encode(newDateObjectFromTime(*reinterpret_cast<const QTime *>(ptr))); case QMetaType::QRegExp: return QV4::Encode(newRegExpObject(*reinterpret_cast<const QRegExp *>(ptr))); +#if QT_CONFIG(regularexpression) + case QMetaType::QRegularExpression: + return QV4::Encode(newRegExpObject(*reinterpret_cast<const QRegularExpression *>(ptr))); +#endif case QMetaType::QObjectStar: return QV4::QObjectWrapper::wrap(this, *reinterpret_cast<QObject* const *>(ptr)); #if QT_CONFIG(qml_sequence_object) @@ -1534,9 +1583,9 @@ QV4::ReturnedValue QV4::ExecutionEngine::fromVariant(const QVariant &variant) } #endif case QMetaType::QVariantList: - return arrayFromVariantList(this, *reinterpret_cast<const QVariantList *>(ptr)); + return variantListToJS(this, *reinterpret_cast<const QVariantList *>(ptr)); case QMetaType::QVariantMap: - return objectFromVariantMap(this, *reinterpret_cast<const QVariantMap *>(ptr)); + return variantMapToJS(this, *reinterpret_cast<const QVariantMap *>(ptr)); case QMetaType::QJsonValue: return QV4::JsonObject::fromJsonValue(this, *reinterpret_cast<const QJsonValue *>(ptr)); case QMetaType::QJsonObject: @@ -1597,6 +1646,11 @@ QV4::ReturnedValue QV4::ExecutionEngine::fromVariant(const QVariant &variant) return retn->asReturnedValue(); #endif + if (QMetaType::hasRegisteredConverterFunction(type, qMetaTypeId<QtMetaTypePrivate::QSequentialIterableImpl>())) { + QSequentialIterable lst = variant.value<QSequentialIterable>(); + return sequentialIterableToJS(this, lst); + } + if (const QMetaObject *vtmo = QQmlValueTypeFactory::metaObjectForMetaType(type)) return QV4::QQmlValueTypeWrapper::create(this, variant, vtmo, type); } @@ -1661,9 +1715,8 @@ static QV4::ReturnedValue variantMapToJS(QV4::ExecutionEngine *v4, const QVarian s = v4->newIdentifier(it.key()); key = s->propertyKey(); v = variantToJS(v4, it.value()); - uint idx = key->asArrayIndex(); - if (idx < UINT_MAX) - o->arraySet(idx, v); + if (key->isArrayIndex()) + o->arraySet(key->asArrayIndex(), v); else o->insertMember(s, v); } @@ -1676,99 +1729,13 @@ QV4::ReturnedValue ExecutionEngine::metaTypeToJS(int type, const void *data) { Q_ASSERT(data != nullptr); - // check if it's one of the types we know - switch (QMetaType::Type(type)) { - case QMetaType::UnknownType: - case QMetaType::Void: - return QV4::Encode::undefined(); - case QMetaType::Nullptr: - case QMetaType::VoidStar: - return QV4::Encode::null(); - case QMetaType::Bool: - return QV4::Encode(*reinterpret_cast<const bool*>(data)); - case QMetaType::Int: - return QV4::Encode(*reinterpret_cast<const int*>(data)); - case QMetaType::UInt: - return QV4::Encode(*reinterpret_cast<const uint*>(data)); - case QMetaType::LongLong: - return QV4::Encode(double(*reinterpret_cast<const qlonglong*>(data))); - case QMetaType::ULongLong: -#if defined(Q_OS_WIN) && defined(_MSC_FULL_VER) && _MSC_FULL_VER <= 12008804 -#pragma message("** NOTE: You need the Visual Studio Processor Pack to compile support for 64bit unsigned integers.") - return QV4::Encode(double((qlonglong)*reinterpret_cast<const qulonglong*>(data))); -#elif defined(Q_CC_MSVC) && !defined(Q_CC_MSVC_NET) - return QV4::Encode(double((qlonglong)*reinterpret_cast<const qulonglong*>(data))); -#else - return QV4::Encode(double(*reinterpret_cast<const qulonglong*>(data))); -#endif - case QMetaType::Double: - return QV4::Encode(*reinterpret_cast<const double*>(data)); - case QMetaType::QString: - return newString(*reinterpret_cast<const QString*>(data))->asReturnedValue(); - case QMetaType::QByteArray: - return newArrayBuffer(*reinterpret_cast<const QByteArray*>(data))->asReturnedValue(); - case QMetaType::Float: - return QV4::Encode(*reinterpret_cast<const float*>(data)); - case QMetaType::Short: - return QV4::Encode((int)*reinterpret_cast<const short*>(data)); - case QMetaType::UShort: - return QV4::Encode((int)*reinterpret_cast<const unsigned short*>(data)); - case QMetaType::Char: - return QV4::Encode((int)*reinterpret_cast<const char*>(data)); - case QMetaType::UChar: - return QV4::Encode((int)*reinterpret_cast<const unsigned char*>(data)); - case QMetaType::QChar: - return QV4::Encode((int)(*reinterpret_cast<const QChar*>(data)).unicode()); - case QMetaType::QStringList: - return QV4::Encode(newArrayObject(*reinterpret_cast<const QStringList *>(data))); - case QMetaType::QVariantList: - return variantListToJS(this, *reinterpret_cast<const QVariantList *>(data)); - case QMetaType::QVariantMap: - return variantMapToJS(this, *reinterpret_cast<const QVariantMap *>(data)); - case QMetaType::QDateTime: - return QV4::Encode(newDateObject(*reinterpret_cast<const QDateTime *>(data))); - case QMetaType::QDate: - return QV4::Encode(newDateObject(QDateTime(*reinterpret_cast<const QDate *>(data)))); - case QMetaType::QRegExp: - return QV4::Encode(newRegExpObject(*reinterpret_cast<const QRegExp *>(data))); - case QMetaType::QObjectStar: - return QV4::QObjectWrapper::wrap(this, *reinterpret_cast<QObject* const *>(data)); - case QMetaType::QVariant: + QVariant variant(type, data); + if (QMetaType::Type(variant.type()) == QMetaType::QVariant) { + // unwrap it: this is tested in QJSEngine, and makes the most sense for + // end-user code too. return variantToJS(this, *reinterpret_cast<const QVariant*>(data)); - case QMetaType::QJsonValue: - return QV4::JsonObject::fromJsonValue(this, *reinterpret_cast<const QJsonValue *>(data)); - case QMetaType::QJsonObject: - return QV4::JsonObject::fromJsonObject(this, *reinterpret_cast<const QJsonObject *>(data)); - case QMetaType::QJsonArray: - return QV4::JsonObject::fromJsonArray(this, *reinterpret_cast<const QJsonArray *>(data)); - default: - if (type == qMetaTypeId<QJSValue>()) { - return QJSValuePrivate::convertedToValue(this, *reinterpret_cast<const QJSValue*>(data)); - } else { - QByteArray typeName = QMetaType::typeName(type); - if (typeName.endsWith('*') && !*reinterpret_cast<void* const *>(data)) { - return QV4::Encode::null(); - } - QMetaType mt(type); - if (auto metaObject = mt.metaObject()) { - auto flags = mt.flags(); - if (flags & QMetaType::IsGadget) { - return QV4::QQmlValueTypeWrapper::create(this, QVariant(type, data), metaObject, type); - } else if (flags & QMetaType::PointerToQObject) { - return QV4::QObjectWrapper::wrap(this, *reinterpret_cast<QObject* const *>(data)); - } - } - if (QMetaType::hasRegisteredConverterFunction(type, qMetaTypeId<QtMetaTypePrivate::QSequentialIterableImpl>())) { - auto v = QVariant(type, data); - QSequentialIterable lst = v.value<QSequentialIterable>(); - return sequentialIterableToJS(this, lst); - } - // Fall back to wrapping in a QVariant. - return QV4::Encode(newVariantObject(QVariant(type, data))); - } } - Q_UNREACHABLE(); - return 0; + return fromVariant(variant); } ReturnedValue ExecutionEngine::global() @@ -1796,7 +1763,8 @@ QQmlRefPointer<CompiledData::CompilationUnit> ExecutionEngine::compileModule(con QQmlRefPointer<CompiledData::CompilationUnit> ExecutionEngine::compileModule(const QUrl &url, const QString &sourceCode, const QDateTime &sourceTimeStamp) { QList<QQmlJS::DiagnosticMessage> diagnostics; - auto unit = compileModule(/*debugMode*/debugger() != nullptr, url.toString(), sourceCode, sourceTimeStamp, &diagnostics); + auto unit = Compiler::Codegen::compileModule(/*debugMode*/debugger() != nullptr, url.toString(), + sourceCode, sourceTimeStamp, &diagnostics); for (const QQmlJS::DiagnosticMessage &m : diagnostics) { if (m.isError()) { throwSyntaxError(m.message, url.toString(), m.loc.startLine, m.loc.startColumn); @@ -1809,52 +1777,6 @@ QQmlRefPointer<CompiledData::CompilationUnit> ExecutionEngine::compileModule(con return unit; } -#endif // ifndef V4_BOOTSTRAP - -QQmlRefPointer<CompiledData::CompilationUnit> ExecutionEngine::compileModule(bool debugMode, const QString &url, const QString &sourceCode, - const QDateTime &sourceTimeStamp, QList<QQmlJS::DiagnosticMessage> *diagnostics) -{ - QQmlJS::Engine ee; - QQmlJS::Lexer lexer(&ee); - lexer.setCode(sourceCode, /*line*/1, /*qml mode*/false); - QQmlJS::Parser parser(&ee); - - const bool parsed = parser.parseModule(); - - if (diagnostics) - *diagnostics = parser.diagnosticMessages(); - - if (!parsed) - return nullptr; - - QQmlJS::AST::ESModule *moduleNode = QQmlJS::AST::cast<QQmlJS::AST::ESModule*>(parser.rootNode()); - if (!moduleNode) { - // if parsing was successful, and we have no module, then - // the file was empty. - if (diagnostics) - diagnostics->clear(); - return nullptr; - } - - using namespace QV4::Compiler; - Compiler::Module compilerModule(debugMode); - compilerModule.unitFlags |= CompiledData::Unit::IsESModule; - compilerModule.sourceTimeStamp = sourceTimeStamp; - JSUnitGenerator jsGenerator(&compilerModule); - Codegen cg(&jsGenerator, /*strictMode*/true); - cg.generateFromModule(url, url, sourceCode, moduleNode, &compilerModule); - auto errors = cg.errors(); - if (diagnostics) - *diagnostics << errors; - - if (!errors.isEmpty()) - return nullptr; - - return cg.generateCompilationUnit(); -} - -#ifndef V4_BOOTSTRAP - void ExecutionEngine::injectModule(const QQmlRefPointer<CompiledData::CompilationUnit> &moduleUnit) { // Injection can happen from the QML type loader thread for example, but instantiation and @@ -1898,6 +1820,133 @@ QQmlRefPointer<CompiledData::CompilationUnit> ExecutionEngine::loadModule(const return newModule; } +void ExecutionEngine::initQmlGlobalObject() +{ + initializeGlobal(); + freezeObject(*globalObject); +} + +void ExecutionEngine::initializeGlobal() +{ + QV4::Scope scope(this); + QV4::GlobalExtensions::init(globalObject, QJSEngine::AllExtensions); + + QV4::ScopedObject qt(scope, memoryManager->allocate<QV4::QtObject>(qmlEngine())); + globalObject->defineDefaultProperty(QStringLiteral("Qt"), qt); + +#if QT_CONFIG(qml_locale) + QQmlLocale::registerStringLocaleCompare(this); + QQmlDateExtension::registerExtension(this); + QQmlNumberExtension::registerExtension(this); +#endif + +#if QT_CONFIG(qml_xml_http_request) + qt_add_domexceptions(this); + m_xmlHttpRequestData = qt_add_qmlxmlhttprequest(this); +#endif + + qt_add_sqlexceptions(this); + + { + for (uint i = 0; i < globalObject->internalClass()->size; ++i) { + if (globalObject->internalClass()->nameMap.at(i).isString()) { + QV4::PropertyKey id = globalObject->internalClass()->nameMap.at(i); + m_illegalNames.insert(id.toQString()); + } + } + } +} + +const QSet<QString> &ExecutionEngine::illegalNames() const +{ + return m_illegalNames; +} + +void ExecutionEngine::setQmlEngine(QQmlEngine *engine) +{ + m_qmlEngine = engine; + initQmlGlobalObject(); +} + +static void freeze_recursive(QV4::ExecutionEngine *v4, QV4::Object *object) +{ + if (object->as<QV4::QObjectWrapper>()) + return; + + QV4::Scope scope(v4); + + bool instanceOfObject = false; + QV4::ScopedObject p(scope, object->getPrototypeOf()); + while (p) { + if (p->d() == v4->objectPrototype()->d()) { + instanceOfObject = true; + break; + } + p = p->getPrototypeOf(); + } + if (!instanceOfObject) + return; + + QV4::Heap::InternalClass *frozen = object->internalClass()->propertiesFrozen(); + if (object->internalClass() == frozen) + return; + object->setInternalClass(frozen); + + QV4::ScopedObject o(scope); + for (uint i = 0; i < frozen->size; ++i) { + if (!frozen->nameMap.at(i).isStringOrSymbol()) + continue; + o = *object->propertyData(i); + if (o) + freeze_recursive(v4, o); + } +} + +void ExecutionEngine::freezeObject(const QV4::Value &value) +{ + QV4::Scope scope(this); + QV4::ScopedObject o(scope, value); + freeze_recursive(this, o); +} + +void ExecutionEngine::startTimer(const QString &timerName) +{ + if (!m_time.isValid()) + m_time.start(); + m_startedTimers[timerName] = m_time.elapsed(); +} + +qint64 ExecutionEngine::stopTimer(const QString &timerName, bool *wasRunning) +{ + if (!m_startedTimers.contains(timerName)) { + *wasRunning = false; + return 0; + } + *wasRunning = true; + qint64 startedAt = m_startedTimers.take(timerName); + return m_time.elapsed() - startedAt; +} + +int ExecutionEngine::consoleCountHelper(const QString &file, quint16 line, quint16 column) +{ + const QString key = file + QString::number(line) + QString::number(column); + int number = m_consoleCount.value(key, 0); + number++; + m_consoleCount.insert(key, number); + return number; +} + +void ExecutionEngine::setExtensionData(int index, Deletable *data) +{ + if (m_extensionData.count() <= index) + m_extensionData.resize(index + 1); + + if (m_extensionData.at(index)) + delete m_extensionData.at(index); + + m_extensionData[index] = data; +} + // Converts a JS value to a meta-type. // data must point to a place that can store a value of the given type. // Returns true if conversion succeeded, false otherwise. @@ -1973,6 +2022,13 @@ bool ExecutionEngine::metaTypeFromJS(const Value *value, int type, void *data) *reinterpret_cast<QRegExp *>(data) = r->toQRegExp(); return true; } break; +#if QT_CONFIG(regularexpression) + case QMetaType::QRegularExpression: + if (const QV4::RegExpObject *r = value->as<QV4::RegExpObject>()) { + *reinterpret_cast<QRegularExpression *>(data) = r->toQRegularExpression(); + return true; + } break; +#endif case QMetaType::QObjectStar: { const QV4::QObjectWrapper *qobjectWrapper = value->as<QV4::QObjectWrapper>(); if (qobjectWrapper || value->isNull()) { @@ -2137,6 +2193,23 @@ static QObject *qtObjectFromJS(QV4::ExecutionEngine *engine, const QV4::Value &v return wrapper->object(); } -#endif // ifndef V4_BOOTSTRAP +struct QV4EngineRegistrationData +{ + QV4EngineRegistrationData() : extensionCount(0) {} + + QMutex mutex; + int extensionCount; +}; +Q_GLOBAL_STATIC(QV4EngineRegistrationData, registrationData); + +QMutex *ExecutionEngine::registrationMutex() +{ + return ®istrationData()->mutex; +} + +int ExecutionEngine::registerExtension() +{ + return registrationData()->extensionCount++; +} QT_END_NAMESPACE diff --git a/src/qml/jsruntime/qv4engine_p.h b/src/qml/jsruntime/qv4engine_p.h index 86367c0ece..0d113754c0 100644 --- a/src/qml/jsruntime/qv4engine_p.h +++ b/src/qml/jsruntime/qv4engine_p.h @@ -53,25 +53,82 @@ #include "qv4global_p.h" #include "qv4managed_p.h" #include "qv4context_p.h" +#include "qv4stackframe_p.h" #include <private/qintrusivelist_p.h> #include "qv4enginebase_p.h" #include <private/qqmlrefcount_p.h> #include <private/qqmljsengine_p.h> +#include <private/qqmldelayedcallqueue_p.h> +#include <QtCore/qelapsedtimer.h> +#include <QtCore/qmutex.h> -#ifndef V4_BOOTSTRAP -# include "qv4function_p.h" -# include <private/qv8engine_p.h> -# include <private/qv4compileddata_p.h> -#endif +#include "qv4function_p.h" +#include <private/qv4compileddata_p.h> namespace WTF { class BumpPointerAllocator; class PageAllocation; } +#define V4_DEFINE_EXTENSION(dataclass, datafunction) \ + static inline dataclass *datafunction(QV4::ExecutionEngine *engine) \ + { \ + static int extensionId = -1; \ + if (extensionId == -1) { \ + QV4::ExecutionEngine::registrationMutex()->lock(); \ + if (extensionId == -1) \ + extensionId = QV4::ExecutionEngine::registerExtension(); \ + QV4::ExecutionEngine::registrationMutex()->unlock(); \ + } \ + dataclass *rv = (dataclass *)engine->extensionData(extensionId); \ + if (!rv) { \ + rv = new dataclass(engine); \ + engine->setExtensionData(extensionId, rv); \ + } \ + return rv; \ + } \ + + QT_BEGIN_NAMESPACE -class QV8Engine; +namespace QV4 { struct QObjectMethod; } + +// Used to allow a QObject method take and return raw V4 handles without having to expose +// 48 in the public API. +// Use like this: +// class MyClass : public QObject { +// Q_OBJECT +// ... +// Q_INVOKABLE void myMethod(QQmlV4Function*); +// }; +// The QQmlV8Function - and consequently the arguments and return value - only remains +// valid during the call. If the return value isn't set within myMethod(), the will return +// undefined. + +class QQmlV4Function +{ +public: + int length() const { return callData->argc(); } + QV4::ReturnedValue operator[](int idx) const { return (idx < callData->argc() ? callData->args[idx].asReturnedValue() : QV4::Encode::undefined()); } + void setReturnValue(QV4::ReturnedValue rv) { *retVal = rv; } + QV4::ExecutionEngine *v4engine() const { return e; } +private: + friend struct QV4::QObjectMethod; + QQmlV4Function(); + QQmlV4Function(const QQmlV4Function &); + QQmlV4Function &operator=(const QQmlV4Function &); + + QQmlV4Function(QV4::CallData *callData, QV4::Value *retVal, QV4::ExecutionEngine *e) + : callData(callData), retVal(retVal), e(e) + { + callData->thisObject = QV4::Encode::undefined(); + } + + QV4::CallData *callData; + QV4::Value *retVal; + QV4::ExecutionEngine *e; +}; + class QQmlError; class QJSEngine; class QQmlEngine; @@ -128,14 +185,8 @@ public: Function *globalCode; -#ifdef V4_BOOTSTRAP - QJSEngine *jsEngine() const; - QQmlEngine *qmlEngine() const; -#else // !V4_BOOTSTRAP QJSEngine *jsEngine() const { return publicEngine; } - QQmlEngine *qmlEngine() const { return v8Engine ? v8Engine->engine() : nullptr; } -#endif // V4_BOOTSTRAP - QV8Engine *v8Engine; + QQmlEngine *qmlEngine() const { return m_qmlEngine; } QJSEngine *publicEngine; enum JSObjects { @@ -438,9 +489,7 @@ public: Symbol *symbol_unscopables() const { return reinterpret_cast<Symbol *>(jsSymbols + Symbol_unscopables); } Symbol *symbol_revokableProxy() const { return reinterpret_cast<Symbol *>(jsSymbols + Symbol_revokableProxy); } -#ifndef V4_BOOTSTRAP QIntrusiveList<CompiledData::CompilationUnit, &CompiledData::CompilationUnit::nextCompilationUnit> compilationUnits; -#endif quint32 m_engineId; @@ -464,7 +513,7 @@ public: // but any time a QObject is wrapped a second time in another engine, we have to do // bookkeeping. MultiplyWrappedQObjectMap *m_multiplyWrappedQObjects; -#if defined(V4_ENABLE_JIT) && !defined(V4_BOOTSTRAP) +#if QT_CONFIG(qml_jit) const bool m_canAllocateExecutableMemory; #endif @@ -520,6 +569,9 @@ public: Heap::RegExpObject *newRegExpObject(const QString &pattern, int flags); Heap::RegExpObject *newRegExpObject(RegExp *re); Heap::RegExpObject *newRegExpObject(const QRegExp &re); +#if QT_CONFIG(regularexpression) + Heap::RegExpObject *newRegExpObject(const QRegularExpression &re); +#endif Heap::Object *newErrorObject(const Value &value); Heap::Object *newErrorObject(const QString &message); @@ -592,7 +644,7 @@ public: bool canJIT(Function *f = nullptr) { -#if defined(V4_ENABLE_JIT) && !defined(V4_BOOTSTRAP) +#if QT_CONFIG(qml_jit) if (!m_canAllocateExecutableMemory) return false; if (f) @@ -605,11 +657,47 @@ public: } QV4::ReturnedValue global(); + void initQmlGlobalObject(); + void initializeGlobal(); + + void freezeObject(const QV4::Value &value); + + // Return the list of illegal id names (the names of the properties on the global object) + const QSet<QString> &illegalNames() const; + +#if QT_CONFIG(qml_xml_http_request) + void *xmlHttpRequestData() const { return m_xmlHttpRequestData; } +#endif + + void setQmlEngine(QQmlEngine *engine); + + QQmlDelayedCallQueue *delayedCallQueue() { return &m_delayedCallQueue; } + + // used for console.time(), console.timeEnd() + void startTimer(const QString &timerName); + qint64 stopTimer(const QString &timerName, bool *wasRunning); + + // used for console.count() + int consoleCountHelper(const QString &file, quint16 line, quint16 column); + + struct Deletable { + virtual ~Deletable() {} + }; + + static QMutex *registrationMutex(); + static int registerExtension(); + + void setExtensionData(int, Deletable *); + Deletable *extensionData(int index) const + { + if (index < m_extensionData.count()) + return m_extensionData[index]; + else + return nullptr; + } double localTZA = 0.0; // local timezone, initialized at startup - static QQmlRefPointer<CompiledData::CompilationUnit> compileModule(bool debugMode, const QString &url, const QString &sourceCode, const QDateTime &sourceTimeStamp, QList<QQmlJS::DiagnosticMessage> *diagnostics); -#ifndef V4_BOOTSTRAP QQmlRefPointer<CompiledData::CompilationUnit> compileModule(const QUrl &url); QQmlRefPointer<CompiledData::CompilationUnit> compileModule(const QUrl &url, const QString &sourceCode, const QDateTime &sourceTimeStamp); @@ -618,29 +706,33 @@ public: void injectModule(const QQmlRefPointer<CompiledData::CompilationUnit> &moduleUnit); QQmlRefPointer<CompiledData::CompilationUnit> moduleForUrl(const QUrl &_url, const CompiledData::CompilationUnit *referrer = nullptr) const; QQmlRefPointer<CompiledData::CompilationUnit> loadModule(const QUrl &_url, const CompiledData::CompilationUnit *referrer = nullptr); -#endif private: #if QT_CONFIG(qml_debug) QScopedPointer<QV4::Debugging::Debugger> m_debugger; QScopedPointer<QV4::Profiling::Profiler> m_profiler; #endif + QSet<QString> m_illegalNames; int jitCallCountThreshold; // used by generated Promise objects to handle 'then' events QScopedPointer<QV4::Promise::ReactionHandler> m_reactionHandler; -}; -// This is a trick to tell the code generators that functions taking a NoThrowContext won't -// throw exceptions and therefore don't need a check after the call. -#ifndef V4_BOOTSTRAP -struct NoThrowEngine : public ExecutionEngine -{ -}; -#else -struct NoThrowEngine; +#if QT_CONFIG(qml_xml_http_request) + void *m_xmlHttpRequestData; #endif + QQmlEngine *m_qmlEngine; + + QQmlDelayedCallQueue m_delayedCallQueue; + + QElapsedTimer m_time; + QHash<QString, qint64> m_startedTimers; + + QHash<QString, quint32> m_consoleCount; + + QVector<Deletable *> m_extensionData; +}; #define CHECK_STACK_LIMITS(v4) if ((v4)->checkStackLimits()) return Encode::undefined(); \ ExecutionEngineCallDepthRecorder _executionEngineCallDepthRecorder(v4); diff --git a/src/qml/jsruntime/qv4enginebase_p.h b/src/qml/jsruntime/qv4enginebase_p.h index b5cfea8863..00876c71a2 100644 --- a/src/qml/jsruntime/qv4enginebase_p.h +++ b/src/qml/jsruntime/qv4enginebase_p.h @@ -69,9 +69,20 @@ struct Q_QML_EXPORT EngineBase { CppStackFrame *currentStackFrame = nullptr; Value *jsStackTop = nullptr; + + // The JIT expects hasException and isInterrupted to be in the same 32bit word in memory. quint8 hasException = false; - quint8 writeBarrierActive = false; + // isInterrupted is expected to be set from a different thread +#if defined(Q_ATOMIC_INT8_IS_SUPPORTED) + QAtomicInteger<quint8> isInterrupted = false; quint16 unused = 0; +#elif defined(Q_ATOMIC_INT16_IS_SUPPORTED) + quint8 unused = 0; + QAtomicInteger<quint16> isInterrupted = false; +#else +# error V4 needs either 8bit or 16bit atomics. +#endif + quint8 isExecutingInRegExpJIT = false; quint8 padding[3]; MemoryManager *memoryManager = nullptr; @@ -137,6 +148,10 @@ Q_STATIC_ASSERT(offsetof(EngineBase, hasException) == offsetof(EngineBase, jsSta Q_STATIC_ASSERT(offsetof(EngineBase, memoryManager) == offsetof(EngineBase, hasException) + 8); Q_STATIC_ASSERT(offsetof(EngineBase, runtime) == offsetof(EngineBase, memoryManager) + QT_POINTER_SIZE); +#ifndef V4_BOOTSTRAP +Q_STATIC_ASSERT(offsetof(EngineBase, isInterrupted) + sizeof(EngineBase::isInterrupted) <= offsetof(EngineBase, hasException) + 4); +#endif + } QT_END_NAMESPACE diff --git a/src/qml/jsruntime/qv4function.cpp b/src/qml/jsruntime/qv4function.cpp index 1bd4329fe8..debdf23d27 100644 --- a/src/qml/jsruntime/qv4function.cpp +++ b/src/qml/jsruntime/qv4function.cpp @@ -75,19 +75,12 @@ ReturnedValue Function::call(const Value *thisObject, const Value *argv, int arg Function *Function::create(ExecutionEngine *engine, CompiledData::CompilationUnit *unit, const CompiledData::Function *function) { - quint16 traceSlotCount = 0; -#if QT_CONFIG(qml_tracing) - traceSlotCount = function->nTraceInfos == CompiledData::Function::NoTracing() - ? 1 - : function->nTraceInfos; -#endif - quint8 *storage = new quint8[sizeof(Function) + traceSlotCount]; - return new(storage) Function(engine, unit, function); + return new Function(engine, unit, function); } void Function::destroy() { - delete[] reinterpret_cast<quint8 *>(this); + delete this; } Function::Function(ExecutionEngine *engine, CompiledData::CompilationUnit *unit, const CompiledData::Function *function) @@ -111,13 +104,6 @@ Function::Function(ExecutionEngine *engine, CompiledData::CompilationUnit *unit, internalClass = ic->d(); nFormals = compiledFunction->nFormals; - -#if QT_CONFIG(qml_tracing) - if (tracingEnabled()) { - for (uint i = 0; i < function->nTraceInfos; ++i) - *traceInfo(i) = 0; - } -#endif } Function::~Function() @@ -188,22 +174,4 @@ QQmlSourceLocation Function::sourceLocation() const return QQmlSourceLocation(sourceFile(), compiledFunction->location.line, compiledFunction->location.column); } -QString Function::traceInfoToString() -{ - QString info = QLatin1String("=== Trace information for ") + name()->toQString() + QLatin1Char(':'); - if (!tracingEnabled()) - return info + QStringLiteral(" disabled. Interpreter call count: %1\n").arg(interpreterCallCount); - if (compiledFunction->nTraceInfos == 0) - return info + QLatin1String(" none.\n"); - - info += QLatin1Char('\n'); - for (uint i = 0, ei = compiledFunction->nTraceInfos; i < ei; ++i) { - auto bits = QString::number(*traceInfo(i), 2); - if (bits.size() < 8) - bits.prepend(QString(8 - bits.size(), '0')); - info += QStringLiteral(" %1: %2\n").arg(QString::number(i), bits); - } - return info; -} - QT_END_NAMESPACE diff --git a/src/qml/jsruntime/qv4function_p.h b/src/qml/jsruntime/qv4function_p.h index f8125a58f8..01b212370d 100644 --- a/src/qml/jsruntime/qv4function_p.h +++ b/src/qml/jsruntime/qv4function_p.h @@ -123,31 +123,6 @@ public: return nullptr; return compilationUnit->runtimeFunctions[compiledFunction->nestedFunctionIndex]; } - - Q_NEVER_INLINE QString traceInfoToString(); - - quint8 *traceInfo(uint i) - { -#if QT_CONFIG(qml_tracing) - Q_ASSERT((tracingEnabled() && i < traceInfoCount()) || (i == 0)); - return reinterpret_cast<quint8 *>(this) + sizeof(Function) + i; -#else - Q_UNUSED(i); - return nullptr; -#endif - } - - quint32 traceInfoCount() const - { return compiledFunction->nTraceInfos; } - - bool tracingEnabled() const - { -#if QT_CONFIG(qml_tracing) - return traceInfoCount() != CompiledData::Function::NoTracing(); -#else - return false; -#endif - } }; } diff --git a/src/qml/jsruntime/qv4functionobject_p.h b/src/qml/jsruntime/qv4functionobject_p.h index e03d49c74d..4fee26f341 100644 --- a/src/qml/jsruntime/qv4functionobject_p.h +++ b/src/qml/jsruntime/qv4functionobject_p.h @@ -87,11 +87,11 @@ DECLARE_HEAP_OBJECT(FunctionObject, Object) { } Q_QML_PRIVATE_EXPORT void init(QV4::ExecutionContext *scope, QV4::String *name, VTable::Call call); - void init(QV4::ExecutionContext *scope, QV4::String *name = nullptr); - void init(QV4::ExecutionContext *scope, QV4::Function *function, QV4::String *n = nullptr); - void init(QV4::ExecutionContext *scope, const QString &name); - void init(); - void destroy(); + Q_QML_PRIVATE_EXPORT void init(QV4::ExecutionContext *scope, QV4::String *name = nullptr); + Q_QML_PRIVATE_EXPORT void init(QV4::ExecutionContext *scope, QV4::Function *function, QV4::String *n = nullptr); + Q_QML_PRIVATE_EXPORT void init(QV4::ExecutionContext *scope, const QString &name); + Q_QML_PRIVATE_EXPORT void init(); + Q_QML_PRIVATE_EXPORT void destroy(); void setFunction(Function *f); @@ -260,7 +260,7 @@ struct FunctionPrototype: FunctionObject static ReturnedValue method_hasInstance(const FunctionObject *, const Value *thisObject, const Value *argv, int argc); }; -struct IndexedBuiltinFunction : FunctionObject +struct Q_QML_PRIVATE_EXPORT IndexedBuiltinFunction : FunctionObject { V4_OBJECT2(IndexedBuiltinFunction, FunctionObject) }; diff --git a/src/qml/jsruntime/qv4global_p.h b/src/qml/jsruntime/qv4global_p.h index d47393b3bb..42b6edb6e2 100644 --- a/src/qml/jsruntime/qv4global_p.h +++ b/src/qml/jsruntime/qv4global_p.h @@ -82,53 +82,9 @@ inline bool isfinite(double d) { return _finite(d); } inline double trunc(double d) { return d > 0 ? floor(d) : ceil(d); } #endif -// Decide whether to enable or disable the JIT - -// White list architectures -// -// NOTE: This should match the logic in qv4targetplatform_p.h! - -#if defined(Q_PROCESSOR_X86_32) && (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) && (QT_POINTER_SIZE == 8) \ - && (defined(Q_OS_WIN) || defined(Q_OS_LINUX) || defined(Q_OS_QNX) || defined(Q_OS_MAC) || defined(Q_OS_FREEBSD)) -# define V4_ENABLE_JIT -#elif defined(Q_PROCESSOR_ARM_32) && (QT_POINTER_SIZE == 4) \ - && (defined(Q_OS_LINUX) || defined(Q_OS_QNX) || defined(Q_OS_FREEBSD) || defined(Q_OS_INTEGRITY)) -# 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) && (QT_POINTER_SIZE == 8) -# if defined(Q_OS_LINUX) || defined(Q_OS_QNX) || defined(Q_OS_INTEGRITY) -# define V4_ENABLE_JIT -# endif -//#elif defined(Q_PROCESSOR_MIPS_32) && defined(Q_OS_LINUX) -//# define V4_ENABLE_JIT -#endif - -// check FPU with double precision on ARM platform -#if (defined(Q_PROCESSOR_ARM_64) || defined(Q_PROCESSOR_ARM_32)) && defined(V4_ENABLE_JIT) && defined(__ARM_FP) && (__ARM_FP <= 0x04) -# undef V4_ENABLE_JIT -#endif - -// Black list some platforms -#if defined(V4_ENABLE_JIT) -#if defined(Q_OS_IOS) || defined(Q_OS_TVOS) -# undef V4_ENABLE_JIT -#endif -#endif - -// For debug purposes: add CONFIG+=force-compile-jit to qmake's command-line to always compile the JIT. -#if defined(V4_FORCE_COMPILE_JIT) && !defined(V4_ENABLE_JIT) -# define V4_ENABLE_JIT -#endif - // Do certain things depending on whether the JIT is enabled or disabled -#ifdef V4_ENABLE_JIT +#if QT_CONFIG(qml_jit) #define ENABLE_YARR_JIT 1 #define ENABLE_JIT 1 #define ENABLE_ASSEMBLER 1 @@ -280,20 +236,6 @@ struct IdentifierTable; class RegExpCache; class MultiplyWrappedQObjectMap; -enum class ObservedTraceValues : quint8 { - Integer = 1 << 0, - Boolean = 1 << 1, - Double = 1 << 2, - Other = 1 << 3, - TypeMask = Integer | Boolean | Double | Other, - - TruePathTaken = 1 << 0, - FalsePathTaken = 1 << 1, - - ArrayWasAccessed = 1 << 7, - ArrayAccessNeededFallback = 1 << 6, -}; - enum PropertyFlag { Attr_Data = 0, Attr_Accessor = 0x1, diff --git a/src/qml/jsruntime/qv4identifier.cpp b/src/qml/jsruntime/qv4identifier.cpp index 5db5bd46ec..f9bc7b68c6 100644 --- a/src/qml/jsruntime/qv4identifier.cpp +++ b/src/qml/jsruntime/qv4identifier.cpp @@ -39,29 +39,19 @@ #include "qv4identifier_p.h" #include "qv4identifiertable_p.h" #include "qv4string_p.h" +#include <private/qprimefornumbits_p.h> QT_BEGIN_NAMESPACE namespace QV4 { -static const uchar prime_deltas[] = { - 0, 0, 1, 3, 1, 5, 3, 3, 1, 9, 7, 5, 3, 9, 25, 3, - 1, 21, 3, 21, 7, 15, 9, 5, 3, 29, 15, 0, 0, 0, 0, 0 -}; - -static inline int primeForNumBits(int numBits) -{ - return (1 << numBits) + prime_deltas[numBits]; -} - - IdentifierHashData::IdentifierHashData(IdentifierTable *table, int numBits) : size(0) , numBits(numBits) , identifierTable(table) { refCount.store(1); - alloc = primeForNumBits(numBits); + alloc = qPrimeForNumBits(numBits); entries = (IdentifierHashEntry *)malloc(alloc*sizeof(IdentifierHashEntry)); memset(entries, 0, alloc*sizeof(IdentifierHashEntry)); identifierTable->addIdentifierHash(this); @@ -110,7 +100,7 @@ IdentifierHashEntry *IdentifierHash::addEntry(PropertyKey identifier) if (grow) { ++d->numBits; - int newAlloc = primeForNumBits(d->numBits); + int newAlloc = qPrimeForNumBits(d->numBits); IdentifierHashEntry *newEntries = (IdentifierHashEntry *)malloc(newAlloc * sizeof(IdentifierHashEntry)); memset(newEntries, 0, newAlloc*sizeof(IdentifierHashEntry)); for (int i = 0; i < d->alloc; ++i) { diff --git a/src/qml/jsruntime/qv4identifiertable.cpp b/src/qml/jsruntime/qv4identifiertable.cpp index 4305bc4647..21b47c3909 100644 --- a/src/qml/jsruntime/qv4identifiertable.cpp +++ b/src/qml/jsruntime/qv4identifiertable.cpp @@ -38,28 +38,18 @@ ****************************************************************************/ #include "qv4identifiertable_p.h" #include "qv4symbol_p.h" +#include <private/qprimefornumbits_p.h> QT_BEGIN_NAMESPACE namespace QV4 { -static const uchar prime_deltas[] = { - 0, 0, 1, 3, 1, 5, 3, 3, 1, 9, 7, 5, 3, 9, 25, 3, - 1, 21, 3, 21, 7, 15, 9, 5, 3, 29, 15, 0, 0, 0, 0, 0 -}; - -static inline int primeForNumBits(int numBits) -{ - return (1 << numBits) + prime_deltas[numBits]; -} - - IdentifierTable::IdentifierTable(ExecutionEngine *engine, int numBits) : engine(engine) , size(0) , numBits(numBits) { - alloc = primeForNumBits(numBits); + alloc = qPrimeForNumBits(numBits); entriesByHash = (Heap::StringOrSymbol **)malloc(alloc*sizeof(Heap::StringOrSymbol *)); entriesById = (Heap::StringOrSymbol **)malloc(alloc*sizeof(Heap::StringOrSymbol *)); memset(entriesByHash, 0, alloc*sizeof(Heap::String *)); @@ -87,7 +77,7 @@ void IdentifierTable::addEntry(Heap::StringOrSymbol *str) if (grow) { ++numBits; - int newAlloc = primeForNumBits(numBits); + int newAlloc = qPrimeForNumBits(numBits); Heap::StringOrSymbol **newEntries = (Heap::StringOrSymbol **)malloc(newAlloc*sizeof(Heap::String *)); memset(newEntries, 0, newAlloc*sizeof(Heap::StringOrSymbol *)); for (uint i = 0; i < alloc; ++i) { @@ -216,9 +206,8 @@ PropertyKey IdentifierTable::asPropertyKeyImpl(const Heap::String *str) Heap::StringOrSymbol *IdentifierTable::resolveId(PropertyKey i) const { - uint arrayIdx = i.asArrayIndex(); - if (arrayIdx < UINT_MAX) - return engine->newString(QString::number(arrayIdx)); + if (i.isArrayIndex()) + return engine->newString(QString::number(i.asArrayIndex())); if (!i.isValid()) return nullptr; diff --git a/src/qml/jsruntime/qv4include.cpp b/src/qml/jsruntime/qv4include.cpp index 36569b0a60..c0885a418c 100644 --- a/src/qml/jsruntime/qv4include.cpp +++ b/src/qml/jsruntime/qv4include.cpp @@ -72,13 +72,17 @@ QV4Include::QV4Include(const QUrl &url, QV4::ExecutionEngine *engine, m_resultObject.set(v4, resultValue(v4)); #if QT_CONFIG(qml_network) - m_network = engine->v8Engine->networkAccessManager(); + if (QQmlEngine *qmlEngine = engine->qmlEngine()) { + m_network = qmlEngine->networkAccessManager(); - QNetworkRequest request; - request.setUrl(url); + QNetworkRequest request; + request.setUrl(url); - m_reply = m_network->get(request); - QObject::connect(m_reply, SIGNAL(finished()), this, SLOT(finished())); + m_reply = m_network->get(request); + QObject::connect(m_reply, SIGNAL(finished()), this, SLOT(finished())); + } else { + finished(); + } #else finished(); #endif @@ -197,7 +201,7 @@ void QV4Include::finished() } /* - Documented in qv8engine.cpp + Documented in qv4engine.cpp */ QV4::ReturnedValue QV4Include::method_include(const QV4::FunctionObject *b, const QV4::Value *, const QV4::Value *argv, int argc) { @@ -214,7 +218,6 @@ QV4::ReturnedValue QV4Include::method_include(const QV4::FunctionObject *b, cons if (argc >= 2 && argv[1].as<QV4::FunctionObject>()) callbackFunction = argv[1]; -#if QT_CONFIG(qml_network) QUrl url(scope.engine->resolvedUrl(argv[0].toQStringNoThrow())); if (scope.engine->qmlEngine() && scope.engine->qmlEngine()->urlInterceptor()) url = scope.engine->qmlEngine()->urlInterceptor()->intercept(url, QQmlAbstractUrlInterceptor::JavaScriptFile); @@ -225,9 +228,13 @@ QV4::ReturnedValue QV4Include::method_include(const QV4::FunctionObject *b, cons QV4::Scoped<QV4::QmlContext> qmlcontext(scope, scope.engine->qmlContext()); if (localFile.isEmpty()) { +#if QT_CONFIG(qml_network) QV4Include *i = new QV4Include(url, scope.engine, qmlcontext, callbackFunction); result = i->result(); - +#else + result = resultValue(scope.engine, NetworkError); + callback(callbackFunction, result); +#endif } else { QScopedPointer<QV4::Script> script; QString error; @@ -252,12 +259,6 @@ QV4::ReturnedValue QV4Include::method_include(const QV4::FunctionObject *b, cons callback(callbackFunction, result); } -#else - QV4::ScopedValue result(scope); - result = resultValue(scope.engine, NetworkError); - callback(callbackFunction, result); -#endif - return result->asReturnedValue(); } diff --git a/src/qml/jsruntime/qv4internalclass.cpp b/src/qml/jsruntime/qv4internalclass.cpp index a10fda79f2..d597335031 100644 --- a/src/qml/jsruntime/qv4internalclass.cpp +++ b/src/qml/jsruntime/qv4internalclass.cpp @@ -45,27 +45,18 @@ #include "qv4identifiertable_p.h" #include "qv4value_p.h" #include "qv4mm_p.h" +#include <private/qprimefornumbits_p.h> QT_BEGIN_NAMESPACE namespace QV4 { -static const uchar prime_deltas[] = { - 0, 0, 1, 3, 1, 5, 3, 3, 1, 9, 7, 5, 3, 9, 25, 3, - 1, 21, 3, 21, 7, 15, 9, 5, 3, 29, 15, 0, 0, 0, 0, 0 -}; - -static inline int primeForNumBits(int numBits) -{ - return (1 << numBits) + prime_deltas[numBits]; -} - PropertyHashData::PropertyHashData(int numBits) : refCount(1) , size(0) , numBits(numBits) { - alloc = primeForNumBits(numBits); + alloc = qPrimeForNumBits(numBits); entries = (PropertyHash::Entry *)malloc(alloc*sizeof(PropertyHash::Entry)); memset(entries, 0, alloc*sizeof(PropertyHash::Entry)); } diff --git a/src/qml/jsruntime/qv4lookup.cpp b/src/qml/jsruntime/qv4lookup.cpp index f8999342d1..99f425293e 100644 --- a/src/qml/jsruntime/qv4lookup.cpp +++ b/src/qml/jsruntime/qv4lookup.cpp @@ -462,11 +462,11 @@ bool Lookup::setterTwoClasses(Lookup *l, ExecutionEngine *engine, Value &object, return false; } - if (l->setter == Lookup::setter0 || l->setter == Lookup::setter0Inline) { + if (l->setter == Lookup::setter0MemberData || l->setter == Lookup::setter0Inline) { l->objectLookupTwoClasses.ic = first.objectLookup.ic; l->objectLookupTwoClasses.ic2 = second.objectLookup.ic; - l->objectLookupTwoClasses.offset = first.objectLookup.offset; - l->objectLookupTwoClasses.offset2 = second.objectLookup.offset; + l->objectLookupTwoClasses.offset = first.objectLookup.index; + l->objectLookupTwoClasses.offset2 = second.objectLookup.index; l->setter = setter0setter0; return true; } @@ -487,11 +487,11 @@ bool Lookup::setterFallback(Lookup *l, ExecutionEngine *engine, Value &object, c return o->put(name, value); } -bool Lookup::setter0(Lookup *l, ExecutionEngine *engine, Value &object, const Value &value) +bool Lookup::setter0MemberData(Lookup *l, ExecutionEngine *engine, Value &object, const Value &value) { Heap::Object *o = static_cast<Heap::Object *>(object.heapObject()); if (o && o->internalClass == l->objectLookup.ic) { - o->setProperty(engine, l->objectLookup.offset, value); + o->memberData->values.set(engine, l->objectLookup.offset, value); return true; } @@ -502,7 +502,7 @@ bool Lookup::setter0Inline(Lookup *l, ExecutionEngine *engine, Value &object, co { Heap::Object *o = static_cast<Heap::Object *>(object.heapObject()); if (o && o->internalClass == l->objectLookup.ic) { - o->setInlineProperty(engine, l->objectLookup.offset, value); + o->setInlinePropertyWithOffset(engine, l->objectLookup.offset, value); return true; } diff --git a/src/qml/jsruntime/qv4lookup_p.h b/src/qml/jsruntime/qv4lookup_p.h index 03dc5f6d3c..f2e0afd797 100644 --- a/src/qml/jsruntime/qv4lookup_p.h +++ b/src/qml/jsruntime/qv4lookup_p.h @@ -64,7 +64,7 @@ QT_BEGIN_NAMESPACE namespace QV4 { -struct Lookup { +struct Q_QML_PRIVATE_EXPORT Lookup { union { ReturnedValue (*getter)(Lookup *l, ExecutionEngine *engine, const Value &object); ReturnedValue (*globalGetter)(Lookup *l, ExecutionEngine *engine); @@ -81,8 +81,9 @@ struct Lookup { } markDef; struct { Heap::InternalClass *ic; - quintptr _unused; - int offset; + quintptr unused; + uint index; + uint offset; } objectLookup; struct { quintptr protoId; @@ -92,8 +93,8 @@ struct Lookup { struct { Heap::InternalClass *ic; Heap::InternalClass *ic2; - int offset; - int offset2; + uint offset; + uint offset2; } objectLookupTwoClasses; struct { quintptr protoId; @@ -111,12 +112,14 @@ struct Lookup { struct { Heap::InternalClass *newClass; quintptr protoId; - int offset; + uint offset; + uint unused; } insertionLookup; struct { quintptr _unused; quintptr _unused2; uint index; + uint unused; } indexedLookup; struct { Heap::InternalClass *ic; @@ -187,7 +190,7 @@ struct Lookup { static bool setterGeneric(Lookup *l, ExecutionEngine *engine, Value &object, const Value &value); Q_NEVER_INLINE static bool setterTwoClasses(Lookup *l, ExecutionEngine *engine, Value &object, const Value &value); static bool setterFallback(Lookup *l, ExecutionEngine *engine, Value &object, const Value &value); - static bool setter0(Lookup *l, ExecutionEngine *engine, Value &object, const Value &value); + static bool setter0MemberData(Lookup *l, ExecutionEngine *engine, Value &object, const Value &value); static bool setter0Inline(Lookup *l, ExecutionEngine *engine, Value &object, const Value &value); static bool setter0setter0(Lookup *l, ExecutionEngine *engine, Value &object, const Value &value); static bool setterInsert(Lookup *l, ExecutionEngine *engine, Value &object, const Value &value); diff --git a/src/qml/jsruntime/qv4managed_p.h b/src/qml/jsruntime/qv4managed_p.h index d85b30a056..4f22dc7330 100644 --- a/src/qml/jsruntime/qv4managed_p.h +++ b/src/qml/jsruntime/qv4managed_p.h @@ -54,7 +54,6 @@ #include "qv4value_p.h" #include "qv4enginebase_p.h" #include <private/qv4heap_p.h> -#include <private/qv4writebarrier_p.h> #include <private/qv4vtable_p.h> QT_BEGIN_NAMESPACE diff --git a/src/qml/jsruntime/qv4mapobject.cpp b/src/qml/jsruntime/qv4mapobject.cpp index 68741e7677..90e1908a84 100644 --- a/src/qml/jsruntime/qv4mapobject.cpp +++ b/src/qml/jsruntime/qv4mapobject.cpp @@ -80,7 +80,7 @@ ReturnedValue WeakMapCtor::construct(const FunctionObject *f, const Value *argv, if (!adder) return scope.engine->throwTypeError(); - ScopedObject iter(scope, Runtime::method_getIterator(scope.engine, iterable, true)); + ScopedObject iter(scope, Runtime::GetIterator::call(scope.engine, iterable, true)); if (scope.hasException()) return Encode::undefined(); Q_ASSERT(iter); @@ -89,7 +89,7 @@ ReturnedValue WeakMapCtor::construct(const FunctionObject *f, const Value *argv, Value *arguments = scope.alloc(2); ScopedValue done(scope); forever { - done = Runtime::method_iteratorNext(scope.engine, iter, obj); + done = Runtime::IteratorNext::call(scope.engine, iter, obj); if (scope.hasException()) break; if (done->toBoolean()) @@ -112,7 +112,7 @@ ReturnedValue WeakMapCtor::construct(const FunctionObject *f, const Value *argv, break; } ScopedValue falsey(scope, Encode(false)); - return Runtime::method_iteratorClose(scope.engine, iter, falsey); + return Runtime::IteratorClose::call(scope.engine, iter, falsey); } } return a->asReturnedValue(); diff --git a/src/qml/jsruntime/qv4math_p.h b/src/qml/jsruntime/qv4math_p.h index a60a49a811..90246c4229 100644 --- a/src/qml/jsruntime/qv4math_p.h +++ b/src/qml/jsruntime/qv4math_p.h @@ -66,42 +66,27 @@ QT_BEGIN_NAMESPACE namespace QV4 { -static inline QMLJS_READONLY ReturnedValue add_int32(int a, int b, quint8 *traceInfo = nullptr) +static inline QMLJS_READONLY ReturnedValue add_int32(int a, int b) { int result; - if (Q_UNLIKELY(add_overflow(a, b, &result))) { - if (traceInfo) - *traceInfo |= quint8(QV4::ObservedTraceValues::Double); + if (Q_UNLIKELY(add_overflow(a, b, &result))) return Value::fromDouble(static_cast<double>(a) + b).asReturnedValue(); - } - if (traceInfo) - *traceInfo |= quint8(QV4::ObservedTraceValues::Integer); return Value::fromInt32(result).asReturnedValue(); } -static inline QMLJS_READONLY ReturnedValue sub_int32(int a, int b, quint8 *traceInfo = nullptr) +static inline QMLJS_READONLY ReturnedValue sub_int32(int a, int b) { int result; - if (Q_UNLIKELY(sub_overflow(a, b, &result))) { - if (traceInfo) - *traceInfo |= quint8(QV4::ObservedTraceValues::Double); + if (Q_UNLIKELY(sub_overflow(a, b, &result))) return Value::fromDouble(static_cast<double>(a) - b).asReturnedValue(); - } - if (traceInfo) - *traceInfo |= quint8(QV4::ObservedTraceValues::Integer); return Value::fromInt32(result).asReturnedValue(); } -static inline QMLJS_READONLY ReturnedValue mul_int32(int a, int b, quint8 *traceInfo = nullptr) +static inline QMLJS_READONLY ReturnedValue mul_int32(int a, int b) { int result; - if (Q_UNLIKELY(mul_overflow(a, b, &result))) { - if (traceInfo) - *traceInfo |= quint8(QV4::ObservedTraceValues::Double); + if (Q_UNLIKELY(mul_overflow(a, b, &result))) return Value::fromDouble(static_cast<double>(a) * b).asReturnedValue(); - } - if (traceInfo) - *traceInfo |= quint8(QV4::ObservedTraceValues::Integer); return Value::fromInt32(result).asReturnedValue(); } diff --git a/src/qml/jsruntime/qv4object.cpp b/src/qml/jsruntime/qv4object.cpp index 02524b7da6..89161433ed 100644 --- a/src/qml/jsruntime/qv4object.cpp +++ b/src/qml/jsruntime/qv4object.cpp @@ -407,8 +407,8 @@ ReturnedValue Object::internalGet(PropertyKey id, const Value *receiver, bool *h { Heap::Object *o = d(); - uint index = id.asArrayIndex(); - if (index != UINT_MAX) { + if (id.isArrayIndex()) { + const uint index = id.asArrayIndex(); Scope scope(this); PropertyAttributes attrs; ScopedProperty pd(scope); @@ -432,8 +432,6 @@ ReturnedValue Object::internalGet(PropertyKey id, const Value *receiver, bool *h break; } } else { - Q_ASSERT(!id.isArrayIndex()); - while (1) { auto idx = o->internalClass->findValueOrGetter(id); if (idx.isValid()) { @@ -471,14 +469,13 @@ bool Object::internalPut(PropertyKey id, const Value &value, Value *receiver) if (d()->internalClass->vtable->getOwnProperty == Object::virtualGetOwnProperty) { // This object standard methods in the vtable, so we can take a shortcut // and avoid the calls to getOwnProperty and defineOwnProperty - uint index = id.asArrayIndex(); PropertyAttributes attrs; PropertyIndex propertyIndex{nullptr, nullptr}; - if (index != UINT_MAX) { + if (id.isArrayIndex()) { if (arrayData()) - propertyIndex = arrayData()->getValueOrSetter(index, &attrs); + propertyIndex = arrayData()->getValueOrSetter(id.asArrayIndex(), &attrs); } else { auto member = internalClass()->findValueOrSetter(id); if (member.isValid()) { @@ -547,12 +544,11 @@ bool Object::internalPut(PropertyKey id, const Value &value, Value *receiver) if (r->internalClass()->vtable->defineOwnProperty == virtualDefineOwnProperty) { // standard object, we can avoid some more checks - uint index = id.asArrayIndex(); - if (index == UINT_MAX) { + if (id.isArrayIndex()) { + r->arraySet(id.asArrayIndex(), value); + } else { ScopedStringOrSymbol s(scope, id.asStringOrSymbol()); r->insertMember(s, value); - } else { - r->arraySet(index, value); } return true; } @@ -787,8 +783,15 @@ bool Object::virtualResolveLookupSetter(Object *object, ExecutionEngine *engine, return lookup->setter(lookup, engine, *object, value); } else if (idx.attrs.isData() && idx.attrs.isWritable()) { lookup->objectLookup.ic = object->internalClass(); - lookup->objectLookup.offset = idx.index; - lookup->setter = idx.index < object->d()->vtable()->nInlineProperties ? Lookup::setter0Inline : Lookup::setter0; + lookup->objectLookup.index = idx.index; + const auto nInline = object->d()->vtable()->nInlineProperties; + if (idx.index < nInline) { + lookup->setter = Lookup::setter0Inline; + lookup->objectLookup.offset = idx.index + object->d()->vtable()->inlinePropertyOffset; + } else { + lookup->setter = Lookup::setter0MemberData; + lookup->objectLookup.offset = idx.index - nInline; + } return lookup->setter(lookup, engine, *object, value); } else { // ### handle setter diff --git a/src/qml/jsruntime/qv4object_p.h b/src/qml/jsruntime/qv4object_p.h index bee4aadafe..52ad3ea319 100644 --- a/src/qml/jsruntime/qv4object_p.h +++ b/src/qml/jsruntime/qv4object_p.h @@ -79,21 +79,21 @@ DECLARE_EXPORTED_HEAP_OBJECT(Object, Base) { } const Value *inlinePropertyDataWithOffset(uint indexWithOffset) const { - Q_ASSERT(indexWithOffset >= vtable()->inlinePropertyOffset && indexWithOffset < vtable()->inlinePropertyOffset + vtable()->nInlineProperties); + Q_ASSERT(indexWithOffset >= vtable()->inlinePropertyOffset && indexWithOffset < uint(vtable()->inlinePropertyOffset + vtable()->nInlineProperties)); return reinterpret_cast<const Value *>(this) + indexWithOffset; } const Value *inlinePropertyData(uint index) const { Q_ASSERT(index < vtable()->nInlineProperties); return reinterpret_cast<const Value *>(this) + vtable()->inlinePropertyOffset + index; } - void setInlineProperty(ExecutionEngine *e, uint index, Value v) { - Q_ASSERT(index < vtable()->nInlineProperties); - Value *prop = reinterpret_cast<Value *>(this) + vtable()->inlinePropertyOffset + index; + void setInlinePropertyWithOffset(ExecutionEngine *e, uint indexWithOffset, Value v) { + Q_ASSERT(indexWithOffset >= vtable()->inlinePropertyOffset && indexWithOffset < uint(vtable()->inlinePropertyOffset + vtable()->nInlineProperties)); + Value *prop = reinterpret_cast<Value *>(this) + indexWithOffset; WriteBarrier::write(e, this, prop->data_ptr(), v.asReturnedValue()); } - void setInlineProperty(ExecutionEngine *e, uint index, Heap::Base *b) { - Q_ASSERT(index < vtable()->nInlineProperties); - Value *prop = reinterpret_cast<Value *>(this) + vtable()->inlinePropertyOffset + index; + void setInlinePropertyWithOffset(ExecutionEngine *e, uint indexWithOffset, Heap::Base *b) { + Q_ASSERT(indexWithOffset >= vtable()->inlinePropertyOffset && indexWithOffset < uint(vtable()->inlinePropertyOffset + vtable()->nInlineProperties)); + Value *prop = reinterpret_cast<Value *>(this) + indexWithOffset; WriteBarrier::write(e, this, prop->data_ptr(), Value::fromHeapObject(b).asReturnedValue()); } @@ -115,7 +115,7 @@ DECLARE_EXPORTED_HEAP_OBJECT(Object, Base) { void setProperty(ExecutionEngine *e, uint index, Value v) { uint nInline = vtable()->nInlineProperties; if (index < nInline) { - setInlineProperty(e, index, v); + setInlinePropertyWithOffset(e, index + vtable()->inlinePropertyOffset, v); return; } index -= nInline; @@ -124,7 +124,7 @@ DECLARE_EXPORTED_HEAP_OBJECT(Object, Base) { void setProperty(ExecutionEngine *e, uint index, Heap::Base *b) { uint nInline = vtable()->nInlineProperties; if (index < nInline) { - setInlineProperty(e, index, b); + setInlinePropertyWithOffset(e, index + vtable()->inlinePropertyOffset, b); return; } index -= nInline; @@ -410,7 +410,7 @@ private: friend struct ObjectPrototype; }; -struct ObjectOwnPropertyKeyIterator : OwnPropertyKeyIterator +struct Q_QML_PRIVATE_EXPORT ObjectOwnPropertyKeyIterator : OwnPropertyKeyIterator { uint arrayIndex = 0; uint memberIndex = 0; diff --git a/src/qml/jsruntime/qv4objectproto_p.h b/src/qml/jsruntime/qv4objectproto_p.h index e9515b5b68..8707305dc2 100644 --- a/src/qml/jsruntime/qv4objectproto_p.h +++ b/src/qml/jsruntime/qv4objectproto_p.h @@ -74,7 +74,7 @@ struct ObjectCtor: FunctionObject static ReturnedValue virtualCall(const FunctionObject *m, const Value *thisObject, const Value *argv, int argc); }; -struct ObjectPrototype: Object +struct Q_QML_PRIVATE_EXPORT ObjectPrototype: Object { void init(ExecutionEngine *engine, Object *ctor); diff --git a/src/qml/jsruntime/qv4promiseobject.cpp b/src/qml/jsruntime/qv4promiseobject.cpp index 8450655334..b32e227b58 100644 --- a/src/qml/jsruntime/qv4promiseobject.cpp +++ b/src/qml/jsruntime/qv4promiseobject.cpp @@ -496,7 +496,7 @@ ReturnedValue PromiseCtor::method_all(const FunctionObject *f, const Value *this ScopedFunctionObject reject(scope, capability->d()->reject); ScopedObject itemsObject(scope, argv); - ScopedObject iteratorObject(scope, Runtime::method_getIterator(e, itemsObject, true)); + ScopedObject iteratorObject(scope, Runtime::GetIterator::call(e, itemsObject, true)); if (!iteratorObject || scope.hasException()) { ScopedObject error(scope); if (scope.hasException()) { @@ -521,7 +521,7 @@ ReturnedValue PromiseCtor::method_all(const FunctionObject *f, const Value *this for (;;) { Scope scope(e); ScopedValue nextValue(scope); - doneValue = Value::fromReturnedValue(Runtime::method_iteratorNext(e, iteratorObject, nextValue)); + doneValue = Value::fromReturnedValue(Runtime::IteratorNext::call(e, iteratorObject, nextValue)); if (doneValue->toBoolean()) break; @@ -549,7 +549,7 @@ ReturnedValue PromiseCtor::method_all(const FunctionObject *f, const Value *this } if (!doneValue->toBoolean()) - completion = Runtime::method_iteratorClose(e, iteratorObject, doneValue); + completion = Runtime::IteratorClose::call(e, iteratorObject, doneValue); reject->call(newPromise, completion, 1); return newPromise.asReturnedValue(); @@ -557,7 +557,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()) { - ScopedValue completion(scope, Runtime::method_iteratorClose(e, iteratorObject, doneValue)); + ScopedValue completion(scope, Runtime::IteratorClose::call(e, iteratorObject, doneValue)); if (scope.hasException()) { completion = e->exceptionValue->asReturnedValue(); dropException(e); @@ -579,7 +579,7 @@ ReturnedValue PromiseCtor::method_all(const FunctionObject *f, const Value *this } if (!doneValue->toBoolean()) - completion = Runtime::method_iteratorClose(scope.engine, iteratorObject, doneValue); + completion = Runtime::IteratorClose::call(scope.engine, iteratorObject, doneValue); reject->call(newPromise, completion, 1); return newPromise.asReturnedValue(); @@ -598,7 +598,7 @@ ReturnedValue PromiseCtor::method_all(const FunctionObject *f, const Value *this dropException(e); if (!doneValue->toBoolean()) - completion = Runtime::method_iteratorClose(scope.engine, iteratorObject, doneValue); + completion = Runtime::IteratorClose::call(scope.engine, iteratorObject, doneValue); reject->call(newPromise, completion, 1); return newPromise.asReturnedValue(); @@ -646,7 +646,7 @@ ReturnedValue PromiseCtor::method_race(const FunctionObject *f, const Value *thi ScopedFunctionObject reject(scope, capability->d()->reject); ScopedObject itemsObject(scope, argv); - ScopedObject iteratorObject(scope, Runtime::method_getIterator(e, itemsObject, true)); + ScopedObject iteratorObject(scope, Runtime::GetIterator::call(e, itemsObject, true)); if (!iteratorObject) { ScopedObject error(scope, e->newTypeErrorObject(QStringLiteral("Type error"))); reject->call(newPromise, error, 1); @@ -657,10 +657,10 @@ ReturnedValue PromiseCtor::method_race(const FunctionObject *f, const Value *thi for (;;) { Scope scope(e); ScopedValue nextValue(scope); - doneValue = Value::fromReturnedValue(Runtime::method_iteratorNext(e, iteratorObject, nextValue)); + doneValue = Value::fromReturnedValue(Runtime::IteratorNext::call(e, iteratorObject, nextValue)); if (scope.hasException()) { - ScopedValue completion(scope, Runtime::method_iteratorClose(e, iteratorObject, doneValue)); + ScopedValue completion(scope, Runtime::IteratorClose::call(e, iteratorObject, doneValue)); if (scope.hasException()) { completion = e->exceptionValue->asReturnedValue(); dropException(e); @@ -695,7 +695,7 @@ ReturnedValue PromiseCtor::method_race(const FunctionObject *f, const Value *thi } if (!doneValue->toBoolean()) - completion = Runtime::method_iteratorClose(e, iteratorObject, doneValue); + completion = Runtime::IteratorClose::call(e, iteratorObject, doneValue); reject->call(newPromise, completion, 1); return newPromise.asReturnedValue(); @@ -703,7 +703,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()) { - ScopedValue completion(scope, Runtime::method_iteratorClose(e, iteratorObject, doneValue)); + ScopedValue completion(scope, Runtime::IteratorClose::call(e, iteratorObject, doneValue)); if (scope.hasException()) { completion = e->exceptionValue->asReturnedValue(); dropException(e); @@ -723,7 +723,7 @@ ReturnedValue PromiseCtor::method_race(const FunctionObject *f, const Value *thi } if (!doneValue->toBoolean()) - completion = Runtime::method_iteratorClose(e, iteratorObject, doneValue); + completion = Runtime::IteratorClose::call(e, iteratorObject, doneValue); reject->call(newPromise, completion, 1); return newPromise.asReturnedValue(); @@ -742,7 +742,7 @@ ReturnedValue PromiseCtor::method_race(const FunctionObject *f, const Value *thi dropException(e); if (!doneValue->toBoolean()) - completion = Runtime::method_iteratorClose(e, iteratorObject, doneValue); + completion = Runtime::IteratorClose::call(e, iteratorObject, doneValue); reject->call(newPromise, completion, 1); return newPromise.asReturnedValue(); diff --git a/src/qml/jsruntime/qv4propertykey_p.h b/src/qml/jsruntime/qv4propertykey_p.h index 47867765db..b2a2ec3dea 100644 --- a/src/qml/jsruntime/qv4propertykey_p.h +++ b/src/qml/jsruntime/qv4propertykey_p.h @@ -113,8 +113,8 @@ public: static PropertyKey invalid() { PropertyKey key; key.val = 0; return key; } static PropertyKey fromArrayIndex(uint idx) { PropertyKey key; key.val = ArrayIndexMask | static_cast<quint64>(idx); return key; } bool isStringOrSymbol() const { return isManaged() && val != 0; } - uint asArrayIndex() const { return (isManaged() || val == 0) ? std::numeric_limits<uint>::max() : static_cast<uint>(val & 0xffffffff); } - uint isArrayIndex() const { return !isManaged() && val != 0 && static_cast<uint>(val & 0xffffffff) != std::numeric_limits<uint>::max(); } + uint asArrayIndex() const { Q_ASSERT(isArrayIndex()); return static_cast<uint>(val & 0xffffffff); } + uint isArrayIndex() const { return !isManaged() && val != 0; } bool isValid() const { return val != 0; } static PropertyKey fromStringOrSymbol(Heap::StringOrSymbol *b) { PropertyKey key; key.setM(b); return key; } @@ -124,7 +124,7 @@ public: return m(); } - bool isString() const; + Q_QML_EXPORT bool isString() const; bool isSymbol() const; bool isCanonicalNumericIndexString() const; diff --git a/src/qml/jsruntime/qv4qmlcontext.cpp b/src/qml/jsruntime/qv4qmlcontext.cpp index 0c5226d46c..f3351f6da0 100644 --- a/src/qml/jsruntime/qv4qmlcontext.cpp +++ b/src/qml/jsruntime/qv4qmlcontext.cpp @@ -38,7 +38,6 @@ ****************************************************************************/ #include "qv4qmlcontext_p.h" -#include <private/qv8engine_p.h> #include <private/qqmlengine_p.h> #include <private/qqmlcontext_p.h> @@ -232,17 +231,17 @@ ReturnedValue QQmlContextWrapper::getPropertyAndBase(const QQmlContextWrapper *r } else if (r.type.isValid()) { if (lookup) { if (r.type.isSingleton()) { - QQmlEngine *e = v4->qmlEngine(); - QQmlType::SingletonInstanceInfo *siinfo = r.type.singletonInstanceInfo(); - siinfo->init(e); - if (siinfo->qobjectApi(e)) { + QQmlEnginePrivate *e = QQmlEnginePrivate::get(v4->qmlEngine()); + if (r.type.isQObjectSingleton() || r.type.isCompositeSingleton()) { + e->singletonInstance<QObject*>(r.type); lookup->qmlContextSingletonLookup.singleton = static_cast<Heap::Object*>( Value::fromReturnedValue( QQmlTypeWrapper::create(v4, nullptr, r.type) ).heapObject()); } else { - QV4::ScopedObject o(scope, QJSValuePrivate::convertedToValue(v4, siinfo->scriptApi(e))); + QJSValue singleton = e->singletonInstance<QJSValue>(r.type); + QV4::ScopedObject o(scope, QJSValuePrivate::convertedToValue(v4, singleton)); lookup->qmlContextSingletonLookup.singleton = o->d(); } lookup->qmlContextPropertyGetter = QQmlContextWrapper::lookupSingleton; diff --git a/src/qml/jsruntime/qv4qobjectwrapper.cpp b/src/qml/jsruntime/qv4qobjectwrapper.cpp index 6fed538fa8..095f27279f 100644 --- a/src/qml/jsruntime/qv4qobjectwrapper.cpp +++ b/src/qml/jsruntime/qv4qobjectwrapper.cpp @@ -39,7 +39,7 @@ #include "qv4qobjectwrapper_p.h" -#include <private/qqmlpropertycache_p.h> +#include <private/qqmlstaticmetaobject_p.h> #include <private/qqmlengine_p.h> #include <private/qqmlvmemetaobject_p.h> #include <private/qqmlbinding_p.h> @@ -50,7 +50,6 @@ #include <private/qqmlvaluetypewrapper_p.h> #include <private/qqmllistwrapper_p.h> #include <private/qqmlbuiltinfunctions_p.h> -#include <private/qv8engine_p.h> #include <private/qv4arraybuffer_p.h> #include <private/qv4functionobject_p.h> @@ -165,10 +164,6 @@ static QV4::ReturnedValue loadProperty(QV4::ExecutionEngine *v4, QObject *object double v = 0; property.readProperty(object, &v); return QV4::Encode(v); - } else if (property.isV4Handle()) { - QQmlV4Handle handle; - property.readProperty(object, &handle); - return handle; } else if (property.propType() == qMetaTypeId<QJSValue>()) { QJSValue v; property.readProperty(object, &v); @@ -768,6 +763,8 @@ struct QObjectWrapperOwnPropertyKeyIterator : ObjectOwnPropertyKeyIterator ~QObjectWrapperOwnPropertyKeyIterator() override = default; PropertyKey next(const QV4::Object *o, Property *pd = nullptr, PropertyAttributes *attrs = nullptr) override; +private: + QSet<QByteArray> m_alreadySeen; }; PropertyKey QObjectWrapperOwnPropertyKeyIterator::next(const QV4::Object *o, Property *pd, PropertyAttributes *attrs) @@ -808,6 +805,11 @@ PropertyKey QObjectWrapperOwnPropertyKeyIterator::next(const QV4::Object *o, Pro ++propertyIndex; if (method.access() == QMetaMethod::Private || (preventDestruction && (index == deleteLaterIdx || index == destroyedIdx1 || index == destroyedIdx2))) continue; + // filter out duplicates due to overloads: + if (m_alreadySeen.contains(method.name())) + continue; + else + m_alreadySeen.insert(method.name()); ExecutionEngine *thatEngine = that->engine(); Scope scope(thatEngine); ScopedString methodName(scope, thatEngine->newString(QString::fromUtf8(method.name()))); @@ -1194,15 +1196,14 @@ DEFINE_OBJECT_VTABLE(QObjectWrapper); namespace { -template<typename A, typename B, typename C, typename D, typename E, - typename F, typename G, typename H> -class MaxSizeOf8 { +template<typename A, typename B, typename C, typename D, typename E, typename F, typename G> +class MaxSizeOf7 { template<typename Z, typename X> struct SMax { char dummy[sizeof(Z) > sizeof(X) ? sizeof(Z) : sizeof(X)]; }; public: - static const size_t Size = sizeof(SMax<A, SMax<B, SMax<C, SMax<D, SMax<E, SMax<F, SMax<G, H> > > > > > >); + static const size_t Size = sizeof(SMax<A, SMax<B, SMax<C, SMax<D, SMax<E, SMax<F, G> > > > > >); }; struct CallArgument { @@ -1235,14 +1236,13 @@ private: std::vector<QUrl> *stdVectorQUrlPtr; std::vector<QModelIndex> *stdVectorQModelIndexPtr; - char allocData[MaxSizeOf8<QVariant, - QString, - QList<QObject *>, - QJSValue, - QQmlV4Handle, - QJsonArray, - QJsonObject, - QJsonValue>::Size]; + char allocData[MaxSizeOf7<QVariant, + QString, + QList<QObject *>, + QJSValue, + QJsonArray, + QJsonObject, + QJsonValue>::Size]; qint64 q_for_alignment; }; @@ -1253,7 +1253,6 @@ private: QVariant *qvariantPtr; QList<QObject *> *qlistPtr; QJSValue *qjsValuePtr; - QQmlV4Handle *handlePtr; QJsonArray *jsonArrayPtr; QJsonObject *jsonObjectPtr; QJsonValue *jsonValuePtr; @@ -1384,6 +1383,9 @@ static int MatchScore(const QV4::Value &actual, int conversionType) } else if (actual.as<QV4::RegExpObject>()) { switch (conversionType) { case QMetaType::QRegExp: +#if QT_CONFIG(regularexpression) + case QMetaType::QRegularExpression: +#endif return 0; default: return 10; @@ -1722,9 +1724,6 @@ void CallArgument::initAsType(int callType) } else if (callType == qMetaTypeId<QList<QObject *> >()) { type = callType; qlistPtr = new (&allocData) QList<QObject *>(); - } else if (callType == qMetaTypeId<QQmlV4Handle>()) { - type = callType; - handlePtr = new (&allocData) QQmlV4Handle; } else if (callType == QMetaType::QJsonArray) { type = callType; jsonArrayPtr = new (&allocData) QJsonArray(); @@ -1825,9 +1824,6 @@ bool CallArgument::fromValue(int callType, QV4::ExecutionEngine *engine, const Q return false; } } - } else if (callType == qMetaTypeId<QQmlV4Handle>()) { - handlePtr = new (&allocData) QQmlV4Handle(value.asReturnedValue()); - type = callType; } else if (callType == QMetaType::QJsonArray) { QV4::ScopedArrayObject a(scope, value); jsonArrayPtr = new (&allocData) QJsonArray(QV4::JsonObject::toJsonArray(a)); @@ -1952,8 +1948,6 @@ QV4::ReturnedValue CallArgument::toValue(QV4::ExecutionEngine *engine) array->arrayPut(ii, (v = QV4::QObjectWrapper::wrap(scope.engine, list.at(ii)))); array->setArrayLengthUnchecked(list.count()); return array.asReturnedValue(); - } else if (type == qMetaTypeId<QQmlV4Handle>()) { - return *handlePtr; } else if (type == QMetaType::QJsonArray) { return QV4::JsonObject::fromJsonArray(scope.engine, *jsonArrayPtr); } else if (type == QMetaType::QJsonObject) { diff --git a/src/qml/jsruntime/qv4qobjectwrapper_p.h b/src/qml/jsruntime/qv4qobjectwrapper_p.h index 2558ede401..795bf241f2 100644 --- a/src/qml/jsruntime/qv4qobjectwrapper_p.h +++ b/src/qml/jsruntime/qv4qobjectwrapper_p.h @@ -55,9 +55,7 @@ #include <QtCore/qmetatype.h> #include <QtCore/qpair.h> #include <QtCore/qhash.h> -#include <private/qhashedstring_p.h> #include <private/qqmldata_p.h> -#include <private/qqmlpropertycache_p.h> #include <private/qintrusivelist_p.h> #include <private/qv4value_p.h> diff --git a/src/qml/jsruntime/qv4reflect.cpp b/src/qml/jsruntime/qv4reflect.cpp index 15dcb602eb..0772770d63 100644 --- a/src/qml/jsruntime/qv4reflect.cpp +++ b/src/qml/jsruntime/qv4reflect.cpp @@ -148,7 +148,7 @@ ReturnedValue Reflect::method_deleteProperty(const FunctionObject *f, const Valu if (!argc || !argv[0].isObject()) return e->throwTypeError(); - bool result = Runtime::method_deleteProperty(e, argv[0], argc > 1 ? argv[1] : Value::undefinedValue()); + bool result = Runtime::DeleteProperty_NoThrow::call(e, argv[0], argc > 1 ? argv[1] : Value::undefinedValue()); return Encode(result); } diff --git a/src/qml/jsruntime/qv4regexpobject.cpp b/src/qml/jsruntime/qv4regexpobject.cpp index 39a2e96b45..64aba1d85c 100644 --- a/src/qml/jsruntime/qv4regexpobject.cpp +++ b/src/qml/jsruntime/qv4regexpobject.cpp @@ -50,6 +50,9 @@ #include <QtCore/QDebug> #include <QtCore/qregexp.h> +#if QT_CONFIG(regularexpression) +#include <QtCore/qregularexpression.h> +#endif #include <cassert> #include <typeinfo> #include <iostream> @@ -134,6 +137,25 @@ void Heap::RegExpObject::init(const QRegExp &re) o->initProperties(); } +#if QT_CONFIG(regularexpression) +// Converts a QRegularExpression to a JS RegExp. +// The conversion is not 100% exact since ECMA regexp and QRegularExpression +// have different semantics/flags, but we try to do our best. +void Heap::RegExpObject::init(const QRegularExpression &re) +{ + Object::init(); + + Scope scope(internalClass->engine); + Scoped<QV4::RegExpObject> o(scope, this); + + const uint flags = (re.patternOptions() & QRegularExpression::CaseInsensitiveOption) + ? CompiledData::RegExp::RegExp_IgnoreCase + : CompiledData::RegExp::RegExp_NoFlags; + o->d()->value.set(scope.engine, QV4::RegExp::create(scope.engine, re.pattern(), flags)); + o->initProperties(); +} +#endif + void RegExpObject::initProperties() { setProperty(Index_LastIndex, Value::fromInt32(0)); @@ -150,6 +172,20 @@ QRegExp RegExpObject::toQRegExp() const return QRegExp(*value()->pattern, caseSensitivity, QRegExp::RegExp2); } +#if QT_CONFIG(regularexpression) +// Converts a JS RegExp to a QRegularExpression. +// The conversion is not 100% exact since ECMA regexp and QRegularExpression +// have different semantics/flags, but we try to do our best. +QRegularExpression RegExpObject::toQRegularExpression() const +{ + QRegularExpression::PatternOptions caseSensitivity + = (value()->flags & CompiledData::RegExp::RegExp_IgnoreCase) + ? QRegularExpression::CaseInsensitiveOption + : QRegularExpression::NoPatternOption; + return QRegularExpression(*value()->pattern, caseSensitivity); +} +#endif + QString RegExpObject::toString() const { QString p = *value()->pattern; @@ -162,13 +198,6 @@ QString RegExpObject::toString() const return p; } -QString RegExpObject::source() const -{ - Scope scope(engine()); - ScopedValue s(scope, get(scope.engine->id_source())); - return s->toQString(); -} - ReturnedValue RegExpObject::builtinExec(ExecutionEngine *engine, const String *str) { QString s = str->toQString(); diff --git a/src/qml/jsruntime/qv4regexpobject_p.h b/src/qml/jsruntime/qv4regexpobject_p.h index a584404c0b..b94889e9f0 100644 --- a/src/qml/jsruntime/qv4regexpobject_p.h +++ b/src/qml/jsruntime/qv4regexpobject_p.h @@ -81,6 +81,9 @@ DECLARE_HEAP_OBJECT(RegExpObject, Object) { void init(); void init(QV4::RegExp *value); void init(const QRegExp &re); +#if QT_CONFIG(regularexpression) + void init(const QRegularExpression &re); +#endif }; #define RegExpCtorMembers(class, Member) \ @@ -98,7 +101,7 @@ DECLARE_HEAP_OBJECT(RegExpCtor, FunctionObject) { } -struct RegExpObject: Object { +struct Q_QML_PRIVATE_EXPORT RegExpObject: Object { V4_OBJECT2(RegExpObject, Object) Q_MANAGED_TYPE(RegExpObject) V4_INTERNALCLASS(RegExpObject) @@ -138,8 +141,16 @@ struct RegExpObject: Object { } QRegExp toQRegExp() const; +#if QT_CONFIG(regularexpression) + QRegularExpression toQRegularExpression() const; +#endif QString toString() const; - QString source() const; + QString source() const + { + Scope scope(engine()); + ScopedValue s(scope, get(scope.engine->id_source())); + return s->toQString(); + } Heap::RegExp *value() const { return d()->value; } uint flags() const { return d()->value->flags; } diff --git a/src/qml/jsruntime/qv4runtime.cpp b/src/qml/jsruntime/qv4runtime.cpp index f7c339dc26..107dfbda6f 100644 --- a/src/qml/jsruntime/qv4runtime.cpp +++ b/src/qml/jsruntime/qv4runtime.cpp @@ -38,9 +38,9 @@ ****************************************************************************/ #include "qv4global_p.h" -#include "qv4engine_p.h" #include "qv4runtime_p.h" #ifndef V4_BOOTSTRAP +#include "qv4engine_p.h" #include "qv4object_p.h" #include "qv4objectproto_p.h" #include "qv4globalobject_p.h" @@ -63,7 +63,6 @@ #include "qv4qobjectwrapper_p.h" #include "qv4symbol_p.h" #include "qv4generatorobject_p.h" -#include <private/qv8engine_p.h> #endif #include <QtCore/QDebug> @@ -225,13 +224,6 @@ void RuntimeCounters::count(const char *func, uint tag1, uint tag2) #ifndef V4_BOOTSTRAP -Runtime::Runtime() -{ -#define INIT_METHOD(returnvalue, name, args) runtimeMethods[name] = reinterpret_cast<void*>(&method_##name); -FOR_EACH_RUNTIME_METHOD(INIT_METHOD) -#undef INIT_METHOD -} - void RuntimeHelpers::numberToString(QString *result, double num, int radix) { Q_ASSERT(result); @@ -320,7 +312,7 @@ void RuntimeHelpers::numberToString(QString *result, double num, int radix) result->prepend(QLatin1Char('-')); } -ReturnedValue Runtime::method_closure(ExecutionEngine *engine, int functionId) +ReturnedValue Runtime::Closure::call(ExecutionEngine *engine, int functionId) { QV4::Function *clos = static_cast<CompiledData::CompilationUnit*>(engine->currentStackFrame->v4Function->compilationUnit)->runtimeFunctions[functionId]; Q_ASSERT(clos); @@ -330,7 +322,7 @@ ReturnedValue Runtime::method_closure(ExecutionEngine *engine, int functionId) return FunctionObject::createScriptFunction(current, clos)->asReturnedValue(); } -bool Runtime::method_deleteProperty(ExecutionEngine *engine, const Value &base, const Value &index) +Bool Runtime::DeleteProperty_NoThrow::call(ExecutionEngine *engine, const Value &base, const Value &index) { Scope scope(engine); ScopedObject o(scope, base.toObject(engine)); @@ -344,14 +336,36 @@ bool Runtime::method_deleteProperty(ExecutionEngine *engine, const Value &base, return o->deleteProperty(key); } -bool Runtime::method_deleteName(ExecutionEngine *engine, int nameIndex) +ReturnedValue Runtime::DeleteProperty::call(ExecutionEngine *engine, QV4::Function *function, const QV4::Value &base, const QV4::Value &index) +{ + if (!Runtime::DeleteProperty_NoThrow::call(engine, base, index)) { + if (function->isStrict()) + engine->throwTypeError(); + return Encode(false); + } else { + return Encode(true); + } +} + +Bool Runtime::DeleteName_NoThrow::call(ExecutionEngine *engine, int nameIndex) { Scope scope(engine); ScopedString name(scope, engine->currentStackFrame->v4Function->compilationUnit->runtimeStrings[nameIndex]); return static_cast<ExecutionContext &>(engine->currentStackFrame->jsFrame->context).deleteProperty(name); } -QV4::ReturnedValue Runtime::method_instanceof(ExecutionEngine *engine, const Value &lval, const Value &rval) +ReturnedValue Runtime::DeleteName::call(ExecutionEngine *engine, Function *function, int name) +{ + if (!Runtime::DeleteName_NoThrow::call(engine, name)) { + if (function->isStrict()) + engine->throwTypeError(); + return Encode(false); + } else { + return Encode(true); + } +} + +QV4::ReturnedValue Runtime::Instanceof::call(ExecutionEngine *engine, const Value &lval, const Value &rval) { // 11.8.6, 5: rval must be an Object const Object *rhs = rval.as<Object>(); @@ -376,7 +390,7 @@ QV4::ReturnedValue Runtime::method_instanceof(ExecutionEngine *engine, const Val return Encode(result->toBoolean()); } -QV4::ReturnedValue Runtime::method_in(ExecutionEngine *engine, const Value &left, const Value &right) +QV4::ReturnedValue Runtime::In::call(ExecutionEngine *engine, const Value &left, const Value &right) { Object *ro = right.objectValue(); if (!ro) @@ -604,13 +618,12 @@ QV4::ReturnedValue RuntimeHelpers::addHelper(ExecutionEngine *engine, const Valu return Encode(x + y); } -ReturnedValue RuntimeHelpers::getTemplateObject(Function *function, int index) +ReturnedValue Runtime::GetTemplateObject::call(Function *function, int index) { return function->compilationUnit->templateObjectAt(index)->asReturnedValue(); } - -void Runtime::method_storeProperty(ExecutionEngine *engine, const Value &object, int nameIndex, const Value &value) +void Runtime::StoreProperty::call(ExecutionEngine *engine, const Value &object, int nameIndex, const Value &value) { Scope scope(engine); QV4::Function *v4Function = engine->currentStackFrame->v4Function; @@ -683,30 +696,8 @@ static Q_NEVER_INLINE ReturnedValue getElementFallback(ExecutionEngine *engine, return o->get(name); } -ReturnedValue Runtime::method_loadElement(ExecutionEngine *engine, const Value &object, const Value &index) -{ - if (index.isPositiveInt()) { - uint idx = static_cast<uint>(index.int_32()); - if (Heap::Base *b = object.heapObject()) { - if (b->internalClass->vtable->isObject) { - Heap::Object *o = static_cast<Heap::Object *>(b); - if (o->arrayData && o->arrayData->type == Heap::ArrayData::Simple) { - Heap::SimpleArrayData *s = o->arrayData.cast<Heap::SimpleArrayData>(); - if (idx < s->values.size) - if (!s->data(idx).isEmpty()) - return s->data(idx).asReturnedValue(); - } - } - } - return getElementIntFallback(engine, object, idx); - } - - return getElementFallback(engine, object, index); -} - -ReturnedValue Runtime::method_loadElement_traced(ExecutionEngine *engine, const Value &object, const Value &index, quint8 *traceSlot) +ReturnedValue Runtime::LoadElement::call(ExecutionEngine *engine, const Value &object, const Value &index) { - *traceSlot |= quint8(ObservedTraceValues::ArrayWasAccessed); if (index.isPositiveInt()) { uint idx = static_cast<uint>(index.int_32()); if (Heap::Base *b = object.heapObject()) { @@ -720,11 +711,9 @@ ReturnedValue Runtime::method_loadElement_traced(ExecutionEngine *engine, const } } } - *traceSlot |= quint8(ObservedTraceValues::ArrayAccessNeededFallback); return getElementIntFallback(engine, object, idx); } - *traceSlot |= quint8(ObservedTraceValues::ArrayAccessNeededFallback); return getElementFallback(engine, object, index); } @@ -761,7 +750,7 @@ static Q_NEVER_INLINE bool setElementFallback(ExecutionEngine *engine, const Val return o->put(name, value); } -void Runtime::method_storeElement(ExecutionEngine *engine, const Value &object, const Value &index, const Value &value) +void Runtime::StoreElement::call(ExecutionEngine *engine, const Value &object, const Value &index, const Value &value) { if (index.isPositiveInt()) { uint idx = static_cast<uint>(index.int_32()); @@ -783,31 +772,7 @@ void Runtime::method_storeElement(ExecutionEngine *engine, const Value &object, engine->throwTypeError(); } -void Runtime::method_storeElement_traced(ExecutionEngine *engine, const Value &object, const Value &index, const Value &value, quint8 *traceSlot) -{ - *traceSlot |= quint8(ObservedTraceValues::ArrayWasAccessed); - if (index.isPositiveInt()) { - uint idx = static_cast<uint>(index.int_32()); - if (Heap::Base *b = object.heapObject()) { - if (b->internalClass->vtable->isObject) { - Heap::Object *o = static_cast<Heap::Object *>(b); - if (o->arrayData && o->arrayData->type == Heap::ArrayData::Simple) { - Heap::SimpleArrayData *s = o->arrayData.cast<Heap::SimpleArrayData>(); - if (idx < s->values.size) { - s->setData(engine, idx, value); - return; - } - } - } - } - } - - *traceSlot |= quint8(ObservedTraceValues::ArrayAccessNeededFallback); - if (!setElementFallback(engine, object, index, value) && engine->currentStackFrame->v4Function->isStrict()) - engine->throwTypeError(); -} - -ReturnedValue Runtime::method_getIterator(ExecutionEngine *engine, const Value &in, int iterator) +ReturnedValue Runtime::GetIterator::call(ExecutionEngine *engine, const Value &in, int iterator) { Scope scope(engine); ScopedObject o(scope, (Object *)nullptr); @@ -830,7 +795,7 @@ ReturnedValue Runtime::method_getIterator(ExecutionEngine *engine, const Value & return engine->newForInIteratorObject(o)->asReturnedValue(); } -ReturnedValue Runtime::method_iteratorNext(ExecutionEngine *engine, const Value &iterator, Value *value) +ReturnedValue Runtime::IteratorNext::call(ExecutionEngine *engine, const Value &iterator, Value *value) { // if we throw an exception from here, return true, not undefined. This is to ensure iteratorDone is set to true // and the stack unwinding won't close the iterator @@ -866,7 +831,7 @@ ReturnedValue Runtime::method_iteratorNext(ExecutionEngine *engine, const Value return Encode(false); } -ReturnedValue Runtime::method_iteratorNextForYieldStar(ExecutionEngine *engine, const Value &received, const Value &iterator, Value *object) +ReturnedValue Runtime::IteratorNextForYieldStar::call(ExecutionEngine *engine, const Value &received, const Value &iterator, Value *object) { // the return value encodes how to continue the yield* iteration. // true implies iteration is done, false for iteration to continue @@ -903,7 +868,7 @@ ReturnedValue Runtime::method_iteratorNextForYieldStar(ExecutionEngine *engine, if (t->isUndefined()) { // no throw method on the iterator ScopedValue done(scope, Encode(false)); - method_iteratorClose(engine, iterator, done); + IteratorClose::call(engine, iterator, done); if (engine->hasException) return Encode::undefined(); return engine->throwTypeError(); @@ -938,7 +903,7 @@ ReturnedValue Runtime::method_iteratorNextForYieldStar(ExecutionEngine *engine, return Encode(false); } -ReturnedValue Runtime::method_iteratorClose(ExecutionEngine *engine, const Value &iterator, const Value &done) +ReturnedValue Runtime::IteratorClose::call(ExecutionEngine *engine, const Value &iterator, const Value &done) { Q_ASSERT(iterator.isObject()); Q_ASSERT(done.isBoolean()); @@ -978,7 +943,7 @@ ReturnedValue Runtime::method_iteratorClose(ExecutionEngine *engine, const Value return originalCompletion(); } -ReturnedValue Runtime::method_destructureRestElement(ExecutionEngine *engine, const Value &iterator) +ReturnedValue Runtime::DestructureRestElement::call(ExecutionEngine *engine, const Value &iterator) { Q_ASSERT(iterator.isObject()); @@ -988,7 +953,7 @@ ReturnedValue Runtime::method_destructureRestElement(ExecutionEngine *engine, co uint index = 0; while (1) { ScopedValue n(scope); - ScopedValue done(scope, method_iteratorNext(engine, iterator, n)); + ScopedValue done(scope, IteratorNext::call(engine, iterator, n)); if (engine->hasException) return Encode::undefined(); Q_ASSERT(done->isBoolean()); @@ -1000,7 +965,7 @@ ReturnedValue Runtime::method_destructureRestElement(ExecutionEngine *engine, co return array->asReturnedValue(); } -void Runtime::method_storeNameSloppy(ExecutionEngine *engine, int nameIndex, const Value &value) +void Runtime::StoreNameSloppy::call(ExecutionEngine *engine, int nameIndex, const Value &value) { Scope scope(engine); ScopedString name(scope, engine->currentStackFrame->v4Function->compilationUnit->runtimeStrings[nameIndex]); @@ -1010,7 +975,7 @@ void Runtime::method_storeNameSloppy(ExecutionEngine *engine, int nameIndex, con engine->globalObject->put(name, value); } -void Runtime::method_storeNameStrict(ExecutionEngine *engine, int nameIndex, const Value &value) +void Runtime::StoreNameStrict::call(ExecutionEngine *engine, int nameIndex, const Value &value) { Scope scope(engine); ScopedString name(scope, engine->currentStackFrame->v4Function->compilationUnit->runtimeStrings[nameIndex]); @@ -1021,7 +986,7 @@ void Runtime::method_storeNameStrict(ExecutionEngine *engine, int nameIndex, con engine->throwReferenceError(name); } -ReturnedValue Runtime::method_loadProperty(ExecutionEngine *engine, const Value &object, int nameIndex) +ReturnedValue Runtime::LoadProperty::call(ExecutionEngine *engine, const Value &object, int nameIndex) { Scope scope(engine); ScopedString name(scope, engine->currentStackFrame->v4Function->compilationUnit->runtimeStrings[nameIndex]); @@ -1041,7 +1006,7 @@ ReturnedValue Runtime::method_loadProperty(ExecutionEngine *engine, const Value return o->get(name); } -ReturnedValue Runtime::method_loadName(ExecutionEngine *engine, int nameIndex) +ReturnedValue Runtime::LoadName::call(ExecutionEngine *engine, int nameIndex) { Scope scope(engine); ScopedString name(scope, engine->currentStackFrame->v4Function->compilationUnit->runtimeStrings[nameIndex]); @@ -1084,7 +1049,7 @@ static Object *getSuperBase(Scope &scope) return proto; } -ReturnedValue Runtime::method_loadSuperProperty(ExecutionEngine *engine, const Value &property) +ReturnedValue Runtime::LoadSuperProperty::call(ExecutionEngine *engine, const Value &property) { Scope scope(engine); Object *base = getSuperBase(scope); @@ -1096,7 +1061,7 @@ ReturnedValue Runtime::method_loadSuperProperty(ExecutionEngine *engine, const V return base->get(key, &engine->currentStackFrame->jsFrame->thisObject); } -void Runtime::method_storeSuperProperty(ExecutionEngine *engine, const Value &property, const Value &value) +void Runtime::StoreSuperProperty::call(ExecutionEngine *engine, const Value &property, const Value &value) { Scope scope(engine); Object *base = getSuperBase(scope); @@ -1110,7 +1075,40 @@ void Runtime::method_storeSuperProperty(ExecutionEngine *engine, const Value &pr engine->throwTypeError(); } -ReturnedValue Runtime::method_loadSuperConstructor(ExecutionEngine *engine, const Value &t) +ReturnedValue Runtime::LoadGlobalLookup::call(ExecutionEngine *engine, Function *f, int index) +{ + Lookup *l = f->compilationUnit->runtimeLookups + index; + return l->globalGetter(l, engine); +} + +ReturnedValue Runtime::LoadQmlContextPropertyLookup::call(ExecutionEngine *engine, uint index) +{ + Lookup *l = engine->currentStackFrame->v4Function->compilationUnit->runtimeLookups + index; + return l->qmlContextPropertyGetter(l, engine, nullptr); +} + +ReturnedValue Runtime::GetLookup::call(ExecutionEngine *engine, Function *f, const Value &base, int index) +{ + Lookup *l = f->compilationUnit->runtimeLookups + index; + return l->getter(l, engine, base); +} + +void Runtime::SetLookupSloppy::call(Function *f, const Value &base, int index, const Value &value) +{ + ExecutionEngine *engine = f->internalClass->engine; + QV4::Lookup *l = f->compilationUnit->runtimeLookups + index; + l->setter(l, engine, const_cast<Value &>(base), value); +} + +void Runtime::SetLookupStrict::call(Function *f, const Value &base, int index, const Value &value) +{ + ExecutionEngine *engine = f->internalClass->engine; + QV4::Lookup *l = f->compilationUnit->runtimeLookups + index; + if (!l->setter(l, engine, const_cast<Value &>(base), value)) + engine->throwTypeError(); +} + +ReturnedValue Runtime::LoadSuperConstructor::call(ExecutionEngine *engine, const Value &t) { if (engine->currentStackFrame->thisObject() != Value::emptyValue().asReturnedValue()) { return engine->throwReferenceError(QStringLiteral("super() already called."), QString(), 0, 0); // ### fix line number @@ -1143,9 +1141,9 @@ uint RuntimeHelpers::equalHelper(const Value &x, const Value &y) double dx = RuntimeHelpers::toNumber(x); return dx == y.asDouble(); } else if (x.isBoolean()) { - return Runtime::method_compareEqual(Value::fromDouble((double) x.booleanValue()), y); + return Runtime::CompareEqual::call(Value::fromDouble((double) x.booleanValue()), y); } else if (y.isBoolean()) { - return Runtime::method_compareEqual(x, Value::fromDouble((double) y.booleanValue())); + return Runtime::CompareEqual::call(x, Value::fromDouble((double) y.booleanValue())); } else { #ifdef V4_BOOTSTRAP Q_UNIMPLEMENTED(); @@ -1155,11 +1153,11 @@ uint RuntimeHelpers::equalHelper(const Value &x, const Value &y) if (yo && (x.isNumber() || x.isString())) { Scope scope(yo->engine()); ScopedValue py(scope, RuntimeHelpers::objectDefaultValue(yo, PREFERREDTYPE_HINT)); - return Runtime::method_compareEqual(x, py); + return Runtime::CompareEqual::call(x, py); } else if (xo && (y.isNumber() || y.isString())) { Scope scope(xo->engine()); ScopedValue px(scope, RuntimeHelpers::objectDefaultValue(xo, PREFERREDTYPE_HINT)); - return Runtime::method_compareEqual(px, y); + return Runtime::CompareEqual::call(px, y); } #endif } @@ -1177,12 +1175,18 @@ Bool RuntimeHelpers::strictEqual(const Value &x, const Value &y) if (x.isNumber()) return y.isNumber() && x.asDouble() == y.asDouble(); - if (x.isManaged()) + if (x.isManaged()) { +#ifdef V4_BOOTSTRAP + Q_UNIMPLEMENTED(); + return false; +#else return y.isManaged() && x.cast<Managed>()->isEqualTo(y.cast<Managed>()); +#endif + } return false; } -QV4::Bool Runtime::method_compareGreaterThan(const Value &l, const Value &r) +QV4::Bool Runtime::CompareGreaterThan::call(const Value &l, const Value &r) { TRACE2(l, r); if (l.isInteger() && r.isInteger()) @@ -1210,7 +1214,7 @@ QV4::Bool Runtime::method_compareGreaterThan(const Value &l, const Value &r) QV4::Scope scope(e); QV4::ScopedValue pl(scope, lo ? RuntimeHelpers::objectDefaultValue(lo, QV4::NUMBER_HINT) : l.asReturnedValue()); QV4::ScopedValue pr(scope, ro ? RuntimeHelpers::objectDefaultValue(ro, QV4::NUMBER_HINT) : r.asReturnedValue()); - return Runtime::method_compareGreaterThan(pl, pr); + return Runtime::CompareGreaterThan::call(pl, pr); #endif } @@ -1219,7 +1223,7 @@ QV4::Bool Runtime::method_compareGreaterThan(const Value &l, const Value &r) return dl > dr; } -QV4::Bool Runtime::method_compareLessThan(const Value &l, const Value &r) +QV4::Bool Runtime::CompareLessThan::call(const Value &l, const Value &r) { TRACE2(l, r); if (l.isInteger() && r.isInteger()) @@ -1247,7 +1251,7 @@ QV4::Bool Runtime::method_compareLessThan(const Value &l, const Value &r) QV4::Scope scope(e); QV4::ScopedValue pl(scope, lo ? RuntimeHelpers::objectDefaultValue(lo, QV4::NUMBER_HINT) : l.asReturnedValue()); QV4::ScopedValue pr(scope, ro ? RuntimeHelpers::objectDefaultValue(ro, QV4::NUMBER_HINT) : r.asReturnedValue()); - return Runtime::method_compareLessThan(pl, pr); + return Runtime::CompareLessThan::call(pl, pr); #endif } @@ -1256,7 +1260,7 @@ QV4::Bool Runtime::method_compareLessThan(const Value &l, const Value &r) return dl < dr; } -QV4::Bool Runtime::method_compareGreaterEqual(const Value &l, const Value &r) +QV4::Bool Runtime::CompareGreaterEqual::call(const Value &l, const Value &r) { TRACE2(l, r); if (l.isInteger() && r.isInteger()) @@ -1284,7 +1288,7 @@ QV4::Bool Runtime::method_compareGreaterEqual(const Value &l, const Value &r) QV4::Scope scope(e); QV4::ScopedValue pl(scope, lo ? RuntimeHelpers::objectDefaultValue(lo, QV4::NUMBER_HINT) : l.asReturnedValue()); QV4::ScopedValue pr(scope, ro ? RuntimeHelpers::objectDefaultValue(ro, QV4::NUMBER_HINT) : r.asReturnedValue()); - return Runtime::method_compareGreaterEqual(pl, pr); + return Runtime::CompareGreaterEqual::call(pl, pr); #endif } @@ -1293,7 +1297,7 @@ QV4::Bool Runtime::method_compareGreaterEqual(const Value &l, const Value &r) return dl >= dr; } -QV4::Bool Runtime::method_compareLessEqual(const Value &l, const Value &r) +QV4::Bool Runtime::CompareLessEqual::call(const Value &l, const Value &r) { TRACE2(l, r); if (l.isInteger() && r.isInteger()) @@ -1321,7 +1325,7 @@ QV4::Bool Runtime::method_compareLessEqual(const Value &l, const Value &r) QV4::Scope scope(e); QV4::ScopedValue pl(scope, lo ? RuntimeHelpers::objectDefaultValue(lo, QV4::NUMBER_HINT) : l.asReturnedValue()); QV4::ScopedValue pr(scope, ro ? RuntimeHelpers::objectDefaultValue(ro, QV4::NUMBER_HINT) : r.asReturnedValue()); - return Runtime::method_compareLessEqual(pl, pr); + return Runtime::CompareLessEqual::call(pl, pr); #endif } @@ -1331,21 +1335,21 @@ QV4::Bool Runtime::method_compareLessEqual(const Value &l, const Value &r) } #ifndef V4_BOOTSTRAP -Bool Runtime::method_compareInstanceof(ExecutionEngine *engine, const Value &left, const Value &right) +Bool Runtime::CompareInstanceof::call(ExecutionEngine *engine, const Value &left, const Value &right) { TRACE2(left, right); Scope scope(engine); - ScopedValue v(scope, method_instanceof(engine, left, right)); + ScopedValue v(scope, Instanceof::call(engine, left, right)); return v->booleanValue(); } -uint Runtime::method_compareIn(ExecutionEngine *engine, const Value &left, const Value &right) +uint Runtime::CompareIn::call(ExecutionEngine *engine, const Value &left, const Value &right) { TRACE2(left, right); Scope scope(engine); - ScopedValue v(scope, method_in(engine, left, right)); + ScopedValue v(scope, In::call(engine, left, right)); return v->booleanValue(); } @@ -1359,7 +1363,7 @@ static ReturnedValue throwPropertyIsNotAFunctionTypeError(ExecutionEngine *engin return engine->throwTypeError(msg); } -ReturnedValue Runtime::method_callGlobalLookup(ExecutionEngine *engine, uint index, Value *argv, int argc) +ReturnedValue Runtime::CallGlobalLookup::call(ExecutionEngine *engine, uint index, Value argv[], int argc) { Scope scope(engine); Lookup *l = engine->currentStackFrame->v4Function->compilationUnit->runtimeLookups + index; @@ -1372,7 +1376,8 @@ ReturnedValue Runtime::method_callGlobalLookup(ExecutionEngine *engine, uint ind return static_cast<FunctionObject &>(function).call(&thisObject, argv, argc); } -ReturnedValue Runtime::method_callQmlContextPropertyLookup(ExecutionEngine *engine, uint index, Value *argv, int argc) +ReturnedValue Runtime::CallQmlContextPropertyLookup::call(ExecutionEngine *engine, uint index, + Value *argv, int argc) { Scope scope(engine); ScopedValue thisObject(scope); @@ -1385,7 +1390,7 @@ ReturnedValue Runtime::method_callQmlContextPropertyLookup(ExecutionEngine *engi return static_cast<FunctionObject &>(function).call(thisObject, argv, argc); } -ReturnedValue Runtime::method_callPossiblyDirectEval(ExecutionEngine *engine, Value *argv, int argc) +ReturnedValue Runtime::CallPossiblyDirectEval::call(ExecutionEngine *engine, Value *argv, int argc) { Scope scope(engine); ScopedValue thisObject(scope); @@ -1404,7 +1409,7 @@ ReturnedValue Runtime::method_callPossiblyDirectEval(ExecutionEngine *engine, Va return function->call(thisObject, argv, argc); } -ReturnedValue Runtime::method_callName(ExecutionEngine *engine, int nameIndex, Value *argv, int argc) +ReturnedValue Runtime::CallName::call(ExecutionEngine *engine, int nameIndex, Value *argv, int argc) { Scope scope(engine); ScopedValue thisObject(scope); @@ -1422,8 +1427,9 @@ ReturnedValue Runtime::method_callName(ExecutionEngine *engine, int nameIndex, V return f->call(thisObject, argv, argc); } -ReturnedValue Runtime::method_callProperty(ExecutionEngine *engine, Value *base, int nameIndex, Value *argv, int argc) +ReturnedValue Runtime::CallProperty::call(ExecutionEngine *engine, const Value &baseRef, int nameIndex, Value *argv, int argc) { + const Value *base = &baseRef; Scope scope(engine); ScopedString name(scope, engine->currentStackFrame->v4Function->compilationUnit->runtimeStrings[nameIndex]); ScopedObject lookupObject(scope, base); @@ -1437,7 +1443,7 @@ ReturnedValue Runtime::method_callProperty(ExecutionEngine *engine, Value *base, } if (base->isManaged()) { - Managed *m = static_cast<Managed *>(base); + const Managed *m = static_cast<const Managed *>(base); lookupObject = m->internalClass()->prototype; Q_ASSERT(m->internalClass()->prototype); } else { @@ -1461,20 +1467,21 @@ ReturnedValue Runtime::method_callProperty(ExecutionEngine *engine, Value *base, return f->call(base, argv, argc); } -ReturnedValue Runtime::method_callPropertyLookup(ExecutionEngine *engine, Value *base, uint index, Value *argv, int argc) +ReturnedValue Runtime::CallPropertyLookup::call(ExecutionEngine *engine, const Value &base, uint index, Value *argv, int argc) { Lookup *l = engine->currentStackFrame->v4Function->compilationUnit->runtimeLookups + index; // ok to have the value on the stack here - Value f = Value::fromReturnedValue(l->getter(l, engine, *base)); + Value f = Value::fromReturnedValue(l->getter(l, engine, base)); if (!f.isFunctionObject()) return engine->throwTypeError(); - return static_cast<FunctionObject &>(f).call(base, argv, argc); + return static_cast<FunctionObject &>(f).call(&base, argv, argc); } -ReturnedValue Runtime::method_callElement(ExecutionEngine *engine, Value *base, const Value &index, Value *argv, int argc) +ReturnedValue Runtime::CallElement::call(ExecutionEngine *engine, const Value &baseRef, const Value &index, Value *argv, int argc) { + const Value *base = &baseRef; Scope scope(engine); ScopedValue thisObject(scope, base->toObject(engine)); base = thisObject; @@ -1483,14 +1490,14 @@ ReturnedValue Runtime::method_callElement(ExecutionEngine *engine, Value *base, if (engine->hasException) return Encode::undefined(); - ScopedFunctionObject f(scope, static_cast<Object *>(base)->get(str)); + ScopedFunctionObject f(scope, static_cast<const Object *>(base)->get(str)); if (!f) return engine->throwTypeError(); return f->call(base, argv, argc); } -ReturnedValue Runtime::method_callValue(ExecutionEngine *engine, const Value &func, Value *argv, int argc) +ReturnedValue Runtime::CallValue::call(ExecutionEngine *engine, const Value &func, Value *argv, int argc) { if (!func.isFunctionObject()) return engine->throwTypeError(QStringLiteral("%1 is not a function").arg(func.toQStringNoThrow())); @@ -1498,11 +1505,12 @@ ReturnedValue Runtime::method_callValue(ExecutionEngine *engine, const Value &fu return static_cast<const FunctionObject &>(func).call(&undef, argv, argc); } -ReturnedValue Runtime::method_callWithReceiver(ExecutionEngine *engine, const Value &func, const Value *thisObject, Value *argv, int argc) +ReturnedValue Runtime::CallWithReceiver::call(ExecutionEngine *engine, const Value &func, + const Value &thisObject, Value argv[], int argc) { 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 static_cast<const FunctionObject &>(func).call(&thisObject, argv, argc); } struct CallArgs { @@ -1528,11 +1536,11 @@ static CallArgs createSpreadArguments(Scope &scope, Value *argv, int argc) } // spread element ++i; - it = Runtime::method_getIterator(scope.engine, argv[i], /* ForInIterator */ 1); + it = Runtime::GetIterator::call(scope.engine, argv[i], /* ForInIterator */ 1); if (scope.engine->hasException) return { nullptr, 0 }; while (1) { - done = Runtime::method_iteratorNext(scope.engine, it, v); + done = Runtime::IteratorNext::call(scope.engine, it, v); if (scope.engine->hasException) return { nullptr, 0 }; Q_ASSERT(done->isBoolean()); @@ -1545,7 +1553,7 @@ static CallArgs createSpreadArguments(Scope &scope, Value *argv, int argc) return { arguments, argCount }; } -ReturnedValue Runtime::method_callWithSpread(ExecutionEngine *engine, const Value &function, const Value &thisObject, Value *argv, int argc) +ReturnedValue Runtime::CallWithSpread::call(ExecutionEngine *engine, const Value &function, const Value &thisObject, Value *argv, int argc) { Q_ASSERT(argc >= 1); if (!function.isFunctionObject()) @@ -1559,7 +1567,7 @@ ReturnedValue Runtime::method_callWithSpread(ExecutionEngine *engine, const Valu return static_cast<const FunctionObject &>(function).call(&thisObject, arguments.argv, arguments.argc); } -ReturnedValue Runtime::method_construct(ExecutionEngine *engine, const Value &function, const Value &newTarget, Value *argv, int argc) +ReturnedValue Runtime::Construct::call(ExecutionEngine *engine, const Value &function, const Value &newTarget, Value *argv, int argc) { if (!function.isFunctionObject()) return engine->throwTypeError(); @@ -1567,7 +1575,7 @@ ReturnedValue Runtime::method_construct(ExecutionEngine *engine, const Value &fu return static_cast<const FunctionObject &>(function).callAsConstructor(argv, argc, &newTarget); } -ReturnedValue Runtime::method_constructWithSpread(ExecutionEngine *engine, const Value &function, const Value &newTarget, Value *argv, int argc) +ReturnedValue Runtime::ConstructWithSpread::call(ExecutionEngine *engine, const Value &function, const Value &newTarget, Value *argv, int argc) { if (!function.isFunctionObject()) return engine->throwTypeError(); @@ -1580,7 +1588,7 @@ ReturnedValue Runtime::method_constructWithSpread(ExecutionEngine *engine, const return static_cast<const FunctionObject &>(function).callAsConstructor(arguments.argv, arguments.argc, &newTarget); } -ReturnedValue Runtime::method_tailCall(CppStackFrame *frame, ExecutionEngine *engine) +ReturnedValue Runtime::TailCall::call(CppStackFrame *frame, ExecutionEngine *engine) { // IMPORTANT! The JIT assumes that this method has the same amount (or less) arguments than // the jitted function, so it can safely do a tail call. @@ -1610,13 +1618,13 @@ ReturnedValue Runtime::method_tailCall(CppStackFrame *frame, ExecutionEngine *en return Encode::undefined(); } -void Runtime::method_throwException(ExecutionEngine *engine, const Value &value) +void Runtime::ThrowException::call(ExecutionEngine *engine, const Value &value) { if (!value.isEmpty()) engine->throwError(value); } -ReturnedValue Runtime::method_typeofValue(ExecutionEngine *engine, const Value &value) +ReturnedValue Runtime::TypeofValue::call(ExecutionEngine *engine, const Value &value) { Scope scope(engine); ScopedString res(scope); @@ -1647,83 +1655,109 @@ ReturnedValue Runtime::method_typeofValue(ExecutionEngine *engine, const Value & return res.asReturnedValue(); } -QV4::ReturnedValue Runtime::method_typeofName(ExecutionEngine *engine, int nameIndex) +QV4::ReturnedValue Runtime::TypeofName::call(ExecutionEngine *engine, int nameIndex) { Scope scope(engine); ScopedString name(scope, engine->currentStackFrame->v4Function->compilationUnit->runtimeStrings[nameIndex]); ScopedValue prop(scope, static_cast<ExecutionContext &>(engine->currentStackFrame->jsFrame->context).getProperty(name)); // typeof doesn't throw. clear any possible exception scope.engine->hasException = false; - return method_typeofValue(engine, prop); + return TypeofValue::call(engine, prop); } -ReturnedValue Runtime::method_createWithContext(ExecutionEngine *engine, Value *jsStackFrame) +void Runtime::PushCallContext::call(CppStackFrame *frame) { - QV4::Value &accumulator = jsStackFrame[CallData::Accumulator]; - accumulator = accumulator.toObject(engine); - if (engine->hasException) - return Encode::undefined(); - Q_ASSERT(accumulator.isObject()); - const Object &obj = static_cast<const Object &>(accumulator); - ExecutionContext *context = static_cast<ExecutionContext *>(jsStackFrame + CallData::Context); - return context->newWithContext(obj.d())->asReturnedValue(); + frame->jsFrame->context = ExecutionContext::newCallContext(frame)->asReturnedValue(); } -ReturnedValue Runtime::method_createCatchContext(ExecutionContext *parent, int blockIndex, int exceptionVarNameIndex) +ReturnedValue Runtime::PushWithContext::call(ExecutionEngine *engine, const Value &acc) { - ExecutionEngine *e = parent->engine(); - return parent->newCatchContext(e->currentStackFrame, blockIndex, - e->currentStackFrame->v4Function->compilationUnit->runtimeStrings[exceptionVarNameIndex])->asReturnedValue(); + CallData *jsFrame = engine->currentStackFrame->jsFrame; + Value &newAcc = jsFrame->accumulator; + newAcc = Value::fromHeapObject(acc.toObject(engine)); + if (!engine->hasException) { + Q_ASSERT(newAcc.isObject()); + const Object &obj = static_cast<const Object &>(newAcc); + Value &context = jsFrame->context; + auto ec = static_cast<const ExecutionContext *>(&context); + context = ec->newWithContext(obj.d())->asReturnedValue(); + } + return newAcc.asReturnedValue(); } -ReturnedValue Runtime::method_createBlockContext(ExecutionContext *parent, int index) +void Runtime::PushCatchContext::call(ExecutionEngine *engine, int blockIndex, int exceptionVarNameIndex) { - ExecutionEngine *e = parent->engine(); - return parent->newBlockContext(e->currentStackFrame, index)->asReturnedValue(); + auto name = engine->currentStackFrame->v4Function->compilationUnit->runtimeStrings[exceptionVarNameIndex]; + engine->currentStackFrame->jsFrame->context = ExecutionContext::newCatchContext(engine->currentStackFrame, blockIndex, name)->asReturnedValue(); } -ReturnedValue Runtime::method_cloneBlockContext(ExecutionContext *previous) +void Runtime::PushBlockContext::call(ExecutionEngine *engine, int index) { - return ExecutionContext::cloneBlockContext(static_cast<Heap::CallContext *>(previous->d()))->asReturnedValue(); + engine->currentStackFrame->jsFrame->context = ExecutionContext::newBlockContext(engine->currentStackFrame, index)->asReturnedValue(); } +void Runtime::CloneBlockContext::call(ExecutionEngine *engine) +{ + auto frame = engine->currentStackFrame; + auto context = static_cast<Heap::CallContext *>(frame->jsFrame->context.m()); + frame->jsFrame->context = + ExecutionContext::cloneBlockContext(engine, context)->asReturnedValue(); +} -ReturnedValue Runtime::method_createScriptContext(ExecutionEngine *engine, int index) +void Runtime::PushScriptContext::call(ExecutionEngine *engine, int index) { Q_ASSERT(engine->currentStackFrame->context()->d()->type == Heap::ExecutionContext::Type_GlobalContext || engine->currentStackFrame->context()->d()->type == Heap::ExecutionContext::Type_QmlContext); ReturnedValue c = ExecutionContext::newBlockContext(engine->currentStackFrame, index)->asReturnedValue(); engine->setScriptContext(c); - return c; + engine->currentStackFrame->jsFrame->context = c; } -ReturnedValue Runtime::method_popScriptContext(ExecutionEngine *engine) +void Runtime::PopScriptContext::call(ExecutionEngine *engine) { ReturnedValue root = engine->rootContext()->asReturnedValue(); engine->setScriptContext(root); - return root; + engine->currentStackFrame->jsFrame->context = root; } -void Runtime::method_throwReferenceError(ExecutionEngine *engine, int nameIndex) +void Runtime::ThrowReferenceError::call(ExecutionEngine *engine, int nameIndex) { Scope scope(engine); ScopedString name(scope, engine->currentStackFrame->v4Function->compilationUnit->runtimeStrings[nameIndex]); engine->throwReferenceError(name); } -void Runtime::method_declareVar(ExecutionEngine *engine, bool deletable, int nameIndex) +void Runtime::ThrowOnNullOrUndefined::call(ExecutionEngine *engine, const Value &v) +{ + if (v.isNullOrUndefined()) + engine->throwTypeError(); +} + +ReturnedValue Runtime::ConvertThisToObject::call(ExecutionEngine *engine, const Value &t) +{ + if (!t.isObject()) { + if (t.isNullOrUndefined()) { + return engine->globalObject->asReturnedValue(); + } else { + return t.toObject(engine)->asReturnedValue(); + } + } + return t.asReturnedValue(); +} + +void Runtime::DeclareVar::call(ExecutionEngine *engine, Bool deletable, int nameIndex) { Scope scope(engine); ScopedString name(scope, engine->currentStackFrame->v4Function->compilationUnit->runtimeStrings[nameIndex]); static_cast<ExecutionContext &>(engine->currentStackFrame->jsFrame->context).createMutableBinding(name, deletable); } -ReturnedValue Runtime::method_arrayLiteral(ExecutionEngine *engine, Value *values, uint length) +ReturnedValue Runtime::ArrayLiteral::call(ExecutionEngine *engine, Value *values, uint length) { return engine->newArrayObject(values, length)->asReturnedValue(); } -ReturnedValue Runtime::method_objectLiteral(ExecutionEngine *engine, int classId, const QV4::Value *args, int argc) +ReturnedValue Runtime::ObjectLiteral::call(ExecutionEngine *engine, int classId, QV4::Value args[], int argc) { Scope scope(engine); Scoped<InternalClass> klass(scope, engine->currentStackFrame->v4Function->compilationUnit->runtimeClasses[classId]); @@ -1796,7 +1830,8 @@ ReturnedValue Runtime::method_objectLiteral(ExecutionEngine *engine, int classId return o.asReturnedValue(); } -ReturnedValue Runtime::method_createClass(ExecutionEngine *engine, int classIndex, const Value &superClass, const Value *computedNames) +ReturnedValue Runtime::CreateClass::call(ExecutionEngine *engine, int classIndex, + const Value &superClass, Value computedNames[]) { const CompiledData::CompilationUnit *unit = engine->currentStackFrame->v4Function->compilationUnit; const QV4::CompiledData::Class *cls = unit->unitData()->classAt(classIndex); @@ -1898,20 +1933,20 @@ ReturnedValue Runtime::method_createClass(ExecutionEngine *engine, int classInde return constructor->asReturnedValue(); } -QV4::ReturnedValue Runtime::method_createMappedArgumentsObject(ExecutionEngine *engine) +QV4::ReturnedValue Runtime::CreateMappedArgumentsObject::call(ExecutionEngine *engine) { Q_ASSERT(engine->currentContext()->d()->type == Heap::ExecutionContext::Type_CallContext); Heap::InternalClass *ic = engine->internalClasses(EngineBase::Class_ArgumentsObject); return engine->memoryManager->allocObject<ArgumentsObject>(ic, engine->currentStackFrame)->asReturnedValue(); } -QV4::ReturnedValue Runtime::method_createUnmappedArgumentsObject(ExecutionEngine *engine) +QV4::ReturnedValue Runtime::CreateUnmappedArgumentsObject::call(ExecutionEngine *engine) { Heap::InternalClass *ic = engine->internalClasses(EngineBase::Class_StrictArgumentsObject); return engine->memoryManager->allocObject<StrictArgumentsObject>(ic, engine->currentStackFrame)->asReturnedValue(); } -QV4::ReturnedValue Runtime::method_createRestParameter(ExecutionEngine *engine, int argIndex) +QV4::ReturnedValue Runtime::CreateRestParameter::call(ExecutionEngine *engine, int argIndex) { const Value *values = engine->currentStackFrame->originalArguments + argIndex; int nValues = engine->currentStackFrame->originalArgumentsCount - argIndex; @@ -1920,14 +1955,32 @@ QV4::ReturnedValue Runtime::method_createRestParameter(ExecutionEngine *engine, return engine->newArrayObject(values, nValues)->asReturnedValue(); } -ReturnedValue Runtime::method_regexpLiteral(ExecutionEngine *engine, int id) +ReturnedValue Runtime::RegexpLiteral::call(ExecutionEngine *engine, int id) { Heap::RegExpObject *ro = engine->newRegExpObject(engine->currentStackFrame->v4Function->compilationUnit->runtimeRegularExpressions[id].as<RegExp>()); return ro->asReturnedValue(); } + +ReturnedValue Runtime::ToObject::call(ExecutionEngine *engine, const Value &obj) +{ + if (obj.isObject()) + return obj.asReturnedValue(); + + return obj.toObject(engine)->asReturnedValue(); +} + +Bool Runtime::ToBoolean::call(const Value &obj) +{ + return obj.toBoolean(); +} + +ReturnedValue Runtime::ToNumber::call(ExecutionEngine *, const Value &v) +{ + return Encode(v.toNumber()); +} #endif // V4_BOOTSTRAP -ReturnedValue Runtime::method_uMinus(const Value &value) +ReturnedValue Runtime::UMinus::call(const Value &value) { TRACE1(value); @@ -1944,7 +1997,7 @@ ReturnedValue Runtime::method_uMinus(const Value &value) // binary operators #ifndef V4_BOOTSTRAP -ReturnedValue Runtime::method_add(ExecutionEngine *engine, const Value &left, const Value &right) +ReturnedValue Runtime::Add::call(ExecutionEngine *engine, const Value &left, const Value &right) { TRACE2(left, right); @@ -1956,7 +2009,7 @@ ReturnedValue Runtime::method_add(ExecutionEngine *engine, const Value &left, co return RuntimeHelpers::addHelper(engine, left, right); } -ReturnedValue Runtime::method_sub(const Value &left, const Value &right) +ReturnedValue Runtime::Sub::call(const Value &left, const Value &right) { TRACE2(left, right); @@ -1969,7 +2022,7 @@ ReturnedValue Runtime::method_sub(const Value &left, const Value &right) return Value::fromDouble(lval - rval).asReturnedValue(); } -ReturnedValue Runtime::method_mul(const Value &left, const Value &right) +ReturnedValue Runtime::Mul::call(const Value &left, const Value &right) { TRACE2(left, right); @@ -1982,7 +2035,7 @@ ReturnedValue Runtime::method_mul(const Value &left, const Value &right) return Value::fromDouble(lval * rval).asReturnedValue(); } -ReturnedValue Runtime::method_div(const Value &left, const Value &right) +ReturnedValue Runtime::Div::call(const Value &left, const Value &right) { TRACE2(left, right); @@ -2003,7 +2056,7 @@ ReturnedValue Runtime::method_div(const Value &left, const Value &right) return Value::fromDouble(lval / rval).asReturnedValue(); } -ReturnedValue Runtime::method_mod(const Value &left, const Value &right) +ReturnedValue Runtime::Mod::call(const Value &left, const Value &right) { TRACE2(left, right); @@ -2024,7 +2077,43 @@ ReturnedValue Runtime::method_mod(const Value &left, const Value &right) return Value::fromDouble(std::fmod(lval, rval)).asReturnedValue(); } -ReturnedValue Runtime::method_shl(const Value &left, const Value &right) +ReturnedValue Runtime::Exp::call(const Value &base, const Value &exp) +{ + double b = base.toNumber(); + double e = exp.toNumber(); + if (qt_is_inf(e) && (b == 1 || b == -1)) + return Encode(qt_snan()); + return Encode(pow(b,e)); +} + +ReturnedValue Runtime::BitAnd::call(const Value &left, const Value &right) +{ + TRACE2(left, right); + + int lval = left.toInt32(); + int rval = right.toInt32(); + return Encode((int)(lval & rval)); +} + +ReturnedValue Runtime::BitOr::call(const Value &left, const Value &right) +{ + TRACE2(left, right); + + int lval = left.toInt32(); + int rval = right.toInt32(); + return Encode((int)(lval | rval)); +} + +ReturnedValue Runtime::BitXor::call(const Value &left, const Value &right) +{ + TRACE2(left, right); + + int lval = left.toInt32(); + int rval = right.toInt32(); + return Encode((int)(lval ^ rval)); +} + +ReturnedValue Runtime::Shl::call(const Value &left, const Value &right) { TRACE2(left, right); @@ -2033,7 +2122,7 @@ ReturnedValue Runtime::method_shl(const Value &left, const Value &right) return Encode((int)(lval << rval)); } -ReturnedValue Runtime::method_shr(const Value &left, const Value &right) +ReturnedValue Runtime::Shr::call(const Value &left, const Value &right) { TRACE2(left, right); @@ -2042,7 +2131,7 @@ ReturnedValue Runtime::method_shr(const Value &left, const Value &right) return Encode((int)(lval >> rval)); } -ReturnedValue Runtime::method_ushr(const Value &left, const Value &right) +ReturnedValue Runtime::UShr::call(const Value &left, const Value &right) { TRACE2(left, right); @@ -2055,38 +2144,39 @@ ReturnedValue Runtime::method_ushr(const Value &left, const Value &right) #endif // V4_BOOTSTRAP -ReturnedValue Runtime::method_greaterThan(const Value &left, const Value &right) +ReturnedValue Runtime::GreaterThan::call(const Value &left, const Value &right) { TRACE2(left, right); - bool r = method_compareGreaterThan(left, right); + bool r = CompareGreaterThan::call(left, right); return Encode(r); } -ReturnedValue Runtime::method_lessThan(const Value &left, const Value &right) +ReturnedValue Runtime::LessThan::call(const Value &left, const Value &right) { TRACE2(left, right); - bool r = method_compareLessThan(left, right); + bool r = CompareLessThan::call(left, right); return Encode(r); } -ReturnedValue Runtime::method_greaterEqual(const Value &left, const Value &right) +ReturnedValue Runtime::GreaterEqual::call(const Value &left, const Value &right) { TRACE2(left, right); - bool r = method_compareGreaterEqual(left, right); + bool r = CompareGreaterEqual::call(left, right); return Encode(r); } -ReturnedValue Runtime::method_lessEqual(const Value &left, const Value &right) +ReturnedValue Runtime::LessEqual::call(const Value &left, const Value &right) { TRACE2(left, right); - bool r = method_compareLessEqual(left, right); + bool r = CompareLessEqual::call(left, right); return Encode(r); } +#ifndef V4_BOOTSTRAP struct LazyScope { ExecutionEngine *engine = nullptr; @@ -2106,8 +2196,9 @@ struct LazyScope **scopedValue = value; } }; +#endif -Bool Runtime::method_compareEqual(const Value &left, const Value &right) +Bool Runtime::CompareEqual::call(const Value &left, const Value &right) { TRACE2(left, right); @@ -2216,23 +2307,23 @@ Bool Runtime::method_compareEqual(const Value &left, const Value &right) } } -ReturnedValue Runtime::method_equal(const Value &left, const Value &right) +ReturnedValue Runtime::Equal::call(const Value &left, const Value &right) { TRACE2(left, right); - bool r = method_compareEqual(left, right); + bool r = CompareEqual::call(left, right); return Encode(r); } -ReturnedValue Runtime::method_notEqual(const Value &left, const Value &right) +ReturnedValue Runtime::NotEqual::call(const Value &left, const Value &right) { TRACE2(left, right); - bool r = !method_compareEqual(left, right); + bool r = !CompareEqual::call(left, right); return Encode(r); } -ReturnedValue Runtime::method_strictEqual(const Value &left, const Value &right) +ReturnedValue Runtime::StrictEqual::call(const Value &left, const Value &right) { TRACE2(left, right); @@ -2240,7 +2331,7 @@ ReturnedValue Runtime::method_strictEqual(const Value &left, const Value &right) return Encode(r); } -ReturnedValue Runtime::method_strictNotEqual(const Value &left, const Value &right) +ReturnedValue Runtime::StrictNotEqual::call(const Value &left, const Value &right) { TRACE2(left, right); @@ -2248,21 +2339,21 @@ ReturnedValue Runtime::method_strictNotEqual(const Value &left, const Value &rig return Encode(r); } -Bool Runtime::method_compareNotEqual(const Value &left, const Value &right) +Bool Runtime::CompareNotEqual::call(const Value &left, const Value &right) { TRACE2(left, right); - return !Runtime::method_compareEqual(left, right); + return !Runtime::CompareEqual::call(left, right); } -Bool Runtime::method_compareStrictEqual(const Value &left, const Value &right) +Bool Runtime::CompareStrictEqual::call(const Value &left, const Value &right) { TRACE2(left, right); return RuntimeHelpers::strictEqual(left, right); } -Bool Runtime::method_compareStrictNotEqual(const Value &left, const Value &right) +Bool Runtime::CompareStrictNotEqual::call(const Value &left, const Value &right) { TRACE2(left, right); diff --git a/src/qml/jsruntime/qv4runtime_p.h b/src/qml/jsruntime/qv4runtime_p.h index 2be3ebf012..349099f8d5 100644 --- a/src/qml/jsruntime/qv4runtime_p.h +++ b/src/qml/jsruntime/qv4runtime_p.h @@ -52,8 +52,6 @@ #include "qv4global_p.h" #include "qv4value_p.h" -#include "qv4context_p.h" -#include "qv4engine_p.h" #include "qv4math_p.h" #include "qv4runtimeapi_p.h" #include <QtCore/qnumeric.h> @@ -114,8 +112,6 @@ struct Q_QML_PRIVATE_EXPORT RuntimeHelpers { static Bool strictEqual(const Value &x, const Value &y); static ReturnedValue addHelper(ExecutionEngine *engine, const Value &left, const Value &right); - - static ReturnedValue getTemplateObject(Function *function, int index); }; diff --git a/src/qml/jsruntime/qv4runtimeapi_p.h b/src/qml/jsruntime/qv4runtimeapi_p.h index ceec13a3bb..13a73b7046 100644 --- a/src/qml/jsruntime/qv4runtimeapi_p.h +++ b/src/qml/jsruntime/qv4runtimeapi_p.h @@ -57,173 +57,442 @@ QT_BEGIN_NAMESPACE namespace QV4 { typedef uint Bool; -struct NoThrowEngine; -namespace { -template <typename T> -struct ExceptionCheck { - enum { NeedsCheck = 1 }; -}; -// push_catch and pop context methods shouldn't check for exceptions -template <> -struct ExceptionCheck<void (*)(QV4::NoThrowEngine *)> { - enum { NeedsCheck = 0 }; -}; -template <typename A> -struct ExceptionCheck<void (*)(A, QV4::NoThrowEngine)> { - enum { NeedsCheck = 0 }; -}; -template <> -struct ExceptionCheck<QV4::ReturnedValue (*)(QV4::NoThrowEngine *)> { - enum { NeedsCheck = 0 }; -}; -template <typename A> -struct ExceptionCheck<QV4::ReturnedValue (*)(QV4::NoThrowEngine *, A)> { - enum { NeedsCheck = 0 }; -}; -template <typename A, typename B> -struct ExceptionCheck<QV4::ReturnedValue (*)(QV4::NoThrowEngine *, A, B)> { - enum { NeedsCheck = 0 }; -}; -template <typename A, typename B, typename C> -struct ExceptionCheck<void (*)(QV4::NoThrowEngine *, A, B, C)> { - enum { NeedsCheck = 0 }; -}; -} // anonymous namespace - -#define FOR_EACH_RUNTIME_METHOD(F) \ - /* call */ \ - F(ReturnedValue, callGlobalLookup, (ExecutionEngine *engine, uint index, Value *argv, int argc)) \ - F(ReturnedValue, callQmlContextPropertyLookup, (ExecutionEngine *engine, uint index, Value *argv, int argc)) \ - F(ReturnedValue, callName, (ExecutionEngine *engine, int nameIndex, Value *argv, int argc)) \ - F(ReturnedValue, callProperty, (ExecutionEngine *engine, Value *base, int nameIndex, Value *argv, int argc)) \ - F(ReturnedValue, callPropertyLookup, (ExecutionEngine *engine, Value *base, uint index, Value *argv, int argc)) \ - F(ReturnedValue, callElement, (ExecutionEngine *engine, Value *base, const Value &index, Value *argv, int argc)) \ - F(ReturnedValue, callValue, (ExecutionEngine *engine, const Value &func, Value *argv, int argc)) \ - F(ReturnedValue, callWithReceiver, (ExecutionEngine *engine, const Value &func, const Value *thisObject, Value *argv, int argc)) \ - F(ReturnedValue, callPossiblyDirectEval, (ExecutionEngine *engine, Value *argv, int argc)) \ - F(ReturnedValue, callWithSpread, (ExecutionEngine *engine, const Value &func, const Value &thisObject, Value *argv, int argc)) \ - F(ReturnedValue, tailCall, (CppStackFrame *frame, ExecutionEngine *engine)) \ - \ - /* construct */ \ - F(ReturnedValue, construct, (ExecutionEngine *engine, const Value &func, const Value &newTarget, Value *argv, int argc)) \ - F(ReturnedValue, constructWithSpread, (ExecutionEngine *engine, const Value &func, const Value &newTarget, Value *argv, int argc)) \ - \ - /* load & store */ \ - F(void, storeNameStrict, (ExecutionEngine *engine, int nameIndex, const Value &value)) \ - F(void, storeNameSloppy, (ExecutionEngine *engine, int nameIndex, const Value &value)) \ - F(void, storeProperty, (ExecutionEngine *engine, const Value &object, int nameIndex, const Value &value)) \ - F(void, storeElement, (ExecutionEngine *engine, const Value &object, const Value &index, const Value &value)) \ - F(void, storeElement_traced, (ExecutionEngine *engine, const Value &object, const Value &index, const Value &value, quint8 *traceSlot)) \ - F(ReturnedValue, loadProperty, (ExecutionEngine *engine, const Value &object, int nameIndex)) \ - F(ReturnedValue, loadName, (ExecutionEngine *engine, int nameIndex)) \ - F(ReturnedValue, loadElement, (ExecutionEngine *engine, const Value &object, const Value &index)) \ - F(ReturnedValue, loadElement_traced, (ExecutionEngine *engine, const Value &object, const Value &index, quint8 *traceSlot)) \ - F(ReturnedValue, loadSuperProperty, (ExecutionEngine *engine, const Value &property)) \ - F(void, storeSuperProperty, (ExecutionEngine *engine, const Value &property, const Value &value)) \ - F(ReturnedValue, loadSuperConstructor, (ExecutionEngine *engine, const Value &t)) \ - \ - /* typeof */ \ - F(ReturnedValue, typeofValue, (ExecutionEngine *engine, const Value &val)) \ - F(ReturnedValue, typeofName, (ExecutionEngine *engine, int nameIndex)) \ - \ - /* delete */ \ - F(bool, deleteProperty, (ExecutionEngine *engine, const Value &base, const Value &index)) \ - F(bool, deleteName, (ExecutionEngine *engine, int nameIndex)) \ - \ - /* exceptions & scopes */ \ - F(void, throwException, (ExecutionEngine *engine, const Value &value)) \ - F(ReturnedValue, createWithContext, (ExecutionEngine *, Value *jsStackFrame)) \ - F(ReturnedValue, createCatchContext, (ExecutionContext *parent, int blockIndex, int exceptionVarNameIndex)) \ - F(ReturnedValue, createBlockContext, (ExecutionContext *parent, int index)) \ - F(ReturnedValue, createScriptContext, (ExecutionEngine *engine, int index)) \ - F(ReturnedValue, cloneBlockContext, (ExecutionContext *previous)) \ - F(ReturnedValue, popScriptContext, (ExecutionEngine *engine)) \ - F(void, throwReferenceError, (ExecutionEngine *engine, int nameIndex)) \ - \ - /* closures */ \ - F(ReturnedValue, closure, (ExecutionEngine *engine, int functionId)) \ - \ - /* function header */ \ - F(void, declareVar, (ExecutionEngine *engine, bool deletable, int nameIndex)) \ - F(ReturnedValue, createMappedArgumentsObject, (ExecutionEngine *engine)) \ - F(ReturnedValue, createUnmappedArgumentsObject, (ExecutionEngine *engine)) \ - F(ReturnedValue, createRestParameter, (ExecutionEngine *engine, int argIndex)) \ - \ - /* literals */ \ - F(ReturnedValue, arrayLiteral, (ExecutionEngine *engine, Value *values, uint length)) \ - F(ReturnedValue, objectLiteral, (ExecutionEngine *engine, int classId, const Value *args, int argc)) \ - F(ReturnedValue, createClass, (ExecutionEngine *engine, int classIndex, const Value &heritage, const Value *computedNames)) \ - \ - /* for-in, for-of and array destructuring */ \ - F(ReturnedValue, getIterator, (ExecutionEngine *engine, const Value &in, int iterator)) \ - F(ReturnedValue, iteratorNext, (ExecutionEngine *engine, const Value &iterator, Value *value)) \ - F(ReturnedValue, iteratorNextForYieldStar, (ExecutionEngine *engine, const Value &received, const Value &iterator, Value *object)) \ - F(ReturnedValue, iteratorClose, (ExecutionEngine *engine, const Value &iterator, const Value &done)) \ - F(ReturnedValue, destructureRestElement, (ExecutionEngine *engine, const Value &iterator)) \ - \ - /* unary operators */ \ - F(ReturnedValue, uMinus, (const Value &value)) \ - \ - /* binary operators */ \ - F(ReturnedValue, instanceof, (ExecutionEngine *engine, const Value &left, const Value &right)) \ - F(ReturnedValue, in, (ExecutionEngine *engine, const Value &left, const Value &right)) \ - F(ReturnedValue, add, (ExecutionEngine *engine, const Value &left, const Value &right)) \ - F(ReturnedValue, sub, (const Value &left, const Value &right)) \ - F(ReturnedValue, mul, (const Value &left, const Value &right)) \ - F(ReturnedValue, div, (const Value &left, const Value &right)) \ - F(ReturnedValue, mod, (const Value &left, const Value &right)) \ - F(ReturnedValue, shl, (const Value &left, const Value &right)) \ - F(ReturnedValue, shr, (const Value &left, const Value &right)) \ - F(ReturnedValue, ushr, (const Value &left, const Value &right)) \ - F(ReturnedValue, greaterThan, (const Value &left, const Value &right)) \ - F(ReturnedValue, lessThan, (const Value &left, const Value &right)) \ - F(ReturnedValue, greaterEqual, (const Value &left, const Value &right)) \ - F(ReturnedValue, lessEqual, (const Value &left, const Value &right)) \ - F(ReturnedValue, equal, (const Value &left, const Value &right)) \ - F(ReturnedValue, notEqual, (const Value &left, const Value &right)) \ - F(ReturnedValue, strictEqual, (const Value &left, const Value &right)) \ - F(ReturnedValue, strictNotEqual, (const Value &left, const Value &right)) \ - \ - /* comparisons */ \ - F(Bool, compareGreaterThan, (const Value &l, const Value &r)) \ - F(Bool, compareLessThan, (const Value &l, const Value &r)) \ - F(Bool, compareGreaterEqual, (const Value &l, const Value &r)) \ - F(Bool, compareLessEqual, (const Value &l, const Value &r)) \ - F(Bool, compareEqual, (const Value &left, const Value &right)) \ - F(Bool, compareNotEqual, (const Value &left, const Value &right)) \ - F(Bool, compareStrictEqual, (const Value &left, const Value &right)) \ - F(Bool, compareStrictNotEqual, (const Value &left, const Value &right)) \ - \ - F(Bool, compareInstanceof, (ExecutionEngine *engine, const Value &left, const Value &right)) \ - F(Bool, compareIn, (ExecutionEngine *engine, const Value &left, const Value &right)) \ - \ - F(ReturnedValue, regexpLiteral, (ExecutionEngine *engine, int id)) struct Q_QML_PRIVATE_EXPORT Runtime { - Runtime(); - typedef ReturnedValue (*UnaryOperation)(const Value &value); typedef ReturnedValue (*BinaryOperation)(const Value &left, const Value &right); - typedef ReturnedValue (*BinaryOperationContext)(ExecutionEngine *engine, const Value &left, const Value &right); + typedef ReturnedValue (*BinaryOperationContext)(ExecutionEngine *, const Value &left, const Value &right); -#define DEFINE_RUNTIME_METHOD_ENUM(returnvalue, name, args) name, - enum RuntimeMethods { - FOR_EACH_RUNTIME_METHOD(DEFINE_RUNTIME_METHOD_ENUM) - RuntimeMethodCount, - InvalidRuntimeMethod = RuntimeMethodCount + enum class Throws { No, Yes }; + enum class ChangesContext { No, Yes }; + enum class Pure { No, Yes }; + enum class LastArgumentIsOutputValue { No, Yes }; + + template<Throws t, ChangesContext c = ChangesContext::No, Pure p = Pure::No, + LastArgumentIsOutputValue out = LastArgumentIsOutputValue::No> + struct Method + { + static constexpr bool throws = t == Throws::Yes; + static constexpr bool changesContext = c == ChangesContext::Yes; + static constexpr bool pure = p == Pure::Yes; + static constexpr bool lastArgumentIsOutputValue = out == LastArgumentIsOutputValue::Yes; + }; + using PureMethod = Method<Throws::No, ChangesContext::No, Pure::Yes>; + using IteratorMethod = Method<Throws::Yes, ChangesContext::No, Pure::No, + LastArgumentIsOutputValue::Yes>; + + /* call */ + struct Q_QML_PRIVATE_EXPORT CallGlobalLookup : Method<Throws::Yes> + { + static ReturnedValue call(ExecutionEngine *, uint, Value[], int); + }; + struct Q_QML_PRIVATE_EXPORT CallQmlContextPropertyLookup : Method<Throws::Yes> + { + static ReturnedValue call(ExecutionEngine *, uint, Value[], int); + }; + struct Q_QML_PRIVATE_EXPORT CallName : Method<Throws::Yes> + { + static ReturnedValue call(ExecutionEngine *, int, Value[], int); + }; + struct Q_QML_PRIVATE_EXPORT CallProperty : Method<Throws::Yes> + { + static ReturnedValue call(ExecutionEngine *, const Value &, int, Value[], int); + }; + struct Q_QML_PRIVATE_EXPORT CallPropertyLookup : Method<Throws::Yes> + { + static ReturnedValue call(ExecutionEngine *, const Value &, uint, Value[], int); + }; + struct Q_QML_PRIVATE_EXPORT CallElement : Method<Throws::Yes> + { + static ReturnedValue call(ExecutionEngine *, const Value &, const Value &, Value[], int); + }; + struct Q_QML_PRIVATE_EXPORT CallValue : Method<Throws::Yes> + { + static ReturnedValue call(ExecutionEngine *, const Value &, Value[], int); + }; + struct Q_QML_PRIVATE_EXPORT CallWithReceiver : Method<Throws::Yes> + { + static ReturnedValue call(ExecutionEngine *, const Value &, const Value &, Value[], int); + }; + struct Q_QML_PRIVATE_EXPORT CallPossiblyDirectEval : Method<Throws::Yes> + { + static ReturnedValue call(ExecutionEngine *, Value[], int); + }; + struct Q_QML_PRIVATE_EXPORT CallWithSpread : Method<Throws::Yes> + { + static ReturnedValue call(ExecutionEngine *, const Value &, const Value &, Value[], int); + }; + struct Q_QML_PRIVATE_EXPORT TailCall : Method<Throws::Yes> + { + static ReturnedValue call(CppStackFrame *, ExecutionEngine *); }; -#undef DEFINE_RUNTIME_METHOD_ENUM - void *runtimeMethods[RuntimeMethodCount]; + /* construct */ + struct Q_QML_PRIVATE_EXPORT Construct : Method<Throws::Yes> + { + static ReturnedValue call(ExecutionEngine *, const Value &, const Value &, Value[], int); + }; + struct Q_QML_PRIVATE_EXPORT ConstructWithSpread : Method<Throws::Yes> + { + static ReturnedValue call(ExecutionEngine *, const Value &, const Value &, Value[], int); + }; - static uint runtimeMethodOffset(RuntimeMethods method) { return method*QT_POINTER_SIZE; } + /* load & store */ + struct Q_QML_PRIVATE_EXPORT StoreNameStrict : Method<Throws::Yes> + { + static void call(ExecutionEngine *, int, const Value &); + }; + struct Q_QML_PRIVATE_EXPORT StoreNameSloppy : Method<Throws::Yes> + { + static void call(ExecutionEngine *, int, const Value &); + }; + struct Q_QML_PRIVATE_EXPORT StoreProperty : Method<Throws::Yes> + { + static void call(ExecutionEngine *, const Value &, int, const Value &); + }; + struct Q_QML_PRIVATE_EXPORT StoreElement : Method<Throws::Yes> + { + static void call(ExecutionEngine *, const Value &, const Value &, const Value &); + }; + struct Q_QML_PRIVATE_EXPORT LoadProperty : Method<Throws::Yes> + { + static ReturnedValue call(ExecutionEngine *, const Value &, int); + }; + struct Q_QML_PRIVATE_EXPORT LoadName : Method<Throws::Yes> + { + static ReturnedValue call(ExecutionEngine *, int); + }; + struct Q_QML_PRIVATE_EXPORT LoadElement : Method<Throws::Yes> + { + static ReturnedValue call(ExecutionEngine *, const Value &, const Value &); + }; + struct Q_QML_PRIVATE_EXPORT LoadSuperProperty : Method<Throws::Yes> + { + static ReturnedValue call(ExecutionEngine *, const Value &); + }; + struct Q_QML_PRIVATE_EXPORT StoreSuperProperty : Method<Throws::Yes> + { + static void call(ExecutionEngine *, const Value &, const Value &); + }; + struct Q_QML_PRIVATE_EXPORT LoadSuperConstructor : Method<Throws::Yes> + { + static ReturnedValue call(ExecutionEngine *, const Value &); + }; + struct Q_QML_PRIVATE_EXPORT LoadGlobalLookup : Method<Throws::Yes> + { + static ReturnedValue call(ExecutionEngine *, Function *, int); + }; + struct Q_QML_PRIVATE_EXPORT LoadQmlContextPropertyLookup : Method<Throws::Yes> + { + static ReturnedValue call(ExecutionEngine *, uint); + }; + struct Q_QML_PRIVATE_EXPORT GetLookup : Method<Throws::Yes> + { + static ReturnedValue call(ExecutionEngine *, Function *, const Value &, int); + }; + struct Q_QML_PRIVATE_EXPORT SetLookupStrict : Method<Throws::Yes> + { + static void call(Function *, const Value &, int, const Value &); + }; + struct Q_QML_PRIVATE_EXPORT SetLookupSloppy : Method<Throws::Yes> + { + static void call(Function *, const Value &, int, const Value &); + }; + + /* typeof */ + struct Q_QML_PRIVATE_EXPORT TypeofValue : PureMethod + { + static ReturnedValue call(ExecutionEngine *, const Value &); + }; + struct Q_QML_PRIVATE_EXPORT TypeofName : Method<Throws::No> + { + static ReturnedValue call(ExecutionEngine *, int); + }; + + /* delete */ + struct Q_QML_PRIVATE_EXPORT DeleteProperty_NoThrow : Method<Throws::No> + { + static Bool call(ExecutionEngine *, const Value &, const Value &); + }; + struct Q_QML_PRIVATE_EXPORT DeleteProperty : Method<Throws::Yes> + { + static ReturnedValue call(ExecutionEngine *, Function *, const Value &, const Value &); + }; + struct Q_QML_PRIVATE_EXPORT DeleteName_NoThrow : Method<Throws::No> + { + static Bool call(ExecutionEngine *, int); + }; + struct Q_QML_PRIVATE_EXPORT DeleteName : Method<Throws::Yes> + { + static ReturnedValue call(ExecutionEngine *, Function *, int); + }; + + /* exceptions & scopes */ + struct Q_QML_PRIVATE_EXPORT ThrowException : Method<Throws::Yes> + { + static void call(ExecutionEngine *, const Value &); + }; + struct Q_QML_PRIVATE_EXPORT PushCallContext : Method<Throws::No, ChangesContext::Yes> + { + static void call(CppStackFrame *); + }; + struct Q_QML_PRIVATE_EXPORT PushWithContext : Method<Throws::Yes, ChangesContext::Yes> + { + static ReturnedValue call(ExecutionEngine *, const Value &); + }; + struct Q_QML_PRIVATE_EXPORT PushCatchContext : Method<Throws::No, ChangesContext::Yes> + { + static void call(ExecutionEngine *, int, int); + }; + struct Q_QML_PRIVATE_EXPORT PushBlockContext : Method<Throws::No, ChangesContext::Yes> + { + static void call(ExecutionEngine *, int); + }; + struct Q_QML_PRIVATE_EXPORT CloneBlockContext : Method<Throws::No, ChangesContext::Yes> + { + static void call(ExecutionEngine *); + }; + struct Q_QML_PRIVATE_EXPORT PushScriptContext : Method<Throws::No, ChangesContext::Yes> + { + static void call(ExecutionEngine *, int); + }; + struct Q_QML_PRIVATE_EXPORT PopScriptContext : Method<Throws::No, ChangesContext::Yes> + { + static void call(ExecutionEngine *); + }; + struct Q_QML_PRIVATE_EXPORT ThrowReferenceError : Method<Throws::Yes> + { + static void call(ExecutionEngine *, int); + }; + struct Q_QML_PRIVATE_EXPORT ThrowOnNullOrUndefined : Method<Throws::Yes> + { + static void call(ExecutionEngine *, const Value &); + }; + + /* closures */ + struct Q_QML_PRIVATE_EXPORT Closure : Method<Throws::No> + { + static ReturnedValue call(ExecutionEngine *, int); + }; -#define RUNTIME_METHOD(returnvalue, name, args) \ - typedef returnvalue (*Method_##name)args; \ - enum { Method_##name##_NeedsExceptionCheck = ExceptionCheck<Method_##name>::NeedsCheck }; \ - static returnvalue method_##name args; - FOR_EACH_RUNTIME_METHOD(RUNTIME_METHOD) -#undef RUNTIME_METHOD + /* Function header */ + struct Q_QML_PRIVATE_EXPORT ConvertThisToObject : Method<Throws::Yes> + { + static ReturnedValue call(ExecutionEngine *, const Value &); + }; + struct Q_QML_PRIVATE_EXPORT DeclareVar : Method<Throws::Yes> + { + static void call(ExecutionEngine *, Bool, int); + }; + struct Q_QML_PRIVATE_EXPORT CreateMappedArgumentsObject : Method<Throws::No> + { + static ReturnedValue call(ExecutionEngine *); + }; + struct Q_QML_PRIVATE_EXPORT CreateUnmappedArgumentsObject : Method<Throws::No> + { + static ReturnedValue call(ExecutionEngine *); + }; + struct Q_QML_PRIVATE_EXPORT CreateRestParameter : PureMethod + { + static ReturnedValue call(ExecutionEngine *, int); + }; + + /* literals */ + struct Q_QML_PRIVATE_EXPORT ArrayLiteral : Method<Throws::Yes> + { + static ReturnedValue call(ExecutionEngine *, Value[], uint); + }; + struct Q_QML_PRIVATE_EXPORT ObjectLiteral : Method<Throws::Yes> + { + static ReturnedValue call(ExecutionEngine *, int, Value[], int); + }; + struct Q_QML_PRIVATE_EXPORT CreateClass : Method<Throws::Yes> + { + static ReturnedValue call(ExecutionEngine *, int, const Value &, Value[]); + }; + + /* for-in, for-of and array destructuring */ + struct Q_QML_PRIVATE_EXPORT GetIterator : Method<Throws::Yes> + { + static ReturnedValue call(ExecutionEngine *, const Value &, int); + }; + struct Q_QML_PRIVATE_EXPORT IteratorNext : IteratorMethod + { + static ReturnedValue call(ExecutionEngine *, const Value &, Value *); + }; + struct Q_QML_PRIVATE_EXPORT IteratorNextForYieldStar : IteratorMethod + { + static ReturnedValue call(ExecutionEngine *, const Value &, const Value &, Value *); + }; + struct Q_QML_PRIVATE_EXPORT IteratorClose : Method<Throws::Yes> + { + static ReturnedValue call(ExecutionEngine *, const Value &, const Value &); + }; + struct Q_QML_PRIVATE_EXPORT DestructureRestElement : Method<Throws::Yes> + { + static ReturnedValue call(ExecutionEngine *, const Value &); + }; + + /* conversions */ + struct Q_QML_PRIVATE_EXPORT ToObject : Method<Throws::Yes> + { + static ReturnedValue call(ExecutionEngine *, const Value &); + }; + struct Q_QML_PRIVATE_EXPORT ToBoolean : PureMethod + { + static Bool call(const Value &); + }; + struct Q_QML_PRIVATE_EXPORT ToNumber : Method<Throws::Yes> + { + static ReturnedValue call(ExecutionEngine *, const Value &); + }; + /* unary operators */ + struct Q_QML_PRIVATE_EXPORT UMinus : Method<Throws::Yes> + { + static ReturnedValue call(const Value &); + }; + + /* binary operators */ + struct Q_QML_PRIVATE_EXPORT Instanceof : Method<Throws::Yes> + { + static ReturnedValue call(ExecutionEngine *, const Value &, const Value &); + }; + struct Q_QML_PRIVATE_EXPORT In : Method<Throws::Yes> + { + static ReturnedValue call(ExecutionEngine *, const Value &, const Value &); + }; + struct Q_QML_PRIVATE_EXPORT Add : Method<Throws::Yes> + { + static ReturnedValue call(ExecutionEngine *, const Value &, const Value &); + }; + struct Q_QML_PRIVATE_EXPORT Sub : Method<Throws::Yes> + { + static ReturnedValue call(const Value &, const Value &); + }; + struct Q_QML_PRIVATE_EXPORT Mul : Method<Throws::Yes> + { + static ReturnedValue call(const Value &, const Value &); + }; + struct Q_QML_PRIVATE_EXPORT Div : Method<Throws::Yes> + { + static ReturnedValue call(const Value &, const Value &); + }; + struct Q_QML_PRIVATE_EXPORT Mod : Method<Throws::Yes> + { + static ReturnedValue call(const Value &, const Value &); + }; + struct Q_QML_PRIVATE_EXPORT Exp : Method<Throws::Yes> + { + static ReturnedValue call(const Value &, const Value &); + }; + struct Q_QML_PRIVATE_EXPORT BitAnd : Method<Throws::Yes> + { + static ReturnedValue call(const Value &, const Value &); + }; + struct Q_QML_PRIVATE_EXPORT BitOr : Method<Throws::Yes> + { + static ReturnedValue call(const Value &, const Value &); + }; + struct Q_QML_PRIVATE_EXPORT BitXor : Method<Throws::Yes> + { + static ReturnedValue call(const Value &, const Value &); + }; + struct Q_QML_PRIVATE_EXPORT Shl : Method<Throws::Yes> + { + static ReturnedValue call(const Value &, const Value &); + }; + struct Q_QML_PRIVATE_EXPORT Shr : Method<Throws::Yes> + { + static ReturnedValue call(const Value &, const Value &); + }; + struct Q_QML_PRIVATE_EXPORT UShr : Method<Throws::Yes> + { + static ReturnedValue call(const Value &, const Value &); + }; + struct Q_QML_PRIVATE_EXPORT GreaterThan : Method<Throws::Yes> + { + static ReturnedValue call(const Value &, const Value &); + }; + struct Q_QML_PRIVATE_EXPORT LessThan : Method<Throws::Yes> + { + static ReturnedValue call(const Value &, const Value &); + }; + struct Q_QML_PRIVATE_EXPORT GreaterEqual : Method<Throws::Yes> + { + static ReturnedValue call(const Value &, const Value &); + }; + struct Q_QML_PRIVATE_EXPORT LessEqual : Method<Throws::Yes> + { + static ReturnedValue call(const Value &, const Value &); + }; + struct Q_QML_PRIVATE_EXPORT Equal : Method<Throws::Yes> + { + static ReturnedValue call(const Value &, const Value &); + }; + struct Q_QML_PRIVATE_EXPORT NotEqual : Method<Throws::Yes> + { + static ReturnedValue call(const Value &, const Value &); + }; + struct Q_QML_PRIVATE_EXPORT StrictEqual : Method<Throws::Yes> + { + static ReturnedValue call(const Value &, const Value &); + }; + struct Q_QML_PRIVATE_EXPORT StrictNotEqual : Method<Throws::Yes> + { + static ReturnedValue call(const Value &, const Value &); + }; + + /* comparisons */ + struct Q_QML_PRIVATE_EXPORT CompareGreaterThan : Method<Throws::Yes> + { + static Bool call(const Value &, const Value &); + }; + struct Q_QML_PRIVATE_EXPORT CompareLessThan : Method<Throws::Yes> + { + static Bool call(const Value &, const Value &); + }; + struct Q_QML_PRIVATE_EXPORT CompareGreaterEqual : Method<Throws::Yes> + { + static Bool call(const Value &, const Value &); + }; + struct Q_QML_PRIVATE_EXPORT CompareLessEqual : Method<Throws::Yes> + { + static Bool call(const Value &, const Value &); + }; + struct Q_QML_PRIVATE_EXPORT CompareEqual : Method<Throws::Yes> + { + static Bool call(const Value &, const Value &); + }; + struct Q_QML_PRIVATE_EXPORT CompareNotEqual : Method<Throws::Yes> + { + static Bool call(const Value &, const Value &); + }; + struct Q_QML_PRIVATE_EXPORT CompareStrictEqual : Method<Throws::Yes> + { + static Bool call(const Value &, const Value &); + }; + struct Q_QML_PRIVATE_EXPORT CompareStrictNotEqual : Method<Throws::Yes> + { + static Bool call(const Value &, const Value &); + }; + + struct Q_QML_PRIVATE_EXPORT CompareInstanceof : Method<Throws::Yes> + { + static Bool call(ExecutionEngine *, const Value &, const Value &); + }; + struct Q_QML_PRIVATE_EXPORT CompareIn : Method<Throws::Yes> + { + static Bool call(ExecutionEngine *, const Value &, const Value &); + }; + + struct Q_QML_PRIVATE_EXPORT RegexpLiteral : PureMethod + { + static ReturnedValue call(ExecutionEngine *, int); + }; + struct Q_QML_PRIVATE_EXPORT GetTemplateObject : PureMethod + { + static ReturnedValue call(Function *, int); + }; struct StackOffsets { static const int tailCall_function = -1; @@ -234,7 +503,6 @@ struct Q_QML_PRIVATE_EXPORT Runtime { }; static_assert(std::is_standard_layout<Runtime>::value, "Runtime needs to be standard layout in order for us to be able to use offsetof"); -static_assert(offsetof(Runtime, runtimeMethods) == 0, "JIT expects this to be the first member"); static_assert(sizeof(Runtime::BinaryOperation) == sizeof(void*), "JIT expects a function pointer to fit into a regular pointer, for cross-compilation offset translation"); } // namespace QV4 diff --git a/src/qml/jsruntime/qv4runtimecodegen.cpp b/src/qml/jsruntime/qv4runtimecodegen.cpp index 9866966936..99d0de5ec6 100644 --- a/src/qml/jsruntime/qv4runtimecodegen.cpp +++ b/src/qml/jsruntime/qv4runtimecodegen.cpp @@ -37,6 +37,7 @@ ** ****************************************************************************/ +#include "qv4engine_p.h" #include "qv4runtimecodegen_p.h" #include "qv4compilerscanfunctions_p.h" diff --git a/src/qml/jsruntime/qv4sequenceobject_p.h b/src/qml/jsruntime/qv4sequenceobject_p.h index da71215bed..886dfaa521 100644 --- a/src/qml/jsruntime/qv4sequenceobject_p.h +++ b/src/qml/jsruntime/qv4sequenceobject_p.h @@ -65,7 +65,7 @@ QT_BEGIN_NAMESPACE namespace QV4 { -struct SequencePrototype : public QV4::Object +struct Q_QML_PRIVATE_EXPORT SequencePrototype : public QV4::Object { V4_PROTOTYPE(arrayPrototype) void init(); diff --git a/src/qml/jsruntime/qv4serialize.cpp b/src/qml/jsruntime/qv4serialize.cpp deleted file mode 100644 index 50871a4d87..0000000000 --- a/src/qml/jsruntime/qv4serialize.cpp +++ /dev/null @@ -1,427 +0,0 @@ -/**************************************************************************** -** -** 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$ -** -****************************************************************************/ - -#include "qv4serialize_p.h" - -#include <private/qv8engine_p.h> -#if QT_CONFIG(qml_list_model) -#include <private/qqmllistmodel_p.h> -#include <private/qqmllistmodelworkeragent_p.h> -#endif - -#include <private/qv4value_p.h> -#include <private/qv4dateobject_p.h> -#include <private/qv4regexpobject_p.h> -#if QT_CONFIG(qml_sequence_object) -#include <private/qv4sequenceobject_p.h> -#endif -#include <private/qv4objectproto_p.h> -#include <private/qv4qobjectwrapper_p.h> - -QT_BEGIN_NAMESPACE - -using namespace QV4; - -// We allow the following JavaScript types to be passed between the main and -// the secondary thread: -// + undefined -// + null -// + Boolean -// + String -// + Function -// + Array -// + "Simple" Objects -// + Number -// + Date -// + RegExp -// <quint8 type><quint24 size><data> - -enum Type { - WorkerUndefined, - WorkerNull, - WorkerTrue, - WorkerFalse, - WorkerString, - WorkerFunction, - WorkerArray, - WorkerObject, - WorkerInt32, - WorkerUint32, - WorkerNumber, - WorkerDate, - WorkerRegexp, -#if QT_CONFIG(qml_list_model) - WorkerListModel, -#endif -#if QT_CONFIG(qml_sequence_object) - WorkerSequence -#endif -}; - -static inline quint32 valueheader(Type type, quint32 size = 0) -{ - return quint8(type) << 24 | (size & 0xFFFFFF); -} - -static inline Type headertype(quint32 header) -{ - return (Type)(header >> 24); -} - -static inline quint32 headersize(quint32 header) -{ - return header & 0xFFFFFF; -} - -static inline void push(QByteArray &data, quint32 value) -{ - data.append((const char *)&value, sizeof(quint32)); -} - -static inline void push(QByteArray &data, double value) -{ - data.append((const char *)&value, sizeof(double)); -} - -static inline void push(QByteArray &data, void *ptr) -{ - data.append((const char *)&ptr, sizeof(void *)); -} - -static inline void reserve(QByteArray &data, int extra) -{ - data.reserve(data.size() + extra); -} - -static inline quint32 popUint32(const char *&data) -{ - quint32 rv = *((const quint32 *)data); - data += sizeof(quint32); - return rv; -} - -static inline double popDouble(const char *&data) -{ - double rv = *((const double *)data); - data += sizeof(double); - return rv; -} - -static inline void *popPtr(const char *&data) -{ - void *rv = *((void *const *)data); - data += sizeof(void *); - return rv; -} - -// XXX TODO: Check that worker script is exception safe in the case of -// serialization/deserialization failures - -#define ALIGN(size) (((size) + 3) & ~3) -void Serialize::serialize(QByteArray &data, const QV4::Value &v, ExecutionEngine *engine) -{ - QV4::Scope scope(engine); - - if (v.isEmpty()) { - Q_ASSERT(!"Serialize: got empty value"); - } else if (v.isUndefined()) { - push(data, valueheader(WorkerUndefined)); - } else if (v.isNull()) { - push(data, valueheader(WorkerNull)); - } else if (v.isBoolean()) { - push(data, valueheader(v.booleanValue() == true ? WorkerTrue : WorkerFalse)); - } else if (v.isString()) { - const QString &qstr = v.toQString(); - int length = qstr.length(); - if (length > 0xFFFFFF) { - push(data, valueheader(WorkerUndefined)); - return; - } - int utf16size = ALIGN(length * sizeof(quint16)); - - reserve(data, utf16size + sizeof(quint32)); - push(data, valueheader(WorkerString, length)); - - int offset = data.size(); - data.resize(data.size() + utf16size); - char *buffer = data.data() + offset; - - memcpy(buffer, qstr.constData(), length*sizeof(QChar)); - } else if (v.as<FunctionObject>()) { - // XXX TODO: Implement passing function objects between the main and - // worker scripts - push(data, valueheader(WorkerUndefined)); - } else if (const QV4::ArrayObject *array = v.as<ArrayObject>()) { - uint length = array->getLength(); - if (length > 0xFFFFFF) { - push(data, valueheader(WorkerUndefined)); - return; - } - reserve(data, sizeof(quint32) + length * sizeof(quint32)); - push(data, valueheader(WorkerArray, length)); - ScopedValue val(scope); - for (uint ii = 0; ii < length; ++ii) - serialize(data, (val = array->get(ii)), engine); - } else if (v.isInteger()) { - reserve(data, 2 * sizeof(quint32)); - push(data, valueheader(WorkerInt32)); - push(data, (quint32)v.integerValue()); -// } else if (v.IsUint32()) { -// reserve(data, 2 * sizeof(quint32)); -// push(data, valueheader(WorkerUint32)); -// push(data, v.Uint32Value()); - } else if (v.isNumber()) { - reserve(data, sizeof(quint32) + sizeof(double)); - push(data, valueheader(WorkerNumber)); - push(data, v.asDouble()); - } else if (const QV4::DateObject *d = v.as<DateObject>()) { - reserve(data, sizeof(quint32) + sizeof(double)); - push(data, valueheader(WorkerDate)); - push(data, d->date()); - } else if (const RegExpObject *re = v.as<RegExpObject>()) { - quint32 flags = re->flags(); - QString pattern = re->source(); - int length = pattern.length() + 1; - if (length > 0xFFFFFF) { - push(data, valueheader(WorkerUndefined)); - return; - } - int utf16size = ALIGN(length * sizeof(quint16)); - - reserve(data, sizeof(quint32) + utf16size); - push(data, valueheader(WorkerRegexp, flags)); - push(data, (quint32)length); - - int offset = data.size(); - data.resize(data.size() + utf16size); - char *buffer = data.data() + offset; - - memcpy(buffer, pattern.constData(), length*sizeof(QChar)); - } else if (const QObjectWrapper *qobjectWrapper = v.as<QV4::QObjectWrapper>()) { - // XXX TODO: Generalize passing objects between the main thread and worker scripts so - // that others can trivially plug in their elements. -#if QT_CONFIG(qml_list_model) - QQmlListModel *lm = qobject_cast<QQmlListModel *>(qobjectWrapper->object()); - if (lm && lm->agent()) { - QQmlListModelWorkerAgent *agent = lm->agent(); - agent->addref(); - push(data, valueheader(WorkerListModel)); - push(data, (void *)agent); - return; - } -#else - Q_UNUSED(qobjectWrapper); -#endif - // No other QObject's are allowed to be sent - push(data, valueheader(WorkerUndefined)); - } else if (const Object *o = v.as<Object>()) { -#if QT_CONFIG(qml_sequence_object) - if (o->isListType()) { - // valid sequence. we generate a length (sequence length + 1 for the sequence type) - uint seqLength = ScopedValue(scope, o->get(engine->id_length()))->toUInt32(); - uint length = seqLength + 1; - if (length > 0xFFFFFF) { - push(data, valueheader(WorkerUndefined)); - return; - } - reserve(data, sizeof(quint32) + length * sizeof(quint32)); - push(data, valueheader(WorkerSequence, length)); - serialize(data, QV4::Value::fromInt32(QV4::SequencePrototype::metaTypeForSequence(o)), engine); // sequence type - ScopedValue val(scope); - for (uint ii = 0; ii < seqLength; ++ii) - serialize(data, (val = o->get(ii)), engine); // sequence elements - - return; - } -#endif - - // regular object - QV4::ScopedValue val(scope, v); - QV4::ScopedArrayObject properties(scope, QV4::ObjectPrototype::getOwnPropertyNames(engine, val)); - quint32 length = properties->getLength(); - if (length > 0xFFFFFF) { - push(data, valueheader(WorkerUndefined)); - return; - } - push(data, valueheader(WorkerObject, length)); - - QV4::ScopedValue s(scope); - for (quint32 ii = 0; ii < length; ++ii) { - s = properties->get(ii); - serialize(data, s, engine); - - QV4::String *str = s->as<String>(); - val = o->get(str); - if (scope.hasException()) - scope.engine->catchException(); - - serialize(data, val, engine); - } - return; - } else { - push(data, valueheader(WorkerUndefined)); - } -} - -ReturnedValue Serialize::deserialize(const char *&data, ExecutionEngine *engine) -{ - quint32 header = popUint32(data); - Type type = headertype(header); - - Scope scope(engine); - - switch (type) { - case WorkerUndefined: - return QV4::Encode::undefined(); - case WorkerNull: - return QV4::Encode::null(); - case WorkerTrue: - return QV4::Encode(true); - case WorkerFalse: - return QV4::Encode(false); - case WorkerString: - { - quint32 size = headersize(header); - QString qstr((const QChar *)data, size); - data += ALIGN(size * sizeof(quint16)); - return QV4::Encode(engine->newString(qstr)); - } - case WorkerFunction: - Q_ASSERT(!"Unreachable"); - break; - case WorkerArray: - { - quint32 size = headersize(header); - ScopedArrayObject a(scope, engine->newArrayObject()); - ScopedValue v(scope); - for (quint32 ii = 0; ii < size; ++ii) { - v = deserialize(data, engine); - a->put(ii, v); - } - return a.asReturnedValue(); - } - case WorkerObject: - { - quint32 size = headersize(header); - ScopedObject o(scope, engine->newObject()); - ScopedValue name(scope); - ScopedString n(scope); - ScopedValue value(scope); - for (quint32 ii = 0; ii < size; ++ii) { - name = deserialize(data, engine); - value = deserialize(data, engine); - n = name->asReturnedValue(); - o->put(n, value); - } - return o.asReturnedValue(); - } - case WorkerInt32: - return QV4::Encode((qint32)popUint32(data)); - case WorkerUint32: - return QV4::Encode(popUint32(data)); - case WorkerNumber: - return QV4::Encode(popDouble(data)); - case WorkerDate: - return QV4::Encode(engine->newDateObject(QV4::Value::fromDouble(popDouble(data)))); - case WorkerRegexp: - { - quint32 flags = headersize(header); - quint32 length = popUint32(data); - QString pattern = QString((const QChar *)data, length - 1); - data += ALIGN(length * sizeof(quint16)); - return Encode(engine->newRegExpObject(pattern, flags)); - } -#if QT_CONFIG(qml_list_model) - case WorkerListModel: - { - void *ptr = popPtr(data); - QQmlListModelWorkerAgent *agent = (QQmlListModelWorkerAgent *)ptr; - QV4::ScopedValue rv(scope, QV4::QObjectWrapper::wrap(engine, agent)); - // ### Find a better solution then the ugly property - QQmlListModelWorkerAgent::VariantRef ref(agent); - QVariant var = qVariantFromValue(ref); - QV4::ScopedValue v(scope, scope.engine->fromVariant(var)); - QV4::ScopedString s(scope, engine->newString(QStringLiteral("__qml:hidden:ref"))); - rv->as<Object>()->defineReadonlyProperty(s, v); - - agent->release(); - agent->setEngine(engine); - return rv->asReturnedValue(); - } -#endif -#if QT_CONFIG(qml_sequence_object) - case WorkerSequence: - { - ScopedValue value(scope); - bool succeeded = false; - quint32 length = headersize(header); - quint32 seqLength = length - 1; - value = deserialize(data, engine); - int sequenceType = value->integerValue(); - ScopedArrayObject array(scope, engine->newArrayObject()); - array->arrayReserve(seqLength); - for (quint32 ii = 0; ii < seqLength; ++ii) { - value = deserialize(data, engine); - array->arrayPut(ii, value); - } - array->setArrayLengthUnchecked(seqLength); - QVariant seqVariant = QV4::SequencePrototype::toVariant(array, sequenceType, &succeeded); - return QV4::SequencePrototype::fromVariant(engine, seqVariant, &succeeded); - } -#endif - } - Q_ASSERT(!"Unreachable"); - return QV4::Encode::undefined(); -} - -QByteArray Serialize::serialize(const QV4::Value &value, ExecutionEngine *engine) -{ - QByteArray rv; - serialize(rv, value, engine); - return rv; -} - -ReturnedValue Serialize::deserialize(const QByteArray &data, ExecutionEngine *engine) -{ - const char *stream = data.constData(); - return deserialize(stream, engine); -} - -QT_END_NAMESPACE - diff --git a/src/qml/jsruntime/qv4setobject.cpp b/src/qml/jsruntime/qv4setobject.cpp index 088ecbe30d..1664d1bd71 100644 --- a/src/qml/jsruntime/qv4setobject.cpp +++ b/src/qml/jsruntime/qv4setobject.cpp @@ -76,7 +76,7 @@ ReturnedValue WeakSetCtor::construct(const FunctionObject *f, const Value *argv, ScopedFunctionObject adder(scope, a->get(ScopedString(scope, scope.engine->newString(QString::fromLatin1("add"))))); if (!adder) return scope.engine->throwTypeError(); - ScopedObject iter(scope, Runtime::method_getIterator(scope.engine, iterable, true)); + ScopedObject iter(scope, Runtime::GetIterator::call(scope.engine, iterable, true)); CHECK_EXCEPTION(); if (!iter) return a.asReturnedValue(); @@ -84,7 +84,7 @@ ReturnedValue WeakSetCtor::construct(const FunctionObject *f, const Value *argv, Value *nextValue = scope.alloc(1); ScopedValue done(scope); forever { - done = Runtime::method_iteratorNext(scope.engine, iter, nextValue); + done = Runtime::IteratorNext::call(scope.engine, iter, nextValue); CHECK_EXCEPTION(); if (done->toBoolean()) return a.asReturnedValue(); @@ -92,7 +92,7 @@ ReturnedValue WeakSetCtor::construct(const FunctionObject *f, const Value *argv, adder->call(a, nextValue, 1); if (scope.engine->hasException) { ScopedValue falsey(scope, Encode(false)); - return Runtime::method_iteratorClose(scope.engine, iter, falsey); + return Runtime::IteratorClose::call(scope.engine, iter, falsey); } } } diff --git a/src/qml/jsruntime/qv4stackframe_p.h b/src/qml/jsruntime/qv4stackframe_p.h index 44cfef9173..51a6acf43c 100644 --- a/src/qml/jsruntime/qv4stackframe_p.h +++ b/src/qml/jsruntime/qv4stackframe_p.h @@ -52,6 +52,7 @@ #include <private/qv4context_p.h> #include <private/qv4enginebase_p.h> +#include <private/qv4calldata_p.h> #ifndef V4_BOOTSTRAP #include <private/qv4function_p.h> #endif @@ -60,55 +61,6 @@ QT_BEGIN_NAMESPACE namespace QV4 { -struct CallData -{ - enum Offsets { - Function = 0, - Context = 1, - Accumulator = 2, - This = 3, - NewTarget = 4, - Argc = 5, - - LastOffset = Argc, - OffsetCount = LastOffset + 1 - }; - - Value function; - Value context; - Value accumulator; - Value thisObject; - Value newTarget; - Value _argc; - - int argc() const { - Q_ASSERT(_argc.isInteger()); - return _argc.int_32(); - } - - void setArgc(int argc) { - Q_ASSERT(argc >= 0); - _argc.setInt_32(argc); - } - - inline ReturnedValue argument(int i) const { - return i < argc() ? args[i].asReturnedValue() : Value::undefinedValue().asReturnedValue(); - } - - Value args[1]; - - static Q_DECL_CONSTEXPR int HeaderSize() { return offsetof(CallData, args) / sizeof(QV4::Value); } -}; - -Q_STATIC_ASSERT(std::is_standard_layout<CallData>::value); -Q_STATIC_ASSERT(offsetof(CallData, function ) == CallData::Function * sizeof(Value)); -Q_STATIC_ASSERT(offsetof(CallData, context ) == CallData::Context * sizeof(Value)); -Q_STATIC_ASSERT(offsetof(CallData, accumulator) == CallData::Accumulator * sizeof(Value)); -Q_STATIC_ASSERT(offsetof(CallData, thisObject ) == CallData::This * sizeof(Value)); -Q_STATIC_ASSERT(offsetof(CallData, newTarget ) == CallData::NewTarget * sizeof(Value)); -Q_STATIC_ASSERT(offsetof(CallData, _argc ) == CallData::Argc * sizeof(Value)); -Q_STATIC_ASSERT(offsetof(CallData, args ) == 6 * sizeof(Value)); - struct Q_QML_EXPORT CppStackFrame { EngineBase *engine; Value *savedStackTop; diff --git a/src/qml/jsruntime/qv4string.cpp b/src/qml/jsruntime/qv4string.cpp index 68d65f2e24..24a17bf5d5 100644 --- a/src/qml/jsruntime/qv4string.cpp +++ b/src/qml/jsruntime/qv4string.cpp @@ -256,8 +256,3 @@ qint64 String::virtualGetLength(const Managed *m) } #endif // V4_BOOTSTRAP - -uint String::toArrayIndex(const QString &str) -{ - return QV4::String::toArrayIndex(str.constData(), str.constData() + str.length()); -} diff --git a/src/qml/jsruntime/qv4string_p.h b/src/qml/jsruntime/qv4string_p.h index fbd4f5f550..a986fe185e 100644 --- a/src/qml/jsruntime/qv4string_p.h +++ b/src/qml/jsruntime/qv4string_p.h @@ -54,6 +54,7 @@ #include "qv4managed_p.h" #include <QtCore/private/qnumeric_p.h> #include "qv4enginebase_p.h" +#include "qv4stringtoarrayindex_p.h" QT_BEGIN_NAMESPACE @@ -242,40 +243,11 @@ protected: #endif public: - static uint toArrayIndex(const QString &str); - -private: - static inline uint toUInt(const QChar *ch) { return ch->unicode(); } - static inline uint toUInt(const char *ch) { return static_cast<unsigned char>(*ch); } - - template <typename T> - static inline uint toArrayIndex(const T *ch, const T *end) - { - uint i = toUInt(ch) - '0'; - if (i > 9) - return UINT_MAX; - ++ch; - // reject "01", "001", ... - if (i == 0 && ch != end) - return UINT_MAX; - - while (ch < end) { - uint x = toUInt(ch) - '0'; - if (x > 9) - return UINT_MAX; - if (mul_overflow(i, uint(10), &i) || add_overflow(i, x, &i)) // i = i * 10 + x - return UINT_MAX; - ++ch; - } - return i; - } - -public: template <typename T> static inline uint calculateHashValue(const T *ch, const T* end, uint *subtype) { // array indices get their number as hash value - uint h = toArrayIndex(ch, end); + uint h = stringToArrayIndex(ch, end); if (h != UINT_MAX) { if (subtype) *subtype = Heap::StringOrSymbol::StringType_ArrayIndex; @@ -283,12 +255,12 @@ public: } while (ch < end) { - h = 31 * h + toUInt(ch); + h = 31 * h + charToUInt(ch); ++ch; } if (subtype) - *subtype = (toUInt(ch) == '@') ? Heap::StringOrSymbol::StringType_Symbol : Heap::StringOrSymbol::StringType_Regular; + *subtype = (charToUInt(ch) == '@') ? Heap::StringOrSymbol::StringType_Symbol : Heap::StringOrSymbol::StringType_Regular; return h; } }; diff --git a/src/qml/jsruntime/qv4stringobject.cpp b/src/qml/jsruntime/qv4stringobject.cpp index 6afa6d36d6..227df4014e 100644 --- a/src/qml/jsruntime/qv4stringobject.cpp +++ b/src/qml/jsruntime/qv4stringobject.cpp @@ -152,13 +152,14 @@ PropertyAttributes StringObject::virtualGetOwnProperty(const Managed *m, Propert if (attributes != Attr_Invalid) return attributes; - const StringObject *s = static_cast<const StringObject *>(m); - uint slen = s->d()->string->toQString().length(); - uint index = id.asArrayIndex(); - if (index < slen) { - if (p) - p->value = s->getIndex(index); - return Attr_NotConfigurable|Attr_NotWritable; + if (id.isArrayIndex()) { + const uint index = id.asArrayIndex(); + const auto s = static_cast<const StringObject *>(m); + if (index < uint(s->d()->string->toQString().length())) { + if (p) + p->value = s->getIndex(index); + return Attr_NotConfigurable|Attr_NotWritable; + } } return Object::virtualGetOwnProperty(m, id, p); } diff --git a/src/qml/jsruntime/qv4serialize_p.h b/src/qml/jsruntime/qv4stringtoarrayindex_p.h index c8700c3ca5..61bd988d1e 100644 --- a/src/qml/jsruntime/qv4serialize_p.h +++ b/src/qml/jsruntime/qv4stringtoarrayindex_p.h @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2016 The Qt Company Ltd. +** Copyright (C) 2019 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the QtQml module of the Qt Toolkit. @@ -37,8 +37,8 @@ ** ****************************************************************************/ -#ifndef QV4SERIALIZE_P_H -#define QV4SERIALIZE_P_H +#ifndef QV4STRINGTOARRAYINDEX_P_H +#define QV4STRINGTOARRAYINDEX_P_H // // W A R N I N G @@ -51,26 +51,46 @@ // We mean it. // -#include <QtCore/qbytearray.h> -#include <private/qv4value_p.h> +#include <QtCore/private/qnumeric_p.h> +#include <QtCore/qstring.h> +#include <limits> QT_BEGIN_NAMESPACE namespace QV4 { -class Serialize { -public: +inline uint charToUInt(const QChar *ch) { return ch->unicode(); } +inline uint charToUInt(const char *ch) { return static_cast<unsigned char>(*ch); } - static QByteArray serialize(const Value &, ExecutionEngine *); - static ReturnedValue deserialize(const QByteArray &, ExecutionEngine *); +template <typename T> +uint stringToArrayIndex(const T *ch, const T *end) +{ + uint i = charToUInt(ch) - '0'; + if (i > 9) + return std::numeric_limits<uint>::max(); + ++ch; + // reject "01", "001", ... + if (i == 0 && ch != end) + return std::numeric_limits<uint>::max(); -private: - static void serialize(QByteArray &, const Value &, ExecutionEngine *); - static ReturnedValue deserialize(const char *&, ExecutionEngine *); -}; + while (ch < end) { + uint x = charToUInt(ch) - '0'; + if (x > 9) + return std::numeric_limits<uint>::max(); + if (mul_overflow(i, uint(10), &i) || add_overflow(i, x, &i)) // i = i * 10 + x + return std::numeric_limits<uint>::max(); + ++ch; + } + return i; +} +inline uint stringToArrayIndex(const QString &str) +{ + return stringToArrayIndex(str.constData(), str.constData() + str.length()); } +} // namespace QV4 + QT_END_NAMESPACE -#endif // QV8WORKER_P_H +#endif // QV4STRINGTOARRAYINDEX_P_H diff --git a/src/qml/jsruntime/qv4typedarray.cpp b/src/qml/jsruntime/qv4typedarray.cpp index faf7934c06..43e1dabb6d 100644 --- a/src/qml/jsruntime/qv4typedarray.cpp +++ b/src/qml/jsruntime/qv4typedarray.cpp @@ -459,24 +459,23 @@ Heap::TypedArray *TypedArray::create(ExecutionEngine *e, Heap::TypedArray::Type ReturnedValue TypedArray::virtualGet(const Managed *m, PropertyKey id, const Value *receiver, bool *hasProperty) { - uint index = id.asArrayIndex(); - if (index == UINT_MAX && !id.isCanonicalNumericIndexString()) + const bool isArrayIndex = id.isArrayIndex(); + if (!isArrayIndex && !id.isCanonicalNumericIndexString()) return Object::virtualGet(m, id, receiver, hasProperty); - // fall through, with index == UINT_MAX it'll do the right thing. Scope scope(static_cast<const Object *>(m)->engine()); Scoped<TypedArray> a(scope, static_cast<const TypedArray *>(m)); if (a->d()->buffer->isDetachedBuffer()) return scope.engine->throwTypeError(); - if (index >= a->length()) { + if (!isArrayIndex || id.asArrayIndex() >= a->length()) { if (hasProperty) *hasProperty = false; return Encode::undefined(); } uint bytesPerElement = a->d()->type->bytesPerElement; - uint byteOffset = a->d()->byteOffset + index * bytesPerElement; + uint byteOffset = a->d()->byteOffset + id.asArrayIndex() * bytesPerElement; Q_ASSERT(byteOffset + bytesPerElement <= (uint)a->d()->buffer->byteLength()); if (hasProperty) @@ -486,27 +485,22 @@ ReturnedValue TypedArray::virtualGet(const Managed *m, PropertyKey id, const Val bool TypedArray::virtualHasProperty(const Managed *m, PropertyKey id) { - uint index = id.asArrayIndex(); - if (index == UINT_MAX && !id.isCanonicalNumericIndexString()) + const bool isArrayIndex = id.isArrayIndex(); + if (!isArrayIndex && !id.isCanonicalNumericIndexString()) return Object::virtualHasProperty(m, id); - // fall through, with index == UINT_MAX it'll do the right thing. const TypedArray *a = static_cast<const TypedArray *>(m); if (a->d()->buffer->isDetachedBuffer()) { a->engine()->throwTypeError(); return false; } - if (index >= a->length()) - return false; - return true; + return isArrayIndex && id.asArrayIndex() < a->length(); } PropertyAttributes TypedArray::virtualGetOwnProperty(const Managed *m, PropertyKey id, Property *p) { - uint index = id.asArrayIndex(); - if (index == UINT_MAX && !id.isCanonicalNumericIndexString()) + if (!id.isArrayIndex() && !id.isCanonicalNumericIndexString()) return Object::virtualGetOwnProperty(m, id, p); - // fall through, with index == UINT_MAX it'll do the right thing. bool hasProperty = false; ReturnedValue v = virtualGet(m, id, m, &hasProperty); @@ -517,10 +511,9 @@ PropertyAttributes TypedArray::virtualGetOwnProperty(const Managed *m, PropertyK bool TypedArray::virtualPut(Managed *m, PropertyKey id, const Value &value, Value *receiver) { - uint index = id.asArrayIndex(); - if (index == UINT_MAX && !id.isCanonicalNumericIndexString()) + const bool isArrayIndex = id.isArrayIndex(); + if (!isArrayIndex && !id.isCanonicalNumericIndexString()) return Object::virtualPut(m, id, value, receiver); - // fall through, with index == UINT_MAX it'll do the right thing. ExecutionEngine *v4 = static_cast<Object *>(m)->engine(); if (v4->hasException) @@ -531,6 +524,10 @@ bool TypedArray::virtualPut(Managed *m, PropertyKey id, const Value &value, Valu if (a->d()->buffer->isDetachedBuffer()) return scope.engine->throwTypeError(); + if (!isArrayIndex) + return false; + + const uint index = id.asArrayIndex(); if (index >= a->length()) return false; @@ -547,11 +544,12 @@ bool TypedArray::virtualPut(Managed *m, PropertyKey id, const Value &value, Valu bool TypedArray::virtualDefineOwnProperty(Managed *m, PropertyKey id, const Property *p, PropertyAttributes attrs) { - uint index = id.asArrayIndex(); - if (index == UINT_MAX && !id.isCanonicalNumericIndexString()) - return Object::virtualDefineOwnProperty(m, id, p, attrs); - // fall through, with index == UINT_MAX it'll do the right thing. + if (!id.isArrayIndex()) { + return !id.isCanonicalNumericIndexString() + && Object::virtualDefineOwnProperty(m, id, p, attrs); + } + const uint index = id.asArrayIndex(); TypedArray *a = static_cast<TypedArray *>(m); if (index >= a->length() || attrs.isAccessor()) return false; @@ -1595,7 +1593,7 @@ ReturnedValue IntrinsicTypedArrayPrototype::method_toLocaleString(const Function R += separator; v = instance->get(k); - v = Runtime::method_callElement(scope.engine, v, *scope.engine->id_toLocaleString(), nullptr, 0); + v = Runtime::CallElement::call(scope.engine, v, *scope.engine->id_toLocaleString(), nullptr, 0); s = v->toString(scope.engine); if (scope.hasException()) return Encode::undefined(); diff --git a/src/qml/jsruntime/qv4value.cpp b/src/qml/jsruntime/qv4value.cpp index cbc153bb86..82cf11f148 100644 --- a/src/qml/jsruntime/qv4value.cpp +++ b/src/qml/jsruntime/qv4value.cpp @@ -36,11 +36,11 @@ ** $QT_END_LICENSE$ ** ****************************************************************************/ -#include <qv4engine_p.h> + #include <qv4runtime_p.h> -#include <qv4string_p.h> #include <qv4propertykey_p.h> #ifndef V4_BOOTSTRAP +#include <qv4string_p.h> #include <qv4symbol_p.h> #include <qv4object_p.h> #include <qv4objectproto_p.h> @@ -248,7 +248,6 @@ QV4::PropertyKey Value::toPropertyKey(ExecutionEngine *e) const ScopedStringOrSymbol s(scope, v); return s->toPropertyKey(); } -#endif // V4_BOOTSTRAP bool Value::sameValue(Value other) const { if (_val == other._val) @@ -285,7 +284,6 @@ bool Value::sameValueZero(Value other) const { return false; } -#ifndef V4_BOOTSTRAP Heap::String *Value::toString(ExecutionEngine *e, Value val) { return RuntimeHelpers::convertToString(e, val); diff --git a/src/qml/jsruntime/qv4value_p.h b/src/qml/jsruntime/qv4value_p.h index b4a045edfb..da08841026 100644 --- a/src/qml/jsruntime/qv4value_p.h +++ b/src/qml/jsruntime/qv4value_p.h @@ -281,8 +281,22 @@ struct Q_QML_PRIVATE_EXPORT Value inline bool isUndefined() const { return _val == 0; } inline bool isDouble() const { return (_val >> IsDouble_Shift); } - inline bool isManaged() const { return _val && ((_val >> IsManagedOrUndefined_Shift) == 0); } - inline bool isManagedOrUndefined() const { return ((_val >> IsManagedOrUndefined_Shift) == 0); } + inline bool isManaged() const + { +#if QT_POINTER_SIZE == 4 + return value() && tag() == Managed_Type_Internal; +#else + return _val && ((_val >> IsManagedOrUndefined_Shift) == 0); +#endif + } + inline bool isManagedOrUndefined() const + { +#if QT_POINTER_SIZE == 4 + return tag() == Managed_Type_Internal; +#else + return ((_val >> IsManagedOrUndefined_Shift) == 0); +#endif + } inline bool isIntOrBool() const { return (_val >> IsIntegerOrBool_Shift) == 3; diff --git a/src/qml/jsruntime/qv4variantobject.cpp b/src/qml/jsruntime/qv4variantobject.cpp index e4d8bcaafc..e117e509ab 100644 --- a/src/qml/jsruntime/qv4variantobject.cpp +++ b/src/qml/jsruntime/qv4variantobject.cpp @@ -41,7 +41,6 @@ #include "qv4functionobject_p.h" #include "qv4objectproto_p.h" #include <private/qqmlvaluetypewrapper_p.h> -#include <private/qv8engine_p.h> #include <private/qv4qobjectwrapper_p.h> QT_BEGIN_NAMESPACE diff --git a/src/qml/jsruntime/qv4vme_moth.cpp b/src/qml/jsruntime/qv4vme_moth.cpp index d2c91da12c..d348a79861 100644 --- a/src/qml/jsruntime/qv4vme_moth.cpp +++ b/src/qml/jsruntime/qv4vme_moth.cpp @@ -61,12 +61,16 @@ #include "qv4alloca_p.h" +#if QT_CONFIG(qml_jit) #include <private/qv4baselinejit_p.h> +#endif #include <qtqml_tracepoints_p.h> #undef COUNT_INSTRUCTIONS +enum { ShowWhenDeoptimiationHappens = 0 }; + extern "C" { // This is the interface to Qt Creator's (new) QML debugger. @@ -345,73 +349,9 @@ static struct InstrCount { #undef CHECK_EXCEPTION #endif #define CHECK_EXCEPTION \ - if (engine->hasException) \ + if (engine->hasException || engine->isInterrupted) \ goto handleUnwind -static inline void traceJumpTakesTruePath(bool truePathTaken, Function *f, int slot) -{ -#if QT_CONFIG(qml_tracing) - quint8 *traceInfo = f->traceInfo(slot); - Q_ASSERT(traceInfo); - *traceInfo |= truePathTaken ? quint8(ObservedTraceValues::TruePathTaken) - : quint8(ObservedTraceValues::FalsePathTaken); -#else - Q_UNUSED(truePathTaken); - Q_UNUSED(f); - Q_UNUSED(slot); -#endif -} - -static inline void traceValue(ReturnedValue acc, Function *f, int slot) -{ -#if QT_CONFIG(qml_tracing) - quint8 *traceInfo = f->traceInfo(slot); - Q_ASSERT(traceInfo); - switch (Primitive::fromReturnedValue(acc).type()) { - case QV4::Value::Integer_Type: - *traceInfo |= quint8(ObservedTraceValues::Integer); - break; - case QV4::Value::Boolean_Type: - *traceInfo |= quint8(ObservedTraceValues::Boolean); - break; - case QV4::Value::Double_Type: - *traceInfo |= quint8(ObservedTraceValues::Double); - break; - default: - *traceInfo |= quint8(ObservedTraceValues::Other); - break; - } -#else - Q_UNUSED(acc); - Q_UNUSED(f); - Q_UNUSED(slot); -#endif -} - -static inline void traceDoubleValue(Function *f, int slot) -{ -#if QT_CONFIG(qml_tracing) - quint8 *traceInfo = f->traceInfo(slot); - Q_ASSERT(traceInfo); - *traceInfo |= quint8(ObservedTraceValues::Double); -#else - Q_UNUSED(f); - Q_UNUSED(slot); -#endif -} - -static inline void traceOtherValue(Function *f, int slot) -{ -#if QT_CONFIG(qml_tracing) - quint8 *traceInfo = f->traceInfo(slot); - Q_ASSERT(traceInfo); - *traceInfo |= quint8(ObservedTraceValues::Other); -#else - Q_UNUSED(f); - Q_UNUSED(slot); -#endif -} - static inline Heap::CallContext *getScope(QV4::Value *stack, int level) { Heap::ExecutionContext *scope = static_cast<ExecutionContext &>(stack[CallData::Context]).d(); @@ -491,7 +431,7 @@ ReturnedValue VME::exec(CppStackFrame *frame, ExecutionEngine *engine) Profiling::FunctionCallProfiler profiler(engine, function); // start execution profiling QV4::Debugging::Debugger *debugger = engine->debugger(); -#ifdef V4_ENABLE_JIT +#if QT_CONFIG(qml_jit) if (debugger == nullptr) { if (function->jittedCode == nullptr) { if (engine->canJIT(function)) @@ -499,16 +439,20 @@ ReturnedValue VME::exec(CppStackFrame *frame, ExecutionEngine *engine) else ++function->interpreterCallCount; } - if (function->jittedCode != nullptr) - return function->jittedCode(frame, engine); } -#endif // V4_ENABLE_JIT +#endif // QT_CONFIG(qml_jit) // interpreter if (debugger) debugger->enteringFunction(); - ReturnedValue result = interpret(frame, engine, function->codeData); + ReturnedValue result; + if (function->jittedCode != nullptr && debugger == nullptr) { + result = function->jittedCode(frame, engine); + } else { + // interpreter + result = interpret(frame, engine, function->codeData); + } if (debugger) debugger->leavingFunction(result); @@ -523,11 +467,6 @@ QV4::ReturnedValue VME::interpret(CppStackFrame *frame, ExecutionEngine *engine, QV4::ReturnedValue acc = accumulator.asReturnedValue(); Value *stack = reinterpret_cast<Value *>(frame->jsFrame); - if (function->tracingEnabled()) { - for (int i = 0; i < int(function->nFormals); ++i) - traceValue(frame->jsFrame->argument(i), function, i); - } - MOTH_JUMP_TABLE; for (;;) { @@ -586,7 +525,6 @@ QV4::ReturnedValue VME::interpret(CppStackFrame *frame, ExecutionEngine *engine, auto cc = static_cast<Heap::CallContext *>(stack[CallData::Context].m()); Q_ASSERT(cc->type != QV4::Heap::CallContext::Type_GlobalContext); acc = cc->locals[index].asReturnedValue(); - traceValue(acc, function, traceSlot); MOTH_END_INSTR(LoadLocal) MOTH_BEGIN_INSTR(StoreLocal) @@ -599,7 +537,6 @@ QV4::ReturnedValue VME::interpret(CppStackFrame *frame, ExecutionEngine *engine, MOTH_BEGIN_INSTR(LoadScopedLocal) auto cc = getScope(stack, scope); acc = cc->locals[index].asReturnedValue(); - traceValue(acc, function, traceSlot); MOTH_END_INSTR(LoadScopedLocal) MOTH_BEGIN_INSTR(StoreScopedLocal) @@ -613,18 +550,17 @@ QV4::ReturnedValue VME::interpret(CppStackFrame *frame, ExecutionEngine *engine, MOTH_END_INSTR(LoadRuntimeString) MOTH_BEGIN_INSTR(MoveRegExp) - STACK_VALUE(destReg) = Runtime::method_regexpLiteral(engine, regExpId); + STACK_VALUE(destReg) = Runtime::RegexpLiteral::call(engine, regExpId); MOTH_END_INSTR(MoveRegExp) MOTH_BEGIN_INSTR(LoadClosure) - acc = Runtime::method_closure(engine, value); + acc = Runtime::Closure::call(engine, value); MOTH_END_INSTR(LoadClosure) MOTH_BEGIN_INSTR(LoadName) STORE_IP(); - acc = Runtime::method_loadName(engine, name); + acc = Runtime::LoadName::call(engine, name); CHECK_EXCEPTION; - traceValue(acc, function, traceSlot); MOTH_END_INSTR(LoadName) MOTH_BEGIN_INSTR(LoadGlobalLookup) @@ -632,7 +568,6 @@ QV4::ReturnedValue VME::interpret(CppStackFrame *frame, ExecutionEngine *engine, QV4::Lookup *l = function->compilationUnit->runtimeLookups + index; acc = l->globalGetter(l, engine); CHECK_EXCEPTION; - traceValue(acc, function, traceSlot); MOTH_END_INSTR(LoadGlobalLookup) MOTH_BEGIN_INSTR(LoadQmlContextPropertyLookup) @@ -640,54 +575,41 @@ QV4::ReturnedValue VME::interpret(CppStackFrame *frame, ExecutionEngine *engine, QV4::Lookup *l = function->compilationUnit->runtimeLookups + index; acc = l->qmlContextPropertyGetter(l, engine, nullptr); CHECK_EXCEPTION; - traceValue(acc, function, traceSlot); MOTH_END_INSTR(LoadQmlContextPropertyLookup) MOTH_BEGIN_INSTR(StoreNameStrict) STORE_IP(); STORE_ACC(); - Runtime::method_storeNameStrict(engine, name, accumulator); + Runtime::StoreNameStrict::call(engine, name, accumulator); CHECK_EXCEPTION; MOTH_END_INSTR(StoreNameStrict) MOTH_BEGIN_INSTR(StoreNameSloppy) STORE_IP(); STORE_ACC(); - Runtime::method_storeNameSloppy(engine, name, accumulator); + Runtime::StoreNameSloppy::call(engine, name, accumulator); CHECK_EXCEPTION; MOTH_END_INSTR(StoreNameSloppy) MOTH_BEGIN_INSTR(LoadElement) STORE_IP(); STORE_ACC(); -#if QT_CONFIG(qml_tracing) - acc = Runtime::method_loadElement_traced(engine, STACK_VALUE(base), accumulator, function->traceInfo(traceSlot)); - traceValue(acc, function, traceSlot); -#else - Q_UNUSED(traceSlot); - acc = Runtime::method_loadElement(engine, STACK_VALUE(base), accumulator); -#endif + acc = Runtime::LoadElement::call(engine, STACK_VALUE(base), accumulator); CHECK_EXCEPTION; MOTH_END_INSTR(LoadElement) MOTH_BEGIN_INSTR(StoreElement) STORE_IP(); STORE_ACC(); -#if QT_CONFIG(qml_tracing) - Runtime::method_storeElement_traced(engine, STACK_VALUE(base), STACK_VALUE(index), accumulator, function->traceInfo(traceSlot)); -#else - Q_UNUSED(traceSlot); - Runtime::method_storeElement(engine, STACK_VALUE(base), STACK_VALUE(index), accumulator); -#endif + Runtime::StoreElement::call(engine, STACK_VALUE(base), STACK_VALUE(index), accumulator); CHECK_EXCEPTION; MOTH_END_INSTR(StoreElement) MOTH_BEGIN_INSTR(LoadProperty) STORE_IP(); STORE_ACC(); - acc = Runtime::method_loadProperty(engine, accumulator, name); + acc = Runtime::LoadProperty::call(engine, accumulator, name); CHECK_EXCEPTION; - traceValue(acc, function, traceSlot); MOTH_END_INSTR(LoadProperty) MOTH_BEGIN_INSTR(GetLookup) @@ -706,13 +628,12 @@ QV4::ReturnedValue VME::interpret(CppStackFrame *frame, ExecutionEngine *engine, acc = l->getter(l, engine, accumulator); CHECK_EXCEPTION; - traceValue(acc, function, traceSlot); MOTH_END_INSTR(GetLookup) MOTH_BEGIN_INSTR(StoreProperty) STORE_IP(); STORE_ACC(); - Runtime::method_storeProperty(engine, STACK_VALUE(base), name, accumulator); + Runtime::StoreProperty::call(engine, STACK_VALUE(base), name, accumulator); CHECK_EXCEPTION; MOTH_END_INSTR(StoreProperty) @@ -728,14 +649,14 @@ QV4::ReturnedValue VME::interpret(CppStackFrame *frame, ExecutionEngine *engine, MOTH_BEGIN_INSTR(LoadSuperProperty) STORE_IP(); STORE_ACC(); - acc = Runtime::method_loadSuperProperty(engine, STACK_VALUE(property)); + acc = Runtime::LoadSuperProperty::call(engine, STACK_VALUE(property)); CHECK_EXCEPTION; MOTH_END_INSTR(LoadSuperProperty) MOTH_BEGIN_INSTR(StoreSuperProperty) STORE_IP(); STORE_ACC(); - Runtime::method_storeSuperProperty(engine, STACK_VALUE(property), accumulator); + Runtime::StoreSuperProperty::call(engine, STACK_VALUE(property), accumulator); CHECK_EXCEPTION; MOTH_END_INSTR(StoreSuperProperty) @@ -766,7 +687,7 @@ QV4::ReturnedValue VME::interpret(CppStackFrame *frame, ExecutionEngine *engine, MOTH_BEGIN_INSTR(IteratorNextForYieldStar) STORE_ACC(); - acc = Runtime::method_iteratorNextForYieldStar(engine, accumulator, STACK_VALUE(iterator), &STACK_VALUE(object)); + acc = Runtime::IteratorNextForYieldStar::call(engine, accumulator, STACK_VALUE(iterator), &STACK_VALUE(object)); CHECK_EXCEPTION; MOTH_END_INSTR(IteratorNextForYieldStar) @@ -780,7 +701,6 @@ QV4::ReturnedValue VME::interpret(CppStackFrame *frame, ExecutionEngine *engine, Value undef = Value::undefinedValue(); acc = static_cast<const FunctionObject &>(func).call(&undef, stack + argv, argc); CHECK_EXCEPTION; - traceValue(acc, function, traceSlot); MOTH_END_INSTR(CallValue) MOTH_BEGIN_INSTR(CallWithReceiver) @@ -792,14 +712,12 @@ QV4::ReturnedValue VME::interpret(CppStackFrame *frame, ExecutionEngine *engine, } acc = static_cast<const FunctionObject &>(func).call(stack + thisObject, stack + argv, argc); CHECK_EXCEPTION; - traceValue(acc, function, traceSlot); MOTH_END_INSTR(CallWithReceiver) MOTH_BEGIN_INSTR(CallProperty) STORE_IP(); - acc = Runtime::method_callProperty(engine, stack + base, name, stack + argv, argc); + acc = Runtime::CallProperty::call(engine, stack[base], name, stack + argv, argc); CHECK_EXCEPTION; - traceValue(acc, function, traceSlot); MOTH_END_INSTR(CallProperty) MOTH_BEGIN_INSTR(CallPropertyLookup) @@ -827,49 +745,42 @@ QV4::ReturnedValue VME::interpret(CppStackFrame *frame, ExecutionEngine *engine, acc = static_cast<FunctionObject &>(f).call(stack + base, stack + argv, argc); CHECK_EXCEPTION; - traceValue(acc, function, traceSlot); MOTH_END_INSTR(CallPropertyLookup) MOTH_BEGIN_INSTR(CallElement) STORE_IP(); - acc = Runtime::method_callElement(engine, stack + base, STACK_VALUE(index), stack + argv, argc); + acc = Runtime::CallElement::call(engine, stack[base], STACK_VALUE(index), stack + argv, argc); CHECK_EXCEPTION; - traceValue(acc, function, traceSlot); MOTH_END_INSTR(CallElement) MOTH_BEGIN_INSTR(CallName) STORE_IP(); - acc = Runtime::method_callName(engine, name, stack + argv, argc); + acc = Runtime::CallName::call(engine, name, stack + argv, argc); CHECK_EXCEPTION; - traceValue(acc, function, traceSlot); MOTH_END_INSTR(CallName) MOTH_BEGIN_INSTR(CallPossiblyDirectEval) STORE_IP(); - acc = Runtime::method_callPossiblyDirectEval(engine, stack + argv, argc); + acc = Runtime::CallPossiblyDirectEval::call(engine, stack + argv, argc); CHECK_EXCEPTION; - traceValue(acc, function, traceSlot); MOTH_END_INSTR(CallPossiblyDirectEval) MOTH_BEGIN_INSTR(CallGlobalLookup) STORE_IP(); - acc = Runtime::method_callGlobalLookup(engine, index, stack + argv, argc); + acc = Runtime::CallGlobalLookup::call(engine, index, stack + argv, argc); CHECK_EXCEPTION; - traceValue(acc, function, traceSlot); MOTH_END_INSTR(CallGlobalLookup) MOTH_BEGIN_INSTR(CallQmlContextPropertyLookup) STORE_IP(); - acc = Runtime::method_callQmlContextPropertyLookup(engine, index, stack + argv, argc); + acc = Runtime::CallQmlContextPropertyLookup::call(engine, index, stack + argv, argc); CHECK_EXCEPTION; - traceValue(acc, function, traceSlot); MOTH_END_INSTR(CallQmlContextPropertyLookup) MOTH_BEGIN_INSTR(CallWithSpread) STORE_IP(); - acc = Runtime::method_callWithSpread(engine, STACK_VALUE(func), STACK_VALUE(thisObject), stack + argv, argc); + acc = Runtime::CallWithSpread::call(engine, STACK_VALUE(func), STACK_VALUE(thisObject), stack + argv, argc); CHECK_EXCEPTION; - traceValue(acc, function, traceSlot); MOTH_END_INSTR(CallWithSpread) MOTH_BEGIN_INSTR(TailCall) @@ -878,19 +789,19 @@ QV4::ReturnedValue VME::interpret(CppStackFrame *frame, ExecutionEngine *engine, *engine->jsAlloca(1) = Primitive::fromInt32(argv); *engine->jsAlloca(1) = STACK_VALUE(thisObject); *engine->jsAlloca(1) = STACK_VALUE(func); - return Runtime::method_tailCall(frame, engine); + return Runtime::TailCall::call(frame, engine); CHECK_EXCEPTION; MOTH_END_INSTR(TailCall) MOTH_BEGIN_INSTR(Construct) STORE_IP(); - acc = Runtime::method_construct(engine, STACK_VALUE(func), ACC, stack + argv, argc); + acc = Runtime::Construct::call(engine, STACK_VALUE(func), ACC, stack + argv, argc); CHECK_EXCEPTION; MOTH_END_INSTR(Construct) MOTH_BEGIN_INSTR(ConstructWithSpread) STORE_IP(); - acc = Runtime::method_constructWithSpread(engine, STACK_VALUE(func), ACC, stack + argv, argc); + acc = Runtime::ConstructWithSpread::call(engine, STACK_VALUE(func), ACC, stack + argv, argc); CHECK_EXCEPTION; MOTH_END_INSTR(ConstructWithSpread) @@ -918,7 +829,7 @@ QV4::ReturnedValue VME::interpret(CppStackFrame *frame, ExecutionEngine *engine, if (ACC.isEmpty()) { STORE_IP(); STORE_ACC(); - Runtime::method_throwReferenceError(engine, name); + Runtime::ThrowReferenceError::call(engine, name); goto handleUnwind; } MOTH_END_INSTR(DeadTemporalZoneCheck) @@ -926,7 +837,7 @@ QV4::ReturnedValue VME::interpret(CppStackFrame *frame, ExecutionEngine *engine, MOTH_BEGIN_INSTR(ThrowException) STORE_IP(); STORE_ACC(); - Runtime::method_throwException(engine, accumulator); + Runtime::ThrowException::call(engine, accumulator); goto handleUnwind; MOTH_END_INSTR(ThrowException) @@ -944,40 +855,36 @@ QV4::ReturnedValue VME::interpret(CppStackFrame *frame, ExecutionEngine *engine, MOTH_END_INSTR(SetException) MOTH_BEGIN_INSTR(PushCatchContext) - ExecutionContext *c = static_cast<ExecutionContext *>(stack + CallData::Context); - STACK_VALUE(CallData::Context) = Runtime::method_createCatchContext(c, index, name); + Runtime::PushCatchContext::call(engine, index, name); MOTH_END_INSTR(PushCatchContext) MOTH_BEGIN_INSTR(CreateCallContext) - stack[CallData::Context] = ExecutionContext::newCallContext(frame); + Runtime::PushCallContext::call(frame); MOTH_END_INSTR(CreateCallContext) MOTH_BEGIN_INSTR(PushWithContext) STORE_IP(); STORE_ACC(); - auto ctx = Runtime::method_createWithContext(engine, stack); + acc = Runtime::PushWithContext::call(engine, stack[CallData::Accumulator]); CHECK_EXCEPTION; - STACK_VALUE(CallData::Context) = ctx; MOTH_END_INSTR(PushWithContext) MOTH_BEGIN_INSTR(PushBlockContext) STORE_ACC(); - ExecutionContext *c = static_cast<ExecutionContext *>(stack + CallData::Context); - STACK_VALUE(CallData::Context) = Runtime::method_createBlockContext(c, index); + Runtime::PushBlockContext::call(engine, index); MOTH_END_INSTR(PushBlockContext) MOTH_BEGIN_INSTR(CloneBlockContext) STORE_ACC(); - ExecutionContext *c = static_cast<ExecutionContext *>(stack + CallData::Context); - STACK_VALUE(CallData::Context) = Runtime::method_cloneBlockContext(c); + Runtime::CloneBlockContext::call(engine); MOTH_END_INSTR(CloneBlockContext) MOTH_BEGIN_INSTR(PushScriptContext) - STACK_VALUE(CallData::Context) = Runtime::method_createScriptContext(engine, index); + Runtime::PushScriptContext::call(engine, index); MOTH_END_INSTR(PushScriptContext) MOTH_BEGIN_INSTR(PopScriptContext) - STACK_VALUE(CallData::Context) = Runtime::method_popScriptContext(engine); + Runtime::PopScriptContext::call(engine); MOTH_END_INSTR(PopScriptContext) MOTH_BEGIN_INSTR(PopContext) @@ -988,14 +895,14 @@ QV4::ReturnedValue VME::interpret(CppStackFrame *frame, ExecutionEngine *engine, MOTH_BEGIN_INSTR(GetIterator) STORE_IP(); STORE_ACC(); - acc = Runtime::method_getIterator(engine, accumulator, iterator); + acc = Runtime::GetIterator::call(engine, accumulator, iterator); CHECK_EXCEPTION; MOTH_END_INSTR(GetIterator) MOTH_BEGIN_INSTR(IteratorNext) STORE_IP(); STORE_ACC(); - acc = Runtime::method_iteratorNext(engine, accumulator, &STACK_VALUE(value)); + acc = Runtime::IteratorNext::call(engine, accumulator, &STACK_VALUE(value)); STACK_VALUE(done) = acc; CHECK_EXCEPTION; MOTH_END_INSTR(IteratorNext) @@ -1003,97 +910,73 @@ QV4::ReturnedValue VME::interpret(CppStackFrame *frame, ExecutionEngine *engine, MOTH_BEGIN_INSTR(IteratorClose) STORE_IP(); STORE_ACC(); - acc = Runtime::method_iteratorClose(engine, accumulator, STACK_VALUE(done)); + acc = Runtime::IteratorClose::call(engine, accumulator, STACK_VALUE(done)); CHECK_EXCEPTION; MOTH_END_INSTR(IteratorClose) MOTH_BEGIN_INSTR(DestructureRestElement) STORE_IP(); STORE_ACC(); - acc = Runtime::method_destructureRestElement(engine, ACC); + acc = Runtime::DestructureRestElement::call(engine, ACC); CHECK_EXCEPTION; MOTH_END_INSTR(DestructureRestElement) MOTH_BEGIN_INSTR(DeleteProperty) - if (!Runtime::method_deleteProperty(engine, STACK_VALUE(base), STACK_VALUE(index))) { - if (function->isStrict()) { - STORE_IP(); - engine->throwTypeError(); - goto handleUnwind; - } - acc = Encode(false); - } else { - acc = Encode(true); - } + acc = Runtime::DeleteProperty::call(engine, function, STACK_VALUE(base), STACK_VALUE(index)); + CHECK_EXCEPTION; MOTH_END_INSTR(DeleteProperty) MOTH_BEGIN_INSTR(DeleteName) - if (!Runtime::method_deleteName(engine, name)) { - if (function->isStrict()) { - STORE_IP(); - QString n = function->compilationUnit->runtimeStrings[name]->toQString(); - engine->throwSyntaxError(QStringLiteral("Can't delete property %1").arg(n)); - goto handleUnwind; - } - acc = Encode(false); - } else { - acc = Encode(true); - } + acc = Runtime::DeleteName::call(engine, function, name); + CHECK_EXCEPTION; MOTH_END_INSTR(DeleteName) MOTH_BEGIN_INSTR(TypeofName) - acc = Runtime::method_typeofName(engine, name); + acc = Runtime::TypeofName::call(engine, name); MOTH_END_INSTR(TypeofName) MOTH_BEGIN_INSTR(TypeofValue) STORE_ACC(); - acc = Runtime::method_typeofValue(engine, accumulator); + acc = Runtime::TypeofValue::call(engine, accumulator); MOTH_END_INSTR(TypeofValue) MOTH_BEGIN_INSTR(DeclareVar) - Runtime::method_declareVar(engine, isDeletable, varName); + Runtime::DeclareVar::call(engine, isDeletable, varName); MOTH_END_INSTR(DeclareVar) MOTH_BEGIN_INSTR(DefineArray) QV4::Value *arguments = stack + args; - acc = Runtime::method_arrayLiteral(engine, arguments, argc); + acc = Runtime::ArrayLiteral::call(engine, arguments, argc); MOTH_END_INSTR(DefineArray) MOTH_BEGIN_INSTR(DefineObjectLiteral) QV4::Value *arguments = stack + args; - acc = Runtime::method_objectLiteral(engine, internalClassId, arguments, argc); + acc = Runtime::ObjectLiteral::call(engine, internalClassId, arguments, argc); MOTH_END_INSTR(DefineObjectLiteral) MOTH_BEGIN_INSTR(CreateClass) - acc = Runtime::method_createClass(engine, classIndex, STACK_VALUE(heritage), stack + computedNames); + acc = Runtime::CreateClass::call(engine, classIndex, STACK_VALUE(heritage), stack + computedNames); MOTH_END_INSTR(CreateClass) MOTH_BEGIN_INSTR(CreateMappedArgumentsObject) - acc = Runtime::method_createMappedArgumentsObject(engine); + acc = Runtime::CreateMappedArgumentsObject::call(engine); MOTH_END_INSTR(CreateMappedArgumentsObject) MOTH_BEGIN_INSTR(CreateUnmappedArgumentsObject) - acc = Runtime::method_createUnmappedArgumentsObject(engine); + acc = Runtime::CreateUnmappedArgumentsObject::call(engine); MOTH_END_INSTR(CreateUnmappedArgumentsObject) MOTH_BEGIN_INSTR(CreateRestParameter) - acc = Runtime::method_createRestParameter(engine, argIndex); + acc = Runtime::CreateRestParameter::call(engine, argIndex); MOTH_END_INSTR(CreateRestParameter) MOTH_BEGIN_INSTR(ConvertThisToObject) - Value *t = &stack[CallData::This]; - if (!t->isObject()) { - if (t->isNullOrUndefined()) { - *t = engine->globalObject->asReturnedValue(); - } else { - *t = t->toObject(engine)->asReturnedValue(); - CHECK_EXCEPTION; - } - } + stack[CallData::This] = Runtime::ConvertThisToObject::call(engine, stack[CallData::This]); + CHECK_EXCEPTION; MOTH_END_INSTR(ConvertThisToObject) MOTH_BEGIN_INSTR(LoadSuperConstructor) - acc = Runtime::method_loadSuperConstructor(engine, stack[CallData::Function]); + acc = Runtime::LoadSuperConstructor::call(engine, stack[CallData::Function]); CHECK_EXCEPTION; MOTH_END_INSTR(LoadSuperConstructor) @@ -1112,7 +995,6 @@ QV4::ReturnedValue VME::interpret(CppStackFrame *frame, ExecutionEngine *engine, takeJump = ACC.int_32(); else takeJump = ACC.toBoolean(); - traceJumpTakesTruePath(takeJump, function, traceSlot); if (takeJump) code += offset; MOTH_END_INSTR(JumpTrue) @@ -1123,7 +1005,6 @@ QV4::ReturnedValue VME::interpret(CppStackFrame *frame, ExecutionEngine *engine, takeJump = !ACC.int_32(); else takeJump = !ACC.toBoolean(); - traceJumpTakesTruePath(!takeJump, function, traceSlot); if (takeJump) code += offset; MOTH_END_INSTR(JumpFalse) @@ -1138,6 +1019,10 @@ QV4::ReturnedValue VME::interpret(CppStackFrame *frame, ExecutionEngine *engine, code += offset; MOTH_END_INSTR(JumpNotUndefined) + MOTH_BEGIN_INSTR(CheckException) + CHECK_EXCEPTION; + MOTH_END_INSTR(CheckException) + MOTH_BEGIN_INSTR(CmpEqNull) acc = Encode(ACC.isNullOrUndefined()); MOTH_END_INSTR(CmpEqNull) @@ -1174,7 +1059,7 @@ QV4::ReturnedValue VME::interpret(CppStackFrame *frame, ExecutionEngine *engine, acc = Encode(left.int_32() == ACC.int_32()); } else { STORE_ACC(); - acc = Encode(bool(Runtime::method_compareEqual(left, accumulator))); + acc = Encode(bool(Runtime::CompareEqual::call(left, accumulator))); CHECK_EXCEPTION; } MOTH_END_INSTR(CmpEq) @@ -1185,7 +1070,7 @@ QV4::ReturnedValue VME::interpret(CppStackFrame *frame, ExecutionEngine *engine, acc = Encode(bool(left.int_32() != ACC.int_32())); } else { STORE_ACC(); - acc = Encode(bool(!Runtime::method_compareEqual(left, accumulator))); + acc = Encode(bool(!Runtime::CompareEqual::call(left, accumulator))); CHECK_EXCEPTION; } MOTH_END_INSTR(CmpNe) @@ -1198,7 +1083,7 @@ QV4::ReturnedValue VME::interpret(CppStackFrame *frame, ExecutionEngine *engine, acc = Encode(left.asDouble() > ACC.asDouble()); } else { STORE_ACC(); - acc = Encode(bool(Runtime::method_compareGreaterThan(left, accumulator))); + acc = Encode(bool(Runtime::CompareGreaterThan::call(left, accumulator))); CHECK_EXCEPTION; } MOTH_END_INSTR(CmpGt) @@ -1211,7 +1096,7 @@ QV4::ReturnedValue VME::interpret(CppStackFrame *frame, ExecutionEngine *engine, acc = Encode(left.asDouble() >= ACC.asDouble()); } else { STORE_ACC(); - acc = Encode(bool(Runtime::method_compareGreaterEqual(left, accumulator))); + acc = Encode(bool(Runtime::CompareGreaterEqual::call(left, accumulator))); CHECK_EXCEPTION; } MOTH_END_INSTR(CmpGe) @@ -1224,7 +1109,7 @@ QV4::ReturnedValue VME::interpret(CppStackFrame *frame, ExecutionEngine *engine, acc = Encode(left.asDouble() < ACC.asDouble()); } else { STORE_ACC(); - acc = Encode(bool(Runtime::method_compareLessThan(left, accumulator))); + acc = Encode(bool(Runtime::CompareLessThan::call(left, accumulator))); CHECK_EXCEPTION; } MOTH_END_INSTR(CmpLt) @@ -1237,7 +1122,7 @@ QV4::ReturnedValue VME::interpret(CppStackFrame *frame, ExecutionEngine *engine, acc = Encode(left.asDouble() <= ACC.asDouble()); } else { STORE_ACC(); - acc = Encode(bool(Runtime::method_compareLessEqual(left, accumulator))); + acc = Encode(bool(Runtime::CompareLessEqual::call(left, accumulator))); CHECK_EXCEPTION; } MOTH_END_INSTR(CmpLe) @@ -1247,7 +1132,7 @@ QV4::ReturnedValue VME::interpret(CppStackFrame *frame, ExecutionEngine *engine, acc = Encode(true); } else { STORE_ACC(); - acc = Encode(bool(RuntimeHelpers::strictEqual(STACK_VALUE(lhs), accumulator))); + acc = Runtime::StrictEqual::call(STACK_VALUE(lhs), accumulator); CHECK_EXCEPTION; } MOTH_END_INSTR(CmpStrictEqual) @@ -1255,7 +1140,7 @@ QV4::ReturnedValue VME::interpret(CppStackFrame *frame, ExecutionEngine *engine, MOTH_BEGIN_INSTR(CmpStrictNotEqual) if (STACK_VALUE(lhs).rawValue() != ACC.rawValue() || ACC.isNaN()) { STORE_ACC(); - acc = Encode(!RuntimeHelpers::strictEqual(STACK_VALUE(lhs), accumulator)); + acc = Runtime::StrictNotEqual::call(STACK_VALUE(lhs), accumulator); CHECK_EXCEPTION; } else { acc = Encode(false); @@ -1264,13 +1149,13 @@ QV4::ReturnedValue VME::interpret(CppStackFrame *frame, ExecutionEngine *engine, MOTH_BEGIN_INSTR(CmpIn) STORE_ACC(); - acc = Runtime::method_in(engine, STACK_VALUE(lhs), accumulator); + acc = Runtime::In::call(engine, STACK_VALUE(lhs), accumulator); CHECK_EXCEPTION; MOTH_END_INSTR(CmpIn) MOTH_BEGIN_INSTR(CmpInstanceOf) STORE_ACC(); - acc = Runtime::method_instanceof(engine, STACK_VALUE(lhs), ACC); + acc = Runtime::Instanceof::call(engine, STACK_VALUE(lhs), ACC); CHECK_EXCEPTION; MOTH_END_INSTR(CmpInstanceOf) @@ -1294,17 +1179,14 @@ QV4::ReturnedValue VME::interpret(CppStackFrame *frame, ExecutionEngine *engine, int a = ACC.int_32(); if (a == 0 || a == std::numeric_limits<int>::min()) { acc = Encode(-static_cast<double>(a)); - traceDoubleValue(function, traceSlot); } else { - acc = sub_int32(0, ACC.int_32(), function->traceInfo(traceSlot)); + acc = sub_int32(0, ACC.int_32()); } } else if (ACC.isDouble()) { acc ^= (1ull << 63); // simply flip sign bit - traceDoubleValue(function, traceSlot); } else { acc = Encode(-ACC.toNumberImpl()); CHECK_EXCEPTION; - traceOtherValue(function, traceSlot); } MOTH_END_INSTR(UMinus) @@ -1315,57 +1197,49 @@ QV4::ReturnedValue VME::interpret(CppStackFrame *frame, ExecutionEngine *engine, MOTH_BEGIN_INSTR(Increment) if (Q_LIKELY(ACC.integerCompatible())) { - acc = add_int32(ACC.int_32(), 1, function->traceInfo(traceSlot)); + acc = add_int32(ACC.int_32(), 1); } else if (ACC.isDouble()) { acc = QV4::Encode(ACC.doubleValue() + 1.); - traceDoubleValue(function, traceSlot); } else { acc = Encode(ACC.toNumberImpl() + 1.); CHECK_EXCEPTION; - traceDoubleValue(function, traceSlot); } MOTH_END_INSTR(Increment) MOTH_BEGIN_INSTR(Decrement) if (Q_LIKELY(ACC.integerCompatible())) { - acc = sub_int32(ACC.int_32(), 1, function->traceInfo(traceSlot)); + acc = sub_int32(ACC.int_32(), 1); } else if (ACC.isDouble()) { acc = QV4::Encode(ACC.doubleValue() - 1.); - traceDoubleValue(function, traceSlot); } else { acc = Encode(ACC.toNumberImpl() - 1.); CHECK_EXCEPTION; - traceDoubleValue(function, traceSlot); } MOTH_END_INSTR(Decrement) MOTH_BEGIN_INSTR(Add) const Value left = STACK_VALUE(lhs); if (Q_LIKELY(Value::integerCompatible(left, ACC))) { - acc = add_int32(left.int_32(), ACC.int_32(), function->traceInfo(traceSlot)); + acc = add_int32(left.int_32(), ACC.int_32()); } else if (left.isNumber() && ACC.isNumber()) { acc = Encode(left.asDouble() + ACC.asDouble()); - traceDoubleValue(function, traceSlot); } else { STORE_ACC(); - acc = Runtime::method_add(engine, left, accumulator); + acc = Runtime::Add::call(engine, left, accumulator); CHECK_EXCEPTION; - traceOtherValue(function, traceSlot); } MOTH_END_INSTR(Add) MOTH_BEGIN_INSTR(Sub) const Value left = STACK_VALUE(lhs); if (Q_LIKELY(Value::integerCompatible(left, ACC))) { - acc = sub_int32(left.int_32(), ACC.int_32(), function->traceInfo(traceSlot)); + acc = sub_int32(left.int_32(), ACC.int_32()); } else if (left.isNumber() && ACC.isNumber()) { acc = Encode(left.asDouble() - ACC.asDouble()); - traceDoubleValue(function, traceSlot); } else { STORE_ACC(); - acc = Runtime::method_sub(left, accumulator); + acc = Runtime::Sub::call(left, accumulator); CHECK_EXCEPTION; - traceOtherValue(function, traceSlot); } MOTH_END_INSTR(Sub) @@ -1382,29 +1256,26 @@ QV4::ReturnedValue VME::interpret(CppStackFrame *frame, ExecutionEngine *engine, MOTH_BEGIN_INSTR(Mul) const Value left = STACK_VALUE(lhs); if (Q_LIKELY(Value::integerCompatible(left, ACC))) { - acc = mul_int32(left.int_32(), ACC.int_32(), function->traceInfo(traceSlot)); + acc = mul_int32(left.int_32(), ACC.int_32()); } else if (left.isNumber() && ACC.isNumber()) { acc = Encode(left.asDouble() * ACC.asDouble()); - traceDoubleValue(function, traceSlot); } else { STORE_ACC(); - acc = Runtime::method_mul(left, accumulator); + acc = Runtime::Mul::call(left, accumulator); CHECK_EXCEPTION; - traceOtherValue(function, traceSlot); } MOTH_END_INSTR(Mul) MOTH_BEGIN_INSTR(Div) STORE_ACC(); - acc = Runtime::method_div(STACK_VALUE(lhs), accumulator); + acc = Runtime::Div::call(STACK_VALUE(lhs), accumulator); CHECK_EXCEPTION; MOTH_END_INSTR(Div) MOTH_BEGIN_INSTR(Mod) STORE_ACC(); - acc = Runtime::method_mod(STACK_VALUE(lhs), accumulator); + acc = Runtime::Mod::call(STACK_VALUE(lhs), accumulator); CHECK_EXCEPTION; - traceValue(acc, function, traceSlot); MOTH_END_INSTR(Mod) MOTH_BEGIN_INSTR(BitAnd) @@ -1491,7 +1362,7 @@ QV4::ReturnedValue VME::interpret(CppStackFrame *frame, ExecutionEngine *engine, MOTH_END_INSTR(ThrowOnNullOrUndefined) MOTH_BEGIN_INSTR(GetTemplateObject) - acc = RuntimeHelpers::getTemplateObject(function, index); + acc = Runtime::GetTemplateObject::call(function, index); MOTH_END_INSTR(GetTemplateObject) MOTH_BEGIN_INSTR(Debug) @@ -1502,7 +1373,10 @@ QV4::ReturnedValue VME::interpret(CppStackFrame *frame, ExecutionEngine *engine, MOTH_END_INSTR(Debug) handleUnwind: - Q_ASSERT(engine->hasException || frame->unwindLevel); + // We do start the exception handler in case of isInterrupted. The exception handler will + // immediately abort, due to the same isInterrupted. We don't skip the exception handler + // because the current behavior is easier to implement in the JIT. + Q_ASSERT(engine->hasException || engine->isInterrupted || frame->unwindLevel); if (!frame->unwindHandler) { acc = Encode::undefined(); return acc; diff --git a/src/qml/jsruntime/qv4vtable_p.h b/src/qml/jsruntime/qv4vtable_p.h index aff1ae82d7..9dda104cd1 100644 --- a/src/qml/jsruntime/qv4vtable_p.h +++ b/src/qml/jsruntime/qv4vtable_p.h @@ -58,7 +58,7 @@ namespace QV4 { struct Lookup; -struct OwnPropertyKeyIterator { +struct Q_QML_PRIVATE_EXPORT OwnPropertyKeyIterator { virtual ~OwnPropertyKeyIterator() = 0; virtual PropertyKey next(const Object *o, Property *p = nullptr, PropertyAttributes *attrs = nullptr) = 0; }; @@ -90,8 +90,8 @@ struct VTable typedef bool (*ResolveLookupSetter)(Object *, ExecutionEngine *, Lookup *, const Value &); const VTable * const parent; - quint32 inlinePropertyOffset : 16; - quint32 nInlineProperties : 16; + quint16 inlinePropertyOffset; + quint16 nInlineProperties; quint8 isExecutionContext; quint8 isString; quint8 isObject; |