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 
196  protected:
197  ScriptEngineScopeGuard() = default;
198 
199  // prevent copy and move
202  ScriptEngineScopeGuard& operator=(const ScriptEngineScopeGuard&) = delete;
203  ScriptEngineScopeGuard& operator=(ScriptEngineScopeGuard&&) = delete;
204  public:
205  virtual ~ScriptEngineScopeGuard() = default;
206  };
207 
217  virtual std::unique_ptr<ScriptEngineScopeGuard> getScopeGuard() = 0;
218 
223  virtual void abortEvaluation() = 0;
224 
229  virtual void clearExceptions() = 0;
230 
238  virtual ScriptContext* currentContext() const = 0;
239 
250  virtual ScriptValue evaluate(const QString& program, const QString& fileName = QString()) = 0;
251 
258  virtual ScriptValue evaluate(const ScriptProgramPointer &program) = 0;
259 
260 
270  virtual ScriptValue evaluateInClosure(const ScriptValue& locals, const ScriptProgramPointer& program) = 0;
271 
281  Q_ASSERT(false);
282  return ScriptValue();
283  }
284 
291  virtual bool hasUncaughtException() const = 0;
292 
299  virtual bool isEvaluating() const = 0;
300  //virtual ScriptValue lintScript(const QString& sourceCode, const QString& fileName, const int lineNumber = 1) = 0;
301 
316  virtual ScriptValue checkScriptSyntax(ScriptProgramPointer program) = 0;
317 
323  ScriptManager* manager() const { return _manager; }
324 
325  virtual ScriptValue newArray(uint length = 0) = 0;
326  virtual ScriptValue newArrayBuffer(const QByteArray& message) = 0;
327  virtual ScriptValue newFunction(FunctionSignature fun, int length = 0) {
328  Q_ASSERT(false);
329  return ScriptValue();
330  }
331  virtual ScriptValue newObject() = 0;
332  virtual ScriptProgramPointer newProgram(const QString& sourceCode, const QString& fileName) = 0;
333  virtual ScriptValue newQObject(QObject *object, ValueOwnership ownership = QtOwnership, const QObjectWrapOptions &options = QObjectWrapOptions()) = 0;
334  virtual ScriptValue newValue(bool value) = 0;
335  virtual ScriptValue newValue(int value) = 0;
336  virtual ScriptValue newValue(uint value) = 0;
337  virtual ScriptValue newValue(double value) = 0;
338  virtual ScriptValue newValue(const QString& value) = 0;
339  virtual ScriptValue newValue(const QLatin1String& value) = 0;
340  virtual ScriptValue newValue(const char* value) = 0;
341  virtual ScriptValue newVariant(const QVariant& value) = 0;
342  virtual ScriptValue nullValue() = 0;
343 
344 
354  virtual ScriptValue makeError(const ScriptValue& other, const QString& type = "Error") = 0;
355 
356 
365  virtual bool raiseException(const ScriptValue& exception, const QString &reason = QString()) = 0;
366 
375  virtual bool raiseException(const QString& error, const QString &reason = QString()) = 0;
376 
377 
378  virtual void registerEnum(const QString& enumName, QMetaEnum newEnum) = 0;
379  virtual void registerFunction(const QString& name, FunctionSignature fun, int numArguments = -1) = 0;
380  virtual void registerFunction(const QString& parent, const QString& name, FunctionSignature fun, int numArguments = -1) = 0;
381  virtual void registerGetterSetter(const QString& name, FunctionSignature getter, FunctionSignature setter, const QString& parent = QString("")) = 0;
382  virtual void registerGlobalObject(const QString& name, QObject* object, ScriptEngine::ValueOwnership = ScriptEngine::QtOwnership) = 0;
383  virtual void setDefaultPrototype(int metaTypeId, const ScriptValue& prototype) = 0;
384  virtual void setObjectName(const QString& name) = 0;
385  virtual bool setProperty(const char* name, const QVariant& value) = 0;
386  virtual void setProcessEventsInterval(int interval) = 0;
387  virtual QThread* thread() const = 0;
388  virtual void setThread(QThread* thread) = 0;
389  //Q_INVOKABLE virtual void enterIsolateOnThisThread() = 0;
390  virtual ScriptValue undefinedValue() = 0;
391 
400  virtual std::shared_ptr<ScriptException> uncaughtException() const = 0;
401 
402  virtual void updateMemoryCost(const qint64& deltaSize) = 0;
403  virtual void requestCollectGarbage() = 0;
404 
413  virtual void compileTest() = 0;
414  virtual QString scriptValueDebugDetails(const ScriptValue &value) = 0;
415  virtual QString scriptValueDebugListMembers(const ScriptValue &value) = 0;
416 
424  virtual void logBacktrace(const QString &title) = 0;
425 
433  virtual ScriptEngineMemoryStatistics getMemoryUsageStatistics() = 0;
434 
439 
443  virtual void dumpHeapObjectStatistics() = 0;
444 
448  virtual void startProfiling() = 0;
449 
453  virtual void stopProfilingAndSave() = 0;
454 
458  virtual void disconnectSignalProxies() = 0;
459 
460 public:
461  // helper to detect and log warnings when other code invokes QScriptEngine/BaseScriptEngine in thread-unsafe ways
462  bool IS_THREADSAFE_INVOCATION(const QString& method);
463 
464 public:
465  template <typename T>
466  inline T fromScriptValue(const ScriptValue& value) {
467  return scriptvalue_cast<T>(value);
468  }
469 
470  template <typename T>
471  inline ScriptValue toScriptValue(const T& value) {
472  return scriptValueFromValue(this, value);
473  }
474 
475 public: // not for public use, but I don't like how Qt strings this along with private friend functions
476  virtual ScriptValue create(int type, const void* ptr) = 0;
477  virtual QVariant convert(const ScriptValue& value, int type) = 0;
478  virtual void registerCustomType(int type, MarshalFunction mf, DemarshalFunction df) = 0;
479  virtual QStringList getCurrentScriptURLs() const = 0;
480  virtual void perManagerLoopIterationCleanup() = 0;
481 
482 signals:
488  void exception(std::shared_ptr<ScriptException> exception);
489 
490 protected:
491  virtual ~ScriptEngine() {} // prevent explicit deletion of base class
492 
493  ScriptManager *_manager;
494 };
495 Q_DECLARE_OPERATORS_FOR_FLAGS(ScriptEngine::QObjectWrapOptions);
496 
497 ScriptEnginePointer newScriptEngine(ScriptManager* manager = nullptr);
498 
499 // Standardized CPS callback helpers (see: http://fredkschott.com/post/2014/03/understanding-error-first-callbacks-in-node-js/)
500 // These two helpers allow async JS APIs that use a callback parameter to be more friendly to scripters by accepting thisObject
501 // context and adopting a consistent and intuitable callback signature:
502 // function callback(err, result) { if (err) { ... } else { /* do stuff with result */ } }
503 //
504 // To use, first pass the user-specified callback args in the same order used with optionally-scoped Qt signal connections:
505 // auto handler = makeScopedHandlerObject(scopeOrCallback, optionalMethodOrName);
506 // And then invoke the scoped handler later per CPS conventions:
507 // auto result = callScopedHandlerObject(handler, err, result);
508 ScriptValue makeScopedHandlerObject(const ScriptValue& scopeOrCallback, const ScriptValue& methodOrName);
509 ScriptValue callScopedHandlerObject(const ScriptValue& handler, const ScriptValue& err, const ScriptValue& result);
510 
512 // Inline implementations
513 /*
514 QThread* ScriptEngine::thread() const {
515  QObject* qobject = toQObject();
516  if (qobject == nullptr) {
517  return nullptr;
518  }
519  return qobject->thread();
520 }
521 */
522 
523 #endif // hifi_ScriptEngine_h
524 
[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:195
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:323
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 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:280
virtual std::unique_ptr< ScriptEngineScopeGuard > getScopeGuard()=0
Creates a thread safety scope guard.
Manages a single scripting engine.
Definition: ScriptManager.h:281
Engine-independent representation of a script program.
Definition: ScriptProgram.h:35
[ScriptInterface] Provides an engine-independent interface for QScriptValue
Definition: ScriptValue.h:40