aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLars Knoll <lars.knoll@qt.io>2018-09-10 23:30:04 +0200
committerLars Knoll <lars.knoll@qt.io>2018-09-16 17:00:22 +0000
commite436fb3569603bca8ad0a71fef67c03d2920aedc (patch)
treea8076925a788fd721c8b46119f0f13009ca882e8
parent6982d0d6290c137468749bb8ab2f2e20dfa453fd (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>
-rw-r--r--src/plugins/qmltooling/qmldbg_debugger/qv4datacollector.cpp2
-rw-r--r--src/plugins/qmltooling/qmldbg_nativedebugger/qqmlnativedebugservice.cpp2
-rw-r--r--src/qml/jsruntime/qv4internalclass.cpp100
-rw-r--r--src/qml/jsruntime/qv4internalclass_p.h39
-rw-r--r--src/qml/jsruntime/qv4memberdata.cpp5
m---------tests/auto/qml/ecmascripttests/test2620
6 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
diff --git a/tests/auto/qml/ecmascripttests/test262 b/tests/auto/qml/ecmascripttests/test262
-Subproject 6b0c42c63c2492bd0a7a96d3179d122b5f71793
+Subproject 3c69133cc419840c1be34638039cd8c48a7ef58