aboutsummaryrefslogtreecommitdiffstats
path: root/src/qml/jsruntime/qv4engine_p.h
diff options
context:
space:
mode:
Diffstat (limited to 'src/qml/jsruntime/qv4engine_p.h')
-rw-r--r--src/qml/jsruntime/qv4engine_p.h493
1 files changed, 382 insertions, 111 deletions
diff --git a/src/qml/jsruntime/qv4engine_p.h b/src/qml/jsruntime/qv4engine_p.h
index 86367c0ece..0958ab3ab5 100644
--- a/src/qml/jsruntime/qv4engine_p.h
+++ b/src/qml/jsruntime/qv4engine_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QV4ENGINE_H
#define QV4ENGINE_H
@@ -50,32 +14,102 @@
// We mean it.
//
-#include "qv4global_p.h"
-#include "qv4managed_p.h"
-#include "qv4context_p.h"
#include <private/qintrusivelist_p.h>
-#include "qv4enginebase_p.h"
+#include <private/qqmldelayedcallqueue_p.h>
#include <private/qqmlrefcount_p.h>
-#include <private/qqmljsengine_p.h>
-
-#ifndef V4_BOOTSTRAP
-# include "qv4function_p.h"
-# include <private/qv8engine_p.h>
-# include <private/qv4compileddata_p.h>
-#endif
+#include <private/qv4compileddata_p.h>
+#include <private/qv4context_p.h>
+#include <private/qv4enginebase_p.h>
+#include <private/qv4executablecompilationunit_p.h>
+#include <private/qv4function_p.h>
+#include <private/qv4global_p.h>
+#include <private/qv4stacklimits_p.h>
+
+#include <QtCore/qelapsedtimer.h>
+#include <QtCore/qmutex.h>
+#include <QtCore/qprocessordetection.h>
+#include <QtCore/qset.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;
+#if QT_CONFIG(qml_network)
+class QNetworkAccessManager;
+
+namespace QV4 {
+struct QObjectMethod;
+namespace detail {
+QNetworkAccessManager *getNetworkAccessManager(ExecutionEngine *engine);
+}
+}
+#else
+namespace QV4 { struct QObjectMethod; }
+#endif // qml_network
+
+// Used to allow a QObject method take and return raw V4 handles without having to expose
+// 48 in the public API.
+// Use like this:
+// class MyClass : public QObject {
+// Q_OBJECT
+// ...
+// Q_INVOKABLE void myMethod(QQmlV4FunctionPtr);
+// };
+// 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;
class QQmlContextData;
+class QQmlTypeLoader;
namespace QV4 {
namespace Debugging {
@@ -101,21 +135,29 @@ class ReactionHandler;
struct Q_QML_EXPORT ExecutionEngine : public EngineBase
{
private:
- static qint32 maxCallDepth;
-
friend struct ExecutionContextSaver;
friend struct ExecutionContext;
friend struct Heap::ExecutionContext;
public:
+ enum class DiskCache {
+ Disabled = 0,
+ AotByteCode = 1 << 0,
+ AotNative = 1 << 1,
+ QmlcRead = 1 << 2,
+ QmlcWrite = 1 << 3,
+ Aot = AotByteCode | AotNative,
+ Qmlc = QmlcRead | QmlcWrite,
+ Enabled = Aot | Qmlc,
+
+ };
+
+ Q_DECLARE_FLAGS(DiskCacheOptions, DiskCache);
+
ExecutableAllocator *executableAllocator;
ExecutableAllocator *regExpAllocator;
WTF::BumpPointerAllocator *bumperPointerAllocator; // Used by Yarr Regex engine.
- enum {
- JSStackLimit = 4*1024*1024,
- GCStackLimit = 2*1024*1024
- };
WTF::PageAllocation *jsStack;
WTF::PageAllocation *gcStack;
@@ -128,16 +170,18 @@ 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;
+ template<typename TypeLoader = QQmlTypeLoader>
+ TypeLoader *typeLoader()
+ {
+ if (m_qmlEngine)
+ return TypeLoader::get(m_qmlEngine);
+ return nullptr;
+ }
+
enum JSObjects {
RootContext,
ScriptContext,
@@ -163,9 +207,7 @@ public:
URIErrorProto,
PromiseProto,
VariantProto,
-#if QT_CONFIG(qml_sequence_object)
SequenceProto,
-#endif
SharedArrayBufferProto,
ArrayBufferProto,
DataViewProto,
@@ -175,6 +217,7 @@ public:
MapProto,
IntrinsicTypedArrayProto,
ValueTypeProto,
+ TypeWrapperProto,
SignalHandlerProto,
IteratorProto,
ForInIteratorProto,
@@ -182,6 +225,8 @@ public:
MapIteratorProto,
ArrayIteratorProto,
StringIteratorProto,
+ UrlProto,
+ UrlSearchParamsProto,
Object_Ctor,
String_Ctor,
@@ -209,6 +254,8 @@ public:
WeakMap_Ctor,
Map_Ctor,
IntrinsicTypedArray_Ctor,
+ Url_Ctor,
+ UrlSearchParams_Ctor,
GetSymbolSpecies,
@@ -249,6 +296,14 @@ public:
FunctionObject *weakMapCtor() const { return reinterpret_cast<FunctionObject *>(jsObjects + WeakMap_Ctor); }
FunctionObject *mapCtor() const { return reinterpret_cast<FunctionObject *>(jsObjects + Map_Ctor); }
FunctionObject *intrinsicTypedArrayCtor() const { return reinterpret_cast<FunctionObject *>(jsObjects + IntrinsicTypedArray_Ctor); }
+ FunctionObject *urlCtor() const
+ {
+ return reinterpret_cast<FunctionObject *>(jsObjects + Url_Ctor);
+ }
+ FunctionObject *urlSearchParamsCtor() const
+ {
+ return reinterpret_cast<FunctionObject *>(jsObjects + UrlSearchParams_Ctor);
+ }
FunctionObject *typedArrayCtors;
FunctionObject *getSymbolSpecies() const { return reinterpret_cast<FunctionObject *>(jsObjects + GetSymbolSpecies); }
@@ -274,9 +329,7 @@ public:
Object *uRIErrorPrototype() const { return reinterpret_cast<Object *>(jsObjects + URIErrorProto); }
Object *promisePrototype() const { return reinterpret_cast<Object *>(jsObjects + PromiseProto); }
Object *variantPrototype() const { return reinterpret_cast<Object *>(jsObjects + VariantProto); }
-#if QT_CONFIG(qml_sequence_object)
Object *sequencePrototype() const { return reinterpret_cast<Object *>(jsObjects + SequenceProto); }
-#endif
Object *sharedArrayBufferPrototype() const { return reinterpret_cast<Object *>(jsObjects + SharedArrayBufferProto); }
Object *arrayBufferPrototype() const { return reinterpret_cast<Object *>(jsObjects + ArrayBufferProto); }
@@ -290,17 +343,24 @@ public:
Object *valueTypeWrapperPrototype() const { return reinterpret_cast<Object *>(jsObjects + ValueTypeProto); }
Object *signalHandlerPrototype() const { return reinterpret_cast<Object *>(jsObjects + SignalHandlerProto); }
+ Object *typeWrapperPrototype() const { return reinterpret_cast<Object *>(jsObjects + TypeWrapperProto); }
Object *iteratorPrototype() const { return reinterpret_cast<Object *>(jsObjects + IteratorProto); }
Object *forInIteratorPrototype() const { return reinterpret_cast<Object *>(jsObjects + ForInIteratorProto); }
Object *setIteratorPrototype() const { return reinterpret_cast<Object *>(jsObjects + SetIteratorProto); }
Object *mapIteratorPrototype() const { return reinterpret_cast<Object *>(jsObjects + MapIteratorProto); }
Object *arrayIteratorPrototype() const { return reinterpret_cast<Object *>(jsObjects + ArrayIteratorProto); }
Object *stringIteratorPrototype() const { return reinterpret_cast<Object *>(jsObjects + StringIteratorProto); }
+ Object *urlPrototype() const { return reinterpret_cast<Object *>(jsObjects + UrlProto); }
+ Object *urlSearchParamsPrototype() const { return reinterpret_cast<Object *>(jsObjects + UrlSearchParamsProto); }
EvalFunction *evalFunction() const { return reinterpret_cast<EvalFunction *>(jsObjects + Eval_Function); }
FunctionObject *getStackFunction() const { return reinterpret_cast<FunctionObject *>(jsObjects + GetStack_Function); }
FunctionObject *thrower() const { return reinterpret_cast<FunctionObject *>(jsObjects + ThrowerObject); }
+#if QT_CONFIG(qml_network)
+ QNetworkAccessManager* (*networkAccessManager)(ExecutionEngine*) = detail::getNetworkAccessManager;
+#endif
+
enum JSStrings {
String_Empty,
String_undefined,
@@ -438,10 +498,6 @@ 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;
RegExpCache *regExpCache;
@@ -454,7 +510,8 @@ public:
// calling preserve() on the object which removes it from this scarceResource list.
class ScarceResourceData {
public:
- ScarceResourceData(const QVariant &data = QVariant()) : data(data) {}
+ ScarceResourceData() = default;
+ ScarceResourceData(const QMetaType type, const void *data) : data(type, data) {}
QVariant data;
QIntrusiveListNode node;
};
@@ -464,7 +521,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
@@ -487,7 +544,14 @@ public:
void setProfiler(Profiling::Profiler *profiler);
#endif // QT_CONFIG(qml_debug)
- ExecutionContext *currentContext() const;
+ // We don't want to #include <private/qv4stackframe_p.h> here, but we still want
+ // currentContext() to be inline. Therefore we shift the requirement to provide the
+ // complete type of CppStackFrame to the caller by making this a template.
+ template<typename StackFrame = CppStackFrame>
+ ExecutionContext *currentContext() const
+ {
+ return static_cast<const StackFrame *>(currentStackFrame)->context();
+ }
// ensure we always get odd prototype IDs. This helps make marking in QV4::Lookup fast
quintptr newProtoId() { return (protoIdCount += 2); }
@@ -497,6 +561,7 @@ public:
Heap::Object *newObject();
Heap::Object *newObject(Heap::InternalClass *internalClass);
+ Heap::String *newString(char16_t c) { return newString(QChar(c)); }
Heap::String *newString(const QString &s = QString());
Heap::String *newIdentifier(const QString &text);
@@ -513,13 +578,21 @@ public:
Heap::ArrayBuffer *newArrayBuffer(const QByteArray &array);
Heap::ArrayBuffer *newArrayBuffer(size_t length);
- Heap::DateObject *newDateObject(const Value &value);
- Heap::DateObject *newDateObject(const QDateTime &dt);
- Heap::DateObject *newDateObjectFromTime(const QTime &t);
+ Heap::DateObject *newDateObject(double dateTime);
+ Heap::DateObject *newDateObject(const QDateTime &dateTime);
+ Heap::DateObject *newDateObject(QDate date, Heap::Object *parent, int index, uint flags);
+ Heap::DateObject *newDateObject(QTime time, Heap::Object *parent, int index, uint flags);
+ Heap::DateObject *newDateObject(QDateTime dateTime, Heap::Object *parent, int index, uint flags);
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::UrlObject *newUrlObject();
+ Heap::UrlObject *newUrlObject(const QUrl &url);
+ Heap::UrlSearchParamsObject *newUrlSearchParamsObject();
Heap::Object *newErrorObject(const Value &value);
Heap::Object *newErrorObject(const QString &message);
@@ -537,16 +610,35 @@ public:
Heap::Object *newPromiseObject(const QV4::FunctionObject *thisObject, const QV4::PromiseCapability *capability);
Promise::ReactionHandler *getPromiseReactionHandler();
- Heap::Object *newVariantObject(const QVariant &v);
+ Heap::Object *newVariantObject(const QMetaType type, const void *data);
Heap::Object *newForInIteratorObject(Object *o);
Heap::Object *newSetIteratorObject(Object *o);
Heap::Object *newMapIteratorObject(Object *o);
Heap::Object *newArrayIteratorObject(Object *o);
+ static Heap::ExecutionContext *qmlContext(Heap::ExecutionContext *ctx)
+ {
+ Heap::ExecutionContext *outer = ctx->outer;
+
+ if (ctx->type != Heap::ExecutionContext::Type_QmlContext && !outer)
+ return nullptr;
+
+ while (outer && outer->type != Heap::ExecutionContext::Type_GlobalContext) {
+ ctx = outer;
+ outer = ctx->outer;
+ }
+
+ Q_ASSERT(ctx);
+ if (ctx->type != Heap::ExecutionContext::Type_QmlContext)
+ return nullptr;
+
+ return ctx;
+ }
+
Heap::QmlContext *qmlContext() const;
QObject *qmlScopeObject() const;
- QQmlContextData *callingQmlContext() const;
+ QQmlRefPointer<QQmlContextData> callingQmlContext() const;
StackTrace stackTrace(int frameLimit = -1) const;
@@ -580,23 +672,34 @@ public:
QQmlError catchExceptionAsQmlError();
// variant conversions
- QVariant toVariant(const QV4::Value &value, int typeHint, bool createJSValueForObjects = true);
+ static QVariant toVariant(
+ const QV4::Value &value, QMetaType typeHint, bool createJSValueForObjectsAndSymbols = true);
+ static QVariant toVariantLossy(const QV4::Value &value);
QV4::ReturnedValue fromVariant(const QVariant &);
+ QV4::ReturnedValue fromVariant(
+ const QVariant &variant, Heap::Object *parent, int property, uint flags);
- QVariantMap variantMapFromJS(const QV4::Object *o);
+ static QVariantMap variantMapFromJS(const QV4::Object *o);
- bool metaTypeFromJS(const Value *value, int type, void *data);
- QV4::ReturnedValue metaTypeToJS(int type, const void *data);
+ static bool metaTypeFromJS(const Value &value, QMetaType type, void *data);
+ QV4::ReturnedValue metaTypeToJS(QMetaType type, const void *data);
+
+ int maxJSStackSize() const;
+ int maxGCStackSize() const;
bool checkStackLimits();
+ int safeForAllocLength(qint64 len64);
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)
- return !f->isGenerator() && f->interpreterCallCount >= jitCallCountThreshold;
+ if (f) {
+ return f->kind != Function::AotCompiled
+ && !f->isGenerator()
+ && f->interpreterCallCount >= s_jitCallCountThreshold;
+ }
return true;
#else
Q_UNUSED(f);
@@ -605,57 +708,223 @@ public:
}
QV4::ReturnedValue global();
+ void initQmlGlobalObject();
+ void initializeGlobal();
+ void createQtObject();
- double localTZA = 0.0; // local timezone, initialized at startup
+ void freezeObject(const QV4::Value &value);
+ void lockObject(const QV4::Value &value);
- 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);
+ // Return the list of illegal id names (the names of the properties on the global object)
+ const QSet<QString> &illegalNames() const;
- mutable QMutex moduleMutex;
- QHash<QUrl, QQmlRefPointer<CompiledData::CompilationUnit>> modules;
- 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);
+#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.size())
+ return m_extensionData[index];
+ else
+ return nullptr;
+ }
+
+ double localTZA = 0.0; // local timezone, initialized at startup
+
+ QQmlRefPointer<ExecutableCompilationUnit> compileModule(const QUrl &url);
+ QQmlRefPointer<ExecutableCompilationUnit> compileModule(
+ const QUrl &url, const QString &sourceCode, const QDateTime &sourceTimeStamp);
+
+ QQmlRefPointer<ExecutableCompilationUnit> compilationUnitForUrl(const QUrl &url) const;
+
+ QQmlRefPointer<ExecutableCompilationUnit> executableCompilationUnit(
+ QQmlRefPointer<QV4::CompiledData::CompilationUnit> &&unit);
+
+ QQmlRefPointer<ExecutableCompilationUnit> insertCompilationUnit(
+ QQmlRefPointer<QV4::CompiledData::CompilationUnit> &&unit);
+
+ QMultiHash<QUrl, QQmlRefPointer<ExecutableCompilationUnit>> compilationUnits() const
+ {
+ return m_compilationUnits;
+ }
+ void clearCompilationUnits() { m_compilationUnits.clear(); }
+ void trimCompilationUnits();
+
+ QV4::Value *registerNativeModule(const QUrl &url, const QV4::Value &module);
+
+ struct Module {
+ QQmlRefPointer<ExecutableCompilationUnit> compiled;
+
+ // We can pass a raw value pointer here, but nowhere else. See below.
+ Value *native = nullptr;
+ };
+
+ Module moduleForUrl(const QUrl &_url, const ExecutableCompilationUnit *referrer = nullptr) const;
+ Module loadModule(const QUrl &_url, const ExecutableCompilationUnit *referrer = nullptr);
+
+ DiskCacheOptions diskCacheOptions() const;
+
+ void callInContext(QV4::Function *function, QObject *self, QV4::ExecutionContext *ctxt,
+ int argc, void **args, QMetaType *types);
+ QV4::ReturnedValue callInContext(QV4::Function *function, QObject *self,
+ QV4::ExecutionContext *ctxt, int argc, const QV4::Value *argv);
+
+ QV4::ReturnedValue fromData(
+ QMetaType type, const void *ptr,
+ Heap::Object *parent = nullptr, int property = -1, uint flags = 0);
+
+
+ static void setMaxCallDepth(int maxCallDepth) { s_maxCallDepth = maxCallDepth; }
+ static int maxCallDepth() { return s_maxCallDepth; }
+
+ template<typename Value>
+ static QJSPrimitiveValue createPrimitive(const Value &v)
+ {
+ if (v->isUndefined())
+ return QJSPrimitiveValue(QJSPrimitiveUndefined());
+ if (v->isNull())
+ return QJSPrimitiveValue(QJSPrimitiveNull());
+ if (v->isBoolean())
+ return QJSPrimitiveValue(v->toBoolean());
+ if (v->isInteger())
+ return QJSPrimitiveValue(v->integerValue());
+ if (v->isDouble())
+ return QJSPrimitiveValue(v->doubleValue());
+ bool ok;
+ const QString result = v->toQString(&ok);
+ return ok ? QJSPrimitiveValue(result) : QJSPrimitiveValue(QJSPrimitiveUndefined());
+ }
+
private:
+ template<int Frames>
+ friend struct ExecutionEngineCallDepthRecorder;
+
+ static void initializeStaticMembers();
+
+ bool inStack(const void *current) const
+ {
+#if Q_STACK_GROWTH_DIRECTION > 0
+ return current < cppStackLimit && current >= cppStackBase;
+#else
+ return current > cppStackLimit && current <= cppStackBase;
+#endif
+ }
+
+ bool hasCppStackOverflow()
+ {
+ if (s_maxCallDepth >= 0)
+ return callDepth >= s_maxCallDepth;
+
+ if (inStack(currentStackPointer()))
+ return false;
+
+ // Double check the stack limits on failure.
+ // We may have moved to a different thread.
+ const StackProperties stack = stackProperties();
+ cppStackBase = stack.base;
+ cppStackLimit = stack.softLimit;
+ return !inStack(currentStackPointer());
+ }
+
+ bool hasJsStackOverflow() const
+ {
+ return jsStackTop > jsStackLimit;
+ }
+
+ bool hasStackOverflow()
+ {
+ return hasJsStackOverflow() || hasCppStackOverflow();
+ }
+
+ static int s_maxCallDepth;
+ static int s_jitCallCountThreshold;
+ static int s_maxJSStackSize;
+ static int s_maxGCStackSize;
+
#if QT_CONFIG(qml_debug)
QScopedPointer<QV4::Debugging::Debugger> m_debugger;
QScopedPointer<QV4::Profiling::Profiler> m_profiler;
#endif
- int jitCallCountThreshold;
+ QSet<QString> m_illegalNames;
// 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;
-#define CHECK_STACK_LIMITS(v4) if ((v4)->checkStackLimits()) return Encode::undefined(); \
+ QElapsedTimer m_time;
+ QHash<QString, qint64> m_startedTimers;
+
+ QHash<QString, quint32> m_consoleCount;
+
+ QVector<Deletable *> m_extensionData;
+
+ QMultiHash<QUrl, QQmlRefPointer<ExecutableCompilationUnit>> m_compilationUnits;
+
+ // QV4::PersistentValue would be preferred, but using QHash will create copies,
+ // and QV4::PersistentValue doesn't like creating copies.
+ // Instead, we allocate a raw pointer using the same manual memory management
+ // technique in QV4::PersistentValue.
+ QHash<QUrl, Value *> nativeModules;
+};
+
+#define CHECK_STACK_LIMITS(v4) \
+ if (v4->checkStackLimits()) \
+ return Encode::undefined(); \
ExecutionEngineCallDepthRecorder _executionEngineCallDepthRecorder(v4);
+template<int Frames = 1>
struct ExecutionEngineCallDepthRecorder
{
ExecutionEngine *ee;
- ExecutionEngineCallDepthRecorder(ExecutionEngine *e): ee(e) { ++ee->callDepth; }
- ~ExecutionEngineCallDepthRecorder() { --ee->callDepth; }
+ ExecutionEngineCallDepthRecorder(ExecutionEngine *e): ee(e)
+ {
+ if (ExecutionEngine::s_maxCallDepth >= 0)
+ ee->callDepth += Frames;
+ }
+
+ ~ExecutionEngineCallDepthRecorder()
+ {
+ if (ExecutionEngine::s_maxCallDepth >= 0)
+ ee->callDepth -= Frames;
+ }
+
+ bool hasOverflow() const
+ {
+ return ee->hasCppStackOverflow();
+ }
};
inline bool ExecutionEngine::checkStackLimits()
{
- if (Q_UNLIKELY((jsStackTop > jsStackLimit) || (callDepth >= maxCallDepth))) {
+ if (Q_UNLIKELY(hasStackOverflow())) {
throwRangeError(QStringLiteral("Maximum call stack size exceeded."));
return true;
}
@@ -663,6 +932,8 @@ inline bool ExecutionEngine::checkStackLimits()
return false;
}
+Q_DECLARE_OPERATORS_FOR_FLAGS(ExecutionEngine::DiskCacheOptions);
+
} // namespace QV4
QT_END_NAMESPACE