diff options
-rw-r--r-- | src/qml/compiler/qv4compileddata.cpp | 13 | ||||
-rw-r--r-- | src/qml/compiler/qv4compileddata_p.h | 3 | ||||
-rw-r--r-- | src/qml/compiler/qv4compiler.cpp | 9 | ||||
-rw-r--r-- | src/qml/compiler/qv4compiler_p.h | 1 | ||||
-rw-r--r-- | src/qml/compiler/qv4isel_masm.cpp | 102 | ||||
-rw-r--r-- | src/qml/compiler/qv4isel_masm_p.h | 12 | ||||
-rw-r--r-- | src/qml/compiler/qv4isel_p.h | 1 | ||||
-rw-r--r-- | src/qml/jsruntime/qv4lookup.cpp | 57 | ||||
-rw-r--r-- | src/qml/jsruntime/qv4lookup_p.h | 5 | ||||
-rw-r--r-- | src/qml/jsruntime/qv4object_p.h | 2 |
10 files changed, 97 insertions, 108 deletions
diff --git a/src/qml/compiler/qv4compileddata.cpp b/src/qml/compiler/qv4compileddata.cpp index 717e7f4ba2..367ada194b 100644 --- a/src/qml/compiler/qv4compileddata.cpp +++ b/src/qml/compiler/qv4compileddata.cpp @@ -95,21 +95,24 @@ QV4::Function *CompilationUnit::linkToEngine(ExecutionEngine *engine) for (uint i = 0; i < data->lookupTableSize; ++i) { QV4::Lookup *l = runtimeLookups + i; - if (compiledLookups[i].type_and_flags == CompiledData::Lookup::Type_Getter) + Lookup::Type type = Lookup::Type(compiledLookups[i].type_and_flags); + if (type == CompiledData::Lookup::Type_Getter) l->getter = QV4::Lookup::getterGeneric; - else if (compiledLookups[i].type_and_flags == CompiledData::Lookup::Type_Setter) + else if (type == CompiledData::Lookup::Type_Setter) l->setter = QV4::Lookup::setterGeneric; - else if (compiledLookups[i].type_and_flags == CompiledData::Lookup::Type_GlobalGetter) + else if (type == CompiledData::Lookup::Type_GlobalGetter) l->globalGetter = QV4::Lookup::globalGetterGeneric; - else if (compiledLookups[i].type_and_flags == CompiledData::Lookup::Type_IndexedGetter) + else if (type == CompiledData::Lookup::Type_IndexedGetter) l->indexedGetter = QV4::Lookup::indexedGetterGeneric; + else if (type == CompiledData::Lookup::Type_IndexedSetter) + l->indexedSetter = QV4::Lookup::indexedSetterGeneric; 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) + if (type == CompiledData::Lookup::Type_IndexedGetter || type == CompiledData::Lookup::Type_IndexedSetter) l->engine = engine; } } diff --git a/src/qml/compiler/qv4compileddata_p.h b/src/qml/compiler/qv4compileddata_p.h index 29b6fd564e..451bf4216a 100644 --- a/src/qml/compiler/qv4compileddata_p.h +++ b/src/qml/compiler/qv4compileddata_p.h @@ -114,7 +114,8 @@ struct Lookup Type_Getter = 0x0, Type_Setter = 0x1, Type_GlobalGetter = 2, - Type_IndexedGetter = 3 + Type_IndexedGetter = 3, + Type_IndexedSetter = 4 }; quint32 type_and_flags; diff --git a/src/qml/compiler/qv4compiler.cpp b/src/qml/compiler/qv4compiler.cpp index d18c43a969..7fb10d5f42 100644 --- a/src/qml/compiler/qv4compiler.cpp +++ b/src/qml/compiler/qv4compiler.cpp @@ -81,6 +81,15 @@ uint QV4::Compiler::JSUnitGenerator::registerIndexedGetterLookup() return lookups.size() - 1; } +uint QV4::Compiler::JSUnitGenerator::registerIndexedSetterLookup() +{ + CompiledData::Lookup l; + l.type_and_flags = CompiledData::Lookup::Type_IndexedSetter; + l.nameIndex = 0; + lookups << l; + return lookups.size() - 1; +} + uint QV4::Compiler::JSUnitGenerator::registerGetterLookup(const QString &name) { CompiledData::Lookup l; diff --git a/src/qml/compiler/qv4compiler_p.h b/src/qml/compiler/qv4compiler_p.h index 4779b5d3c4..6baefae7b7 100644 --- a/src/qml/compiler/qv4compiler_p.h +++ b/src/qml/compiler/qv4compiler_p.h @@ -71,6 +71,7 @@ struct Q_QML_EXPORT JSUnitGenerator { uint registerSetterLookup(const QString &name); uint registerGlobalGetterLookup(const QString &name); uint registerIndexedGetterLookup(); + uint registerIndexedSetterLookup(); int registerRegExp(QQmlJS::V4IR::RegExp *regexp); diff --git a/src/qml/compiler/qv4isel_masm.cpp b/src/qml/compiler/qv4isel_masm.cpp index b8b16a4151..427a6b7d56 100644 --- a/src/qml/compiler/qv4isel_masm.cpp +++ b/src/qml/compiler/qv4isel_masm.cpp @@ -1023,107 +1023,19 @@ void InstructionSelection::getElement(V4IR::Expr *base, V4IR::Expr *index, V4IR: return; } -#if 0 // QT_POINTER_SIZE == 8 - V4IR::Temp *tbase = base->asTemp(); - V4IR::Temp *tindex = index->asTemp(); - if (tbase && tindex && - tbase->kind != V4IR::Temp::PhysicalRegister) { - Assembler::Pointer addr = _as->loadTempAddress(Assembler::ReturnValueRegister, tbase); - _as->load64(addr, Assembler::ScratchRegister); - _as->move(Assembler::ScratchRegister, Assembler::ReturnValueRegister); - _as->urshift64(Assembler::TrustedImm32(QV4::Value::IsManaged_Shift), Assembler::ReturnValueRegister); - Assembler::Jump notManaged = _as->branch64(Assembler::NotEqual, Assembler::ReturnValueRegister, Assembler::TrustedImm64(0)); - // check whether we have an object with a simple array - // ### need to check we have an object first! - Assembler::Address managedType(Assembler::ScratchRegister, qOffsetOf(QV4::Object, arrayData) + qOffsetOf(QV4::ArrayData, flags)); - _as->load8(managedType, Assembler::ReturnValueRegister); - _as->and32(Assembler::TrustedImm32(QV4::ArrayData::SimpleArray), Assembler::ReturnValueRegister); - Assembler::Jump notSimple = _as->branch32(Assembler::Equal, Assembler::ReturnValueRegister, Assembler::TrustedImm32(0)); - - bool needNegativeCheck = false; - Assembler::Jump fallback, fallback2; - if (tindex->kind == V4IR::Temp::PhysicalRegister) { - if (tindex->type == V4IR::SInt32Type) { - fallback = _as->branch32(Assembler::LessThan, (Assembler::RegisterID)tindex->index, Assembler::TrustedImm32(0)); - _as->move((Assembler::RegisterID) tindex->index, Assembler::ScratchRegister); - needNegativeCheck = true; - } else { - // double, convert and check if it's a int - fallback2 = _as->branchTruncateDoubleToUint32((Assembler::FPRegisterID) tindex->index, Assembler::ScratchRegister); - _as->convertInt32ToDouble(Assembler::ScratchRegister, Assembler::FPGpr0); - fallback = _as->branchDouble(Assembler::DoubleNotEqual, Assembler::FPGpr0, (Assembler::FPRegisterID) tindex->index); - } - } else { - Assembler::Pointer indexAddr = _as->loadTempAddress(Assembler::ReturnValueRegister, tindex); - _as->load64(indexAddr, Assembler::ScratchRegister); - _as->move(Assembler::ScratchRegister, Assembler::ReturnValueRegister); - _as->urshift64(Assembler::TrustedImm32(QV4::Value::IsNumber_Shift), Assembler::ReturnValueRegister); - Assembler::Jump isInteger = _as->branch64(Assembler::Equal, Assembler::ReturnValueRegister, Assembler::TrustedImm64(1)); - - // other type, convert to double and check if it's a int - // this check is ok to do even if the type is something else than a double, as - // that would result in a NaN - _as->move(Assembler::TrustedImm64(QV4::Value::NaNEncodeMask), Assembler::ReturnValueRegister); - _as->xor64(Assembler::ScratchRegister, Assembler::ReturnValueRegister); - _as->move64ToDouble(Assembler::ReturnValueRegister, Assembler::FPGpr0); - fallback2 = _as->branchTruncateDoubleToUint32(Assembler::FPGpr0, Assembler::ScratchRegister); - _as->convertInt32ToDouble(Assembler::ScratchRegister, Assembler::FPGpr1); - fallback = _as->branchDouble(Assembler::DoubleNotEqualOrUnordered, Assembler::FPGpr0, Assembler::FPGpr1); - - isInteger.link(_as); - _as->or32(Assembler::TrustedImm32(0), Assembler::ScratchRegister); - needNegativeCheck = true; - } - - // get data, ScratchRegister holds index - addr = _as->loadTempAddress(Assembler::ReturnValueRegister, tbase); - _as->load64(addr, Assembler::ReturnValueRegister); - Address dataLen(Assembler::ReturnValueRegister, qOffsetOf(Object, arrayData) + qOffsetOf(ArrayData, length)); - Assembler::Jump outOfRange; - if (needNegativeCheck) - outOfRange = _as->branch32(Assembler::LessThan, Assembler::ScratchRegister, Assembler::TrustedImm32(0)); - Assembler::Jump outOfRange2 = _as->branch32(Assembler::GreaterThanOrEqual, Assembler::ScratchRegister, dataLen); - Address arrayData(Assembler::ReturnValueRegister, qOffsetOf(Object, arrayData) + qOffsetOf(ArrayData, data)); - _as->load64(arrayData, Assembler::ReturnValueRegister); - Q_ASSERT(sizeof(Property) == (1<<4)); - _as->lshift64(Assembler::TrustedImm32(4), Assembler::ScratchRegister); - _as->add64(Assembler::ReturnValueRegister, Assembler::ScratchRegister); - Address value(Assembler::ScratchRegister, qOffsetOf(Property, value)); - _as->load64(value, Assembler::ReturnValueRegister); - - // check that the value is not empty - _as->move(Assembler::ReturnValueRegister, Assembler::ScratchRegister); - _as->urshift64(Assembler::TrustedImm32(32), Assembler::ScratchRegister); - Assembler::Jump emptyValue = _as->branch32(Assembler::Equal, Assembler::TrustedImm32(QV4::Value::Empty_Type), Assembler::ScratchRegister); - _as->storeReturnValue(target); - - Assembler::Jump done = _as->jump(); - - emptyValue.link(_as); - if (outOfRange.isSet()) - outOfRange.link(_as); - outOfRange2.link(_as); - if (fallback.isSet()) - fallback.link(_as); - if (fallback2.isSet()) - fallback2.link(_as); - notSimple.link(_as); - notManaged.link(_as); - - generateFunctionCall(target, __qmljs_get_element, Assembler::ContextRegister, - Assembler::PointerToValue(base), Assembler::PointerToValue(index)); - - done.link(_as); - return; - } -#endif - generateFunctionCall(target, __qmljs_get_element, Assembler::ContextRegister, Assembler::PointerToValue(base), Assembler::PointerToValue(index)); } void InstructionSelection::setElement(V4IR::Expr *source, V4IR::Expr *targetBase, V4IR::Expr *targetIndex) { + if (useFastLookups) { + uint lookup = registerIndexedSetterLookup(); + generateLookupCall(Assembler::Void, lookup, qOffsetOf(QV4::Lookup, indexedSetter), + Assembler::PointerToValue(targetBase), Assembler::PointerToValue(targetIndex), + Assembler::PointerToValue(source)); + return; + } generateFunctionCall(Assembler::Void, __qmljs_set_element, Assembler::ContextRegister, Assembler::PointerToValue(targetBase), Assembler::PointerToValue(targetIndex), Assembler::PointerToValue(source)); diff --git a/src/qml/compiler/qv4isel_masm_p.h b/src/qml/compiler/qv4isel_masm_p.h index a146220015..f22e0930e3 100644 --- a/src/qml/compiler/qv4isel_masm_p.h +++ b/src/qml/compiler/qv4isel_masm_p.h @@ -1580,8 +1580,8 @@ private: int prepareVariableArguments(V4IR::ExprList* args); int prepareCallData(V4IR::ExprList* args, V4IR::Expr *thisObject); - template <typename Retval, typename Arg1, typename Arg2> - void generateLookupCall(Retval retval, uint index, uint getterSetterOffset, Arg1 arg1, Arg2 arg2) + template <typename Retval, typename Arg1, typename Arg2, typename Arg3> + void generateLookupCall(Retval retval, uint index, uint getterSetterOffset, Arg1 arg1, Arg2 arg2, Arg3 arg3) { Assembler::RegisterID lookupRegister; #if CPU(ARM) @@ -1595,13 +1595,13 @@ private: getterSetter.offset += getterSetterOffset; _as->generateFunctionCallImp(retval, "lookup getter/setter", - RelativeCall(getterSetter), lookupAddr, arg1, arg2); + RelativeCall(getterSetter), lookupAddr, arg1, arg2, arg3); } - template <typename Arg1> - void generateLookupCall(uint index, uint getterSetterOffset, Arg1 arg1) + template <typename Retval, typename Arg1, typename Arg2> + void generateLookupCall(Retval retval, uint index, uint getterSetterOffset, Arg1 arg1, Arg2 arg2) { - generateLookupCall(index, getterSetterOffset, arg1, Assembler::VoidType()); + generateLookupCall(retval, index, getterSetterOffset, arg1, arg2, Assembler::VoidType()); } /// This is a temporary method, and will be removed when registers are fully supported. diff --git a/src/qml/compiler/qv4isel_p.h b/src/qml/compiler/qv4isel_p.h index 6f33098172..57222672b9 100644 --- a/src/qml/compiler/qv4isel_p.h +++ b/src/qml/compiler/qv4isel_p.h @@ -73,6 +73,7 @@ public: int registerString(const QString &str) { return jsGenerator->registerString(str); } uint registerIndexedGetterLookup() { return jsGenerator->registerIndexedGetterLookup(); } + uint registerIndexedSetterLookup() { return jsGenerator->registerIndexedSetterLookup(); } 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 c9d22523a9..4a75272843 100644 --- a/src/qml/jsruntime/qv4lookup.cpp +++ b/src/qml/jsruntime/qv4lookup.cpp @@ -180,6 +180,63 @@ ReturnedValue Lookup::indexedGetterObjectInt(Lookup *l, const ValueRef object, c return indexedGetterFallback(l, object, index); } +void Lookup::indexedSetterGeneric(Lookup *l, const ValueRef object, const ValueRef index, const ValueRef v) +{ + if (object->isObject()) { + Object *o = object->objectValue(); + if (o->arrayData && o->arrayData->type == ArrayData::Simple && index->asArrayIndex() < UINT_MAX) { + l->indexedSetter = indexedSetterObjectInt; + indexedSetterObjectInt(l, object, index, v); + return; + } + } + indexedSetterFallback(l, object, index, v); +} + +void Lookup::indexedSetterFallback(Lookup *l, const ValueRef object, const ValueRef index, const ValueRef value) +{ + ExecutionContext *ctx = l->engine->currentContext(); + Scope scope(ctx); + ScopedObject o(scope, object->toObject(ctx)); + if (scope.engine->hasException) + return; + + uint idx = index->asArrayIndex(); + if (idx < UINT_MAX) { + if (o->arrayData && o->arrayData->type == ArrayData::Simple) { + SimpleArrayData *s = static_cast<SimpleArrayData *>(o->arrayData); + if (s && idx < s->len && !s->data[idx].isEmpty()) { + s->data[idx] = value; + return; + } + } + o->putIndexed(idx, value); + return; + } + + ScopedString name(scope, index->toString(ctx)); + o->put(name, value); +} + +void Lookup::indexedSetterObjectInt(Lookup *l, const ValueRef object, const ValueRef index, const ValueRef v) +{ + uint idx = index->asArrayIndex(); + if (idx == UINT_MAX || !object->isObject()) { + indexedSetterGeneric(l, object, index, v); + return; + } + + Object *o = object->objectValue(); + if (o->arrayData && o->arrayData->type == ArrayData::Simple) { + SimpleArrayData *s = static_cast<SimpleArrayData *>(o->arrayData); + if (idx < s->len && !s->data[idx].isEmpty()) { + s->data[idx] = v; + return; + } + } + indexedSetterFallback(l, object, index, v); +} + ReturnedValue Lookup::getterGeneric(QV4::Lookup *l, const ValueRef object) { if (Object *o = object->asObject()) diff --git a/src/qml/jsruntime/qv4lookup_p.h b/src/qml/jsruntime/qv4lookup_p.h index 50874411de..7f107bf8eb 100644 --- a/src/qml/jsruntime/qv4lookup_p.h +++ b/src/qml/jsruntime/qv4lookup_p.h @@ -56,6 +56,7 @@ struct Lookup { enum { Size = 4 }; union { ReturnedValue (*indexedGetter)(Lookup *l, const ValueRef object, const ValueRef index); + void (*indexedSetter)(Lookup *l, const ValueRef object, const ValueRef index, const ValueRef v); ReturnedValue (*getter)(Lookup *l, const ValueRef object); ReturnedValue (*globalGetter)(Lookup *l, ExecutionContext *ctx); void (*setter)(Lookup *l, const ValueRef object, const ValueRef v); @@ -78,6 +79,10 @@ struct Lookup { static ReturnedValue indexedGetterFallback(Lookup *l, const ValueRef object, const ValueRef index); static ReturnedValue indexedGetterObjectInt(Lookup *l, const ValueRef object, const ValueRef index); + static void indexedSetterGeneric(Lookup *l, const ValueRef object, const ValueRef index, const ValueRef v); + static void indexedSetterFallback(Lookup *l, const ValueRef object, const ValueRef index, const ValueRef value); + static void indexedSetterObjectInt(Lookup *l, const ValueRef object, const ValueRef index, const ValueRef v); + static ReturnedValue getterGeneric(Lookup *l, const ValueRef object); static ReturnedValue getter0(Lookup *l, const ValueRef object); static ReturnedValue getter1(Lookup *l, const ValueRef object); diff --git a/src/qml/jsruntime/qv4object_p.h b/src/qml/jsruntime/qv4object_p.h index ca54388359..7541178dc1 100644 --- a/src/qml/jsruntime/qv4object_p.h +++ b/src/qml/jsruntime/qv4object_p.h @@ -206,7 +206,7 @@ public: void push_back(const ValueRef v); ArrayData::Type arrayType() const { - return arrayData ? (ArrayData::Type)arrayData->type : ArrayData::Simple; + return arrayData ? arrayData->type : ArrayData::Simple; } // ### remove me void setArrayType(ArrayData::Type t) { |