aboutsummaryrefslogtreecommitdiffstats
path: root/src/qml
diff options
context:
space:
mode:
authorLars Knoll <lars.knoll@digia.com>2013-10-13 21:03:44 +0200
committerThe Qt Project <gerrit-noreply@qt-project.org>2013-10-14 21:59:59 +0200
commit1be51cc3e7c9ca5256a52136d6fcc9c22c997625 (patch)
treee0c4f1feae828c4f04f0b8b63201627aa20cf43c /src/qml
parent668eca2b9343cf5d79dc1faa6c251595e2e84918 (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>
Diffstat (limited to 'src/qml')
-rw-r--r--src/qml/compiler/qv4isel_masm.cpp100
-rw-r--r--src/qml/compiler/qv4isel_masm_p.h1
-rw-r--r--src/qml/jsruntime/qv4managed.cpp1
-rw-r--r--src/qml/jsruntime/qv4managed_p.h28
-rw-r--r--src/qml/jsruntime/qv4object.cpp5
-rw-r--r--src/qml/jsruntime/qv4sequenceobject.cpp2
-rw-r--r--src/qml/qml/qqmllistwrapper.cpp1
-rw-r--r--src/qml/types/qqmldelegatemodel.cpp1
8 files changed, 118 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() {}