From 3d96b151936e8f9ee03d7cef54b09d5032a5257e Mon Sep 17 00:00:00 2001 From: Lars Knoll Date: Fri, 1 Feb 2013 15:59:22 +0100 Subject: [PATCH] Refactor property access Move the property descriptors into a a vector and separate them from the lookup table. This is a pre-requirement for a hidden class implementation later on. Change-Id: Ib08b8152597ae0b6c883eef0fced55ee0cb4c286 Reviewed-by: Simon Hausmann --- src/v4/qv4array.cpp | 13 ++++++++++++- src/v4/qv4array.h | 13 ++++--------- src/v4/qv4arrayobject.cpp | 2 +- src/v4/qv4object.cpp | 16 ++++++++++------ src/v4/qv4objectiterator.cpp | 11 +++++++---- src/v4/qv4propertytable.h | 21 ++++++++++++++++----- src/v4/qv4regexpobject.cpp | 16 +++++++++++----- src/v4/qv4regexpobject.h | 2 +- src/v4/qv4stringobject.cpp | 2 +- 9 files changed, 63 insertions(+), 33 deletions(-) diff --git a/src/v4/qv4array.cpp b/src/v4/qv4array.cpp index 9879b2f..5f0d838 100644 --- a/src/v4/qv4array.cpp +++ b/src/v4/qv4array.cpp @@ -464,7 +464,7 @@ SparseArrayNode *SparseArray::insert(uint akey) Array::Array(const Array &other) : len(other.len) - , lengthProperty(0) + , arrayObject(0) , values(other.values) , sparse(0) { @@ -581,7 +581,18 @@ void Array::initSparse() } } +void Array::setLengthUnchecked(uint l) +{ + len = l; + if (arrayObject) { + // length is always the first property of an array + PropertyDescriptor &lengthProperty = arrayObject->members->values[0]; + lengthProperty.value = Value::fromUInt32(l); + } +} + bool Array::setLength(uint newLen) { + const PropertyDescriptor *lengthProperty = arrayObject->members->values.constData(); if (lengthProperty && !lengthProperty->isWritable()) return false; uint oldLen = length(); diff --git a/src/v4/qv4array.h b/src/v4/qv4array.h index 9fb8bb6..b165ed2 100644 --- a/src/v4/qv4array.h +++ b/src/v4/qv4array.h @@ -367,7 +367,7 @@ class Array friend struct ArrayPrototype; uint len; - PropertyDescriptor *lengthProperty; + ArrayObject *arrayObject; union { uint freeList; uint offset; @@ -429,7 +429,7 @@ class Array } public: - Array() : len(0), lengthProperty(0), offset(0), sparse(0) {} + Array() : len(0), arrayObject(0), offset(0), sparse(0) {} Array(const Array &other); ~Array() { delete sparse; } void initSparse(); @@ -437,14 +437,9 @@ public: uint length() const { return len; } bool setLength(uint newLen); - void setLengthProperty(PropertyDescriptor *pd) { lengthProperty = pd; } - PropertyDescriptor *getLengthProperty() { return lengthProperty; } + void setArrayObject(ArrayObject *a) { arrayObject = a; } - void setLengthUnchecked(uint l) { - len = l; - if (lengthProperty) - lengthProperty->value = Value::fromUInt32(l); - } + void setLengthUnchecked(uint l); PropertyDescriptor *insert(uint index) { PropertyDescriptor *pd; diff --git a/src/v4/qv4arrayobject.cpp b/src/v4/qv4arrayobject.cpp index 032b56f..680a373 100644 --- a/src/v4/qv4arrayobject.cpp +++ b/src/v4/qv4arrayobject.cpp @@ -654,7 +654,7 @@ Value ArrayPrototype::method_map(ExecutionContext *ctx) Value thisArg = ctx->argument(1); ArrayObject *a = ctx->engine->newArrayObject(ctx); - a->array.setLength(len); + a->array.setLengthUnchecked(len); for (uint k = 0; k < len; ++k) { bool exists; diff --git a/src/v4/qv4object.cpp b/src/v4/qv4object.cpp index 6f5fb60..6a5aa21 100644 --- a/src/v4/qv4object.cpp +++ b/src/v4/qv4object.cpp @@ -187,11 +187,13 @@ void Object::markObjects() if (!(*it)) continue; (*it)->name->mark(); - PropertyDescriptor &pd = (*it)->descriptor; + } + for (int i = 0; i < (uint)members->values.size(); ++i) { + const PropertyDescriptor &pd = members->values.at(i); if (pd.isData()) { if (Managed *m = pd.value.asManaged()) m->mark(); - } else if (pd.isAccessor()) { + } else if (pd.isAccessor()) { if (pd.get) pd.get->mark(); if (pd.set) @@ -503,7 +505,7 @@ bool Object::__delete__(ExecutionContext *ctx, String *name) if (members) { if (PropertyTableEntry *entry = members->findEntry(name)) { - if (entry->descriptor.isConfigurable()) { + if (members->values[entry->valueIndex].isConfigurable()) { members->remove(entry); return true; } @@ -536,7 +538,8 @@ bool Object::__defineOwnProperty__(ExecutionContext *ctx, String *name, const Pr PropertyDescriptor *current; if (isArrayObject() && name->isEqualTo(ctx->engine->id_length)) { - PropertyDescriptor *lp = array.getLengthProperty(); + PropertyDescriptor *lp = members->values.data(); // length is always the first property + assert(lp == members->find(ctx->engine->id_length)); if (desc->isEmpty() || desc->isSubset(lp)) return true; if (!lp->isWritable() || desc->type == PropertyDescriptor::Accessor || desc->isConfigurable() || desc->isEnumerable()) @@ -584,7 +587,7 @@ bool Object::__defineOwnProperty__(ExecutionContext *ctx, uint index, const Prop PropertyDescriptor *current; // 15.4.5.1, 4b - if (isArrayObject() && index >= array.length() && !array.getLengthProperty()->isWritable()) + if (isArrayObject() && index >= array.length() && !members->values.at(0).isWritable()) goto reject; if (isNonStrictArgumentsObject) @@ -693,7 +696,8 @@ void ArrayObject::init(ExecutionContext *context) pd->enumberable = PropertyDescriptor::Disabled; pd->configurable = PropertyDescriptor::Disabled; pd->value = Value::fromInt32(0); - array.setLengthProperty(pd); + array.setArrayObject(this); + assert(pd = members->values.data()); } diff --git a/src/v4/qv4objectiterator.cpp b/src/v4/qv4objectiterator.cpp index 8da2e7b..8ce6237 100644 --- a/src/v4/qv4objectiterator.cpp +++ b/src/v4/qv4objectiterator.cpp @@ -128,10 +128,13 @@ PropertyDescriptor *ObjectIterator::next(String **name, uint *index) PropertyTableEntry *pt = current->members->_properties[tableIndex]; ++tableIndex; // ### check that it's not a repeated attribute - if (pt && (!(flags & EnumberableOnly) || pt->descriptor.isEnumerable())) { - *name = pt->name; - p = &pt->descriptor; - return p; + if (pt) { + PropertyDescriptor *pd = current->members->values.data() + pt->valueIndex; + if (!(flags & EnumberableOnly) || pd->isEnumerable()) { + *name = pt->name; + p = pd; + return p; + } } } return 0; diff --git a/src/v4/qv4propertytable.h b/src/v4/qv4propertytable.h index b00acfa..30aa5d2 100644 --- a/src/v4/qv4propertytable.h +++ b/src/v4/qv4propertytable.h @@ -52,13 +52,14 @@ namespace VM { struct ObjectIterator; struct PropertyTableEntry { - PropertyDescriptor descriptor; String *name; + uint valueIndex; PropertyTableEntry *next; int index; inline PropertyTableEntry(String *name) : name(name), + valueIndex(UINT_MAX), next(0), index(-1) { } @@ -69,6 +70,8 @@ struct PropertyTableEntry { class PropertyTable { Q_DISABLE_COPY(PropertyTable) + friend class Array; + friend class ArrayObject; public: PropertyTable() @@ -109,6 +112,9 @@ public: _properties[prop->index] = 0; prop->next = _freeList; _freeList = prop; + // ### empty space in value array + values[prop->valueIndex].type = PropertyDescriptor::Generic; + values[prop->valueIndex].writable = PropertyDescriptor::Undefined; } PropertyTableEntry *findEntry(String *name) const @@ -123,12 +129,12 @@ public: return 0; } - PropertyDescriptor *find(String *name) const + PropertyDescriptor *find(String *name) { if (_properties) { for (PropertyTableEntry *prop = _buckets[name->hashValue() % _bucketCount]; prop; prop = prop->next) { if (prop && prop->name->isEqualTo(name)) - return &prop->descriptor; + return values.data() + prop->valueIndex; } } @@ -138,7 +144,7 @@ public: PropertyDescriptor *insert(String *name) { if (PropertyTableEntry *prop = findEntry(name)) - return &prop->descriptor; + return values.data() + prop->valueIndex; if (_propertyCount == _allocated) { if (! _allocated) @@ -173,7 +179,9 @@ public: bucket = prop; } - return &prop->descriptor; + prop->valueIndex = values.size(); + values.resize(values.size() + 1); + return values.data() + prop->valueIndex; } private: @@ -210,6 +218,8 @@ private: private: friend struct ObjectIterator; + friend struct Object; + PropertyTableEntry **_properties; PropertyTableEntry **_buckets; PropertyTableEntry *_freeList; @@ -217,6 +227,7 @@ private: int _bucketCount; int _primeIdx: 5; int _allocated: 27; + QVector values; }; } // namespace VM diff --git a/src/v4/qv4regexpobject.cpp b/src/v4/qv4regexpobject.cpp index 31fb584..5a0faf1 100644 --- a/src/v4/qv4regexpobject.cpp +++ b/src/v4/qv4regexpobject.cpp @@ -72,7 +72,7 @@ RegExpObject::RegExpObject(ExecutionEngine *engine, PassRefPtr value, bo if (!members) members.reset(new PropertyTable()); - lastIndexProperty = members->insert(engine->newIdentifier(QStringLiteral("lastIndex"))); + PropertyDescriptor *lastIndexProperty = members->insert(engine->newIdentifier(QStringLiteral("lastIndex"))); lastIndexProperty->type = PropertyDescriptor::Data; lastIndexProperty->writable = PropertyDescriptor::Enabled; lastIndexProperty->enumberable = PropertyDescriptor::Disabled; @@ -86,6 +86,12 @@ RegExpObject::RegExpObject(ExecutionEngine *engine, PassRefPtr value, bo defineReadonlyProperty(engine->newIdentifier(QStringLiteral("multiline")), Value::fromBoolean(this->value->multiLine())); } +PropertyDescriptor *RegExpObject::lastIndexProperty(ExecutionContext *ctx) +{ + return members->find(ctx->engine->newIdentifier(QStringLiteral("lastIndex"))); +} + + RegExpCtor::RegExpCtor(ExecutionContext *scope) : FunctionObject(scope) @@ -167,16 +173,16 @@ Value RegExpPrototype::method_exec(ExecutionContext *ctx) arg = __qmljs_to_string(arg, ctx); QString s = arg.stringValue()->toQString(); - int offset = r->global ? r->lastIndexProperty->value.toInt32(ctx) : 0; + int offset = r->global ? r->lastIndexProperty(ctx)->value.toInt32(ctx) : 0; if (offset < 0 || offset > s.length()) { - r->lastIndexProperty->value = Value::fromInt32(0); + r->lastIndexProperty(ctx)->value = Value::fromInt32(0); return Value::nullValue(); } uint* matchOffsets = (uint*)alloca(r->value->captureCount() * 2 * sizeof(uint)); int result = r->value->match(s, offset, matchOffsets); if (result == -1) { - r->lastIndexProperty->value = Value::fromInt32(0); + r->lastIndexProperty(ctx)->value = Value::fromInt32(0); return Value::nullValue(); } @@ -195,7 +201,7 @@ Value RegExpPrototype::method_exec(ExecutionContext *ctx) array->__put__(ctx, QLatin1String("input"), arg); if (r->global) - r->lastIndexProperty->value = Value::fromInt32(matchOffsets[1]); + r->lastIndexProperty(ctx)->value = Value::fromInt32(matchOffsets[1]); return Value::fromObject(array); } diff --git a/src/v4/qv4regexpobject.h b/src/v4/qv4regexpobject.h index a37905f..cd79533 100644 --- a/src/v4/qv4regexpobject.h +++ b/src/v4/qv4regexpobject.h @@ -68,7 +68,7 @@ namespace VM { struct RegExpObject: Object { RefPtr value; - PropertyDescriptor *lastIndexProperty; + PropertyDescriptor *lastIndexProperty(ExecutionContext *ctx); bool global; RegExpObject(ExecutionEngine *engine, PassRefPtr value, bool global); }; diff --git a/src/v4/qv4stringobject.cpp b/src/v4/qv4stringobject.cpp index 4e0285c..788d6cd 100644 --- a/src/v4/qv4stringobject.cpp +++ b/src/v4/qv4stringobject.cpp @@ -420,7 +420,7 @@ Value StringPrototype::method_replace(ExecutionContext *ctx) offset = qMax(offset + 1, matchOffsets[oldSize + 1]); } if (regExp->global) - regExp->lastIndexProperty->value = Value::fromUInt32(0); + regExp->lastIndexProperty(ctx)->value = Value::fromUInt32(0); numStringMatches = matchOffsets.size() / (regExp->value->captureCount() * 2); numCaptures = regExp->value->captureCount(); } else { -- 2.7.4