diff options
author | Lars Knoll <lars.knoll@qt.io> | 2018-09-10 23:30:04 +0200 |
---|---|---|
committer | Lars Knoll <lars.knoll@qt.io> | 2018-09-16 17:00:22 +0000 |
commit | e436fb3569603bca8ad0a71fef67c03d2920aedc (patch) | |
tree | a8076925a788fd721c8b46119f0f13009ca882e8 /src | |
parent | 6982d0d6290c137468749bb8ab2f2e20dfa453fd (diff) |
Store InternalClass::nameMap in a MemberData
This helps make that memory known to the GC as well, and makes
marking of internal classes much more efficient, as we don't
mark the property keys repeatedly (even if they are shared
between different internal classes)
Change-Id: Ibb7e5383672d7657926bd08bf13f73f7680a9f31
Reviewed-by: Simon Hausmann <simon.hausmann@qt.io>
Diffstat (limited to 'src')
-rw-r--r-- | src/plugins/qmltooling/qmldbg_debugger/qv4datacollector.cpp | 2 | ||||
-rw-r--r-- | src/plugins/qmltooling/qmldbg_nativedebugger/qqmlnativedebugservice.cpp | 2 | ||||
-rw-r--r-- | src/qml/jsruntime/qv4internalclass.cpp | 100 | ||||
-rw-r--r-- | src/qml/jsruntime/qv4internalclass_p.h | 39 | ||||
-rw-r--r-- | src/qml/jsruntime/qv4memberdata.cpp | 5 |
5 files changed, 126 insertions, 22 deletions
diff --git a/src/plugins/qmltooling/qmldbg_debugger/qv4datacollector.cpp b/src/plugins/qmltooling/qmldbg_debugger/qv4datacollector.cpp index 5bfeca13e3..3dfb755936 100644 --- a/src/plugins/qmltooling/qmldbg_debugger/qv4datacollector.cpp +++ b/src/plugins/qmltooling/qmldbg_debugger/qv4datacollector.cpp @@ -224,7 +224,7 @@ bool QV4DataCollector::collectScope(QJsonObject *dict, int frameNr, int scopeNr) QV4::ScopedValue v(scope); QV4::Heap::InternalClass *ic = ctxt->internalClass(); for (uint i = 0; i < ic->size; ++i) { - QString name = ic->nameMap[i].toQString(); + QString name = ic->keyAt(i); names.append(name); v = static_cast<QV4::Heap::CallContext *>(ctxt->d())->locals[i]; collectedRefs.append(addValueRef(v)); diff --git a/src/plugins/qmltooling/qmldbg_nativedebugger/qqmlnativedebugservice.cpp b/src/plugins/qmltooling/qmldbg_nativedebugger/qqmlnativedebugservice.cpp index 3b47f73949..cda16207c2 100644 --- a/src/plugins/qmltooling/qmldbg_nativedebugger/qqmlnativedebugservice.cpp +++ b/src/plugins/qmltooling/qmldbg_nativedebugger/qqmlnativedebugservice.cpp @@ -494,7 +494,7 @@ void NativeDebugger::handleVariables(QJsonObject *response, const QJsonObject &a QV4::Heap::InternalClass *ic = callContext->internalClass(); QV4::ScopedValue v(scope); for (uint i = 0; i < ic->size; ++i) { - QString name = ic->nameMap[i].toQString(); + QString name = ic->keyAt(i); v = callContext->d()->locals[i]; collector.collect(&output, QString(), name, v); } diff --git a/src/qml/jsruntime/qv4internalclass.cpp b/src/qml/jsruntime/qv4internalclass.cpp index c890dc0550..b22d3073b9 100644 --- a/src/qml/jsruntime/qv4internalclass.cpp +++ b/src/qml/jsruntime/qv4internalclass.cpp @@ -137,14 +137,83 @@ void PropertyHash::detach(bool grow, int classSize) d = dd; } + +SharedInternalClassDataPrivate<PropertyKey>::SharedInternalClassDataPrivate(const SharedInternalClassDataPrivate<PropertyKey> &other) + : refcount(1), + engine(other.engine), + data(nullptr) +{ + if (other.alloc()) { + int s = other.size(); + data = MemberData::allocate(engine, other.alloc(), other.data); + setSize(s); + } +} + +SharedInternalClassDataPrivate<PropertyKey>::SharedInternalClassDataPrivate(const SharedInternalClassDataPrivate<PropertyKey> &other, + uint pos, PropertyKey value) + : refcount(1), + engine(other.engine) +{ + data = MemberData::allocate(engine, other.alloc(), nullptr); + memcpy(data, other.data, sizeof(Heap::MemberData) - sizeof(Value) + pos*sizeof(Value)); + data->values.size = pos + 1; + data->values.set(engine, pos, Value::fromReturnedValue(value.id())); +} + +void SharedInternalClassDataPrivate<PropertyKey>::grow() +{ + uint a = alloc() * 2; + int s = size(); + data = MemberData::allocate(engine, a, data); + setSize(s); + Q_ASSERT(alloc() >= a); +} + +uint SharedInternalClassDataPrivate<PropertyKey>::alloc() const +{ + return data ? data->values.alloc : 0; +} + +uint SharedInternalClassDataPrivate<PropertyKey>::size() const +{ + return data ? data->values.size : 0; +} + +void SharedInternalClassDataPrivate<PropertyKey>::setSize(uint s) +{ + Q_ASSERT(data && s <= alloc()); + data->values.size = s; +} + +PropertyKey SharedInternalClassDataPrivate<PropertyKey>::at(uint i) +{ + Q_ASSERT(data && i < size()); + return PropertyKey::fromId(data->values.values[i].rawValue()); +} + +void SharedInternalClassDataPrivate<PropertyKey>::set(uint i, PropertyKey t) +{ + Q_ASSERT(data && i < size()); + data->values.values[i].rawValueRef() = t.id(); +} + +void SharedInternalClassDataPrivate<PropertyKey>::mark(MarkStack *s) +{ + if (data) + data->mark(s); +} + + + namespace Heap { void InternalClass::init(ExecutionEngine *engine) { Base::init(); new (&propertyTable) PropertyHash(); - new (&nameMap) SharedInternalClassData<PropertyKey>(); - new (&propertyData) SharedInternalClassData<PropertyAttributes>(); + new (&nameMap) SharedInternalClassData<PropertyKey>(engine); + new (&propertyData) SharedInternalClassData<PropertyAttributes>(engine); new (&transitions) std::vector<Transition>(); this->engine = engine; @@ -204,6 +273,11 @@ void InternalClass::destroy() Base::destroy(); } +QString InternalClass::keyAt(uint index) const +{ + return nameMap.at(index).toQString(); +} + static void insertHoleIntoPropertyData(QV4::Object *object, int idx) { Heap::Object *o = object->d(); @@ -288,8 +362,8 @@ Heap::InternalClass *InternalClass::changeMember(PropertyKey identifier, Propert if (data.isAccessor() != propertyData.at(idx).isAccessor()) { // this changes the layout of the class, so we need to rebuild the data newClass->propertyTable = PropertyHash(); - newClass->nameMap = SharedInternalClassData<PropertyKey>(); - newClass->propertyData = SharedInternalClassData<PropertyAttributes>(); + newClass->nameMap = SharedInternalClassData<PropertyKey>(engine); + newClass->propertyData = SharedInternalClassData<PropertyAttributes>(engine); newClass->size = 0; for (uint i = 0; i < size; ++i) { PropertyKey identifier = nameMap.at(i); @@ -423,7 +497,9 @@ Heap::InternalClass *InternalClass::addMemberImpl(PropertyKey identifier, Proper return t.lookup; // create a new class and add it to the tree - Heap::InternalClass *newClass = engine->newClass(this); + Scope scope(engine); + Scoped<QV4::InternalClass> ic(scope, engine->newClass(this)); + InternalClass *newClass = ic->d(); PropertyHash::Entry e = { identifier, newClass->size }; newClass->propertyTable.addEntry(e, newClass->size); @@ -504,7 +580,9 @@ Heap::InternalClass *InternalClass::sealed() return t.lookup; } - Heap::InternalClass *s = engine->newClass(this); + Scope scope(engine); + Scoped<QV4::InternalClass> ic(scope, engine->newClass(this)); + Heap::InternalClass *s = ic->d(); for (uint i = 0; i < size; ++i) { PropertyAttributes attrs = propertyData.at(i); @@ -550,7 +628,9 @@ Heap::InternalClass *InternalClass::frozen() return t.lookup; } - Heap::InternalClass *f = engine->newClass(this); + Scope scope(engine); + Scoped<QV4::InternalClass> ic(scope, engine->newClass(this)); + Heap::InternalClass *f = ic->d(); for (uint i = 0; i < size; ++i) { PropertyAttributes attrs = propertyData.at(i); @@ -631,11 +711,7 @@ void InternalClass::markObjects(Heap::Base *b, MarkStack *stack) if (ic->parent) ic->parent->mark(stack); - for (uint i = 0; i < ic->size; ++i) { - PropertyKey id = ic->nameMap.at(i); - if (Heap::Base *b = id.asStringOrSymbol()) - b->mark(stack); - } + ic->nameMap.mark(stack); } } diff --git a/src/qml/jsruntime/qv4internalclass_p.h b/src/qml/jsruntime/qv4internalclass_p.h index 8bf83d87b4..cb45343d6d 100644 --- a/src/qml/jsruntime/qv4internalclass_p.h +++ b/src/qml/jsruntime/qv4internalclass_p.h @@ -143,7 +143,7 @@ inline uint PropertyHash::lookup(PropertyKey identifier) const template<typename T> struct SharedInternalClassDataPrivate { - SharedInternalClassDataPrivate() + SharedInternalClassDataPrivate(ExecutionEngine *) : refcount(1), m_alloc(0), m_size(0), @@ -159,7 +159,7 @@ struct SharedInternalClassDataPrivate { memcpy(data, other.data, m_size*sizeof(T)); } } - SharedInternalClassDataPrivate(const SharedInternalClassDataPrivate &other, int pos, T value) + SharedInternalClassDataPrivate(const SharedInternalClassDataPrivate &other, uint pos, T value) : refcount(1), m_alloc(pos + 8), m_size(pos + 1) @@ -191,21 +191,45 @@ struct SharedInternalClassDataPrivate { T at(uint i) { Q_ASSERT(data && i < m_alloc); return data[i]; } void set(uint i, T t) { Q_ASSERT(data && i < m_alloc); data[i] = t; } - int refcount; + void mark(MarkStack *) {} + + int refcount = 1; private: uint m_alloc; uint m_size; T *data; }; +template<> +struct SharedInternalClassDataPrivate<PropertyKey> { + SharedInternalClassDataPrivate(ExecutionEngine *e) : refcount(1), engine(e), data(nullptr) {} + SharedInternalClassDataPrivate(const SharedInternalClassDataPrivate &other); + SharedInternalClassDataPrivate(const SharedInternalClassDataPrivate &other, uint pos, PropertyKey value); + ~SharedInternalClassDataPrivate() {} + + void grow(); + uint alloc() const; + uint size() const; + void setSize(uint s); + + PropertyKey at(uint i); + void set(uint i, PropertyKey t); + + void mark(MarkStack *s); + + int refcount = 1; +private: + ExecutionEngine *engine; + Heap::MemberData *data; +}; template <typename T> struct SharedInternalClassData { using Private = SharedInternalClassDataPrivate<T>; Private *d; - inline SharedInternalClassData() { - d = new Private; + inline SharedInternalClassData(ExecutionEngine *e) { + d = new Private(e); } inline SharedInternalClassData(const SharedInternalClassData &other) @@ -238,8 +262,8 @@ struct SharedInternalClassData { Q_ASSERT(pos == d->size()); if (pos == d->alloc()) d->grow(); - d->set(pos, value); d->setSize(d->size() + 1); + d->set(pos, value); } void set(uint pos, T value) { @@ -262,6 +286,8 @@ struct SharedInternalClassData { Q_ASSERT(i < d->size()); return d->at(i); } + + void mark(MarkStack *s) { d->mark(s); } }; struct InternalClassTransition @@ -318,6 +344,7 @@ struct InternalClass : Base { void init(InternalClass *other); void destroy(); + Q_QML_PRIVATE_EXPORT QString keyAt(uint index) const; Q_REQUIRED_RESULT InternalClass *nonExtensible(); static void addMember(QV4::Object *object, PropertyKey id, PropertyAttributes data, uint *index); diff --git a/src/qml/jsruntime/qv4memberdata.cpp b/src/qml/jsruntime/qv4memberdata.cpp index da086bd47a..246f857643 100644 --- a/src/qml/jsruntime/qv4memberdata.cpp +++ b/src/qml/jsruntime/qv4memberdata.cpp @@ -62,8 +62,9 @@ static size_t nextPowerOfTwo(size_t s) Heap::MemberData *MemberData::allocate(ExecutionEngine *e, uint n, Heap::MemberData *old) { - Q_ASSERT(!old || old->values.size < n); - Q_ASSERT(n); + Q_ASSERT(!old || old->values.size <= n); + if (!n) + n = 4; size_t alloc = MemoryManager::align(sizeof(Heap::MemberData) + (n - 1)*sizeof(Value)); // round up to next power of two to avoid quadratic behaviour for very large objects |