optimise property access
authorLars Knoll <lars.knoll@digia.com>
Wed, 16 Jan 2013 23:45:11 +0000 (00:45 +0100)
committerSimon Hausmann <simon.hausmann@digia.com>
Thu, 17 Jan 2013 14:45:24 +0000 (15:45 +0100)
Inline the canPut method and simplify our code path for
[[put]].

Change-Id: I4198b0bdef16a4fdf6113a8e015915492c9c301d
Reviewed-by: Simon Hausmann <simon.hausmann@digia.com>
qmljs_objects.cpp
qmljs_objects.h
qmljs_runtime.cpp
qv4array.h
tests/TestExpectations

index fee5378..3a700e2 100644 (file)
@@ -280,7 +280,7 @@ Value Object::__get__(ExecutionContext *ctx, String *name, bool *hasProperty)
 
 Value Object::__get__(ExecutionContext *ctx, uint index, bool *hasProperty)
 {
-    if (PropertyDescriptor *p = __getPropertyDescriptor__(ctx, index)) {
+    if (const PropertyDescriptor *p = __getPropertyDescriptor__(ctx, index)) {
         if (hasProperty)
             *hasProperty = true;
         return getValue(ctx, p);
@@ -292,55 +292,6 @@ Value Object::__get__(ExecutionContext *ctx, uint index, bool *hasProperty)
 }
 
 
-// Section 8.12.4
-bool Object::__canPut__(ExecutionContext *ctx, String *name)
-{
-    uint idx = name->asArrayIndex();
-    if (idx != String::InvalidArrayIndex)
-        return __canPut__(ctx, idx);
-
-    if (PropertyDescriptor *p = __getOwnProperty__(ctx, name)) {
-        if (p->isAccessor())
-            return p->set != 0;
-        return p->isWritable();
-    }
-
-    if (! prototype)
-        return extensible;
-
-    if (PropertyDescriptor *p = prototype->__getPropertyDescriptor__(ctx, name)) {
-        if (p->isAccessor())
-            return p->set != 0;
-        if (!extensible)
-            return false;
-        return p->isWritable();
-    }
-
-    return extensible;
-}
-
-bool Object::__canPut__(ExecutionContext *ctx, uint index)
-{
-    if (PropertyDescriptor *p = __getOwnProperty__(ctx, index)) {
-        if (p->isAccessor())
-            return p->set != 0;
-        return p->isWritable();
-    }
-
-    if (! prototype)
-        return extensible;
-
-    if (PropertyDescriptor *p = prototype->__getPropertyDescriptor__(ctx, index)) {
-        if (p->isAccessor())
-            return p->set != 0;
-        if (!extensible)
-            return false;
-        return p->isWritable();
-    }
-
-    return extensible;
-}
-
 // Section 8.12.5
 void Object::__put__(ExecutionContext *ctx, String *name, Value value)
 {
@@ -348,42 +299,71 @@ void Object::__put__(ExecutionContext *ctx, String *name, Value value)
     if (idx != String::InvalidArrayIndex)
         return __put__(ctx, idx, value);
 
+    PropertyDescriptor *pd  = __getOwnProperty__(ctx, name);
     // clause 1
-    if (!__canPut__(ctx, name))
-        goto reject;
+    if (pd) {
+        if (pd->isAccessor()) {
+                if (pd->set)
+                    goto cont;
+                goto reject;
+        } else if (!pd->isWritable())
+            goto reject;
+        else if (isArray && name->isEqualTo(ctx->engine->id_length)) {
+            bool ok;
+            uint l = value.asArrayLength(ctx, &ok);
+            if (!ok)
+                ctx->throwRangeError(value);
+            ok = array.setLength(l);
+            if (!ok)
+                goto reject;
+        } else {
+            pd->value = value;
+        }
+        return;
+    } else if (!prototype) {
+        if (!extensible)
+            goto reject;
+    } else {
+        if (PropertyDescriptor *p = prototype->__getPropertyDescriptor__(ctx, name)) {
+            if (p->isAccessor()) {
+                if (p->set)
+                    goto cont;
+                goto reject;
+            }
+            if (!extensible)
+                goto reject;
+            if (!p->isWritable())
+                goto reject;
+        } else {
+            if (!extensible)
+                goto reject;
+        }
+    }
+
+    cont:
 
     if (!members)
         members.reset(new PropertyTable());
 
-    {
-        // Clause 2
-        PropertyDescriptor *pd = __getOwnProperty__(ctx, name);
-        // Clause 3
-        if (pd && pd->isData()) {
-            // spec says to call [[DefineOwnProperty]] with { [[Value]]: value }
-
-            // ### to simplify and speed up we should expand the relevant parts here (clauses 6,7,9,10,12,13)
-            PropertyDescriptor desc = PropertyDescriptor::fromValue(value);
-            __defineOwnProperty__(ctx, name, &desc);
-            return;
-        }
 
-        // clause 4
-        if (!pd && prototype)
-            pd = prototype->__getPropertyDescriptor__(ctx, name);
+    // clause 4
+    if (!pd && prototype)
+        pd = prototype->__getPropertyDescriptor__(ctx, name);
 
-        // Clause 5
-        if (pd && pd->isAccessor()) {
-            assert(pd->set != 0);
+    // Clause 5
+    if (pd && pd->isAccessor()) {
+        assert(pd->set != 0);
 
-            Value args[1];
-            args[0] = value;
-            pd->set->call(ctx, Value::fromObject(this), args, 1);
-            return;
-        }
+        Value args[1];
+        args[0] = value;
+        pd->set->call(ctx, Value::fromObject(this), args, 1);
+        return;
+    }
 
+    {
         PropertyDescriptor *p = members->insert(name);
-        *p = PropertyDescriptor::fromValue(value);
+        p->type = PropertyDescriptor::Data;
+        p->value = value;
         p->configurable = PropertyDescriptor::Enabled;
         p->enumberable = PropertyDescriptor::Enabled;
         p->writable = PropertyDescriptor::Enabled;
@@ -397,41 +377,57 @@ void Object::__put__(ExecutionContext *ctx, String *name, Value value)
 
 void Object::__put__(ExecutionContext *ctx, uint index, Value value)
 {
+    PropertyDescriptor *pd  = __getOwnProperty__(ctx, index);
     // clause 1
-    if (!__canPut__(ctx, index))
-        goto reject;
-
-    {
-        // Clause 2
-        PropertyDescriptor *pd = __getOwnProperty__(ctx, index);
-        // Clause 3
-        if (pd && pd->isData()) {
-            // spec says to call [[DefineOwnProperty]] with { [[Value]]: value }
-
-            // ### to simplify and speed up we should expand the relevant parts here (clauses 6,7,9,10,12,13)
-            PropertyDescriptor desc = PropertyDescriptor::fromValue(value);
-            __defineOwnProperty__(ctx, index, &desc);
-            return;
+    if (pd) {
+        if (pd->isAccessor()) {
+                if (pd->set)
+                    goto cont;
+                goto reject;
+        } else if (!pd->isWritable())
+            goto reject;
+        else
+            pd->value = value;
+        return;
+    } else if (!prototype) {
+        if (!extensible)
+            goto reject;
+    } else {
+        if (PropertyDescriptor *p = prototype->__getPropertyDescriptor__(ctx, index)) {
+            if (p->isAccessor()) {
+                if (p->set)
+                    goto cont;
+                goto reject;
+            }
+            if (!extensible)
+                goto reject;
+            if (!p->isWritable())
+                goto reject;
+        } else {
+            if (!extensible)
+                goto reject;
         }
+    }
 
-        // clause 4
-        if (!pd && prototype)
-            pd = prototype->__getPropertyDescriptor__(ctx, index);
+    cont:
 
-        // Clause 5
-        if (pd && pd->isAccessor()) {
-            assert(pd->set != 0);
+    // clause 4
+    if (!pd && prototype)
+        pd = prototype->__getPropertyDescriptor__(ctx, index);
 
-            Value args[1];
-            args[0] = value;
-            pd->set->call(ctx, Value::fromObject(this), args, 1);
-            return;
-        }
+    // Clause 5
+    if (pd && pd->isAccessor()) {
+        assert(pd->set != 0);
 
-        array.set(index, value);
+        Value args[1];
+        args[0] = value;
+        pd->set->call(ctx, Value::fromObject(this), args, 1);
         return;
     }
 
+    array.set(index, value);
+    return;
+
   reject:
     if (ctx->strictMode)
         __qmljs_throw_type_error(ctx);
index d004868..362fe70 100644 (file)
@@ -124,7 +124,7 @@ struct Object: Managed {
     PropertyDescriptor *__getOwnProperty__(ExecutionContext *ctx, String *name);
     PropertyDescriptor *__getOwnProperty__(ExecutionContext *ctx, uint index);
     PropertyDescriptor *__getPropertyDescriptor__(ExecutionContext *ctx, String *name);
-    virtual PropertyDescriptor *__getPropertyDescriptor__(ExecutionContext *ctx, uint index);
+    PropertyDescriptor *__getPropertyDescriptor__(ExecutionContext *ctx, uint index);
 
     virtual Value __get__(ExecutionContext *ctx, String *name, bool *hasProperty = 0);
     virtual Value __get__(ExecutionContext *ctx, uint index, bool *hasProperty = 0);
@@ -132,8 +132,6 @@ struct Object: Managed {
     virtual void __put__(ExecutionContext *ctx, String *name, Value value);
     virtual void __put__(ExecutionContext *ctx, uint index, Value value);
 
-    virtual bool __canPut__(ExecutionContext *ctx, String *name);
-    virtual bool __canPut__(ExecutionContext *ctx, uint index);
     virtual bool __hasProperty__(const ExecutionContext *ctx, String *name) const;
     virtual bool __hasProperty__(const ExecutionContext *ctx, uint index) const;
     virtual bool __delete__(ExecutionContext *ctx, String *name);
index 0bc37da..d7829e3 100644 (file)
@@ -576,14 +576,16 @@ void __qmljs_set_property(ExecutionContext *ctx, Value object, String *name, Val
 Value __qmljs_get_element(ExecutionContext *ctx, Value object, Value index)
 {
     uint idx = index.asArrayIndex();
+
     if (object.isString() && idx < UINT_MAX) {
-        if (idx > INT_MAX || (int) idx >= object.stringValue()->toQString().length())
+        String *str = object.stringValue();
+        if (idx >= (uint)str->toQString().length())
             return Value::undefinedValue();
-        const QString s = object.stringValue()->toQString().mid(idx, 1);
+        const QString s = str->toQString().mid(idx, 1);
         return Value::fromString(ctx, s);
     }
 
-    if (! object.isObject())
+    if (!object.isObject())
         object = __qmljs_to_object(object, ctx);
 
     Object *o = object.objectValue();
index a7fc6b7..58529ef 100644 (file)
@@ -512,16 +512,25 @@ public:
         }
     }
 
+    const PropertyDescriptor *nonSparseAt(uint index) const {
+        if (sparse)
+            return 0;
+        index += offset;
+        if (index >= (uint)values.size())
+            return 0;
+        return values.constData() + index;
+    }
+
     const PropertyDescriptor *at(uint index) const {
         if (!sparse) {
             if (index >= values.size() - offset)
                 return 0;
-            return values.data() + index + offset;
+            return values.constData() + index + offset;
         } else {
             SparseArrayNode *n = sparse->findNode(index);
             if (!n)
                 return 0;
-            return values.data() + n->value;
+            return values.constData() + n->value;
         }
     }
 
index a3d65d6..7764282 100644 (file)
@@ -1069,7 +1069,6 @@ S15.4.4.13_A4_T2 failing
 15.4.4.16-7-5 failing
 15.4.4.16-7-8 failing
 15.4.4.16-7-9 failing
-15.4.4.16-7-b-1 failing
 15.4.4.16-7-b-10 failing
 15.4.4.16-7-b-12 failing
 15.4.4.16-7-b-15 failing
@@ -1194,7 +1193,6 @@ S15.4.4.13_A4_T2 failing
 15.4.4.17-7-5 failing
 15.4.4.17-7-8 failing
 15.4.4.17-7-9 failing
-15.4.4.17-7-b-1 failing
 15.4.4.17-7-b-10 failing
 15.4.4.17-7-b-12 failing
 15.4.4.17-7-b-15 failing
@@ -1319,7 +1317,6 @@ S15.4.4.13_A4_T2 failing
 15.4.4.18-7-4 failing
 15.4.4.18-7-8 failing
 15.4.4.18-7-9 failing
-15.4.4.18-7-b-1 failing
 15.4.4.18-7-b-10 failing
 15.4.4.18-7-b-12 failing
 15.4.4.18-7-b-15 failing
@@ -1439,7 +1436,6 @@ S15.4.4.13_A4_T2 failing
 15.4.4.19-8-1 failing
 15.4.4.19-8-5 failing
 15.4.4.19-8-8 failing
-15.4.4.19-8-b-1 failing
 15.4.4.19-8-b-10 failing
 15.4.4.19-8-b-12 failing
 15.4.4.19-8-b-15 failing
@@ -1571,7 +1567,6 @@ S15.4.4.13_A4_T2 failing
 15.4.4.20-9-5 failing
 15.4.4.20-9-8 failing
 15.4.4.20-9-9 failing
-15.4.4.20-9-b-1 failing
 15.4.4.20-9-b-10 failing
 15.4.4.20-9-b-12 failing
 15.4.4.20-9-b-15 failing
@@ -1936,7 +1931,6 @@ S15.4.4.13_A4_T2 failing
 15.4.4.22-8-c-5 failing
 15.4.4.22-8-c-6 failing
 15.4.4.22-9-8 failing
-15.4.4.22-9-9 failing
 15.4.4.22-9-b-10 failing
 15.4.4.22-9-b-12 failing
 15.4.4.22-9-b-17 failing
@@ -2596,10 +2590,9 @@ S15.4.4.13_A1_T2 failing
 15.4.4.18-7-c-i-6 failing
 15.4.4.19-8-c-i-6 failing
 15.4.4.20-9-c-i-6 failing
-15.4.4.21-8-b-iii-1-6 failing
 15.4.4.22-8-b-iii-1-6 failing
 
 # Bugs in Array.prototype
 15.4.4.14-9-b-i-5 failing
 15.4.4.16-7-c-i-6 failing
-15.4.4.17-7-c-i-6 failing
+15.4.4.17-7-c-i-6 failing
\ No newline at end of file