Showing the changes to libraries/script-engine/src/v8/ScriptObjectV8Proxy.cpp (1 of 2 files). Show all
Unified · Split
| @@ -134,6 +134,23 @@ V8ScriptValue ScriptObjectV8Proxy::newQObject(ScriptEngineV8* engine, QObject* o · 133 unmodified lines | |||
| 134 | QPointer<ScriptEngineV8> enginePtr = engine; | 134 | QPointer<ScriptEngineV8> enginePtr = engine; |
| 135 | object->connect(object, &QObject::destroyed, engine, [enginePtr, object]() { | 135 | object->connect(object, &QObject::destroyed, engine, [enginePtr, object]() { |
| 136 | if (!enginePtr) return; | 136 | if (!enginePtr) return; |
| 137 | // Lookup needs to be done twice, because _qobjectWrapperMapProtect must not be locked when disconnecting signals | ||
| 138 | QSharedPointer<ScriptObjectV8Proxy> proxy; | ||
| 139 | { | ||
| 140 | QMutexLocker guard(&enginePtr->_qobjectWrapperMapProtect); | ||
| 141 | auto lookupV8 = enginePtr->_qobjectWrapperMapV8.find(object); | ||
| 142 | if (lookupV8 != enginePtr->_qobjectWrapperMapV8.end()) { | ||
| 143 | proxy = lookupV8.value(); | ||
| 144 | } | ||
| 145 | } | ||
| 146 | if (proxy) { | ||
| 147 | for (auto signal : proxy->_signalInstances) { | ||
| 148 | if (signal) { | ||
| 149 | signal->disconnectAllScriptSignalProxies(); | ||
| 150 | } | ||
| 151 | } | ||
| 152 | } | ||
| 153 | |||
| 137 | QMutexLocker guard(&enginePtr->_qobjectWrapperMapProtect); | 154 | QMutexLocker guard(&enginePtr->_qobjectWrapperMapProtect); |
| 138 | ScriptEngineV8::ObjectWrapperMap::iterator lookup = enginePtr->_qobjectWrapperMap.find(object); | 155 | ScriptEngineV8::ObjectWrapperMap::iterator lookup = enginePtr->_qobjectWrapperMap.find(object); |
| 139 | if (lookup != enginePtr->_qobjectWrapperMap.end()) { | 156 | if (lookup != enginePtr->_qobjectWrapperMap.end()) { |
| @@ -195,7 +212,13 @@ ScriptObjectV8Proxy* ScriptObjectV8Proxy::unwrapProxy(v8::Isolate* isolate, v8:: · 55 unmodified lines | |||
| 195 | qCDebug(scriptengine_v8) << "Cannot unwrap proxy - internal fields don't point to object proxy"; | 212 | qCDebug(scriptengine_v8) << "Cannot unwrap proxy - internal fields don't point to object proxy"; |
| 196 | return nullptr; | 213 | return nullptr; |
| 197 | } | 214 | } |
| 198 | return reinterpret_cast<ScriptObjectV8Proxy*>(v8Object->GetAlignedPointerFromInternalField(1)); | 215 | |
| 216 | ScriptObjectV8Proxy* proxy = reinterpret_cast<ScriptObjectV8Proxy*>(v8Object->GetAlignedPointerFromInternalField(1)); | ||
| 217 | if (proxy) { | ||
| 218 | Q_ASSERT(!proxy->_wasDestroyed); | ||
| 219 | } | ||
| 220 | |||
| 221 | return proxy; | ||
| 199 | } | 222 | } |
| 200 | 223 | ||
| 201 | QObject* ScriptObjectV8Proxy::unwrap(const V8ScriptValue& val) { | 224 | QObject* ScriptObjectV8Proxy::unwrap(const V8ScriptValue& val) { |
| @@ -204,6 +227,12 @@ QObject* ScriptObjectV8Proxy::unwrap(const V8ScriptValue& val) { · 2 unmodified lines | |||
| 204 | } | 227 | } |
| 205 | 228 | ||
| 206 | ScriptObjectV8Proxy::~ScriptObjectV8Proxy() { | 229 | ScriptObjectV8Proxy::~ScriptObjectV8Proxy() { |
| 230 | for (auto signal : _signalInstances) { | ||
| 231 | if (signal) { | ||
| 232 | signal->disconnectAllScriptSignalProxies(); | ||
| 233 | } | ||
| 234 | } | ||
| 235 | _wasDestroyed = true; | ||
| 207 | if (_ownsObject) { | 236 | if (_ownsObject) { |
| 208 | auto isolate = _engine->getIsolate(); | 237 | auto isolate = _engine->getIsolate(); |
| 209 | v8::Locker locker(isolate); | 238 | v8::Locker locker(isolate); |
| @@ -1177,6 +1206,10 @@ ScriptSignalV8Proxy::ScriptSignalV8Proxy(ScriptEngineV8* engine, QObject* object · 967 unmodified lines | |||
| 1177 | } | 1206 | } |
| 1178 | 1207 | ||
| 1179 | ScriptSignalV8Proxy::~ScriptSignalV8Proxy() { | 1208 | ScriptSignalV8Proxy::~ScriptSignalV8Proxy() { |
| 1209 | if (!_cleanup) { | ||
| 1210 | disconnectAllScriptSignalProxies(); | ||
| 1211 | } | ||
| 1212 | |||
| 1180 | auto isolate = _engine->getIsolate(); | 1213 | auto isolate = _engine->getIsolate(); |
| 1181 | v8::Locker locker(isolate); | 1214 | v8::Locker locker(isolate); |
| 1182 | v8::Isolate::Scope isolateScope(isolate); | 1215 | v8::Isolate::Scope isolateScope(isolate); |
| @@ -1408,18 +1441,23 @@ void ScriptSignalV8Proxy::connect(ScriptValue arg0, ScriptValue arg1) { · 225 unmodified lines | |||
| 1408 | Q_ASSERT(ScriptObjectV8Proxy::unwrapProxy(v8EntryObject)); | 1441 | Q_ASSERT(ScriptObjectV8Proxy::unwrapProxy(v8EntryObject)); |
| 1409 | // For debugging | 1442 | // For debugging |
| 1410 | ScriptSignalV8Proxy* entryProxy = dynamic_cast<ScriptSignalV8Proxy*>(ScriptObjectV8Proxy::unwrapProxy(v8EntryObject)->toQObject()); | 1443 | ScriptSignalV8Proxy* entryProxy = dynamic_cast<ScriptSignalV8Proxy*>(ScriptObjectV8Proxy::unwrapProxy(v8EntryObject)->toQObject()); |
| 1411 | Q_ASSERT(thisProxy); | 1444 | Q_ASSERT(entryProxy); |
| 1412 | qCDebug(scriptengine_v8) << "ScriptSignalV8Proxy::connect: entry proxy: " << entryProxy->fullName(); | 1445 | qCDebug(scriptengine_v8) << "ScriptSignalV8Proxy::connect: entry proxy: " << entryProxy->fullName(); |
| 1413 | } | 1446 | } |
| 1414 | if (!newArray->Set(destFunctionContext, idx, entry).FromMaybe(false)) { | 1447 | if (!newArray->Set(destFunctionContext, idx, entry).FromMaybe(false)) { |
| 1415 | Q_ASSERT(false); | 1448 | Q_ASSERT(false); |
| 1416 | } | 1449 | } |
| 1450 | if (entry->StrictEquals(v8ThisObject.get())) { | ||
| 1451 | foundIt = true; | ||
| 1452 | } | ||
| 1417 | } | 1453 | } |
| 1418 | if (!newArray->Set(destFunctionContext, length, v8ThisObject.get()).FromMaybe(false)) { | 1454 | if (!foundIt) { |
| 1419 | Q_ASSERT(false); | 1455 | if (!newArray->Set(destFunctionContext, length, v8ThisObject.get()).FromMaybe(false)) { |
| 1420 | } | 1456 | Q_ASSERT(false); |
| 1421 | if (!destFunction->Set(destFunctionContext, destDataName, newArray).FromMaybe(false)) { | 1457 | } |
| 1422 | Q_ASSERT(false); | 1458 | if (!destFunction->Set(destFunctionContext, destDataName, newArray).FromMaybe(false)) { |
| 1459 | Q_ASSERT(false); | ||
| 1460 | } | ||
| 1423 | } | 1461 | } |
| 1424 | } else { | 1462 | } else { |
| 1425 | v8::Local<v8::Array> newArray = v8::Array::New(isolate, 1); | 1463 | v8::Local<v8::Array> newArray = v8::Array::New(isolate, 1); |
| @@ -1449,9 +1487,11 @@ void ScriptSignalV8Proxy::connect(ScriptValue arg0, ScriptValue arg1) { · 23 unmodified lines | |||
| 1449 | void ScriptSignalV8Proxy::disconnect(ScriptValue arg0, ScriptValue arg1) { | 1487 | void ScriptSignalV8Proxy::disconnect(ScriptValue arg0, ScriptValue arg1) { |
| 1450 | QObject* qobject = _object; | 1488 | QObject* qobject = _object; |
| 1451 | v8::Isolate *isolate = _engine->getIsolate(); | 1489 | v8::Isolate *isolate = _engine->getIsolate(); |
| 1452 | if (!qobject) { | 1490 | if (!_cleanup) { |
| 1453 | isolate->ThrowError("Referencing deleted native object"); | 1491 | if (!qobject) { |
| 1454 | return; | 1492 | isolate->ThrowError("Referencing deleted native object"); |
| 1493 | return; | ||
| 1494 | } | ||
| 1455 | } | 1495 | } |
| 1456 | v8::Locker locker(isolate); | 1496 | v8::Locker locker(isolate); |
| 1457 | v8::Isolate::Scope isolateScope(isolate); | 1497 | v8::Isolate::Scope isolateScope(isolate); |
| @@ -1502,15 +1542,11 @@ void ScriptSignalV8Proxy::disconnect(ScriptValue arg0, ScriptValue arg1) { · 44 unmodified lines | |||
| 1502 | v8::Local<v8::String> destDataName = v8::String::NewFromUtf8(isolate, "__data__").ToLocalChecked(); | 1542 | v8::Local<v8::String> destDataName = v8::String::NewFromUtf8(isolate, "__data__").ToLocalChecked(); |
| 1503 | v8::Local<v8::Value> destData; | 1543 | v8::Local<v8::Value> destData; |
| 1504 | 1544 | ||
| 1505 | //auto destFunctionContext = destFunction->CreationContext(); | ||
| 1506 | auto destFunctionContext = context; | 1545 | auto destFunctionContext = context; |
| 1507 | Q_ASSERT(thisObject().isObject()); | 1546 | ScriptEngine::QObjectWrapOptions options = ScriptEngine::ExcludeSuperClassContents | |
| 1508 | V8ScriptValue v8ThisObject = ScriptValueV8Wrapper::fullUnwrap(_engine, thisObject()); | 1547 | ScriptEngine::PreferExistingWrapperObject; |
| 1509 | Q_ASSERT(ScriptObjectV8Proxy::unwrapProxy(v8ThisObject)); | 1548 | // It's not necessarily new, newQObject looks for it first in object wrapper map, and for already existing signal it should be found there |
| 1510 | // For debugging | 1549 | V8ScriptValue v8ThisObject = ScriptObjectV8Proxy::newQObject(_engine, this, ScriptEngine::ScriptOwnership, options); |
| 1511 | ScriptSignalV8Proxy* thisProxy = dynamic_cast<ScriptSignalV8Proxy*>(ScriptObjectV8Proxy::unwrapProxy(v8ThisObject)->toQObject()); | ||
| 1512 | Q_ASSERT(thisProxy); | ||
| 1513 | //qCDebug(scriptengine_v8) << "ScriptSignalV8Proxy::disconnect: " << thisProxy->fullName() << " fullName: " << fullName(); | ||
| 1514 | if (!destFunction->Get(destFunctionContext, destDataName).ToLocal(&destData)) { | 1550 | if (!destFunction->Get(destFunctionContext, destDataName).ToLocal(&destData)) { |
| 1515 | Q_ASSERT(false); | 1551 | Q_ASSERT(false); |
| 1516 | } | 1552 | } |
| @@ -1518,24 +1554,18 @@ void ScriptSignalV8Proxy::disconnect(ScriptValue arg0, ScriptValue arg1) { · 1 unmodified line | |||
| 1518 | v8::Local<v8::Array> destArray = v8::Local<v8::Array>::Cast(destData); | 1554 | v8::Local<v8::Array> destArray = v8::Local<v8::Array>::Cast(destData); |
| 1519 | int length = destArray->Length(); | 1555 | int length = destArray->Length(); |
| 1520 | v8::Local<v8::Array> newArray = v8::Array::New(isolate, length - 1); | 1556 | v8::Local<v8::Array> newArray = v8::Array::New(isolate, length - 1); |
| 1521 | bool foundIt = false; | 1557 | int findCounter = 0; |
| 1522 | int newIndex = 0; | 1558 | int newIndex = 0; |
| 1523 | for (int idx = 0; idx < length; ++idx) { | 1559 | for (int idx = 0; idx < length; ++idx) { |
| 1524 | v8::Local<v8::Value> entry = destArray->Get(destFunctionContext, idx).ToLocalChecked(); | 1560 | v8::Local<v8::Value> entry = destArray->Get(destFunctionContext, idx).ToLocalChecked(); |
| 1525 | // For debugging: | 1561 | // For debugging: |
| 1526 | { | 1562 | { |
| 1527 | //qCDebug(scriptengine_v8) << "ScriptSignalV8Proxy::disconnect: entry details: " << _engine->scriptValueDebugDetailsV8(V8ScriptValue(_engine, entry)) | ||
| 1528 | // << " Array: " << _engine->scriptValueDebugDetailsV8(V8ScriptValue(_engine, destArray)); | ||
| 1529 | Q_ASSERT(entry->IsObject()); | 1563 | Q_ASSERT(entry->IsObject()); |
| 1530 | V8ScriptValue v8EntryObject(_engine, entry); | 1564 | V8ScriptValue v8EntryObject(_engine, entry); |
| 1531 | Q_ASSERT(ScriptObjectV8Proxy::unwrapProxy(v8EntryObject)); | 1565 | Q_ASSERT(ScriptObjectV8Proxy::unwrapProxy(v8EntryObject)); |
| 1532 | // For debugging | ||
| 1533 | //ScriptSignalV8Proxy* entryProxy = dynamic_cast<ScriptSignalV8Proxy*>(ScriptObjectV8Proxy::unwrapProxy(v8EntryObject)->toQObject()); | ||
| 1534 | Q_ASSERT(thisProxy); | ||
| 1535 | //qCDebug(scriptengine_v8) << "ScriptSignalV8Proxy::disconnect: entry proxy: " << entryProxy->fullName(); | ||
| 1536 | } | 1566 | } |
| 1537 | if (entry->StrictEquals(v8ThisObject.get())) { | 1567 | if (entry->StrictEquals(v8ThisObject.get())) { |
| 1538 | foundIt = true; | 1568 | findCounter++; |
| 1539 | } else { | 1569 | } else { |
| 1540 | if (!newArray->Set(destFunctionContext, newIndex, entry).FromMaybe(false)) { | 1570 | if (!newArray->Set(destFunctionContext, newIndex, entry).FromMaybe(false)) { |
| 1541 | Q_ASSERT(false); | 1571 | Q_ASSERT(false); |
| @@ -1543,7 +1573,7 @@ void ScriptSignalV8Proxy::disconnect(ScriptValue arg0, ScriptValue arg1) { · 1 unmodified line | |||
| 1543 | newIndex++; | 1573 | newIndex++; |
| 1544 | } | 1574 | } |
| 1545 | } | 1575 | } |
| 1546 | Q_ASSERT(foundIt); | 1576 | Q_ASSERT(findCounter == 1); |
| 1547 | if (!destFunction->Set(destFunctionContext, destDataName, newArray).FromMaybe(false)) { | 1577 | if (!destFunction->Set(destFunctionContext, destDataName, newArray).FromMaybe(false)) { |
| 1548 | Q_ASSERT(false); | 1578 | Q_ASSERT(false); |
| 1549 | } | 1579 | } |
| @@ -1554,8 +1584,30 @@ void ScriptSignalV8Proxy::disconnect(ScriptValue arg0, ScriptValue arg1) { · 4 unmodified lines | |||
| 1554 | // inform Qt that we're no longer connected to this signal | 1584 | // inform Qt that we're no longer connected to this signal |
| 1555 | if (_connections.empty()) { | 1585 | if (_connections.empty()) { |
| 1556 | Q_ASSERT(_isConnected); | 1586 | Q_ASSERT(_isConnected); |
| 1557 | bool result = QMetaObject::disconnect(qobject, _meta.methodIndex(), this, _metaCallId); | 1587 | // During cleanup qobject might be null since it might have been already deleted |
| 1558 | Q_ASSERT(result); | 1588 | if (!_cleanup || (_cleanup && qobject)) { |
| 1589 | Q_ASSERT(qobject); | ||
| 1590 | bool result = QMetaObject::disconnect(qobject, _meta.methodIndex(), this, _metaCallId); | ||
| 1591 | Q_ASSERT(result); | ||
| 1592 | } | ||
| 1559 | _isConnected = false; | 1593 | _isConnected = false; |
| 1560 | } | 1594 | } |
| 1561 | } | 1595 | } |
| 1596 | |||
| 1597 | void ScriptSignalV8Proxy::disconnectAllScriptSignalProxies() { | ||
| 1598 | _cleanup = true; | ||
| 1599 | QList<Connection> connections; | ||
| 1600 | withReadLock([&]{ | ||
| 1601 | connections = _connections; | ||
| 1602 | }); | ||
| 1603 | |||
| 1604 | for (auto &connection : connections) { | ||
| 1605 | ScriptValue thisValue(new ScriptValueV8Wrapper(_engine, connection.thisValue)); | ||
| 1606 | ScriptValue callback(new ScriptValueV8Wrapper(_engine, connection.callback)); | ||
| 1607 | disconnect(thisValue, callback); | ||
| 1608 | } | ||
| 1609 | } | ||
| 1610 | |||
| 1611 | void ScriptSignalV8Proxy::disconnectAll() { | ||
| 1612 | QObject::disconnect(this, nullptr, nullptr, nullptr); | ||
| 1613 | } | ||