From c4047cb7037ace18b8d6d379c6d7805f836696ec Mon Sep 17 00:00:00 2001 From: ksuprynowicz Date: Sat, 8 Oct 2022 20:05:49 +0200 Subject: [PATCH] Added context scopes --- interface/src/Application.cpp | 5 +- libraries/script-engine/src/ScriptEngine.h | 1 + libraries/script-engine/src/ScriptManager.cpp | 4 +- .../src/v8/ScriptContextV8Wrapper.cpp | 34 +++- .../script-engine/src/v8/ScriptEngineV8.cpp | 151 +++++++++++----- .../script-engine/src/v8/ScriptEngineV8.h | 4 +- .../src/v8/ScriptObjectV8Proxy.cpp | 11 +- .../src/v8/ScriptValueIteratorV8Wrapper.cpp | 6 +- .../src/v8/ScriptValueV8Wrapper.cpp | 170 ++++++++++++++---- libraries/script-engine/src/v8/V8Types.h | 9 +- 10 files changed, 300 insertions(+), 95 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index ca0a7fb6b9..435d6b57f1 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -7506,8 +7506,9 @@ void Application::registerScriptEngineWithApplicationServices(const ScriptManage scriptEngine->registerGetterSetter("location", LocationScriptingInterface::locationGetter, LocationScriptingInterface::locationSetter, "Window"); // register `location` on the global object. - scriptEngine->registerGetterSetter("location", LocationScriptingInterface::locationGetter, - LocationScriptingInterface::locationSetter); + //V8TODO causes a crash + //scriptEngine->registerGetterSetter("location", LocationScriptingInterface::locationGetter, + // LocationScriptingInterface::locationSetter); scriptEngine->registerFunction("OverlayWindow", clientScript ? QmlWindowClass::constructor : QmlWindowClass::restricted_constructor); #if !defined(Q_OS_ANDROID) && !defined(DISABLE_QML) diff --git a/libraries/script-engine/src/ScriptEngine.h b/libraries/script-engine/src/ScriptEngine.h index c2628f9317..a668cb262e 100644 --- a/libraries/script-engine/src/ScriptEngine.h +++ b/libraries/script-engine/src/ScriptEngine.h @@ -119,6 +119,7 @@ public: virtual void setProcessEventsInterval(int interval) = 0; virtual QThread* thread() const = 0; virtual void setThread(QThread* thread) = 0; + Q_INVOKABLE virtual void enterIsolateOnThisThread() = 0; virtual ScriptValue undefinedValue() = 0; virtual ScriptValue uncaughtException() const = 0; virtual QStringList uncaughtExceptionBacktrace() const = 0; diff --git a/libraries/script-engine/src/ScriptManager.cpp b/libraries/script-engine/src/ScriptManager.cpp index c19b942075..c0a335b653 100644 --- a/libraries/script-engine/src/ScriptManager.cpp +++ b/libraries/script-engine/src/ScriptManager.cpp @@ -825,7 +825,9 @@ void ScriptManager::run() { // (because we're a client script) hifi::scripting::setLocalAccessSafeThread(true); } - + + _engine->enterIsolateOnThisThread(); + auto filenameParts = _fileNameString.split("/"); auto name = filenameParts.size() > 0 ? filenameParts[filenameParts.size() - 1] : "unknown"; PROFILE_SET_THREAD_NAME("Script: " + name); diff --git a/libraries/script-engine/src/v8/ScriptContextV8Wrapper.cpp b/libraries/script-engine/src/v8/ScriptContextV8Wrapper.cpp index 9f1b47c287..d983dacd70 100644 --- a/libraries/script-engine/src/v8/ScriptContextV8Wrapper.cpp +++ b/libraries/script-engine/src/v8/ScriptContextV8Wrapper.cpp @@ -38,12 +38,23 @@ v8::Local ScriptContextV8Wrapper::toV8Value() const { } int ScriptContextV8Wrapper::argumentCount() const { - Q_ASSERT(_functionCallbackInfo); - return _functionCallbackInfo->Length(); + /*auto isolate = _engine->getIsolate(); + Q_ASSERT(isolate->IsCurrent()); + v8::HandleScope handleScope(isolate); + v8::Context::Scope contextScope(_engine->getContext());*/ + //Q_ASSERT(_functionCallbackInfo);A + // V8TODO + return Q_METAMETHOD_INVOKE_MAX_ARGS; + // This was wrong, in function registration it seems to be used as maximum number od arguments instead? + // Is it also used for something else? + //return _functionCallbackInfo->Length(); } ScriptValue ScriptContextV8Wrapper::argument(int index) const { - v8::HandleScope handleScope(_engine->getIsolate()); + auto isolate = _engine->getIsolate(); + Q_ASSERT(isolate->IsCurrent()); + v8::HandleScope handleScope(isolate); + v8::Context::Scope contextScope(_engine->getContext()); Q_ASSERT(_functionCallbackInfo); v8::Local result = (*_functionCallbackInfo)[index]; //V8ScriptValue result = _context->argument(index); @@ -52,7 +63,9 @@ ScriptValue ScriptContextV8Wrapper::argument(int index) const { QStringList ScriptContextV8Wrapper::backtrace() const { auto isolate = _engine->getIsolate(); + Q_ASSERT(isolate->IsCurrent()); v8::HandleScope handleScope(isolate); + v8::Context::Scope contextScope(_engine->getContext()); v8::Local stackTrace = v8::StackTrace::CurrentStackTrace(isolate, 40); QStringList backTrace; //V8TODO nicer formatting @@ -93,20 +106,29 @@ ScriptContextPointer ScriptContextV8Wrapper::parentContext() const { ScriptValue ScriptContextV8Wrapper::thisObject() const { Q_ASSERT(_functionCallbackInfo); - v8::HandleScope handleScope(_engine->getIsolate()); + auto isolate = _engine->getIsolate(); + Q_ASSERT(isolate->IsCurrent()); + v8::HandleScope handleScope(isolate); + v8::Context::Scope contextScope(_engine->getContext()); 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()); + auto isolate = _engine->getIsolate(); + Q_ASSERT(isolate->IsCurrent()); + v8::HandleScope handleScope(isolate); + v8::Context::Scope contextScope(_engine->getContext()); 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()); + auto isolate = _engine->getIsolate(); + Q_ASSERT(isolate->IsCurrent()); + v8::HandleScope handleScope(isolate); + v8::Context::Scope contextScope(_engine->getContext()); ScriptValueV8Wrapper* unwrapped = ScriptValueV8Wrapper::unwrap(value); if (!unwrapped) { return _engine->undefinedValue(); diff --git a/libraries/script-engine/src/v8/ScriptEngineV8.cpp b/libraries/script-engine/src/v8/ScriptEngineV8.cpp index 361b9a8f39..dcb2f9a26e 100644 --- a/libraries/script-engine/src/v8/ScriptEngineV8.cpp +++ b/libraries/script-engine/src/v8/ScriptEngineV8.cpp @@ -113,6 +113,8 @@ ScriptValue ScriptEngineV8::makeError(const ScriptValue& _other, const QString& if (!IS_THREADSAFE_INVOCATION(thread(), __FUNCTION__)) { return nullValue(); } + v8::HandleScope handleScope(_v8Isolate); + v8::Context::Scope contextScope(_v8Context.Get(_v8Isolate)); return nullValue(); //V8TODO @@ -136,6 +138,8 @@ ScriptValue ScriptEngineV8::cheskScriptSyntax(ScriptProgramPointer program) { if (!IS_THREADSAFE_INVOCATION(thread(), __FUNCTION__)) { return nullValue(); } + v8::HandleScope handleScope(_v8Isolate); + v8::Context::Scope contextScope(_v8Context.Get(_v8Isolate)); ScriptSyntaxCheckResultPointer syntaxCheck = program->checkSyntax(); //V8TODO if (syntaxCheck->state() != ScriptSyntaxCheckResult::Valid) { @@ -190,6 +194,8 @@ ScriptValue ScriptEngineV8::cloneUncaughtException(const QString& extraDetail) { if (!hasUncaughtException()) { return nullValue(); } + v8::HandleScope handleScope(_v8Isolate); + v8::Context::Scope contextScope(_v8Context.Get(_v8Isolate)); return nullValue(); //V8TODO /* @@ -284,6 +290,8 @@ bool ScriptEngineV8::maybeEmitUncaughtException(const QString& debugHint) { ScriptValue ScriptEngineV8::newLambdaFunction(std::function operation, const V8ScriptValue& data, const ValueOwnership& ownership) { + v8::HandleScope handleScope(_v8Isolate); + v8::Context::Scope contextScope(_v8Context.Get(_v8Isolate)); auto lambda = new Lambda(this, operation, data); auto object = newQObject(lambda, ownership); //V8TODO? @@ -294,6 +302,7 @@ ScriptValue ScriptEngineV8::newLambdaFunction(std::functiongetIsolate()); + v8::Context::Scope contextScope(_engine->getContext()); v8::Local string; QString qString(""); if (_data.constGet()->ToString(_engine->getContext()).ToLocal(&string)) { @@ -373,30 +382,14 @@ ScriptEngineV8::ScriptEngineV8(ScriptManager* scriptManager) : v8::Isolate::CreateParams isolateParams; isolateParams.array_buffer_allocator = v8::ArrayBuffer::Allocator::NewDefaultAllocator(); _v8Isolate = v8::Isolate::New(isolateParams); + _v8Isolate->Enter(); v8::HandleScope handleScope(_v8Isolate); v8::Local context = v8::Context::New(_v8Isolate); + Q_ASSERT(!context.IsEmpty()); _v8Context = v8::UniquePersistent(_v8Isolate, context); registerSystemTypes(); - _currentThread = QThread::currentThread(); - // V8TODO: port to V8 - /* - if (_scriptManager) { - connect(this, &QScriptEngine::signalHandlerException, this, [this](const V8ScriptValue& exception) { - if (hasUncaughtException()) { - // the engine's uncaughtException() seems to produce much better stack traces here - emit _scriptManager->unhandledException(cloneUncaughtException("signalHandlerException")); - clearExceptions(); - } else { - // ... but may not always be available -- so if needed we fallback to the passed exception - V8ScriptValue thrown = makeError(exception); - emit _scriptManager->unhandledException(ScriptValue(new ScriptValueV8Wrapper(this, std::move(thrown)))); - } - }, Qt::DirectConnection); - moveToThread(scriptManager->thread()); - }*/ - // V8TODO: dispose of isolate on ScriptEngineV8 destruction //v8::UniquePersistent null = v8::UniquePersistent(_v8Isolate, v8::Null(_v8Isolate)); //_nullValue = ScriptValue(new ScriptValueV8Wrapper(this, std::move(null))); @@ -410,6 +403,25 @@ ScriptEngineV8::ScriptEngineV8(ScriptManager* scriptManager) : // V8TODO: //QScriptEngine::setProcessEventsInterval(MSECS_PER_SECOND); + + //_currentThread = QThread::currentThread(); + + if (_scriptManager) { + // V8TODO: port to V8 + /*connect(this, &QScriptEngine::signalHandlerException, this, [this](const V8ScriptValue& exception) { + if (hasUncaughtException()) { + // the engine's uncaughtException() seems to produce much better stack traces here + emit _scriptManager->unhandledException(cloneUncaughtException("signalHandlerException")); + clearExceptions(); + } else { + // ... but may not always be available -- so if needed we fallback to the passed exception + V8ScriptValue thrown = makeError(exception); + emit _scriptManager->unhandledException(ScriptValue(new ScriptValueV8Wrapper(this, std::move(thrown)))); + } + }, Qt::DirectConnection);*/ + //moveToThread(scriptManager->thread()); + setThread(scriptManager->thread()); + } } void ScriptEngineV8::registerEnum(const QString& enumName, QMetaEnum newEnum) { @@ -417,6 +429,8 @@ void ScriptEngineV8::registerEnum(const QString& enumName, QMetaEnum newEnum) { qCCritical(scriptengine) << "registerEnum called on invalid enum with name " << enumName; return; } + v8::HandleScope handleScope(_v8Isolate); + v8::Context::Scope contextScope(_v8Context.Get(_v8Isolate)); for (int i = 0; i < newEnum.keyCount(); i++) { const char* keyName = newEnum.key(i); @@ -426,8 +440,7 @@ void ScriptEngineV8::registerEnum(const QString& enumName, QMetaEnum newEnum) { } void ScriptEngineV8::registerValue(const QString& valueName, V8ScriptValue value) { - //V8TODO - /*if (QThread::currentThread() != QScriptEngine::thread()) { + if (QThread::currentThread() != thread()) { #ifdef THREAD_DEBUGGING qCDebug(scriptengine) << "*** WARNING *** ScriptEngineV8::registerValue() called on wrong thread [" << QThread::currentThread() << "], invoking on correct thread [" << thread() << "]"; #endif @@ -435,8 +448,9 @@ void ScriptEngineV8::registerValue(const QString& valueName, V8ScriptValue value Q_ARG(const QString&, valueName), Q_ARG(V8ScriptValue, value)); return; - }*/ + } v8::HandleScope handleScope(_v8Isolate); + v8::Context::Scope contextScope(_v8Context.Get(_v8Isolate)); QStringList pathToValue = valueName.split("."); int partsToGo = pathToValue.length(); v8::Local partObject = _v8Context.Get(_v8Isolate)->Global(); @@ -470,8 +484,7 @@ void ScriptEngineV8::registerValue(const QString& valueName, V8ScriptValue value } void ScriptEngineV8::registerGlobalObject(const QString& name, QObject* object) { - //V8TODO - /*if (QThread::currentThread() != QScriptEngine::thread()) { + if (QThread::currentThread() != thread()) { #ifdef THREAD_DEBUGGING qCDebug(scriptengine) << "*** WARNING *** ScriptEngineV8::registerGlobalObject() called on wrong thread [" << QThread::currentThread() << "], invoking on correct thread [" << thread() << "] name:" << name; #endif @@ -482,8 +495,10 @@ void ScriptEngineV8::registerGlobalObject(const QString& name, QObject* object) } #ifdef THREAD_DEBUGGING qCDebug(scriptengine) << "ScriptEngineV8::registerGlobalObject() called on thread [" << QThread::currentThread() << "] name:" << name; -#endif*/ +#endif v8::HandleScope handleScope(_v8Isolate); + Q_ASSERT(_v8Isolate->IsCurrent()); + v8::Context::Scope contextScope(_v8Context.Get(_v8Isolate)); v8::Local v8GlobalObject = getContext()->Global(); v8::Local v8Name = v8::String::NewFromUtf8(_v8Isolate, name.toStdString().c_str()).ToLocalChecked(); @@ -499,22 +514,23 @@ void ScriptEngineV8::registerGlobalObject(const QString& name, QObject* object) } void ScriptEngineV8::registerFunction(const QString& name, ScriptEngine::FunctionSignature functionSignature, int numArguments) { - //V8TODO - /*if (QThread::currentThread() != QScriptEngine::thread()) { + if (QThread::currentThread() != thread()) { #ifdef THREAD_DEBUGGING qCDebug(scriptengine) << "*** WARNING *** ScriptEngineV8::registerFunction() called on wrong thread [" << QThread::currentThread() << "], invoking on correct thread [" << thread() << "] name:" << name; #endif QMetaObject::invokeMethod(this, "registerFunction", Q_ARG(const QString&, name), - Q_ARG(QScriptEngine::FunctionSignature, functionSignature), + Q_ARG(ScriptEngine::FunctionSignature, functionSignature), Q_ARG(int, numArguments)); return; } #ifdef THREAD_DEBUGGING qCDebug(scriptengine) << "ScriptEngineV8::registerFunction() called on thread [" << QThread::currentThread() << "] name:" << name; -#endif*/ +#endif //auto scriptFun = static_cast(newFunction(functionSignature, numArguments).ptr())->toV8Value().constGet(); + v8::HandleScope handleScope(_v8Isolate); + v8::Context::Scope contextScope(_v8Context.Get(_v8Isolate)); auto scriptFun = newFunction(functionSignature, numArguments); //getContext()->Global().Set(); @@ -522,21 +538,22 @@ void ScriptEngineV8::registerFunction(const QString& name, ScriptEngine::Functio } void ScriptEngineV8::registerFunction(const QString& parent, const QString& name, ScriptEngine::FunctionSignature functionSignature, int numArguments) { - //V8TODO - /*if (QThread::currentThread() != QScriptEngine::thread()) { + if (QThread::currentThread() != thread()) { #ifdef THREAD_DEBUGGING qCDebug(scriptengine) << "*** WARNING *** ScriptEngineV8::registerFunction() called on wrong thread [" << QThread::currentThread() << "], invoking on correct thread [" << thread() << "] parent:" << parent << "name:" << name; #endif QMetaObject::invokeMethod(this, "registerFunction", Q_ARG(const QString&, name), - Q_ARG(QScriptEngine::FunctionSignature, functionSignature), + Q_ARG(ScriptEngine::FunctionSignature, functionSignature), Q_ARG(int, numArguments)); return; } #ifdef THREAD_DEBUGGING qCDebug(scriptengine) << "ScriptEngineV8::registerFunction() called on thread [" << QThread::currentThread() << "] parent:" << parent << "name:" << name; -#endif*/ +#endif + v8::HandleScope handleScope(_v8Isolate); + v8::Context::Scope contextScope(_v8Context.Get(_v8Isolate)); ScriptValue object = globalObject().property(parent); if (object.isValid()) { ScriptValue scriptFun = ScriptEngine::newFunction(functionSignature, numArguments); @@ -546,8 +563,7 @@ void ScriptEngineV8::registerFunction(const QString& parent, const QString& name void ScriptEngineV8::registerGetterSetter(const QString& name, ScriptEngine::FunctionSignature getter, ScriptEngine::FunctionSignature setter, const QString& parent) { - //V8TODO - /*if (QThread::currentThread() != QScriptEngine::thread()) { + if (QThread::currentThread() != thread()) { #ifdef THREAD_DEBUGGING qCDebug(scriptengine) << "*** WARNING *** ScriptEngineV8::registerGetterSetter() called on wrong thread [" << QThread::currentThread() << "], invoking on correct thread [" << thread() << "] " " name:" << name << "parent:" << parent; @@ -561,7 +577,10 @@ void ScriptEngineV8::registerGetterSetter(const QString& name, ScriptEngine::Fun } #ifdef THREAD_DEBUGGING qCDebug(scriptengine) << "ScriptEngineV8::registerGetterSetter() called on thread [" << QThread::currentThread() << "] name:" << name << "parent:" << parent; -#endif*/ +#endif + + v8::HandleScope handleScope(_v8Isolate); + v8::Context::Scope contextScope(_v8Context.Get(_v8Isolate)); ScriptValue setterFunction = newFunction(setter, 1); ScriptValue getterFunction = newFunction(getter); @@ -585,6 +604,7 @@ ScriptValue ScriptEngineV8::evaluateInClosure(const ScriptValue& _closure, return nullValue(); } v8::HandleScope handleScope(_v8Isolate); + v8::Context::Scope contextScope(_v8Context.Get(_v8Isolate)); ScriptProgramV8Wrapper* unwrappedProgram = ScriptProgramV8Wrapper::unwrap(_program); if (unwrappedProgram == nullptr) { return nullValue(); @@ -684,7 +704,7 @@ ScriptValue ScriptEngineV8::evaluateInClosure(const ScriptValue& _closure, setGlobalObject(oldGlobal); }*/ - _v8Context.Get(_v8Isolate)->Enter(); + //_v8Context.Get(_v8Isolate)->Enter(); return result; } @@ -695,7 +715,7 @@ ScriptValue ScriptEngineV8::evaluate(const QString& sourceCode, const QString& f //V8TODO - /*if (QThread::currentThread() != QScriptEngine::thread()) { + if (QThread::currentThread() != thread()) { ScriptValue result; #ifdef THREAD_DEBUGGING qCDebug(scriptengine) << "*** WARNING *** ScriptEngineV8::evaluate() called on wrong thread [" << QThread::currentThread() << "], invoking on correct thread [" << thread() << "] " @@ -706,10 +726,11 @@ ScriptValue ScriptEngineV8::evaluate(const QString& sourceCode, const QString& f Q_ARG(const QString&, sourceCode), Q_ARG(const QString&, fileName)); return result; - }*/ + } // Compile and check syntax // V8TODO: Could these all be replaced with checkSyntax function from wrapper? v8::HandleScope handleScope(_v8Isolate); + v8::Context::Scope contextScope(_v8Context.Get(_v8Isolate)); v8::TryCatch tryCatch(getIsolate()); v8::ScriptOrigin scriptOrigin(getIsolate(), v8::String::NewFromUtf8(getIsolate(), fileName.toStdString().c_str()).ToLocalChecked()); v8::Local script; @@ -775,8 +796,7 @@ Q_INVOKABLE ScriptValue ScriptEngineV8::evaluate(const ScriptProgramPointer& pro return undefinedValue(); // bail early } - //V8TODO - /*if (QThread::currentThread() != QScriptEngine::thread()) { + if (QThread::currentThread() != thread()) { ScriptValue result; #ifdef THREAD_DEBUGGING qCDebug(scriptengine) << "*** WARNING *** ScriptEngineV8::evaluate() called on wrong thread [" << QThread::currentThread() << "], invoking on correct thread [" << thread() << "] " @@ -786,8 +806,9 @@ Q_INVOKABLE ScriptValue ScriptEngineV8::evaluate(const ScriptProgramPointer& pro Q_RETURN_ARG(ScriptValue, result), Q_ARG(const ScriptProgramPointer&, program)); return result; - }*/ + } v8::HandleScope handleScope(_v8Isolate); + v8::Context::Scope contextScope(_v8Context.Get(_v8Isolate)); ScriptProgramV8Wrapper* unwrapped = ScriptProgramV8Wrapper::unwrap(program); if (!unwrapped) { auto err = makeError(newValue("could not unwrap program")); @@ -843,6 +864,7 @@ void ScriptEngineV8::updateMemoryCost(const qint64& deltaSize) { ScriptValue ScriptEngineV8::globalObject() const { v8::HandleScope handleScope(_v8Isolate); + v8::Context::Scope contextScope(_v8Context.Get(_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))); } @@ -852,12 +874,15 @@ ScriptManager* ScriptEngineV8::manager() const { } ScriptValue ScriptEngineV8::newArray(uint length) { + v8::HandleScope handleScope(_v8Isolate); + v8::Context::Scope contextScope(_v8Context.Get(_v8Isolate)); V8ScriptValue result(_v8Isolate, v8::Array::New(_v8Isolate, static_cast(length))); return ScriptValue(new ScriptValueV8Wrapper(this, std::move(result))); } ScriptValue ScriptEngineV8::newArrayBuffer(const QByteArray& message) { v8::HandleScope handleScope(_v8Isolate); + v8::Context::Scope contextScope(_v8Context.Get(_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()); @@ -873,12 +898,16 @@ ScriptValue ScriptEngineV8::newArrayBuffer(const QByteArray& message) { } ScriptValue ScriptEngineV8::newObject() { + v8::HandleScope handleScope(_v8Isolate); + v8::Context::Scope contextScope(_v8Context.Get(_v8Isolate)); V8ScriptValue result(_v8Isolate, v8::Object::New(_v8Isolate)); return ScriptValue(new ScriptValueV8Wrapper(this, std::move(result))); } ScriptValue ScriptEngineV8::newMethod(QObject* object, V8ScriptValue lifetime, const QList& metas, int numMaxParams) { + v8::HandleScope handleScope(_v8Isolate); + v8::Context::Scope contextScope(_v8Context.Get(_v8Isolate)); V8ScriptValue result(ScriptMethodV8Proxy::newMethod(this, object, lifetime, metas, numMaxParams)); return ScriptValue(new ScriptValueV8Wrapper(this, std::move(result))); } @@ -893,33 +922,43 @@ ScriptProgramPointer ScriptEngineV8::newProgram(const QString& sourceCode, const ScriptValue ScriptEngineV8::newQObject(QObject* object, ScriptEngine::ValueOwnership ownership, const ScriptEngine::QObjectWrapOptions& options) { + v8::HandleScope handleScope(_v8Isolate); + v8::Context::Scope contextScope(_v8Context.Get(_v8Isolate)); V8ScriptValue result = ScriptObjectV8Proxy::newQObject(this, object, ownership, options); return ScriptValue(new ScriptValueV8Wrapper(this, std::move(result))); } ScriptValue ScriptEngineV8::newValue(bool value) { + v8::HandleScope handleScope(_v8Isolate); + v8::Context::Scope contextScope(_v8Context.Get(_v8Isolate)); V8ScriptValue result(_v8Isolate, v8::Boolean::New(_v8Isolate, value)); return ScriptValue(new ScriptValueV8Wrapper(this, std::move(result))); } ScriptValue ScriptEngineV8::newValue(int value) { + v8::HandleScope handleScope(_v8Isolate); + v8::Context::Scope contextScope(_v8Context.Get(_v8Isolate)); V8ScriptValue result(_v8Isolate, v8::Integer::New(_v8Isolate, value)); return ScriptValue(new ScriptValueV8Wrapper(this, std::move(result))); } ScriptValue ScriptEngineV8::newValue(uint value) { + v8::HandleScope handleScope(_v8Isolate); + v8::Context::Scope contextScope(_v8Context.Get(_v8Isolate)); V8ScriptValue result(_v8Isolate, v8::Uint32::New(_v8Isolate, value)); return ScriptValue(new ScriptValueV8Wrapper(this, std::move(result))); } ScriptValue ScriptEngineV8::newValue(double value) { v8::HandleScope handleScope(_v8Isolate); + v8::Context::Scope contextScope(_v8Context.Get(_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::Context::Scope contextScope(_v8Context.Get(_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))); @@ -927,6 +966,7 @@ ScriptValue ScriptEngineV8::newValue(const QString& value) { ScriptValue ScriptEngineV8::newValue(const QLatin1String& value) { v8::HandleScope handleScope(_v8Isolate); + v8::Context::Scope contextScope(_v8Context.Get(_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))); @@ -934,12 +974,15 @@ ScriptValue ScriptEngineV8::newValue(const QLatin1String& value) { ScriptValue ScriptEngineV8::newValue(const char* value) { v8::HandleScope handleScope(_v8Isolate); + v8::Context::Scope contextScope(_v8Context.Get(_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))); } ScriptValue ScriptEngineV8::newVariant(const QVariant& value) { + v8::HandleScope handleScope(_v8Isolate); + v8::Context::Scope contextScope(_v8Context.Get(_v8Isolate)); V8ScriptValue result = castVariantToValue(value); return ScriptValue(new ScriptValueV8Wrapper(this, std::move(result))); } @@ -1005,12 +1048,14 @@ ScriptValue ScriptEngineV8::newFunction(ScriptEngine::FunctionSignature fun, int //V8TODO: is using GetCurrentContext ok, or context wrapper needs to be added? v8::HandleScope handleScope(info.GetIsolate()); auto context = info.GetIsolate()->GetCurrentContext(); + v8::Context::Scope contextScope(context); + auto object = v8::Local::Cast(info.Data()); auto function = reinterpret_cast - (info.Data()->ToObject(context).ToLocalChecked()->GetAlignedPointerFromInternalField(0)); + (object->GetAlignedPointerFromInternalField(0)); ScriptContext *scriptContext = reinterpret_cast - (info.Data()->ToObject(context).ToLocalChecked()->GetAlignedPointerFromInternalField(1));; + (object->GetAlignedPointerFromInternalField(1));; ScriptEngineV8 *scriptEngine = reinterpret_cast - (info.Data()->ToObject(context).ToLocalChecked()->GetAlignedPointerFromInternalField(2));; + (object->GetAlignedPointerFromInternalField(2));; ScriptValue result = function(scriptContext, scriptEngine); ScriptValueV8Wrapper* unwrapped = ScriptValueV8Wrapper::unwrap(result); info.GetReturnValue().Set(unwrapped->toV8Value().constGet()); @@ -1019,6 +1064,7 @@ ScriptValue ScriptEngineV8::newFunction(ScriptEngine::FunctionSignature fun, int //auto functionData = v8::Object::New(_v8Isolate); //functionData->setIn v8::HandleScope handleScope(_v8Isolate); + v8::Context::Scope contextScope(_v8Context.Get(_v8Isolate)); auto functionDataTemplate = v8::ObjectTemplate::New(_v8Isolate); functionDataTemplate->SetInternalFieldCount(3); auto functionData = functionDataTemplate->NewInstance(getContext()).ToLocalChecked(); @@ -1044,6 +1090,7 @@ void ScriptEngineV8::setObjectName(const QString& name) { //V8TODO bool ScriptEngineV8::setProperty(const char* name, const QVariant& value) { v8::HandleScope handleScope(_v8Isolate); + v8::Context::Scope contextScope(_v8Context.Get(_v8Isolate)); v8::Local global = getContext()->Global(); auto v8Name = v8::String::NewFromUtf8(getIsolate(), name).ToLocalChecked(); V8ScriptValue v8Value = castVariantToValue(value); @@ -1056,13 +1103,23 @@ void ScriptEngineV8::setProcessEventsInterval(int interval) { } QThread* ScriptEngineV8::thread() const { - return _currentThread; + return QObject::thread(); } void ScriptEngineV8::setThread(QThread* thread) { + qDebug() << "Moved script engine " << objectName() << " to different thread"; + _v8Isolate->Exit(); moveToThread(thread); + QMetaObject::invokeMethod(this, "enterIsolateOnThisThread"); } +void ScriptEngineV8::enterIsolateOnThisThread() { + Q_ASSERT(thread() == QThread::currentThread()); + _v8Isolate->Enter(); + qDebug() << "Script engine " << objectName() << " entered isolate on a new thread"; +} + + ScriptValue ScriptEngineV8::uncaughtException() const { //V8TODO //V8ScriptValue result = QScriptEngine::uncaughtException(); @@ -1088,12 +1145,16 @@ bool ScriptEngineV8::raiseException(const ScriptValue& exception) { } ScriptValue ScriptEngineV8::create(int type, const void* ptr) { + v8::HandleScope handleScope(_v8Isolate); + v8::Context::Scope contextScope(_v8Context.Get(_v8Isolate)); QVariant variant(type, ptr); V8ScriptValue scriptValue = castVariantToValue(variant); return ScriptValue(new ScriptValueV8Wrapper(this, std::move(scriptValue))); } QVariant ScriptEngineV8::convert(const ScriptValue& value, int typeId) { + v8::HandleScope handleScope(_v8Isolate); + v8::Context::Scope contextScope(_v8Context.Get(_v8Isolate)); ScriptValueV8Wrapper* unwrapped = ScriptValueV8Wrapper::unwrap(value); if (unwrapped == nullptr) { return QVariant(); diff --git a/libraries/script-engine/src/v8/ScriptEngineV8.h b/libraries/script-engine/src/v8/ScriptEngineV8.h index 19c2a9c5c0..383cdf0afb 100644 --- a/libraries/script-engine/src/v8/ScriptEngineV8.h +++ b/libraries/script-engine/src/v8/ScriptEngineV8.h @@ -114,12 +114,12 @@ public: // ScriptEngine implementation const QString& parent = QString("")) override; Q_INVOKABLE virtual void registerGlobalObject(const QString& name, QObject* object) override; virtual void setDefaultPrototype(int metaTypeId, const ScriptValue& prototype) override; - // Already implemented by QObject virtual void setObjectName(const QString& name) override; virtual bool setProperty(const char* name, const QVariant& value) override; virtual void setProcessEventsInterval(int interval) override; virtual QThread* thread() const override; virtual void setThread(QThread* thread) override; + Q_INVOKABLE virtual void enterIsolateOnThisThread() override; virtual ScriptValue undefinedValue() override; virtual ScriptValue uncaughtException() const override; virtual QStringList uncaughtExceptionBacktrace() const override; @@ -219,7 +219,7 @@ protected: ScriptValue _nullValue; ScriptValue _undefinedValue; mutable ScriptContextQtPointer _currContext; - QThread *_currentThread; + //QThread *_currentThread; //V8TODO //ArrayBufferClass* _arrayBufferClass; diff --git a/libraries/script-engine/src/v8/ScriptObjectV8Proxy.cpp b/libraries/script-engine/src/v8/ScriptObjectV8Proxy.cpp index 04ad70ea15..bd184b860c 100644 --- a/libraries/script-engine/src/v8/ScriptObjectV8Proxy.cpp +++ b/libraries/script-engine/src/v8/ScriptObjectV8Proxy.cpp @@ -139,7 +139,7 @@ ScriptObjectV8Proxy* ScriptObjectV8Proxy::unwrapProxy(const V8ScriptValue& val) if (!v8Value->IsObject()) { return nullptr; } - v8::Local v8Object = v8Value->ToObject(val.constGetContext()).ToLocalChecked(); + v8::Local v8Object = v8::Local::Cast(v8Value); if (v8Object->InternalFieldCount() != 2) { return nullptr; } @@ -167,6 +167,7 @@ void ScriptObjectV8Proxy::investigate() { if (!qobject) return; v8::HandleScope handleScope(_engine->getIsolate()); + v8::Context::Scope contextScope(_engine->getContext()); auto objectTemplate = _v8ObjectTemplate.Get(_engine->getIsolate()); objectTemplate->SetInternalFieldCount(3); @@ -228,13 +229,17 @@ void ScriptObjectV8Proxy::investigate() { break; } - V8ScriptString name(_engine->getIsolate(), v8::String::NewFromUtf8(_engine->getIsolate(), szName.data(), v8::NewStringType::kNormal, szName.length()).ToLocalChecked()); + auto nameString = v8::String::NewFromUtf8(_engine->getIsolate(), szName.data(), v8::NewStringType::kNormal, szName.length()).ToLocalChecked(); + V8ScriptString name(_engine->getIsolate(), nameString); auto nameLookup = methodNames.find(name); if (isSignal) { if (nameLookup == methodNames.end()) { SignalDef& signalDef = _signals.insert(idx, SignalDef(_engine->getIsolate(), name.get())).value(); signalDef.name = name; signalDef.signal = method; + qDebug(scriptengine) << "Utf8Value 1: " << QString(*v8::String::Utf8Value(const_cast(_engine->getIsolate()), nameString)); + qDebug(scriptengine) << "Utf8Value 2: " << QString(*v8::String::Utf8Value(const_cast(_engine->getIsolate()), name.constGet())); + qDebug(scriptengine) << "toQString: " << name.toQString(); methodNames.insert(name, idx); } else { int originalMethodId = nameLookup.value(); @@ -474,7 +479,7 @@ ScriptVariantV8Proxy* ScriptVariantV8Proxy::unwrapProxy(const V8ScriptValue& val if (!v8Value->IsObject()) { return nullptr; } - v8::Local v8Object = v8Value->ToObject(val.constGetContext()).ToLocalChecked(); + v8::Local v8Object = v8::Local::Cast(v8Value); if (v8Object->InternalFieldCount() != 2) { return nullptr; } diff --git a/libraries/script-engine/src/v8/ScriptValueIteratorV8Wrapper.cpp b/libraries/script-engine/src/v8/ScriptValueIteratorV8Wrapper.cpp index 5120503ef4..b0857d3953 100644 --- a/libraries/script-engine/src/v8/ScriptValueIteratorV8Wrapper.cpp +++ b/libraries/script-engine/src/v8/ScriptValueIteratorV8Wrapper.cpp @@ -18,10 +18,8 @@ V8ScriptValueIterator::V8ScriptValueIterator(ScriptEngineV8* engine, v8::LocalgetContext()); auto context = _context.Get(isolate); - v8::Local v8Object; - if (!object->ToObject(context).ToLocal(&v8Object)) { - Q_ASSERT(false); - } + Q_ASSERT(object->IsObject()); + v8::Local v8Object = v8::Local::Cast(object); _object.Reset(isolate, v8Object); _propertyNames.Reset(isolate, v8Object->GetOwnPropertyNames(context).ToLocalChecked()); _length = _propertyNames.Get(isolate)->Length(); diff --git a/libraries/script-engine/src/v8/ScriptValueV8Wrapper.cpp b/libraries/script-engine/src/v8/ScriptValueV8Wrapper.cpp index 42878abd1f..b4263c53dd 100644 --- a/libraries/script-engine/src/v8/ScriptValueV8Wrapper.cpp +++ b/libraries/script-engine/src/v8/ScriptValueV8Wrapper.cpp @@ -60,7 +60,10 @@ V8ScriptValue ScriptValueV8Wrapper::fullUnwrap(ScriptEngineV8* engine, const Scr } ScriptValue ScriptValueV8Wrapper::call(const ScriptValue& thisObject, const ScriptValueList& args) { - v8::HandleScope handleScope(_engine->getIsolate()); + auto isolate = _engine->getIsolate(); + Q_ASSERT(isolate->IsCurrent()); + v8::HandleScope handleScope(isolate); + v8::Context::Scope contextScope(_engine->getContext()); V8ScriptValue v8This = fullUnwrap(thisObject); //V8ScriptValueList qArgs; Q_ASSERT(args.length() <= Q_METAMETHOD_INVOKE_MAX_ARGS); @@ -85,7 +88,10 @@ ScriptValue ScriptValueV8Wrapper::call(const ScriptValue& thisObject, const Scri } ScriptValue ScriptValueV8Wrapper::call(const ScriptValue& thisObject, const ScriptValue& arguments) { - v8::HandleScope handleScope(_engine->getIsolate()); + auto isolate = _engine->getIsolate(); + Q_ASSERT(isolate->IsCurrent()); + v8::HandleScope handleScope(isolate); + v8::Context::Scope contextScope(_engine->getContext()); V8ScriptValue v8This = fullUnwrap(thisObject); V8ScriptValue v8Args = fullUnwrap(arguments); // V8TODO should there be a v8 try-catch here? @@ -106,7 +112,10 @@ ScriptValue ScriptValueV8Wrapper::call(const ScriptValue& thisObject, const Scri } ScriptValue ScriptValueV8Wrapper::construct(const ScriptValueList& args) { - v8::HandleScope handleScope(_engine->getIsolate()); + auto isolate = _engine->getIsolate(); + Q_ASSERT(isolate->IsCurrent()); + v8::HandleScope handleScope(isolate); + v8::Context::Scope contextScope(_engine->getContext()); 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]; @@ -129,7 +138,10 @@ ScriptValue ScriptValueV8Wrapper::construct(const ScriptValueList& args) { } ScriptValue ScriptValueV8Wrapper::construct(const ScriptValue& arguments) { - v8::HandleScope handleScope(_engine->getIsolate()); + auto isolate = _engine->getIsolate(); + Q_ASSERT(isolate->IsCurrent()); + v8::HandleScope handleScope(isolate); + v8::Context::Scope contextScope(_engine->getContext()); // V8TODO I'm not sure in what format arguments are yet, backtrace will show how it is used Q_ASSERT(false); return _engine->undefinedValue(); @@ -157,13 +169,17 @@ ScriptValueIteratorPointer ScriptValueV8Wrapper::newIterator() const { } ScriptValue ScriptValueV8Wrapper::property(const QString& name, const ScriptValue::ResolveFlags& mode) const { - v8::HandleScope handleScope(_engine->getIsolate()); + auto isolate = _engine->getIsolate(); + Q_ASSERT(isolate->IsCurrent()); + v8::HandleScope handleScope(isolate); + v8::Context::Scope contextScope(_engine->getContext()); if (!_value.constGet()->IsObject()) { //V8TODO: what about flags? - v8::Local resultLocal; - v8::Local key = v8::String::NewFromUtf8(_engine->getIsolate(), name.toStdString().c_str(),v8::NewStringType::kNormal).ToLocalChecked(); - if (_value.constGet()->ToObject(_value.constGetContext()).ToLocalChecked() - ->Get(_value.constGetContext(), key).ToLocal(&resultLocal)) { + v8::Local resultLocal; + v8::Local key = v8::String::NewFromUtf8(_engine->getIsolate(), name.toStdString().c_str(),v8::NewStringType::kNormal).ToLocalChecked(); + Q_ASSERT(_value.constGet()->IsObject()); + const v8::Local object = v8::Local::Cast(_value.constGet()); + if (object->Get(_value.constGetContext(), key).ToLocal(&resultLocal)) { V8ScriptValue result(_engine->getIsolate(), resultLocal); return ScriptValue(new ScriptValueV8Wrapper(_engine, std::move(result))); } @@ -176,12 +192,16 @@ ScriptValue ScriptValueV8Wrapper::property(const QString& name, const ScriptValu } ScriptValue ScriptValueV8Wrapper::property(quint32 arrayIndex, const ScriptValue::ResolveFlags& mode) const { - v8::HandleScope handleScope(_engine->getIsolate()); + auto isolate = _engine->getIsolate(); + Q_ASSERT(isolate->IsCurrent()); + v8::HandleScope handleScope(isolate); + v8::Context::Scope contextScope(_engine->getContext()); if (!_value.constGet()->IsObject()) { //V8TODO: what about flags? - v8::Local resultLocal; - if (_value.constGet()->ToObject(_value.constGetContext()).ToLocalChecked() - ->Get(_value.constGetContext(), arrayIndex).ToLocal(&resultLocal)) { + v8::Local resultLocal; + Q_ASSERT(_value.constGet()->IsObject()); + const v8::Local object = v8::Local::Cast(_value.constGet()); + if (object->Get(_value.constGetContext(), arrayIndex).ToLocal(&resultLocal)) { V8ScriptValue result(_engine->getIsolate(), resultLocal); return ScriptValue(new ScriptValueV8Wrapper(_engine, std::move(result))); } @@ -192,17 +212,28 @@ ScriptValue ScriptValueV8Wrapper::property(quint32 arrayIndex, const ScriptValue } void ScriptValueV8Wrapper::setData(const ScriptValue& value) { + auto isolate = _engine->getIsolate(); + Q_ASSERT(isolate->IsCurrent()); + v8::HandleScope handleScope(isolate); + v8::Context::Scope contextScope(_engine->getContext()); V8ScriptValue unwrapped = fullUnwrap(value); (**_value.get()) = (**unwrapped.get()); } void ScriptValueV8Wrapper::setProperty(const QString& name, const ScriptValue& value, const ScriptValue::PropertyFlags& flags) { - v8::HandleScope handleScope(_engine->getIsolate()); + auto isolate = _engine->getIsolate(); + Q_ASSERT(isolate->IsCurrent()); + v8::HandleScope handleScope(isolate); + v8::Context::Scope contextScope(_engine->getContext()); V8ScriptValue unwrapped = fullUnwrap(value); if(_value.constGet()->IsObject()) { - v8::Local key = v8::String::NewFromUtf8(_engine->getIsolate(), name.toStdString().c_str(),v8::NewStringType::kNormal).ToLocalChecked(); - v8::Maybe retVal = _value.get()->ToObject(_value.getContext()).ToLocalChecked() - ->Set(_value.getContext(), key, unwrapped.constGet()); + v8::Local key = v8::String::NewFromUtf8(isolate, name.toStdString().c_str(),v8::NewStringType::kNormal).ToLocalChecked(); + Q_ASSERT(_value.get()->IsObject()); + auto object = v8::Local::Cast(_value.get()); + // V8TODO: What if velue context and current context is different? + //v8::Maybe retVal = object->Set(_value.getContext(), key, unwrapped.constGet()); + //v8::Maybe retVal = object->Set(_engine->getContext(), key, unwrapped.constGet()); + v8::Maybe retVal = object->Set(isolate->GetCurrentContext(), key, unwrapped.constGet()); if (retVal.IsJust() ? !retVal.FromJust() : true){ qDebug(scriptengine) << "Failed to set property"; } @@ -214,10 +245,14 @@ void ScriptValueV8Wrapper::setProperty(const QString& name, const ScriptValue& v } void ScriptValueV8Wrapper::setProperty(quint32 arrayIndex, const ScriptValue& value, const ScriptValue::PropertyFlags& flags) { + auto isolate = _engine->getIsolate(); + Q_ASSERT(isolate->IsCurrent()); + v8::HandleScope handleScope(isolate); + v8::Context::Scope contextScope(_engine->getContext()); V8ScriptValue unwrapped = fullUnwrap(value); if(_value.constGet()->IsObject()) { - v8::Maybe retVal(_value.get()->ToObject(_value.getContext()).ToLocalChecked() - ->Set(_value.getContext(), arrayIndex, unwrapped.constGet())); + auto object = v8::Local::Cast(_value.get()); + v8::Maybe retVal(object->Set(_value.getContext(), arrayIndex, unwrapped.constGet())); if (retVal.IsJust() ? !retVal.FromJust() : true){ qDebug(scriptengine) << "Failed to set property"; } @@ -229,11 +264,15 @@ void ScriptValueV8Wrapper::setProperty(quint32 arrayIndex, const ScriptValue& va } void ScriptValueV8Wrapper::setPrototype(const ScriptValue& prototype) { + auto isolate = _engine->getIsolate(); + Q_ASSERT(isolate->IsCurrent()); + v8::HandleScope handleScope(isolate); + v8::Context::Scope contextScope(_engine->getContext()); ScriptValueV8Wrapper* unwrappedPrototype = unwrap(prototype); if (unwrappedPrototype) { if(unwrappedPrototype->toV8Value().constGet()->IsObject() && _value.constGet()->IsObject()) { - v8::Maybe retVal = _value.get()->ToObject(_value.getContext()).ToLocalChecked() - ->SetPrototype(_value.getContext(), unwrappedPrototype->toV8Value().constGet()); + auto object = v8::Local::Cast(_value.get()); + v8::Maybe retVal = object->SetPrototype(_value.getContext(), unwrappedPrototype->toV8Value().constGet()); if (retVal.IsJust() ? !retVal.FromJust() : true){ qDebug(scriptengine) << "Failed to assign prototype"; } @@ -244,18 +283,27 @@ void ScriptValueV8Wrapper::setPrototype(const ScriptValue& prototype) { } bool ScriptValueV8Wrapper::strictlyEquals(const ScriptValue& other) const { - v8::HandleScope handleScope(_engine->getIsolate()); + auto isolate = _engine->getIsolate(); + Q_ASSERT(isolate->IsCurrent()); + v8::HandleScope handleScope(isolate); + v8::Context::Scope contextScope(_engine->getContext()); ScriptValueV8Wrapper* unwrappedOther = unwrap(other); return unwrappedOther ? _value.constGet()->StrictEquals(unwrappedOther->toV8Value().constGet()) : false; } bool ScriptValueV8Wrapper::toBool() const { - v8::HandleScope handleScope(_engine->getIsolate()); + auto isolate = _engine->getIsolate(); + Q_ASSERT(isolate->IsCurrent()); + v8::HandleScope handleScope(isolate); + v8::Context::Scope contextScope(_engine->getContext()); return _value.constGet()->ToBoolean(_engine->getIsolate())->Value(); } qint32 ScriptValueV8Wrapper::toInt32() const { - v8::HandleScope handleScope(_engine->getIsolate()); + auto isolate = _engine->getIsolate(); + Q_ASSERT(isolate->IsCurrent()); + v8::HandleScope handleScope(isolate); + v8::Context::Scope contextScope(_engine->getContext()); v8::Local *integer; if (!_value.constGet()->ToInteger(_value.constGetContext()).ToLocal(integer)) { Q_ASSERT(false); @@ -264,7 +312,10 @@ qint32 ScriptValueV8Wrapper::toInt32() const { } double ScriptValueV8Wrapper::toInteger() const { - v8::HandleScope handleScope(_engine->getIsolate()); + auto isolate = _engine->getIsolate(); + Q_ASSERT(isolate->IsCurrent()); + v8::HandleScope handleScope(isolate); + v8::Context::Scope contextScope(_engine->getContext()); v8::Local *integer; if (!_value.constGet()->ToInteger(_value.constGetContext()).ToLocal(integer)) { Q_ASSERT(false); @@ -273,7 +324,10 @@ double ScriptValueV8Wrapper::toInteger() const { } double ScriptValueV8Wrapper::toNumber() const { - v8::HandleScope handleScope(_engine->getIsolate()); + auto isolate = _engine->getIsolate(); + Q_ASSERT(isolate->IsCurrent()); + v8::HandleScope handleScope(isolate); + v8::Context::Scope contextScope(_engine->getContext()); v8::Local *number; if (!_value.constGet()->ToNumber(_value.constGetContext()).ToLocal(number)) { Q_ASSERT(false); @@ -282,14 +336,20 @@ double ScriptValueV8Wrapper::toNumber() const { } QString ScriptValueV8Wrapper::toString() const { - v8::HandleScope handleScope(_engine->getIsolate()); + auto isolate = _engine->getIsolate(); + Q_ASSERT(isolate->IsCurrent()); + v8::HandleScope handleScope(isolate); + v8::Context::Scope contextScope(_engine->getContext()); v8::String::Utf8Value string(_engine->getIsolate(), _value.constGet()); Q_ASSERT(*string != nullptr); return QString(*string); } quint16 ScriptValueV8Wrapper::toUInt16() const { - v8::HandleScope handleScope(_engine->getIsolate()); + auto isolate = _engine->getIsolate(); + Q_ASSERT(isolate->IsCurrent()); + v8::HandleScope handleScope(isolate); + v8::Context::Scope contextScope(_engine->getContext()); v8::Local *integer; if (!_value.constGet()->ToUint32(_value.constGetContext()).ToLocal(integer)) { Q_ASSERT(false); @@ -298,7 +358,10 @@ quint16 ScriptValueV8Wrapper::toUInt16() const { } quint32 ScriptValueV8Wrapper::toUInt32() const { - v8::HandleScope handleScope(_engine->getIsolate()); + auto isolate = _engine->getIsolate(); + Q_ASSERT(isolate->IsCurrent()); + v8::HandleScope handleScope(isolate); + v8::Context::Scope contextScope(_engine->getContext()); v8::Local *integer; if (!_value.constGet()->ToUint32(_value.constGetContext()).ToLocal(integer)) { Q_ASSERT(false); @@ -327,7 +390,10 @@ QObject* ScriptValueV8Wrapper::toQObject() const { } bool ScriptValueV8Wrapper::equals(const ScriptValue& other) const { - v8::HandleScope handleScope(_engine->getIsolate()); + auto isolate = _engine->getIsolate(); + Q_ASSERT(isolate->IsCurrent()); + v8::HandleScope handleScope(isolate); + v8::Context::Scope contextScope(_engine->getContext()); ScriptValueV8Wrapper* unwrappedOther = unwrap(other); //V8TODO: does this work with different contexts/isolates? // in such case conversion will probably be necessary @@ -343,51 +409,95 @@ bool ScriptValueV8Wrapper::equals(const ScriptValue& other) const { } bool ScriptValueV8Wrapper::isArray() const { + auto isolate = _engine->getIsolate(); + Q_ASSERT(isolate->IsCurrent()); + v8::HandleScope handleScope(isolate); + v8::Context::Scope contextScope(_engine->getContext()); return _value.constGet()->IsArray(); } bool ScriptValueV8Wrapper::isBool() const { + auto isolate = _engine->getIsolate(); + Q_ASSERT(isolate->IsCurrent()); + v8::HandleScope handleScope(isolate); + v8::Context::Scope contextScope(_engine->getContext()); return _value.constGet()->IsBoolean(); } bool ScriptValueV8Wrapper::isError() const { + auto isolate = _engine->getIsolate(); + Q_ASSERT(isolate->IsCurrent()); + v8::HandleScope handleScope(isolate); + v8::Context::Scope contextScope(_engine->getContext()); //V8TODO return false; //return _value.constGet()->IsError(); } bool ScriptValueV8Wrapper::isFunction() const { + auto isolate = _engine->getIsolate(); + Q_ASSERT(isolate->IsCurrent()); + v8::HandleScope handleScope(isolate); + v8::Context::Scope contextScope(_engine->getContext()); return _value.constGet()->IsFunction(); } bool ScriptValueV8Wrapper::isNumber() const { + auto isolate = _engine->getIsolate(); + Q_ASSERT(isolate->IsCurrent()); + v8::HandleScope handleScope(isolate); + v8::Context::Scope contextScope(_engine->getContext()); return _value.constGet()->IsNumber(); } bool ScriptValueV8Wrapper::isNull() const { + auto isolate = _engine->getIsolate(); + Q_ASSERT(isolate->IsCurrent()); + v8::HandleScope handleScope(isolate); + v8::Context::Scope contextScope(_engine->getContext()); return _value.constGet()->IsNull(); } bool ScriptValueV8Wrapper::isObject() const { + auto isolate = _engine->getIsolate(); + Q_ASSERT(isolate->IsCurrent()); + v8::HandleScope handleScope(isolate); + v8::Context::Scope contextScope(_engine->getContext()); return _value.constGet()->IsObject(); } bool ScriptValueV8Wrapper::isString() const { + auto isolate = _engine->getIsolate(); + Q_ASSERT(isolate->IsCurrent()); + v8::HandleScope handleScope(isolate); + v8::Context::Scope contextScope(_engine->getContext()); return _value.constGet()->IsString(); } bool ScriptValueV8Wrapper::isUndefined() const { + auto isolate = _engine->getIsolate(); + Q_ASSERT(isolate->IsCurrent()); + v8::HandleScope handleScope(isolate); + v8::Context::Scope contextScope(_engine->getContext()); return _value.constGet()->IsUndefined(); } bool ScriptValueV8Wrapper::isValid() const { //V8TODO + auto isolate = _engine->getIsolate(); + Q_ASSERT(isolate->IsCurrent()); + v8::HandleScope handleScope(isolate); + v8::Context::Scope contextScope(_engine->getContext()); return true; //return _value.constGet()->IsValid(); } bool ScriptValueV8Wrapper::isVariant() const { //V8TODO + auto isolate = _engine->getIsolate(); + Q_ASSERT(isolate->IsCurrent()); + v8::HandleScope handleScope(isolate); + v8::Context::Scope contextScope(_engine->getContext()); return false; //return _value.isVariant(); } diff --git a/libraries/script-engine/src/v8/V8Types.h b/libraries/script-engine/src/v8/V8Types.h index fac4d18f2e..dd98e61c06 100644 --- a/libraries/script-engine/src/v8/V8Types.h +++ b/libraries/script-engine/src/v8/V8Types.h @@ -27,18 +27,21 @@ public: V8ScriptValueTemplate(v8::Isolate *isolate, const v8::Local value) : _isolate(isolate) { //_value.reset(_isolate, value); v8::HandleScope handleScope(_isolate); + Q_ASSERT(isolate->IsCurrent()); + Q_ASSERT(!isolate->GetCurrentContext().IsEmpty()); _context.Reset(isolate, isolate->GetCurrentContext()); _value.reset(new v8::UniquePersistent(_isolate, std::move(value))); }; v8::Local get() { v8::EscapableHandleScope handleScope(_isolate); - return _value.get()->Get(_isolate); + return handleScope.Escape(_value.get()->Get(_isolate)); }; const v8::Local constGet() const { v8::EscapableHandleScope handleScope(_isolate); - return _value.get()->Get(_isolate); + return handleScope.Escape(_value.get()->Get(_isolate)); }; V8ScriptValueTemplate&& copy() const { + Q_ASSERT(_isolate->IsCurrent()); v8::HandleScope handleScope(_isolate); return new V8ScriptValueTemplate(_isolate, v8::Local::New(_isolate, constGet()));}; const v8::Local constGetContext() const { @@ -72,6 +75,8 @@ public: V8ScriptString() = delete; V8ScriptString(v8::Isolate *isolate, const v8::Local value) : V8ScriptValueTemplate(isolate, value) {}; const QString toQString() const { + Q_ASSERT(constGet()->IsString()); + Q_ASSERT(constGetIsolate()->IsCurrent()); return QString(*v8::String::Utf8Value(const_cast(constGetIsolate()), constGet())); }; bool operator==(const V8ScriptString& string) const {