From c3417b807c1c9a9057cb9730717ff0fa8a0451c6 Mon Sep 17 00:00:00 2001 From: ksuprynowicz Date: Sat, 11 Feb 2023 20:42:25 +0100 Subject: [PATCH] Increased thread safety in V8 --- libraries/script-engine/src/ScriptManager.cpp | 4 +- .../script-engine/src/ScriptValueUtils.cpp | 3 ++ .../src/v8/ScriptContextV8Wrapper.cpp | 5 ++- .../src/v8/ScriptContextV8Wrapper.h | 2 + .../script-engine/src/v8/ScriptEngineV8.cpp | 6 +-- .../src/v8/ScriptEngineV8_cast.cpp | 11 +++++- .../src/v8/ScriptObjectV8Proxy.cpp | 25 ++++++++++--- .../src/v8/ScriptObjectV8Proxy.h | 2 +- .../src/v8/ScriptValueIteratorV8Wrapper.h | 1 + .../src/v8/ScriptValueV8Wrapper.cpp | 37 +++++++++++++++---- .../src/v8/ScriptValueV8Wrapper.h | 1 - libraries/script-engine/src/v8/V8Lambda.h | 4 +- libraries/script-engine/src/v8/V8Types.h | 27 +++++++++++--- .../controllerModules/inEditMode.js | 4 ++ 14 files changed, 102 insertions(+), 30 deletions(-) diff --git a/libraries/script-engine/src/ScriptManager.cpp b/libraries/script-engine/src/ScriptManager.cpp index eae3eca3e1..18f41f32c5 100644 --- a/libraries/script-engine/src/ScriptManager.cpp +++ b/libraries/script-engine/src/ScriptManager.cpp @@ -1322,7 +1322,7 @@ ScriptValue ScriptManager::newModule(const QString& modulePath, const ScriptValu auto closure = _engine->newObject(); auto exports = _engine->newObject(); auto module = _engine->newObject(); - qCDebug(scriptengine_module) << "newModule" << parent.property("filename").toString(); + //qCDebug(scriptengine_module) << "newModule" << parent.property("filename").toString(); closure.setProperty("module", module, READONLY_PROP_FLAGS); @@ -1530,7 +1530,7 @@ ScriptValue ScriptManager::require(const QString& moduleId) { // set up a new reference point for detecting cache key deletion cacheMeta.setProperty(modulePath, module); - qCDebug(scriptengine_module) << "//ScriptManager::require(" << moduleId << ")"; + //qCDebug(scriptengine_module) << "//ScriptManager::require(" << moduleId << ")"; _engine->maybeEmitUncaughtException(__FUNCTION__); //qCDebug(scriptengine_module) << "Exports: " << _engine->scriptValueDebugDetails(module.property("exports")); diff --git a/libraries/script-engine/src/ScriptValueUtils.cpp b/libraries/script-engine/src/ScriptValueUtils.cpp index f1c1461271..e574ba7e8e 100644 --- a/libraries/script-engine/src/ScriptValueUtils.cpp +++ b/libraries/script-engine/src/ScriptValueUtils.cpp @@ -459,6 +459,9 @@ ScriptValue quatToScriptValue(ScriptEngine* engine, const glm::quat& quat) { // V8TODO: add similar check to other conversions bool quatFromScriptValue(const ScriptValue& object, glm::quat& quat) { + if (!object.isValid()) { + return false; + } if (!object.isObject()) { return false; } diff --git a/libraries/script-engine/src/v8/ScriptContextV8Wrapper.cpp b/libraries/script-engine/src/v8/ScriptContextV8Wrapper.cpp index 1250b68fa8..c4eadc6b14 100644 --- a/libraries/script-engine/src/v8/ScriptContextV8Wrapper.cpp +++ b/libraries/script-engine/src/v8/ScriptContextV8Wrapper.cpp @@ -178,7 +178,8 @@ ScriptValue ScriptContextV8Wrapper::throwError(const QString& text) { return ScriptValue(new ScriptValueV8Wrapper(_engine, std::move(result))); } else { qWarning() << "throwError on a different thread not implemented yet, error value: " << text; - return _engine->undefinedValue(); + //return _engine->undefinedValue(); + return ScriptValue(); } } @@ -197,7 +198,7 @@ ScriptValue ScriptContextV8Wrapper::throwValue(const ScriptValue& value) { } ScriptFunctionContextV8Wrapper::ScriptFunctionContextV8Wrapper(ScriptEngineV8* engine, const v8::Local context) : _engine(engine) { - v8::Locker locker(); + v8::Locker locker(engine->getIsolate()); v8::Isolate::Scope isolateScope(engine->getIsolate()); v8::HandleScope handleScope(engine->getIsolate()); _context.Reset(engine->getIsolate(), context); diff --git a/libraries/script-engine/src/v8/ScriptContextV8Wrapper.h b/libraries/script-engine/src/v8/ScriptContextV8Wrapper.h index fdd1b00ce0..59b056ea44 100644 --- a/libraries/script-engine/src/v8/ScriptContextV8Wrapper.h +++ b/libraries/script-engine/src/v8/ScriptContextV8Wrapper.h @@ -60,6 +60,7 @@ private: // storage // V8TODO: Is custom copy constructor needed for thread safety? v8::Persistent _context; ScriptContextPointer _parentContext; + Q_DISABLE_COPY(ScriptContextV8Wrapper) }; class ScriptFunctionContextV8Wrapper final : public ScriptFunctionContext { @@ -78,6 +79,7 @@ private: // storage // V8TODO: Is custom copy constructor needed for thread safety? v8::Persistent _context; //V8ScriptContextInfo _value; + Q_DISABLE_COPY(ScriptFunctionContextV8Wrapper) }; #endif // hifi_ScriptContextV8Wrapper_h diff --git a/libraries/script-engine/src/v8/ScriptEngineV8.cpp b/libraries/script-engine/src/v8/ScriptEngineV8.cpp index f58bc1e838..186bba2e5b 100644 --- a/libraries/script-engine/src/v8/ScriptEngineV8.cpp +++ b/libraries/script-engine/src/v8/ScriptEngineV8.cpp @@ -339,7 +339,7 @@ Lambda::~Lambda() { } Lambda::Lambda(ScriptEngineV8* engine, - std::function operation, + std::function operation, V8ScriptValue data) : _engine(engine), _operation(operation), _data(data) { @@ -1056,7 +1056,7 @@ ScriptValue ScriptEngineV8::evaluate(const QString& sourceCode, const QString& f _evaluatingCounter--; return err; } - qCDebug(scriptengine) << "Script compilation succesful: " << fileName; + //qCDebug(scriptengine) << "Script compilation succesful: " << fileName; //V8TODO /*auto syntaxError = lintScript(sourceCode, fileName); @@ -1599,7 +1599,7 @@ int ScriptEngineV8::uncaughtExceptionLineNumber() const { bool ScriptEngineV8::raiseException(const ScriptValue& exception) { //V8TODO //Q_ASSERT(false); - qCritical() << "Script exception occured: " << exception.toString(); + qCritical() << "Script exception occurred: " << exception.toString(); /*ScriptValueV8Wrapper* unwrapped = ScriptValueV8Wrapper::unwrap(exception); V8ScriptValue qException = unwrapped ? unwrapped->toV8Value() : QScriptEngine::newVariant(exception.toVariant()); return raiseException(qException);*/ diff --git a/libraries/script-engine/src/v8/ScriptEngineV8_cast.cpp b/libraries/script-engine/src/v8/ScriptEngineV8_cast.cpp index 45e6e93108..5b550eef0f 100644 --- a/libraries/script-engine/src/v8/ScriptEngineV8_cast.cpp +++ b/libraries/script-engine/src/v8/ScriptEngineV8_cast.cpp @@ -343,7 +343,8 @@ bool ScriptEngineV8::castValueToVariant(const V8ScriptValue& v8Val, QVariant& de _customTypeProtect.unlock(); } if (demarshalFunc) { - dest = QVariant(destTypeId, static_cast(NULL)); + //dest = QVariant(destTypeId, static_cast(NULL)); + dest = QVariant(); ScriptValue wrappedVal(new ScriptValueV8Wrapper(this, v8Val)); //Q_ASSERT(dest.constData() != nullptr); bool success = demarshalFunc(wrappedVal, dest); @@ -464,6 +465,14 @@ bool ScriptEngineV8::castValueToVariant(const V8ScriptValue& v8Val, QVariant& de dest = QVariant::fromValue(static_cast(val->ToUint32(context).ToLocalChecked()->Value())); break; case QMetaType::QObjectStar: + { + // V8TODO: this is to diagnose a really weird segfault where it looks like only half of the QPointer is set to null upon object deletion + uint64_t ptrVal = (uint64_t)(ScriptObjectV8Proxy::unwrap(v8Val)); + if ((uint32_t)(ptrVal) == 0 && ptrVal != 0) { + printf("break"); + Q_ASSERT(false); + } + } dest = QVariant::fromValue(ScriptObjectV8Proxy::unwrap(v8Val)); break; case QMetaType::QVariant: diff --git a/libraries/script-engine/src/v8/ScriptObjectV8Proxy.cpp b/libraries/script-engine/src/v8/ScriptObjectV8Proxy.cpp index 2c3f551ea6..4f9a4dbb43 100644 --- a/libraries/script-engine/src/v8/ScriptObjectV8Proxy.cpp +++ b/libraries/script-engine/src/v8/ScriptObjectV8Proxy.cpp @@ -21,9 +21,11 @@ #include "ScriptContextV8Wrapper.h" #include "ScriptValueV8Wrapper.h" -Q_DECLARE_METATYPE(V8ScriptContext*) +//V8TODO: is this needed for anything? It could cause trouble with multithreading if V8ScriptContext is v8::Persistent +//Q_DECLARE_METATYPE(V8ScriptContext*) + Q_DECLARE_METATYPE(ScriptValue) -//V8TODO? +//V8TODO: default constructor would be needed //Q_DECLARE_METATYPE(V8ScriptValue) Q_DECLARE_METATYPE(QSharedPointer) @@ -60,8 +62,8 @@ private: // storage }; ScriptObjectV8Proxy::ScriptObjectV8Proxy(ScriptEngineV8* engine, QObject* object, bool ownsObject, const ScriptEngine::QObjectWrapOptions& options) : - _engine(engine), _wrapOptions(options), _ownsObject(ownsObject), _object(object), - _v8ObjectTemplate(engine->getIsolate(), v8::ObjectTemplate::New(engine->getIsolate())) { + _engine(engine), _wrapOptions(options), _ownsObject(ownsObject), _object(object) { + //_v8ObjectTemplate(engine->getIsolate(), v8::ObjectTemplate::New(engine->getIsolate()) investigate(); } @@ -147,6 +149,9 @@ 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->IsNullOrUndefined()) { + return nullptr; + } if (!v8Value->IsObject()) { //qDebug(scriptengine) << "Cannot unwrap proxy - value is not an object"; return nullptr; @@ -170,6 +175,10 @@ ScriptObjectV8Proxy* ScriptObjectV8Proxy::unwrapProxy(v8::Isolate* isolate, v8:: //V8TODO: shouldn't there be context scope here? //v8::Local context = val.constGetContext(); //v8::Context::Scope contextScope(context); + if (value->IsNullOrUndefined()) { + //qDebug(scriptengine) << "Cannot unwrap proxy - value is not an object"; + return nullptr; + } if (!value->IsObject()) { //qDebug(scriptengine) << "Cannot unwrap proxy - value is not an object"; return nullptr; @@ -201,7 +210,10 @@ ScriptObjectV8Proxy::~ScriptObjectV8Proxy() { void ScriptObjectV8Proxy::investigate() { QObject* qobject = _object; - Q_ASSERT(qobject); + if (!qobject) { + QStringList backtrace = _engine->currentContext()->backtrace(); + qDebug(scriptengine) << "ScriptObjectV8Proxy::investigate: Object pointer is NULL, " << backtrace; + } if (!qobject) return; auto isolate = _engine->getIsolate(); @@ -210,7 +222,8 @@ void ScriptObjectV8Proxy::investigate() { v8::HandleScope handleScope(_engine->getIsolate()); v8::Context::Scope contextScope(_engine->getContext()); - auto objectTemplate = _v8ObjectTemplate.Get(_engine->getIsolate()); + //auto objectTemplate = _v8ObjectTemplate.Get(_engine->getIsolate()); + auto objectTemplate = v8::ObjectTemplate::New(_engine->getIsolate()); objectTemplate->SetInternalFieldCount(3); objectTemplate->SetHandler(v8::NamedPropertyHandlerConfiguration(v8Get, v8Set)); diff --git a/libraries/script-engine/src/v8/ScriptObjectV8Proxy.h b/libraries/script-engine/src/v8/ScriptObjectV8Proxy.h index d88ca24883..94893ed3a2 100644 --- a/libraries/script-engine/src/v8/ScriptObjectV8Proxy.h +++ b/libraries/script-engine/src/v8/ScriptObjectV8Proxy.h @@ -113,7 +113,7 @@ private: // storage const bool _ownsObject; QPointer _object; // V8TODO Is this necessary? - v8::UniquePersistent _v8ObjectTemplate; + // v8::UniquePersistent _v8ObjectTemplate; // Handle for its own object v8::UniquePersistent _v8Object; int pointerCorruptionTest = 12345678; diff --git a/libraries/script-engine/src/v8/ScriptValueIteratorV8Wrapper.h b/libraries/script-engine/src/v8/ScriptValueIteratorV8Wrapper.h index 5ce7a8f4c4..5912c3af85 100644 --- a/libraries/script-engine/src/v8/ScriptValueIteratorV8Wrapper.h +++ b/libraries/script-engine/src/v8/ScriptValueIteratorV8Wrapper.h @@ -37,6 +37,7 @@ private: int _length; int _currentIndex; ScriptEngineV8 *_engine; + Q_DISABLE_COPY(V8ScriptValueIterator) }; /// [V8] Implements ScriptValueIterator for V8 and translates calls for V8ScriptValueIterator diff --git a/libraries/script-engine/src/v8/ScriptValueV8Wrapper.cpp b/libraries/script-engine/src/v8/ScriptValueV8Wrapper.cpp index 5db23d080a..f76798b45b 100644 --- a/libraries/script-engine/src/v8/ScriptValueV8Wrapper.cpp +++ b/libraries/script-engine/src/v8/ScriptValueV8Wrapper.cpp @@ -237,15 +237,15 @@ ScriptValueIteratorPointer ScriptValueV8Wrapper::newIterator() const { bool ScriptValueV8Wrapper::hasProperty(const QString& name) const { auto isolate = _engine->getIsolate(); - v8::Locker locker(_engine->getIsolate()); - v8::Isolate::Scope isolateScope(_engine->getIsolate()); + v8::Locker locker(isolate); + v8::Isolate::Scope isolateScope(isolate); v8::HandleScope handleScope(isolate); v8::Context::Scope contextScope(_engine->getContext()); //V8TODO: does function return true on IsObject too? 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(); + v8::Local key = v8::String::NewFromUtf8(isolate, name.toStdString().c_str(),v8::NewStringType::kNormal).ToLocalChecked(); const v8::Local object = v8::Local::Cast(_value.constGet()); //V8TODO: Which context? if (object->Get(_engine->getContext(), key).ToLocal(&resultLocal)) { @@ -265,6 +265,9 @@ ScriptValue ScriptValueV8Wrapper::property(const QString& name, const ScriptValu v8::Isolate::Scope isolateScope(_engine->getIsolate()); v8::HandleScope handleScope(isolate); v8::Context::Scope contextScope(_engine->getContext()); + if (_value.constGet()->IsNullOrUndefined()) { + return _engine->undefinedValue(); + } if (_value.constGet()->IsObject()) { //V8TODO: what about flags? v8::Local resultLocal; @@ -304,6 +307,10 @@ ScriptValue ScriptValueV8Wrapper::property(quint32 arrayIndex, const ScriptValue v8::Isolate::Scope isolateScope(isolate); v8::HandleScope handleScope(isolate); v8::Context::Scope contextScope(_engine->getContext()); + if (_value.constGet()->IsNullOrUndefined()) { + qDebug() << "Failed to get property, parent of value: " << arrayIndex << " is not a V8 object, reported type: " << QString(*v8::String::Utf8Value(isolate, _value.constGet()->TypeOf(isolate))); + return _engine->undefinedValue(); + } if (_value.constGet()->IsObject()) { //V8TODO: what about flags? v8::Local resultLocal; @@ -315,9 +322,6 @@ ScriptValue ScriptValueV8Wrapper::property(quint32 arrayIndex, const ScriptValue } qDebug() << "Failed to get property, parent of value: " << arrayIndex << " is not a V8 object, reported type: " << QString(*v8::String::Utf8Value(isolate, _value.constGet()->TypeOf(isolate))); return _engine->undefinedValue(); - /*v8::Local nullValue = v8::Null(_engine->getIsolate()); - V8ScriptValue nullScriptValue(_engine->getIsolate(), std::move(nullValue)); - return ScriptValue(new ScriptValueV8Wrapper(_engine, nullScriptValue));*/ } void ScriptValueV8Wrapper::setData(const ScriptValue& value) { @@ -329,6 +333,10 @@ void ScriptValueV8Wrapper::setData(const ScriptValue& value) { V8ScriptValue unwrapped = fullUnwrap(value); // V8TODO Check if it uses same isolate. Would pointer check be enough? // Private properties are an experimental feature for now on V8, so we are using regular value for now + if (_value.constGet()->IsNullOrUndefined()) { + qDebug() << "ScriptValueV8Wrapper::setData() was called on a value that is null or undefined"; + return; + } if (_value.constGet()->IsObject()) { auto v8Object = v8::Local::Cast(_value.constGet()); if( !v8Object->Set(_engine->getContext(), v8::String::NewFromUtf8(isolate, "__data").ToLocalChecked(), unwrapped.constGet()).FromMaybe(false)) { @@ -349,6 +357,10 @@ void ScriptValueV8Wrapper::setProperty(const QString& name, const ScriptValue& v v8::HandleScope handleScope(isolate); v8::Context::Scope contextScope(_engine->getContext()); V8ScriptValue unwrapped = fullUnwrap(value); + if (_value.constGet()->IsNullOrUndefined()) { + qDebug() << "ScriptValueV8Wrapper::setProperty() was called on a value that is null or undefined"; + return; + } if(_value.constGet()->IsObject()) { v8::Local key = v8::String::NewFromUtf8(isolate, name.toStdString().c_str(),v8::NewStringType::kNormal).ToLocalChecked(); Q_ASSERT(_value.get()->IsObject()); @@ -381,6 +393,10 @@ void ScriptValueV8Wrapper::setProperty(quint32 arrayIndex, const ScriptValue& va v8::HandleScope handleScope(isolate); v8::Context::Scope contextScope(_engine->getContext()); V8ScriptValue unwrapped = fullUnwrap(value); + if (_value.constGet()->IsNullOrUndefined()) { + qDebug() << "ScriptValueV8Wrapper::setProperty() was called on a value that is null or undefined"; + return; + } if(_value.constGet()->IsObject()) { auto object = v8::Local::Cast(_value.get()); //V8TODO: I don't know which context to use here @@ -404,6 +420,9 @@ void ScriptValueV8Wrapper::setPrototype(const ScriptValue& prototype) { v8::Context::Scope contextScope(_engine->getContext()); ScriptValueV8Wrapper* unwrappedPrototype = unwrap(prototype); if (unwrappedPrototype) { + if(unwrappedPrototype->toV8Value().constGet()->IsNullOrUndefined() && _value.constGet()->IsNullOrUndefined()) { + qDebug(scriptengine) << "Failed to assign prototype - one of values is null or undefined"; + } if(unwrappedPrototype->toV8Value().constGet()->IsObject() && _value.constGet()->IsObject()) { auto object = v8::Local::Cast(_value.get()); //V8TODO: I don't know which context to use here @@ -526,7 +545,11 @@ QVariant ScriptValueV8Wrapper::toVariant() const { QObject* ScriptValueV8Wrapper::toQObject() const { QVariant dest; if (_engine->castValueToVariant(_value, dest, QMetaType::QObjectStar)) { - return dest.value(); + if (dest.canConvert()) { + return dest.value(); + } else { + Q_ASSERT(false); + } } else { Q_ASSERT(false); return nullptr; diff --git a/libraries/script-engine/src/v8/ScriptValueV8Wrapper.h b/libraries/script-engine/src/v8/ScriptValueV8Wrapper.h index 44ac8533a8..9c68084f81 100644 --- a/libraries/script-engine/src/v8/ScriptValueV8Wrapper.h +++ b/libraries/script-engine/src/v8/ScriptValueV8Wrapper.h @@ -30,7 +30,6 @@ class ScriptValueV8Wrapper final : public ScriptValueProxy { public: // construction inline ScriptValueV8Wrapper(ScriptEngineV8* engine, const V8ScriptValue& value) : _engine(engine), _value(value) {} -// _engine(engine), _value(std::move(value.copy())) {} inline ScriptValueV8Wrapper(ScriptEngineV8* engine, V8ScriptValue&& value) : _engine(engine), _value(std::move(value)) {} static ScriptValueV8Wrapper* unwrap(const ScriptValue& val); diff --git a/libraries/script-engine/src/v8/V8Lambda.h b/libraries/script-engine/src/v8/V8Lambda.h index 1f30177c16..1453d03a96 100644 --- a/libraries/script-engine/src/v8/V8Lambda.h +++ b/libraries/script-engine/src/v8/V8Lambda.h @@ -25,7 +25,7 @@ class Lambda : public QObject { Q_OBJECT public: Lambda(ScriptEngineV8* engine, - std::function operation, + std::function operation, V8ScriptValue data); ~Lambda(); public slots: @@ -34,7 +34,7 @@ public slots: private: ScriptEngineV8* _engine; - std::function _operation; + std::function _operation; V8ScriptValue _data; }; diff --git a/libraries/script-engine/src/v8/V8Types.h b/libraries/script-engine/src/v8/V8Types.h index d494e8af26..fa33f95605 100644 --- a/libraries/script-engine/src/v8/V8Types.h +++ b/libraries/script-engine/src/v8/V8Types.h @@ -31,7 +31,17 @@ public: v8::Isolate::Scope isolateScope(_engine->getIsolate()); v8::HandleScope handleScope(_engine->getIsolate()); v8::Context::Scope(_engine->getContext()); - _value.reset(new v8::UniquePersistent(_engine->getIsolate(), std::move(value))); + _value.reset(new v8::UniquePersistent(_engine->getIsolate(), value)); + }; + + V8ScriptValueTemplate& operator= (const V8ScriptValueTemplate &source) { + v8::Locker locker(_engine->getIsolate()); + v8::Isolate::Scope isolateScope(_engine->getIsolate()); + v8::HandleScope handleScope(_engine->getIsolate()); + v8::Context::Scope(_engine->getContext()); + _engine = source.getEngine(); + _value.reset(new v8::UniquePersistent(_engine->getIsolate(), source.constGet())); + return *this; }; V8ScriptValueTemplate(ScriptEngineV8 *engine) : _engine(engine) { @@ -47,7 +57,7 @@ public: v8::Isolate::Scope isolateScope(_engine->getIsolate()); v8::HandleScope handleScope(_engine->getIsolate()); v8::Context::Scope(_engine->getContext()); - _value.reset(new v8::UniquePersistent(_engine->getIsolate(), std::move(copied.constGet()))); + _value.reset(new v8::UniquePersistent(_engine->getIsolate(), copied.constGet())); } v8::Local get() { @@ -92,6 +102,7 @@ public: void reset(v8::Isolate *isolate, v8::Local) { Q_ASSERT(false); }; + private: std::shared_ptr> _value; // V8TODO: maybe make it weak @@ -105,19 +116,25 @@ private: //typedef V8ScriptValueTemplate V8ScriptValue; //typedef V8ScriptValueTemplate V8ScriptProgram; // V8TODO: Maybe weak? -typedef v8::Persistent V8ScriptContext; +//typedef v8::Persistent V8ScriptContext; class V8ScriptString : public V8ScriptValueTemplate { public: V8ScriptString() = delete; V8ScriptString(ScriptEngineV8 *engine, const v8::Local value) : V8ScriptValueTemplate(engine, value) {}; const QString toQString() const { - Q_ASSERT(constGetIsolate()->IsCurrent()); + v8::Locker locker(getEngine()->getIsolate()); + v8::Isolate::Scope isolateScope(getEngine()->getIsolate()); + v8::HandleScope handleScope(getEngine()->getIsolate()); + v8::Context::Scope(getEngine()->getContext()); Q_ASSERT(constGet()->IsString()); return QString(*v8::String::Utf8Value(const_cast(constGetIsolate()), constGet())); }; bool operator==(const V8ScriptString& string) const { - Q_ASSERT(constGetIsolate()->IsCurrent()); + v8::Locker locker(getEngine()->getIsolate()); + v8::Isolate::Scope isolateScope(getEngine()->getIsolate()); + v8::HandleScope handleScope(getEngine()->getIsolate()); + v8::Context::Scope(getEngine()->getContext()); Q_ASSERT(constGet()->IsString()); return constGet()->StringEquals(string.constGet()); } diff --git a/scripts/system/controllers/controllerModules/inEditMode.js b/scripts/system/controllers/controllerModules/inEditMode.js index 39fa19c329..5150e84c72 100644 --- a/scripts/system/controllers/controllerModules/inEditMode.js +++ b/scripts/system/controllers/controllerModules/inEditMode.js @@ -72,14 +72,17 @@ Script.include("/~/system/libraries/utils.js"); if (controllerData.triggerClicks[this.hand]) { var hand = this.hand === RIGHT_HAND ? Controller.Standard.RightHand : Controller.Standard.LeftHand; if (!this.triggerClicked) { + print("inEditMode click"); this.selectedTarget = controllerData.rayPicks[this.hand]; if (!this.selectedTarget.intersects) { + print("inEditMode no intersect"); Messages.sendLocalMessage(this.ENTITY_TOOL_UPDATES_CHANNEL, JSON.stringify({ method: "clearSelection", hand: hand })); } else { if (this.selectedTarget.type === Picks.INTERSECTED_ENTITY) { + print("inEditMode select entity"); Messages.sendLocalMessage(this.ENTITY_TOOL_UPDATES_CHANNEL, JSON.stringify({ method: "selectEntity", entityID: this.selectedTarget.objectID, @@ -88,6 +91,7 @@ Script.include("/~/system/libraries/utils.js"); intersection: this.selectedTarget.intersection })); } else if (this.selectedTarget.type === Picks.INTERSECTED_OVERLAY) { + print("inEditMode select overlay"); Messages.sendLocalMessage(this.ENTITY_TOOL_UPDATES_CHANNEL, JSON.stringify({ method: "selectOverlay", overlayID: this.selectedTarget.objectID,