History

Fixed evaluateInClosure and other V8 stuff

ksuprynowicz committed 3 years ago

Commit 70d4a431 parent cc20ced8 files · +378 −191Browse files

Showing the changes to libraries/script-engine/src/v8/ScriptEngineV8.cpp (1 of 8 files). Show all

Unified · Split

libraries/script-engine/src/v8/ScriptEngineV8.cpp+270−144
@@ -113,6 +113,8 @@ ScriptValue ScriptEngineV8::makeError(const ScriptValue& _other, const QString& · 112 unmodified lines
113113 if (!IS_THREADSAFE_INVOCATION(thread(), __FUNCTION__)) {
114114 return nullValue();
115115 }
116+ v8::Locker locker(_v8Isolate);
117+ v8::Isolate::Scope isolateScope(_v8Isolate);
116118 v8::HandleScope handleScope(_v8Isolate);
117119 v8::Context::Scope contextScope(_v8Context.Get(_v8Isolate));
118120 return nullValue();
@@ -138,6 +140,8 @@ ScriptValue ScriptEngineV8::checkScriptSyntax(ScriptProgramPointer program) { · 19 unmodified lines
138140 if (!IS_THREADSAFE_INVOCATION(thread(), __FUNCTION__)) {
139141 return nullValue();
140142 }
143+ v8::Locker locker(_v8Isolate);
144+ v8::Isolate::Scope isolateScope(_v8Isolate);
141145 v8::HandleScope handleScope(_v8Isolate);
142146 v8::Context::Scope contextScope(_v8Context.Get(_v8Isolate));
143147 ScriptSyntaxCheckResultPointer syntaxCheck = program->checkSyntax();
@@ -194,6 +198,8 @@ ScriptValue ScriptEngineV8::cloneUncaughtException(const QString& extraDetail) { · 50 unmodified lines
194198 if (!hasUncaughtException()) {
195199 return nullValue();
196200 }
201+ v8::Locker locker(_v8Isolate);
202+ v8::Isolate::Scope isolateScope(_v8Isolate);
197203 v8::HandleScope handleScope(_v8Isolate);
198204 v8::Context::Scope contextScope(_v8Context.Get(_v8Isolate));
199205 return nullValue();
@@ -343,7 +349,8 @@ V8ScriptValue Lambda::call() { · 143 unmodified lines
343349
344350 #ifdef DEBUG_JS
345351 void ScriptEngineV8::_debugDump(const QString& header, const V8ScriptValue& object, const QString& footer) {
346− if (!IS_THREADSAFE_INVOCATION(thread(), __FUNCTION__)) {
352+ // V8TODO
353+ /*if (!IS_THREADSAFE_INVOCATION(thread(), __FUNCTION__)) {
347354 return;
348355 }
349356 if (!header.isEmpty()) {
@@ -360,7 +367,7 @@ void ScriptEngineV8::_debugDump(const QString& header, const V8ScriptValue& obje · 10 unmodified lines
360367 }
361368 if (!footer.isEmpty()) {
362369 qCDebug(shared) << footer;
363− }
370+ }*/
364371 }
365372 #endif
366373
@@ -370,7 +377,7 @@ v8::Platform* ScriptEngineV8::getV8Platform() { · 3 unmodified lines
370377 }
371378
372379 ScriptEngineV8::ScriptEngineV8(ScriptManager* scriptManager) :
373− _scriptManager(scriptManager), _isEvaluating(false)
380+ _scriptManager(scriptManager), _evaluatingCounter(0)
374381 //V8TODO
375382 //_arrayBufferClass(new ArrayBufferClass(this))
376383 {
@@ -395,7 +402,8 @@ ScriptEngineV8::ScriptEngineV8(ScriptManager* scriptManager) : · 18 unmodified lines
395402 v8::Isolate::CreateParams isolateParams;
396403 isolateParams.array_buffer_allocator = v8::ArrayBuffer::Allocator::NewDefaultAllocator();
397404 _v8Isolate = v8::Isolate::New(isolateParams);
398− _v8Isolate->Enter();
405+ v8::Locker locker(_v8Isolate);
406+ v8::Isolate::Scope isolateScope(_v8Isolate);
399407 v8::HandleScope handleScope(_v8Isolate);
400408 v8::Local<v8::Context> context = v8::Context::New(_v8Isolate);
401409 Q_ASSERT(!context.IsEmpty());
@@ -447,6 +455,8 @@ void ScriptEngineV8::registerEnum(const QString& enumName, QMetaEnum newEnum) { · 45 unmodified lines
447455 qCCritical(scriptengine) << "registerEnum called on invalid enum with name " << enumName;
448456 return;
449457 }
458+ v8::Locker locker(_v8Isolate);
459+ v8::Isolate::Scope isolateScope(_v8Isolate);
450460 v8::HandleScope handleScope(_v8Isolate);
451461 v8::Context::Scope contextScope(_v8Context.Get(_v8Isolate));
452462
@@ -467,6 +477,8 @@ void ScriptEngineV8::registerValue(const QString& valueName, V8ScriptValue value · 14 unmodified lines
467477 Q_ARG(V8ScriptValue, value));
468478 return;
469479 }
480+ v8::Locker locker(_v8Isolate);
481+ v8::Isolate::Scope isolateScope(_v8Isolate);
470482 v8::HandleScope handleScope(_v8Isolate);
471483 v8::Context::Scope contextScope(_v8Context.Get(_v8Isolate));
472484 QStringList pathToValue = valueName.split(".");
@@ -514,34 +526,36 @@ void ScriptEngineV8::registerGlobalObject(const QString& name, QObject* object) · 41 unmodified lines
514526 #ifdef THREAD_DEBUGGING
515527 qCDebug(scriptengine) << "ScriptEngineV8::registerGlobalObject() called on thread [" << QThread::currentThread() << "] name:" << name;
516528 #endif
517− bool is_isolate_exit_needed = false;
529+ /*bool is_isolate_exit_needed = false;
518530 if(!_v8Isolate->IsCurrent() && !_v8Locker) {
519531 // V8TODO: Theoretically only script thread should access this, so it should be safe
520532 _v8Locker.reset(new v8::Locker(_v8Isolate));
521533 _v8Isolate->Enter();
522534 is_isolate_exit_needed = true;
523− }
524− {
525− v8::HandleScope handleScope(_v8Isolate);
526− Q_ASSERT(_v8Isolate->IsCurrent());
527− v8::Context::Scope contextScope(_v8Context.Get(_v8Isolate));
528− v8::Local<v8::Object> v8GlobalObject = getContext()->Global();
529− v8::Local<v8::String> v8Name = v8::String::NewFromUtf8(_v8Isolate, name.toStdString().c_str()).ToLocalChecked();
530−
531− // V8TODO: Is IsEmpty check enough or IsValid is needed too?
532− if (!v8GlobalObject->Get(getContext(), v8Name).IsEmpty()) {
533− if (object) {
534− V8ScriptValue value = ScriptObjectV8Proxy::newQObject(this, object, ScriptEngine::QtOwnership);
535− v8GlobalObject->Set(getContext(), v8Name, value.get());
536− } else {
537− v8GlobalObject->Set(getContext(), v8Name, v8::Null(_v8Isolate));
538− }
535+ }*/
536+ //{
537+ v8::Locker locker(_v8Isolate);
538+ v8::Isolate::Scope isolateScope(_v8Isolate);
539+ v8::HandleScope handleScope(_v8Isolate);
540+ Q_ASSERT(_v8Isolate->IsCurrent());
541+ v8::Context::Scope contextScope(_v8Context.Get(_v8Isolate));
542+ v8::Local<v8::Object> v8GlobalObject = getContext()->Global();
543+ v8::Local<v8::String> v8Name = v8::String::NewFromUtf8(_v8Isolate, name.toStdString().c_str()).ToLocalChecked();
544+
545+ // V8TODO: Is IsEmpty check enough or IsValid is needed too?
546+ if (!v8GlobalObject->Get(getContext(), v8Name).IsEmpty()) {
547+ if (object) {
548+ V8ScriptValue value = ScriptObjectV8Proxy::newQObject(this, object, ScriptEngine::QtOwnership);
549+ v8GlobalObject->Set(getContext(), v8Name, value.get());
550+ } else {
551+ v8GlobalObject->Set(getContext(), v8Name, v8::Null(_v8Isolate));
539552 }
540553 }
541− if (is_isolate_exit_needed) {
554+ //}
555+ /*if (is_isolate_exit_needed) {
542556 _v8Isolate->Exit();
543557 _v8Locker.reset(nullptr);
544− }
558+ }*/
545559 }
546560
547561 void ScriptEngineV8::registerFunction(const QString& name, ScriptEngine::FunctionSignature functionSignature, int numArguments) {
@@ -561,26 +575,28 @@ void ScriptEngineV8::registerFunction(const QString& name, ScriptEngine::Functio · 13 unmodified lines
561575 qCDebug(scriptengine) << "ScriptEngineV8::registerFunction() called on thread [" << QThread::currentThread() << "] name:" << name;
562576 #endif
563577
564− bool is_isolate_exit_needed = false;
578+ /*bool is_isolate_exit_needed = false;
565579 if(!_v8Isolate->IsCurrent() && !_v8Locker) {
566580 // V8TODO: Theoretically only script thread should access this, so it should be safe
567581 _v8Locker.reset(new v8::Locker(_v8Isolate));
568582 _v8Isolate->Enter();
569583 is_isolate_exit_needed = true;
570584 }
571− {
585+ {*/
572586 //auto scriptFun = static_cast<ScriptValueV8Wrapper*>(newFunction(functionSignature, numArguments).ptr())->toV8Value().constGet();
573− v8::HandleScope handleScope(_v8Isolate);
574− v8::Context::Scope contextScope(_v8Context.Get(_v8Isolate));
575− auto scriptFun = newFunction(functionSignature, numArguments);
587+ v8::Locker locker(_v8Isolate);
588+ v8::Isolate::Scope isolateScope(_v8Isolate);
589+ v8::HandleScope handleScope(_v8Isolate);
590+ v8::Context::Scope contextScope(_v8Context.Get(_v8Isolate));
591+ auto scriptFun = newFunction(functionSignature, numArguments);
576592
577− //getContext()->Global().Set();
578− globalObject().setProperty(name, scriptFun);
579− }
593+ //getContext()->Global().Set();
594+ globalObject().setProperty(name, scriptFun);
595+ /*}
580596 if (is_isolate_exit_needed) {
581597 _v8Isolate->Exit();
582598 _v8Locker.reset(nullptr);
583− }
599+ }*/
584600 }
585601
586602 void ScriptEngineV8::registerFunction(const QString& parent, const QString& name, ScriptEngine::FunctionSignature functionSignature, int numArguments) {
@@ -598,26 +614,28 @@ void ScriptEngineV8::registerFunction(const QString& parent, const QString& name · 11 unmodified lines
598614 qCDebug(scriptengine) << "ScriptEngineV8::registerFunction() called on thread [" << QThread::currentThread() << "] parent:" << parent << "name:" << name;
599615 #endif
600616
601− bool is_isolate_exit_needed = false;
617+ /*bool is_isolate_exit_needed = false;
602618 if(!_v8Isolate->IsCurrent() && !_v8Locker) {
603619 // V8TODO: Theoretically only script thread should access this, so it should be safe
604620 _v8Locker.reset(new v8::Locker(_v8Isolate));
605621 _v8Isolate->Enter();
606622 is_isolate_exit_needed = true;
607623 }
608− {
609− v8::HandleScope handleScope(_v8Isolate);
610− v8::Context::Scope contextScope(_v8Context.Get(_v8Isolate));
611− ScriptValue object = globalObject().property(parent);
612− if (object.isValid()) {
613− ScriptValue scriptFun = newFunction(functionSignature, numArguments);
614− object.setProperty(name, scriptFun);
615− }
624+ {*/
625+ v8::Locker locker(_v8Isolate);
626+ v8::Isolate::Scope isolateScope(_v8Isolate);
627+ v8::HandleScope handleScope(_v8Isolate);
628+ v8::Context::Scope contextScope(_v8Context.Get(_v8Isolate));
629+ ScriptValue object = globalObject().property(parent);
630+ if (object.isValid()) {
631+ ScriptValue scriptFun = newFunction(functionSignature, numArguments);
632+ object.setProperty(name, scriptFun);
616633 }
634+ /*}
617635 if (is_isolate_exit_needed) {
618636 _v8Isolate->Exit();
619637 _v8Locker.reset(nullptr);
620− }
638+ }*/
621639 }
622640
623641 void ScriptEngineV8::registerGetterSetter(const QString& name, ScriptEngine::FunctionSignature getter,
@@ -638,14 +656,16 @@ void ScriptEngineV8::registerGetterSetter(const QString& name, ScriptEngine::Fun · 14 unmodified lines
638656 qCDebug(scriptengine) << "ScriptEngineV8::registerGetterSetter() called on thread [" << QThread::currentThread() << "] name:" << name << "parent:" << parent;
639657 #endif
640658
641− bool is_isolate_exit_needed = false;
659+ /*bool is_isolate_exit_needed = false;
642660 if(!_v8Isolate->IsCurrent() && !_v8Locker) {
643661 // V8TODO: Theoretically only script thread should access this, so it should be safe
644662 _v8Locker.reset(new v8::Locker(_v8Isolate));
645663 _v8Isolate->Enter();
646664 is_isolate_exit_needed = true;
647665 }
648− {
666+ {*/
667+ v8::Locker locker(_v8Isolate);
668+ v8::Isolate::Scope isolateScope(_v8Isolate);
649669 v8::HandleScope handleScope(_v8Isolate);
650670 v8::Context::Scope contextScope(getContext());
651671
@@ -717,11 +737,11 @@ void ScriptEngineV8::registerGetterSetter(const QString& name, ScriptEngine::Fun · 65 unmodified lines
717737 //globalObject().setProperty(name, setterFunction, ScriptValue::PropertySetter);
718738 //globalObject().setProperty(name, getterFunction, ScriptValue::PropertyGetter);
719739 }
720− }
740+ /*}
721741 if (is_isolate_exit_needed) {
722742 _v8Isolate->Exit();
723743 _v8Locker.reset(nullptr);
724− }
744+ }*/
725745 }
726746
727747 ScriptValue ScriptEngineV8::evaluateInClosure(const ScriptValue& _closure,
@@ -730,42 +750,59 @@ ScriptValue ScriptEngineV8::evaluateInClosure(const ScriptValue& _closure, · 2 unmodified lines
730750 if (!IS_THREADSAFE_INVOCATION(thread(), __FUNCTION__)) {
731751 return nullValue();
732752 }
733− Q_ASSERT(!isEvaluating());
734− _isEvaluating = true;
753+ _evaluatingCounter++;
754+ v8::Locker locker(_v8Isolate);
755+ v8::Isolate::Scope isolateScope(_v8Isolate);
735756 v8::HandleScope handleScope(_v8Isolate);
736− v8::Context::Scope contextScope(_v8Context.Get(_v8Isolate));
737− ScriptProgramV8Wrapper* unwrappedProgram = ScriptProgramV8Wrapper::unwrap(_program);
738− if (unwrappedProgram == nullptr) {
739− _isEvaluating = false;
740− return nullValue();
741− }
742− const V8ScriptProgram& program = unwrappedProgram->toV8Value();
743757
744− const auto fileName = unwrappedProgram->fileName();
745− const auto shortName = QUrl(fileName).fileName();
758+ v8::Local<v8::Object> closureObject;
759+ //v8::Local<v8::Value> oldGlobal;
760+ v8::Local<v8::Value> closureGlobal;
761+ ScriptValueV8Wrapper* unwrappedClosure;
762+ ScriptProgramV8Wrapper* unwrappedProgram;
746763
747− ScriptValueV8Wrapper* unwrappedClosure = ScriptValueV8Wrapper::unwrap(_closure);
748− if (unwrappedClosure == nullptr) {
749− _isEvaluating = false;
750− return nullValue();
751− }
752− const V8ScriptValue& closure = unwrappedClosure->toV8Value();
753− if (!closure.constGet()->IsObject()) {
754− _isEvaluating = false;
755− return nullValue();
756− }
757− const v8::Local<v8::Object> closureObject = v8::Local<v8::Object>::Cast(closure.constGet());
764+ {
765+ v8::Context::Scope contextScope(_v8Context.Get(_v8Isolate));
766+ unwrappedProgram = ScriptProgramV8Wrapper::unwrap(_program);
767+ if (unwrappedProgram == nullptr) {
768+ _evaluatingCounter--;
769+ qDebug(scriptengine) << "Cannot unwrap program for closure";
770+ Q_ASSERT(false);
771+ return nullValue();
772+ }
773+ // V8TODO: is another context switch necessary after unwrapping closure?
758774
759− v8::Local<v8::Value> oldGlobal;
760− v8::Local<v8::Value> closureGlobal;
761− if (!closureObject->Get(closure.constGetContext() ,v8::String::NewFromUtf8(_v8Isolate, "global").ToLocalChecked()).ToLocal(&closureGlobal)) {
762− _isEvaluating = false;
763− return nullValue();
764− }
775+ const auto fileName = unwrappedProgram->fileName();
776+ const auto shortName = QUrl(fileName).fileName();
765777
766− _v8Context.Get(_v8Isolate)->Exit();
767− _v8Context.Get(_v8Isolate)->DetachGlobal();
768− oldGlobal = _v8Context.Get(_v8Isolate)->Global();
778+ unwrappedClosure = ScriptValueV8Wrapper::unwrap(_closure);
779+ if (unwrappedClosure == nullptr) {
780+ _evaluatingCounter--;
781+ qDebug(scriptengine) << "Cannot unwrap closure";
782+ Q_ASSERT(false);
783+ return nullValue();
784+ }
785+
786+ const V8ScriptValue& closure = unwrappedClosure->toV8Value();
787+ const V8ScriptProgram& program = unwrappedProgram->toV8Value();
788+ if (!closure.constGet()->IsObject()) {
789+ _evaluatingCounter--;
790+ qDebug(scriptengine) << "Unwrapped closure is not an object";
791+ Q_ASSERT(false);
792+ return nullValue();
793+ }
794+ closureObject = v8::Local<v8::Object>::Cast(closure.constGet());
795+
796+ if (!closureObject->Get(closure.constGetContext(), v8::String::NewFromUtf8(_v8Isolate, "global").ToLocalChecked())
797+ .ToLocal(&closureGlobal)) {
798+ _evaluatingCounter--;
799+ qDebug(scriptengine) << "Cannot get global from unwrapped closure";
800+ Q_ASSERT(false);
801+ return nullValue();
802+ }
803+ }
804+ //_v8Context.Get(_v8Isolate)->DetachGlobal();
805+ //oldGlobal = _v8Context.Get(_v8Isolate)->Global();
769806 v8::Local<v8::Context> closureContext;
770807
771808 if (closureGlobal->IsObject()) {
@@ -775,61 +812,71 @@ ScriptValue ScriptEngineV8::evaluateInClosure(const ScriptValue& _closure, · 3 unmodified lines
775812 closureContext = v8::Context::New(_v8Isolate, nullptr, v8::Local<v8::ObjectTemplate>(), closureGlobal);
776813 //setGlobalObject(global);
777814 } else {
778− closureContext = v8::Context::New(_v8Isolate, nullptr, v8::Local<v8::ObjectTemplate>(), oldGlobal);
815+ closureContext = v8::Context::New(_v8Isolate);
779816 }
780817
818+ ScriptValue result;
781819 //auto context = pushContext();
782−
783− v8::Local<v8::Value> thiz;
784− // V8TODO: not sure if "this" doesn't exist or is empty in some cases
785− if (!closureObject->Get(closure.constGetContext() ,v8::String::NewFromUtf8(_v8Isolate, "this").ToLocalChecked()).ToLocal(&thiz)) {
786− _isEvaluating = false;
787− return nullValue();
788− }
789− //thiz = closure.property("this");
790− if (thiz->IsObject()) {
820+ {
821+ v8::Context::Scope contextScope(closureContext);
822+ const V8ScriptValue& closure = unwrappedClosure->toV8Value();
823+ if (!unwrappedProgram->compile()) {
824+ qDebug(scriptengine) << "Can't compile script for evaluating in closure";
825+ Q_ASSERT(false);
826+ return nullValue();
827+ }
828+ const V8ScriptProgram& program = unwrappedProgram->toV8Value();
829+
830+ v8::Local<v8::Value> thiz;
831+ // V8TODO: not sure if "this" doesn't exist or is empty in some cases
832+ if (!closureObject->Get(closure.constGetContext(), v8::String::NewFromUtf8(_v8Isolate, "this").ToLocalChecked())
833+ .ToLocal(&thiz)) {
834+ _evaluatingCounter--;
835+ qDebug(scriptengine) << "Empty this object in closure";
836+ Q_ASSERT(false);
837+ return nullValue();
838+ }
839+ //thiz = closure.property("this");
840+ if (thiz->IsObject()) {
791841 #ifdef DEBUG_JS
792− qCDebug(shared) << " setting this = closure.this" << shortName;
842+ qCDebug(shared) << " setting this = closure.this" << shortName;
793843 #endif
794− //V8TODO I don't know how to do this in V8, will adding "this" to global object work?
795− closureContext->Global()->Set(closureContext, v8::String::NewFromUtf8(_v8Isolate, "this").ToLocalChecked(), thiz);
796− //context->setThisObject(thiz);
797− }
844+ //V8TODO I don't know how to do this in V8, will adding "this" to global object work?
845+ closureContext->Global()->Set(closureContext, v8::String::NewFromUtf8(_v8Isolate, "this").ToLocalChecked(), thiz);
846+ //context->setThisObject(thiz);
847+ }
798848
799− //context->pushScope(closure);
849+ //context->pushScope(closure);
800850 #ifdef DEBUG_JS
801− qCDebug(shared) << QString("[%1] evaluateInClosure %2").arg(isEvaluating()).arg(shortName);
851+ qCDebug(shared) << QString("[%1] evaluateInClosure %2").arg(isEvaluating()).arg(shortName);
802852 #endif
803− ScriptValue result;
804− {
805− v8::TryCatch tryCatch(getIsolate());
806− auto maybeResult = program.constGet()->Run(closureContext);
807− v8::Local<v8::Value> v8Result;
808− if (!maybeResult.ToLocal(&v8Result)) {
809− v8::String::Utf8Value utf8Value(getIsolate(), tryCatch.Exception());
810− QString errorMessage = QString(*utf8Value);
811− qWarning() << __FUNCTION__ << "---------- hasCaught:" << errorMessage;
812− //V8TODO: better error reporting
813− }
853+ {
854+ v8::TryCatch tryCatch(getIsolate());
855+ auto maybeResult = program.constGet()->Run(closureContext);
856+ v8::Local<v8::Value> v8Result;
857+ if (!maybeResult.ToLocal(&v8Result)) {
858+ v8::String::Utf8Value utf8Value(getIsolate(), tryCatch.Exception());
859+ QString errorMessage = QString(*utf8Value);
860+ qWarning(scriptengine) << __FUNCTION__ << "---------- hasCaught:" << errorMessage;
861+ //V8TODO: better error reporting
862+ }
814863
815− if (hasUncaughtException()) {
816− auto err = cloneUncaughtException(__FUNCTION__);
864+ if (hasUncaughtException()) {
865+ auto err = cloneUncaughtException(__FUNCTION__);
817866 #ifdef DEBUG_JS_EXCEPTIONS
818− qCWarning(shared) << __FUNCTION__ << "---------- hasCaught:" << err.toString() << result.toString();
819− err.setProperty("_result", result);
867+ qCWarning(shared) << __FUNCTION__ << "---------- hasCaught:" << err.toString() << result.toString();
868+ err.setProperty("_result", result);
820869 #endif
821− result = err;
822− } else {
823− result = ScriptValue(new ScriptValueV8Wrapper(this, V8ScriptValue(_v8Isolate, v8Result)));
870+ result = err;
871+ } else {
872+ result = ScriptValue(new ScriptValueV8Wrapper(this, V8ScriptValue(_v8Isolate, v8Result)));
873+ }
824874 }
825− }
826875 #ifdef DEBUG_JS
827− qCDebug(shared) << QString("[%1] //evaluateInClosure %2").arg(isEvaluating()).arg(shortName);
876+ qCDebug(shared) << QString("[%1] //evaluateInClosure %2").arg(isEvaluating()).arg(shortName);
828877 #endif
829− //popContext();
830− closureContext->Exit();
831− _v8Context.Get(_v8Isolate)->Enter();
832−
878+ //popContext();
879+ }
833880 //This is probably unnecessary in V8
834881 /*if (oldGlobal.isValid()) {
835882 #ifdef DEBUG_JS
@@ -838,8 +885,8 @@ ScriptValue ScriptEngineV8::evaluateInClosure(const ScriptValue& _closure, · 2 unmodified lines
838885 setGlobalObject(oldGlobal);
839886 }*/
840887
841− //_v8Context.Get(_v8Isolate)->Enter();
842− _isEvaluating = false;
888+ closureContext->DetachGlobal();
889+ _evaluatingCounter--;
843890 return result;
844891 }
845892
@@ -865,8 +912,9 @@ ScriptValue ScriptEngineV8::evaluate(const QString& sourceCode, const QString& f · 19 unmodified lines
865912 // Compile and check syntax
866913 // V8TODO: Could these all be replaced with checkSyntax function from wrapper?
867914 Q_ASSERT(!_v8Isolate->IsDead());
868− Q_ASSERT(!isEvaluating());
869− _isEvaluating = true;
915+ _evaluatingCounter++;
916+ v8::Locker locker(_v8Isolate);
917+ v8::Isolate::Scope isolateScope(_v8Isolate);
870918 v8::HandleScope handleScope(_v8Isolate);
871919 v8::Context::Scope contextScope(_v8Context.Get(_v8Isolate));
872920 v8::TryCatch tryCatch(getIsolate());
@@ -896,7 +944,7 @@ ScriptValue ScriptEngineV8::evaluate(const QString& sourceCode, const QString& f · 23 unmodified lines
896944 auto err = makeError(newValue(errorMessage));
897945 raiseException(err);
898946 maybeEmitUncaughtException("compile");
899− _isEvaluating = false;
947+ _evaluatingCounter--;
900948 return err;
901949 }
902950 qCDebug(scriptengine) << "Script compilation succesful: " << fileName;
@@ -930,11 +978,11 @@ ScriptValue ScriptEngineV8::evaluate(const QString& sourceCode, const QString& f · 27 unmodified lines
930978 //V8TODO
931979 //raiseException(errorValue);
932980 //maybeEmitUncaughtException("evaluate");
933− _isEvaluating = false;
981+ _evaluatingCounter--;
934982 return errorValue;
935983 }
936984 V8ScriptValue resultValue(_v8Isolate, result);
937− _isEvaluating = false;
985+ _evaluatingCounter--;
938986 return ScriptValue(new ScriptValueV8Wrapper(this, std::move(resultValue)));
939987 }
940988
@@ -979,19 +1027,20 @@ Q_INVOKABLE ScriptValue ScriptEngineV8::evaluate(const ScriptProgramPointer& pro · 38 unmodified lines
9791027 Q_ARG(const ScriptProgramPointer&, program));
9801028 return result;
9811029 }
982− Q_ASSERT(!isEvaluating());
983− _isEvaluating = true;
984− bool is_isolate_exit_needed = false;
1030+ _evaluatingCounter++;
1031+ /*bool is_isolate_exit_needed = false;
9851032 if(!_v8Isolate->IsCurrent() && !_v8Locker) {
9861033 // V8TODO: Theoretically only script thread should access this, so it should be safe
9871034 _v8Locker.reset(new v8::Locker(_v8Isolate));
9881035 _v8Isolate->Enter();
9891036 is_isolate_exit_needed = true;
990− }
1037+ }*/
9911038 ScriptValue errorValue;
9921039 ScriptValue resultValue;
9931040 bool hasFailed = false;
9941041 {
1042+ v8::Locker locker(_v8Isolate);
1043+ v8::Isolate::Scope isolateScope(_v8Isolate);
9951044 v8::HandleScope handleScope(_v8Isolate);
9961045 v8::Context::Scope contextScope(_v8Context.Get(_v8Isolate));
9971046 ScriptProgramV8Wrapper* unwrapped = ScriptProgramV8Wrapper::unwrap(program);
@@ -1039,11 +1088,11 @@ Q_INVOKABLE ScriptValue ScriptEngineV8::evaluate(const ScriptProgramPointer& pro · 41 unmodified lines
10391088 resultValue = ScriptValue(new ScriptValueV8Wrapper(this, std::move(resultValueV8)));
10401089 }
10411090 }
1042− _isEvaluating = false;
1043− if (is_isolate_exit_needed) {
1091+ _evaluatingCounter--;
1092+ /*if (is_isolate_exit_needed) {
10441093 _v8Isolate->Exit();
10451094 _v8Locker.reset(nullptr);
1046− }
1095+ }*/
10471096 if (hasFailed) {
10481097 return errorValue;
10491098 } else {
@@ -1066,6 +1115,8 @@ void ScriptEngineV8::updateMemoryCost(const qint64& deltaSize) { · 16 unmodified lines
10661115 // ScriptEngine implementation
10671116
10681117 ScriptValue ScriptEngineV8::globalObject() const {
1118+ v8::Locker locker(_v8Isolate);
1119+ v8::Isolate::Scope isolateScope(_v8Isolate);
10691120 v8::HandleScope handleScope(_v8Isolate);
10701121 v8::Context::Scope contextScope(_v8Context.Get(_v8Isolate));
10711122 V8ScriptValue global(_v8Isolate, getConstContext()->Global());// = QScriptEngine::globalObject(); // can't cache the value as it may change
@@ -1077,6 +1128,8 @@ ScriptManager* ScriptEngineV8::manager() const { · 5 unmodified lines
10771128 }
10781129
10791130 ScriptValue ScriptEngineV8::newArray(uint length) {
1131+ v8::Locker locker(_v8Isolate);
1132+ v8::Isolate::Scope isolateScope(_v8Isolate);
10801133 v8::HandleScope handleScope(_v8Isolate);
10811134 v8::Context::Scope contextScope(_v8Context.Get(_v8Isolate));
10821135 V8ScriptValue result(_v8Isolate, v8::Array::New(_v8Isolate, static_cast<int>(length)));
@@ -1084,6 +1137,8 @@ ScriptValue ScriptEngineV8::newArray(uint length) { · 1 unmodified line
10841137 }
10851138
10861139 ScriptValue ScriptEngineV8::newArrayBuffer(const QByteArray& message) {
1140+ v8::Locker locker(_v8Isolate);
1141+ v8::Isolate::Scope isolateScope(_v8Isolate);
10871142 v8::HandleScope handleScope(_v8Isolate);
10881143 v8::Context::Scope contextScope(_v8Context.Get(_v8Isolate));
10891144 //V8TODO: this will leak memory
@@ -1101,14 +1156,33 @@ ScriptValue ScriptEngineV8::newArrayBuffer(const QByteArray& message) { · 11 unmodified lines
11011156 }
11021157
11031158 ScriptValue ScriptEngineV8::newObject() {
1104− v8::HandleScope handleScope(_v8Isolate);
1105− v8::Context::Scope contextScope(_v8Context.Get(_v8Isolate));
1106− V8ScriptValue result(_v8Isolate, v8::Object::New(_v8Isolate));
1107− return ScriptValue(new ScriptValueV8Wrapper(this, std::move(result)));
1159+ /*bool is_isolate_exit_needed = false;
1160+ if(!_v8Isolate->IsCurrent() && !_v8Locker) {
1161+ // V8TODO: Theoretically only script thread should access this, so it should be safe
1162+ _v8Locker.reset(new v8::Locker(_v8Isolate));
1163+ _v8Isolate->Enter();
1164+ is_isolate_exit_needed = true;
1165+ }*/
1166+ ScriptValue result;
1167+ {
1168+ v8::Locker locker(_v8Isolate);
1169+ v8::Isolate::Scope isolateScope(_v8Isolate);
1170+ v8::HandleScope handleScope(_v8Isolate);
1171+ v8::Context::Scope contextScope(_v8Context.Get(_v8Isolate));
1172+ V8ScriptValue resultV8 = V8ScriptValue(_v8Isolate, v8::Object::New(_v8Isolate));
1173+ result = ScriptValue(new ScriptValueV8Wrapper(this, std::move(resultV8)));
1174+ }
1175+ /*if (is_isolate_exit_needed) {
1176+ _v8Isolate->Exit();
1177+ _v8Locker.reset(nullptr);
1178+ }*/
1179+ return result;
11081180 }
11091181
11101182 ScriptValue ScriptEngineV8::newMethod(QObject* object, V8ScriptValue lifetime,
11111183 const QList<QMetaMethod>& metas, int numMaxParams) {
1184+ v8::Locker locker(_v8Isolate);
1185+ v8::Isolate::Scope isolateScope(_v8Isolate);
11121186 v8::HandleScope handleScope(_v8Isolate);
11131187 v8::Context::Scope contextScope(_v8Context.Get(_v8Isolate));
11141188 V8ScriptValue result(ScriptMethodV8Proxy::newMethod(this, object, lifetime, metas, numMaxParams));
@@ -1120,6 +1194,8 @@ ScriptProgramPointer ScriptEngineV8::newProgram(const QString& sourceCode, const · 5 unmodified lines
11201194 //V8TODO: should it be compiled on creation?
11211195 //V8ScriptProgram result(sourceCode, fileName);
11221196
1197+ v8::Locker locker(_v8Isolate);
1198+ v8::Isolate::Scope isolateScope(_v8Isolate);
11231199 v8::HandleScope handleScope(_v8Isolate);
11241200 v8::Context::Scope contextScope(_v8Context.Get(_v8Isolate));
11251201 return std::make_shared<ScriptProgramV8Wrapper>(this, sourceCode, fileName);
@@ -1128,6 +1204,8 @@ ScriptProgramPointer ScriptEngineV8::newProgram(const QString& sourceCode, const · 2 unmodified lines
11281204 ScriptValue ScriptEngineV8::newQObject(QObject* object,
11291205 ScriptEngine::ValueOwnership ownership,
11301206 const ScriptEngine::QObjectWrapOptions& options) {
1207+ v8::Locker locker(_v8Isolate);
1208+ v8::Isolate::Scope isolateScope(_v8Isolate);
11311209 v8::HandleScope handleScope(_v8Isolate);
11321210 v8::Context::Scope contextScope(_v8Context.Get(_v8Isolate));
11331211 V8ScriptValue result = ScriptObjectV8Proxy::newQObject(this, object, ownership, options);
@@ -1135,6 +1213,8 @@ ScriptValue ScriptEngineV8::newQObject(QObject* object, · 1 unmodified line
11351213 }
11361214
11371215 ScriptValue ScriptEngineV8::newValue(bool value) {
1216+ v8::Locker locker(_v8Isolate);
1217+ v8::Isolate::Scope isolateScope(_v8Isolate);
11381218 v8::HandleScope handleScope(_v8Isolate);
11391219 v8::Context::Scope contextScope(_v8Context.Get(_v8Isolate));
11401220 V8ScriptValue result(_v8Isolate, v8::Boolean::New(_v8Isolate, value));
@@ -1142,6 +1222,8 @@ ScriptValue ScriptEngineV8::newValue(bool value) { · 1 unmodified line
11421222 }
11431223
11441224 ScriptValue ScriptEngineV8::newValue(int value) {
1225+ v8::Locker locker(_v8Isolate);
1226+ v8::Isolate::Scope isolateScope(_v8Isolate);
11451227 v8::HandleScope handleScope(_v8Isolate);
11461228 v8::Context::Scope contextScope(_v8Context.Get(_v8Isolate));
11471229 V8ScriptValue result(_v8Isolate, v8::Integer::New(_v8Isolate, value));
@@ -1149,6 +1231,8 @@ ScriptValue ScriptEngineV8::newValue(int value) { · 1 unmodified line
11491231 }
11501232
11511233 ScriptValue ScriptEngineV8::newValue(uint value) {
1234+ v8::Locker locker(_v8Isolate);
1235+ v8::Isolate::Scope isolateScope(_v8Isolate);
11521236 v8::HandleScope handleScope(_v8Isolate);
11531237 v8::Context::Scope contextScope(_v8Context.Get(_v8Isolate));
11541238 V8ScriptValue result(_v8Isolate, v8::Uint32::New(_v8Isolate, value));
@@ -1156,6 +1240,8 @@ ScriptValue ScriptEngineV8::newValue(uint value) { · 1 unmodified line
11561240 }
11571241
11581242 ScriptValue ScriptEngineV8::newValue(double value) {
1243+ v8::Locker locker(_v8Isolate);
1244+ v8::Isolate::Scope isolateScope(_v8Isolate);
11591245 v8::HandleScope handleScope(_v8Isolate);
11601246 v8::Context::Scope contextScope(_v8Context.Get(_v8Isolate));
11611247 V8ScriptValue result(_v8Isolate, v8::Number::New(_v8Isolate, value));
@@ -1163,6 +1249,8 @@ ScriptValue ScriptEngineV8::newValue(double value) { · 1 unmodified line
11631249 }
11641250
11651251 ScriptValue ScriptEngineV8::newValue(const QString& value) {
1252+ v8::Locker locker(_v8Isolate);
1253+ v8::Isolate::Scope isolateScope(_v8Isolate);
11661254 v8::HandleScope handleScope(_v8Isolate);
11671255 v8::Context::Scope contextScope(_v8Context.Get(_v8Isolate));
11681256 v8::Local<v8::String> valueV8 = v8::String::NewFromUtf8(_v8Isolate, value.toStdString().c_str(), v8::NewStringType::kNormal).ToLocalChecked();
@@ -1171,6 +1259,8 @@ ScriptValue ScriptEngineV8::newValue(const QString& value) { · 2 unmodified lines
11711259 }
11721260
11731261 ScriptValue ScriptEngineV8::newValue(const QLatin1String& value) {
1262+ v8::Locker locker(_v8Isolate);
1263+ v8::Isolate::Scope isolateScope(_v8Isolate);
11741264 v8::HandleScope handleScope(_v8Isolate);
11751265 v8::Context::Scope contextScope(_v8Context.Get(_v8Isolate));
11761266 v8::Local<v8::String> valueV8 = v8::String::NewFromUtf8(_v8Isolate, value.latin1(), v8::NewStringType::kNormal).ToLocalChecked();
@@ -1179,6 +1269,8 @@ ScriptValue ScriptEngineV8::newValue(const QLatin1String& value) { · 2 unmodified lines
11791269 }
11801270
11811271 ScriptValue ScriptEngineV8::newValue(const char* value) {
1272+ v8::Locker locker(_v8Isolate);
1273+ v8::Isolate::Scope isolateScope(_v8Isolate);
11821274 v8::HandleScope handleScope(_v8Isolate);
11831275 v8::Context::Scope contextScope(_v8Context.Get(_v8Isolate));
11841276 v8::Local<v8::String> valueV8 = v8::String::NewFromUtf8(_v8Isolate, value, v8::NewStringType::kNormal).ToLocalChecked();
@@ -1187,6 +1279,8 @@ ScriptValue ScriptEngineV8::newValue(const char* value) { · 2 unmodified lines
11871279 }
11881280
11891281 ScriptValue ScriptEngineV8::newVariant(const QVariant& value) {
1282+ v8::Locker locker(_v8Isolate);
1283+ v8::Isolate::Scope isolateScope(_v8Isolate);
11901284 v8::HandleScope handleScope(_v8Isolate);
11911285 v8::Context::Scope contextScope(_v8Context.Get(_v8Isolate));
11921286 V8ScriptValue result = castVariantToValue(value);
@@ -1236,7 +1330,7 @@ bool ScriptEngineV8::hasUncaughtException() const { · 43 unmodified lines
12361330
12371331 bool ScriptEngineV8::isEvaluating() const {
12381332 //return QScriptEngine::isEvaluating();
1239− return _isEvaluating;
1333+ return _evaluatingCounter > 0;
12401334 return false;
12411335 }
12421336
@@ -1274,6 +1368,8 @@ ScriptValue ScriptEngineV8::newFunction(ScriptEngine::FunctionSignature fun, int · 31 unmodified lines
12741368 //auto functionTemplate = v8::FunctionTemplate::New(_v8Isolate, v8FunctionCallback, v8::Local<v8::Value>(), v8::Local<v8::Signature>(), length);
12751369 //auto functionData = v8::Object::New(_v8Isolate);
12761370 //functionData->setIn
1371+ v8::Locker locker(_v8Isolate);
1372+ v8::Isolate::Scope isolateScope(_v8Isolate);
12771373 v8::HandleScope handleScope(_v8Isolate);
12781374 v8::Context::Scope contextScope(_v8Context.Get(_v8Isolate));
12791375 auto functionDataTemplate = v8::ObjectTemplate::New(_v8Isolate);
@@ -1299,6 +1395,8 @@ void ScriptEngineV8::setObjectName(const QString& name) { · 19 unmodified lines
12991395
13001396 //V8TODO
13011397 bool ScriptEngineV8::setProperty(const char* name, const QVariant& value) {
1398+ v8::Locker locker(_v8Isolate);
1399+ v8::Isolate::Scope isolateScope(_v8Isolate);
13021400 v8::HandleScope handleScope(_v8Isolate);
13031401 v8::Context::Scope contextScope(_v8Context.Get(_v8Isolate));
13041402 v8::Local<v8::Object> global = getContext()->Global();
@@ -1322,14 +1420,14 @@ void ScriptEngineV8::setThread(QThread* thread) { · 17 unmodified lines
13221420 qDebug() << "Script engine " << objectName() << " exited isolate";
13231421 }
13241422 Q_ASSERT(QObject::thread() == QThread::currentThread());
1325− if (_v8Locker) {
1423+ /*if (_v8Locker) {
13261424 _v8Locker.reset();
1327− }
1425+ }*/
13281426 moveToThread(thread);
13291427 qDebug() << "Moved script engine " << objectName() << " to different thread";
13301428 }
13311429
1332−void ScriptEngineV8::enterIsolateOnThisThread() {
1430+/*void ScriptEngineV8::enterIsolateOnThisThread() {
13331431 Q_ASSERT(thread() == QThread::currentThread());
13341432 Q_ASSERT(!_v8Locker);
13351433 _v8Locker.reset(new v8::Locker(_v8Isolate));
@@ -1337,7 +1435,7 @@ void ScriptEngineV8::enterIsolateOnThisThread() { · 1 unmodified line
13371435 _v8Isolate->Enter();
13381436 qDebug() << "Script engine " << objectName() << " entered isolate on a new thread";
13391437 }
1340−}
1438+}*/
13411439
13421440
13431441 ScriptValue ScriptEngineV8::uncaughtException() const {
@@ -1367,6 +1465,8 @@ bool ScriptEngineV8::raiseException(const ScriptValue& exception) { · 23 unmodified lines
13671465 }
13681466
13691467 ScriptValue ScriptEngineV8::create(int type, const void* ptr) {
1468+ v8::Locker locker(_v8Isolate);
1469+ v8::Isolate::Scope isolateScope(_v8Isolate);
13701470 v8::HandleScope handleScope(_v8Isolate);
13711471 v8::Context::Scope contextScope(_v8Context.Get(_v8Isolate));
13721472 QVariant variant(type, ptr);
@@ -1375,6 +1475,8 @@ ScriptValue ScriptEngineV8::create(int type, const void* ptr) { · 2 unmodified lines
13751475 }
13761476
13771477 QVariant ScriptEngineV8::convert(const ScriptValue& value, int typeId) {
1478+ v8::Locker locker(_v8Isolate);
1479+ v8::Isolate::Scope isolateScope(_v8Isolate);
13781480 v8::HandleScope handleScope(_v8Isolate);
13791481 v8::Context::Scope contextScope(_v8Context.Get(_v8Isolate));
13801482 ScriptValueV8Wrapper* unwrapped = ScriptValueV8Wrapper::unwrap(value);
@@ -1397,20 +1499,44 @@ QVariant ScriptEngineV8::convert(const ScriptValue& value, int typeId) { · 16 unmodified lines
13971499 }
13981500
13991501 void ScriptEngineV8::compileTest() {
1400− //v8::Locker locker(_v8Isolate);
1401− //v8::Isolate::Scope isolateScope(_v8Isolate);
1502+ v8::Locker locker(_v8Isolate);
1503+ v8::Isolate::Scope isolateScope(_v8Isolate);
14021504 v8::HandleScope handleScope(_v8Isolate);
14031505 v8::Context::Scope contextScope(_v8Context.Get(_v8Isolate));
14041506 v8::Local<v8::Script> script;
14051507 v8::ScriptOrigin scriptOrigin(getIsolate(), v8::String::NewFromUtf8(getIsolate(),"test").ToLocalChecked());
14061508 if (v8::Script::Compile(getContext(), v8::String::NewFromUtf8(getIsolate(), "print(\"hello world\");").ToLocalChecked(), &scriptOrigin).ToLocal(&script)) {
1407− qCDebug(scriptengine) << "Compile test succesful";
1509+ qCDebug(scriptengine) << "Compile test successful";
14081510 } else {
14091511 qCDebug(scriptengine) << "Compile test failed";
14101512 Q_ASSERT(false);
14111513 }
14121514 }
14131515
1516+QString ScriptEngineV8::scriptValueDebugDetails(ScriptValue &value) {
1517+ V8ScriptValue v8Value = ScriptValueV8Wrapper::fullUnwrap(this, value);
1518+ return scriptValueDebugDetailsV8(v8Value);
1519+}
1520+
1521+QString ScriptEngineV8::scriptValueDebugDetailsV8(const V8ScriptValue &v8Value) {
1522+ v8::Locker locker(_v8Isolate);
1523+ v8::Isolate::Scope isolateScope(_v8Isolate);
1524+ v8::HandleScope handleScope(_v8Isolate);
1525+ v8::Context::Scope contextScope(getContext());
1526+
1527+ QString parentValueQString("");
1528+ v8::Local<v8::String> parentValueString;
1529+ if (v8Value.constGet()->ToDetailString(getContext()).ToLocal(&parentValueString)) {
1530+ parentValueQString = QString(*v8::String::Utf8Value(_v8Isolate, parentValueString));
1531+ }
1532+ QString JSONQString;
1533+ v8::Local<v8::String> JSONString;
1534+ if (v8::JSON::Stringify(getContext(), v8Value.constGet()).ToLocal(&JSONString)) {
1535+ JSONQString = QString(*v8::String::Utf8Value(_v8Isolate, JSONString));
1536+ }
1537+ return parentValueQString + QString(" JSON: ") + JSONQString;
1538+}
1539+
14141540 /*QStringList ScriptEngineV8::getCurrentStackTrace() {
14151541 v8::Local<v8::StackTrace> stackTrace = v8::StackTrace::CurrentStackTrace(_v8Isolate, 100);
14161542 QStringList backtrace;