Overte C++ Documentation
ScriptEngine.h
1 //
2 // ScriptEngine.h
3 // libraries/script-engine/src
4 //
5 // Created by Brad Hefta-Gaub on 12/14/13.
6 // Copyright 2013 High Fidelity, Inc.
7 // Copyright 2020 Vircadia contributors.
8 // Copyright 2023 Overte e.V.
9 //
10 // Distributed under the Apache License, Version 2.0.
11 // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
12 // SPDX-License-Identifier: Apache-2.0
13 //
14 
17 
18 #ifndef hifi_ScriptEngine_h
19 #define hifi_ScriptEngine_h
20 
21 #include <memory>
22 
23 #include <QtCore/QFlags>
24 #include <QtCore/QObject>
25 
26 #include "ScriptValue.h"
27 #include "ScriptException.h"
28 
29 // These are used for debugging memory leaks caused by persistent handles
30 //#define OVERTE_V8_MEMORY_DEBUG
31 
32 class QByteArray;
33 class QLatin1String;
34 class QString;
35 class QThread;
36 class QVariant;
37 class ScriptContext;
38 class ScriptEngine;
39 class ScriptManager;
40 class ScriptProgram;
41 using ScriptEnginePointer = std::shared_ptr<ScriptEngine>;
42 using ScriptProgramPointer = std::shared_ptr<ScriptProgram>;
43 
44 Q_DECLARE_METATYPE(ScriptEnginePointer);
45 
46 template <typename T>
47 inline ScriptValue
48 
49 scriptValueFromValue(ScriptEngine* engine, const T& t);
50 
51 template <typename T>
52 inline T scriptvalue_cast(const ScriptValue& value);
53 
54 class ScriptEngineMemoryStatistics {
55 public:
56  size_t totalHeapSize;
57  size_t usedHeapSize;
58  size_t totalAvailableSize;
59  size_t totalGlobalHandlesSize;
60  size_t usedGlobalHandlesSize;
61 #ifdef OVERTE_V8_MEMORY_DEBUG
62  size_t scriptValueCount;
63  size_t scriptValueProxyCount;
64  size_t qObjectCount;
65  //size_t qVariantProxyCount;
66 #endif
67 };
68 
93 class ScriptEngine : public QObject {
94  Q_OBJECT
95 public:
96 
97  ScriptEngine(ScriptManager *manager = nullptr) : _manager(manager) {
98 
99  }
100 
101  typedef ScriptValue (*FunctionSignature)(ScriptContext*, ScriptEngine*);
102  typedef ScriptValue (*MarshalFunction)(ScriptEngine*, const void*);
103  typedef bool (*DemarshalFunction)(const ScriptValue&, QVariant &dest);
104 
115 
121 
129  };
130 
136 
141  //ExcludeChildObjects = 0x0001,
142 
148 
154 
160 
161  //ExcludeDeleteLater = 0x0010,
162 
167  ExcludeSlots = 0x0020,
168 
174 
180 
186  };
187  Q_DECLARE_FLAGS(QObjectWrapOptions, QObjectWrapOption);
188 
189 public:
190 
198  protected:
199  ScriptEngineScopeGuard() = default;
200 
201  // prevent copy and move
204  ScriptEngineScopeGuard& operator=(const ScriptEngineScopeGuard&) = delete;
205  ScriptEngineScopeGuard& operator=(ScriptEngineScopeGuard&&) = delete;
206  public:
207  virtual ~ScriptEngineScopeGuard() = default;
208  };
209 
221  virtual std::unique_ptr<ScriptEngineScopeGuard> getScopeGuard() = 0;
222 
227  virtual void abortEvaluation() = 0;
228 
233  virtual void clearExceptions() = 0;
234 
242  virtual ScriptContext* currentContext() const = 0;
243 
254  virtual ScriptValue evaluate(const QString& program, const QString& fileName = QString()) = 0;
255 
262  virtual ScriptValue evaluate(const ScriptProgramPointer &program) = 0;
263 
264 
274  virtual ScriptValue evaluateInClosure(const ScriptValue& locals, const ScriptProgramPointer& program) = 0;
275 
285  Q_ASSERT(false);
286  return ScriptValue();
287  }
288 
295  virtual bool hasUncaughtException() const = 0;
296 
303  virtual bool isEvaluating() const = 0;
304  //virtual ScriptValue lintScript(const QString& sourceCode, const QString& fileName, const int lineNumber = 1) = 0;
305 
320  virtual ScriptValue checkScriptSyntax(ScriptProgramPointer program) = 0;
321 
327  ScriptManager* manager() const { return _manager; }
328 
329  virtual ScriptValue newArray(uint length = 0) = 0;
330  virtual ScriptValue newArrayBuffer(const QByteArray& message) = 0;
331  virtual ScriptValue newFunction(FunctionSignature fun, int length = 0) {
332  Q_ASSERT(false);
333  return ScriptValue();
334  }
335  virtual ScriptValue newObject() = 0;
336  virtual ScriptProgramPointer newProgram(const QString& sourceCode, const QString& fileName) = 0;
337  virtual ScriptValue newQObject(QObject *object, ValueOwnership ownership = QtOwnership, const QObjectWrapOptions &options = QObjectWrapOptions()) = 0;
338  virtual ScriptValue newValue(bool value) = 0;
339  virtual ScriptValue newValue(int value) = 0;
340  virtual ScriptValue newValue(uint value) = 0;
341  virtual ScriptValue newValue(double value) = 0;
342  virtual ScriptValue newValue(const QString& value) = 0;
343  virtual ScriptValue newValue(const QLatin1String& value) = 0;
344  virtual ScriptValue newValue(const char* value) = 0;
345  virtual ScriptValue newVariant(const QVariant& value) = 0;
346  virtual ScriptValue nullValue() = 0;
347 
348 
358  virtual ScriptValue makeError(const ScriptValue& other, const QString& type = "Error") = 0;
359 
360 
369  virtual bool raiseException(const ScriptValue& exception, const QString &reason = QString()) = 0;
370 
379  virtual bool raiseException(const QString& error, const QString &reason = QString()) = 0;
380 
381 
382  virtual void registerEnum(ScriptEngineScopeGuard* scopeGuard, const QString& enumName, QMetaEnum newEnum) = 0;
383  virtual void registerFunction(ScriptEngineScopeGuard* scopeGuard, const QString& name, FunctionSignature fun, int numArguments = -1) = 0;
384  virtual void registerFunction(ScriptEngineScopeGuard* scopeGuard, const QString& parent, const QString& name, FunctionSignature fun, int numArguments = -1) = 0;
385  virtual void registerGetterSetter(ScriptEngineScopeGuard* scopeGuard, const QString& name, FunctionSignature getter, FunctionSignature setter, const QString& parent = QString("")) = 0;
386  virtual void registerGlobalObject(ScriptEngineScopeGuard* scopeGuard, const QString& name, QObject* object, ScriptEngine::ValueOwnership = ScriptEngine::QtOwnership) = 0;
387  virtual void setDefaultPrototype(int metaTypeId, const ScriptValue& prototype) = 0;
388  virtual void setObjectName(const QString& name) = 0;
389  virtual bool setProperty(const char* name, const QVariant& value) = 0;
390  virtual void setProcessEventsInterval(int interval) = 0;
391  virtual QThread* thread() const = 0;
392  virtual void setThread(QThread* thread) = 0;
393  //Q_INVOKABLE virtual void enterIsolateOnThisThread() = 0;
394  virtual ScriptValue undefinedValue() = 0;
395 
404  virtual std::shared_ptr<ScriptException> uncaughtException() const = 0;
405 
406  virtual void updateMemoryCost(const qint64& deltaSize) = 0;
407  virtual void requestCollectGarbage() = 0;
408 
413  virtual void processEvents() = 0;
414 
423  virtual void compileTest() = 0;
424  virtual QString scriptValueDebugDetails(const ScriptValue &value) = 0;
425  virtual QString scriptValueDebugListMembers(const ScriptValue &value) = 0;
426 
434  virtual void logBacktrace(const QString &title) = 0;
435 
443  virtual ScriptEngineMemoryStatistics getMemoryUsageStatistics() = 0;
444 
449 
453  virtual void dumpHeapObjectStatistics() = 0;
454 
458  virtual void startProfiling() = 0;
459 
463  virtual void stopProfilingAndSave() = 0;
464 
468  virtual void disconnectSignalProxies() = 0;
469 
470 public:
471  // helper to detect and log warnings when other code invokes QScriptEngine/BaseScriptEngine in thread-unsafe ways
472  bool IS_THREADSAFE_INVOCATION(const QString& method);
473 
474 public:
475  template <typename T>
476  inline T fromScriptValue(const ScriptValue& value) {
477  return scriptvalue_cast<T>(value);
478  }
479 
480  template <typename T>
481  inline ScriptValue toScriptValue(const T& value) {
482  return scriptValueFromValue(this, value);
483  }
484 
485 public: // not for public use, but I don't like how Qt strings this along with private friend functions
486  virtual ScriptValue create(int type, const void* ptr) = 0;
487  virtual QVariant convert(const ScriptValue& value, int type) = 0;
488  virtual void registerCustomType(int type, MarshalFunction mf, DemarshalFunction df) = 0;
489  virtual QStringList getCurrentScriptURLs() const = 0;
490  virtual void perManagerLoopIterationCleanup() = 0;
491 
492 signals:
498  void exception(std::shared_ptr<ScriptException> exception);
499 
500 protected:
501  virtual ~ScriptEngine() {} // prevent explicit deletion of base class
502 
503  ScriptManager *_manager;
504 };
505 Q_DECLARE_OPERATORS_FOR_FLAGS(ScriptEngine::QObjectWrapOptions);
506 
507 ScriptEnginePointer newScriptEngine(ScriptManager* manager = nullptr);
508 
509 // Standardized CPS callback helpers (see: http://fredkschott.com/post/2014/03/understanding-error-first-callbacks-in-node-js/)
510 // These two helpers allow async JS APIs that use a callback parameter to be more friendly to scripters by accepting thisObject
511 // context and adopting a consistent and intuitable callback signature:
512 // function callback(err, result) { if (err) { ... } else { /* do stuff with result */ } }
513 //
514 // To use, first pass the user-specified callback args in the same order used with optionally-scoped Qt signal connections:
515 // auto handler = makeScopedHandlerObject(scopeOrCallback, optionalMethodOrName);
516 // And then invoke the scoped handler later per CPS conventions:
517 // auto result = callScopedHandlerObject(handler, err, result);
518 ScriptValue makeScopedHandlerObject(const ScriptValue& scopeOrCallback, const ScriptValue& methodOrName);
519 ScriptValue callScopedHandlerObject(const ScriptValue& handler, const ScriptValue& err, const ScriptValue& result);
520 
522 // Inline implementations
523 /*
524 QThread* ScriptEngine::thread() const {
525  QObject* qobject = toQObject();
526  if (qobject == nullptr) {
527  return nullptr;
528  }
529  return qobject->thread();
530 }
531 */
532 
533 #endif // hifi_ScriptEngine_h
534 
[ScriptInterface] Provides an engine-independent interface for QScriptContext
Definition: ScriptContext.h:55
Class used as a base for script engine-specific thread safety guards.
Definition: ScriptEngine.h:197
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 bool raiseException(const QString &error, const QString &reason=QString())=0
Causes an exception to be raised in the currently executing script.
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
@ ScriptOwnership
Object is managed by the script.
Definition: ScriptEngine.h:120
@ AutoOwnership
Ownership is determined automatically. If the object has a parent, it's deemed QtOwnership....
Definition: ScriptEngine.h:128
virtual ScriptValue evaluate(const ScriptProgramPointer &program)=0
Evaluates a pre-compiled program.
ScriptManager * manager() const
Pointer to the ScriptManager that controls this scripting engine.
Definition: ScriptEngine.h:327
QObjectWrapOption
Which part of an object is exposed to the script.
Definition: ScriptEngine.h:135
@ SkipMethodsInEnumeration
Don't include methods (signals and slots) when enumerating the object's properties.
Definition: ScriptEngine.h:185
@ ExcludeSuperClassContents
The script object will not expose the QObject::deleteLater() slot.
Definition: ScriptEngine.h:159
@ ExcludeSuperClassProperties
The script object will not expose properties inherited from the superclass.
Definition: ScriptEngine.h:153
@ PreferExistingWrapperObject
If a wrapper object with the requested configuration already exists, return that object.
Definition: ScriptEngine.h:179
@ ExcludeSuperClassMethods
The script object will not expose child objects as properties.
Definition: ScriptEngine.h:147
@ ExcludeSlots
The script object will not expose the QObject's slots.
Definition: ScriptEngine.h:167
@ AutoCreateDynamicProperties
Properties that don't already exist in the QObject will be created as dynamic properties of that obje...
Definition: ScriptEngine.h:173
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.
void exception(std::shared_ptr< ScriptException > exception)
The script being run threw an exception.
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
Engine-independent representation of a script program.
Definition: ScriptProgram.h:35
[ScriptInterface] Provides an engine-independent interface for QScriptValue
Definition: ScriptValue.h:40