aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLars Knoll <lars.knoll@digia.com>2013-08-30 14:39:40 +0200
committerThe Qt Project <gerrit-noreply@qt-project.org>2013-09-02 17:27:36 +0200
commitbdc558c932fdb4b651c85d632bd65b9380e2e42a (patch)
tree0bdb468025ddba3e5cb44cdd9f4f8d8b1b0dd791
parent2bd74245fadb69922132f7ca2ae98e645f67742b (diff)
Optimise property lookups on primitive types
This gives a large speedup on code such as "foo".charAt(2), or (5.).toString(). Change-Id: I8b6c46f2f69a4b00f82048a9368d8e9baf4d89ee Reviewed-by: Simon Hausmann <simon.hausmann@digia.com>
-rw-r--r--src/qml/jsruntime/qv4lookup.cpp146
-rw-r--r--src/qml/jsruntime/qv4lookup_p.h16
-rw-r--r--src/qml/jsruntime/qv4runtime.cpp37
-rw-r--r--tests/manual/v4/TestExpectations3
4 files changed, 169 insertions, 33 deletions
diff --git a/src/qml/jsruntime/qv4lookup.cpp b/src/qml/jsruntime/qv4lookup.cpp
index 94df9685e3..e66055653e 100644
--- a/src/qml/jsruntime/qv4lookup.cpp
+++ b/src/qml/jsruntime/qv4lookup.cpp
@@ -93,16 +93,58 @@ void Lookup::getterGeneric(QV4::Lookup *l, QV4::Value *result, const QV4::Value
return;
}
- Value res;
- if (Managed *m = object.asManaged()) {
- res = m->get(l->name);
- } else {
- ExecutionContext *ctx = l->name->engine()->current;
- Object *o = __qmljs_convert_to_object(ctx, object);
- res = o->get(l->name);
+ ExecutionEngine *engine = l->name->engine();
+ Object *proto;
+ switch (object.type()) {
+ case Value::Undefined_Type:
+ case Value::Null_Type:
+ engine->current->throwTypeError();
+ case Value::Boolean_Type:
+ proto = engine->booleanClass->prototype;
+ break;
+ case Value::String_Type:
+ proto = engine->stringClass->prototype;
+ if (l->name == engine->id_length) {
+ // special case, as the property is on the object itself
+ l->getter = stringLengthGetter;
+ stringLengthGetter(l, result, object);
+ return;
+ }
+ break;
+ case Value::Integer_Type:
+ default: // Number
+ proto = engine->numberClass->prototype;
}
+
+ PropertyAttributes attrs;
+ Property *p = l->lookup(proto, &attrs);
+ if (p) {
+ l->type = object.type();
+ l->proto = proto;
+ if (attrs.isData()) {
+ if (l->level == 0)
+ l->getter = Lookup::primitiveGetter0;
+ else if (l->level == 1)
+ l->getter = Lookup::primitiveGetter1;
+ if (result)
+ *result = p->value;
+ return;
+ } else {
+ if (l->level == 0)
+ l->getter = Lookup::primitiveGetterAccessor0;
+ else if (l->level == 1)
+ l->getter = Lookup::primitiveGetterAccessor1;
+ if (result)
+ *result = p->value;
+ Value res = proto->getValue(object, p, attrs);
+ if (result)
+ *result = res;
+ return;
+ }
+ }
+
if (result)
- *result = res;
+ *result = Value::undefinedValue();
}
void Lookup::getter0(Lookup *l, Value *result, const Value &object)
@@ -225,6 +267,94 @@ void Lookup::getterAccessor2(Lookup *l, Value *result, const Value &object)
}
+void Lookup::primitiveGetter0(Lookup *l, Value *result, const Value &object)
+{
+ if (object.type() == l->type) {
+ Object *o = l->proto;
+ if (l->classList[0] == o->internalClass) {
+ if (result)
+ *result = o->memberData[l->index].value;
+ return;
+ }
+ }
+ l->getter = getterGeneric;
+ getterGeneric(l, result, object);
+}
+
+void Lookup::primitiveGetter1(Lookup *l, Value *result, const Value &object)
+{
+ if (object.type() == l->type) {
+ Object *o = l->proto;
+ if (l->classList[0] == o->internalClass &&
+ l->classList[1] == o->prototype()->internalClass) {
+ if (result)
+ *result = o->prototype()->memberData[l->index].value;
+ return;
+ }
+ }
+ l->getter = getterGeneric;
+ getterGeneric(l, result, object);
+}
+
+void Lookup::primitiveGetterAccessor0(Lookup *l, Value *result, const Value &object)
+{
+ if (object.type() == l->type) {
+ Object *o = l->proto;
+ if (l->classList[0] == o->internalClass) {
+ Value res;
+ FunctionObject *getter = o->memberData[l->index].getter();
+ if (!getter) {
+ res = Value::undefinedValue();
+ } else {
+ CALLDATA(0);
+ d.thisObject = object;
+ res = getter->call(d);
+ }
+ if (result)
+ *result = res;
+ return;
+ }
+ }
+ l->getter = getterGeneric;
+ getterGeneric(l, result, object);
+}
+
+void Lookup::primitiveGetterAccessor1(Lookup *l, Value *result, const Value &object)
+{
+ if (object.type() == l->type) {
+ Object *o = l->proto;
+ if (l->classList[0] == o->internalClass &&
+ l->classList[1] == o->prototype()->internalClass) {
+ Value res;
+ FunctionObject *getter = o->prototype()->memberData[l->index].getter();
+ if (!getter) {
+ res = Value::undefinedValue();
+ } else {
+ CALLDATA(0);
+ d.thisObject = object;
+ res = getter->call(d);
+ }
+ if (result)
+ *result = res;
+ return;
+ }
+ }
+ l->getter = getterGeneric;
+ getterGeneric(l, result, object);
+}
+
+void Lookup::stringLengthGetter(Lookup *l, Value *result, const Value &object)
+{
+ if (String *s = object.asString()) {
+ if (result)
+ *result = Value::fromUInt32(s->length());
+ return;
+ }
+ l->getter = getterGeneric;
+ getterGeneric(l, result, object);
+}
+
+
void Lookup::globalGetterGeneric(Lookup *l, ExecutionContext *ctx, Value *result)
{
Object *o = ctx->engine->globalObject;
diff --git a/src/qml/jsruntime/qv4lookup_p.h b/src/qml/jsruntime/qv4lookup_p.h
index 3763182e84..b37738dd92 100644
--- a/src/qml/jsruntime/qv4lookup_p.h
+++ b/src/qml/jsruntime/qv4lookup_p.h
@@ -59,7 +59,15 @@ struct Lookup {
void (*globalGetter)(Lookup *l, ExecutionContext *ctx, Value *result);
void (*setter)(Lookup *l, const Value &object, const Value &v);
};
- InternalClass *classList[Size];
+ union {
+ InternalClass *classList[Size];
+ struct {
+ void *dummy0;
+ void *dummy1;
+ Object *proto;
+ unsigned type;
+ };
+ };
int level;
uint index;
String *name;
@@ -72,6 +80,12 @@ struct Lookup {
static void getterAccessor1(Lookup *l, Value *result, const Value &object);
static void getterAccessor2(Lookup *l, Value *result, const Value &object);
+ static void primitiveGetter0(Lookup *l, Value *result, const Value &object);
+ static void primitiveGetter1(Lookup *l, Value *result, const Value &object);
+ static void primitiveGetterAccessor0(Lookup *l, Value *result, const Value &object);
+ static void primitiveGetterAccessor1(Lookup *l, Value *result, const Value &object);
+ static void stringLengthGetter(Lookup *l, Value *result, const Value &object);
+
static void globalGetterGeneric(Lookup *l, ExecutionContext *ctx, Value *result);
static void globalGetter0(Lookup *l, ExecutionContext *ctx, Value *result);
static void globalGetter1(Lookup *l, ExecutionContext *ctx, Value *result);
diff --git a/src/qml/jsruntime/qv4runtime.cpp b/src/qml/jsruntime/qv4runtime.cpp
index 4f195670b2..33521efb02 100644
--- a/src/qml/jsruntime/qv4runtime.cpp
+++ b/src/qml/jsruntime/qv4runtime.cpp
@@ -808,19 +808,12 @@ void __qmljs_call_property(ExecutionContext *context, Value *result, const Value
void __qmljs_call_property_lookup(ExecutionContext *context, Value *result, const Value &thisObject, uint index, Value *args, int argc)
{
- Lookup *l = context->lookups + index;
+ Value func;
- Object *baseObject;
- if (thisObject.isObject())
- baseObject = thisObject.objectValue();
- else if (thisObject.isString())
- baseObject = context->engine->stringClass->prototype;
- else
- baseObject = __qmljs_convert_to_object(context, thisObject);
+ Lookup *l = context->lookups + index;
+ l->getter(l, &func, thisObject);
- Value func;
- l->getter(l, &func, Value::fromObject(baseObject));
- FunctionObject *o = func.asFunctionObject();
+ Object *o = func.asObject();
if (!o)
context->throwTypeError();
@@ -869,21 +862,21 @@ void __qmljs_call_value(ExecutionContext *context, Value *result, const Value *t
void __qmljs_construct_global_lookup(ExecutionContext *context, Value *result, uint index, Value *args, int argc)
{
- Lookup *l = context->lookups + index;
Value func;
+
+ Lookup *l = context->lookups + index;
l->globalGetter(l, context, &func);
- if (Object *f = func.asObject()) {
- CallData d;
- d.args = args;
- d.argc = argc;
- Value res = f->construct(d);
- if (result)
- *result = res;
- return;
- }
+ Object *f = func.asObject();
+ if (!f)
+ context->throwTypeError();
- context->throwTypeError();
+ CallData d;
+ d.args = args;
+ d.argc = argc;
+ Value res = f->construct(d);
+ if (result)
+ *result = res;
}
diff --git a/tests/manual/v4/TestExpectations b/tests/manual/v4/TestExpectations
index e1c228db8e..a5270c369f 100644
--- a/tests/manual/v4/TestExpectations
+++ b/tests/manual/v4/TestExpectations
@@ -3,7 +3,6 @@
15.2.3.6-2-17-1 failing
-10.4.3-1-104 failing
10.4.3-1-106 failing
11.2.3-3_3 failing
S13_A15_T4 failing
@@ -18,4 +17,4 @@ S15.2.4.4_A14 failing
Sbp_12.5_A9_T3 failing
Sbp_12.6.1_A13_T3 failing
Sbp_12.6.2_A13_T3 failing
-Sbp_12.6.4_A13_T3 failing
+Sbp_12.6.4_A13_T3 failing \ No newline at end of file