19 #ifndef hifi_ScriptEngineV8_h
20 #define hifi_ScriptEngineV8_h
24 #include <QtCore/QByteArray>
25 #include <QtCore/QHash>
26 #include <QtCore/QMetaEnum>
27 #include <QtCore/QMutex>
28 #include <QtCore/QObject>
29 #include <QtCore/QPointer>
30 #include <QtCore/QSharedPointer>
31 #include <QtCore/QString>
33 #include <v8-isolate.h>
34 #include <v8-profiler.h>
36 #include "libplatform/libplatform.h"
39 #include "ScriptEngineDebugFlags.h"
40 #include "../ScriptEngine.h"
41 #include "../ScriptManager.h"
42 #include "../ScriptException.h"
44 #include "ArrayBufferClass.h"
50 class ScriptMethodV8Proxy;
52 class ScriptSignalV8Proxy;
54 template <
typename T>
class V8ScriptValueTemplate;
55 typedef V8ScriptValueTemplate<v8::Value> V8ScriptValue;
56 typedef V8ScriptValueTemplate<v8::Script> V8ScriptProgram;
58 using ScriptContextV8Pointer = std::shared_ptr<ScriptContextV8Wrapper>;
60 const double GARBAGE_COLLECTION_TIME_LIMIT_S = 1.0;
62 Q_DECLARE_METATYPE(ScriptEngine::FunctionSignature)
66 public std::enable_shared_from_this<ScriptEngineV8> {
71 virtual ~ScriptEngineV8();
78 class ScriptEngineScopeGuardV8 final :
public ScriptEngineScopeGuard {
80 explicit ScriptEngineScopeGuardV8(v8::Isolate *isolate) : _locker(isolate), _isolateScope(isolate) {};
81 ~ScriptEngineScopeGuardV8()
override =
default;
84 v8::Isolate::Scope _isolateScope;
87 std::unique_ptr<ScriptEngineScopeGuard>
getScopeGuard()
override;
91 Q_INVOKABLE
virtual ScriptValue evaluate(
const QString& program,
const QString& fileName = QString())
override;
99 virtual ScriptValue newArray(uint length = 0)
override;
100 virtual ScriptValue newArrayBuffer(
const QByteArray& message)
override;
101 virtual ScriptValue newFunction(ScriptEngine::FunctionSignature fun,
int length = 0)
override;
103 virtual ScriptValue newMethod(QObject*
object, V8ScriptValue lifetime,
104 const QList<QMetaMethod>& metas,
int numMaxParams);
105 virtual ScriptProgramPointer newProgram(
const QString& sourceCode,
const QString& fileName)
override;
107 const ScriptEngine::QObjectWrapOptions& options = ScriptEngine::QObjectWrapOptions())
override;
111 virtual ScriptValue newValue(
double value)
override;
112 virtual ScriptValue newValue(
const QString& value)
override;
113 virtual ScriptValue newValue(
const QLatin1String& value)
override;
114 virtual ScriptValue newValue(
const char* value)
override;
115 virtual ScriptValue newVariant(
const QVariant& value)
override;
120 virtual bool raiseException(
const QString& exception,
const QString &reason = QString())
override;
122 Q_INVOKABLE
virtual void registerEnum(ScriptEngineScopeGuard* scopeGuard,
const QString& enumName, QMetaEnum newEnum)
override;
123 Q_INVOKABLE
virtual void registerFunction(ScriptEngineScopeGuard* scopeGuard,
const QString& name,
124 ScriptEngine::FunctionSignature fun,
125 int numArguments = -1)
override;
126 Q_INVOKABLE
virtual void registerFunction(ScriptEngineScopeGuard* scopeGuard,
const QString& parent,
128 ScriptEngine::FunctionSignature fun,
129 int numArguments = -1)
override;
130 Q_INVOKABLE
virtual void registerGetterSetter(ScriptEngineScopeGuard* scopeGuard,
const QString& name,
131 ScriptEngine::FunctionSignature getter,
132 ScriptEngine::FunctionSignature setter,
133 const QString& parent = QString(
""))
override;
134 Q_INVOKABLE
virtual void registerGlobalObject(ScriptEngineScopeGuard* scopeGuard,
const QString& name,
136 virtual void setDefaultPrototype(
int metaTypeId,
const ScriptValue& prototype)
override;
137 virtual void setObjectName(
const QString& name)
override;
138 virtual bool setProperty(
const char* name,
const QVariant& value)
override;
139 virtual void setProcessEventsInterval(
int interval)
override;
140 virtual QThread* thread()
const override;
141 virtual void setThread(QThread* thread)
override;
144 virtual void updateMemoryCost(
const qint64& deltaSize)
override;
145 virtual void requestCollectGarbage()
override { _v8Isolate->MemoryPressureNotification(v8::MemoryPressureLevel::kCritical); }
148 virtual QString scriptValueDebugDetails(
const ScriptValue &value)
override;
149 QString scriptValueDebugDetailsV8(
const V8ScriptValue &value);
150 virtual QString scriptValueDebugListMembers(
const ScriptValue &value)
override;
151 QString scriptValueDebugListMembersV8(
const V8ScriptValue &v8Value);
152 virtual void logBacktrace(
const QString &title = QString(
""))
override;
158 void scheduleValueWrapperForDeletion(
ScriptValueV8Wrapper* wrapper) {_scriptValueWrappersToDelete.enqueue(wrapper);}
159 void deleteUnusedValueWrappers();
160 virtual void perManagerLoopIterationCleanup()
override;
164 inline bool IS_THREADSAFE_INVOCATION(
const QString& method) {
return ScriptEngine::IS_THREADSAFE_INVOCATION(method); }
174 static bool IS_THREADSAFE_INVOCATION(
const QThread* thread,
const QString& method);
179 Q_INVOKABLE
void registerValue(ScriptEngineScopeGuardV8* scopeGuard,
const QString& valueName, V8ScriptValue value);
186 virtual ScriptValue create(
int type,
const void* ptr)
override;
187 virtual QVariant convert(
const ScriptValue& value,
int typeId)
override;
188 virtual void registerCustomType(
int type, ScriptEngine::MarshalFunction marshalFunc,
189 ScriptEngine::DemarshalFunction demarshalFunc)
override;
190 int computeCastPenalty(
const V8ScriptValue& val,
int destTypeId);
191 bool castValueToVariant(
const V8ScriptValue& val, QVariant& dest,
int destTypeId);
194 bool convertJSArrayToVariant(v8::Local<v8::Array> array, QVariant &dest);
195 bool convertJSObjectToVariant(v8::Local<v8::Object>
object, QVariant &dest);
196 V8ScriptValue castVariantToValue(
const QVariant& val);
197 QString valueType(
const V8ScriptValue& val);
198 v8::Isolate* getIsolate() {
199 Q_ASSERT(_v8Isolate !=
nullptr);
201 v8::Local<v8::Context> getContext();
202 const v8::Local<v8::Context> getConstContext()
const;
203 QString formatErrorMessageFromTryCatch(v8::TryCatch &tryCatch);
205 virtual QStringList getCurrentScriptURLs()
const override;
207 using ObjectWrapperMap = QMap<QObject*, QWeakPointer<ScriptObjectV8Proxy>>;
208 mutable QMutex _qobjectWrapperMapProtect;
209 ObjectWrapperMap _qobjectWrapperMap;
211 QMap<QObject*, QSharedPointer<ScriptObjectV8Proxy>> _qobjectWrapperMapV8;
216 QQueue<ScriptValueV8Wrapper*> _scriptValueWrappersToDelete;
219 v8::Local<v8::ObjectTemplate> getObjectProxyTemplate();
220 v8::Local<v8::ObjectTemplate> getMethodDataTemplate();
221 v8::Local<v8::ObjectTemplate> getFunctionDataTemplate();
222 v8::Local<v8::ObjectTemplate> getVariantDataTemplate();
223 v8::Local<v8::ObjectTemplate> getVariantProxyTemplate();
225 ScriptContextV8Pointer pushContext(v8::Local<v8::Context> context);
227 void storeGlobalObjectContents();
228 #ifdef OVERTE_V8_MEMORY_DEBUG
229 void incrementScriptValueCounter() { scriptValueCount++; };
230 void decrementScriptValueCounter() { scriptValueCount--; };
231 void incrementScriptValueProxyCounter() { scriptValueProxyCount++; };
232 void decrementScriptValueProxyCounter() { scriptValueProxyCount--; };
237 void registerSystemTypes();
240 static QMutex _v8InitMutex;
241 static std::once_flag _v8InitOnceFlag;
242 static v8::Platform* getV8Platform();
244 void setUncaughtEngineException(
const QString &message,
const QString& info = QString());
245 void setUncaughtException(
const v8::TryCatch &tryCatch,
const QString& info = QString());
246 void setUncaughtException(std::shared_ptr<ScriptException> exception);
248 friend class ScriptSignalV8Proxy;
250 std::shared_ptr<ScriptException> _uncaughtException;
254 v8::Isolate* _v8Isolate;
256 struct CustomMarshal {
257 ScriptEngine::MarshalFunction marshalFunc;
258 ScriptEngine::DemarshalFunction demarshalFunc;
260 using CustomMarshalMap = QHash<int, CustomMarshal>;
261 using CustomPrototypeMap = QHash<int, V8ScriptValue>;
263 mutable QReadWriteLock _customTypeProtect { QReadWriteLock::Recursive };
264 CustomMarshalMap _customTypes;
265 CustomPrototypeMap _customPrototypes;
269 QList<ScriptContextV8Pointer> _contexts;
271 v8::Persistent<v8::Object> _globalObjectContents;
272 bool areGlobalObjectContentsStored {
false};
276 v8::Persistent<v8::ObjectTemplate> _objectProxyTemplate;
277 v8::Persistent<v8::ObjectTemplate> _methodDataTemplate;
278 v8::Persistent<v8::ObjectTemplate> _functionDataTemplate;
279 v8::Persistent<v8::ObjectTemplate> _variantDataTemplate;
280 v8::Persistent<v8::ObjectTemplate> _variantProxyTemplate;
283 volatile int _memoryCorruptionIndicator = 12345678;
288 int _evaluatingCounter;
289 #ifdef OVERTE_V8_MEMORY_DEBUG
290 std::atomic<size_t> scriptValueCount{0};
291 std::atomic<size_t> scriptValueProxyCount{0};
294 #ifdef OVERTE_SCRIPT_USE_AFTER_DELETE_GUARD
295 bool _wasDestroyed{
false};
299 v8::CpuProfiler *_profiler{
nullptr};
300 v8::ProfilerId _profilerId{0};
304 QReadWriteLock _signalProxySetLock;
305 QSet<ScriptSignalV8Proxy*> _signalProxySet;
308 friend ScriptSignalV8Proxy;
319 bool _isContextChangeNeeded;
320 ScriptEngineV8* _engine;
323 QString getFileNameFromTryCatch(v8::TryCatch &tryCatch, v8::Isolate *isolate, v8::Local<v8::Context> &context );
[V8] Implements ScriptEngine for V8 and translates calls for QScriptEngine
Definition: ScriptEngineV8.h:314
[ScriptInterface] Provides an engine-independent interface for QScriptContext
Definition: ScriptContext.h:55
[V8] Implements ScriptContext for V8 and translates calls for V8ScriptContextInfo
Definition: ScriptContextV8Wrapper.h:33
Provides an engine-independent interface for a scripting engine.
Definition: ScriptEngine.h:93
virtual ScriptValue makeError(const ScriptValue &other, const QString &type="Error")=0
Make a ScriptValue that contains an error.
virtual void logBacktrace(const QString &title)=0
Log the current backtrace.
virtual ScriptValue checkScriptSyntax(ScriptProgramPointer program)=0
Check a program for syntax errors.
virtual ScriptValue evaluate(const QString &program, const QString &fileName=QString())=0
Runs a script.
virtual bool raiseException(const ScriptValue &exception, const QString &reason=QString())=0
Causes an exception to be raised in the currently executing script.
virtual void stopProfilingAndSave()=0
Stops collecting profiling data and saves it to a CSV file in Logs directory.
virtual bool isEvaluating() const =0
Whether a script is currently being evaluated.
virtual std::shared_ptr< ScriptException > uncaughtException() const =0
Last uncaught exception, if any.
virtual void dumpHeapObjectStatistics()=0
Prints heap statistics to a file. Collecting needs to first be started with dumpHeapObjectStatistics(...
virtual void abortEvaluation()=0
Stops the currently running script.
virtual ScriptValue evaluateInClosure(const ScriptValue &locals, const ScriptProgramPointer &program)=0
Evaluate a script in a separate environment.
virtual ScriptContext * currentContext() const =0
Context of the currently running script.
virtual void clearExceptions()=0
Clears uncaughtException and related.
virtual bool hasUncaughtException() const =0
Whether the script has an uncaught exception.
virtual void compileTest()=0
Test the underlying scripting engine.
virtual void startCollectingObjectStatistics()=0
Start collecting object statistics that can later be reported with dumpHeapObjectStatistics().
ValueOwnership
Who owns a given object.
Definition: ScriptEngine.h:109
@ QtOwnership
Object is managed by Qt.
Definition: ScriptEngine.h:114
virtual ScriptEngineMemoryStatistics getMemoryUsageStatistics()=0
Return memory usage statistics data.
virtual void processEvents()=0
Tells the script engine to process any events it may have queued internally. Used by V8 for async fun...
virtual void startProfiling()=0
Starts collecting profiling data.
virtual void disconnectSignalProxies()=0
Cleanup function that disconnects signals connected to script proxies to avoid use-after-delete crash...
virtual ScriptValue globalObject()
Global object which holds all the functions and variables available everywhere.
Definition: ScriptEngine.h:284
virtual std::unique_ptr< ScriptEngineScopeGuard > getScopeGuard()=0
Creates a thread safety scope guard.
Manages a single scripting engine.
Definition: ScriptManager.h:282
Definition: ScriptObjectV8Proxy.h:45
[ScriptInterface] Provides an engine-independent interface for QScriptValue
Definition: ScriptValue.h:40
[V8] Implements ScriptValue for V8 and translates calls for V8ScriptValue
Definition: ScriptValueV8Wrapper.h:32