Add V8 handle scopes

This commit is contained in:
ksuprynowicz 2022-10-08 16:30:36 +02:00
parent e1fb864c7a
commit f0e1327032
10 changed files with 135 additions and 43 deletions

View file

@ -33,7 +33,8 @@ ScriptContextV8Wrapper* ScriptContextV8Wrapper::unwrap(ScriptContext* val) {
} }
v8::Local<v8::Context> ScriptContextV8Wrapper::toV8Value() const { v8::Local<v8::Context> ScriptContextV8Wrapper::toV8Value() const {
return _context.Get(_engine->getIsolate()); v8::EscapableHandleScope handleScope(_engine->getIsolate());
return handleScope.Escape(_context.Get(_engine->getIsolate()));
} }
int ScriptContextV8Wrapper::argumentCount() const { int ScriptContextV8Wrapper::argumentCount() const {
@ -42,6 +43,7 @@ int ScriptContextV8Wrapper::argumentCount() const {
} }
ScriptValue ScriptContextV8Wrapper::argument(int index) const { ScriptValue ScriptContextV8Wrapper::argument(int index) const {
v8::HandleScope handleScope(_engine->getIsolate());
Q_ASSERT(_functionCallbackInfo); Q_ASSERT(_functionCallbackInfo);
v8::Local<v8::Value> result = (*_functionCallbackInfo)[index]; v8::Local<v8::Value> result = (*_functionCallbackInfo)[index];
//V8ScriptValue result = _context->argument(index); //V8ScriptValue result = _context->argument(index);
@ -50,6 +52,7 @@ ScriptValue ScriptContextV8Wrapper::argument(int index) const {
QStringList ScriptContextV8Wrapper::backtrace() const { QStringList ScriptContextV8Wrapper::backtrace() const {
auto isolate = _engine->getIsolate(); auto isolate = _engine->getIsolate();
v8::HandleScope handleScope(isolate);
v8::Local<v8::StackTrace> stackTrace = v8::StackTrace::CurrentStackTrace(isolate, 40); v8::Local<v8::StackTrace> stackTrace = v8::StackTrace::CurrentStackTrace(isolate, 40);
QStringList backTrace; QStringList backTrace;
//V8TODO nicer formatting //V8TODO nicer formatting
@ -90,17 +93,20 @@ ScriptContextPointer ScriptContextV8Wrapper::parentContext() const {
ScriptValue ScriptContextV8Wrapper::thisObject() const { ScriptValue ScriptContextV8Wrapper::thisObject() const {
Q_ASSERT(_functionCallbackInfo); Q_ASSERT(_functionCallbackInfo);
v8::HandleScope handleScope(_engine->getIsolate());
v8::Local<v8::Value> result = _functionCallbackInfo->This(); v8::Local<v8::Value> result = _functionCallbackInfo->This();
return ScriptValue(new ScriptValueV8Wrapper(_engine, V8ScriptValue(_engine->getIsolate(), result))); return ScriptValue(new ScriptValueV8Wrapper(_engine, V8ScriptValue(_engine->getIsolate(), result)));
return ScriptValue(); return ScriptValue();
} }
ScriptValue ScriptContextV8Wrapper::throwError(const QString& text) { ScriptValue ScriptContextV8Wrapper::throwError(const QString& text) {
v8::HandleScope handleScope(_engine->getIsolate());
V8ScriptValue result(_engine->getIsolate(), _engine->getIsolate()->ThrowError(v8::String::NewFromUtf8(_engine->getIsolate(), text.toStdString().c_str()).ToLocalChecked())); V8ScriptValue result(_engine->getIsolate(), _engine->getIsolate()->ThrowError(v8::String::NewFromUtf8(_engine->getIsolate(), text.toStdString().c_str()).ToLocalChecked()));
return ScriptValue(new ScriptValueV8Wrapper(_engine, std::move(result))); return ScriptValue(new ScriptValueV8Wrapper(_engine, std::move(result)));
} }
ScriptValue ScriptContextV8Wrapper::throwValue(const ScriptValue& value) { ScriptValue ScriptContextV8Wrapper::throwValue(const ScriptValue& value) {
v8::HandleScope handleScope(_engine->getIsolate());
ScriptValueV8Wrapper* unwrapped = ScriptValueV8Wrapper::unwrap(value); ScriptValueV8Wrapper* unwrapped = ScriptValueV8Wrapper::unwrap(value);
if (!unwrapped) { if (!unwrapped) {
return _engine->undefinedValue(); return _engine->undefinedValue();

View file

@ -56,6 +56,7 @@ private: // storage
class ScriptFunctionContextV8Wrapper final : public ScriptFunctionContext { class ScriptFunctionContextV8Wrapper final : public ScriptFunctionContext {
public: // construction public: // construction
//V8TODO
inline ScriptFunctionContextV8Wrapper(v8::Local<v8::Context> context) { } inline ScriptFunctionContextV8Wrapper(v8::Local<v8::Context> context) { }
public: // ScriptFunctionContext implementation public: // ScriptFunctionContext implementation

View file

@ -293,6 +293,7 @@ ScriptValue ScriptEngineV8::newLambdaFunction(std::function<V8ScriptValue(V8Scri
return call; return call;
} }
QString Lambda::toString() const { QString Lambda::toString() const {
v8::HandleScope handleScope(_engine->getIsolate());
v8::Local<v8::String> string; v8::Local<v8::String> string;
QString qString(""); QString qString("");
if (_data.constGet()->ToString(_engine->getContext()).ToLocal(&string)) { if (_data.constGet()->ToString(_engine->getContext()).ToLocal(&string)) {
@ -372,6 +373,7 @@ ScriptEngineV8::ScriptEngineV8(ScriptManager* scriptManager) :
v8::Isolate::CreateParams isolateParams; v8::Isolate::CreateParams isolateParams;
isolateParams.array_buffer_allocator = v8::ArrayBuffer::Allocator::NewDefaultAllocator(); isolateParams.array_buffer_allocator = v8::ArrayBuffer::Allocator::NewDefaultAllocator();
_v8Isolate = v8::Isolate::New(isolateParams); _v8Isolate = v8::Isolate::New(isolateParams);
v8::HandleScope handleScope(_v8Isolate);
v8::Local<v8::Context> context = v8::Context::New(_v8Isolate); v8::Local<v8::Context> context = v8::Context::New(_v8Isolate);
_v8Context = v8::UniquePersistent<v8::Context>(_v8Isolate, context); _v8Context = v8::UniquePersistent<v8::Context>(_v8Isolate, context);
@ -434,7 +436,7 @@ void ScriptEngineV8::registerValue(const QString& valueName, V8ScriptValue value
Q_ARG(V8ScriptValue, value)); Q_ARG(V8ScriptValue, value));
return; return;
}*/ }*/
v8::HandleScope handleScope(_v8Isolate);
QStringList pathToValue = valueName.split("."); QStringList pathToValue = valueName.split(".");
int partsToGo = pathToValue.length(); int partsToGo = pathToValue.length();
v8::Local<v8::Object> partObject = _v8Context.Get(_v8Isolate)->Global(); v8::Local<v8::Object> partObject = _v8Context.Get(_v8Isolate)->Global();
@ -449,15 +451,21 @@ void ScriptEngineV8::registerValue(const QString& valueName, V8ScriptValue value
//QObject *object = new QObject; //QObject *object = new QObject;
v8::Local<v8::Object> partValue = v8::Object::New(_v8Isolate); //newQObject(object, QScriptEngine::ScriptOwnership); v8::Local<v8::Object> partValue = v8::Object::New(_v8Isolate); //newQObject(object, QScriptEngine::ScriptOwnership);
//V8ScriptValue partValue = QScriptEngine::newArray(); //newQObject(object, QScriptEngine::ScriptOwnership); //V8ScriptValue partValue = QScriptEngine::newArray(); //newQObject(object, QScriptEngine::ScriptOwnership);
Q_ASSERT(partObject->Set(_v8Context.Get(_v8Isolate), pathPartV8, partValue).FromMaybe(false)); if (!partObject->Set(_v8Context.Get(_v8Isolate), pathPartV8, partValue).FromMaybe(false)) {
Q_ASSERT(false);
}
} else { } else {
//partObject = currentPath->ToObject(); //partObject = currentPath->ToObject();
//V8TODO: do these still happen if asserts are disabled? //V8TODO: do these still happen if asserts are disabled?
Q_ASSERT(partObject->Set(_v8Context.Get(_v8Isolate), pathPartV8, value.constGet()).FromMaybe(false)); if (!partObject->Set(_v8Context.Get(_v8Isolate), pathPartV8, value.constGet()).FromMaybe(false)) {
Q_ASSERT(false);
}
} }
} }
v8::Local<v8::Value> child; v8::Local<v8::Value> child;
Q_ASSERT(partObject->Get(_v8Context.Get(_v8Isolate), pathPartV8).ToLocal(&child)); if (!partObject->Get(_v8Context.Get(_v8Isolate), pathPartV8).ToLocal(&child)) {
Q_ASSERT(false);
}
} }
} }
@ -475,6 +483,7 @@ void ScriptEngineV8::registerGlobalObject(const QString& name, QObject* object)
#ifdef THREAD_DEBUGGING #ifdef THREAD_DEBUGGING
qCDebug(scriptengine) << "ScriptEngineV8::registerGlobalObject() called on thread [" << QThread::currentThread() << "] name:" << name; qCDebug(scriptengine) << "ScriptEngineV8::registerGlobalObject() called on thread [" << QThread::currentThread() << "] name:" << name;
#endif*/ #endif*/
v8::HandleScope handleScope(_v8Isolate);
v8::Local<v8::Object> v8GlobalObject = getContext()->Global(); v8::Local<v8::Object> v8GlobalObject = getContext()->Global();
v8::Local<v8::String> v8Name = v8::String::NewFromUtf8(_v8Isolate, name.toStdString().c_str()).ToLocalChecked(); v8::Local<v8::String> v8Name = v8::String::NewFromUtf8(_v8Isolate, name.toStdString().c_str()).ToLocalChecked();
@ -575,6 +584,7 @@ ScriptValue ScriptEngineV8::evaluateInClosure(const ScriptValue& _closure,
if (!IS_THREADSAFE_INVOCATION(thread(), __FUNCTION__)) { if (!IS_THREADSAFE_INVOCATION(thread(), __FUNCTION__)) {
return nullValue(); return nullValue();
} }
v8::HandleScope handleScope(_v8Isolate);
ScriptProgramV8Wrapper* unwrappedProgram = ScriptProgramV8Wrapper::unwrap(_program); ScriptProgramV8Wrapper* unwrappedProgram = ScriptProgramV8Wrapper::unwrap(_program);
if (unwrappedProgram == nullptr) { if (unwrappedProgram == nullptr) {
return nullValue(); return nullValue();
@ -699,6 +709,7 @@ ScriptValue ScriptEngineV8::evaluate(const QString& sourceCode, const QString& f
}*/ }*/
// Compile and check syntax // Compile and check syntax
// V8TODO: Could these all be replaced with checkSyntax function from wrapper? // V8TODO: Could these all be replaced with checkSyntax function from wrapper?
v8::HandleScope handleScope(_v8Isolate);
v8::TryCatch tryCatch(getIsolate()); v8::TryCatch tryCatch(getIsolate());
v8::ScriptOrigin scriptOrigin(getIsolate(), v8::String::NewFromUtf8(getIsolate(), fileName.toStdString().c_str()).ToLocalChecked()); v8::ScriptOrigin scriptOrigin(getIsolate(), v8::String::NewFromUtf8(getIsolate(), fileName.toStdString().c_str()).ToLocalChecked());
v8::Local<v8::Script> script; v8::Local<v8::Script> script;
@ -776,7 +787,7 @@ Q_INVOKABLE ScriptValue ScriptEngineV8::evaluate(const ScriptProgramPointer& pro
Q_ARG(const ScriptProgramPointer&, program)); Q_ARG(const ScriptProgramPointer&, program));
return result; return result;
}*/ }*/
v8::HandleScope handleScope(_v8Isolate);
ScriptProgramV8Wrapper* unwrapped = ScriptProgramV8Wrapper::unwrap(program); ScriptProgramV8Wrapper* unwrapped = ScriptProgramV8Wrapper::unwrap(program);
if (!unwrapped) { if (!unwrapped) {
auto err = makeError(newValue("could not unwrap program")); auto err = makeError(newValue("could not unwrap program"));
@ -831,6 +842,7 @@ void ScriptEngineV8::updateMemoryCost(const qint64& deltaSize) {
// ScriptEngine implementation // ScriptEngine implementation
ScriptValue ScriptEngineV8::globalObject() const { ScriptValue ScriptEngineV8::globalObject() const {
v8::HandleScope handleScope(_v8Isolate);
V8ScriptValue global(_v8Isolate, getConstContext()->Global());// = QScriptEngine::globalObject(); // can't cache the value as it may change V8ScriptValue global(_v8Isolate, getConstContext()->Global());// = QScriptEngine::globalObject(); // can't cache the value as it may change
return ScriptValue(new ScriptValueV8Wrapper(const_cast<ScriptEngineV8*>(this), std::move(global))); return ScriptValue(new ScriptValueV8Wrapper(const_cast<ScriptEngineV8*>(this), std::move(global)));
} }
@ -845,6 +857,7 @@ ScriptValue ScriptEngineV8::newArray(uint length) {
} }
ScriptValue ScriptEngineV8::newArrayBuffer(const QByteArray& message) { ScriptValue ScriptEngineV8::newArrayBuffer(const QByteArray& message) {
v8::HandleScope handleScope(_v8Isolate);
//V8TODO: this will leak memory //V8TODO: this will leak memory
std::shared_ptr<v8::BackingStore> backingStore(v8::ArrayBuffer::NewBackingStore(_v8Isolate, message.size())); std::shared_ptr<v8::BackingStore> backingStore(v8::ArrayBuffer::NewBackingStore(_v8Isolate, message.size()));
std::memcpy(backingStore.get()->Data(), message.constData(), message.size()); std::memcpy(backingStore.get()->Data(), message.constData(), message.size());
@ -900,23 +913,27 @@ ScriptValue ScriptEngineV8::newValue(uint value) {
} }
ScriptValue ScriptEngineV8::newValue(double value) { ScriptValue ScriptEngineV8::newValue(double value) {
v8::HandleScope handleScope(_v8Isolate);
V8ScriptValue result(_v8Isolate, v8::Number::New(_v8Isolate, value)); V8ScriptValue result(_v8Isolate, v8::Number::New(_v8Isolate, value));
return ScriptValue(new ScriptValueV8Wrapper(this, std::move(result))); return ScriptValue(new ScriptValueV8Wrapper(this, std::move(result)));
} }
ScriptValue ScriptEngineV8::newValue(const QString& value) { ScriptValue ScriptEngineV8::newValue(const QString& value) {
v8::HandleScope handleScope(_v8Isolate);
v8::Local<v8::String> valueV8 = v8::String::NewFromUtf8(_v8Isolate, value.toStdString().c_str(), v8::NewStringType::kNormal).ToLocalChecked(); v8::Local<v8::String> valueV8 = v8::String::NewFromUtf8(_v8Isolate, value.toStdString().c_str(), v8::NewStringType::kNormal).ToLocalChecked();
V8ScriptValue result(_v8Isolate, valueV8); V8ScriptValue result(_v8Isolate, valueV8);
return ScriptValue(new ScriptValueV8Wrapper(this, std::move(result))); return ScriptValue(new ScriptValueV8Wrapper(this, std::move(result)));
} }
ScriptValue ScriptEngineV8::newValue(const QLatin1String& value) { ScriptValue ScriptEngineV8::newValue(const QLatin1String& value) {
v8::HandleScope handleScope(_v8Isolate);
v8::Local<v8::String> valueV8 = v8::String::NewFromUtf8(_v8Isolate, value.latin1(), v8::NewStringType::kNormal).ToLocalChecked(); v8::Local<v8::String> valueV8 = v8::String::NewFromUtf8(_v8Isolate, value.latin1(), v8::NewStringType::kNormal).ToLocalChecked();
V8ScriptValue result(_v8Isolate, valueV8); V8ScriptValue result(_v8Isolate, valueV8);
return ScriptValue(new ScriptValueV8Wrapper(this, std::move(result))); return ScriptValue(new ScriptValueV8Wrapper(this, std::move(result)));
} }
ScriptValue ScriptEngineV8::newValue(const char* value) { ScriptValue ScriptEngineV8::newValue(const char* value) {
v8::HandleScope handleScope(_v8Isolate);
v8::Local<v8::String> valueV8 = v8::String::NewFromUtf8(_v8Isolate, value, v8::NewStringType::kNormal).ToLocalChecked(); v8::Local<v8::String> valueV8 = v8::String::NewFromUtf8(_v8Isolate, value, v8::NewStringType::kNormal).ToLocalChecked();
V8ScriptValue result(_v8Isolate, valueV8); V8ScriptValue result(_v8Isolate, valueV8);
return ScriptValue(new ScriptValueV8Wrapper(this, std::move(result))); return ScriptValue(new ScriptValueV8Wrapper(this, std::move(result)));
@ -986,6 +1003,7 @@ ScriptValue ScriptEngineV8::newFunction(ScriptEngine::FunctionSignature fun, int
auto v8FunctionCallback = [](const v8::FunctionCallbackInfo<v8::Value>& info) { auto v8FunctionCallback = [](const v8::FunctionCallbackInfo<v8::Value>& info) {
//V8TODO: is using GetCurrentContext ok, or context wrapper needs to be added? //V8TODO: is using GetCurrentContext ok, or context wrapper needs to be added?
v8::HandleScope handleScope(info.GetIsolate());
auto context = info.GetIsolate()->GetCurrentContext(); auto context = info.GetIsolate()->GetCurrentContext();
auto function = reinterpret_cast<ScriptEngine::FunctionSignature> auto function = reinterpret_cast<ScriptEngine::FunctionSignature>
(info.Data()->ToObject(context).ToLocalChecked()->GetAlignedPointerFromInternalField(0)); (info.Data()->ToObject(context).ToLocalChecked()->GetAlignedPointerFromInternalField(0));
@ -1000,6 +1018,7 @@ ScriptValue ScriptEngineV8::newFunction(ScriptEngine::FunctionSignature fun, int
//auto functionTemplate = v8::FunctionTemplate::New(_v8Isolate, v8FunctionCallback, v8::Local<v8::Value>(), v8::Local<v8::Signature>(), length); //auto functionTemplate = v8::FunctionTemplate::New(_v8Isolate, v8FunctionCallback, v8::Local<v8::Value>(), v8::Local<v8::Signature>(), length);
//auto functionData = v8::Object::New(_v8Isolate); //auto functionData = v8::Object::New(_v8Isolate);
//functionData->setIn //functionData->setIn
v8::HandleScope handleScope(_v8Isolate);
auto functionDataTemplate = v8::ObjectTemplate::New(_v8Isolate); auto functionDataTemplate = v8::ObjectTemplate::New(_v8Isolate);
functionDataTemplate->SetInternalFieldCount(3); functionDataTemplate->SetInternalFieldCount(3);
auto functionData = functionDataTemplate->NewInstance(getContext()).ToLocalChecked(); auto functionData = functionDataTemplate->NewInstance(getContext()).ToLocalChecked();
@ -1024,6 +1043,7 @@ void ScriptEngineV8::setObjectName(const QString& name) {
//V8TODO //V8TODO
bool ScriptEngineV8::setProperty(const char* name, const QVariant& value) { bool ScriptEngineV8::setProperty(const char* name, const QVariant& value) {
v8::HandleScope handleScope(_v8Isolate);
v8::Local<v8::Object> global = getContext()->Global(); v8::Local<v8::Object> global = getContext()->Global();
auto v8Name = v8::String::NewFromUtf8(getIsolate(), name).ToLocalChecked(); auto v8Name = v8::String::NewFromUtf8(getIsolate(), name).ToLocalChecked();
V8ScriptValue v8Value = castVariantToValue(value); V8ScriptValue v8Value = castVariantToValue(value);

View file

@ -175,7 +175,10 @@ public: // not for public use, but I don't like how Qt strings this along with p
v8::EscapableHandleScope handleScope(_v8Isolate); v8::EscapableHandleScope handleScope(_v8Isolate);
return handleScope.Escape(_v8Context.Get(_v8Isolate)); return handleScope.Escape(_v8Context.Get(_v8Isolate));
} }
const v8::Local<v8::Context> getConstContext() const {return _v8Context.Get(_v8Isolate);} const v8::Local<v8::Context> getConstContext() const {
v8::EscapableHandleScope handleScope(_v8Isolate);
return handleScope.Escape(_v8Context.Get(_v8Isolate));
}
using ObjectWrapperMap = QMap<QObject*, QWeakPointer<ScriptObjectV8Proxy>>; using ObjectWrapperMap = QMap<QObject*, QWeakPointer<ScriptObjectV8Proxy>>;
mutable QMutex _qobjectWrapperMapProtect; mutable QMutex _qobjectWrapperMapProtect;

View file

@ -198,6 +198,7 @@ void ScriptEngineV8::registerSystemTypes() {
} }
int ScriptEngineV8::computeCastPenalty(const V8ScriptValue& v8Val, int destTypeId) { int ScriptEngineV8::computeCastPenalty(const V8ScriptValue& v8Val, int destTypeId) {
v8::HandleScope handleScope(_v8Isolate);
const v8::Local<v8::Value> val = v8Val.constGet(); const v8::Local<v8::Value> val = v8Val.constGet();
if (val->IsNumber()) { if (val->IsNumber()) {
switch (destTypeId){ switch (destTypeId){
@ -291,6 +292,7 @@ int ScriptEngineV8::computeCastPenalty(const V8ScriptValue& v8Val, int destTypeI
} }
bool ScriptEngineV8::castValueToVariant(const V8ScriptValue& v8Val, QVariant& dest, int destTypeId) { bool ScriptEngineV8::castValueToVariant(const V8ScriptValue& v8Val, QVariant& dest, int destTypeId) {
v8::HandleScope handleScope(_v8Isolate);
const v8::Local<v8::Value> val = v8Val.constGet(); const v8::Local<v8::Value> val = v8Val.constGet();
// if we're not particularly interested in a specific type, try to detect if we're dealing with a registered type // if we're not particularly interested in a specific type, try to detect if we're dealing with a registered type
@ -468,6 +470,8 @@ bool ScriptEngineV8::castValueToVariant(const V8ScriptValue& v8Val, QVariant& de
} }
QString ScriptEngineV8::valueType(const V8ScriptValue& v8Val) { QString ScriptEngineV8::valueType(const V8ScriptValue& v8Val) {
// V8TODO
v8::HandleScope handleScope(const_cast<v8::Isolate*>(v8Val.constGetIsolate()));
const v8::Local<v8::Value> val = v8Val.constGet(); const v8::Local<v8::Value> val = v8Val.constGet();
if (val->IsUndefined()) { if (val->IsUndefined()) {

View file

@ -133,6 +133,8 @@ V8ScriptValue ScriptObjectV8Proxy::newQObject(ScriptEngineV8* engine, QObject* o
} }
ScriptObjectV8Proxy* ScriptObjectV8Proxy::unwrapProxy(const V8ScriptValue& val) { ScriptObjectV8Proxy* ScriptObjectV8Proxy::unwrapProxy(const V8ScriptValue& val) {
//V8TODO This shouldn't cause problems but I'm not sure if it's ok
v8::HandleScope handleScope(const_cast<v8::Isolate*>(val.constGetIsolate()));
auto v8Value = val.constGet(); auto v8Value = val.constGet();
if (!v8Value->IsObject()) { if (!v8Value->IsObject()) {
return nullptr; return nullptr;
@ -164,6 +166,8 @@ void ScriptObjectV8Proxy::investigate() {
Q_ASSERT(qobject); Q_ASSERT(qobject);
if (!qobject) return; if (!qobject) return;
v8::HandleScope handleScope(_engine->getIsolate());
auto objectTemplate = _v8ObjectTemplate.Get(_engine->getIsolate()); auto objectTemplate = _v8ObjectTemplate.Get(_engine->getIsolate());
objectTemplate->SetInternalFieldCount(3); objectTemplate->SetInternalFieldCount(3);
objectTemplate->SetHandler(v8::NamedPropertyHandlerConfiguration(v8Get, v8Set)); objectTemplate->SetHandler(v8::NamedPropertyHandlerConfiguration(v8Get, v8Set));
@ -464,6 +468,8 @@ V8ScriptValue ScriptVariantV8Proxy::newVariant(ScriptEngineV8* engine, const QVa
} }
ScriptVariantV8Proxy* ScriptVariantV8Proxy::unwrapProxy(const V8ScriptValue& val) { ScriptVariantV8Proxy* ScriptVariantV8Proxy::unwrapProxy(const V8ScriptValue& val) {
// V8TODO
v8::HandleScope handleScope(const_cast<v8::Isolate*>(val.constGetIsolate()));
auto v8Value = val.constGet(); auto v8Value = val.constGet();
if (!v8Value->IsObject()) { if (!v8Value->IsObject()) {
return nullptr; return nullptr;
@ -550,6 +556,8 @@ void ScriptMethodV8Proxy::call(const v8::FunctionCallbackInfo<v8::Value>& argume
isolate->ThrowError("Referencing deleted native object"); isolate->ThrowError("Referencing deleted native object");
return; return;
} }
v8::HandleScope handleScope(_engine->getIsolate());
int scriptNumArgs = arguments.Length(); int scriptNumArgs = arguments.Length();
int numArgs = std::min(scriptNumArgs, _numMaxParms); int numArgs = std::min(scriptNumArgs, _numMaxParms);
@ -898,6 +906,8 @@ int ScriptSignalV8Proxy::qt_metacall(QMetaObject::Call call, int id, void** argu
if (id != 0 || call != QMetaObject::InvokeMetaMethod) { if (id != 0 || call != QMetaObject::InvokeMetaMethod) {
return id; return id;
} }
v8::HandleScope handleScope(_engine->getIsolate());
//V8ScriptValueList args(isolate, v8::Null(isolate)); //V8ScriptValueList args(isolate, v8::Null(isolate));
v8::Local<v8::Value> args[Q_METAMETHOD_INVOKE_MAX_ARGS]; v8::Local<v8::Value> args[Q_METAMETHOD_INVOKE_MAX_ARGS];
@ -952,12 +962,14 @@ ScriptSignalV8Proxy::ConnectionList::iterator ScriptSignalV8Proxy::findConnectio
void ScriptSignalV8Proxy::connect(V8ScriptValue arg0, V8ScriptValue arg1) { void ScriptSignalV8Proxy::connect(V8ScriptValue arg0, V8ScriptValue arg1) {
QObject* qobject = _object; QObject* qobject = _object;
v8::Isolate *isolate = _engine->getIsolate();
if (!qobject) { if (!qobject) {
_engine->getIsolate()->ThrowError("Referencing deleted native object"); isolate->ThrowError("Referencing deleted native object");
return; return;
} }
v8::HandleScope handleScope(isolate);
v8::Isolate *isolate = _engine->getIsolate();
// untangle the arguments // untangle the arguments
V8ScriptValue callback(isolate, v8::Null(isolate)); V8ScriptValue callback(isolate, v8::Null(isolate));
V8ScriptValue callbackThis(isolate, v8::Null(isolate)); V8ScriptValue callbackThis(isolate, v8::Null(isolate));
@ -968,7 +980,7 @@ void ScriptSignalV8Proxy::connect(V8ScriptValue arg0, V8ScriptValue arg1) {
callback = arg0; callback = arg0;
} }
if (!callback.get()->IsFunction()) { if (!callback.get()->IsFunction()) {
_engine->getIsolate()->ThrowError("Function expected as argument to 'connect'"); isolate->ThrowError("Function expected as argument to 'connect'");
return; return;
} }
@ -1030,11 +1042,12 @@ void ScriptSignalV8Proxy::connect(V8ScriptValue arg0, V8ScriptValue arg1) {
void ScriptSignalV8Proxy::disconnect(V8ScriptValue arg0, V8ScriptValue arg1) { void ScriptSignalV8Proxy::disconnect(V8ScriptValue arg0, V8ScriptValue arg1) {
QObject* qobject = _object; QObject* qobject = _object;
v8::Isolate *isolate = _engine->getIsolate();
if (!qobject) { if (!qobject) {
_engine->getIsolate()->ThrowError("Referencing deleted native object"); isolate->ThrowError("Referencing deleted native object");
return; return;
} }
v8::Isolate *isolate = _engine->getIsolate(); v8::HandleScope handleScope(isolate);
// untangle the arguments // untangle the arguments
V8ScriptValue callback(isolate, v8::Null(isolate)); V8ScriptValue callback(isolate, v8::Null(isolate));
@ -1046,7 +1059,7 @@ void ScriptSignalV8Proxy::disconnect(V8ScriptValue arg0, V8ScriptValue arg1) {
callback = arg0; callback = arg0;
} }
if (!callback.get()->IsFunction()) { if (!callback.get()->IsFunction()) {
_engine->getIsolate()->ThrowError("Function expected as argument to 'disconnect'"); isolate->ThrowError("Function expected as argument to 'disconnect'");
return; return;
} }

View file

@ -32,29 +32,32 @@ ScriptSyntaxCheckResultPointer ScriptProgramV8Wrapper::checkSyntax() {
} }
bool ScriptProgramV8Wrapper::compile() { bool ScriptProgramV8Wrapper::compile() {
auto isolate = _engine->getIsolate();
v8::HandleScope handleScope(isolate);
auto context = _engine->getContext();
int errorColumnNumber = 0; int errorColumnNumber = 0;
int errorLineNumber = 0; int errorLineNumber = 0;
QString errorMessage = ""; QString errorMessage = "";
QString errorBacktrace = ""; QString errorBacktrace = "";
ScriptSyntaxCheckResult::State state; ScriptSyntaxCheckResult::State state;
v8::TryCatch tryCatch(_engine->getIsolate()); v8::TryCatch tryCatch(isolate);
v8::ScriptOrigin scriptOrigin(_engine->getIsolate(), v8::String::NewFromUtf8(_engine->getIsolate(), _url.toStdString().c_str()).ToLocalChecked()); v8::ScriptOrigin scriptOrigin(isolate, v8::String::NewFromUtf8(isolate, _url.toStdString().c_str()).ToLocalChecked());
v8::Local<v8::Script> script; v8::Local<v8::Script> script;
if (v8::Script::Compile(_engine->getContext(), v8::String::NewFromUtf8(_engine->getIsolate(), _source.toStdString().c_str()).ToLocalChecked(), &scriptOrigin).ToLocal(&script)) { if (v8::Script::Compile(context, v8::String::NewFromUtf8(isolate, _source.toStdString().c_str()).ToLocalChecked(), &scriptOrigin).ToLocal(&script)) {
_compileResult = ScriptSyntaxCheckResultV8Wrapper(ScriptSyntaxCheckResult::Valid); _compileResult = ScriptSyntaxCheckResultV8Wrapper(ScriptSyntaxCheckResult::Valid);
_value = V8ScriptProgram(_engine->getIsolate(), script); _value = V8ScriptProgram(isolate, script);
return true; return true;
} }
v8::String::Utf8Value utf8Value(_engine->getIsolate(), tryCatch.Exception()); v8::String::Utf8Value utf8Value(isolate, tryCatch.Exception());
errorMessage = QString(*utf8Value); errorMessage = QString(*utf8Value);
v8::Local<v8::Message> exceptionMessage = tryCatch.Message(); v8::Local<v8::Message> exceptionMessage = tryCatch.Message();
if (!exceptionMessage.IsEmpty()) { if (!exceptionMessage.IsEmpty()) {
errorLineNumber = exceptionMessage->GetLineNumber(_engine->getContext()).FromJust(); errorLineNumber = exceptionMessage->GetLineNumber(context).FromJust();
errorColumnNumber = exceptionMessage->GetStartColumn(_engine->getContext()).FromJust(); errorColumnNumber = exceptionMessage->GetStartColumn(context).FromJust();
v8::Local<v8::Value> backtraceV8String; v8::Local<v8::Value> backtraceV8String;
if (tryCatch.StackTrace(_engine->getContext()).ToLocal(&backtraceV8String) && backtraceV8String->IsString() && if (tryCatch.StackTrace(context).ToLocal(&backtraceV8String) && backtraceV8String->IsString() &&
v8::Local<v8::String>::Cast(backtraceV8String)->Length() > 0) { v8::Local<v8::String>::Cast(backtraceV8String)->Length() > 0) {
v8::String::Utf8Value backtraceUtf8Value(_engine->getIsolate(), backtraceV8String); v8::String::Utf8Value backtraceUtf8Value(isolate, backtraceV8String);
errorBacktrace = *backtraceUtf8Value; errorBacktrace = *backtraceUtf8Value;
} }
} }

View file

@ -14,15 +14,17 @@
#include "ScriptValueIteratorV8Wrapper.h" #include "ScriptValueIteratorV8Wrapper.h"
V8ScriptValueIterator::V8ScriptValueIterator(ScriptEngineV8* engine, v8::Local<v8::Value> object) : _engine(engine) { V8ScriptValueIterator::V8ScriptValueIterator(ScriptEngineV8* engine, v8::Local<v8::Value> object) : _engine(engine) {
_context.Reset(_engine->getIsolate(), _engine->getContext()); auto isolate = _engine->getIsolate();
auto context = _context.Get(_engine->getIsolate()); v8::HandleScope handleScope(isolate);
_context.Reset(isolate, _engine->getContext());
auto context = _context.Get(isolate);
v8::Local<v8::Object> v8Object; v8::Local<v8::Object> v8Object;
if (!object->ToObject(context).ToLocal(&v8Object)) { if (!object->ToObject(context).ToLocal(&v8Object)) {
Q_ASSERT(false); Q_ASSERT(false);
} }
_object.Reset(_engine->getIsolate(), v8Object); _object.Reset(isolate, v8Object);
_propertyNames.Reset(_engine->getIsolate(), v8Object->GetOwnPropertyNames(context).ToLocalChecked()); _propertyNames.Reset(isolate, v8Object->GetOwnPropertyNames(context).ToLocalChecked());
_length = _propertyNames.Get(_engine->getIsolate())->Length(); _length = _propertyNames.Get(isolate)->Length();
_currentIndex = 0; _currentIndex = 0;
} }
@ -31,12 +33,14 @@ bool V8ScriptValueIterator::hasNext() const {
} }
QString V8ScriptValueIterator::name() const { QString V8ScriptValueIterator::name() const {
auto context = _context.Get(_engine->getIsolate()); auto isolate = _engine->getIsolate();
v8::HandleScope handleScope(isolate);
auto context = _context.Get(isolate);
v8::Local<v8::Value> propertyName; v8::Local<v8::Value> propertyName;
if (!_propertyNames.Get(_engine->getIsolate())->Get(context, _length).ToLocal(&propertyName)) { if (!_propertyNames.Get(isolate)->Get(context, _length).ToLocal(&propertyName)) {
Q_ASSERT(false); Q_ASSERT(false);
} }
return QString(*v8::String::Utf8Value(_engine->getIsolate(), propertyName)); return QString(*v8::String::Utf8Value(isolate, propertyName));
} }
void V8ScriptValueIterator::next() { void V8ScriptValueIterator::next() {
@ -46,16 +50,18 @@ void V8ScriptValueIterator::next() {
} }
V8ScriptValue V8ScriptValueIterator::value() { V8ScriptValue V8ScriptValueIterator::value() {
auto context = _context.Get(_engine->getIsolate()); auto isolate = _engine->getIsolate();
v8::HandleScope handleScope(isolate);
auto context = _context.Get(isolate);
v8::Local<v8::Value> v8Value; v8::Local<v8::Value> v8Value;
v8::Local<v8::Value> propertyName; v8::Local<v8::Value> propertyName;
if (!_propertyNames.Get(_engine->getIsolate())->Get(context, _length).ToLocal(&propertyName)) { if (!_propertyNames.Get(isolate)->Get(context, _length).ToLocal(&propertyName)) {
Q_ASSERT(false); Q_ASSERT(false);
} }
if (!_object.Get(_engine->getIsolate())->Get(context, propertyName->ToString(context).ToLocalChecked()).ToLocal(&v8Value)) { if (!_object.Get(isolate)->Get(context, propertyName->ToString(context).ToLocalChecked()).ToLocal(&v8Value)) {
Q_ASSERT(false); Q_ASSERT(false);
} }
return V8ScriptValue(_engine->getIsolate(), v8Value); return V8ScriptValue(isolate, v8Value);
} }
ScriptValue::PropertyFlags ScriptValueIteratorV8Wrapper::flags() const { ScriptValue::PropertyFlags ScriptValueIteratorV8Wrapper::flags() const {

View file

@ -60,6 +60,7 @@ V8ScriptValue ScriptValueV8Wrapper::fullUnwrap(ScriptEngineV8* engine, const Scr
} }
ScriptValue ScriptValueV8Wrapper::call(const ScriptValue& thisObject, const ScriptValueList& args) { ScriptValue ScriptValueV8Wrapper::call(const ScriptValue& thisObject, const ScriptValueList& args) {
v8::HandleScope handleScope(_engine->getIsolate());
V8ScriptValue v8This = fullUnwrap(thisObject); V8ScriptValue v8This = fullUnwrap(thisObject);
//V8ScriptValueList qArgs; //V8ScriptValueList qArgs;
Q_ASSERT(args.length() <= Q_METAMETHOD_INVOKE_MAX_ARGS); Q_ASSERT(args.length() <= Q_METAMETHOD_INVOKE_MAX_ARGS);
@ -84,6 +85,7 @@ ScriptValue ScriptValueV8Wrapper::call(const ScriptValue& thisObject, const Scri
} }
ScriptValue ScriptValueV8Wrapper::call(const ScriptValue& thisObject, const ScriptValue& arguments) { ScriptValue ScriptValueV8Wrapper::call(const ScriptValue& thisObject, const ScriptValue& arguments) {
v8::HandleScope handleScope(_engine->getIsolate());
V8ScriptValue v8This = fullUnwrap(thisObject); V8ScriptValue v8This = fullUnwrap(thisObject);
V8ScriptValue v8Args = fullUnwrap(arguments); V8ScriptValue v8Args = fullUnwrap(arguments);
// V8TODO should there be a v8 try-catch here? // V8TODO should there be a v8 try-catch here?
@ -104,6 +106,7 @@ ScriptValue ScriptValueV8Wrapper::call(const ScriptValue& thisObject, const Scri
} }
ScriptValue ScriptValueV8Wrapper::construct(const ScriptValueList& args) { ScriptValue ScriptValueV8Wrapper::construct(const ScriptValueList& args) {
v8::HandleScope handleScope(_engine->getIsolate());
Q_ASSERT(args.length() <= Q_METAMETHOD_INVOKE_MAX_ARGS); Q_ASSERT(args.length() <= Q_METAMETHOD_INVOKE_MAX_ARGS);
//V8TODO I'm not sure how else to do this since v8::Local should probably be on stack, not heap //V8TODO I'm not sure how else to do this since v8::Local should probably be on stack, not heap
v8::Local<v8::Value> v8Args[Q_METAMETHOD_INVOKE_MAX_ARGS]; v8::Local<v8::Value> v8Args[Q_METAMETHOD_INVOKE_MAX_ARGS];
@ -126,6 +129,7 @@ ScriptValue ScriptValueV8Wrapper::construct(const ScriptValueList& args) {
} }
ScriptValue ScriptValueV8Wrapper::construct(const ScriptValue& arguments) { ScriptValue ScriptValueV8Wrapper::construct(const ScriptValue& arguments) {
v8::HandleScope handleScope(_engine->getIsolate());
// V8TODO I'm not sure in what format arguments are yet, backtrace will show how it is used // V8TODO I'm not sure in what format arguments are yet, backtrace will show how it is used
Q_ASSERT(false); Q_ASSERT(false);
return _engine->undefinedValue(); return _engine->undefinedValue();
@ -153,6 +157,7 @@ ScriptValueIteratorPointer ScriptValueV8Wrapper::newIterator() const {
} }
ScriptValue ScriptValueV8Wrapper::property(const QString& name, const ScriptValue::ResolveFlags& mode) const { ScriptValue ScriptValueV8Wrapper::property(const QString& name, const ScriptValue::ResolveFlags& mode) const {
v8::HandleScope handleScope(_engine->getIsolate());
if (!_value.constGet()->IsObject()) { if (!_value.constGet()->IsObject()) {
//V8TODO: what about flags? //V8TODO: what about flags?
v8::Local<v8::Value> resultLocal; v8::Local<v8::Value> resultLocal;
@ -171,6 +176,7 @@ ScriptValue ScriptValueV8Wrapper::property(const QString& name, const ScriptValu
} }
ScriptValue ScriptValueV8Wrapper::property(quint32 arrayIndex, const ScriptValue::ResolveFlags& mode) const { ScriptValue ScriptValueV8Wrapper::property(quint32 arrayIndex, const ScriptValue::ResolveFlags& mode) const {
v8::HandleScope handleScope(_engine->getIsolate());
if (!_value.constGet()->IsObject()) { if (!_value.constGet()->IsObject()) {
//V8TODO: what about flags? //V8TODO: what about flags?
v8::Local<v8::Value> resultLocal; v8::Local<v8::Value> resultLocal;
@ -191,6 +197,7 @@ void ScriptValueV8Wrapper::setData(const ScriptValue& value) {
} }
void ScriptValueV8Wrapper::setProperty(const QString& name, const ScriptValue& value, const ScriptValue::PropertyFlags& flags) { void ScriptValueV8Wrapper::setProperty(const QString& name, const ScriptValue& value, const ScriptValue::PropertyFlags& flags) {
v8::HandleScope handleScope(_engine->getIsolate());
V8ScriptValue unwrapped = fullUnwrap(value); V8ScriptValue unwrapped = fullUnwrap(value);
if(_value.constGet()->IsObject()) { if(_value.constGet()->IsObject()) {
v8::Local<v8::String> key = v8::String::NewFromUtf8(_engine->getIsolate(), name.toStdString().c_str(),v8::NewStringType::kNormal).ToLocalChecked(); v8::Local<v8::String> key = v8::String::NewFromUtf8(_engine->getIsolate(), name.toStdString().c_str(),v8::NewStringType::kNormal).ToLocalChecked();
@ -237,47 +244,65 @@ void ScriptValueV8Wrapper::setPrototype(const ScriptValue& prototype) {
} }
bool ScriptValueV8Wrapper::strictlyEquals(const ScriptValue& other) const { bool ScriptValueV8Wrapper::strictlyEquals(const ScriptValue& other) const {
v8::HandleScope handleScope(_engine->getIsolate());
ScriptValueV8Wrapper* unwrappedOther = unwrap(other); ScriptValueV8Wrapper* unwrappedOther = unwrap(other);
return unwrappedOther ? _value.constGet()->StrictEquals(unwrappedOther->toV8Value().constGet()) : false; return unwrappedOther ? _value.constGet()->StrictEquals(unwrappedOther->toV8Value().constGet()) : false;
} }
bool ScriptValueV8Wrapper::toBool() const { bool ScriptValueV8Wrapper::toBool() const {
v8::HandleScope handleScope(_engine->getIsolate());
return _value.constGet()->ToBoolean(_engine->getIsolate())->Value(); return _value.constGet()->ToBoolean(_engine->getIsolate())->Value();
} }
qint32 ScriptValueV8Wrapper::toInt32() const { qint32 ScriptValueV8Wrapper::toInt32() const {
v8::HandleScope handleScope(_engine->getIsolate());
v8::Local<v8::Integer> *integer; v8::Local<v8::Integer> *integer;
Q_ASSERT(_value.constGet()->ToInteger(_value.constGetContext()).ToLocal(integer)); if (!_value.constGet()->ToInteger(_value.constGetContext()).ToLocal(integer)) {
Q_ASSERT(false);
}
return static_cast<int32_t>((*integer)->Value()); return static_cast<int32_t>((*integer)->Value());
} }
double ScriptValueV8Wrapper::toInteger() const { double ScriptValueV8Wrapper::toInteger() const {
v8::HandleScope handleScope(_engine->getIsolate());
v8::Local<v8::Integer> *integer; v8::Local<v8::Integer> *integer;
Q_ASSERT(_value.constGet()->ToInteger(_value.constGetContext()).ToLocal(integer)); if (!_value.constGet()->ToInteger(_value.constGetContext()).ToLocal(integer)) {
Q_ASSERT(false);
}
return (*integer)->Value(); return (*integer)->Value();
} }
double ScriptValueV8Wrapper::toNumber() const { double ScriptValueV8Wrapper::toNumber() const {
v8::HandleScope handleScope(_engine->getIsolate());
v8::Local<v8::Number> *number; v8::Local<v8::Number> *number;
Q_ASSERT(_value.constGet()->ToNumber(_value.constGetContext()).ToLocal(number)); if (!_value.constGet()->ToNumber(_value.constGetContext()).ToLocal(number)) {
Q_ASSERT(false);
}
return (*number)->Value(); return (*number)->Value();
} }
QString ScriptValueV8Wrapper::toString() const { QString ScriptValueV8Wrapper::toString() const {
v8::HandleScope handleScope(_engine->getIsolate());
v8::String::Utf8Value string(_engine->getIsolate(), _value.constGet()); v8::String::Utf8Value string(_engine->getIsolate(), _value.constGet());
Q_ASSERT(*string != nullptr); Q_ASSERT(*string != nullptr);
return QString(*string); return QString(*string);
} }
quint16 ScriptValueV8Wrapper::toUInt16() const { quint16 ScriptValueV8Wrapper::toUInt16() const {
v8::HandleScope handleScope(_engine->getIsolate());
v8::Local<v8::Uint32> *integer; v8::Local<v8::Uint32> *integer;
Q_ASSERT(_value.constGet()->ToUint32(_value.constGetContext()).ToLocal(integer)); if (!_value.constGet()->ToUint32(_value.constGetContext()).ToLocal(integer)) {
Q_ASSERT(false);
}
return static_cast<uint16_t>((*integer)->Value()); return static_cast<uint16_t>((*integer)->Value());
} }
quint32 ScriptValueV8Wrapper::toUInt32() const { quint32 ScriptValueV8Wrapper::toUInt32() const {
v8::HandleScope handleScope(_engine->getIsolate());
v8::Local<v8::Uint32> *integer; v8::Local<v8::Uint32> *integer;
Q_ASSERT(_value.constGet()->ToUint32(_value.constGetContext()).ToLocal(integer)); if (!_value.constGet()->ToUint32(_value.constGetContext()).ToLocal(integer)) {
Q_ASSERT(false);
}
return (*integer)->Value(); return (*integer)->Value();
} }
@ -302,6 +327,7 @@ QObject* ScriptValueV8Wrapper::toQObject() const {
} }
bool ScriptValueV8Wrapper::equals(const ScriptValue& other) const { bool ScriptValueV8Wrapper::equals(const ScriptValue& other) const {
v8::HandleScope handleScope(_engine->getIsolate());
ScriptValueV8Wrapper* unwrappedOther = unwrap(other); ScriptValueV8Wrapper* unwrappedOther = unwrap(other);
//V8TODO: does this work with different contexts/isolates? //V8TODO: does this work with different contexts/isolates?
// in such case conversion will probably be necessary // in such case conversion will probably be necessary

View file

@ -24,13 +24,23 @@ public:
//V8ScriptValueTemplate(v8::Isolate *isolate, v8::Local<T> value) : _isolate(isolate) { //V8ScriptValueTemplate(v8::Isolate *isolate, v8::Local<T> value) : _isolate(isolate) {
//_value.reset(v8::UniquePersistent<T>::New(_isolate, value)); //_value.reset(v8::UniquePersistent<T>::New(_isolate, value));
//}; //};
V8ScriptValueTemplate(v8::Isolate *isolate, const v8::Local<T> value) : _isolate(isolate), _context(isolate, isolate->GetCurrentContext()) { V8ScriptValueTemplate(v8::Isolate *isolate, const v8::Local<T> value) : _isolate(isolate) {
//_value.reset(_isolate, value); //_value.reset(_isolate, value);
v8::HandleScope handleScope(_isolate);
_context.Reset(isolate, isolate->GetCurrentContext());
_value.reset(new v8::UniquePersistent<T>(_isolate, std::move(value))); _value.reset(new v8::UniquePersistent<T>(_isolate, std::move(value)));
}; };
v8::Local<T> get() {return _value.get()->Get(_isolate);}; v8::Local<T> get() {
const v8::Local<T> constGet() const {return _value.get()->Get(_isolate);}; v8::EscapableHandleScope handleScope(_isolate);
V8ScriptValueTemplate<T>&& copy() const {return new V8ScriptValueTemplate(_isolate, v8::Local<T>::New(_isolate, constGet()));}; return _value.get()->Get(_isolate);
};
const v8::Local<T> constGet() const {
v8::EscapableHandleScope handleScope(_isolate);
return _value.get()->Get(_isolate);
};
V8ScriptValueTemplate<T>&& copy() const {
v8::HandleScope handleScope(_isolate);
return new V8ScriptValueTemplate(_isolate, v8::Local<T>::New(_isolate, constGet()));};
const v8::Local<v8::Context> constGetContext() const { const v8::Local<v8::Context> constGetContext() const {
v8::EscapableHandleScope handleScope(_isolate); v8::EscapableHandleScope handleScope(_isolate);
return handleScope.Escape(_context.Get(_isolate)); return handleScope.Escape(_context.Get(_isolate));