Overte C++ Documentation
V8Types.h
1 //
2 // V8Types.h
3 // libraries/script-engine/src/v8
4 //
5 // Created by dr Karol Suprynowicz on 2022/10/08
6 // Copyright 2022-2023 Overte e.V.
7 //
8 // Distributed under the Apache License, Version 2.0.
9 // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
10 // SPDX-License-Identifier: Apache-2.0
11 //
12 
13 #ifndef hifi_V8Types_h
14 #define hifi_V8Types_h
15 
16 #include <memory>
17 
18 #include <libplatform/libplatform.h>
19 #include <v8.h>
20 
21 #include "ScriptEngineV8.h"
22 
23 template <typename T>
24 class V8ScriptValueTemplate {
25 public:
26  V8ScriptValueTemplate() = delete;
27 
28  V8ScriptValueTemplate(ScriptEngineV8 *engine, const v8::Local<T> value/*, V8ScriptValueTemplate::Ownership ownership*/) : _engine(engine) {
29  v8::Locker locker(_engine->getIsolate());
30  v8::Isolate::Scope isolateScope(_engine->getIsolate());
31  v8::HandleScope handleScope(_engine->getIsolate());
32  v8::Context::Scope(_engine->getContext());
33 #ifdef OVERTE_V8_MEMORY_DEBUG
34  _engine->incrementScriptValueCounter();
35 #endif
36  _value.reset(new v8::UniquePersistent<T>(_engine->getIsolate(), value));
37  };
38 
39  V8ScriptValueTemplate& operator= (const V8ScriptValueTemplate &source) {
40  v8::Locker locker(_engine->getIsolate());
41  v8::Isolate::Scope isolateScope(_engine->getIsolate());
42  v8::HandleScope handleScope(_engine->getIsolate());
43  v8::Context::Scope(_engine->getContext());
44  _engine = source.getEngine();
45  _value.reset(new v8::UniquePersistent<T>(_engine->getIsolate(), source.constGet()));
46  return *this;
47  };
48 
49  V8ScriptValueTemplate(ScriptEngineV8 *engine) : _engine(engine) {
50  v8::Locker locker(_engine->getIsolate());
51  v8::Isolate::Scope isolateScope(_engine->getIsolate());
52  v8::HandleScope handleScope(_engine->getIsolate());
53  v8::Context::Scope(_engine->getContext());
54 #ifdef OVERTE_V8_MEMORY_DEBUG
55  _engine->incrementScriptValueCounter();
56 #endif
57  _value.reset(new v8::UniquePersistent<T>(_engine->getIsolate(), v8::Local<T>()));
58  };
59 
60  V8ScriptValueTemplate(const V8ScriptValueTemplate &copied) : _engine(copied.getEngine()) {
61  v8::Locker locker(_engine->getIsolate());
62  v8::Isolate::Scope isolateScope(_engine->getIsolate());
63  v8::HandleScope handleScope(_engine->getIsolate());
64  v8::Context::Scope(_engine->getContext());
65 #ifdef OVERTE_V8_MEMORY_DEBUG
66  _engine->incrementScriptValueCounter();
67 #endif
68  _value.reset(new v8::UniquePersistent<T>(_engine->getIsolate(), copied.constGet()));
69  }
70 
71  v8::Local<T> get() {
72  Q_ASSERT(_engine->getIsolate()->IsCurrent());
73  v8::EscapableHandleScope handleScope(_engine->getIsolate());
74  return handleScope.Escape(_value.get()->Get(_engine->getIsolate()));
75  };
76 
77  const v8::Local<T> constGet() const {
78  Q_ASSERT(_engine->getIsolate()->IsCurrent());
79  v8::EscapableHandleScope handleScope(_engine->getIsolate());
80  return handleScope.Escape(_value.get()->Get(_engine->getIsolate()));
81  };
82 
83  const v8::Local<v8::Context> constGetContext() const {
84  Q_ASSERT(_engine->getIsolate()->IsCurrent());
85  v8::EscapableHandleScope handleScope(_engine->getIsolate());
86  return handleScope.Escape(_engine->getIsolate()->GetCurrentContext());
87  };
88 
89  const v8::Isolate* constGetIsolate() const { return _engine->getIsolate(); };
90  v8::Isolate* getIsolate() { return _engine->getIsolate();};
91 
92  ScriptEngineV8* getEngine() const { return _engine; };
93 
94  v8::Local<v8::Context> getContext() {
95  Q_ASSERT(_engine->getIsolate()->IsCurrent());
96  v8::EscapableHandleScope handleScope(_engine->getIsolate());
97  return handleScope.Escape(_engine->getIsolate()->GetCurrentContext());
98  };
99 
100  void reset(v8::Isolate *isolate, v8::Local<T>) {
101  Q_ASSERT(false);
102  };
103  // V8TODO: add thread safe destructors to all objects that have persistent handles
104  ~V8ScriptValueTemplate() {
105  v8::Locker locker(_engine->getIsolate());
106  v8::Isolate::Scope isolateScope(_engine->getIsolate());
107  v8::HandleScope handleScope(_engine->getIsolate());
108  //v8::Context::Scope(_engine->getContext());
109 #ifdef OVERTE_V8_MEMORY_DEBUG
110  _engine->decrementScriptValueCounter();
111 #endif
112  _value->Reset();
113  }
114 
115 private:
116  std::shared_ptr<v8::UniquePersistent<T>> _value;
117  ScriptEngineV8 *_engine;
118 };
119 
120 class V8ScriptString : public V8ScriptValueTemplate<v8::String> {
121 public:
122  V8ScriptString() = delete;
123  V8ScriptString(ScriptEngineV8 *engine, const v8::Local<v8::String> value) : V8ScriptValueTemplate<v8::String>(engine, value) {};
124  const QString toQString() const {
125  v8::Locker locker(getEngine()->getIsolate());
126  v8::Isolate::Scope isolateScope(getEngine()->getIsolate());
127  v8::HandleScope handleScope(getEngine()->getIsolate());
128  v8::Context::Scope contextScope(getEngine()->getContext());
129  Q_ASSERT(constGet()->IsString());
130  return QString(*v8::String::Utf8Value(const_cast<v8::Isolate*>(constGetIsolate()), constGet()));
131  };
132  bool operator==(const V8ScriptString& string) const {
133  v8::Locker locker(getEngine()->getIsolate());
134  v8::Isolate::Scope isolateScope(getEngine()->getIsolate());
135  v8::HandleScope handleScope(getEngine()->getIsolate());
136  v8::Context::Scope contextScope(getEngine()->getContext());
137  Q_ASSERT(constGet()->IsString());
138  return constGet()->StringEquals(string.constGet());
139  }
140 };
141 
142 inline uint qHash(const V8ScriptString &key, uint seed = 0) {
143  return qHash(key.toQString(), seed);
144 };
145 
146 #endif