From 393108500832dcefa4c4def442a08f20d3fbc4cd Mon Sep 17 00:00:00 2001 From: Lars Knoll Date: Fri, 17 Jan 2014 12:19:34 +0100 Subject: Use lookups for indexed accesses This speeds up reading array data from objects significantly. Change-Id: I5d17a7b3e7583a16dc76d1ee6cbc1d7134e4c2fa Reviewed-by: Simon Hausmann --- src/qml/compiler/qv4compileddata.cpp | 4 ++ src/qml/compiler/qv4compileddata_p.h | 3 +- src/qml/compiler/qv4compiler.cpp | 10 +++++ src/qml/compiler/qv4compiler_p.h | 1 + src/qml/compiler/qv4isel_masm.cpp | 8 ++++ src/qml/compiler/qv4isel_p.h | 1 + src/qml/jsruntime/qv4lookup.cpp | 72 ++++++++++++++++++++++++++++++++++++ src/qml/jsruntime/qv4lookup_p.h | 6 +++ 8 files changed, 104 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/qml/compiler/qv4compileddata.cpp b/src/qml/compiler/qv4compileddata.cpp index 9eac0e678d..717e7f4ba2 100644 --- a/src/qml/compiler/qv4compileddata.cpp +++ b/src/qml/compiler/qv4compileddata.cpp @@ -101,12 +101,16 @@ QV4::Function *CompilationUnit::linkToEngine(ExecutionEngine *engine) l->setter = QV4::Lookup::setterGeneric; else if (compiledLookups[i].type_and_flags == CompiledData::Lookup::Type_GlobalGetter) l->globalGetter = QV4::Lookup::globalGetterGeneric; + else if (compiledLookups[i].type_and_flags == CompiledData::Lookup::Type_IndexedGetter) + l->indexedGetter = QV4::Lookup::indexedGetterGeneric; for (int j = 0; j < QV4::Lookup::Size; ++j) l->classList[j] = 0; l->level = -1; l->index = UINT_MAX; l->name = runtimeStrings[compiledLookups[i].nameIndex].asString(); + if (compiledLookups[i].type_and_flags == CompiledData::Lookup::Type_IndexedGetter) + l->engine = engine; } } diff --git a/src/qml/compiler/qv4compileddata_p.h b/src/qml/compiler/qv4compileddata_p.h index 83e8058be1..4208ec9441 100644 --- a/src/qml/compiler/qv4compileddata_p.h +++ b/src/qml/compiler/qv4compileddata_p.h @@ -102,7 +102,8 @@ struct Lookup enum Type { Type_Getter = 0x0, Type_Setter = 0x1, - Type_GlobalGetter = 2 + Type_GlobalGetter = 2, + Type_IndexedGetter = 3 }; quint32 type_and_flags; diff --git a/src/qml/compiler/qv4compiler.cpp b/src/qml/compiler/qv4compiler.cpp index 9041b04837..d18c43a969 100644 --- a/src/qml/compiler/qv4compiler.cpp +++ b/src/qml/compiler/qv4compiler.cpp @@ -72,6 +72,15 @@ int QV4::Compiler::JSUnitGenerator::getStringId(const QString &string) const return stringToId.value(string); } +uint QV4::Compiler::JSUnitGenerator::registerIndexedGetterLookup() +{ + CompiledData::Lookup l; + l.type_and_flags = CompiledData::Lookup::Type_IndexedGetter; + l.nameIndex = 0; + lookups << l; + return lookups.size() - 1; +} + uint QV4::Compiler::JSUnitGenerator::registerGetterLookup(const QString &name) { CompiledData::Lookup l; @@ -81,6 +90,7 @@ uint QV4::Compiler::JSUnitGenerator::registerGetterLookup(const QString &name) return lookups.size() - 1; } + uint QV4::Compiler::JSUnitGenerator::registerSetterLookup(const QString &name) { CompiledData::Lookup l; diff --git a/src/qml/compiler/qv4compiler_p.h b/src/qml/compiler/qv4compiler_p.h index 1596fcb622..4779b5d3c4 100644 --- a/src/qml/compiler/qv4compiler_p.h +++ b/src/qml/compiler/qv4compiler_p.h @@ -70,6 +70,7 @@ struct Q_QML_EXPORT JSUnitGenerator { uint registerGetterLookup(const QString &name); uint registerSetterLookup(const QString &name); uint registerGlobalGetterLookup(const QString &name); + uint registerIndexedGetterLookup(); int registerRegExp(QQmlJS::V4IR::RegExp *regexp); diff --git a/src/qml/compiler/qv4isel_masm.cpp b/src/qml/compiler/qv4isel_masm.cpp index 415fdad8e9..6df94e713d 100644 --- a/src/qml/compiler/qv4isel_masm.cpp +++ b/src/qml/compiler/qv4isel_masm.cpp @@ -1015,6 +1015,14 @@ void InstructionSelection::setQObjectProperty(V4IR::Expr *source, V4IR::Expr *ta void InstructionSelection::getElement(V4IR::Expr *base, V4IR::Expr *index, V4IR::Temp *target) { + if (useFastLookups) { + uint lookup = registerIndexedGetterLookup(); + generateLookupCall(target, lookup, qOffsetOf(QV4::Lookup, indexedGetter), + Assembler::PointerToValue(base), + Assembler::PointerToValue(index)); + return; + } + #if 0 // QT_POINTER_SIZE == 8 V4IR::Temp *tbase = base->asTemp(); V4IR::Temp *tindex = index->asTemp(); diff --git a/src/qml/compiler/qv4isel_p.h b/src/qml/compiler/qv4isel_p.h index 5ddafc07ab..6f33098172 100644 --- a/src/qml/compiler/qv4isel_p.h +++ b/src/qml/compiler/qv4isel_p.h @@ -72,6 +72,7 @@ public: void setUseFastLookups(bool b) { useFastLookups = b; } int registerString(const QString &str) { return jsGenerator->registerString(str); } + uint registerIndexedGetterLookup() { return jsGenerator->registerIndexedGetterLookup(); } uint registerGetterLookup(const QString &name) { return jsGenerator->registerGetterLookup(name); } uint registerSetterLookup(const QString &name) { return jsGenerator->registerSetterLookup(name); } uint registerGlobalGetterLookup(const QString &name) { return jsGenerator->registerGlobalGetterLookup(name); } diff --git a/src/qml/jsruntime/qv4lookup.cpp b/src/qml/jsruntime/qv4lookup.cpp index 80b8b08a1a..c9d22523a9 100644 --- a/src/qml/jsruntime/qv4lookup.cpp +++ b/src/qml/jsruntime/qv4lookup.cpp @@ -46,6 +46,7 @@ QT_BEGIN_NAMESPACE using namespace QV4; + ReturnedValue Lookup::lookup(ValueRef thisObject, Object *obj, PropertyAttributes *attrs) { int i = 0; @@ -107,6 +108,77 @@ ReturnedValue Lookup::lookup(Object *obj, PropertyAttributes *attrs) return Primitive::emptyValue().asReturnedValue(); } +ReturnedValue Lookup::indexedGetterGeneric(Lookup *l, const ValueRef object, const ValueRef index) +{ + if (object->isObject() && index->asArrayIndex() < UINT_MAX) { + l->indexedGetter = indexedGetterObjectInt; + return indexedGetterObjectInt(l, object, index); + } + return indexedGetterFallback(l, object, index); +} + +ReturnedValue Lookup::indexedGetterFallback(Lookup *l, const ValueRef object, const ValueRef index) +{ + Q_UNUSED(l); + ExecutionContext *ctx = l->engine->currentContext(); + Scope scope(ctx); + uint idx = index->asArrayIndex(); + + Scoped o(scope, object); + if (!o) { + if (idx < UINT_MAX) { + if (String *str = object->asString()) { + if (idx >= (uint)str->toQString().length()) { + return Encode::undefined(); + } + const QString s = str->toQString().mid(idx, 1); + return scope.engine->newString(s)->asReturnedValue(); + } + } + + if (object->isNullOrUndefined()) { + QString message = QStringLiteral("Cannot read property '%1' of %2").arg(index->toQStringNoThrow()).arg(object->toQStringNoThrow()); + return ctx->throwTypeError(message); + } + + o = __qmljs_convert_to_object(ctx, object); + if (!o) // type error + return Encode::undefined(); + } + + if (idx < UINT_MAX) { + if (!o->arrayData->hasAttributes()) { + ScopedValue v(scope, o->arrayData->get(idx)); + if (!v->isEmpty()) + return v->asReturnedValue(); + } + + return o->getIndexed(idx); + } + + ScopedString name(scope, index->toString(ctx)); + if (scope.hasException()) + return Encode::undefined(); + return o->get(name); + +} + + +ReturnedValue Lookup::indexedGetterObjectInt(Lookup *l, const ValueRef object, const ValueRef index) +{ + uint idx = index->asArrayIndex(); + if (idx == UINT_MAX || !object->isObject()) + return indexedGetterGeneric(l, object, index); + + Object *o = object->objectValue(); + if (o->arrayData && o->arrayData->type == ArrayData::Simple) { + if (idx < static_cast(o->arrayData)->len) + if (!o->arrayData->data[idx].isEmpty()) + return o->arrayData->data[idx].asReturnedValue(); + } + + return indexedGetterFallback(l, object, index); +} ReturnedValue Lookup::getterGeneric(QV4::Lookup *l, const ValueRef object) { diff --git a/src/qml/jsruntime/qv4lookup_p.h b/src/qml/jsruntime/qv4lookup_p.h index f47b603c15..50874411de 100644 --- a/src/qml/jsruntime/qv4lookup_p.h +++ b/src/qml/jsruntime/qv4lookup_p.h @@ -55,11 +55,13 @@ namespace QV4 { struct Lookup { enum { Size = 4 }; union { + ReturnedValue (*indexedGetter)(Lookup *l, const ValueRef object, const ValueRef index); ReturnedValue (*getter)(Lookup *l, const ValueRef object); ReturnedValue (*globalGetter)(Lookup *l, ExecutionContext *ctx); void (*setter)(Lookup *l, const ValueRef object, const ValueRef v); }; union { + ExecutionEngine *engine; InternalClass *classList[Size]; struct { void *dummy0; @@ -72,6 +74,10 @@ struct Lookup { uint index; String *name; + static ReturnedValue indexedGetterGeneric(Lookup *l, const ValueRef object, const ValueRef index); + static ReturnedValue indexedGetterFallback(Lookup *l, const ValueRef object, const ValueRef index); + static ReturnedValue indexedGetterObjectInt(Lookup *l, const ValueRef object, const ValueRef index); + static ReturnedValue getterGeneric(Lookup *l, const ValueRef object); static ReturnedValue getter0(Lookup *l, const ValueRef object); static ReturnedValue getter1(Lookup *l, const ValueRef object); -- cgit v1.2.3