Refactor property access
authorLars Knoll <lars.knoll@digia.com>
Fri, 1 Feb 2013 14:59:22 +0000 (15:59 +0100)
committerSimon Hausmann <simon.hausmann@digia.com>
Mon, 4 Feb 2013 13:57:49 +0000 (14:57 +0100)
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 <simon.hausmann@digia.com>
src/v4/qv4array.cpp
src/v4/qv4array.h
src/v4/qv4arrayobject.cpp
src/v4/qv4object.cpp
src/v4/qv4objectiterator.cpp
src/v4/qv4propertytable.h
src/v4/qv4regexpobject.cpp
src/v4/qv4regexpobject.h
src/v4/qv4stringobject.cpp

index 9879b2f..5f0d838 100644 (file)
@@ -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();
index 9fb8bb6..b165ed2 100644 (file)
@@ -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;
index 032b56f..680a373 100644 (file)
@@ -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;
index 6f5fb60..6a5aa21 100644 (file)
@@ -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());
 }
 
 
index 8da2e7b..8ce6237 100644 (file)
@@ -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;
index b00acfa..30aa5d2 100644 (file)
@@ -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<PropertyDescriptor> values;
 };
 
 } // namespace VM
index 31fb584..5a0faf1 100644 (file)
@@ -72,7 +72,7 @@ RegExpObject::RegExpObject(ExecutionEngine *engine, PassRefPtr<RegExp> 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<RegExp> 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);
 }
index a37905f..cd79533 100644 (file)
@@ -68,7 +68,7 @@ namespace VM {
 
 struct RegExpObject: Object {
     RefPtr<RegExp> value;
-    PropertyDescriptor *lastIndexProperty;
+    PropertyDescriptor *lastIndexProperty(ExecutionContext *ctx);
     bool global;
     RegExpObject(ExecutionEngine *engine, PassRefPtr<RegExp> value, bool global);
 };
index 4e0285c..788d6cd 100644 (file)
@@ -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 {