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
146 if (lookupV8 != enginePtr->_qobjectWrapperMapV8.end()) {146 if (lookupV8 != enginePtr->_qobjectWrapperMapV8.end()) {
147 enginePtr->_qobjectWrapperMapV8.erase(lookupV8);147 enginePtr->_qobjectWrapperMapV8.erase(lookupV8);
148 }148 }
149 qDebug() << "ScriptObjectV8Proxy::newQObject object deleted, object count: " << enginePtr->_qobjectWrapperMapV8.size();149 //qDebug() << "ScriptObjectV8Proxy::newQObject object deleted, object count: " << enginePtr->_qobjectWrapperMapV8.size();
150 });150 });
151 //qDebug() << "ScriptObjectV8Proxy::newQObject object count: " << engine->_qobjectWrapperMapV8.size();151 //qDebug() << "ScriptObjectV8Proxy::newQObject object count: " << engine->_qobjectWrapperMapV8.size();
152 }152 }
@@ -218,19 +218,26 @@ QObject* ScriptObjectV8Proxy::unwrap(const V8ScriptValue& val) { · 65 unmodified lines
218}218}
219 219
220ScriptObjectV8Proxy::~ScriptObjectV8Proxy() {220ScriptObjectV8Proxy::~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();
231 if (_ownsObject) {221 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();
232 QObject* qobject = _object;227 QObject* qobject = _object;
233 if(qobject) qobject->deleteLater();228 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();
234 }241 }
235}242}
236 243
@@ -382,6 +389,7 @@ void ScriptObjectV8Proxy::investigate() { · 145 unmodified lines
382 // Add all the methods objects as properties - this allows adding properties to a given method later. Is used by Script.request.389 // Add all the methods objects as properties - this allows adding properties to a given method later. Is used by Script.request.
383 // 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.390 // 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.
384 for (auto i = _methods.begin(); i != _methods.end(); i++) {391 for (auto i = _methods.begin(); i != _methods.end(); i++) {
392 //V8TODO: lifetime may prevent garbage collection?
385 V8ScriptValue method = ScriptMethodV8Proxy::newMethod(_engine, qobject, V8ScriptValue(_engine, v8Object),393 V8ScriptValue method = ScriptMethodV8Proxy::newMethod(_engine, qobject, V8ScriptValue(_engine, v8Object),
386 i.value().methods, i.value().numMaxParms);394 i.value().methods, i.value().numMaxParms);
387 if(!propertiesObject->Set(_engine->getContext(), i.value().name.constGet(), method.get()).FromMaybe(false)) {395 if(!propertiesObject->Set(_engine->getContext(), i.value().name.constGet(), method.get()).FromMaybe(false)) {
@@ -393,7 +401,9 @@ void ScriptObjectV8Proxy::investigate() { · 5 unmodified lines
393void ScriptObjectV8Proxy::weakHandleCallback(const v8::WeakCallbackInfo<ScriptObjectV8Proxy>& info) {401void ScriptObjectV8Proxy::weakHandleCallback(const v8::WeakCallbackInfo<ScriptObjectV8Proxy>& info) {
394 //V8TODO: does the object need to be moved to script engine thread?402 //V8TODO: does the object need to be moved to script engine thread?
395 //V8TODO: why does this never get called?403 //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();
397 info.GetParameter()->_object->deleteLater();407 info.GetParameter()->_object->deleteLater();
398}408}
399 409
@@ -775,6 +785,7 @@ ScriptVariantV8Proxy::~ScriptVariantV8Proxy() { · 375 unmodified lines
775}785}
776 786
777V8ScriptValue ScriptVariantV8Proxy::newVariant(ScriptEngineV8* engine, const QVariant& variant, V8ScriptValue proto) {787V8ScriptValue ScriptVariantV8Proxy::newVariant(ScriptEngineV8* engine, const QVariant& variant, V8ScriptValue proto) {
788 qDebug() << "ScriptVariantV8Proxy::newVariant";
778 auto isolate = engine->getIsolate();789 auto isolate = engine->getIsolate();
779 v8::Locker locker(isolate);790 v8::Locker locker(isolate);
780 v8::Isolate::Scope isolateScope(isolate);791 v8::Isolate::Scope isolateScope(isolate);
@@ -960,12 +971,30 @@ QVariant ScriptVariantV8Proxy::unwrap(const V8ScriptValue& val) { · 179 unmodified lines
960 971
961ScriptMethodV8Proxy::ScriptMethodV8Proxy(ScriptEngineV8* engine, QObject* object, V8ScriptValue lifetime,972ScriptMethodV8Proxy::ScriptMethodV8Proxy(ScriptEngineV8* engine, QObject* object, V8ScriptValue lifetime,
962 const QList<QMetaMethod>& metas, int numMaxParams) :973 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);
964}982}
965 983
966ScriptMethodV8Proxy::~ScriptMethodV8Proxy() {984ScriptMethodV8Proxy::~ScriptMethodV8Proxy() {
967 qCDebug(scriptengine_v8) << "ScriptMethodV8Proxy destroyed";985 //qCDebug(scriptengine_v8) << "ScriptMethodV8Proxy destroyed";
968 printf("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
993void 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();
969}998}
970 999
971V8ScriptValue ScriptMethodV8Proxy::newMethod(ScriptEngineV8* engine, QObject* object, V8ScriptValue lifetime,1000V8ScriptValue ScriptMethodV8Proxy::newMethod(ScriptEngineV8* engine, QObject* object, V8ScriptValue lifetime,
@@ -980,6 +1009,7 @@ V8ScriptValue ScriptMethodV8Proxy::newMethod(ScriptEngineV8* engine, QObject* ob · 8 unmodified lines
980 auto methodData = methodDataTemplate->NewInstance(engine->getContext()).ToLocalChecked();1009 auto methodData = methodDataTemplate->NewInstance(engine->getContext()).ToLocalChecked();
981 methodData->SetAlignedPointerInInternalField(0, const_cast<void*>(internalPointsToMethodProxy));1010 methodData->SetAlignedPointerInInternalField(0, const_cast<void*>(internalPointsToMethodProxy));
982 // V8TODO it needs to be deleted somehow on object destruction1011 // V8TODO it needs to be deleted somehow on object destruction
1012 // weak persistent callback would do this
983 methodData->SetAlignedPointerInInternalField(1, reinterpret_cast<void*>(new ScriptMethodV8Proxy(engine, object, lifetime, metas, numMaxParams)));1013 methodData->SetAlignedPointerInInternalField(1, reinterpret_cast<void*>(new ScriptMethodV8Proxy(engine, object, lifetime, metas, numMaxParams)));
984 auto v8Function = v8::Function::New(engine->getContext(), callback, methodData, numMaxParams).ToLocalChecked();1014 auto v8Function = v8::Function::New(engine->getContext(), callback, methodData, numMaxParams).ToLocalChecked();
985 return V8ScriptValue(engine, v8Function);1015 return V8ScriptValue(engine, v8Function);
@@ -1068,6 +1098,7 @@ void ScriptMethodV8Proxy::call(const v8::FunctionCallbackInfo<v8::Value>& argume · 82 unmodified lines
1068 int bestMeta = 0;1098 int bestMeta = 0;
1069 int bestConversionPenaltyScore = 0;1099 int bestConversionPenaltyScore = 0;
1070 1100
1101
1071 for (int i = 0; i < num_metas; i++) {1102 for (int i = 0; i < num_metas; i++) {
1072 const QMetaMethod& meta = _metas[i];1103 const QMetaMethod& meta = _metas[i];
1073 int methodNumArgs = meta.parameterCount();1104 int methodNumArgs = meta.parameterCount();
@@ -1162,14 +1193,25 @@ void ScriptMethodV8Proxy::call(const v8::FunctionCallbackInfo<v8::Value>& argume · 88 unmodified lines
1162 return;1193 return;
1163 } else if (returnTypeId == scriptValueTypeId) {1194 } else if (returnTypeId == scriptValueTypeId) {
1164 ScriptValue result;1195 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],
1166 qGenArgs[1], qGenArgs[2], qGenArgs[3], qGenArgs[4], qGenArgs[5], qGenArgs[6],1204 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]);
1168 if (!success) {1209 if (!success) {
1169 isolate->ThrowError(v8::String::NewFromUtf8(isolate, QString("Unexpected: Native call of %1 failed").arg(fullName()).toStdString().c_str()).ToLocalChecked());1210 isolate->ThrowError(v8::String::NewFromUtf8(isolate, QString("Unexpected: Native call of %1 failed").arg(fullName()).toStdString().c_str()).ToLocalChecked());
1170 return;1211 return;
1171 }1212 }
1172 V8ScriptValue v8Result = ScriptValueV8Wrapper::fullUnwrap(_engine, result);1213 V8ScriptValue v8Result = ScriptValueV8Wrapper::fullUnwrap(_engine, result);
1214 //V8ScriptValue v8Result = _engine->castVariantToValue(qRetVal);
1173 arguments.GetReturnValue().Set(v8Result.get());1215 arguments.GetReturnValue().Set(v8Result.get());
1174 return;1216 return;
1175 } else {1217 } else {
@@ -1396,14 +1438,34 @@ void ScriptMethodV8Proxy::call(const v8::FunctionCallbackInfo<v8::Value>& argume · 220 unmodified lines
1396 return QVariant();1438 return QVariant();
1397}*/1439}*/
1398 1440
1441ScriptSignalV8Proxy::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
1399ScriptSignalV8Proxy::~ScriptSignalV8Proxy() {1453ScriptSignalV8Proxy::~ScriptSignalV8Proxy() {
1400 auto isolate = _engine->getIsolate();1454 auto isolate = _engine->getIsolate();
1401 v8::Locker locker(isolate);1455 v8::Locker locker(isolate);
1402 v8::Isolate::Scope isolateScope(isolate);1456 v8::Isolate::Scope isolateScope(isolate);
1403 v8::HandleScope handleScope(isolate);1457 v8::HandleScope handleScope(isolate);
1458 _objectLifetime.Reset();
1404 _v8Context.Reset();1459 _v8Context.Reset();
1405}1460}
1406 1461
1462void 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
1407QString ScriptSignalV8Proxy::fullName() const {1469QString ScriptSignalV8Proxy::fullName() const {
1408 Q_ASSERT(_object);1470 Q_ASSERT(_object);
1409 if (!_object) return "";1471 if (!_object) return "";