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-profiler.h>
35 #include "libplatform/libplatform.h"
38 #include "ScriptEngineDebugFlags.h"
39 #include "../ScriptEngine.h"
40 #include "../ScriptManager.h"
41 #include "../ScriptException.h"
43 #include "ArrayBufferClass.h"
49 class ScriptMethodV8Proxy;
51 class ScriptSignalV8Proxy;
53 template <
typename T>
class V8ScriptValueTemplate;
54 typedef V8ScriptValueTemplate<v8::Value> V8ScriptValue;
55 typedef V8ScriptValueTemplate<v8::Script> V8ScriptProgram;
57 using ScriptContextV8Pointer = std::shared_ptr<ScriptContextV8Wrapper>;
59 const double GARBAGE_COLLECTION_TIME_LIMIT_S = 1.0;
61 Q_DECLARE_METATYPE(ScriptEngine::FunctionSignature)
65 public std::enable_shared_from_this<ScriptEngineV8> {
70 virtual ~ScriptEngineV8();
77 class ScriptEngineScopeGuardV8 final :
public ScriptEngineScopeGuard {
79 explicit ScriptEngineScopeGuardV8(v8::Isolate *isolate) : _locker(isolate), _isolateScope(isolate) {};
80 ~ScriptEngineScopeGuardV8()
override =
default;
83 v8::Isolate::Scope _isolateScope;
86 std::unique_ptr<ScriptEngineScopeGuard>
getScopeGuard()
override;
90 Q_INVOKABLE
virtual ScriptValue evaluate(
const QString& program,
const QString& fileName = QString())
override;
98 virtual ScriptValue newArray(uint length = 0)
override;
99 virtual ScriptValue newArrayBuffer(
const QByteArray& message)
override;
100 virtual ScriptValue newFunction(ScriptEngine::FunctionSignature fun,
int length = 0)
override;
102 virtual ScriptValue newMethod(QObject*
object, V8ScriptValue lifetime,
103 const QList<QMetaMethod>& metas,
int numMaxParams);
104 virtual ScriptProgramPointer newProgram(
const QString& sourceCode,
const QString& fileName)
override;
106 const ScriptEngine::QObjectWrapOptions& options = ScriptEngine::QObjectWrapOptions())
override;
110 virtual ScriptValue newValue(
double value)
override;
111 virtual ScriptValue newValue(
const QString& value)
override;
112 virtual ScriptValue newValue(
const QLatin1String& value)
override;
113 virtual ScriptValue newValue(
const char* value)
override;
114 virtual ScriptValue newVariant(
const QVariant& value)
override;
119 virtual bool raiseException(
const QString& exception,
const QString &reason = QString())
override;
121 Q_INVOKABLE
virtual void registerEnum(
const QString& enumName, QMetaEnum newEnum)
override;
122 Q_INVOKABLE
virtual void registerFunction(
const QString& name,
123 ScriptEngine::FunctionSignature fun,
124 int numArguments = -1)
override;
125 Q_INVOKABLE
virtual void registerFunction(
const QString& parent,
127 ScriptEngine::FunctionSignature fun,
128 int numArguments = -1)
override;
129 Q_INVOKABLE
virtual void registerGetterSetter(
const QString& name,
130 ScriptEngine::FunctionSignature getter,
131 ScriptEngine::FunctionSignature setter,
132 const QString& parent = QString(
""))
override;
134 virtual void setDefaultPrototype(
int metaTypeId,
const ScriptValue& prototype)
override;
135 virtual void setObjectName(
const QString& name)
override;
136 virtual bool setProperty(
const char* name,
const QVariant& value)
override;
137 virtual void setProcessEventsInterval(
int interval)
override;
138 virtual QThread* thread()
const override;
139 virtual void setThread(QThread* thread)
override;
142 virtual void updateMemoryCost(
const qint64& deltaSize)
override;
143 virtual void requestCollectGarbage()
override {
while(!_v8Isolate->IdleNotificationDeadline(getV8Platform()->MonotonicallyIncreasingTime() + GARBAGE_COLLECTION_TIME_LIMIT_S)) {}; }
145 virtual QString scriptValueDebugDetails(
const ScriptValue &value)
override;
146 QString scriptValueDebugDetailsV8(
const V8ScriptValue &value);
147 virtual QString scriptValueDebugListMembers(
const ScriptValue &value)
override;
148 QString scriptValueDebugListMembersV8(
const V8ScriptValue &v8Value);
149 virtual void logBacktrace(
const QString &title = QString(
""))
override;
155 void scheduleValueWrapperForDeletion(
ScriptValueV8Wrapper* wrapper) {_scriptValueWrappersToDelete.enqueue(wrapper);}
156 void deleteUnusedValueWrappers();
157 virtual void perManagerLoopIterationCleanup()
override;
161 inline bool IS_THREADSAFE_INVOCATION(
const QString& method) {
return ScriptEngine::IS_THREADSAFE_INVOCATION(method); }
171 static bool IS_THREADSAFE_INVOCATION(
const QThread* thread,
const QString& method);
176 Q_INVOKABLE
void registerValue(
const QString& valueName, V8ScriptValue value);
183 virtual ScriptValue create(
int type,
const void* ptr)
override;
184 virtual QVariant convert(
const ScriptValue& value,
int typeId)
override;
185 virtual void registerCustomType(
int type, ScriptEngine::MarshalFunction marshalFunc,
186 ScriptEngine::DemarshalFunction demarshalFunc)
override;
187 int computeCastPenalty(
const V8ScriptValue& val,
int destTypeId);
188 bool castValueToVariant(
const V8ScriptValue& val, QVariant& dest,
int destTypeId);
191 bool convertJSArrayToVariant(v8::Local<v8::Array> array, QVariant &dest);
192 bool convertJSObjectToVariant(v8::Local<v8::Object>
object, QVariant &dest);
193 V8ScriptValue castVariantToValue(
const QVariant& val);
194 QString valueType(
const V8ScriptValue& val);
195 v8::Isolate* getIsolate() {
196 Q_ASSERT(_v8Isolate !=
nullptr);
198 v8::Local<v8::Context> getContext();
199 const v8::Local<v8::Context> getConstContext()
const;
200 QString formatErrorMessageFromTryCatch(v8::TryCatch &tryCatch);
202 virtual QStringList getCurrentScriptURLs()
const override;
204 using ObjectWrapperMap = QMap<QObject*, QWeakPointer<ScriptObjectV8Proxy>>;
205 mutable QMutex _qobjectWrapperMapProtect;
206 ObjectWrapperMap _qobjectWrapperMap;
208 QMap<QObject*, QSharedPointer<ScriptObjectV8Proxy>> _qobjectWrapperMapV8;
213 QQueue<ScriptValueV8Wrapper*> _scriptValueWrappersToDelete;
216 v8::Local<v8::ObjectTemplate> getObjectProxyTemplate();
217 v8::Local<v8::ObjectTemplate> getMethodDataTemplate();
218 v8::Local<v8::ObjectTemplate> getFunctionDataTemplate();
219 v8::Local<v8::ObjectTemplate> getVariantDataTemplate();
220 v8::Local<v8::ObjectTemplate> getVariantProxyTemplate();
222 ScriptContextV8Pointer pushContext(v8::Local<v8::Context> context);
224 void storeGlobalObjectContents();
225 #ifdef OVERTE_V8_MEMORY_DEBUG
226 void incrementScriptValueCounter() { scriptValueCount++; };
227 void decrementScriptValueCounter() { scriptValueCount--; };
228 void incrementScriptValueProxyCounter() { scriptValueProxyCount++; };
229 void decrementScriptValueProxyCounter() { scriptValueProxyCount--; };
234 void registerSystemTypes();
237 static QMutex _v8InitMutex;
238 static std::once_flag _v8InitOnceFlag;
239 static v8::Platform* getV8Platform();
241 void setUncaughtEngineException(
const QString &message,
const QString& info = QString());
242 void setUncaughtException(
const v8::TryCatch &tryCatch,
const QString& info = QString());
243 void setUncaughtException(std::shared_ptr<ScriptException> exception);
245 friend class ScriptSignalV8Proxy;
247 std::shared_ptr<ScriptException> _uncaughtException;
251 v8::Isolate* _v8Isolate;
253 struct CustomMarshal {
254 ScriptEngine::MarshalFunction marshalFunc;
255 ScriptEngine::DemarshalFunction demarshalFunc;
257 using CustomMarshalMap = QHash<int, CustomMarshal>;
258 using CustomPrototypeMap = QHash<int, V8ScriptValue>;
260 mutable QReadWriteLock _customTypeProtect { QReadWriteLock::Recursive };
261 CustomMarshalMap _customTypes;
262 CustomPrototypeMap _customPrototypes;
266 QList<ScriptContextV8Pointer> _contexts;
268 v8::Persistent<v8::Object> _globalObjectContents;
269 bool areGlobalObjectContentsStored {
false};
273 v8::Persistent<v8::ObjectTemplate> _objectProxyTemplate;
274 v8::Persistent<v8::ObjectTemplate> _methodDataTemplate;
275 v8::Persistent<v8::ObjectTemplate> _functionDataTemplate;
276 v8::Persistent<v8::ObjectTemplate> _variantDataTemplate;
277 v8::Persistent<v8::ObjectTemplate> _variantProxyTemplate;
280 volatile int _memoryCorruptionIndicator = 12345678;
285 int _evaluatingCounter;
286 #ifdef OVERTE_V8_MEMORY_DEBUG
287 std::atomic<size_t> scriptValueCount{0};
288 std::atomic<size_t> scriptValueProxyCount{0};
291 #ifdef OVERTE_SCRIPT_USE_AFTER_DELETE_GUARD
292 bool _wasDestroyed{
false};
296 v8::CpuProfiler *_profiler{
nullptr};
297 v8::ProfilerId _profilerId{0};
301 QReadWriteLock _signalProxySetLock;
302 QSet<ScriptSignalV8Proxy*> _signalProxySet;
305 friend ScriptSignalV8Proxy;
316 bool _isContextChangeNeeded;
317 ScriptEngineV8* _engine;
320 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:311
[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 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:280
virtual std::unique_ptr< ScriptEngineScopeGuard > getScopeGuard()=0
Creates a thread safety scope guard.
Manages a single scripting engine.
Definition: ScriptManager.h:281
Definition: ScriptObjectV8Proxy.h:44
[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