construct,
0 /*markObjects*/,
destroy,
+ 0 /*collectDeletables*/,
hasInstance,
0,
0,
Q_MANAGED_CHECK \
static const QV4::ManagedVTable static_vtbl;
+struct GCDeletable
+{
+ GCDeletable() : next(0), lastCall(false) {}
+ virtual ~GCDeletable() {}
+ GCDeletable *next;
+ bool lastCall;
+};
struct ManagedVTable
{
Value (*construct)(Managed *, ExecutionContext *context, Value *args, int argc);
void (*markObjects)(Managed *);
void (*destroy)(Managed *);
+ void (*collectDeletables)(Managed *, GCDeletable **deletable);
bool (*hasInstance)(Managed *, ExecutionContext *ctx, const Value &value);
Value (*get)(Managed *, ExecutionContext *ctx, String *name, bool *hasProperty);
Value (*getIndexed)(Managed *, ExecutionContext *ctx, uint index, bool *hasProperty);
construct, \
markObjects, \
destroy, \
+ 0, \
hasInstance, \
get, \
getIndexed, \
#classname \
}
+#define DEFINE_MANAGED_VTABLE_WITH_DELETABLES(classname) \
+const QV4::ManagedVTable classname::static_vtbl = \
+{ \
+ call, \
+ construct, \
+ markObjects, \
+ destroy, \
+ collectDeletables, \
+ hasInstance, \
+ get, \
+ getIndexed, \
+ put, \
+ putIndexed, \
+ query, \
+ queryIndexed, \
+ deleteProperty, \
+ deleteIndexedProperty, \
+ getLookup, \
+ setLookup, \
+ isEqualTo, \
+ advanceIterator, \
+ #classname \
+}
struct Q_QML_EXPORT Managed
{
}
}
-std::size_t MemoryManager::sweep()
+std::size_t MemoryManager::sweep(bool lastSweep)
{
PersistentValuePrivate *weak = m_weakValues;
while (weak) {
}
std::size_t freedCount = 0;
+ GCDeletable *deletable = 0;
+ GCDeletable **firstDeletable = &deletable;
for (QVector<Data::Chunk>::iterator i = m_d->heapChunks.begin(), ei = m_d->heapChunks.end(); i != ei; ++i)
- freedCount += sweep(reinterpret_cast<char*>(i->memory.base()), i->memory.size(), i->chunkSize);
+ freedCount += sweep(reinterpret_cast<char*>(i->memory.base()), i->memory.size(), i->chunkSize, &deletable);
ExecutionContext *ctx = m_contextList;
ExecutionContext **n = &m_contextList;
ctx = next;
}
+ deletable = *firstDeletable;
+ while (deletable) {
+ GCDeletable *next = deletable->next;
+ deletable->lastCall = lastSweep;
+ delete deletable;
+ deletable = next;
+ }
+
return freedCount;
}
-std::size_t MemoryManager::sweep(char *chunkStart, std::size_t chunkSize, size_t size)
+std::size_t MemoryManager::sweep(char *chunkStart, std::size_t chunkSize, size_t size, GCDeletable **deletable)
{
// qDebug("chunkStart @ %p, size=%x, pos=%x (%x)", chunkStart, size, size>>4, m_d->smallItems[size >> 4]);
std::size_t freedCount = 0;
#ifdef V4_USE_VALGRIND
VALGRIND_ENABLE_ERROR_REPORTING;
#endif
+ if (m->vtbl->collectDeletables)
+ m->vtbl->collectDeletables(m, deletable);
m->vtbl->destroy(m);
m->setNextFree(*f);
MemoryManager::~MemoryManager()
{
- PersistentValuePrivate *weak = m_weakValues;
- while (weak) {
- if (QObjectWrapper *qobjectWrapper = weak->value.as<QObjectWrapper>()) {
- weak->ref();
- qobjectWrapper->deleteQObject(/*deleteInstantly*/ true);
- PersistentValuePrivate *n = weak->next;
- weak->deref();
- weak = n;
- } else
- weak = weak->next;
- }
-
PersistentValuePrivate *persistent = m_persistentValues;
while (persistent) {
PersistentValuePrivate *n = persistent->next;
persistent = n;
}
- sweep();
+ sweep(/*lastSweep*/true);
#ifdef V4_USE_VALGRIND
VALGRIND_DESTROY_MEMPOOL(this);
#endif
struct ExecutionEngine;
struct ExecutionContext;
struct Managed;
+struct GCDeletable;
class Q_QML_EXPORT MemoryManager
{
private:
void collectFromStack() const;
void mark();
- std::size_t sweep();
- std::size_t sweep(char *chunkStart, std::size_t chunkSize, size_t size);
+ std::size_t sweep(bool lastSweep = false);
+ std::size_t sweep(char *chunkStart, std::size_t chunkSize, size_t size, GCDeletable **deletable);
protected:
QScopedPointer<Data> m_d;
m_toString = engine->newIdentifier(QStringLiteral("toString"));
}
-QObjectWrapper::~QObjectWrapper()
-{
- deleteQObject();
-}
-
void QObjectWrapper::initializeBindings(ExecutionEngine *engine)
{
engine->functionPrototype->defineDefaultProperty(engine, QStringLiteral("connect"), method_connect);
engine->functionPrototype->defineDefaultProperty(engine, QStringLiteral("disconnect"), method_disconnect);
}
-namespace {
- struct SafeQMLObjectDeleter : public QObject
- {
- SafeQMLObjectDeleter(QObject *objectToDelete)
- : m_objectToDelete(objectToDelete)
- {}
-
- ~SafeQMLObjectDeleter()
- {
- QQmlData *ddata = QQmlData::get(m_objectToDelete, false);
- if (ddata && ddata->ownContext && ddata->context)
- ddata->context->emitDestruction();
- // This object is notionally destroyed now
- ddata->isQueuedForDeletion = true;
- delete m_objectToDelete;
- }
-
- QObject *m_objectToDelete;
- };
-}
-
-void QObjectWrapper::deleteQObject(bool deleteInstantly)
-{
- if (!m_object)
- return;
- QQmlData *ddata = QQmlData::get(m_object, false);
- if (!ddata)
- return;
- if (!m_object->parent() && !ddata->indestructible) {
- if (deleteInstantly) {
- QQmlData *ddata = QQmlData::get(m_object, false);
- if (ddata->ownContext && ddata->context)
- ddata->context->emitDestruction();
- // This object is notionally destroyed now
- ddata->isQueuedForDeletion = true;
- delete m_object;
- } else {
- QObject *deleter = new SafeQMLObjectDeleter(m_object);
- deleter->deleteLater();
- m_object = 0;
- }
- }
-}
-
QQmlPropertyData *QObjectWrapper::findProperty(ExecutionEngine *engine, QQmlContextData *qmlContext, String *name, RevisionMode revisionMode, QQmlPropertyData *local) const
{
QHashedV4String propertystring(QV4::Value::fromString(name));
QV4::Object::markObjects(that);
}
-DEFINE_MANAGED_VTABLE(QObjectWrapper);
+namespace {
+ struct QObjectDeleter : public QV4::GCDeletable
+ {
+ QObjectDeleter(QObject *o)
+ : m_objectToDelete(o)
+ {}
+ ~QObjectDeleter()
+ {
+ QQmlData *ddata = QQmlData::get(m_objectToDelete, false);
+ if (ddata && ddata->ownContext && ddata->context)
+ ddata->context->emitDestruction();
+ // This object is notionally destroyed now
+ ddata->isQueuedForDeletion = true;
+ if (lastCall)
+ delete m_objectToDelete;
+ else
+ m_objectToDelete->deleteLater();
+ }
+
+ QObject *m_objectToDelete;
+ };
+}
+
+void QObjectWrapper::collectDeletables(Managed *m, GCDeletable **deletable)
+{
+ QObjectWrapper *This = static_cast<QObjectWrapper*>(m);
+ QQmlGuard<QObject> &object = This->m_object;
+ if (!object)
+ return;
+
+ QQmlData *ddata = QQmlData::get(object, false);
+ if (!ddata)
+ return;
+
+ if (object->parent() || ddata->indestructible)
+ return;
+
+ QObjectDeleter *deleter = new QObjectDeleter(object);
+ object = 0;
+ deleter->next = *deletable;
+ *deletable = deleter;
+}
+
+DEFINE_MANAGED_VTABLE_WITH_DELETABLES(QObjectWrapper);
// XXX TODO: Need to review all calls to QQmlEngine *engine() to confirm QObjects work
// correctly in a worker thread
enum RevisionMode { IgnoreRevision, CheckRevision };
- ~QObjectWrapper();
-
static void initializeBindings(ExecutionEngine *engine);
QObject *object() const { return m_object.data(); }
- void deleteQObject(bool deleteInstantly = false);
-
Value getQmlProperty(ExecutionContext *ctx, QQmlContextData *qmlContext, String *name, RevisionMode revisionMode, bool *hasProperty = 0, bool includeImports = false);
static Value getQmlProperty(ExecutionContext *ctx, QQmlContextData *qmlContext, QObject *object, String *name, RevisionMode revisionMode, bool *hasProperty = 0);
static PropertyAttributes query(const Managed *, String *name);
static Property *advanceIterator(Managed *m, ObjectIterator *it, String **name, uint *index, PropertyAttributes *attributes);
static void markObjects(Managed *that);
-
+ static void collectDeletables(Managed *m, GCDeletable **deletable);
static void destroy(Managed *that)
{
static_cast<QObjectWrapper *>(that)->~QObjectWrapper();
construct,
0 /*markObjects*/,
destroy,
+ 0 /*collectDeletables*/,
hasInstance,
get,
getIndexed,