From 2b06c09318b7a2ef36a31809e740df83953a8921 Mon Sep 17 00:00:00 2001 From: ksuprynowicz Date: Sat, 8 Oct 2022 16:30:36 +0200 Subject: [PATCH] Add V8 handle scopes --- .../src/v8/ScriptContextV8Wrapper.cpp | 8 ++++- .../src/v8/ScriptContextV8Wrapper.h | 1 + .../script-engine/src/v8/ScriptEngineV8.cpp | 30 +++++++++++++--- .../script-engine/src/v8/ScriptEngineV8.h | 5 ++- .../src/v8/ScriptEngineV8_cast.cpp | 4 +++ .../src/v8/ScriptObjectV8Proxy.cpp | 25 +++++++++---- .../src/v8/ScriptProgramV8Wrapper.cpp | 21 ++++++----- .../src/v8/ScriptValueIteratorV8Wrapper.cpp | 30 +++++++++------- .../src/v8/ScriptValueV8Wrapper.cpp | 36 ++++++++++++++++--- libraries/script-engine/src/v8/V8Types.h | 18 +++++++--- 10 files changed, 135 insertions(+), 43 deletions(-) diff --git a/libraries/script-engine/src/v8/ScriptContextV8Wrapper.cpp b/libraries/script-engine/src/v8/ScriptContextV8Wrapper.cpp index 67ad87e715..9f1b47c287 100644 --- a/libraries/script-engine/src/v8/ScriptContextV8Wrapper.cpp +++ b/libraries/script-engine/src/v8/ScriptContextV8Wrapper.cpp @@ -33,7 +33,8 @@ ScriptContextV8Wrapper* ScriptContextV8Wrapper::unwrap(ScriptContext* val) { } v8::Local ScriptContextV8Wrapper::toV8Value() const { - return _context.Get(_engine->getIsolate()); + v8::EscapableHandleScope handleScope(_engine->getIsolate()); + return handleScope.Escape(_context.Get(_engine->getIsolate())); } int ScriptContextV8Wrapper::argumentCount() const { @@ -42,6 +43,7 @@ int ScriptContextV8Wrapper::argumentCount() const { } ScriptValue ScriptContextV8Wrapper::argument(int index) const { + v8::HandleScope handleScope(_engine->getIsolate()); Q_ASSERT(_functionCallbackInfo); v8::Local result = (*_functionCallbackInfo)[index]; //V8ScriptValue result = _context->argument(index); @@ -50,6 +52,7 @@ ScriptValue ScriptContextV8Wrapper::argument(int index) const { QStringList ScriptContextV8Wrapper::backtrace() const { auto isolate = _engine->getIsolate(); + v8::HandleScope handleScope(isolate); v8::Local stackTrace = v8::StackTrace::CurrentStackTrace(isolate, 40); QStringList backTrace; //V8TODO nicer formatting @@ -90,17 +93,20 @@ ScriptContextPointer ScriptContextV8Wrapper::parentContext() const { ScriptValue ScriptContextV8Wrapper::thisObject() const { Q_ASSERT(_functionCallbackInfo); + v8::HandleScope handleScope(_engine->getIsolate()); v8::Local result = _functionCallbackInfo->This(); return ScriptValue(new ScriptValueV8Wrapper(_engine, V8ScriptValue(_engine->getIsolate(), result))); return ScriptValue(); } 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())); return ScriptValue(new ScriptValueV8Wrapper(_engine, std::move(result))); } ScriptValue ScriptContextV8Wrapper::throwValue(const ScriptValue& value) { + v8::HandleScope handleScope(_engine->getIsolate()); ScriptValueV8Wrapper* unwrapped = ScriptValueV8Wrapper::unwrap(value); if (!unwrapped) { return _engine->undefinedValue(); diff --git a/libraries/script-engine/src/v8/ScriptContextV8Wrapper.h b/libraries/script-engine/src/v8/ScriptContextV8Wrapper.h index 2f001da10d..3066ec15e1 100644 --- a/libraries/script-engine/src/v8/ScriptContextV8Wrapper.h +++ b/libraries/script-engine/src/v8/ScriptContextV8Wrapper.h @@ -56,6 +56,7 @@ private: // storage class ScriptFunctionContextV8Wrapper final : public ScriptFunctionContext { public: // construction + //V8TODO inline ScriptFunctionContextV8Wrapper(v8::Local context) { } public: // ScriptFunctionContext implementation diff --git a/libraries/script-engine/src/v8/ScriptEngineV8.cpp b/libraries/script-engine/src/v8/ScriptEngineV8.cpp index ca87bc4b11..361b9a8f39 100644 --- a/libraries/script-engine/src/v8/ScriptEngineV8.cpp +++ b/libraries/script-engine/src/v8/ScriptEngineV8.cpp @@ -293,6 +293,7 @@ ScriptValue ScriptEngineV8::newLambdaFunction(std::functiongetIsolate()); v8::Local string; QString qString(""); if (_data.constGet()->ToString(_engine->getContext()).ToLocal(&string)) { @@ -372,6 +373,7 @@ ScriptEngineV8::ScriptEngineV8(ScriptManager* scriptManager) : v8::Isolate::CreateParams isolateParams; isolateParams.array_buffer_allocator = v8::ArrayBuffer::Allocator::NewDefaultAllocator(); _v8Isolate = v8::Isolate::New(isolateParams); + v8::HandleScope handleScope(_v8Isolate); v8::Local context = v8::Context::New(_v8Isolate); _v8Context = v8::UniquePersistent(_v8Isolate, context); @@ -434,7 +436,7 @@ void ScriptEngineV8::registerValue(const QString& valueName, V8ScriptValue value Q_ARG(V8ScriptValue, value)); return; }*/ - + v8::HandleScope handleScope(_v8Isolate); QStringList pathToValue = valueName.split("."); int partsToGo = pathToValue.length(); v8::Local partObject = _v8Context.Get(_v8Isolate)->Global(); @@ -449,15 +451,21 @@ void ScriptEngineV8::registerValue(const QString& valueName, V8ScriptValue value //QObject *object = new QObject; v8::Local partValue = v8::Object::New(_v8Isolate); //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 { //partObject = currentPath->ToObject(); //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 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 qCDebug(scriptengine) << "ScriptEngineV8::registerGlobalObject() called on thread [" << QThread::currentThread() << "] name:" << name; #endif*/ + v8::HandleScope handleScope(_v8Isolate); v8::Local v8GlobalObject = getContext()->Global(); v8::Local 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__)) { return nullValue(); } + v8::HandleScope handleScope(_v8Isolate); ScriptProgramV8Wrapper* unwrappedProgram = ScriptProgramV8Wrapper::unwrap(_program); if (unwrappedProgram == nullptr) { return nullValue(); @@ -699,6 +709,7 @@ ScriptValue ScriptEngineV8::evaluate(const QString& sourceCode, const QString& f }*/ // Compile and check syntax // V8TODO: Could these all be replaced with checkSyntax function from wrapper? + v8::HandleScope handleScope(_v8Isolate); v8::TryCatch tryCatch(getIsolate()); v8::ScriptOrigin scriptOrigin(getIsolate(), v8::String::NewFromUtf8(getIsolate(), fileName.toStdString().c_str()).ToLocalChecked()); v8::Local script; @@ -776,7 +787,7 @@ Q_INVOKABLE ScriptValue ScriptEngineV8::evaluate(const ScriptProgramPointer& pro Q_ARG(const ScriptProgramPointer&, program)); return result; }*/ - + v8::HandleScope handleScope(_v8Isolate); ScriptProgramV8Wrapper* unwrapped = ScriptProgramV8Wrapper::unwrap(program); if (!unwrapped) { auto err = makeError(newValue("could not unwrap program")); @@ -831,6 +842,7 @@ void ScriptEngineV8::updateMemoryCost(const qint64& deltaSize) { // ScriptEngine implementation ScriptValue ScriptEngineV8::globalObject() const { + v8::HandleScope handleScope(_v8Isolate); V8ScriptValue global(_v8Isolate, getConstContext()->Global());// = QScriptEngine::globalObject(); // can't cache the value as it may change return ScriptValue(new ScriptValueV8Wrapper(const_cast(this), std::move(global))); } @@ -845,6 +857,7 @@ ScriptValue ScriptEngineV8::newArray(uint length) { } ScriptValue ScriptEngineV8::newArrayBuffer(const QByteArray& message) { + v8::HandleScope handleScope(_v8Isolate); //V8TODO: this will leak memory std::shared_ptr backingStore(v8::ArrayBuffer::NewBackingStore(_v8Isolate, 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) { + v8::HandleScope handleScope(_v8Isolate); V8ScriptValue result(_v8Isolate, v8::Number::New(_v8Isolate, value)); return ScriptValue(new ScriptValueV8Wrapper(this, std::move(result))); } ScriptValue ScriptEngineV8::newValue(const QString& value) { + v8::HandleScope handleScope(_v8Isolate); v8::Local valueV8 = v8::String::NewFromUtf8(_v8Isolate, value.toStdString().c_str(), v8::NewStringType::kNormal).ToLocalChecked(); V8ScriptValue result(_v8Isolate, valueV8); return ScriptValue(new ScriptValueV8Wrapper(this, std::move(result))); } ScriptValue ScriptEngineV8::newValue(const QLatin1String& value) { + v8::HandleScope handleScope(_v8Isolate); v8::Local valueV8 = v8::String::NewFromUtf8(_v8Isolate, value.latin1(), v8::NewStringType::kNormal).ToLocalChecked(); V8ScriptValue result(_v8Isolate, valueV8); return ScriptValue(new ScriptValueV8Wrapper(this, std::move(result))); } ScriptValue ScriptEngineV8::newValue(const char* value) { + v8::HandleScope handleScope(_v8Isolate); v8::Local valueV8 = v8::String::NewFromUtf8(_v8Isolate, value, v8::NewStringType::kNormal).ToLocalChecked(); V8ScriptValue result(_v8Isolate, valueV8); return ScriptValue(new ScriptValueV8Wrapper(this, std::move(result))); @@ -986,6 +1003,7 @@ ScriptValue ScriptEngineV8::newFunction(ScriptEngine::FunctionSignature fun, int auto v8FunctionCallback = [](const v8::FunctionCallbackInfo& info) { //V8TODO: is using GetCurrentContext ok, or context wrapper needs to be added? + v8::HandleScope handleScope(info.GetIsolate()); auto context = info.GetIsolate()->GetCurrentContext(); auto function = reinterpret_cast (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::Local(), length); //auto functionData = v8::Object::New(_v8Isolate); //functionData->setIn + v8::HandleScope handleScope(_v8Isolate); auto functionDataTemplate = v8::ObjectTemplate::New(_v8Isolate); functionDataTemplate->SetInternalFieldCount(3); auto functionData = functionDataTemplate->NewInstance(getContext()).ToLocalChecked(); @@ -1024,6 +1043,7 @@ void ScriptEngineV8::setObjectName(const QString& name) { //V8TODO bool ScriptEngineV8::setProperty(const char* name, const QVariant& value) { + v8::HandleScope handleScope(_v8Isolate); v8::Local global = getContext()->Global(); auto v8Name = v8::String::NewFromUtf8(getIsolate(), name).ToLocalChecked(); V8ScriptValue v8Value = castVariantToValue(value); diff --git a/libraries/script-engine/src/v8/ScriptEngineV8.h b/libraries/script-engine/src/v8/ScriptEngineV8.h index 675d1380a3..19c2a9c5c0 100644 --- a/libraries/script-engine/src/v8/ScriptEngineV8.h +++ b/libraries/script-engine/src/v8/ScriptEngineV8.h @@ -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); return handleScope.Escape(_v8Context.Get(_v8Isolate)); } - const v8::Local getConstContext() const {return _v8Context.Get(_v8Isolate);} + const v8::Local getConstContext() const { + v8::EscapableHandleScope handleScope(_v8Isolate); + return handleScope.Escape(_v8Context.Get(_v8Isolate)); + } using ObjectWrapperMap = QMap>; mutable QMutex _qobjectWrapperMapProtect; diff --git a/libraries/script-engine/src/v8/ScriptEngineV8_cast.cpp b/libraries/script-engine/src/v8/ScriptEngineV8_cast.cpp index 3e95f5a495..bf1ecf1aa7 100644 --- a/libraries/script-engine/src/v8/ScriptEngineV8_cast.cpp +++ b/libraries/script-engine/src/v8/ScriptEngineV8_cast.cpp @@ -198,6 +198,7 @@ void ScriptEngineV8::registerSystemTypes() { } int ScriptEngineV8::computeCastPenalty(const V8ScriptValue& v8Val, int destTypeId) { + v8::HandleScope handleScope(_v8Isolate); const v8::Local val = v8Val.constGet(); if (val->IsNumber()) { switch (destTypeId){ @@ -291,6 +292,7 @@ int ScriptEngineV8::computeCastPenalty(const V8ScriptValue& v8Val, int destTypeI } bool ScriptEngineV8::castValueToVariant(const V8ScriptValue& v8Val, QVariant& dest, int destTypeId) { + v8::HandleScope handleScope(_v8Isolate); const v8::Local val = v8Val.constGet(); // 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) { + // V8TODO + v8::HandleScope handleScope(const_cast(v8Val.constGetIsolate())); const v8::Local val = v8Val.constGet(); if (val->IsUndefined()) { diff --git a/libraries/script-engine/src/v8/ScriptObjectV8Proxy.cpp b/libraries/script-engine/src/v8/ScriptObjectV8Proxy.cpp index 232a372708..04ad70ea15 100644 --- a/libraries/script-engine/src/v8/ScriptObjectV8Proxy.cpp +++ b/libraries/script-engine/src/v8/ScriptObjectV8Proxy.cpp @@ -133,6 +133,8 @@ V8ScriptValue ScriptObjectV8Proxy::newQObject(ScriptEngineV8* engine, QObject* o } 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(val.constGetIsolate())); auto v8Value = val.constGet(); if (!v8Value->IsObject()) { return nullptr; @@ -164,6 +166,8 @@ void ScriptObjectV8Proxy::investigate() { Q_ASSERT(qobject); if (!qobject) return; + v8::HandleScope handleScope(_engine->getIsolate()); + auto objectTemplate = _v8ObjectTemplate.Get(_engine->getIsolate()); objectTemplate->SetInternalFieldCount(3); objectTemplate->SetHandler(v8::NamedPropertyHandlerConfiguration(v8Get, v8Set)); @@ -464,6 +468,8 @@ V8ScriptValue ScriptVariantV8Proxy::newVariant(ScriptEngineV8* engine, const QVa } ScriptVariantV8Proxy* ScriptVariantV8Proxy::unwrapProxy(const V8ScriptValue& val) { + // V8TODO + v8::HandleScope handleScope(const_cast(val.constGetIsolate())); auto v8Value = val.constGet(); if (!v8Value->IsObject()) { return nullptr; @@ -550,6 +556,8 @@ void ScriptMethodV8Proxy::call(const v8::FunctionCallbackInfo& argume isolate->ThrowError("Referencing deleted native object"); return; } + + v8::HandleScope handleScope(_engine->getIsolate()); int scriptNumArgs = arguments.Length(); 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) { return id; } + + v8::HandleScope handleScope(_engine->getIsolate()); //V8ScriptValueList args(isolate, v8::Null(isolate)); v8::Local args[Q_METAMETHOD_INVOKE_MAX_ARGS]; @@ -952,12 +962,14 @@ ScriptSignalV8Proxy::ConnectionList::iterator ScriptSignalV8Proxy::findConnectio void ScriptSignalV8Proxy::connect(V8ScriptValue arg0, V8ScriptValue arg1) { QObject* qobject = _object; + v8::Isolate *isolate = _engine->getIsolate(); if (!qobject) { - _engine->getIsolate()->ThrowError("Referencing deleted native object"); + isolate->ThrowError("Referencing deleted native object"); return; } + + v8::HandleScope handleScope(isolate); - v8::Isolate *isolate = _engine->getIsolate(); // untangle the arguments V8ScriptValue callback(isolate, v8::Null(isolate)); V8ScriptValue callbackThis(isolate, v8::Null(isolate)); @@ -968,7 +980,7 @@ void ScriptSignalV8Proxy::connect(V8ScriptValue arg0, V8ScriptValue arg1) { callback = arg0; } if (!callback.get()->IsFunction()) { - _engine->getIsolate()->ThrowError("Function expected as argument to 'connect'"); + isolate->ThrowError("Function expected as argument to 'connect'"); return; } @@ -1030,11 +1042,12 @@ void ScriptSignalV8Proxy::connect(V8ScriptValue arg0, V8ScriptValue arg1) { void ScriptSignalV8Proxy::disconnect(V8ScriptValue arg0, V8ScriptValue arg1) { QObject* qobject = _object; + v8::Isolate *isolate = _engine->getIsolate(); if (!qobject) { - _engine->getIsolate()->ThrowError("Referencing deleted native object"); + isolate->ThrowError("Referencing deleted native object"); return; } - v8::Isolate *isolate = _engine->getIsolate(); + v8::HandleScope handleScope(isolate); // untangle the arguments V8ScriptValue callback(isolate, v8::Null(isolate)); @@ -1046,7 +1059,7 @@ void ScriptSignalV8Proxy::disconnect(V8ScriptValue arg0, V8ScriptValue arg1) { callback = arg0; } if (!callback.get()->IsFunction()) { - _engine->getIsolate()->ThrowError("Function expected as argument to 'disconnect'"); + isolate->ThrowError("Function expected as argument to 'disconnect'"); return; } diff --git a/libraries/script-engine/src/v8/ScriptProgramV8Wrapper.cpp b/libraries/script-engine/src/v8/ScriptProgramV8Wrapper.cpp index edf7f033e2..6ec8165b6a 100644 --- a/libraries/script-engine/src/v8/ScriptProgramV8Wrapper.cpp +++ b/libraries/script-engine/src/v8/ScriptProgramV8Wrapper.cpp @@ -32,29 +32,32 @@ ScriptSyntaxCheckResultPointer ScriptProgramV8Wrapper::checkSyntax() { } bool ScriptProgramV8Wrapper::compile() { + auto isolate = _engine->getIsolate(); + v8::HandleScope handleScope(isolate); + auto context = _engine->getContext(); int errorColumnNumber = 0; int errorLineNumber = 0; QString errorMessage = ""; QString errorBacktrace = ""; ScriptSyntaxCheckResult::State state; - v8::TryCatch tryCatch(_engine->getIsolate()); - v8::ScriptOrigin scriptOrigin(_engine->getIsolate(), v8::String::NewFromUtf8(_engine->getIsolate(), _url.toStdString().c_str()).ToLocalChecked()); + v8::TryCatch tryCatch(isolate); + v8::ScriptOrigin scriptOrigin(isolate, v8::String::NewFromUtf8(isolate, _url.toStdString().c_str()).ToLocalChecked()); v8::Local 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); - _value = V8ScriptProgram(_engine->getIsolate(), script); + _value = V8ScriptProgram(isolate, script); return true; } - v8::String::Utf8Value utf8Value(_engine->getIsolate(), tryCatch.Exception()); + v8::String::Utf8Value utf8Value(isolate, tryCatch.Exception()); errorMessage = QString(*utf8Value); v8::Local exceptionMessage = tryCatch.Message(); if (!exceptionMessage.IsEmpty()) { - errorLineNumber = exceptionMessage->GetLineNumber(_engine->getContext()).FromJust(); - errorColumnNumber = exceptionMessage->GetStartColumn(_engine->getContext()).FromJust(); + errorLineNumber = exceptionMessage->GetLineNumber(context).FromJust(); + errorColumnNumber = exceptionMessage->GetStartColumn(context).FromJust(); v8::Local backtraceV8String; - if (tryCatch.StackTrace(_engine->getContext()).ToLocal(&backtraceV8String) && backtraceV8String->IsString() && + if (tryCatch.StackTrace(context).ToLocal(&backtraceV8String) && backtraceV8String->IsString() && v8::Local::Cast(backtraceV8String)->Length() > 0) { - v8::String::Utf8Value backtraceUtf8Value(_engine->getIsolate(), backtraceV8String); + v8::String::Utf8Value backtraceUtf8Value(isolate, backtraceV8String); errorBacktrace = *backtraceUtf8Value; } } diff --git a/libraries/script-engine/src/v8/ScriptValueIteratorV8Wrapper.cpp b/libraries/script-engine/src/v8/ScriptValueIteratorV8Wrapper.cpp index 317a5734eb..5120503ef4 100644 --- a/libraries/script-engine/src/v8/ScriptValueIteratorV8Wrapper.cpp +++ b/libraries/script-engine/src/v8/ScriptValueIteratorV8Wrapper.cpp @@ -14,15 +14,17 @@ #include "ScriptValueIteratorV8Wrapper.h" V8ScriptValueIterator::V8ScriptValueIterator(ScriptEngineV8* engine, v8::Local object) : _engine(engine) { - _context.Reset(_engine->getIsolate(), _engine->getContext()); - auto context = _context.Get(_engine->getIsolate()); + auto isolate = _engine->getIsolate(); + v8::HandleScope handleScope(isolate); + _context.Reset(isolate, _engine->getContext()); + auto context = _context.Get(isolate); v8::Local v8Object; if (!object->ToObject(context).ToLocal(&v8Object)) { Q_ASSERT(false); } - _object.Reset(_engine->getIsolate(), v8Object); - _propertyNames.Reset(_engine->getIsolate(), v8Object->GetOwnPropertyNames(context).ToLocalChecked()); - _length = _propertyNames.Get(_engine->getIsolate())->Length(); + _object.Reset(isolate, v8Object); + _propertyNames.Reset(isolate, v8Object->GetOwnPropertyNames(context).ToLocalChecked()); + _length = _propertyNames.Get(isolate)->Length(); _currentIndex = 0; } @@ -31,12 +33,14 @@ bool V8ScriptValueIterator::hasNext() 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 propertyName; - if (!_propertyNames.Get(_engine->getIsolate())->Get(context, _length).ToLocal(&propertyName)) { + if (!_propertyNames.Get(isolate)->Get(context, _length).ToLocal(&propertyName)) { Q_ASSERT(false); } - return QString(*v8::String::Utf8Value(_engine->getIsolate(), propertyName)); + return QString(*v8::String::Utf8Value(isolate, propertyName)); } void V8ScriptValueIterator::next() { @@ -46,16 +50,18 @@ void V8ScriptValueIterator::next() { } V8ScriptValue V8ScriptValueIterator::value() { - auto context = _context.Get(_engine->getIsolate()); + auto isolate = _engine->getIsolate(); + v8::HandleScope handleScope(isolate); + auto context = _context.Get(isolate); v8::Local v8Value; v8::Local propertyName; - if (!_propertyNames.Get(_engine->getIsolate())->Get(context, _length).ToLocal(&propertyName)) { + if (!_propertyNames.Get(isolate)->Get(context, _length).ToLocal(&propertyName)) { 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); } - return V8ScriptValue(_engine->getIsolate(), v8Value); + return V8ScriptValue(isolate, v8Value); } ScriptValue::PropertyFlags ScriptValueIteratorV8Wrapper::flags() const { diff --git a/libraries/script-engine/src/v8/ScriptValueV8Wrapper.cpp b/libraries/script-engine/src/v8/ScriptValueV8Wrapper.cpp index 397b16ea2e..42878abd1f 100644 --- a/libraries/script-engine/src/v8/ScriptValueV8Wrapper.cpp +++ b/libraries/script-engine/src/v8/ScriptValueV8Wrapper.cpp @@ -60,6 +60,7 @@ V8ScriptValue ScriptValueV8Wrapper::fullUnwrap(ScriptEngineV8* engine, const Scr } ScriptValue ScriptValueV8Wrapper::call(const ScriptValue& thisObject, const ScriptValueList& args) { + v8::HandleScope handleScope(_engine->getIsolate()); V8ScriptValue v8This = fullUnwrap(thisObject); //V8ScriptValueList qArgs; 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) { + v8::HandleScope handleScope(_engine->getIsolate()); V8ScriptValue v8This = fullUnwrap(thisObject); V8ScriptValue v8Args = fullUnwrap(arguments); // 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) { + v8::HandleScope handleScope(_engine->getIsolate()); 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 v8::Local v8Args[Q_METAMETHOD_INVOKE_MAX_ARGS]; @@ -126,6 +129,7 @@ ScriptValue ScriptValueV8Wrapper::construct(const ScriptValueList& args) { } 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 Q_ASSERT(false); return _engine->undefinedValue(); @@ -153,6 +157,7 @@ ScriptValueIteratorPointer ScriptValueV8Wrapper::newIterator() const { } ScriptValue ScriptValueV8Wrapper::property(const QString& name, const ScriptValue::ResolveFlags& mode) const { + v8::HandleScope handleScope(_engine->getIsolate()); if (!_value.constGet()->IsObject()) { //V8TODO: what about flags? v8::Local resultLocal; @@ -171,6 +176,7 @@ ScriptValue ScriptValueV8Wrapper::property(const QString& name, const ScriptValu } ScriptValue ScriptValueV8Wrapper::property(quint32 arrayIndex, const ScriptValue::ResolveFlags& mode) const { + v8::HandleScope handleScope(_engine->getIsolate()); if (!_value.constGet()->IsObject()) { //V8TODO: what about flags? v8::Local resultLocal; @@ -191,6 +197,7 @@ void ScriptValueV8Wrapper::setData(const ScriptValue& value) { } void ScriptValueV8Wrapper::setProperty(const QString& name, const ScriptValue& value, const ScriptValue::PropertyFlags& flags) { + v8::HandleScope handleScope(_engine->getIsolate()); V8ScriptValue unwrapped = fullUnwrap(value); if(_value.constGet()->IsObject()) { v8::Local 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 { + v8::HandleScope handleScope(_engine->getIsolate()); ScriptValueV8Wrapper* unwrappedOther = unwrap(other); return unwrappedOther ? _value.constGet()->StrictEquals(unwrappedOther->toV8Value().constGet()) : false; } bool ScriptValueV8Wrapper::toBool() const { + v8::HandleScope handleScope(_engine->getIsolate()); return _value.constGet()->ToBoolean(_engine->getIsolate())->Value(); } qint32 ScriptValueV8Wrapper::toInt32() const { + v8::HandleScope handleScope(_engine->getIsolate()); v8::Local *integer; - Q_ASSERT(_value.constGet()->ToInteger(_value.constGetContext()).ToLocal(integer)); + if (!_value.constGet()->ToInteger(_value.constGetContext()).ToLocal(integer)) { + Q_ASSERT(false); + } return static_cast((*integer)->Value()); } double ScriptValueV8Wrapper::toInteger() const { + v8::HandleScope handleScope(_engine->getIsolate()); v8::Local *integer; - Q_ASSERT(_value.constGet()->ToInteger(_value.constGetContext()).ToLocal(integer)); + if (!_value.constGet()->ToInteger(_value.constGetContext()).ToLocal(integer)) { + Q_ASSERT(false); + } return (*integer)->Value(); } double ScriptValueV8Wrapper::toNumber() const { + v8::HandleScope handleScope(_engine->getIsolate()); v8::Local *number; - Q_ASSERT(_value.constGet()->ToNumber(_value.constGetContext()).ToLocal(number)); + if (!_value.constGet()->ToNumber(_value.constGetContext()).ToLocal(number)) { + Q_ASSERT(false); + } return (*number)->Value(); } QString ScriptValueV8Wrapper::toString() const { + v8::HandleScope handleScope(_engine->getIsolate()); v8::String::Utf8Value string(_engine->getIsolate(), _value.constGet()); Q_ASSERT(*string != nullptr); return QString(*string); } quint16 ScriptValueV8Wrapper::toUInt16() const { + v8::HandleScope handleScope(_engine->getIsolate()); v8::Local *integer; - Q_ASSERT(_value.constGet()->ToUint32(_value.constGetContext()).ToLocal(integer)); + if (!_value.constGet()->ToUint32(_value.constGetContext()).ToLocal(integer)) { + Q_ASSERT(false); + } return static_cast((*integer)->Value()); } quint32 ScriptValueV8Wrapper::toUInt32() const { + v8::HandleScope handleScope(_engine->getIsolate()); v8::Local *integer; - Q_ASSERT(_value.constGet()->ToUint32(_value.constGetContext()).ToLocal(integer)); + if (!_value.constGet()->ToUint32(_value.constGetContext()).ToLocal(integer)) { + Q_ASSERT(false); + } return (*integer)->Value(); } @@ -302,6 +327,7 @@ QObject* ScriptValueV8Wrapper::toQObject() const { } bool ScriptValueV8Wrapper::equals(const ScriptValue& other) const { + v8::HandleScope handleScope(_engine->getIsolate()); ScriptValueV8Wrapper* unwrappedOther = unwrap(other); //V8TODO: does this work with different contexts/isolates? // in such case conversion will probably be necessary diff --git a/libraries/script-engine/src/v8/V8Types.h b/libraries/script-engine/src/v8/V8Types.h index 92582b3df7..fac4d18f2e 100644 --- a/libraries/script-engine/src/v8/V8Types.h +++ b/libraries/script-engine/src/v8/V8Types.h @@ -24,13 +24,23 @@ public: //V8ScriptValueTemplate(v8::Isolate *isolate, v8::Local value) : _isolate(isolate) { //_value.reset(v8::UniquePersistent::New(_isolate, value)); //}; - V8ScriptValueTemplate(v8::Isolate *isolate, const v8::Local value) : _isolate(isolate), _context(isolate, isolate->GetCurrentContext()) { + V8ScriptValueTemplate(v8::Isolate *isolate, const v8::Local value) : _isolate(isolate) { //_value.reset(_isolate, value); + v8::HandleScope handleScope(_isolate); + _context.Reset(isolate, isolate->GetCurrentContext()); _value.reset(new v8::UniquePersistent(_isolate, std::move(value))); }; - v8::Local get() {return _value.get()->Get(_isolate);}; - const v8::Local constGet() const {return _value.get()->Get(_isolate);}; - V8ScriptValueTemplate&& copy() const {return new V8ScriptValueTemplate(_isolate, v8::Local::New(_isolate, constGet()));}; + v8::Local get() { + v8::EscapableHandleScope handleScope(_isolate); + return _value.get()->Get(_isolate); + }; + const v8::Local constGet() const { + v8::EscapableHandleScope handleScope(_isolate); + return _value.get()->Get(_isolate); + }; + V8ScriptValueTemplate&& copy() const { + v8::HandleScope handleScope(_isolate); + return new V8ScriptValueTemplate(_isolate, v8::Local::New(_isolate, constGet()));}; const v8::Local constGetContext() const { v8::EscapableHandleScope handleScope(_isolate); return handleScope.Escape(_context.Get(_isolate));