diff options
Diffstat (limited to 'src/qml/memory')
-rw-r--r-- | src/qml/memory/qv4heap_p.h | 12 | ||||
-rw-r--r-- | src/qml/memory/qv4mm.cpp | 45 | ||||
-rw-r--r-- | src/qml/memory/qv4mm_p.h | 48 | ||||
-rw-r--r-- | src/qml/memory/qv4mmdefs_p.h | 33 | ||||
-rw-r--r-- | src/qml/memory/qv4writebarrier_p.h | 15 |
5 files changed, 81 insertions, 72 deletions
diff --git a/src/qml/memory/qv4heap_p.h b/src/qml/memory/qv4heap_p.h index a38a938588..f00ce4283c 100644 --- a/src/qml/memory/qv4heap_p.h +++ b/src/qml/memory/qv4heap_p.h @@ -53,6 +53,7 @@ #include <QtCore/QString> #include <private/qv4global_p.h> #include <private/qv4mmdefs_p.h> +#include <private/qv4internalclass_p.h> #include <QSharedPointer> // To check if Heap::Base::init is called (meaning, all subclasses did their init and called their @@ -69,10 +70,14 @@ QT_BEGIN_NAMESPACE namespace QV4 { +struct InternalClass; + struct VTable { const VTable * const parent; const quint64 markTable; + uint inlinePropertyOffset : 16; + uint nInlineProperties : 16; uint isExecutionContext : 1; uint isString : 1; uint isObject : 1; @@ -94,13 +99,12 @@ struct Q_QML_EXPORT Base { static Q_CONSTEXPR quint64 markTable = 0; - const VTable *vt; + InternalClass *internalClass; inline ReturnedValue asReturnedValue() const; inline void mark(QV4::MarkStack *markStack); - void setVtable(const VTable *v) { vt = v; } - const VTable *vtable() const { return vt; } + const VTable *vtable() const { return internalClass->vtable; } inline bool isMarked() const { const HeapItem *h = reinterpret_cast<const HeapItem *>(this); Chunk *c = h->chunk(); @@ -175,7 +179,7 @@ V4_ASSERT_IS_TRIVIAL(Base) // for a size/offset translation when cross-compiling between 32- and // 64-bit. Q_STATIC_ASSERT(std::is_standard_layout<Base>::value); -Q_STATIC_ASSERT(offsetof(Base, vt) == 0); +Q_STATIC_ASSERT(offsetof(Base, internalClass) == 0); Q_STATIC_ASSERT(sizeof(Base) == QT_POINTER_SIZE); } diff --git a/src/qml/memory/qv4mm.cpp b/src/qml/memory/qv4mm.cpp index 64b07153cc..de97918fb0 100644 --- a/src/qml/memory/qv4mm.cpp +++ b/src/qml/memory/qv4mm.cpp @@ -348,8 +348,9 @@ static void increaseFreedCountForClass(const char *className) (*freedObjectStatsGlobal())[className]++; } -void Chunk::sweep(ClassDestroyStatsCallback classCountPtr) +bool Chunk::sweep(ClassDestroyStatsCallback classCountPtr) { + bool hasUsedSlots = false; SDUMP() << "sweeping chunk" << this; HeapItem *o = realBase(); bool lastSlotFree = false; @@ -395,6 +396,7 @@ void Chunk::sweep(ClassDestroyStatsCallback classCountPtr) } objectBitmap[i] = blackBitmap[i]; grayBitmap[i] = 0; + hasUsedSlots |= (blackBitmap[i] != 0); extendsBitmap[i] = e; lastSlotFree = !((objectBitmap[i]|extendsBitmap[i]) >> (sizeof(quintptr)*8 - 1)); SDUMP() << " new extends =" << binary(e); @@ -403,6 +405,7 @@ void Chunk::sweep(ClassDestroyStatsCallback classCountPtr) o += Chunk::Bits; } // DEBUG << "swept chunk" << this << "freed" << slotsFreed << "slots."; + return hasUsedSlots; } void Chunk::freeAll() @@ -700,12 +703,21 @@ void BlockAllocator::sweep(ClassDestroyStatsCallback classCountPtr) // qDebug() << "BlockAlloc: sweep"; usedSlotsAfterLastSweep = 0; - for (auto c : chunks) { - c->sweep(classCountPtr); - c->sortIntoBins(freeBins, NumBins); -// qDebug() << "used slots in chunk" << c << ":" << c->nUsedSlots(); - usedSlotsAfterLastSweep += c->nUsedSlots(); - } + + auto isFree = [this, classCountPtr] (Chunk *c) { + bool isUsed = c->sweep(classCountPtr); + + if (isUsed) { + c->sortIntoBins(freeBins, NumBins); + usedSlotsAfterLastSweep += c->nUsedSlots(); + } else { + chunkAllocator->free(c); + } + return !isUsed; + }; + + auto newEnd = std::remove_if(chunks.begin(), chunks.end(), isFree); + chunks.erase(newEnd, chunks.end()); } void BlockAllocator::freeAll() @@ -922,13 +934,17 @@ Heap::Base *MemoryManager::allocData(std::size_t size) return *m; } -Heap::Object *MemoryManager::allocObjectWithMemberData(std::size_t size, uint nMembers) +Heap::Object *MemoryManager::allocObjectWithMemberData(const QV4::VTable *vtable, uint nMembers) { + uint size = (vtable->nInlineProperties + vtable->inlinePropertyOffset)*sizeof(Value); + Q_ASSERT(!(size % sizeof(HeapItem))); + Heap::Object *o; - if (!nMembers) { + if (nMembers <= vtable->nInlineProperties) { o = static_cast<Heap::Object *>(allocData(size)); } else { // Allocate both in one go through the block allocator + nMembers -= vtable->nInlineProperties; std::size_t memberSize = align(sizeof(Heap::MemberData) + (nMembers - 1)*sizeof(Value)); size_t totalSize = size + memberSize; Heap::MemberData *m; @@ -947,7 +963,8 @@ Heap::Object *MemoryManager::allocObjectWithMemberData(std::size_t size, uint nM Chunk::clearBit(c->extendsBitmap, index); } o->memberData.set(engine, m); - m->setVtable(MemberData::staticVTable()); + m->internalClass = 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; m->init(); @@ -1147,7 +1164,8 @@ void MemoryManager::runGC() qDebug() << " Allocations since last GC" << allocationCount; allocationCount = 0; #endif - qDebug() << "Allocated" << totalMem << "bytes in" << blockAllocator.chunks.size() << "chunks"; + size_t oldChunks = blockAllocator.chunks.size(); + qDebug() << "Allocated" << totalMem << "bytes in" << oldChunks << "chunks"; qDebug() << "Fragmented memory before GC" << (totalMem - usedBefore); dumpBins(&blockAllocator); @@ -1190,8 +1208,9 @@ void MemoryManager::runGC() }); qDebug() << "Used memory before GC:" << usedBefore; - qDebug() << "Used memory after GC :" << usedAfter; - qDebug() << "Freed up bytes :" << (usedBefore - usedAfter); + qDebug() << "Used memory after GC:" << usedAfter; + qDebug() << "Freed up bytes :" << (usedBefore - usedAfter); + qDebug() << "Freed up chunks :" << (oldChunks - blockAllocator.chunks.size()); size_t lost = blockAllocator.allocatedMem() - memInBins - usedAfter; if (lost) qDebug() << "!!!!!!!!!!!!!!!!!!!!! LOST MEM:" << lost << "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!"; diff --git a/src/qml/memory/qv4mm_p.h b/src/qml/memory/qv4mm_p.h index df7d09dce0..17957d0cd6 100644 --- a/src/qml/memory/qv4mm_p.h +++ b/src/qml/memory/qv4mm_p.h @@ -211,12 +211,13 @@ public: Q_DECL_CONSTEXPR static inline std::size_t align(std::size_t size) { return (size + Chunk::SlotSize - 1) & ~(Chunk::SlotSize - 1); } - QV4::Heap::SimpleCallContext *allocSimpleCallContext(QV4::ExecutionEngine *v4) + QV4::Heap::CallContext *allocSimpleCallContext() { Heap::CallContext *ctxt = stackAllocator.allocate(); memset(ctxt, 0, sizeof(Heap::SimpleCallContext)); - ctxt->setVtable(QV4::SimpleCallContext::staticVTable()); - ctxt->init(v4); + ctxt->internalClass = SimpleCallContext::defaultInternalClass(engine); + Q_ASSERT(ctxt->internalClass && ctxt->internalClass->vtable); + ctxt->init(); return ctxt; } @@ -229,16 +230,20 @@ public: V4_ASSERT_IS_TRIVIAL(typename ManagedType::Data) size = align(size); Heap::Base *o = allocData(size); - o->setVtable(ManagedType::staticVTable()); + InternalClass *ic = ManagedType::defaultInternalClass(engine); + ic = ic->changeVTable(ManagedType::staticVTable()); + o->internalClass = ic; + Q_ASSERT(o->internalClass && o->internalClass->vtable); return static_cast<typename ManagedType::Data *>(o); } template <typename ObjectType> typename ObjectType::Data *allocateObject(InternalClass *ic) { - Heap::Object *o = allocObjectWithMemberData(align(sizeof(typename ObjectType::Data)), ic->size); - o->setVtable(ObjectType::staticVTable()); + Heap::Object *o = allocObjectWithMemberData(ObjectType::staticVTable(), ic->size); o->internalClass = ic; + Q_ASSERT(o->internalClass && o->internalClass->vtable); + Q_ASSERT(ic->vtable == ObjectType::staticVTable()); return static_cast<typename ObjectType::Data *>(o); } @@ -246,11 +251,12 @@ public: typename ObjectType::Data *allocateObject() { InternalClass *ic = ObjectType::defaultInternalClass(engine); - Heap::Object *o = allocObjectWithMemberData(align(sizeof(typename ObjectType::Data)), ic->size); - o->setVtable(ObjectType::staticVTable()); - Object *prototype = ObjectType::defaultPrototype(engine); + ic = ic->changeVTable(ObjectType::staticVTable()); + ic = ic->changePrototype(ObjectType::defaultPrototype(engine)->d()); + Heap::Object *o = allocObjectWithMemberData(ObjectType::staticVTable(), ic->size); o->internalClass = ic; - o->prototype.set(engine, prototype->d()); + Q_ASSERT(o->internalClass && o->internalClass->vtable); + Q_ASSERT(o->internalClass->prototype == ObjectType::defaultPrototype(engine)->d()); return static_cast<typename ObjectType::Data *>(o); } @@ -258,8 +264,9 @@ public: typename ManagedType::Data *allocWithStringData(std::size_t unmanagedSize, Arg1 arg1) { typename ManagedType::Data *o = reinterpret_cast<typename ManagedType::Data *>(allocString(unmanagedSize)); - o->setVtable(ManagedType::staticVTable()); - o->init(this, arg1); + o->internalClass = ManagedType::defaultInternalClass(engine); + Q_ASSERT(o->internalClass && o->internalClass->vtable); + o->init(arg1); return o; } @@ -277,7 +284,8 @@ public: { Scope scope(engine); Scoped<ObjectType> t(scope, allocateObject<ObjectType>(ic)); - t->d_unchecked()->prototype.set(engine, prototype->d()); + Q_ASSERT(t->internalClass()->prototype == (prototype ? prototype->d() : 0)); + Q_UNUSED(prototype); t->d_unchecked()->init(); return t->d(); } @@ -287,7 +295,8 @@ public: { Scope scope(engine); Scoped<ObjectType> t(scope, allocateObject<ObjectType>(ic)); - t->d_unchecked()->prototype.set(engine, prototype->d()); + Q_ASSERT(t->internalClass()->prototype == (prototype ? prototype->d() : 0)); + Q_UNUSED(prototype); t->d_unchecked()->init(arg1); return t->d(); } @@ -297,7 +306,8 @@ public: { Scope scope(engine); Scoped<ObjectType> t(scope, allocateObject<ObjectType>(ic)); - t->d_unchecked()->prototype.set(engine, prototype->d()); + Q_ASSERT(t->internalClass()->prototype == (prototype ? prototype->d() : 0)); + Q_UNUSED(prototype); t->d_unchecked()->init(arg1, arg2); return t->d(); } @@ -307,7 +317,8 @@ public: { Scope scope(engine); Scoped<ObjectType> t(scope, allocateObject<ObjectType>(ic)); - t->d_unchecked()->prototype.set(engine, prototype->d()); + Q_ASSERT(t->internalClass()->prototype == (prototype ? prototype->d() : 0)); + Q_UNUSED(prototype); t->d_unchecked()->init(arg1, arg2, arg3); return t->d(); } @@ -317,7 +328,8 @@ public: { Scope scope(engine); Scoped<ObjectType> t(scope, allocateObject<ObjectType>(ic)); - t->d_unchecked()->prototype.set(engine, prototype->d()); + Q_ASSERT(t->internalClass()->prototype == (prototype ? prototype->d() : 0)); + Q_UNUSED(prototype); t->d_unchecked()->init(arg1, arg2, arg3, arg4); return t->d(); } @@ -437,7 +449,7 @@ protected: /// expects size to be aligned Heap::Base *allocString(std::size_t unmanagedSize); Heap::Base *allocData(std::size_t size); - Heap::Object *allocObjectWithMemberData(std::size_t size, uint nMembers); + Heap::Object *allocObjectWithMemberData(const QV4::VTable *vtable, uint nMembers); #ifdef DETAILED_MM_STATS void willAllocate(std::size_t size); diff --git a/src/qml/memory/qv4mmdefs_p.h b/src/qml/memory/qv4mmdefs_p.h index bf29b44a2c..328797fb5e 100644 --- a/src/qml/memory/qv4mmdefs_p.h +++ b/src/qml/memory/qv4mmdefs_p.h @@ -186,7 +186,7 @@ struct Chunk { return usedSlots; } - void sweep(ClassDestroyStatsCallback classCountPtr); + bool sweep(ClassDestroyStatsCallback classCountPtr); void freeAll(); void resetBlackBits(); void collectGrayItems(QV4::MarkStack *markStack); @@ -269,7 +269,7 @@ Q_STATIC_ASSERT(sizeof(HeapItem) == Chunk::SlotSize); Q_STATIC_ASSERT(QT_POINTER_SIZE*8 == Chunk::Bits); Q_STATIC_ASSERT((1 << Chunk::BitShift) == Chunk::Bits); -struct MarkStack {\ +struct MarkStack { MarkStack(ExecutionEngine *engine); Heap::Base **top = 0; Heap::Base **base = 0; @@ -287,35 +287,6 @@ struct MarkStack {\ }; -// Base class for the execution engine - -#if defined(Q_CC_MSVC) || defined(Q_CC_GNU) -#pragma pack(push, 1) -#endif -struct EngineBase { - Heap::ExecutionContext *current = 0; - - Value *jsStackTop = 0; - quint8 hasException = false; - quint8 writeBarrierActive = false; - quint16 unused = 0; -#if QT_POINTER_SIZE == 8 - quint8 padding[4]; -#endif - MemoryManager *memoryManager = 0; - Runtime runtime; -}; -#if defined(Q_CC_MSVC) || defined(Q_CC_GNU) -#pragma pack(pop) -#endif - -Q_STATIC_ASSERT(std::is_standard_layout<EngineBase>::value); -Q_STATIC_ASSERT(offsetof(EngineBase, current) == 0); -Q_STATIC_ASSERT(offsetof(EngineBase, jsStackTop) == offsetof(EngineBase, current) + QT_POINTER_SIZE); -Q_STATIC_ASSERT(offsetof(EngineBase, hasException) == offsetof(EngineBase, jsStackTop) + QT_POINTER_SIZE); -Q_STATIC_ASSERT(offsetof(EngineBase, memoryManager) == offsetof(EngineBase, hasException) + QT_POINTER_SIZE); -Q_STATIC_ASSERT(offsetof(EngineBase, runtime) == offsetof(EngineBase, memoryManager) + QT_POINTER_SIZE); - // Some helper classes and macros to automate the generation of our // tables used for marking objects diff --git a/src/qml/memory/qv4writebarrier_p.h b/src/qml/memory/qv4writebarrier_p.h index e36ea0749a..86fd28000d 100644 --- a/src/qml/memory/qv4writebarrier_p.h +++ b/src/qml/memory/qv4writebarrier_p.h @@ -123,7 +123,7 @@ struct Pointer { return base; } - void set(ExecutionEngine *e, T newVal) { + void set(EngineBase *e, T newVal) { WriteBarrier::write(e, base(), reinterpret_cast<Heap::Base **>(&ptr), reinterpret_cast<Heap::Base *>(newVal)); } @@ -146,9 +146,12 @@ struct HeapValue : Value { return base; } - void set(ExecutionEngine *e, const Value &newVal) { + void set(EngineBase *e, const Value &newVal) { WriteBarrier::write(e, base(), this, newVal); } + void set(EngineBase *e, Heap::Base *b) { + WriteBarrier::write(e, base(), this, b); + } }; template <size_t offset> @@ -163,10 +166,10 @@ struct ValueArray { return base; } - void set(ExecutionEngine *e, uint index, Value v) { + void set(EngineBase *e, uint index, Value v) { WriteBarrier::write(e, base(), values + index, v); } - void set(ExecutionEngine *e, uint index, Heap::Base *b) { + void set(EngineBase *e, uint index, Heap::Base *b) { WriteBarrier::write(e, base(), values + index, b); } inline const Value &operator[] (uint index) const { @@ -177,13 +180,13 @@ struct ValueArray { return values; } - void insertData(ExecutionEngine *e, uint index, Value v) { + void insertData(EngineBase *e, uint index, Value v) { for (uint i = size - 1; i > index; --i) { values[i] = values[i - 1]; } set(e, index, v); } - void removeData(ExecutionEngine *e, uint index, int n = 1) { + void removeData(EngineBase *e, uint index, int n = 1) { Q_UNUSED(e); for (uint i = index; i < size - n; ++i) { values[i] = values[i + n]; |