aboutsummaryrefslogtreecommitdiffstats
path: root/src/qml/memory
diff options
context:
space:
mode:
authorLars Knoll <lars.knoll@qt.io>2017-01-24 12:07:33 +0100
committerLars Knoll <lars.knoll@qt.io>2017-03-09 08:58:04 +0000
commit6b4b2f5f1bbd706742cbab8764a1d07cbd912600 (patch)
treed11734823cbf27c557fea8b9be5225c1303d7b12 /src/qml/memory
parent78dd18a0cd18449e1289e428ea6eca65e28fb114 (diff)
New mark table implementation
Automatically generate a table containing the data where JS Values and pointers are in objects in the JS heap. This will allow making the GC mark phase a lot more efficient. A bit of a special hack is currently required for MemberData and ArrayData, as they have a variable length, and we need to read the size from the object. We keep backwards compatibility with the old markObjects() functions for now (calling them if they are defined). Some further work on QV4::String and in a few other places is required before we can get remove the compatibility. Change-Id: I78528ace67e886bdbe4a4330c9677c7fc9f08a33 Reviewed-by: Simon Hausmann <simon.hausmann@qt.io>
Diffstat (limited to 'src/qml/memory')
-rw-r--r--src/qml/memory/qv4heap_p.h3
-rw-r--r--src/qml/memory/qv4mm.cpp55
-rw-r--r--src/qml/memory/qv4mm_p.h1
-rw-r--r--src/qml/memory/qv4mmdefs_p.h48
4 files changed, 102 insertions, 5 deletions
diff --git a/src/qml/memory/qv4heap_p.h b/src/qml/memory/qv4heap_p.h
index 8285ef4de7..28d39b7fb7 100644
--- a/src/qml/memory/qv4heap_p.h
+++ b/src/qml/memory/qv4heap_p.h
@@ -72,6 +72,7 @@ namespace QV4 {
struct VTable
{
const VTable * const parent;
+ const quint64 markTable;
uint isExecutionContext : 1;
uint isString : 1;
uint isObject : 1;
@@ -91,6 +92,8 @@ namespace Heap {
struct Q_QML_EXPORT Base {
void *operator new(size_t) = delete;
+ static Q_CONSTEXPR quint64 markTable = 0;
+
const VTable *vt;
inline ReturnedValue asReturnedValue() const;
diff --git a/src/qml/memory/qv4mm.cpp b/src/qml/memory/qv4mm.cpp
index a829e902fb..bb600c6c0f 100644
--- a/src/qml/memory/qv4mm.cpp
+++ b/src/qml/memory/qv4mm.cpp
@@ -740,13 +740,58 @@ Heap::Object *MemoryManager::allocObjectWithMemberData(std::size_t size, uint nM
return o;
}
-static void drainMarkStack(QV4::ExecutionEngine *engine, Value *markBase)
+void MemoryManager::drainMarkStack(Value *markBase)
{
while (engine->jsStackTop > markBase) {
Heap::Base *h = engine->popForGC();
Q_ASSERT(h); // at this point we should only have Heap::Base objects in this area on the stack. If not, weird things might happen.
- Q_ASSERT (h->vtable()->markObjects);
- h->vtable()->markObjects(h, engine);
+ if (h->vtable()->markObjects)
+ h->vtable()->markObjects(h, engine);
+ if (quint64 m = h->vtable()->markTable) {
+// qDebug() << "using mark table:" << hex << m << "for" << h;
+ void **mem = reinterpret_cast<void **>(h);
+ while (m) {
+ MarkFlags mark = static_cast<MarkFlags>(m & 3);
+ switch (mark) {
+ case Mark_NoMark:
+ break;
+ case Mark_Value:
+// qDebug() << "marking value at " << mem;
+ reinterpret_cast<Value *>(mem)->mark(engine);
+ break;
+ case Mark_Pointer: {
+// qDebug() << "marking pointer at " << mem;
+ Heap::Pointer<Heap::Base> *p = reinterpret_cast<Heap::Pointer<Heap::Base> *>(mem);
+ if (*p)
+ (*p)->mark(engine);
+ break;
+ }
+ case Mark_ValueArray: {
+ Q_ASSERT(m == Mark_ValueArray);
+// qDebug() << "marking Value Array at offset" << hex << (mem - reinterpret_cast<void **>(h));
+ uint size;
+ Value *v = reinterpret_cast<Value *>(mem);
+ if (h->vtable() == QV4::MemberData::staticVTable()) {
+ size = static_cast<Heap::MemberData *>(h)->size;
+ } else if (h->vtable()->isArrayData) {
+ size = static_cast<Heap::ArrayData *>(h)->alloc;
+ } else {
+ size = 0;
+ Q_ASSERT(false);
+ }
+ const Value *end = v + size;
+ while (v < end) {
+ v->mark(engine);
+ ++v;
+ }
+ break;
+ }
+ }
+
+ m >>= 2;
+ ++mem;
+ }
+ }
}
}
@@ -788,10 +833,10 @@ void MemoryManager::mark()
qobjectWrapper->mark(engine);
if (engine->jsStackTop >= engine->jsStackLimit)
- drainMarkStack(engine, markBase);
+ drainMarkStack(markBase);
}
- drainMarkStack(engine, markBase);
+ drainMarkStack(markBase);
}
void MemoryManager::sweep(bool lastSweep)
diff --git a/src/qml/memory/qv4mm_p.h b/src/qml/memory/qv4mm_p.h
index 00daf8a622..016879799a 100644
--- a/src/qml/memory/qv4mm_p.h
+++ b/src/qml/memory/qv4mm_p.h
@@ -427,6 +427,7 @@ public:
// called when a JS object grows itself. Specifically: Heap::String::append
void changeUnmanagedHeapSizeUsage(qptrdiff delta) { unmanagedHeapSize += delta; }
+ void drainMarkStack(Value *markBase);
protected:
diff --git a/src/qml/memory/qv4mmdefs_p.h b/src/qml/memory/qv4mmdefs_p.h
index 588ae21ee0..90e7d9cb61 100644
--- a/src/qml/memory/qv4mmdefs_p.h
+++ b/src/qml/memory/qv4mmdefs_p.h
@@ -255,6 +255,54 @@ Q_STATIC_ASSERT(sizeof(HeapItem) == Chunk::SlotSize);
Q_STATIC_ASSERT(QT_POINTER_SIZE*8 == Chunk::Bits);
Q_STATIC_ASSERT((1 << Chunk::BitShift) == Chunk::Bits);
+// Some helper classes and macros to automate the generation of our
+// tables used for marking objects
+
+enum MarkFlags {
+ Mark_NoMark = 0,
+ Mark_Value = 1,
+ Mark_Pointer = 2,
+ Mark_ValueArray = 3
+};
+
+template<typename T>
+struct MarkFlagsForType {
+ static const quint64 markFlags = Mark_NoMark;
+};
+template<typename T>
+struct MarkFlagsForType<Heap::Pointer<T>> {
+ static const quint64 markFlags = Mark_Pointer;
+};
+template<>
+struct MarkFlagsForType<Value> {
+ static const quint64 markFlags = Mark_Value;
+};
+
+typedef Value ValueArray[1];
+template<>
+struct MarkFlagsForType<ValueArray> {
+ static const quint64 markFlags = Mark_ValueArray;
+};
+
+#define HEAP_OBJECT_MEMBER_EXPANSION(c, type, name) type name;
+
+#define HEAP_OBJECT_MARK_EXPANSION(class, type, name) \
+ (MarkFlagsForType<decltype(class::name)>::markFlags << (offsetof(class, name) >> 2)) |
+
+#define DECLARE_HEAP_OBJECT(name, base) \
+struct name##Data { \
+ name##Members(name, HEAP_OBJECT_MEMBER_EXPANSION) \
+}; \
+struct name##SizeStruct : base, name##Data {}; \
+static Q_CONSTEXPR quint64 name##_markTable = \
+ (name##Members(name##Data, HEAP_OBJECT_MARK_EXPANSION) 0) << (((sizeof(name##SizeStruct) - sizeof(name##Data)) >> 2) | QV4::Heap::base::markTable; \
+ \
+struct name : base, name##Data
+
+#define DECLARE_MARK_TABLE(class) static Q_CONSTEXPR quint64 markTable = class##_markTable
+
+
+
}
QT_END_NAMESPACE