Optimise function calls a little.
authorLars Knoll <lars.knoll@digia.com>
Thu, 18 Oct 2012 12:39:59 +0000 (14:39 +0200)
committerSimon Hausmann <simon.hausmann@digia.com>
Thu, 18 Oct 2012 12:45:58 +0000 (14:45 +0200)
Change-Id: I906a4f27bf47ae0ae088ae40a747b28ba827e10a
Reviewed-by: Simon Hausmann <simon.hausmann@digia.com>
qmljs_runtime.cpp
qmljs_runtime.h
qv4ecmaobjects.cpp

index 2522bd5..026cef0 100644 (file)
@@ -924,21 +924,25 @@ Value __qmljs_object_default_value(Context *ctx, Value object, int typeHint)
     if (typeHint == NUMBER_HINT)
         qSwap(meth1, meth2);
 
-    Object *oo = object.asObject();
-    assert(oo != 0);
+    assert(object.isObject());
+    Object *oo = object.objectValue();
 
     Value conv = oo->getProperty(ctx, meth1);
-    if (!conv.isUndefined() && conv.isFunctionObject()) {
-        Value r = __qmljs_call_value(ctx, object, conv, 0, 0);
-        if (r.isPrimitive())
-            return r;
+    if (!conv.isUndefined()) {
+        if (FunctionObject *f = conv.asFunctionObject()) {
+            Value r = __qmljs_call_function(ctx, object, f, 0, 0);
+            if (r.isPrimitive())
+                return r;
+        }
     }
 
     conv = oo->getProperty(ctx, meth2);
-    if (!conv.isUndefined() && conv.isFunctionObject()) {
-        Value r = __qmljs_call_value(ctx, object, conv, 0, 0);
-        if (r.isPrimitive())
-            return r;
+    if (!conv.isUndefined()) {
+        if (FunctionObject *f = conv.asFunctionObject()) {
+            Value r = __qmljs_call_function(ctx, object, f, 0, 0);
+            if (r.isPrimitive())
+                return r;
+        }
     }
 
     return Value::undefinedValue();
@@ -1006,42 +1010,42 @@ void __qmljs_set_property_closure(Context *ctx, Value *object, String *name, IR:
 
 Value __qmljs_get_element(Context *ctx, Value object, Value index)
 {
-    if (object.isString() && index.isNumber()) {
-        const QString s = object.stringValue()->toQString().mid(index.toUInt32(ctx), 1);
-        if (s.isNull())
-            return Value::undefinedValue();
-        else
-            return Value::fromString(ctx, s);
-    } else if (object.isArrayObject() && index.isNumber()) {
-        return object.asArrayObject()->value.at(index.toUInt32(ctx));
-    } else {
-        String *name = index.toString(ctx);
-
-        if (! object.isObject())
-            object = __qmljs_to_object(object, ctx);
+    if (index.isNumber()) {
+        if (object.isString()) {
+            const QString s = object.stringValue()->toQString().mid(index.toUInt32(ctx), 1);
+            if (s.isNull())
+                return Value::undefinedValue();
+            else
+                return Value::fromString(ctx, s);
+        }
 
-        return object.property(ctx, name);
+        if (ArrayObject *a = object.asArrayObject())
+            return a->value.at(index.toUInt32(ctx));
     }
+
+    String *name = index.toString(ctx);
+
+    if (! object.isObject())
+        object = __qmljs_to_object(object, ctx);
+
+    return object.property(ctx, name);
 }
 
 void __qmljs_set_element(Context *ctx, Value object, Value index, Value value)
 {
-    if (object.isArrayObject() && index.isNumber()) {
-        object.asArrayObject()->value.assign(index.toUInt32(ctx), value);
-    } else {
-        String *name = index.toString(ctx);
+    if (index.isNumber()) {
+        if (ArrayObject *a = object.asArrayObject()) {
+            a->value.assign(index.toUInt32(ctx), value);
+            return;
+        }
+    }
 
-        if (! object.isObject())
-            object = __qmljs_to_object(object, ctx);
+    String *name = index.toString(ctx);
 
-        object.objectValue()->setProperty(ctx, name, value, /*flags*/ 0);
-    }
-}
+    if (! object.isObject())
+        object = __qmljs_to_object(object, ctx);
 
-void __qmljs_set_element_number(Context *ctx, Value *object, Value *index, double number)
-{
-    Value v = Value::fromDouble(number);
-    __qmljs_set_element(ctx, *object, *index, v);
+    object.objectValue()->setProperty(ctx, name, value, /*flags*/ 0);
 }
 
 void __qmljs_set_activation_property(Context *ctx, String *name, Value value)
@@ -1079,14 +1083,14 @@ void __qmljs_set_activation_property_closure(Context *ctx, String *name, IR::Fun
 Value __qmljs_get_property(Context *ctx, Value object, String *name)
 {
     if (object.isObject()) {
-        return object.property(ctx, name);
+        return object.objectValue()->getProperty(ctx, name);
     } else if (object.isString() && name->isEqualTo(ctx->engine->id_length)) {
-        return Value::fromDouble(object.stringValue()->toQString().length());
+        return Value::fromInt32(object.stringValue()->toQString().length());
     } else {
         object = __qmljs_to_object(object, ctx);
 
         if (object.isObject()) {
-            return __qmljs_get_property(ctx, object, name);
+            return object.objectValue()->getProperty(ctx, name);
         } else {
             ctx->throwTypeError(); // ### not necessary.
             return Value::undefinedValue();
@@ -1205,25 +1209,29 @@ Value __qmljs_call_property(Context *context, Value base, String *name, Value *a
     return result;
 }
 
+Value __qmljs_call_function(Context *context, Value thisObject, FunctionObject *f, Value *args, int argc)
+{
+    Context k;
+    Context *ctx = f->needsActivation ? context->engine->newContext() : &k;
+    const Value *that = thisObject.isUndefined() ? 0 : &thisObject;
+    ctx->initCallContext(context->engine, that, f, args, argc);
+    f->call(ctx);
+    if (ctx->hasUncaughtException) {
+        context->hasUncaughtException = ctx->hasUncaughtException; // propagate the exception
+        context->result = ctx->result;
+    }
+    ctx->leaveCallContext(f);
+    return ctx->result;
+}
+
 Value __qmljs_call_value(Context *context, Value thisObject, Value func, Value *args, int argc)
 {
-    Value result;
     if (FunctionObject *f = func.asFunctionObject()) {
-        Context k;
-        Context *ctx = f->needsActivation ? context->engine->newContext() : &k;
-        const Value *that = thisObject.isUndefined() ? 0 : &thisObject;
-        ctx->initCallContext(context->engine, that, f, args, argc);
-        f->call(ctx);
-        if (ctx->hasUncaughtException) {
-            context->hasUncaughtException = ctx->hasUncaughtException; // propagate the exception
-            context->result = ctx->result;
-        }
-        ctx->leaveCallContext(f);
-        result = ctx->result;
+        return __qmljs_call_function(context, thisObject, f, args, argc);
     } else {
         context->throwTypeError();
+        return Value::undefinedValue();
     }
-    return result;
 }
 
 Value __qmljs_construct_activation_property(Context *context, String *name, Value *args, int argc)
index 2e7b7d5..994cdd5 100644 (file)
@@ -94,6 +94,7 @@ extern "C" {
 Value __qmljs_call_activation_property(Context *, String *name, Value *args, int argc);
 Value __qmljs_call_property(Context *context, Value base, String *name, Value *args, int argc);
 Value __qmljs_call_value(Context *context, Value thisObject, Value func, Value *args, int argc);
+Value __qmljs_call_function(Context *context, Value thisObject, FunctionObject *f, Value *args, int argc);
 
 Value __qmljs_construct_activation_property(Context *, String *name, Value *args, int argc);
 Value __qmljs_construct_property(Context *context, Value base, String *name, Value *args, int argc);
index 1ff21ac..37d61c1 100644 (file)
@@ -1536,7 +1536,7 @@ void ArrayPrototype::method_every(Context *ctx)
     Value self = ctx->thisObject;
     if (ArrayObject *instance = self.asArrayObject()) {
         Value callback = ctx->argument(0);
-        if (callback.isFunctionObject()) {
+        if (FunctionObject *f = callback.asFunctionObject()) {
             Value thisArg = ctx->argument(1);
             bool ok = true;
             for (uint k = 0; ok && k < instance->value.size(); ++k) {
@@ -1548,7 +1548,7 @@ void ArrayPrototype::method_every(Context *ctx)
                 args[0] = v;
                 args[1] = Value::fromDouble(k);
                 args[2] = ctx->thisObject;
-                Value r = __qmljs_call_value(ctx, thisArg, callback, args, 3);
+                Value r = __qmljs_call_function(ctx, thisArg, f, args, 3);
                 ok = __qmljs_to_boolean(r, ctx);
             }
             ctx->result = Value::fromBoolean(ok);
@@ -1565,7 +1565,7 @@ void ArrayPrototype::method_some(Context *ctx)
     Value self = ctx->thisObject;
     if (ArrayObject *instance = self.asArrayObject()) {
         Value callback = ctx->argument(0);
-        if (callback.isFunctionObject()) {
+        if (FunctionObject *f = callback.asFunctionObject()) {
             Value thisArg = ctx->argument(1);
             bool ok = false;
             for (uint k = 0; !ok && k < instance->value.size(); ++k) {
@@ -1577,7 +1577,7 @@ void ArrayPrototype::method_some(Context *ctx)
                 args[0] = v;
                 args[1] = Value::fromDouble(k);
                 args[2] = ctx->thisObject;
-                Value r = __qmljs_call_value(ctx, thisArg, callback, args, 3);
+                Value r = __qmljs_call_function(ctx, thisArg, f, args, 3);
                 ok = __qmljs_to_boolean(r, ctx);
             }
             ctx->result = Value::fromBoolean(ok);
@@ -1594,9 +1594,7 @@ void ArrayPrototype::method_forEach(Context *ctx)
     Value self = ctx->thisObject;
     if (ArrayObject *instance = self.asArrayObject()) {
         Value callback = ctx->argument(0);
-        if (! callback.isFunctionObject())
-            ctx->throwTypeError();
-        else {
+        if (FunctionObject *f = callback.asFunctionObject()) {
             Value thisArg = ctx->argument(1);
             for (quint32 k = 0; k < instance->value.size(); ++k) {
                 Value v = instance->value.at(k);
@@ -1606,8 +1604,10 @@ void ArrayPrototype::method_forEach(Context *ctx)
                 args[0] = v;
                 args[1] = Value::fromDouble(k);
                 args[2] = ctx->thisObject;
-                /*Value r =*/ __qmljs_call_value(ctx, thisArg, callback, args, 3);
+                /*Value r =*/ __qmljs_call_function(ctx, thisArg, f, args, 3);
             }
+        } else {
+            ctx->throwTypeError();
         }
     } else {
         ctx->throwUnimplemented(QStringLiteral("Array.prototype.forEach"));
@@ -1619,9 +1619,7 @@ void ArrayPrototype::method_map(Context *ctx)
     Value self = ctx->thisObject;
     if (ArrayObject *instance = self.asArrayObject()) {
         Value callback = ctx->argument(0);
-        if (! callback.isFunctionObject())
-            ctx->throwTypeError();
-        else {
+        if (FunctionObject *f = callback.asFunctionObject()) {
             Value thisArg = ctx->argument(1);
             ArrayObject *a = ctx->engine->newArrayObject()->asArrayObject();
             a->value.resize(instance->value.size());
@@ -1633,10 +1631,12 @@ void ArrayPrototype::method_map(Context *ctx)
                 args[0] = v;
                 args[1] = Value::fromDouble(k);
                 args[2] = ctx->thisObject;
-                Value r = __qmljs_call_value(ctx, thisArg, callback, args, 3);
+                Value r = __qmljs_call_function(ctx, thisArg, f, args, 3);
                 a->value.assign(k, r);
             }
             ctx->result = Value::fromObject(a);
+        } else {
+            ctx->throwTypeError();
         }
     } else {
         ctx->throwUnimplemented(QStringLiteral("Array.prototype.map"));
@@ -1648,9 +1648,7 @@ void ArrayPrototype::method_filter(Context *ctx)
     Value self = ctx->thisObject;
     if (ArrayObject *instance = self.asArrayObject()) {
         Value callback = ctx->argument(0);
-        if (! callback.isFunctionObject())
-            ctx->throwTypeError();
-        else {
+        if (FunctionObject *f = callback.asFunctionObject()) {
             Value thisArg = ctx->argument(1);
             ArrayObject *a = ctx->engine->newArrayObject()->asArrayObject();
             for (quint32 k = 0; k < instance->value.size(); ++k) {
@@ -1661,7 +1659,7 @@ void ArrayPrototype::method_filter(Context *ctx)
                 args[0] = v;
                 args[1] = Value::fromDouble(k);
                 args[2] = ctx->thisObject;
-                Value r = __qmljs_call_value(ctx, thisArg, callback, args, 3);
+                Value r = __qmljs_call_function(ctx, thisArg, f, args, 3);
                 if (__qmljs_to_boolean(r, ctx)) {
                     const uint index = a->value.size();
                     a->value.resize(index + 1);
@@ -1669,6 +1667,8 @@ void ArrayPrototype::method_filter(Context *ctx)
                 }
             }
             ctx->result = Value::fromObject(a);
+        } else {
+            ctx->throwTypeError();
         }
     } else {
         ctx->throwUnimplemented(QStringLiteral("Array.prototype.filter"));
@@ -1680,27 +1680,31 @@ void ArrayPrototype::method_reduce(Context *ctx)
     Value self = ctx->thisObject;
     if (ArrayObject *instance = self.asArrayObject()) {
         Value callback = ctx->argument(0);
-        Value initialValue = ctx->argument(1);
-        Value acc = initialValue;
-        for (quint32 k = 0; k < instance->value.size(); ++k) {
-            Value v = instance->value.at(k);
-            if (v.isUndefined())
-                continue;
-
-            if (acc.isUndefined()) {
-                acc = v;
-                continue;
-            }
+        if (FunctionObject *f = callback.asFunctionObject()) {
+            Value initialValue = ctx->argument(1);
+            Value acc = initialValue;
+            for (quint32 k = 0; k < instance->value.size(); ++k) {
+                Value v = instance->value.at(k);
+                if (v.isUndefined())
+                    continue;
+
+                if (acc.isUndefined()) {
+                    acc = v;
+                    continue;
+                }
 
-            Value args[4];
-            args[0] = acc;
-            args[1] = v;
-            args[2] = Value::fromDouble(k);
-            args[3] = ctx->thisObject;
-            Value r = __qmljs_call_value(ctx, Value::undefinedValue(), callback, args, 4);
-            acc = r;
+                Value args[4];
+                args[0] = acc;
+                args[1] = v;
+                args[2] = Value::fromDouble(k);
+                args[3] = ctx->thisObject;
+                Value r = __qmljs_call_function(ctx, Value::undefinedValue(), f, args, 4);
+                acc = r;
+            }
+            ctx->result = acc;
+        } else {
+            ctx->throwTypeError();
         }
-        ctx->result = acc;
     } else {
         ctx->throwUnimplemented(QStringLiteral("Array.prototype.reduce"));
     }
@@ -1711,27 +1715,31 @@ void ArrayPrototype::method_reduceRight(Context *ctx)
     Value self = ctx->thisObject;
     if (ArrayObject *instance = self.asArrayObject()) {
         Value callback = ctx->argument(0);
-        Value initialValue = ctx->argument(1);
-        Value acc = initialValue;
-        for (int k = instance->value.size() - 1; k != -1; --k) {
-            Value v = instance->value.at(k);
-            if (v.isUndefined())
-                continue;
-
-            if (acc.isUndefined()) {
-                acc = v;
-                continue;
-            }
+        if (FunctionObject *f = callback.asFunctionObject()) {
+            Value initialValue = ctx->argument(1);
+            Value acc = initialValue;
+            for (int k = instance->value.size() - 1; k != -1; --k) {
+                Value v = instance->value.at(k);
+                if (v.isUndefined())
+                    continue;
 
-            Value args[4];
-            args[0] = acc;
-            args[1] = v;
-            args[2] = Value::fromDouble(k);
-            args[3] = ctx->thisObject;
-            Value r = __qmljs_call_value(ctx, Value::undefinedValue(), callback, args, 4);
-            acc = r;
+                if (acc.isUndefined()) {
+                    acc = v;
+                    continue;
+                }
+
+                Value args[4];
+                args[0] = acc;
+                args[1] = v;
+                args[2] = Value::fromDouble(k);
+                args[3] = ctx->thisObject;
+                Value r = __qmljs_call_function(ctx, Value::undefinedValue(), f, args, 4);
+                acc = r;
+            }
+            ctx->result = acc;
+        } else {
+            ctx->throwTypeError();
         }
-        ctx->result = acc;
     } else {
         ctx->throwUnimplemented(QStringLiteral("Array.prototype.reduceRight"));
     }
@@ -1777,7 +1785,7 @@ void FunctionPrototype::method_toString(Context *ctx)
 
 void FunctionPrototype::method_apply(Context *ctx)
 {
-    if (/*FunctionObject *fun =*/ ctx->thisObject.asFunctionObject()) {
+    if (FunctionObject *f = ctx->thisObject.asFunctionObject()) {
 
         Value thisObject = ctx->argument(0).toObject(ctx);
         if (thisObject.isNull() || thisObject.isUndefined())
@@ -1798,7 +1806,7 @@ void FunctionPrototype::method_apply(Context *ctx)
             return;
         }
 
-        ctx->result = __qmljs_call_value(ctx, thisObject, ctx->thisObject, args.data(), args.size());
+        ctx->result = __qmljs_call_function(ctx, thisObject, f, args.data(), args.size());
     } else {
         ctx->throwTypeError();
     }
@@ -1806,13 +1814,12 @@ void FunctionPrototype::method_apply(Context *ctx)
 
 void FunctionPrototype::method_call(Context *ctx)
 {
-    if (FunctionObject *fun = ctx->thisObject.asFunctionObject()) {
-        Q_UNUSED(fun);
+    if (FunctionObject *f = ctx->thisObject.asFunctionObject()) {
         Value thisArg = ctx->argument(0);
         QVector<Value> args(ctx->argumentCount ? ctx->argumentCount - 1 : 0);
         if (ctx->argumentCount)
             qCopy(ctx->arguments + 1, ctx->arguments + ctx->argumentCount, args.begin());
-        ctx->result = __qmljs_call_value(ctx, thisArg, ctx->thisObject, args.data(), args.size());
+        ctx->result = __qmljs_call_function(ctx, thisArg, f, args.data(), args.size());
     } else {
         ctx->throwTypeError();
     }