History

V8 memory leak fixes

ksuprynowicz committed 3 years ago

Commit 6466d391 parent cd110664 files · +101 −32Browse files

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

Unified · Split

libraries/script-engine/src/v8/ScriptObjectV8Proxy.cpp+79−17
@@ -146,7 +146,7 @@ V8ScriptValue ScriptObjectV8Proxy::newQObject(ScriptEngineV8* engine, QObject* o · 145 unmodified lines
146146 if (lookupV8 != enginePtr->_qobjectWrapperMapV8.end()) {
147147 enginePtr->_qobjectWrapperMapV8.erase(lookupV8);
148148 }
149− qDebug() << "ScriptObjectV8Proxy::newQObject object deleted, object count: " << enginePtr->_qobjectWrapperMapV8.size();
149+ //qDebug() << "ScriptObjectV8Proxy::newQObject object deleted, object count: " << enginePtr->_qobjectWrapperMapV8.size();
150150 });
151151 //qDebug() << "ScriptObjectV8Proxy::newQObject object count: " << engine->_qobjectWrapperMapV8.size();
152152 }
@@ -218,19 +218,26 @@ QObject* ScriptObjectV8Proxy::unwrap(const V8ScriptValue& val) { · 65 unmodified lines
218218 }
219219
220220 ScriptObjectV8Proxy::~ScriptObjectV8Proxy() {
221− auto isolate = _engine->getIsolate();
222− v8::Locker locker(isolate);
223− v8::Isolate::Scope isolateScope(isolate);
224− v8::HandleScope handleScope(isolate);
225− if(_object) qCDebug(scriptengine_v8) << "Deleting object proxy: " << name();
226− // V8TODO: once WeakPersistent pointer is added we should check if it's valid before deleting
227− Q_ASSERT(!_v8Object.Get(isolate)->IsNullOrUndefined());
228− // This prevents unwrap function from unwrapping proxy that was deleted
229− _v8Object.Get(isolate)->SetAlignedPointerInInternalField(0, const_cast<void*>(internalPointsToDeletedQObjectProxy));
230− _v8Object.Reset();
231221 if (_ownsObject) {
222+ auto isolate = _engine->getIsolate();
223+ v8::Locker locker(isolate);
224+ v8::Isolate::Scope isolateScope(isolate);
225+ v8::HandleScope handleScope(isolate);
226+ _v8Object.Reset();
232227 QObject* qobject = _object;
233228 if(qobject) qobject->deleteLater();
229+ } else {
230+ auto isolate = _engine->getIsolate();
231+ v8::Locker locker(isolate);
232+ v8::Isolate::Scope isolateScope(isolate);
233+ v8::HandleScope handleScope(isolate);
234+ if (_object)
235+ qCDebug(scriptengine_v8) << "Deleting object proxy: " << name();
236+ // V8TODO: once WeakPersistent pointer is added we should check if it's valid before deleting
237+ Q_ASSERT(!_v8Object.Get(isolate)->IsNullOrUndefined());
238+ // This prevents unwrap function from unwrapping proxy that was deleted
239+ _v8Object.Get(isolate)->SetAlignedPointerInInternalField(0, const_cast<void*>(internalPointsToDeletedQObjectProxy));
240+ _v8Object.Reset();
234241 }
235242 }
236243
@@ -382,6 +389,7 @@ void ScriptObjectV8Proxy::investigate() { · 145 unmodified lines
382389 // Add all the methods objects as properties - this allows adding properties to a given method later. Is used by Script.request.
383390 // V8TODO: Should these be deleted when the script-owned object is destroyed? It needs checking if script-owned objects will be garbage-collected, or will self-referencing prevent it.
384391 for (auto i = _methods.begin(); i != _methods.end(); i++) {
392+ //V8TODO: lifetime may prevent garbage collection?
385393 V8ScriptValue method = ScriptMethodV8Proxy::newMethod(_engine, qobject, V8ScriptValue(_engine, v8Object),
386394 i.value().methods, i.value().numMaxParms);
387395 if(!propertiesObject->Set(_engine->getContext(), i.value().name.constGet(), method.get()).FromMaybe(false)) {
@@ -393,7 +401,9 @@ void ScriptObjectV8Proxy::investigate() { · 5 unmodified lines
393401 void ScriptObjectV8Proxy::weakHandleCallback(const v8::WeakCallbackInfo<ScriptObjectV8Proxy>& info) {
394402 //V8TODO: does the object need to be moved to script engine thread?
395403 //V8TODO: why does this never get called?
396− qDebug(scriptengine_v8) << "ScriptObjectV8Proxy::weakHandleCallback";
404+ //qDebug(scriptengine_v8) << "ScriptObjectV8Proxy::weakHandleCallback";
405+ auto proxy = info.GetParameter();
406+ proxy->_v8Object.Reset();
397407 info.GetParameter()->_object->deleteLater();
398408 }
399409
@@ -775,6 +785,7 @@ ScriptVariantV8Proxy::~ScriptVariantV8Proxy() { · 375 unmodified lines
775785 }
776786
777787 V8ScriptValue ScriptVariantV8Proxy::newVariant(ScriptEngineV8* engine, const QVariant& variant, V8ScriptValue proto) {
788+ qDebug() << "ScriptVariantV8Proxy::newVariant";
778789 auto isolate = engine->getIsolate();
779790 v8::Locker locker(isolate);
780791 v8::Isolate::Scope isolateScope(isolate);
@@ -960,12 +971,30 @@ QVariant ScriptVariantV8Proxy::unwrap(const V8ScriptValue& val) { · 179 unmodified lines
960971
961972 ScriptMethodV8Proxy::ScriptMethodV8Proxy(ScriptEngineV8* engine, QObject* object, V8ScriptValue lifetime,
962973 const QList<QMetaMethod>& metas, int numMaxParams) :
963− _numMaxParams(numMaxParams), _engine(engine), _object(object), _objectLifetime(lifetime), _metas(metas) {
974+ _numMaxParams(numMaxParams), _engine(engine), _object(object), /*_objectLifetime(lifetime),*/ _metas(metas) {
975+ auto isolate = engine->getIsolate();
976+ v8::Locker locker(isolate);
977+ v8::Isolate::Scope isolateScope(isolate);
978+ v8::HandleScope handleScope(isolate);
979+ v8::Context::Scope contextScope(engine->getContext());
980+ _objectLifetime.Reset(isolate, lifetime.get());
981+ _objectLifetime.SetWeak(this, weakHandleCallback, v8::WeakCallbackType::kParameter);
964982 }
965983
966984 ScriptMethodV8Proxy::~ScriptMethodV8Proxy() {
967− qCDebug(scriptengine_v8) << "ScriptMethodV8Proxy destroyed";
968− printf("ScriptMethodV8Proxy destroyed");
985+ //qCDebug(scriptengine_v8) << "ScriptMethodV8Proxy destroyed";
986+ auto isolate = _engine->getIsolate();
987+ v8::Locker locker(isolate);
988+ v8::Isolate::Scope isolateScope(isolate);
989+ v8::HandleScope handleScope(isolate);
990+ _objectLifetime.Reset();
991+}
992+
993+void ScriptMethodV8Proxy::weakHandleCallback(const v8::WeakCallbackInfo<ScriptMethodV8Proxy>& info) {
994+ //qDebug(scriptengine_v8) << "ScriptMethodV8Proxy::weakHandleCallback";
995+ auto proxy = info.GetParameter();
996+ proxy->_objectLifetime.Reset();
997+ info.GetParameter()->deleteLater();
969998 }
970999
9711000 V8ScriptValue ScriptMethodV8Proxy::newMethod(ScriptEngineV8* engine, QObject* object, V8ScriptValue lifetime,
@@ -980,6 +1009,7 @@ V8ScriptValue ScriptMethodV8Proxy::newMethod(ScriptEngineV8* engine, QObject* ob · 8 unmodified lines
9801009 auto methodData = methodDataTemplate->NewInstance(engine->getContext()).ToLocalChecked();
9811010 methodData->SetAlignedPointerInInternalField(0, const_cast<void*>(internalPointsToMethodProxy));
9821011 // V8TODO it needs to be deleted somehow on object destruction
1012+ // weak persistent callback would do this
9831013 methodData->SetAlignedPointerInInternalField(1, reinterpret_cast<void*>(new ScriptMethodV8Proxy(engine, object, lifetime, metas, numMaxParams)));
9841014 auto v8Function = v8::Function::New(engine->getContext(), callback, methodData, numMaxParams).ToLocalChecked();
9851015 return V8ScriptValue(engine, v8Function);
@@ -1068,6 +1098,7 @@ void ScriptMethodV8Proxy::call(const v8::FunctionCallbackInfo<v8::Value>& argume · 82 unmodified lines
10681098 int bestMeta = 0;
10691099 int bestConversionPenaltyScore = 0;
10701100
1101+
10711102 for (int i = 0; i < num_metas; i++) {
10721103 const QMetaMethod& meta = _metas[i];
10731104 int methodNumArgs = meta.parameterCount();
@@ -1162,14 +1193,25 @@ void ScriptMethodV8Proxy::call(const v8::FunctionCallbackInfo<v8::Value>& argume · 88 unmodified lines
11621193 return;
11631194 } else if (returnTypeId == scriptValueTypeId) {
11641195 ScriptValue result;
1165− bool success = meta.invoke(qobject, Qt::DirectConnection, Q_RETURN_ARG(ScriptValue, result), qGenArgs[0],
1196+ /*if (_metas.front().name() == "createGarbageCollectorDebuggingObject") {
1197+ //qDebug() << "createGarbageCollectorDebuggingObject";
1198+ return;
1199+ }*/
1200+ /*const char* typeName = meta.typeName();
1201+ QVariant qRetVal(returnTypeId, static_cast<void*>(NULL));
1202+ QGenericReturnArgument sRetVal(typeName, const_cast<void*>(qRetVal.constData()));
1203+ bool success = meta.invoke(qobject, Qt::DirectConnection, sRetVal, qGenArgs[0],
11661204 qGenArgs[1], qGenArgs[2], qGenArgs[3], qGenArgs[4], qGenArgs[5], qGenArgs[6],
1167− qGenArgs[7], qGenArgs[8], qGenArgs[9]);
1205+ qGenArgs[7], qGenArgs[8], qGenArgs[9]);*/
1206+ bool success = meta.invoke(qobject, Qt::DirectConnection, Q_RETURN_ARG(ScriptValue, result), qGenArgs[0],
1207+ qGenArgs[1], qGenArgs[2], qGenArgs[3], qGenArgs[4], qGenArgs[5], qGenArgs[6],
1208+ qGenArgs[7], qGenArgs[8], qGenArgs[9]);
11681209 if (!success) {
11691210 isolate->ThrowError(v8::String::NewFromUtf8(isolate, QString("Unexpected: Native call of %1 failed").arg(fullName()).toStdString().c_str()).ToLocalChecked());
11701211 return;
11711212 }
11721213 V8ScriptValue v8Result = ScriptValueV8Wrapper::fullUnwrap(_engine, result);
1214+ //V8ScriptValue v8Result = _engine->castVariantToValue(qRetVal);
11731215 arguments.GetReturnValue().Set(v8Result.get());
11741216 return;
11751217 } else {
@@ -1396,14 +1438,34 @@ void ScriptMethodV8Proxy::call(const v8::FunctionCallbackInfo<v8::Value>& argume · 220 unmodified lines
13961438 return QVariant();
13971439 }*/
13981440
1441+ScriptSignalV8Proxy::ScriptSignalV8Proxy(ScriptEngineV8* engine, QObject* object, V8ScriptValue lifetime, const QMetaMethod& meta) :
1442+ _engine(engine), _object(object), _meta(meta), _metaCallId(discoverMetaCallIdx()) {
1443+ auto isolate = _engine->getIsolate();
1444+ v8::Locker locker(isolate);
1445+ v8::Isolate::Scope isolateScope(isolate);
1446+ v8::HandleScope handleScope(isolate);
1447+ v8::Context::Scope contextScope(_engine->getContext());
1448+ _objectLifetime.Reset(isolate, lifetime.get());
1449+ _objectLifetime.SetWeak(this, weakHandleCallback, v8::WeakCallbackType::kParameter);
1450+ _v8Context.Reset(isolate, _engine->getContext());
1451+}
1452+
13991453 ScriptSignalV8Proxy::~ScriptSignalV8Proxy() {
14001454 auto isolate = _engine->getIsolate();
14011455 v8::Locker locker(isolate);
14021456 v8::Isolate::Scope isolateScope(isolate);
14031457 v8::HandleScope handleScope(isolate);
1458+ _objectLifetime.Reset();
14041459 _v8Context.Reset();
14051460 }
14061461
1462+void ScriptSignalV8Proxy::weakHandleCallback(const v8::WeakCallbackInfo<ScriptSignalV8Proxy>& info) {
1463+ //qDebug(scriptengine_v8) << "ScriptSignalV8Proxy::weakHandleCallback";
1464+ auto proxy = info.GetParameter();
1465+ proxy->_objectLifetime.Reset();
1466+ proxy->deleteLater();
1467+}
1468+
14071469 QString ScriptSignalV8Proxy::fullName() const {
14081470 Q_ASSERT(_object);
14091471 if (!_object) return "";