qtdeclarative/src/qml/jit/qv4isel_masm_p.h

287 lines
14 KiB
C++

/****************************************************************************
**
** Copyright (C) 2015 The Qt Company Ltd.
** Contact: http://www.qt.io/licensing/
**
** This file is part of the QtQml module of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL21$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see http://www.qt.io/terms-conditions. For further
** information use the contact form at http://www.qt.io/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 or version 3 as published by the Free
** Software Foundation and appearing in the file LICENSE.LGPLv21 and
** LICENSE.LGPLv3 included in the packaging of this file. Please review the
** following information to ensure the GNU Lesser General Public License
** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** As a special exception, The Qt Company gives you certain additional
** rights. These rights are described in The Qt Company LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** $QT_END_LICENSE$
**
****************************************************************************/
#ifndef QV4ISEL_MASM_P_H
#define QV4ISEL_MASM_P_H
#include "private/qv4global_p.h"
#include "private/qv4jsir_p.h"
#include "private/qv4isel_p.h"
#include "private/qv4isel_util_p.h"
#include "private/qv4value_p.h"
#include "private/qv4lookup_p.h"
#include <QtCore/QHash>
#include <QtCore/QStack>
#include <config.h>
#include <wtf/Vector.h>
#include "qv4assembler_p.h"
#if ENABLE(ASSEMBLER)
QT_BEGIN_NAMESPACE
namespace QV4 {
namespace JIT {
class Q_QML_EXPORT InstructionSelection:
protected IR::IRDecoder,
public EvalInstructionSelection
{
public:
InstructionSelection(QQmlEnginePrivate *qmlEngine, QV4::ExecutableAllocator *execAllocator, IR::Module *module, QV4::Compiler::JSUnitGenerator *jsGenerator);
~InstructionSelection();
virtual void run(int functionIndex);
const void *addConstantTable(QVector<QV4::Primitive> *values);
protected:
virtual QQmlRefPointer<QV4::CompiledData::CompilationUnit> backendCompileStep();
virtual void callBuiltinInvalid(IR::Name *func, IR::ExprList *args, IR::Expr *result);
virtual void callBuiltinTypeofMember(IR::Expr *base, const QString &name, IR::Expr *result);
virtual void callBuiltinTypeofSubscript(IR::Expr *base, IR::Expr *index, IR::Expr *result);
virtual void callBuiltinTypeofName(const QString &name, IR::Expr *result);
virtual void callBuiltinTypeofValue(IR::Expr *value, IR::Expr *result);
virtual void callBuiltinDeleteMember(IR::Expr *base, const QString &name, IR::Expr *result);
virtual void callBuiltinDeleteSubscript(IR::Expr *base, IR::Expr *index, IR::Expr *result);
virtual void callBuiltinDeleteName(const QString &name, IR::Expr *result);
virtual void callBuiltinDeleteValue(IR::Expr *result);
virtual void callBuiltinThrow(IR::Expr *arg);
virtual void callBuiltinReThrow();
virtual void callBuiltinUnwindException(IR::Expr *);
virtual void callBuiltinPushCatchScope(const QString &exceptionName);
virtual void callBuiltinForeachIteratorObject(IR::Expr *arg, IR::Expr *result);
virtual void callBuiltinForeachNextPropertyname(IR::Expr *arg, IR::Expr *result);
virtual void callBuiltinPushWithScope(IR::Expr *arg);
virtual void callBuiltinPopScope();
virtual void callBuiltinDeclareVar(bool deletable, const QString &name);
virtual void callBuiltinDefineArray(IR::Expr *result, IR::ExprList *args);
virtual void callBuiltinDefineObjectLiteral(IR::Expr *result, int keyValuePairCount, IR::ExprList *keyValuePairs, IR::ExprList *arrayEntries, bool needSparseArray);
virtual void callBuiltinSetupArgumentObject(IR::Expr *result);
virtual void callBuiltinConvertThisToObject();
virtual void callValue(IR::Expr *value, IR::ExprList *args, IR::Expr *result);
virtual void callQmlContextProperty(IR::Expr *base, IR::Member::MemberKind kind, int propertyIndex, IR::ExprList *args, IR::Expr *result);
virtual void callProperty(IR::Expr *base, const QString &name, IR::ExprList *args, IR::Expr *result);
virtual void callSubscript(IR::Expr *base, IR::Expr *index, IR::ExprList *args, IR::Expr *result);
virtual void convertType(IR::Expr *source, IR::Expr *target);
virtual void loadThisObject(IR::Expr *temp);
virtual void loadQmlContext(IR::Expr *target);
virtual void loadQmlIdArray(IR::Expr *target);
virtual void loadQmlImportedScripts(IR::Expr *target);
virtual void loadQmlContextObject(IR::Expr *target);
virtual void loadQmlSingleton(const QString &name, IR::Expr *target);
virtual void loadConst(IR::Const *sourceConst, IR::Expr *target);
virtual void loadString(const QString &str, IR::Expr *target);
virtual void loadRegexp(IR::RegExp *sourceRegexp, IR::Expr *target);
virtual void getActivationProperty(const IR::Name *name, IR::Expr *target);
virtual void setActivationProperty(IR::Expr *source, const QString &targetName);
virtual void initClosure(IR::Closure *closure, IR::Expr *target);
virtual void getProperty(IR::Expr *base, const QString &name, IR::Expr *target);
virtual void getQmlContextProperty(IR::Expr *source, IR::Member::MemberKind kind, int index, IR::Expr *target);
virtual void getQObjectProperty(IR::Expr *base, int propertyIndex, bool captureRequired, bool isSingleton, int attachedPropertiesId, IR::Expr *target);
virtual void setProperty(IR::Expr *source, IR::Expr *targetBase, const QString &targetName);
virtual void setQmlContextProperty(IR::Expr *source, IR::Expr *targetBase, IR::Member::MemberKind kind, int propertyIndex);
virtual void setQObjectProperty(IR::Expr *source, IR::Expr *targetBase, int propertyIndex);
virtual void getElement(IR::Expr *base, IR::Expr *index, IR::Expr *target);
virtual void setElement(IR::Expr *source, IR::Expr *targetBase, IR::Expr *targetIndex);
virtual void copyValue(IR::Expr *source, IR::Expr *target);
virtual void swapValues(IR::Expr *source, IR::Expr *target);
virtual void unop(IR::AluOp oper, IR::Expr *sourceTemp, IR::Expr *target);
virtual void binop(IR::AluOp oper, IR::Expr *leftSource, IR::Expr *rightSource, IR::Expr *target);
typedef Assembler::Address Address;
typedef Assembler::Pointer Pointer;
#if !defined(ARGUMENTS_IN_REGISTERS)
Address addressForArgument(int index) const
{
// StackFrameRegister points to its old value on the stack, and above
// it we have the return address, hence the need to step over two
// values before reaching the first argument.
return Address(Assembler::StackFrameRegister, (index + 2) * sizeof(void*));
}
#endif
Pointer baseAddressForCallArguments()
{
return _as->stackLayout().argumentAddressForCall(0);
}
Pointer baseAddressForCallData()
{
return _as->stackLayout().callDataAddress();
}
virtual void constructActivationProperty(IR::Name *func, IR::ExprList *args, IR::Expr *result);
virtual void constructProperty(IR::Expr *base, const QString &name, IR::ExprList *args, IR::Expr*result);
virtual void constructValue(IR::Expr *value, IR::ExprList *args, IR::Expr *result);
virtual void visitJump(IR::Jump *);
virtual void visitCJump(IR::CJump *);
virtual void visitRet(IR::Ret *);
bool visitCJumpDouble(IR::AluOp op, IR::Expr *left, IR::Expr *right,
IR::BasicBlock *iftrue, IR::BasicBlock *iffalse);
bool visitCJumpSInt32(IR::AluOp op, IR::Expr *left, IR::Expr *right,
IR::BasicBlock *iftrue, IR::BasicBlock *iffalse);
void visitCJumpStrict(IR::Binop *binop, IR::BasicBlock *trueBlock, IR::BasicBlock *falseBlock);
bool visitCJumpStrictNullUndefined(IR::Type nullOrUndef, IR::Binop *binop,
IR::BasicBlock *trueBlock, IR::BasicBlock *falseBlock);
bool visitCJumpStrictBool(IR::Binop *binop, IR::BasicBlock *trueBlock, IR::BasicBlock *falseBlock);
bool visitCJumpNullUndefined(IR::Type nullOrUndef, IR::Binop *binop,
IR::BasicBlock *trueBlock, IR::BasicBlock *falseBlock);
void visitCJumpEqual(IR::Binop *binop, IR::BasicBlock *trueBlock, IR::BasicBlock *falseBlock);
private:
void convertTypeSlowPath(IR::Expr *source, IR::Expr *target);
void convertTypeToDouble(IR::Expr *source, IR::Expr *target);
void convertTypeToBool(IR::Expr *source, IR::Expr *target);
void convertTypeToSInt32(IR::Expr *source, IR::Expr *target);
void convertTypeToUInt32(IR::Expr *source, IR::Expr *target);
void convertIntToDouble(IR::Expr *source, IR::Expr *target)
{
if (IR::Temp *targetTemp = target->asTemp()) {
if (targetTemp->kind == IR::Temp::PhysicalRegister) {
if (IR::Temp *sourceTemp = source->asTemp()) {
if (sourceTemp->kind == IR::Temp::PhysicalRegister) {
_as->convertInt32ToDouble((Assembler::RegisterID) sourceTemp->index,
(Assembler::FPRegisterID) targetTemp->index);
} else {
_as->convertInt32ToDouble(_as->loadAddress(Assembler::ReturnValueRegister, sourceTemp),
(Assembler::FPRegisterID) targetTemp->index);
}
} else {
_as->convertInt32ToDouble(_as->toInt32Register(source, Assembler::ScratchRegister),
(Assembler::FPRegisterID) targetTemp->index);
}
return;
}
}
_as->convertInt32ToDouble(_as->toInt32Register(source, Assembler::ScratchRegister),
Assembler::FPGpr0);
_as->storeDouble(Assembler::FPGpr0, _as->loadAddress(Assembler::ReturnValueRegister, target));
}
void convertUIntToDouble(IR::Expr *source, IR::Expr *target)
{
Assembler::RegisterID tmpReg = Assembler::ScratchRegister;
Assembler::RegisterID reg = _as->toInt32Register(source, tmpReg);
if (IR::Temp *targetTemp = target->asTemp()) {
if (targetTemp->kind == IR::Temp::PhysicalRegister) {
_as->convertUInt32ToDouble(reg, (Assembler::FPRegisterID) targetTemp->index, tmpReg);
return;
}
}
_as->convertUInt32ToDouble(_as->toUInt32Register(source, tmpReg),
Assembler::FPGpr0, tmpReg);
_as->storeDouble(Assembler::FPGpr0, _as->loadAddress(tmpReg, target));
}
void convertIntToBool(IR::Expr *source, IR::Expr *target)
{
Assembler::RegisterID reg = Assembler::ScratchRegister;
if (IR::Temp *targetTemp = target->asTemp())
if (targetTemp->kind == IR::Temp::PhysicalRegister)
reg = (Assembler::RegisterID) targetTemp->index;
_as->move(_as->toInt32Register(source, reg), reg);
_as->compare32(Assembler::NotEqual, reg, Assembler::TrustedImm32(0), reg);
_as->storeBool(reg, target);
}
#define isel_stringIfyx(s) #s
#define isel_stringIfy(s) isel_stringIfyx(s)
#define generateFunctionCall(t, function, ...) \
_as->generateFunctionCallImp(t, isel_stringIfy(function), function, __VA_ARGS__)
int prepareVariableArguments(IR::ExprList* args);
int prepareCallData(IR::ExprList* args, IR::Expr *thisObject);
void calculateRegistersToSave(const RegisterInformation &used);
template <typename Retval, typename Arg1, typename Arg2, typename Arg3>
void generateLookupCall(Retval retval, uint index, uint getterSetterOffset, Arg1 arg1, Arg2 arg2, Arg3 arg3)
{
// Note: using the return value register is intentional: for ABIs where the first parameter
// goes into the same register as the return value (currently only ARM), the prepareCall
// will combine loading the looupAddr into the register and calculating the indirect call
// address.
Assembler::Pointer lookupAddr(Assembler::ReturnValueRegister, index * sizeof(QV4::Lookup));
_as->generateFunctionCallImp(retval, "lookup getter/setter",
LookupCall(lookupAddr, getterSetterOffset), lookupAddr,
arg1, arg2, arg3);
}
template <typename Retval, typename Arg1, typename Arg2>
void generateLookupCall(Retval retval, uint index, uint getterSetterOffset, Arg1 arg1, Arg2 arg2)
{
generateLookupCall(retval, index, getterSetterOffset, arg1, arg2, Assembler::VoidType());
}
IR::BasicBlock *_block;
QSet<IR::Jump *> _removableJumps;
Assembler* _as;
QScopedPointer<CompilationUnit> compilationUnit;
QQmlEnginePrivate *qmlEngine;
RegisterInformation regularRegistersToSave;
RegisterInformation fpRegistersToSave;
};
class Q_QML_EXPORT ISelFactory: public EvalISelFactory
{
public:
virtual ~ISelFactory() {}
virtual EvalInstructionSelection *create(QQmlEnginePrivate *qmlEngine, QV4::ExecutableAllocator *execAllocator, IR::Module *module, QV4::Compiler::JSUnitGenerator *jsGenerator)
{ return new InstructionSelection(qmlEngine, execAllocator, module, jsGenerator); }
virtual bool jitCompileRegexps() const
{ return true; }
};
} // end of namespace JIT
} // end of namespace QV4
QT_END_NAMESPACE
#endif // ENABLE(ASSEMBLER)
#endif // QV4ISEL_MASM_P_H