Simplify/speed up retrieving of properties
authorLars Knoll <lars.knoll@digia.com>
Fri, 14 Dec 2012 08:57:02 +0000 (09:57 +0100)
committerSimon Hausmann <simon.hausmann@digia.com>
Fri, 14 Dec 2012 09:07:25 +0000 (10:07 +0100)
The hasProperty()/get() sequence used so far is as in the
spec, but requires us to lookup the name twice. Instead add
a bool hasProperty() to Object::__get__() and use that.

Speeds up fact.2.js by ~20%

Change-Id: Ic8c84718f1a702c3da9487010c0d6dd0fee44609
Reviewed-by: Simon Hausmann <simon.hausmann@digia.com>
qmljs_environment.cpp
qmljs_objects.cpp
qmljs_objects.h
qv4ecmaobjects.cpp
qv4ecmaobjects_p.h

index ef55252..a7cf2ce 100644 (file)
@@ -148,8 +148,12 @@ Value ExecutionContext::getBindingValue(ExecutionContext *scope, String *name, b
         if (__qmljs_string_equal(formals()[i], name))
             return arguments[i];
     }
-    if (activation && activation->__hasProperty__(this, name))
-        return activation->__get__(scope, name);
+    if (activation) {
+        bool hasProperty = false;
+        Value v = activation->__get__(scope, name, &hasProperty);
+        if (hasProperty)
+            return v;
+    }
     assert(false);
 }
 
@@ -272,8 +276,10 @@ Value ExecutionContext::getProperty(String *name)
         if (ctx->withObject) {
             With *w = ctx->withObject;
             while (w) {
-                if (w->object->__hasProperty__(ctx, name))
-                    return w->object->__get__(ctx, name);
+                bool hasProperty = false;
+                Value v = w->object->__get__(ctx, name, &hasProperty);
+                if (hasProperty)
+                    return v;
                 w = w->next;
             }
         }
@@ -284,8 +290,12 @@ Value ExecutionContext::getProperty(String *name)
         for (unsigned int i = 0; i < ctx->formalCount(); ++i)
             if (__qmljs_string_equal(ctx->formals()[i], name))
                 return ctx->arguments[i];
-        if (ctx->activation && ctx->activation->__hasProperty__(ctx, name))
-            return ctx->activation->__get__(ctx, name);
+        if (ctx->activation) {
+            bool hasProperty = false;
+            Value v = ctx->activation->__get__(ctx, name, &hasProperty);
+            if (hasProperty)
+                return v;
+        }
         if (name->isEqualTo(ctx->engine->id_arguments)) {
             Value arguments = Value::fromObject(new (engine->memoryManager) ArgumentsObject(this));
             createMutableBinding(ctx->engine->id_arguments, false);
@@ -306,8 +316,10 @@ Value ExecutionContext::getPropertyNoThrow(String *name)
         if (ctx->withObject) {
             With *w = ctx->withObject;
             while (w) {
-                if (w->object->__hasProperty__(ctx, name))
-                    return w->object->__get__(ctx, name);
+                bool hasProperty = false;
+                Value v = w->object->__get__(ctx, name, &hasProperty);
+                if (hasProperty)
+                    return v;
                 w = w->next;
             }
         }
@@ -318,8 +330,12 @@ Value ExecutionContext::getPropertyNoThrow(String *name)
         for (unsigned int i = 0; i < ctx->formalCount(); ++i)
             if (__qmljs_string_equal(ctx->formals()[i], name))
                 return ctx->arguments[i];
-        if (ctx->activation && ctx->activation->__hasProperty__(ctx, name))
-            return ctx->activation->__get__(ctx, name);
+        if (ctx->activation) {
+            bool hasProperty = false;
+            Value v = ctx->activation->__get__(ctx, name, &hasProperty);
+            if (hasProperty)
+                return v;
+        }
         if (name->isEqualTo(ctx->engine->id_arguments)) {
             Value arguments = Value::fromObject(new (engine->memoryManager) ArgumentsObject(this));
             createMutableBinding(ctx->engine->id_arguments, false);
index 616fe82..eb0f150 100644 (file)
@@ -184,8 +184,9 @@ PropertyDescriptor *Object::__getOwnProperty__(ExecutionContext *, String *name)
 // Section 8.12.2
 PropertyDescriptor *Object::__getPropertyDescriptor__(ExecutionContext *ctx, String *name, PropertyDescriptor *to_fill)
 {
-    if (PropertyDescriptor *p = __getOwnProperty__(ctx, name))
-        return p;
+    if (members)
+        if (PropertyDescriptor *p = members->find(name))
+            return p;
 
     if (prototype)
         return prototype->__getPropertyDescriptor__(ctx, name, to_fill);
@@ -193,15 +194,23 @@ PropertyDescriptor *Object::__getPropertyDescriptor__(ExecutionContext *ctx, Str
 }
 
 // Section 8.12.3
-Value Object::__get__(ExecutionContext *ctx, String *name)
+Value Object::__get__(ExecutionContext *ctx, String *name, bool *hasProperty)
 {
-    if (name->isEqualTo(ctx->engine->id___proto__))
+    if (name->isEqualTo(ctx->engine->id___proto__)) {
+        if (hasProperty)
+            *hasProperty = true;
         return Value::fromObject(prototype);
+    }
 
     PropertyDescriptor tmp;
-    if (PropertyDescriptor *p = __getPropertyDescriptor__(ctx, name, &tmp))
+    if (PropertyDescriptor *p = __getPropertyDescriptor__(ctx, name, &tmp)) {
+        if (hasProperty)
+            *hasProperty = true;
         return getValue(ctx, p);
+    }
 
+    if (hasProperty)
+        *hasProperty = false;
     return Value::undefinedValue();
 }
 
@@ -430,11 +439,14 @@ void ForEachIteratorObject::getCollectables(QVector<Object *> &objects)
         objects.append(current);
 }
 
-Value ArrayObject::__get__(ExecutionContext *ctx, String *name)
+Value ArrayObject::__get__(ExecutionContext *ctx, String *name, bool *hasProperty)
 {
-    if (name->isEqualTo(ctx->engine->id_length))
+    if (name->isEqualTo(ctx->engine->id_length)) {
+        if (hasProperty)
+            *hasProperty = true;
         return Value::fromDouble(value.size());
-    return Object::__get__(ctx, name);
+    }
+    return Object::__get__(ctx, name, hasProperty);
 }
 
 bool ArrayObject::inplaceBinOp(Value rhs, Value index, BinOp op, ExecutionContext *ctx)
@@ -718,28 +730,38 @@ Value IsFiniteFunction::call(ExecutionContext *context, Value /*thisObject*/, Va
 }
 
 
-Value RegExpObject::__get__(ExecutionContext *ctx, String *name)
+Value RegExpObject::__get__(ExecutionContext *ctx, String *name, bool *hasProperty)
 {
     QString n = name->toQString();
+    Value v = Value::undefinedValue();
     if (n == QLatin1String("source"))
-        return Value::fromString(ctx, value.pattern());
+        v = Value::fromString(ctx, value.pattern());
     else if (n == QLatin1String("global"))
-        return Value::fromBoolean(global);
+        v = Value::fromBoolean(global);
     else if (n == QLatin1String("ignoreCase"))
-        return Value::fromBoolean(value.patternOptions() & QRegularExpression::CaseInsensitiveOption);
+        v = Value::fromBoolean(value.patternOptions() & QRegularExpression::CaseInsensitiveOption);
     else if (n == QLatin1String("multiline"))
-        return Value::fromBoolean(value.patternOptions() & QRegularExpression::MultilineOption);
+        v = Value::fromBoolean(value.patternOptions() & QRegularExpression::MultilineOption);
     else if (n == QLatin1String("lastIndex"))
-        return lastIndex;
-    return Object::__get__(ctx, name);
+        v = lastIndex;
+    if (v.type() != Value::Undefined_Type) {
+        if (hasProperty)
+            *hasProperty = true;
+        return v;
+    }
+
+    return Object::__get__(ctx, name, hasProperty);
 }
 
-Value ErrorObject::__get__(ExecutionContext *ctx, String *name)
+Value ErrorObject::__get__(ExecutionContext *ctx, String *name, bool *hasProperty)
 {
     QString n = name->toQString();
-    if (n == QLatin1String("message"))
+    if (n == QLatin1String("message")) {
+        if (hasProperty)
+            *hasProperty = true;
         return value;
-    return Object::__get__(ctx, name);
+    }
+    return Object::__get__(ctx, name, hasProperty);
 }
 
 void ErrorObject::setNameProperty(ExecutionContext *ctx)
@@ -775,11 +797,14 @@ Value ScriptFunction::construct(VM::ExecutionContext *ctx)
     return ctx->thisObject;
 }
 
-Value ArgumentsObject::__get__(ExecutionContext *ctx, String *name)
+Value ArgumentsObject::__get__(ExecutionContext *ctx, String *name, bool *hasProperty)
 {
-    if (name->isEqualTo(ctx->engine->id_length))
+    if (name->isEqualTo(ctx->engine->id_length)) {
+        if (hasProperty)
+            *hasProperty = true;
         return Value::fromInt32(context->argumentCount);
-    return Object::__get__(ctx, name);
+    }
+    return Object::__get__(ctx, name, hasProperty);
 }
 
 PropertyDescriptor *ArgumentsObject::__getPropertyDescriptor__(ExecutionContext *ctx, String *name, PropertyDescriptor *to_fill)
index 419ada7..9e3edeb 100644 (file)
@@ -440,7 +440,7 @@ struct Object: Managed {
     virtual ErrorObject *asErrorObject() { return 0; }
     virtual ArgumentsObject *asArgumentsObject() { return 0; }
 
-    virtual Value __get__(ExecutionContext *ctx, String *name);
+    virtual Value __get__(ExecutionContext *ctx, String *name, bool *hasProperty = 0);
     virtual PropertyDescriptor *__getOwnProperty__(ExecutionContext *ctx, String *name);
     virtual PropertyDescriptor *__getPropertyDescriptor__(ExecutionContext *ctx, String *name, PropertyDescriptor *to_fill);
     virtual void __put__(ExecutionContext *ctx, String *name, Value value);
@@ -519,7 +519,7 @@ struct ArrayObject: Object {
     ArrayObject(const Array &value): value(value) {}
     virtual QString className() { return QStringLiteral("Array"); }
     virtual ArrayObject *asArrayObject() { return this; }
-    virtual Value __get__(ExecutionContext *ctx, String *name);
+    virtual Value __get__(ExecutionContext *ctx, String *name, bool *hasProperty);
 
     virtual bool inplaceBinOp(Value rhs, Value index, BinOp op, ExecutionContext *ctx);
 
@@ -642,7 +642,7 @@ struct RegExpObject: Object {
     RegExpObject(const QRegularExpression &value, bool global): value(value), lastIndex(Value::fromInt32(0)), global(global) {}
     virtual QString className() { return QStringLiteral("RegExp"); }
     virtual RegExpObject *asRegExpObject() { return this; }
-    virtual Value __get__(ExecutionContext *ctx, String *name);
+    virtual Value __get__(ExecutionContext *ctx, String *name, bool *hasProperty);
 };
 
 struct ErrorObject: Object {
@@ -650,7 +650,7 @@ struct ErrorObject: Object {
     ErrorObject(const Value &message): value(message) {}
     virtual QString className() { return QStringLiteral("Error"); }
     virtual ErrorObject *asErrorObject() { return this; }
-    virtual Value __get__(ExecutionContext *ctx, String *name);
+    virtual Value __get__(ExecutionContext *ctx, String *name, bool *hasProperty);
 
     virtual struct SyntaxErrorObject *asSyntaxError() { return 0; }
 
@@ -710,7 +710,7 @@ struct ArgumentsObject: Object {
     ArgumentsObject(ExecutionContext *context): context(context) {}
     virtual QString className() { return QStringLiteral("Arguments"); }
     virtual ArgumentsObject *asArgumentsObject() { return this; }
-    virtual Value __get__(ExecutionContext *ctx, String *name);
+    virtual Value __get__(ExecutionContext *ctx, String *name, bool *hasProperty);
     virtual PropertyDescriptor *__getPropertyDescriptor__(ExecutionContext *ctx, String *name, PropertyDescriptor *to_fill);
 };
 
index bd8969d..c9e0ea6 100644 (file)
@@ -542,11 +542,14 @@ Value ObjectCtor::call(ExecutionContext *ctx)
     return __qmljs_to_object(ctx->argument(0), ctx);
 }
 
-Value ObjectCtor::__get__(ExecutionContext *ctx, String *name)
+Value ObjectCtor::__get__(ExecutionContext *ctx, String *name, bool *hasProperty)
 {
-    if (name == ctx->engine->id_length)
+    if (name == ctx->engine->id_length) {
+        if (hasProperty)
+            *hasProperty = true;
         return Value::fromDouble(1);
-    return Object::__get__(ctx, name);
+    }
+    return Object::__get__(ctx, name, hasProperty);
 }
 
 void ObjectPrototype::init(ExecutionContext *ctx, const Value &ctor)
index e6ab1d7..be4b938 100644 (file)
@@ -53,7 +53,7 @@ struct ObjectCtor: FunctionObject
 
     virtual Value construct(ExecutionContext *ctx);
     virtual Value call(ExecutionContext *ctx);
-    virtual Value __get__(ExecutionContext *ctx, String *name);
+    virtual Value __get__(ExecutionContext *ctx, String *name, bool *hasProperty);
 };
 
 struct ObjectPrototype: Object