History

Script engine thread safety improvements

ksuprynowicz committed 3 years ago

Commit 044cd501 parent 6bd8a8d21 files · +374 −204Browse files

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

Unified · Split

libraries/script-engine/src/v8/ScriptEngineV8.cpp+62−37
@@ -49,6 +49,7 @@ · 48 unmodified lines
4949 #include "ScriptObjectV8Proxy.h"
5050 #include "ScriptProgramV8Wrapper.h"
5151 #include "ScriptValueV8Wrapper.h"
52+#include "V8Lambda.h"
5253
5354 static const int MAX_DEBUG_VALUE_LENGTH { 80 };
5455
@@ -72,9 +73,9 @@ bool ScriptEngineV8::IS_THREADSAFE_INVOCATION(const QThread* thread, const QStri · 17 unmodified lines
7273 // engine-aware JS Error copier and factory
7374 V8ScriptValue ScriptEngineV8::makeError(const V8ScriptValue& _other, const QString& type) {
7475 if (!IS_THREADSAFE_INVOCATION(thread(), __FUNCTION__)) {
75− return V8ScriptValue(_v8Isolate, v8::Null(_v8Isolate));
76+ return V8ScriptValue(this, v8::Null(_v8Isolate));
7677 }
77− return V8ScriptValue(_v8Isolate, v8::Null(_v8Isolate));
78+ return V8ScriptValue(this, v8::Null(_v8Isolate));
7879 //V8TODO
7980 /*
8081 auto other = _other;
@@ -293,7 +294,7 @@ bool ScriptEngineV8::maybeEmitUncaughtException(const QString& debugHint) { · 212 unmodified lines
293294 }
294295
295296 // Lambda
296−ScriptValue ScriptEngineV8::newLambdaFunction(std::function<V8ScriptValue(V8ScriptContext*, ScriptEngineV8*)> operation,
297+/*ScriptValue ScriptEngineV8::newLambdaFunction(std::function<V8ScriptValue(V8ScriptContext*, ScriptEngineV8*)> operation,
297298 const V8ScriptValue& data,
298299 const ValueOwnership& ownership) {
299300 v8::HandleScope handleScope(_v8Isolate);
@@ -305,7 +306,7 @@ ScriptValue ScriptEngineV8::newLambdaFunction(std::function<V8ScriptValue(V8Scri · 5 unmodified lines
305306 call.setPrototype(object); // context->callee().prototype() === Lambda QObject
306307 call.setData(ScriptValue(new ScriptValueV8Wrapper(this, data))); // context->callee().data() will === data param
307308 return call;
308−}
309+}*/
309310 QString Lambda::toString() const {
310311 v8::HandleScope handleScope(_engine->getIsolate());
311312 v8::Context::Scope contextScope(_engine->getContext());
@@ -338,7 +339,7 @@ Lambda::Lambda(ScriptEngineV8* engine, · 26 unmodified lines
338339 }
339340 V8ScriptValue Lambda::call() {
340341 if (!_engine->IS_THREADSAFE_INVOCATION(__FUNCTION__)) {
341− return V8ScriptValue(_engine->getIsolate(), v8::Null(_engine->getIsolate()));
342+ return V8ScriptValue(_engine, v8::Null(_engine->getIsolate()));
342343 }
343344 // V8TODO: it needs to be done in entirely different way for V8
344345 Q_ASSERT(false);
@@ -411,10 +412,10 @@ ScriptEngineV8::ScriptEngineV8(ScriptManager* scriptManager) : · 66 unmodified lines
411412 _contexts.append(std::make_shared<ScriptContextV8Wrapper>(this,context, ScriptContextPointer()));
412413
413414
414− V8ScriptValue nullScriptValue(_v8Isolate, v8::Null(_v8Isolate));
415+ V8ScriptValue nullScriptValue(this, v8::Null(_v8Isolate));
415416 _nullValue = ScriptValue(new ScriptValueV8Wrapper(this, nullScriptValue));
416417
417− V8ScriptValue undefined(_v8Isolate, v8::Undefined(_v8Isolate));
418+ V8ScriptValue undefined(this, v8::Undefined(_v8Isolate));
418419 _undefinedValue = ScriptValue(new ScriptValueV8Wrapper(this, undefined));
419420
420421 registerSystemTypes();
@@ -463,7 +464,7 @@ void ScriptEngineV8::registerEnum(const QString& enumName, QMetaEnum newEnum) { · 42 unmodified lines
463464 for (int i = 0; i < newEnum.keyCount(); i++) {
464465 const char* keyName = newEnum.key(i);
465466 QString fullName = enumName + "." + keyName;
466− registerValue(fullName, V8ScriptValue(_v8Isolate, v8::Integer::New(_v8Isolate, newEnum.keyToValue(keyName))));
467+ registerValue(fullName, V8ScriptValue(this, v8::Integer::New(_v8Isolate, newEnum.keyToValue(keyName))));
467468 }
468469 }
469470
@@ -741,7 +742,7 @@ void ScriptEngineV8::registerGetterSetter(const QString& name, ScriptEngine::Fun · 271 unmodified lines
741742 v8::Local<v8::String> v8propertyName =
742743 v8::String::NewFromUtf8(_v8Isolate, name.toStdString().c_str()).ToLocalChecked();
743744 v8::Local<v8::Object> v8ObjectToSetProperty;
744− ScriptObjectV8Proxy *proxy = ScriptObjectV8Proxy::unwrapProxy(V8ScriptValue(_v8Isolate, v8ParentObject));
745+ ScriptObjectV8Proxy *proxy = ScriptObjectV8Proxy::unwrapProxy(V8ScriptValue(this, v8ParentObject));
745746 // If object is ScriptObjectV8Proxy, then setting property needs to be handled differently
746747 if (proxy) {
747748 v8ObjectToSetProperty = v8ParentObject->GetInternalField(2).As<v8::Object>();
@@ -833,13 +834,14 @@ ScriptValue ScriptEngineV8::evaluateInClosure(const ScriptValue& _closure, · 85 unmodified lines
833834 Q_ASSERT(false);
834835 return nullValue();
835836 }
837+ Q_ASSERT(closure.constGet()->IsObject());
836838 closureObject = v8::Local<v8::Object>::Cast(closure.constGet());
837839 qDebug() << "Closure object members:" << scriptValueDebugListMembersV8(closure);
838840 v8::Local<v8::Object> testObject = v8::Object::New(_v8Isolate);
839841 if(!testObject->Set(getContext(), v8::String::NewFromUtf8(_v8Isolate, "test_value").ToLocalChecked(), closureObject).FromMaybe(false)) {
840842 Q_ASSERT(false);
841843 }
842− qDebug() << "Test object members:" << scriptValueDebugListMembersV8(V8ScriptValue(_v8Isolate, testObject));
844+ qDebug() << "Test object members:" << scriptValueDebugListMembersV8(V8ScriptValue(this, testObject));
843845
844846 if (!closureObject->Get(closure.constGetContext(), v8::String::NewFromUtf8(_v8Isolate, "global").ToLocalChecked())
845847 .ToLocal(&closureGlobal)) {
@@ -958,7 +960,7 @@ ScriptValue ScriptEngineV8::evaluateInClosure(const ScriptValue& _closure, · 112 unmodified lines
958960 #endif
959961 result = err;
960962 } else {
961− result = ScriptValue(new ScriptValueV8Wrapper(this, V8ScriptValue(_v8Isolate, v8Result)));
963+ result = ScriptValue(new ScriptValueV8Wrapper(this, V8ScriptValue(this, v8Result)));
962964 }
963965 }
964966 #ifdef DEBUG_JS
@@ -1022,10 +1024,13 @@ ScriptValue ScriptEngineV8::evaluate(const QString& sourceCode, const QString& f · 57 unmodified lines
10221024 errorLineNumber = exceptionMessage->GetLineNumber(getContext()).FromJust();
10231025 errorColumnNumber = exceptionMessage->GetStartColumn(getContext()).FromJust();
10241026 v8::Local<v8::Value> backtraceV8String;
1025− if (tryCatch.StackTrace(getContext()).ToLocal(&backtraceV8String) && backtraceV8String->IsString() &&
1026− v8::Local<v8::String>::Cast(backtraceV8String)->Length() > 0) {
1027− v8::String::Utf8Value backtraceUtf8Value(getIsolate(), backtraceV8String);
1028− errorBacktrace = *backtraceUtf8Value;
1027+ if (tryCatch.StackTrace(getContext()).ToLocal(&backtraceV8String)) {
1028+ if (backtraceV8String->IsString()) {
1029+ if (v8::Local<v8::String>::Cast(backtraceV8String)->Length() > 0) {
1030+ v8::String::Utf8Value backtraceUtf8Value(getIsolate(), backtraceV8String);
1031+ errorBacktrace = *backtraceUtf8Value;
1032+ }
1033+ }
10291034 }
10301035 qCDebug(scriptengine) << "Compiling script \"" << fileName << "\" failed on line " << errorLineNumber << " column " << errorColumnNumber << " with message: \"" << errorMessage <<"\" backtrace: " << errorBacktrace;
10311036 }
@@ -1061,7 +1066,7 @@ ScriptValue ScriptEngineV8::evaluate(const QString& sourceCode, const QString& f · 29 unmodified lines
10611066 if (!script->Run(getContext()).ToLocal(&result)) {
10621067 Q_ASSERT(tryCatchRun.HasCaught());
10631068 auto runError = tryCatchRun.Message();
1064− ScriptValue errorValue(new ScriptValueV8Wrapper(this, V8ScriptValue(_v8Isolate, runError->Get())));
1069+ ScriptValue errorValue(new ScriptValueV8Wrapper(this, V8ScriptValue(this, runError->Get())));
10651070 qCDebug(scriptengine) << "Running script: \"" << fileName << "\" " << formatErrorMessageFromTryCatch(tryCatchRun);
10661071 //V8TODO
10671072 //raiseException(errorValue);
@@ -1069,7 +1074,7 @@ ScriptValue ScriptEngineV8::evaluate(const QString& sourceCode, const QString& f · 1 unmodified line
10691074 _evaluatingCounter--;
10701075 return errorValue;
10711076 }
1072− V8ScriptValue resultValue(_v8Isolate, result);
1077+ V8ScriptValue resultValue(this, result);
10731078 _evaluatingCounter--;
10741079 return ScriptValue(new ScriptValueV8Wrapper(this, std::move(resultValue)));
10751080 }
@@ -1092,10 +1097,13 @@ QString ScriptEngineV8::formatErrorMessageFromTryCatch(v8::TryCatch &tryCatch) { · 16 unmodified lines
10921097 errorLineNumber = exceptionMessage->GetLineNumber(getContext()).FromJust();
10931098 errorColumnNumber = exceptionMessage->GetStartColumn(getContext()).FromJust();
10941099 v8::Local<v8::Value> backtraceV8String;
1095− if (tryCatch.StackTrace(getContext()).ToLocal(&backtraceV8String) && backtraceV8String->IsString() &&
1096− v8::Local<v8::String>::Cast(backtraceV8String)->Length() > 0) {
1097− v8::String::Utf8Value backtraceUtf8Value(getIsolate(), backtraceV8String);
1098− errorBacktrace = *backtraceUtf8Value;
1100+ if (tryCatch.StackTrace(getContext()).ToLocal(&backtraceV8String)) {
1101+ if (backtraceV8String->IsString()) {
1102+ if (v8::Local<v8::String>::Cast(backtraceV8String)->Length() > 0) {
1103+ v8::String::Utf8Value backtraceUtf8Value(getIsolate(), backtraceV8String);
1104+ errorBacktrace = *backtraceUtf8Value;
1105+ }
1106+ }
10991107 }
11001108 QTextStream resultStream(&result);
11011109 resultStream << "failed on line " << errorLineNumber << " column " << errorColumnNumber << " with message: \"" << errorMessage <<"\" backtrace: " << errorBacktrace;
@@ -1185,7 +1193,7 @@ Q_INVOKABLE ScriptValue ScriptEngineV8::evaluate(const ScriptProgramPointer& pro · 83 unmodified lines
11851193 if (!v8Program.constGet()->Run(getContext()).ToLocal(&result)) {
11861194 Q_ASSERT(tryCatchRun.HasCaught());
11871195 auto runError = tryCatchRun.Message();
1188− errorValue = ScriptValue(new ScriptValueV8Wrapper(this, V8ScriptValue(_v8Isolate, runError->Get())));
1196+ errorValue = ScriptValue(new ScriptValueV8Wrapper(this, V8ScriptValue(this, runError->Get())));
11891197 raiseException(errorValue);
11901198 maybeEmitUncaughtException("evaluate");
11911199 hasFailed = true;
@@ -1195,7 +1203,7 @@ Q_INVOKABLE ScriptValue ScriptEngineV8::evaluate(const ScriptProgramPointer& pro · 3 unmodified lines
11951203 }
11961204 }
11971205 if(!hasFailed) {
1198− V8ScriptValue resultValueV8(_v8Isolate, result);
1206+ V8ScriptValue resultValueV8(this, result);
11991207 resultValue = ScriptValue(new ScriptValueV8Wrapper(this, std::move(resultValueV8)));
12001208 }
12011209 }
@@ -1225,12 +1233,12 @@ void ScriptEngineV8::updateMemoryCost(const qint64& deltaSize) { · 23 unmodified lines
12251233 ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
12261234 // ScriptEngine implementation
12271235
1228−ScriptValue ScriptEngineV8::globalObject() const {
1236+ScriptValue ScriptEngineV8::globalObject() {
12291237 v8::Locker locker(_v8Isolate);
12301238 v8::Isolate::Scope isolateScope(_v8Isolate);
12311239 v8::HandleScope handleScope(_v8Isolate);
12321240 v8::Context::Scope contextScope(getConstContext());
1233− V8ScriptValue global(_v8Isolate, getConstContext()->Global());// = QScriptEngine::globalObject(); // can't cache the value as it may change
1241+ V8ScriptValue global(this, getConstContext()->Global());// = QScriptEngine::globalObject(); // can't cache the value as it may change
12341242 return ScriptValue(new ScriptValueV8Wrapper(const_cast<ScriptEngineV8*>(this), std::move(global)));
12351243 }
12361244
@@ -1243,7 +1251,7 @@ ScriptValue ScriptEngineV8::newArray(uint length) { · 6 unmodified lines
12431251 v8::Isolate::Scope isolateScope(_v8Isolate);
12441252 v8::HandleScope handleScope(_v8Isolate);
12451253 v8::Context::Scope contextScope(getContext());
1246− V8ScriptValue result(_v8Isolate, v8::Array::New(_v8Isolate, static_cast<int>(length)));
1254+ V8ScriptValue result(this, v8::Array::New(_v8Isolate, static_cast<int>(length)));
12471255 return ScriptValue(new ScriptValueV8Wrapper(this, std::move(result)));
12481256 }
12491257
@@ -1262,7 +1270,7 @@ ScriptValue ScriptEngineV8::newArrayBuffer(const QByteArray& message) { · 12 unmodified lines
12621270 if (!array) {
12631271 return undefinedValue();
12641272 }*/
1265− V8ScriptValue result(_v8Isolate, arrayBuffer);//QScriptEngine::newObject(array, data);
1273+ V8ScriptValue result(this, arrayBuffer);//QScriptEngine::newObject(array, data);
12661274 return ScriptValue(new ScriptValueV8Wrapper(this, std::move(result)));
12671275 }
12681276
@@ -1280,7 +1288,7 @@ ScriptValue ScriptEngineV8::newObject() { · 11 unmodified lines
12801288 v8::Isolate::Scope isolateScope(_v8Isolate);
12811289 v8::HandleScope handleScope(_v8Isolate);
12821290 v8::Context::Scope contextScope(getContext());
1283− V8ScriptValue resultV8 = V8ScriptValue(_v8Isolate, v8::Object::New(_v8Isolate));
1291+ V8ScriptValue resultV8 = V8ScriptValue(this, v8::Object::New(_v8Isolate));
12841292 result = ScriptValue(new ScriptValueV8Wrapper(this, std::move(resultV8)));
12851293 }
12861294 /*if (is_isolate_exit_needed) {
@@ -1328,7 +1336,7 @@ ScriptValue ScriptEngineV8::newValue(bool value) { · 41 unmodified lines
13281336 v8::Isolate::Scope isolateScope(_v8Isolate);
13291337 v8::HandleScope handleScope(_v8Isolate);
13301338 v8::Context::Scope contextScope(getContext());
1331− V8ScriptValue result(_v8Isolate, v8::Boolean::New(_v8Isolate, value));
1339+ V8ScriptValue result(this, v8::Boolean::New(_v8Isolate, value));
13321340 return ScriptValue(new ScriptValueV8Wrapper(this, std::move(result)));
13331341 }
13341342
@@ -1337,7 +1345,7 @@ ScriptValue ScriptEngineV8::newValue(int value) { · 2 unmodified lines
13371345 v8::Isolate::Scope isolateScope(_v8Isolate);
13381346 v8::HandleScope handleScope(_v8Isolate);
13391347 v8::Context::Scope contextScope(getContext());
1340− V8ScriptValue result(_v8Isolate, v8::Integer::New(_v8Isolate, value));
1348+ V8ScriptValue result(this, v8::Integer::New(_v8Isolate, value));
13411349 return ScriptValue(new ScriptValueV8Wrapper(this, std::move(result)));
13421350 }
13431351
@@ -1346,7 +1354,7 @@ ScriptValue ScriptEngineV8::newValue(uint value) { · 2 unmodified lines
13461354 v8::Isolate::Scope isolateScope(_v8Isolate);
13471355 v8::HandleScope handleScope(_v8Isolate);
13481356 v8::Context::Scope contextScope(getContext());
1349− V8ScriptValue result(_v8Isolate, v8::Uint32::New(_v8Isolate, value));
1357+ V8ScriptValue result(this, v8::Uint32::New(_v8Isolate, value));
13501358 return ScriptValue(new ScriptValueV8Wrapper(this, std::move(result)));
13511359 }
13521360
@@ -1355,7 +1363,7 @@ ScriptValue ScriptEngineV8::newValue(double value) { · 2 unmodified lines
13551363 v8::Isolate::Scope isolateScope(_v8Isolate);
13561364 v8::HandleScope handleScope(_v8Isolate);
13571365 v8::Context::Scope contextScope(getContext());
1358− V8ScriptValue result(_v8Isolate, v8::Number::New(_v8Isolate, value));
1366+ V8ScriptValue result(this, v8::Number::New(_v8Isolate, value));
13591367 return ScriptValue(new ScriptValueV8Wrapper(this, std::move(result)));
13601368 }
13611369
@@ -1365,7 +1373,7 @@ ScriptValue ScriptEngineV8::newValue(const QString& value) { · 3 unmodified lines
13651373 v8::HandleScope handleScope(_v8Isolate);
13661374 v8::Context::Scope contextScope(getContext());
13671375 v8::Local<v8::String> valueV8 = v8::String::NewFromUtf8(_v8Isolate, value.toStdString().c_str(), v8::NewStringType::kNormal).ToLocalChecked();
1368− V8ScriptValue result(_v8Isolate, valueV8);
1376+ V8ScriptValue result(this, valueV8);
13691377 return ScriptValue(new ScriptValueV8Wrapper(this, std::move(result)));
13701378 }
13711379
@@ -1375,7 +1383,7 @@ ScriptValue ScriptEngineV8::newValue(const QLatin1String& value) { · 3 unmodified lines
13751383 v8::HandleScope handleScope(_v8Isolate);
13761384 v8::Context::Scope contextScope(getContext());
13771385 v8::Local<v8::String> valueV8 = v8::String::NewFromUtf8(_v8Isolate, value.latin1(), v8::NewStringType::kNormal).ToLocalChecked();
1378− V8ScriptValue result(_v8Isolate, valueV8);
1386+ V8ScriptValue result(this, valueV8);
13791387 return ScriptValue(new ScriptValueV8Wrapper(this, std::move(result)));
13801388 }
13811389
@@ -1385,7 +1393,7 @@ ScriptValue ScriptEngineV8::newValue(const char* value) { · 3 unmodified lines
13851393 v8::HandleScope handleScope(_v8Isolate);
13861394 v8::Context::Scope contextScope(getContext());
13871395 v8::Local<v8::String> valueV8 = v8::String::NewFromUtf8(_v8Isolate, value, v8::NewStringType::kNormal).ToLocalChecked();
1388− V8ScriptValue result(_v8Isolate, valueV8);
1396+ V8ScriptValue result(this, valueV8);
13891397 return ScriptValue(new ScriptValueV8Wrapper(this, std::move(result)));
13901398 }
13911399
@@ -1463,6 +1471,7 @@ ScriptValue ScriptEngineV8::newFunction(ScriptEngine::FunctionSignature fun, int · 71 unmodified lines
14631471 v8::HandleScope handleScope(info.GetIsolate());
14641472 auto context = info.GetIsolate()->GetCurrentContext();
14651473 v8::Context::Scope contextScope(context);
1474+ Q_ASSERT(info.Data()->IsObject());
14661475 auto object = v8::Local<v8::Object>::Cast(info.Data());
14671476 Q_ASSERT(object->InternalFieldCount() == 2);
14681477 auto function = reinterpret_cast<ScriptEngine::FunctionSignature>
@@ -1493,7 +1502,7 @@ ScriptValue ScriptEngineV8::newFunction(ScriptEngine::FunctionSignature fun, int · 24 unmodified lines
14931502 auto v8Function = v8::Function::New(getContext(), v8FunctionCallback, functionData, length).ToLocalChecked();
14941503 //auto functionObjectTemplate = functionTemplate->InstanceTemplate();
14951504 //auto function =
1496− V8ScriptValue result(_v8Isolate, v8Function); // = QScriptEngine::newFunction(innerFunc, length);
1505+ V8ScriptValue result(this, v8Function); // = QScriptEngine::newFunction(innerFunc, length);
14971506 //auto funAddr = QScriptEngine::newVariant(QVariant(reinterpret_cast<qulonglong>(fun)));
14981507 // V8TODO
14991508 //result.setProperty("_func", funAddr, V8ScriptValue::PropertyFlags(V8ScriptValue::ReadOnly + V8ScriptValue::Undeletable + V8ScriptValue::SkipInEnumeration));
@@ -1685,4 +1694,20 @@ QString ScriptEngineV8::scriptValueDebugDetailsV8(const V8ScriptValue &v8Value) · 185 unmodified lines
16851694 v8::Local<v8::StackFrame> stackFrame = stackTrace->GetFrame(_v8Isolate, n);
16861695
16871696 }
1688−}*/
1697+}*/
1698+
1699+QStringList ScriptEngineV8::getCurrentScriptURLs() const {
1700+ auto isolate = _v8Isolate;
1701+ v8::Locker locker(isolate);
1702+ v8::Isolate::Scope isolateScope(isolate);
1703+ v8::HandleScope handleScope(isolate);
1704+ v8::Context::Scope contextScope(_v8Isolate->GetCurrentContext());
1705+ v8::Local<v8::StackTrace> stackTrace = v8::StackTrace::CurrentStackTrace(isolate, 100);
1706+ QStringList scriptURLs;
1707+ //V8TODO nicer formatting
1708+ for (int i = 0; i < stackTrace->GetFrameCount(); i++) {
1709+ v8::Local<v8::StackFrame> stackFrame = stackTrace->GetFrame(isolate, i);
1710+ scriptURLs.append(QString(*v8::String::Utf8Value(isolate, stackFrame->GetScriptNameOrSourceURL())));
1711+ }
1712+ return scriptURLs;
1713+}