diff options
Diffstat (limited to 'src/qml/jsruntime/qv4internalclass.cpp')
-rw-r--r-- | src/qml/jsruntime/qv4internalclass.cpp | 127 |
1 files changed, 95 insertions, 32 deletions
diff --git a/src/qml/jsruntime/qv4internalclass.cpp b/src/qml/jsruntime/qv4internalclass.cpp index 761a180722..7c4a8de284 100644 --- a/src/qml/jsruntime/qv4internalclass.cpp +++ b/src/qml/jsruntime/qv4internalclass.cpp @@ -151,33 +151,53 @@ InternalClass::InternalClass(const QV4::InternalClass &other) { } -// ### Should we build this up from the empty class to avoid duplication? +void InternalClass::changeMember(Object *object, String *string, PropertyAttributes data, uint *index) +{ + uint idx; + InternalClass *newClass = object->internalClass->changeMember(string, data, &idx); + if (index) + *index = idx; + + if (newClass->size > object->internalClass->size) { + Q_ASSERT(newClass->size == object->internalClass->size + 1); + memmove(object->memberData + idx + 2, object->memberData + idx + 1, (object->internalClass->size - idx - 1)*sizeof(Property)); + } else if (newClass->size < object->internalClass->size) { + Q_ASSERT(newClass->size == object->internalClass->size - 1); + memmove(object->memberData + idx + 1, object->memberData + idx + 2, (object->internalClass->size - idx - 2)*sizeof(Property)); + } + object->internalClass = newClass; +} + InternalClass *InternalClass::changeMember(String *string, PropertyAttributes data, uint *index) { -// qDebug() << "InternalClass::changeMember()" << string->toQString() << hex << (uint)data.m_all; data.resolve(); uint idx = find(string); + Q_ASSERT(idx != UINT_MAX); + if (index) *index = idx; - Q_ASSERT(idx != UINT_MAX); - if (data == propertyData.at(idx)) return this; - Transition t = { { string->identifier }, (int)data.flags() }; QHash<Transition, InternalClass *>::const_iterator tit = transitions.constFind(t); if (tit != transitions.constEnd()) return tit.value(); // create a new class and add it to the tree - InternalClass *newClass = engine->newClass(*this); - newClass->propertyData.set(idx, data); + InternalClass *newClass = engine->emptyClass->changeVTable(vtable); + newClass = newClass->changePrototype(prototype); + for (uint i = 0; i < size; ++i) { + if (i == idx) { + newClass = newClass->addMember(nameMap.at(i), data); + } else if (!propertyData.at(i).isEmpty()) { + newClass = newClass->addMember(nameMap.at(i), propertyData.at(i)); + } + } transitions.insert(t, newClass); return newClass; - } InternalClass *InternalClass::create(ExecutionEngine *engine, const ManagedVTable *vtable, Object *proto) @@ -209,8 +229,10 @@ InternalClass *InternalClass::changePrototype(Object *proto) } else { newClass = engine->emptyClass->changeVTable(vtable); newClass = newClass->changePrototype(proto); - for (uint i = 0; i < size; ++i) - newClass = newClass->addMember(nameMap.at(i), propertyData.at(i)); + for (uint i = 0; i < size; ++i) { + if (!propertyData.at(i).isEmpty()) + newClass = newClass->addMember(nameMap.at(i), propertyData.at(i)); + } } transitions.insert(t, newClass); @@ -238,14 +260,39 @@ InternalClass *InternalClass::changeVTable(const ManagedVTable *vt) } else { newClass = engine->emptyClass->changeVTable(vt); newClass = newClass->changePrototype(prototype); - for (uint i = 0; i < size; ++i) - newClass = newClass->addMember(nameMap.at(i), propertyData.at(i)); + for (uint i = 0; i < size; ++i) { + if (!propertyData.at(i).isEmpty()) + newClass = newClass->addMember(nameMap.at(i), propertyData.at(i)); + } } transitions.insert(t, newClass); return newClass; } +void InternalClass::addMember(Object *object, StringRef string, PropertyAttributes data, uint *index) +{ + return addMember(object, string.getPointer(), data, index); +} + +void InternalClass::addMember(Object *object, String *string, PropertyAttributes data, uint *index) +{ + data.resolve(); + object->internalClass->engine->identifierTable->identifier(string); + if (object->internalClass->propertyTable.lookup(string->identifier) < object->internalClass->size) { + changeMember(object, string, data, index); + return; + } + + uint idx; + InternalClass *newClass = object->internalClass->addMemberImpl(string, data, &idx); + if (index) + *index = idx; + + object->internalClass = newClass; +} + + InternalClass *InternalClass::addMember(StringRef string, PropertyAttributes data, uint *index) { return addMember(string.getPointer(), data, index); @@ -253,13 +300,17 @@ InternalClass *InternalClass::addMember(StringRef string, PropertyAttributes dat InternalClass *InternalClass::addMember(String *string, PropertyAttributes data, uint *index) { -// qDebug() << "InternalClass::addMember()" << string->toQString() << size << hex << (uint)data.m_all << data.type(); data.resolve(); engine->identifierTable->identifier(string); if (propertyTable.lookup(string->identifier) < size) return changeMember(string, data, index); + return addMemberImpl(string, data, index); +} + +InternalClass *InternalClass::addMemberImpl(String *string, PropertyAttributes data, uint *index) +{ Transition t = { { string->identifier }, (int)data.flags() }; QHash<Transition, InternalClass *>::const_iterator tit = transitions.constFind(t); @@ -270,44 +321,56 @@ InternalClass *InternalClass::addMember(String *string, PropertyAttributes data, // create a new class and add it to the tree InternalClass *newClass = engine->newClass(*this); - PropertyHash::Entry e = { string->identifier, size }; - newClass->propertyTable.addEntry(e, size); + PropertyHash::Entry e = { string->identifier, newClass->size }; + newClass->propertyTable.addEntry(e, newClass->size); // The incoming string can come from anywhere, so make sure to // store a string in the nameMap that's guaranteed to get // marked properly during GC. String *name = engine->newIdentifier(string->toQString()); - newClass->nameMap.add(size, name); - - newClass->propertyData.add(size, data); + newClass->nameMap.add(newClass->size, name); + newClass->propertyData.add(newClass->size, data); ++newClass->size; + if (data.isAccessor()) { + // add a dummy entry, since we need two entries for accessors + newClass->propertyTable.addEntry(e, newClass->size); + newClass->nameMap.add(newClass->size, 0); + newClass->propertyData.add(newClass->size, PropertyAttributes()); + ++newClass->size; + } + transitions.insert(t, newClass); return newClass; } void InternalClass::removeMember(Object *object, Identifier *id) { - uint propIdx = propertyTable.lookup(id); - Q_ASSERT(propIdx < size); + InternalClass *oldClass = object->internalClass; + uint propIdx = oldClass->propertyTable.lookup(id); + Q_ASSERT(propIdx < oldClass->size); Transition t = { { id } , -1 }; - QHash<Transition, InternalClass *>::const_iterator tit = transitions.constFind(t); + QHash<Transition, InternalClass *>::const_iterator tit = object->internalClass->transitions.constFind(t); - if (tit != transitions.constEnd()) { + if (tit != object->internalClass->transitions.constEnd()) { object->internalClass = tit.value(); - return; + } else { + // create a new class and add it to the tree + InternalClass *newClass = oldClass->engine->emptyClass->changeVTable(oldClass->vtable); + newClass = newClass->changePrototype(oldClass->prototype); + for (uint i = 0; i < oldClass->size; ++i) { + if (i == propIdx) + continue; + if (!oldClass->propertyData.at(i).isEmpty()) + newClass = newClass->addMember(oldClass->nameMap.at(i), oldClass->propertyData.at(i)); + } + object->internalClass = newClass; } - // create a new class and add it to the tree - object->internalClass = engine->emptyClass->changeVTable(vtable); - object->internalClass = object->internalClass->changePrototype(prototype); - for (uint i = 0; i < size; ++i) { - if (i == propIdx) - continue; - object->internalClass = object->internalClass->addMember(nameMap.at(i), propertyData.at(i)); - } + // remove the entry in memberdata + memmove(object->memberData + propIdx, object->memberData + propIdx + 1, (object->internalClass->size - propIdx)*sizeof(Property)); - transitions.insert(t, object->internalClass); + oldClass->transitions.insert(t, object->internalClass); } uint InternalClass::find(const StringRef string) |