diff options
author | Liang Qi <liang.qi@qt.io> | 2017-05-29 10:30:39 +0200 |
---|---|---|
committer | Lars Knoll <lars.knoll@qt.io> | 2017-06-06 15:59:38 +0200 |
commit | c254cec22a2352a3fcab60244a6ab74f95d45ace (patch) | |
tree | d8456def48b09bd3914eb87c57ab53376f92c14f /src/qml/jsruntime/qv4internalclass.cpp | |
parent | c158ca8be49a75026e83751dfd825c5bdd63189a (diff) | |
parent | 3f9367cb32533b691cb8c761213f21a524e3d1cb (diff) |
Merge remote-tracking branch 'origin/5.9' into dev
Conflicts:
.qmake.conf
src/qml/jsruntime/qv4argumentsobject.cpp
src/qml/jsruntime/qv4arraydata.cpp
src/qml/jsruntime/qv4context.cpp
src/qml/jsruntime/qv4context_p.h
src/qml/jsruntime/qv4errorobject.cpp
src/qml/jsruntime/qv4functionobject.cpp
src/qml/jsruntime/qv4internalclass.cpp
src/qml/jsruntime/qv4lookup.cpp
src/qml/jsruntime/qv4managed.cpp
src/qml/jsruntime/qv4managed_p.h
src/qml/jsruntime/qv4object.cpp
src/qml/jsruntime/qv4object_p.h
src/qml/jsruntime/qv4qmlcontext.cpp
src/qml/jsruntime/qv4runtime.cpp
src/qml/jsruntime/qv4vme_moth.cpp
src/qml/memory/qv4heap_p.h
src/qml/memory/qv4mm.cpp
src/qml/memory/qv4mm_p.h
src/qml/memory/qv4mmdefs_p.h
src/quick/scenegraph/util/qsgdistancefieldutil.cpp
src/quick/scenegraph/util/qsgdistancefieldutil_p.h
tests/auto/qml/qqmllanguage/tst_qqmllanguage.cpp
Change-Id: I7ed925d4f5d308f872a58ddf51fdce0c8494ec9c
Diffstat (limited to 'src/qml/jsruntime/qv4internalclass.cpp')
-rw-r--r-- | src/qml/jsruntime/qv4internalclass.cpp | 132 |
1 files changed, 119 insertions, 13 deletions
diff --git a/src/qml/jsruntime/qv4internalclass.cpp b/src/qml/jsruntime/qv4internalclass.cpp index 3d9a672f2f..603da1df7b 100644 --- a/src/qml/jsruntime/qv4internalclass.cpp +++ b/src/qml/jsruntime/qv4internalclass.cpp @@ -43,6 +43,7 @@ #include <qv4identifier_p.h> #include "qv4object_p.h" #include "qv4identifiertable_p.h" +#include "qv4value_p.h" QT_BEGIN_NAMESPACE @@ -104,6 +105,8 @@ void PropertyHash::addEntry(const PropertyHash::Entry &entry, int classSize) InternalClass::InternalClass(ExecutionEngine *engine) : engine(engine) + , vtable(0) + , prototype(0) , m_sealed(0) , m_frozen(0) , size(0) @@ -115,6 +118,8 @@ InternalClass::InternalClass(ExecutionEngine *engine) InternalClass::InternalClass(const QV4::InternalClass &other) : QQmlJS::Managed() , engine(other.engine) + , vtable(other.vtable) + , prototype(other.prototype) , propertyTable(other.propertyTable) , nameMap(other.nameMap) , propertyData(other.propertyData) @@ -126,6 +131,24 @@ InternalClass::InternalClass(const QV4::InternalClass &other) Q_ASSERT(extensible); } +static void insertHoleIntoPropertyData(Object *object, int idx) +{ + Heap::Object *o = object->d(); + ExecutionEngine *v4 = o->internalClass->engine; + int size = o->internalClass->size; + for (int i = size - 1; i > idx; --i) + o->setProperty(v4, i, *o->propertyData(i - 1)); +} + +static void removeFromPropertyData(Object *object, int idx, bool accessor = false) +{ + Heap::Object *o = object->d(); + ExecutionEngine *v4 = o->internalClass->engine; + int size = o->internalClass->size; + for (int i = idx; i < size; ++i) + o->setProperty(v4, i, *o->propertyData(i + (accessor ? 2 : 1))); +} + void InternalClass::changeMember(Object *object, String *string, PropertyAttributes data, uint *index) { uint idx; @@ -137,10 +160,10 @@ void InternalClass::changeMember(Object *object, String *string, PropertyAttribu object->setInternalClass(newClass); if (newClass->size > oldClass->size) { Q_ASSERT(newClass->size == oldClass->size + 1); - object->d()->memberData->values.insertData(newClass->engine, idx + 1, Primitive::emptyValue()); + insertHoleIntoPropertyData(object, idx); } else if (newClass->size < oldClass->size) { Q_ASSERT(newClass->size == oldClass->size - 1); - object->d()->memberData->values.removeData(newClass->engine, idx + 1); + removeFromPropertyData(object, idx + 1); } } @@ -167,13 +190,14 @@ InternalClass *InternalClass::changeMember(Identifier *identifier, PropertyAttri if (data == propertyData.at(idx)) return this; - Transition temp = { identifier, 0, (int)data.flags() }; + Transition temp = { { identifier }, nullptr, (int)data.flags() }; Transition &t = lookupOrInsertTransition(temp); if (t.lookup) return t.lookup; // create a new class and add it to the tree - InternalClass *newClass = engine->emptyClass; + InternalClass *newClass = engine->internalClasses[EngineBase::Class_Empty]->changeVTable(vtable); + newClass = newClass->changePrototype(prototype); for (uint i = 0; i < size; ++i) { if (i == idx) { newClass = newClass->addMember(nameMap.at(i), data); @@ -187,12 +211,72 @@ InternalClass *InternalClass::changeMember(Identifier *identifier, PropertyAttri return newClass; } +InternalClass *InternalClass::changePrototypeImpl(Heap::Object *proto) +{ + Q_ASSERT(prototype != proto); + + Transition temp = { { nullptr }, 0, Transition::PrototypeChange }; + temp.prototype = proto; + + Transition &t = lookupOrInsertTransition(temp); + if (t.lookup) + return t.lookup; + + // create a new class and add it to the tree + InternalClass *newClass; + if (!size && !prototype) { + newClass = engine->newClass(*this); + newClass->prototype = proto; + } else { + newClass = engine->internalClasses[EngineBase::Class_Empty]->changeVTable(vtable); + newClass = newClass->changePrototype(proto); + for (uint i = 0; i < size; ++i) { + if (!propertyData.at(i).isEmpty()) + newClass = newClass->addMember(nameMap.at(i), propertyData.at(i)); + } + } + + t.lookup = newClass; + return newClass; +} + +InternalClass *InternalClass::changeVTableImpl(const VTable *vt) +{ + Q_ASSERT(vtable != vt); + + Transition temp = { { nullptr }, nullptr, Transition::VTableChange }; + temp.vtable = vt; + + Transition &t = lookupOrInsertTransition(temp); + if (t.lookup) + return t.lookup; + + // create a new class and add it to the tree + InternalClass *newClass; + if (this == engine->internalClasses[EngineBase::Class_Empty]) { + newClass = engine->newClass(*this); + newClass->vtable = vt; + } else { + newClass = engine->internalClasses[EngineBase::Class_Empty]->changeVTable(vt); + newClass = newClass->changePrototype(prototype); + for (uint i = 0; i < size; ++i) { + if (!propertyData.at(i).isEmpty()) + newClass = newClass->addMember(nameMap.at(i), propertyData.at(i)); + } + } + + t.lookup = newClass; + Q_ASSERT(t.lookup); + Q_ASSERT(newClass->vtable); + return newClass; +} + InternalClass *InternalClass::nonExtensible() { if (!extensible) return this; - Transition temp = { Q_NULLPTR, Q_NULLPTR, Transition::NotExtensible}; + Transition temp = { { nullptr }, nullptr, Transition::NotExtensible}; Transition &t = lookupOrInsertTransition(temp); if (t.lookup) return t.lookup; @@ -240,7 +324,7 @@ InternalClass *InternalClass::addMember(Identifier *identifier, PropertyAttribut InternalClass *InternalClass::addMemberImpl(Identifier *identifier, PropertyAttributes data, uint *index) { - Transition temp = { identifier, 0, (int)data.flags() }; + Transition temp = { { identifier }, nullptr, (int)data.flags() }; Transition &t = lookupOrInsertTransition(temp); if (index) @@ -276,7 +360,7 @@ void InternalClass::removeMember(Object *object, Identifier *id) uint propIdx = oldClass->propertyTable.lookup(id); Q_ASSERT(propIdx < oldClass->size); - Transition temp = { id, 0, -1 }; + Transition temp = { { id }, nullptr, -1 }; Transition &t = object->internalClass()->lookupOrInsertTransition(temp); bool accessor = oldClass->propertyData.at(propIdx).isAccessor(); @@ -285,7 +369,8 @@ void InternalClass::removeMember(Object *object, Identifier *id) object->setInternalClass(t.lookup); } else { // create a new class and add it to the tree - InternalClass *newClass = oldClass->engine->emptyClass; + InternalClass *newClass = oldClass->engine->internalClasses[EngineBase::Class_Empty]->changeVTable(oldClass->vtable); + newClass = newClass->changePrototype(oldClass->prototype); for (uint i = 0; i < oldClass->size; ++i) { if (i == propIdx) continue; @@ -298,14 +383,17 @@ void InternalClass::removeMember(Object *object, Identifier *id) Q_ASSERT(object->internalClass()->size == oldClass->size - (accessor ? 2 : 1)); // remove the entry in the property data - object->d()->memberData->values.removeData(oldClass->engine, propIdx, accessor ? 2 : 1); + removeFromPropertyData(object, propIdx, accessor); t.lookup = object->internalClass(); Q_ASSERT(t.lookup); } -uint InternalClass::find(const Identifier *id) +uint QV4::InternalClass::find(const String *string) { + engine->identifierTable->identifier(string); + const Identifier *id = string->d()->identifier; + uint index = propertyTable.lookup(id); if (index < size) return index; @@ -318,7 +406,8 @@ InternalClass *InternalClass::sealed() if (m_sealed) return m_sealed; - m_sealed = engine->emptyClass; + m_sealed = engine->internalClasses[EngineBase::Class_Empty]->changeVTable(vtable); + m_sealed = m_sealed->changePrototype(prototype); for (uint i = 0; i < size; ++i) { PropertyAttributes attrs = propertyData.at(i); if (attrs.isEmpty()) @@ -347,7 +436,8 @@ InternalClass *InternalClass::frozen() InternalClass *InternalClass::propertiesFrozen() const { - InternalClass *frozen = engine->emptyClass; + InternalClass *frozen = engine->internalClasses[EngineBase::Class_Empty]->changeVTable(vtable); + frozen = frozen->changePrototype(prototype); for (uint i = 0; i < size; ++i) { PropertyAttributes attrs = propertyData.at(i); if (attrs.isEmpty()) @@ -390,7 +480,23 @@ void InternalClass::destroy() void InternalClassPool::markObjects(MarkStack *markStack) { - Q_UNUSED(markStack); + InternalClass *ic = markStack->engine->internalClasses[EngineBase::Class_Empty]; + Q_ASSERT(!ic->prototype); + + // only need to go two levels into the IC hierarchy, as prototype changes + // can only happen there + for (auto &t : ic->transitions) { + Q_ASSERT(t.lookup); + if (t.flags == InternalClassTransition::VTableChange) { + InternalClass *ic2 = t.lookup; + for (auto &t2 : ic2->transitions) { + if (t2.flags == InternalClassTransition::PrototypeChange) + t2.lookup->prototype->mark(markStack); + } + } else if (t.flags == InternalClassTransition::PrototypeChange) { + t.lookup->prototype->mark(markStack); + } + } } QT_END_NAMESPACE |