diff options
author | Lars Knoll <lars.knoll@digia.com> | 2013-10-13 21:03:44 +0200 |
---|---|---|
committer | The Qt Project <gerrit-noreply@qt-project.org> | 2013-10-14 21:59:59 +0200 |
commit | 1be51cc3e7c9ca5256a52136d6fcc9c22c997625 (patch) | |
tree | e0c4f1feae828c4f04f0b8b63201627aa20cf43c | |
parent | 668eca2b9343cf5d79dc1faa6c251595e2e84918 (diff) |
inline get_element calls
Inline calls to get_element if the base is an
object with a simple array structure, and the index
is an integer number.
Implemented for 64bit only for now, saves ~25% on crypto.js
Change-Id: I3e34a6409169d90d3937f62264707d52a6c2f9f7
Reviewed-by: Simon Hausmann <simon.hausmann@digia.com>
-rw-r--r-- | src/qml/compiler/qv4isel_masm.cpp | 100 | ||||
-rw-r--r-- | src/qml/compiler/qv4isel_masm_p.h | 1 | ||||
-rw-r--r-- | src/qml/jsruntime/qv4managed.cpp | 1 | ||||
-rw-r--r-- | src/qml/jsruntime/qv4managed_p.h | 28 | ||||
-rw-r--r-- | src/qml/jsruntime/qv4object.cpp | 5 | ||||
-rw-r--r-- | src/qml/jsruntime/qv4sequenceobject.cpp | 2 | ||||
-rw-r--r-- | src/qml/qml/qqmllistwrapper.cpp | 1 | ||||
-rw-r--r-- | src/qml/types/qqmldelegatemodel.cpp | 1 | ||||
-rw-r--r-- | src/quick/items/context2d/qquickcontext2d.cpp | 1 |
9 files changed, 119 insertions, 21 deletions
diff --git a/src/qml/compiler/qv4isel_masm.cpp b/src/qml/compiler/qv4isel_masm.cpp index 842b2611bb..1155322df2 100644 --- a/src/qml/compiler/qv4isel_masm.cpp +++ b/src/qml/compiler/qv4isel_masm.cpp @@ -671,7 +671,6 @@ void InstructionSelection::run(int functionIndex) << JSC::X86Registers::r15; #endif static const QVector<int> fpRegisters = QVector<int>() - << JSC::X86Registers::xmm1 << JSC::X86Registers::xmm2 << JSC::X86Registers::xmm3 << JSC::X86Registers::xmm4 @@ -1102,6 +1101,89 @@ void InstructionSelection::setProperty(V4IR::Expr *source, V4IR::Expr *targetBas void InstructionSelection::getElement(V4IR::Expr *base, V4IR::Expr *index, V4IR::Temp *target) { +#if 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 + Assembler::Address managedType(Assembler::ScratchRegister, qOffsetOf(QV4::Managed, flags)); + _as->load8(managedType, Assembler::ReturnValueRegister); + _as->and32(Assembler::TrustedImm32(QV4::Managed::SimpleArray), Assembler::ReturnValueRegister); + Assembler::Jump notSimple = _as->branch32(Assembler::Equal, Assembler::ReturnValueRegister, Assembler::TrustedImm32(0)); + + Assembler::Jump fallback; + if (tindex->kind == V4IR::Temp::PhysicalRegister) { + if (tindex->type == V4IR::SInt32Type) { + _as->move((Assembler::RegisterID) tindex->index, Assembler::ScratchRegister); + } else { + // double, convert and check if it's a int + _as->truncateDoubleToUint32((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); + _as->truncateDoubleToUint32(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); + } + + // get data, ScratchRegister holds index + addr = _as->loadTempAddress(Assembler::ReturnValueRegister, tbase); + _as->load64(addr, Assembler::ReturnValueRegister); + Address arrayDataLen(Assembler::ReturnValueRegister, qOffsetOf(Object, arrayDataLen)); + Assembler::Jump outOfRange = _as->branch32(Assembler::GreaterThanOrEqual, Assembler::ScratchRegister, arrayDataLen); + Address arrayData(Assembler::ReturnValueRegister, qOffsetOf(Object, arrayData)); + _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); + outOfRange.link(_as); + if (fallback.isSet()) + fallback.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)); } @@ -1313,8 +1395,8 @@ Assembler::Jump InstructionSelection::genInlineBinop(V4IR::AluOp oper, V4IR::Exp // register. switch (oper) { case V4IR::OpAdd: { - Assembler::FPRegisterID lReg = getFreeFPReg(rightSource, 1); - Assembler::FPRegisterID rReg = getFreeFPReg(leftSource, 3); + Assembler::FPRegisterID lReg = getFreeFPReg(rightSource, 2); + Assembler::FPRegisterID rReg = getFreeFPReg(leftSource, 4); Assembler::Jump leftIsNoDbl = genTryDoubleConversion(leftSource, lReg); Assembler::Jump rightIsNoDbl = genTryDoubleConversion(rightSource, rReg); @@ -1328,8 +1410,8 @@ Assembler::Jump InstructionSelection::genInlineBinop(V4IR::AluOp oper, V4IR::Exp rightIsNoDbl.link(_as); } break; case V4IR::OpMul: { - Assembler::FPRegisterID lReg = getFreeFPReg(rightSource, 1); - Assembler::FPRegisterID rReg = getFreeFPReg(leftSource, 3); + Assembler::FPRegisterID lReg = getFreeFPReg(rightSource, 2); + Assembler::FPRegisterID rReg = getFreeFPReg(leftSource, 4); Assembler::Jump leftIsNoDbl = genTryDoubleConversion(leftSource, lReg); Assembler::Jump rightIsNoDbl = genTryDoubleConversion(rightSource, rReg); @@ -1343,8 +1425,8 @@ Assembler::Jump InstructionSelection::genInlineBinop(V4IR::AluOp oper, V4IR::Exp rightIsNoDbl.link(_as); } break; case V4IR::OpSub: { - Assembler::FPRegisterID lReg = getFreeFPReg(rightSource, 1); - Assembler::FPRegisterID rReg = getFreeFPReg(leftSource, 3); + Assembler::FPRegisterID lReg = getFreeFPReg(rightSource, 2); + Assembler::FPRegisterID rReg = getFreeFPReg(leftSource, 4); Assembler::Jump leftIsNoDbl = genTryDoubleConversion(leftSource, lReg); Assembler::Jump rightIsNoDbl = genTryDoubleConversion(rightSource, rReg); @@ -1358,8 +1440,8 @@ Assembler::Jump InstructionSelection::genInlineBinop(V4IR::AluOp oper, V4IR::Exp rightIsNoDbl.link(_as); } break; case V4IR::OpDiv: { - Assembler::FPRegisterID lReg = getFreeFPReg(rightSource, 1); - Assembler::FPRegisterID rReg = getFreeFPReg(leftSource, 3); + Assembler::FPRegisterID lReg = getFreeFPReg(rightSource, 2); + Assembler::FPRegisterID rReg = getFreeFPReg(leftSource, 4); Assembler::Jump leftIsNoDbl = genTryDoubleConversion(leftSource, lReg); Assembler::Jump rightIsNoDbl = genTryDoubleConversion(rightSource, rReg); diff --git a/src/qml/compiler/qv4isel_masm_p.h b/src/qml/compiler/qv4isel_masm_p.h index fb990d0d53..4d1114e756 100644 --- a/src/qml/compiler/qv4isel_masm_p.h +++ b/src/qml/compiler/qv4isel_masm_p.h @@ -136,6 +136,7 @@ public: static const RegisterID ScratchRegister = JSC::X86Registers::r10; static const RegisterID IntegerOpRegister = JSC::X86Registers::eax; static const FPRegisterID FPGpr0 = JSC::X86Registers::xmm0; + static const FPRegisterID FPGpr1 = JSC::X86Registers::xmm1; static const int RegisterSize = 8; diff --git a/src/qml/jsruntime/qv4managed.cpp b/src/qml/jsruntime/qv4managed.cpp index 03608d2556..31bb8f2b94 100644 --- a/src/qml/jsruntime/qv4managed.cpp +++ b/src/qml/jsruntime/qv4managed.cpp @@ -84,6 +84,7 @@ void Managed::operator delete(void *ptr) Managed *m = static_cast<Managed *>(ptr); m->vtbl = 0; m->_data = 0; + m->markBit = 0; m->~Managed(); } diff --git a/src/qml/jsruntime/qv4managed_p.h b/src/qml/jsruntime/qv4managed_p.h index e77c724994..b4469c8048 100644 --- a/src/qml/jsruntime/qv4managed_p.h +++ b/src/qml/jsruntime/qv4managed_p.h @@ -159,7 +159,7 @@ private: protected: Managed(InternalClass *internal) : _data(0), vtbl(&static_vtbl), internalClass(internal) - { inUse = 1; extensible = 1; hasAccessorProperty = 0; } + { inUse = 1; extensible = 1; } public: void *operator new(size_t size, MemoryManager *mm); @@ -282,20 +282,24 @@ public: ReturnedValue asReturnedValue() { return Value::fromManaged(this).asReturnedValue(); } + enum { + SimpleArray = 1 + }; + union { uint _data; struct { - uint markBit : 1; - uint inUse : 1; - uint extensible : 1; // used by Object - uint isNonStrictArgumentsObject : 1; - uint needsActivation : 1; // used by FunctionObject - uint strictMode : 1; // used by FunctionObject - uint bindingKeyFlag : 1; - uint hasAccessorProperty : 1; - uint type : 8; - mutable uint subtype : 8; - uint unused : 8; + uchar markBit : 1; + uchar inUse : 1; + uchar extensible : 1; // used by Object + uchar isNonStrictArgumentsObject : 1; + uchar needsActivation : 1; // used by FunctionObject + uchar strictMode : 1; // used by FunctionObject + uchar bindingKeyFlag : 1; + uchar hasAccessorProperty : 1; + uchar type; + mutable uchar subtype; + uchar flags; }; }; diff --git a/src/qml/jsruntime/qv4object.cpp b/src/qml/jsruntime/qv4object.cpp index 0ccd8e6f62..795362e691 100644 --- a/src/qml/jsruntime/qv4object.cpp +++ b/src/qml/jsruntime/qv4object.cpp @@ -76,6 +76,7 @@ Object::Object(ExecutionEngine *engine) { vtbl = &static_vtbl; type = Type_Object; + flags = SimpleArray; memset(memberData, 0, sizeof(Property)*memberDataAlloc); } @@ -86,6 +87,7 @@ Object::Object(InternalClass *internalClass) { vtbl = &static_vtbl; type = Type_Object; + flags = SimpleArray; if (internalClass->size >= memberDataAlloc) { memberDataAlloc = internalClass->size; @@ -1078,6 +1080,7 @@ void Object::copyArrayData(Object *other) arrayOffset = 0; if (other->sparseArray) { + flags &= ~SimpleArray; sparseArray = new SparseArray(*other->sparseArray); arrayFreeList = other->arrayFreeList; } @@ -1226,6 +1229,7 @@ void Object::arraySort(ExecutionContext *context, ObjectRef thisObject, const Va void Object::initSparse() { if (!sparseArray) { + flags &= ~SimpleArray; sparseArray = new SparseArray; for (int i = 0; i < arrayDataLen; ++i) { if (!((arrayAttributes && arrayAttributes[i].isGeneric()) || arrayData[i].value.isEmpty())) { @@ -1302,6 +1306,7 @@ void Object::ensureArrayAttributes() if (arrayAttributes) return; + flags &= ~SimpleArray; arrayAttributes = new PropertyAttributes[arrayAlloc]; for (uint i = 0; i < arrayDataLen; ++i) arrayAttributes[i] = Attr_Data; diff --git a/src/qml/jsruntime/qv4sequenceobject.cpp b/src/qml/jsruntime/qv4sequenceobject.cpp index 05f51beecf..320646805b 100644 --- a/src/qml/jsruntime/qv4sequenceobject.cpp +++ b/src/qml/jsruntime/qv4sequenceobject.cpp @@ -175,6 +175,7 @@ public: { type = Type_QmlSequence; vtbl = &static_vtbl; + flags &= ~SimpleArray; QV4::Scope scope(engine); QV4::ScopedObject protectThis(scope, this); init(); @@ -188,6 +189,7 @@ public: { type = Type_QmlSequence; vtbl = &static_vtbl; + flags &= ~SimpleArray; QV4::Scope scope(engine); QV4::ScopedObject protectThis(scope, this); loadReference(); diff --git a/src/qml/qml/qqmllistwrapper.cpp b/src/qml/qml/qqmllistwrapper.cpp index c1ec5dc1c1..0364659ecc 100644 --- a/src/qml/qml/qqmllistwrapper.cpp +++ b/src/qml/qml/qqmllistwrapper.cpp @@ -57,6 +57,7 @@ QmlListWrapper::QmlListWrapper(QV8Engine *engine) v8(engine) { vtbl = &static_vtbl; + flags &= ~SimpleArray; } QmlListWrapper::~QmlListWrapper() diff --git a/src/qml/types/qqmldelegatemodel.cpp b/src/qml/types/qqmldelegatemodel.cpp index 4719fbe382..179dcfe373 100644 --- a/src/qml/types/qqmldelegatemodel.cpp +++ b/src/qml/types/qqmldelegatemodel.cpp @@ -3187,6 +3187,7 @@ public: : Object(engine) { vtbl = &static_vtbl; + flags &= ~SimpleArray; } virtual ~QQmlDelegateModelGroupChangeArray() {} diff --git a/src/quick/items/context2d/qquickcontext2d.cpp b/src/quick/items/context2d/qquickcontext2d.cpp index f7704306d3..b9d87309b4 100644 --- a/src/quick/items/context2d/qquickcontext2d.cpp +++ b/src/quick/items/context2d/qquickcontext2d.cpp @@ -871,6 +871,7 @@ struct QQuickJSContext2DPixelData : public QV4::Object : QV4::Object(engine) { vtbl = &static_vtbl; + flags &= ~SimpleArray; } static void destroy(QV4::Managed *that) { |