diff options
author | Lars Knoll <lars.knoll@qt.io> | 2018-01-05 15:30:23 +0100 |
---|---|---|
committer | Lars Knoll <lars.knoll@qt.io> | 2018-04-12 13:59:08 +0000 |
commit | 6002b48c3c5edc509c269c801fc8a088d5065ce8 (patch) | |
tree | a8fc764de87bfbd5f201930dcec1c7459502eb7e /src/qml/memory | |
parent | 3932536b59df7b2fa010be6dd9f2501f6e306c8b (diff) |
garbage collect InternalClass
Internal classes are now allocated and collected through
the GC. As they are important to the deletion of other
objects (because of the vtable pointer living inside the
internal class), they need to get destroyed after regular
objects have been sweeped. Achieve this by using a separate
block allocator for internal class objects.
Our lookups do often contain pointers to internal classes,
so those need to be marked as well, so we don't accidentally
collect them.
Change-Id: I4762b054361c70c31f79f920f669ea0e8551601f
Reviewed-by: Simon Hausmann <simon.hausmann@qt.io>
Diffstat (limited to 'src/qml/memory')
-rw-r--r-- | src/qml/memory/qv4heap_p.h | 5 | ||||
-rw-r--r-- | src/qml/memory/qv4mm.cpp | 15 | ||||
-rw-r--r-- | src/qml/memory/qv4mm_p.h | 54 |
3 files changed, 52 insertions, 22 deletions
diff --git a/src/qml/memory/qv4heap_p.h b/src/qml/memory/qv4heap_p.h index 1ca37fe95f..f327388355 100644 --- a/src/qml/memory/qv4heap_p.h +++ b/src/qml/memory/qv4heap_p.h @@ -113,9 +113,9 @@ Q_STATIC_ASSERT(std::is_trivial< V4PointerCheck >::value); struct Q_QML_EXPORT Base { void *operator new(size_t) = delete; - static void markObjects(Base *, MarkStack *) {} + static void markObjects(Base *, MarkStack *); - InternalClass *internalClass; + Pointer<InternalClass *, 0> internalClass; inline ReturnedValue asReturnedValue() const; inline void mark(QV4::MarkStack *markStack); @@ -195,7 +195,6 @@ Q_STATIC_ASSERT(std::is_standard_layout<Base>::value); Q_STATIC_ASSERT(offsetof(Base, internalClass) == 0); Q_STATIC_ASSERT(sizeof(Base) == QT_POINTER_SIZE); - inline void Base::mark(QV4::MarkStack *markStack) { diff --git a/src/qml/memory/qv4mm.cpp b/src/qml/memory/qv4mm.cpp index fcc00ff331..06313c3d30 100644 --- a/src/qml/memory/qv4mm.cpp +++ b/src/qml/memory/qv4mm.cpp @@ -643,8 +643,9 @@ void BlockAllocator::sweep() void BlockAllocator::freeAll() { - for (auto c : chunks) { + for (auto c : chunks) c->freeAll(engine); + for (auto c : chunks) { Q_V4_PROFILE_DEALLOC(engine, Chunk::DataSize, Profiling::HeapPage); chunkAllocator->free(c); } @@ -758,6 +759,7 @@ MemoryManager::MemoryManager(ExecutionEngine *engine) : engine(engine) , chunkAllocator(new ChunkAllocator) , blockAllocator(chunkAllocator, engine) + , icAllocator(chunkAllocator, engine) , hugeItemAllocator(chunkAllocator, engine) , m_persistentValues(new PersistentValueStorage(engine)) , m_weakValues(new PersistentValueStorage(engine)) @@ -884,7 +886,7 @@ Heap::Object *MemoryManager::allocObjectWithMemberData(const QV4::VTable *vtable Chunk::clearBit(c->extendsBitmap, index); } o->memberData.set(engine, m); - m->internalClass = engine->internalClasses(EngineBase::Class_MemberData); + m->internalClass.set(engine, engine->internalClasses(EngineBase::Class_MemberData)); Q_ASSERT(o->memberData->internalClass); m->values.alloc = static_cast<uint>((memberSize - sizeof(Heap::MemberData) + sizeof(Value))/sizeof(Value)); m->values.size = o->memberData->values.alloc; @@ -1017,8 +1019,11 @@ void MemoryManager::sweep(bool lastSweep, ClassDestroyStatsCallback classCountPt } } - blockAllocator.sweep(); - hugeItemAllocator.sweep(classCountPtr); + if (!lastSweep) { + blockAllocator.sweep(/*classCountPtr*/); + hugeItemAllocator.sweep(classCountPtr); + icAllocator.sweep(/*classCountPtr*/); + } } bool MemoryManager::shouldRunGC() const @@ -1167,6 +1172,7 @@ void MemoryManager::runGC() // reset all black bits blockAllocator.resetBlackBits(); hugeItemAllocator.resetBlackBits(); + icAllocator.resetBlackBits(); } size_t MemoryManager::getUsedMem() const @@ -1193,6 +1199,7 @@ MemoryManager::~MemoryManager() sweep(/*lastSweep*/true); blockAllocator.freeAll(); hugeItemAllocator.freeAll(); + icAllocator.freeAll(); delete m_weakValues; #ifdef V4_USE_VALGRIND diff --git a/src/qml/memory/qv4mm_p.h b/src/qml/memory/qv4mm_p.h index ae2153e7c4..bc9b7130c7 100644 --- a/src/qml/memory/qv4mm_p.h +++ b/src/qml/memory/qv4mm_p.h @@ -160,37 +160,52 @@ public: { return (size + Chunk::SlotSize - 1) & ~(Chunk::SlotSize - 1); } template<typename ManagedType> - inline typename ManagedType::Data *allocManaged(std::size_t size, InternalClass *ic) + inline typename ManagedType::Data *allocManaged(std::size_t size, Heap::InternalClass *ic) { Q_STATIC_ASSERT(std::is_trivial< typename ManagedType::Data >::value); size = align(size); - Heap::Base *o = allocData(size); - o->internalClass = ic; - Q_ASSERT(o->internalClass && o->internalClass->vtable); + typename ManagedType::Data *d = static_cast<typename ManagedType::Data *>(allocData(size)); + d->internalClass.set(engine, ic); + Q_ASSERT(d->internalClass && d->internalClass->vtable); Q_ASSERT(ic->vtable == ManagedType::staticVTable()); - return static_cast<typename ManagedType::Data *>(o); + return d; + } + + template<typename ManagedType> + inline typename ManagedType::Data *allocManaged(std::size_t size, InternalClass *ic) + { + return allocManaged<ManagedType>(size, ic->d()); } template<typename ManagedType> inline typename ManagedType::Data *allocManaged(std::size_t size) { - return allocManaged<ManagedType>(size, ManagedType::defaultInternalClass(engine)); + Scope scope(engine); + Scoped<InternalClass> ic(scope, ManagedType::defaultInternalClass(engine)); + return allocManaged<ManagedType>(size, ic); } template <typename ObjectType> - typename ObjectType::Data *allocateObject(InternalClass *ic) + typename ObjectType::Data *allocateObject(Heap::InternalClass *ic) { Heap::Object *o = allocObjectWithMemberData(ObjectType::staticVTable(), ic->size); - o->internalClass = ic; - Q_ASSERT(o->internalClass && o->internalClass->vtable); - Q_ASSERT(ic->vtable == ObjectType::staticVTable()); + o->internalClass.set(engine, ic); + Q_ASSERT(o->internalClass.get() && o->vtable()); + Q_ASSERT(o->vtable() == ObjectType::staticVTable()); return static_cast<typename ObjectType::Data *>(o); } template <typename ObjectType> + typename ObjectType::Data *allocateObject(InternalClass *ic) + { + return allocateObject<ObjectType>(ic->d()); + } + + template <typename ObjectType> typename ObjectType::Data *allocateObject() { - InternalClass *ic = ObjectType::defaultInternalClass(engine); + Scope scope(engine); + Scoped<InternalClass> ic(scope, ObjectType::defaultInternalClass(engine)); ic = ic->changeVTable(ObjectType::staticVTable()); ic = ic->changePrototype(ObjectType::defaultPrototype(engine)->d()); return allocateObject<ObjectType>(ic); @@ -200,18 +215,18 @@ public: typename ManagedType::Data *allocWithStringData(std::size_t unmanagedSize, Arg1 arg1) { typename ManagedType::Data *o = reinterpret_cast<typename ManagedType::Data *>(allocString(unmanagedSize)); - o->internalClass = ManagedType::defaultInternalClass(engine); + o->internalClass.set(engine, ManagedType::defaultInternalClass(engine)); Q_ASSERT(o->internalClass && o->internalClass->vtable); o->init(arg1); return o; } - template <typename ObjectType> - typename ObjectType::Data *allocObject(InternalClass *ic) + template <typename ObjectType, typename... Args> + typename ObjectType::Data *allocObject(Heap::InternalClass *ic, Args... args) { Scope scope(engine); Scoped<ObjectType> t(scope, allocateObject<ObjectType>(ic)); - t->d_unchecked()->init(); + t->d_unchecked()->init(args...); return t->d(); } @@ -253,6 +268,14 @@ public: // called when a JS object grows itself. Specifically: Heap::String::append void changeUnmanagedHeapSizeUsage(qptrdiff delta) { unmanagedHeapSize += delta; } + template<typename ManagedType> + typename ManagedType::Data *allocIC() + { + size_t size = align(sizeof(typename ManagedType::Data)); + Heap::Base *b = *icAllocator.allocate(size, true); + return static_cast<typename ManagedType::Data *>(b); + } + protected: /// expects size to be aligned Heap::Base *allocString(std::size_t unmanagedSize); @@ -270,6 +293,7 @@ public: QV4::ExecutionEngine *engine; ChunkAllocator *chunkAllocator; BlockAllocator blockAllocator; + BlockAllocator icAllocator; HugeItemAllocator hugeItemAllocator; PersistentValueStorage *m_persistentValues; PersistentValueStorage *m_weakValues; |