aboutsummaryrefslogtreecommitdiffstats
path: root/src/v4/qv4isel_masm_p.h
diff options
context:
space:
mode:
Diffstat (limited to 'src/v4/qv4isel_masm_p.h')
-rw-r--r--src/v4/qv4isel_masm_p.h798
1 files changed, 798 insertions, 0 deletions
diff --git a/src/v4/qv4isel_masm_p.h b/src/v4/qv4isel_masm_p.h
new file mode 100644
index 0000000000..de0971f0cb
--- /dev/null
+++ b/src/v4/qv4isel_masm_p.h
@@ -0,0 +1,798 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the V4VM module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** 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 Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/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 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+#ifndef QV4ISEL_MASM_P_H
+#define QV4ISEL_MASM_P_H
+
+#include "qv4global.h"
+#include "qv4ir_p.h"
+#include "qv4isel_p.h"
+#include "qv4isel_util_p.h"
+#include "qv4object.h"
+#include "qmljs_runtime.h"
+
+#include <QtCore/QHash>
+#include <config.h>
+#include <wtf/Vector.h>
+#include <assembler/MacroAssembler.h>
+
+namespace QQmlJS {
+namespace MASM {
+
+class Assembler : public JSC::MacroAssembler
+{
+public:
+ Assembler(IR::Function* function);
+#if CPU(X86)
+
+#undef VALUE_FITS_IN_REGISTER
+
+ static const RegisterID StackFrameRegister = JSC::X86Registers::ebp;
+ static const RegisterID StackPointerRegister = JSC::X86Registers::esp;
+ static const RegisterID ContextRegister = JSC::X86Registers::esi;
+ static const RegisterID ReturnValueRegister = JSC::X86Registers::eax;
+ static const RegisterID ScratchRegister = JSC::X86Registers::ecx;
+ static const RegisterID CalleeSavedFirstRegister = ScratchRegister;
+ static const RegisterID CalleeSavedLastRegister = ScratchRegister;
+ static const RegisterID IntegerOpRegister = JSC::X86Registers::eax;
+ static const FPRegisterID FPGpr0 = JSC::X86Registers::xmm0;
+
+ static const int RegisterSize = 4;
+
+ static const int RegisterArgumentCount = 0;
+ static RegisterID registerForArgument(int)
+ {
+ assert(false);
+ // Not reached.
+ return JSC::X86Registers::eax;
+ }
+#elif CPU(X86_64)
+
+#define VALUE_FITS_IN_REGISTER
+
+ static const RegisterID StackFrameRegister = JSC::X86Registers::ebp;
+ static const RegisterID StackPointerRegister = JSC::X86Registers::esp;
+ static const RegisterID ContextRegister = JSC::X86Registers::r14;
+ static const RegisterID ReturnValueRegister = JSC::X86Registers::eax;
+ static const RegisterID ScratchRegister = JSC::X86Registers::r10;
+ static const RegisterID IntegerOpRegister = JSC::X86Registers::eax;
+ static const FPRegisterID FPGpr0 = JSC::X86Registers::xmm0;
+
+ static const int RegisterSize = 8;
+
+ static const int RegisterArgumentCount = 6;
+ static RegisterID registerForArgument(int index)
+ {
+ static RegisterID regs[RegisterArgumentCount] = {
+ JSC::X86Registers::edi,
+ JSC::X86Registers::esi,
+ JSC::X86Registers::edx,
+ JSC::X86Registers::ecx,
+ JSC::X86Registers::r8,
+ JSC::X86Registers::r9
+ };
+ assert(index >= 0 && index < RegisterArgumentCount);
+ return regs[index];
+ };
+#elif CPU(ARM)
+
+#undef VALUE_FITS_IN_REGISTER
+
+ static const RegisterID StackFrameRegister = JSC::ARMRegisters::r4;
+ static const RegisterID StackPointerRegister = JSC::ARMRegisters::sp;
+ static const RegisterID ContextRegister = JSC::ARMRegisters::r5;
+ static const RegisterID ReturnValueRegister = JSC::ARMRegisters::r0;
+ static const RegisterID ScratchRegister = JSC::ARMRegisters::r6;
+ static const RegisterID CalleeSavedFirstRegister = JSC::ARMRegisters::r4;
+ static const RegisterID CalleeSavedLastRegister = JSC::ARMRegisters::r11;
+ static const RegisterID IntegerOpRegister = JSC::X86Registers::r0;
+ static const FPRegisterID FPGpr0 = JSC::ARMRegisters::d0;
+
+ static const int RegisterSize = 4;
+
+ static const RegisterID RegisterArgument1 = JSC::ARMRegisters::r0;
+ static const RegisterID RegisterArgument2 = JSC::ARMRegisters::r1;
+ static const RegisterID RegisterArgument3 = JSC::ARMRegisters::r2;
+ static const RegisterID RegisterArgument4 = JSC::ARMRegisters::r3;
+
+ static const int RegisterArgumentCount = 4;
+ static RegisterID registerForArgument(int index)
+ {
+ assert(index >= 0 && index < RegisterArgumentCount);
+ return static_cast<RegisterID>(JSC::ARMRegisters::r0 + index);
+ };
+#else
+#error Argh.
+#endif
+
+ // Explicit type to allow distinguishing between
+ // pushing an address itself or the value it points
+ // to onto the stack when calling functions.
+ struct Pointer : public Address
+ {
+ explicit Pointer(const Address& addr)
+ : Address(addr)
+ {}
+ explicit Pointer(RegisterID reg, int32_t offset)
+ : Address(reg, offset)
+ {}
+ };
+
+ struct VoidType {};
+ static const VoidType Void;
+
+
+ typedef JSC::FunctionPtr FunctionPtr;
+
+ struct CallToLink {
+ Call call;
+ FunctionPtr externalFunction;
+ const char* functionName;
+ };
+ struct PointerToValue {
+ PointerToValue(IR::Temp *value) : value(value) {}
+ IR::Temp *value;
+ };
+
+ void callAbsolute(const char* functionName, FunctionPtr function) {
+ CallToLink ctl;
+ ctl.call = call();
+ ctl.externalFunction = function;
+ ctl.functionName = functionName;
+ _callsToLink.append(ctl);
+ }
+
+ void registerBlock(IR::BasicBlock*);
+ void jumpToBlock(IR::BasicBlock* current, IR::BasicBlock *target);
+ void addPatch(IR::BasicBlock* targetBlock, Jump targetJump);
+
+ Pointer loadTempAddress(RegisterID reg, IR::Temp *t);
+
+ void loadArgument(RegisterID source, RegisterID dest)
+ {
+ move(source, dest);
+ }
+
+ void loadArgument(TrustedImmPtr ptr, RegisterID dest)
+ {
+ move(TrustedImmPtr(ptr), dest);
+ }
+
+ void loadArgument(const Pointer& ptr, RegisterID dest)
+ {
+ addPtr(TrustedImm32(ptr.offset), ptr.base, dest);
+ }
+
+ void loadArgument(PointerToValue temp, RegisterID dest)
+ {
+ assert(temp.value);
+
+ Pointer addr = loadTempAddress(dest, temp.value);
+ loadArgument(addr, dest);
+ }
+
+#ifdef VALUE_FITS_IN_REGISTER
+ void loadArgument(IR::Temp* temp, RegisterID dest)
+ {
+ if (!temp) {
+ VM::Value undefined = VM::Value::undefinedValue();
+ move(TrustedImm64(undefined.val), dest);
+ } else {
+ Pointer addr = loadTempAddress(dest, temp);
+ load64(addr, dest);
+ }
+ }
+
+ void loadArgument(IR::Const* c, RegisterID dest)
+ {
+ VM::Value v = convertToValue(c);
+ move(TrustedImm64(v.val), dest);
+ }
+
+ void loadArgument(IR::Expr* expr, RegisterID dest)
+ {
+ if (!expr) {
+ VM::Value undefined = VM::Value::undefinedValue();
+ move(TrustedImm64(undefined.val), dest);
+ } else if (expr->asTemp()){
+ loadArgument(expr->asTemp(), dest);
+ } else if (expr->asConst()) {
+ loadArgument(expr->asConst(), dest);
+ } else {
+ assert(!"unimplemented expression type in loadArgument");
+ }
+ }
+#else
+ void loadArgument(IR::Expr*, RegisterID)
+ {
+ assert(!"unimplemented: expression in loadArgument");
+ }
+#endif
+
+ void loadArgument(VM::String* string, RegisterID dest)
+ {
+ loadArgument(TrustedImmPtr(string), dest);
+ }
+
+ void loadArgument(TrustedImm32 imm32, RegisterID dest)
+ {
+ xorPtr(dest, dest);
+ if (imm32.m_value)
+ move(imm32, dest);
+ }
+
+ void storeArgument(RegisterID src, IR::Temp *temp)
+ {
+ if (temp) {
+ Pointer addr = loadTempAddress(ScratchRegister, temp);
+#ifdef VALUE_FITS_IN_REGISTER
+ store64(src, addr);
+#else
+ // If the value doesn't fit into a register, then the
+ // register contains the address to where the argument
+ // (return value) is stored. Copy it from there.
+ copyValue(addr, Pointer(src, 0));
+#endif
+ }
+ }
+
+#ifdef VALUE_FITS_IN_REGISTER
+ void storeArgument(RegisterID src, const Pointer &dest)
+ {
+ store64(src, dest);
+ }
+#endif
+
+ void storeArgument(RegisterID src, RegisterID dest)
+ {
+ move(src, dest);
+ }
+
+ void storeArgument(RegisterID, VoidType)
+ {
+ }
+
+ using JSC::MacroAssembler::push;
+
+ void push(const Pointer& ptr)
+ {
+ addPtr(TrustedImm32(ptr.offset), ptr.base, ScratchRegister);
+ push(ScratchRegister);
+ }
+
+ void push(VM::Value value)
+ {
+#ifdef VALUE_FITS_IN_REGISTER
+ move(TrustedImm64(value.val), ScratchRegister);
+ push(ScratchRegister);
+#else
+ move(TrustedImm32(value.tag), ScratchRegister);
+ push(ScratchRegister);
+ move(TrustedImm32(value.int_32), ScratchRegister);
+ push(ScratchRegister);
+#endif
+ }
+
+ void push(PointerToValue temp)
+ {
+ assert (temp.value);
+
+ Pointer ptr = loadTempAddress(ScratchRegister, temp.value);
+ push(ptr);
+ }
+
+ void push(IR::Temp* temp)
+ {
+ if (temp) {
+ Address addr = loadTempAddress(ScratchRegister, temp);
+ addr.offset += 4;
+ push(addr);
+ addr.offset -= 4;
+ push(addr);
+ } else {
+ VM::Value undefined = VM::Value::undefinedValue();
+ push(undefined);
+ }
+ }
+
+ void push(IR::Const* c)
+ {
+ VM::Value v = convertToValue(c);
+ push(v);
+ }
+
+ void push(IR::Expr* e)
+ {
+ if (!e) {
+ VM::Value undefined = VM::Value::undefinedValue();
+ push(undefined);
+ } else if (IR::Const *c = e->asConst())
+ push(c);
+ else if (IR::Temp *t = e->asTemp()) {
+ push(t);
+ } else {
+ assert(!"Trying to push an expression that is not a Temp or Const");
+ }
+ }
+
+ void push(TrustedImmPtr ptr)
+ {
+ move(TrustedImmPtr(ptr), ScratchRegister);
+ push(ScratchRegister);
+ }
+
+ void push(VM::String* name)
+ {
+ push(TrustedImmPtr(name));
+ }
+
+ using JSC::MacroAssembler::loadDouble;
+ void loadDouble(IR::Temp* temp, FPRegisterID dest)
+ {
+ Pointer ptr = loadTempAddress(ScratchRegister, temp);
+ loadDouble(ptr, dest);
+ }
+
+ using JSC::MacroAssembler::storeDouble;
+ void storeDouble(FPRegisterID source, IR::Temp* temp)
+ {
+ Pointer ptr = loadTempAddress(ScratchRegister, temp);
+ storeDouble(source, ptr);
+ }
+
+ template <typename Result, typename Source>
+ void copyValue(Result result, Source source);
+
+ void storeValue(VM::Value value, Address destination)
+ {
+#ifdef VALUE_FITS_IN_REGISTER
+ store64(TrustedImm64(value.val), destination);
+#else
+ store32(TrustedImm32(value.int_32), destination);
+ destination.offset += 4;
+ store32(TrustedImm32(value.tag), destination);
+#endif
+ }
+
+ void storeValue(VM::Value value, IR::Temp* temp);
+
+ void enterStandardStackFrame(int locals);
+ void leaveStandardStackFrame(int locals);
+
+ void callFunctionPrologue()
+ {
+#if CPU(X86)
+ // Callee might clobber it :(
+ push(ContextRegister);
+#endif
+ }
+ void callFunctionEpilogue()
+ {
+#if CPU(X86)
+ pop(ContextRegister);
+#endif
+ }
+
+ static inline int sizeOfArgument(VoidType)
+ { return 0; }
+ static inline int sizeOfArgument(RegisterID)
+ { return RegisterSize; }
+ static inline int sizeOfArgument(IR::Temp*)
+ { return 8; } // Size of value
+ static inline int sizeOfArgument(IR::Expr*)
+ { return 8; } // Size of value
+ static inline int sizeOfArgument(const Pointer&)
+ { return sizeof(void*); }
+ static inline int sizeOfArgument(VM::String* string)
+ { return sizeof(string); }
+ static inline int sizeOfArgument(const PointerToValue &)
+ { return sizeof(void *); }
+ static inline int sizeOfArgument(TrustedImmPtr)
+ { return sizeof(void*); }
+ static inline int sizeOfArgument(TrustedImm32)
+ { return 4; }
+
+ struct ArgumentLoader
+ {
+ ArgumentLoader(Assembler* _assembler, int totalNumberOfArguments)
+ : assembler(_assembler)
+ , stackSpaceForArguments(0)
+ , currentRegisterIndex(qMin(totalNumberOfArguments - 1, RegisterArgumentCount - 1))
+ {
+ }
+
+ template <typename T>
+ void load(T argument)
+ {
+ if (currentRegisterIndex >= 0) {
+ assembler->loadArgument(argument, registerForArgument(currentRegisterIndex));
+ --currentRegisterIndex;
+ } else {
+ assembler->push(argument);
+ stackSpaceForArguments += sizeOfArgument(argument);
+ }
+ }
+
+ void load(VoidType)
+ {
+ if (currentRegisterIndex >= 0)
+ --currentRegisterIndex;
+ }
+
+ Assembler *assembler;
+ int stackSpaceForArguments;
+ int currentRegisterIndex;
+ };
+
+ template <typename ArgRet, typename Arg1, typename Arg2, typename Arg3, typename Arg4, typename Arg5>
+ void generateFunctionCallImp(ArgRet r, const char* functionName, FunctionPtr function, Arg1 arg1, Arg2 arg2, Arg3 arg3, Arg4 arg4, Arg5 arg5)
+ {
+ callFunctionPrologue();
+
+ int totalNumberOfArgs = 5;
+
+ // If necessary reserve space for the return value on the stack and
+ // pass the pointer to it as the first hidden parameter.
+ bool returnValueOnStack = false;
+ int sizeOfReturnValueOnStack = sizeOfArgument(r);
+ if (sizeOfReturnValueOnStack > RegisterSize) {
+ sub32(TrustedImm32(sizeOfReturnValueOnStack), StackPointerRegister);
+ ++totalNumberOfArgs;
+ returnValueOnStack = true;
+ }
+
+ ArgumentLoader l(this, totalNumberOfArgs);
+ l.load(arg5);
+ l.load(arg4);
+ l.load(arg3);
+ l.load(arg2);
+ l.load(arg1);
+
+ if (returnValueOnStack) {
+ // Load address of return value
+ l.load(Pointer(StackPointerRegister, l.stackSpaceForArguments));
+ }
+
+ callAbsolute(functionName, function);
+
+ int stackSizeToCorrect = l.stackSpaceForArguments;
+ if (returnValueOnStack) {
+ stackSizeToCorrect -= sizeof(void*); // Callee removed the hidden argument (address of return value)
+ stackSizeToCorrect += sizeOfReturnValueOnStack;
+ }
+
+ storeArgument(ReturnValueRegister, r);
+
+ if (stackSizeToCorrect)
+ add32(TrustedImm32(stackSizeToCorrect), StackPointerRegister);
+
+ callFunctionEpilogue();
+ }
+
+ template <typename ArgRet, typename Arg1, typename Arg2, typename Arg3, typename Arg4>
+ void generateFunctionCallImp(ArgRet r, const char* functionName, FunctionPtr function, Arg1 arg1, Arg2 arg2, Arg3 arg3, Arg4 arg4)
+ {
+ generateFunctionCallImp(r, functionName, function, arg1, arg2, arg3, arg4, VoidType());
+ }
+
+ template <typename ArgRet, typename Arg1, typename Arg2, typename Arg3>
+ void generateFunctionCallImp(ArgRet r, const char* functionName, FunctionPtr function, Arg1 arg1, Arg2 arg2, Arg3 arg3)
+ {
+ generateFunctionCallImp(r, functionName, function, arg1, arg2, arg3, VoidType(), VoidType());
+ }
+
+ template <typename ArgRet, typename Arg1, typename Arg2>
+ void generateFunctionCallImp(ArgRet r, const char* functionName, FunctionPtr function, Arg1 arg1, Arg2 arg2)
+ {
+ generateFunctionCallImp(r, functionName, function, arg1, arg2, VoidType(), VoidType(), VoidType());
+ }
+
+ template <typename ArgRet, typename Arg1>
+ void generateFunctionCallImp(ArgRet r, const char* functionName, FunctionPtr function, Arg1 arg1)
+ {
+ generateFunctionCallImp(r, functionName, function, arg1, VoidType(), VoidType(), VoidType(), VoidType());
+ }
+
+ typedef Jump (Assembler::*MemRegBinOp)(Address, RegisterID);
+ typedef Jump (Assembler::*ImmRegBinOp)(TrustedImm32, RegisterID);
+
+ struct BinaryOperationInfo {
+ const char *name;
+ VM::Value (*fallbackImplementation)(const VM::Value, const VM::Value, VM::ExecutionContext *);
+ MemRegBinOp inlineMemRegOp;
+ ImmRegBinOp inlineImmRegOp;
+ };
+
+ static const BinaryOperationInfo binaryOperations[QQmlJS::IR::LastAluOp + 1];
+
+ void generateBinOp(IR::AluOp operation, IR::Temp* target, IR::Expr* left, IR::Expr* right);
+
+ Jump inline_add32(Address addr, RegisterID reg)
+ {
+ return branchAdd32(Overflow, addr, reg);
+ }
+
+ Jump inline_add32(TrustedImm32 imm, RegisterID reg)
+ {
+ return branchAdd32(Overflow, imm, reg);
+ }
+
+ Jump inline_sub32(Address addr, RegisterID reg)
+ {
+ return branchSub32(Overflow, addr, reg);
+ }
+
+ Jump inline_sub32(TrustedImm32 imm, RegisterID reg)
+ {
+ return branchSub32(Overflow, imm, reg);
+ }
+
+ Jump inline_mul32(Address addr, RegisterID reg)
+ {
+ return branchMul32(Overflow, addr, reg);
+ }
+
+ Jump inline_mul32(TrustedImm32 imm, RegisterID reg)
+ {
+ return branchMul32(Overflow, imm, reg, reg);
+ }
+
+ Jump inline_shl32(Address addr, RegisterID reg)
+ {
+ load32(addr, ScratchRegister);
+ and32(TrustedImm32(0x1f), ScratchRegister);
+ lshift32(ScratchRegister, reg);
+ return Jump();
+ }
+
+ Jump inline_shl32(TrustedImm32 imm, RegisterID reg)
+ {
+ imm.m_value &= 0x1f;
+ lshift32(imm, reg);
+ return Jump();
+ }
+
+ Jump inline_shr32(Address addr, RegisterID reg)
+ {
+ load32(addr, ScratchRegister);
+ and32(TrustedImm32(0x1f), ScratchRegister);
+ rshift32(ScratchRegister, reg);
+ return Jump();
+ }
+
+ Jump inline_shr32(TrustedImm32 imm, RegisterID reg)
+ {
+ imm.m_value &= 0x1f;
+ rshift32(imm, reg);
+ return Jump();
+ }
+
+ Jump inline_ushr32(Address addr, RegisterID reg)
+ {
+ load32(addr, ScratchRegister);
+ and32(TrustedImm32(0x1f), ScratchRegister);
+ urshift32(ScratchRegister, reg);
+ return Jump();
+ }
+
+ Jump inline_ushr32(TrustedImm32 imm, RegisterID reg)
+ {
+ imm.m_value &= 0x1f;
+ urshift32(imm, reg);
+ return Jump();
+ }
+
+ Jump inline_and32(Address addr, RegisterID reg)
+ {
+ and32(addr, reg);
+ return Jump();
+ }
+
+ Jump inline_and32(TrustedImm32 imm, RegisterID reg)
+ {
+ and32(imm, reg);
+ return Jump();
+ }
+
+ Jump inline_or32(Address addr, RegisterID reg)
+ {
+ or32(addr, reg);
+ return Jump();
+ }
+
+ Jump inline_or32(TrustedImm32 imm, RegisterID reg)
+ {
+ or32(imm, reg);
+ return Jump();
+ }
+
+ Jump inline_xor32(Address addr, RegisterID reg)
+ {
+ xor32(addr, reg);
+ return Jump();
+ }
+
+ Jump inline_xor32(TrustedImm32 imm, RegisterID reg)
+ {
+ xor32(imm, reg);
+ return Jump();
+ }
+
+ void link(VM::Function *vmFunc);
+
+private:
+ IR::Function* _function;
+ QHash<IR::BasicBlock *, Label> _addrs;
+ QHash<IR::BasicBlock *, QVector<Jump> > _patches;
+ QList<CallToLink> _callsToLink;
+};
+
+class Q_V4_EXPORT InstructionSelection:
+ protected IR::InstructionSelection,
+ public EvalInstructionSelection
+{
+public:
+ InstructionSelection(VM::ExecutionEngine *engine, IR::Module *module);
+ ~InstructionSelection();
+
+ virtual void run(VM::Function *vmFunction, IR::Function *function);
+
+protected:
+ virtual void callBuiltinInvalid(IR::Name *func, IR::ExprList *args, IR::Temp *result);
+ virtual void callBuiltinTypeofMember(IR::Temp *base, const QString &name, IR::Temp *result);
+ virtual void callBuiltinTypeofSubscript(IR::Temp *base, IR::Temp *index, IR::Temp *result);
+ virtual void callBuiltinTypeofName(const QString &name, IR::Temp *result);
+ virtual void callBuiltinTypeofValue(IR::Temp *value, IR::Temp *result);
+ virtual void callBuiltinDeleteMember(IR::Temp *base, const QString &name, IR::Temp *result);
+ virtual void callBuiltinDeleteSubscript(IR::Temp *base, IR::Temp *index, IR::Temp *result);
+ virtual void callBuiltinDeleteName(const QString &name, IR::Temp *result);
+ virtual void callBuiltinDeleteValue(IR::Temp *result);
+ virtual void callBuiltinPostDecrementMember(IR::Temp *base, const QString &name, IR::Temp *result);
+ virtual void callBuiltinPostDecrementSubscript(IR::Temp *base, IR::Temp *index, IR::Temp *result);
+ virtual void callBuiltinPostDecrementName(const QString &name, IR::Temp *result);
+ virtual void callBuiltinPostDecrementValue(IR::Temp *value, IR::Temp *result);
+ virtual void callBuiltinPostIncrementMember(IR::Temp *base, const QString &name, IR::Temp *result);
+ virtual void callBuiltinPostIncrementSubscript(IR::Temp *base, IR::Temp *index, IR::Temp *result);
+ virtual void callBuiltinPostIncrementName(const QString &name, IR::Temp *result);
+ virtual void callBuiltinPostIncrementValue(IR::Temp *value, IR::Temp *result);
+ virtual void callBuiltinThrow(IR::Temp *arg);
+ virtual void callBuiltinCreateExceptionHandler(IR::Temp *result);
+ virtual void callBuiltinDeleteExceptionHandler();
+ virtual void callBuiltinGetException(IR::Temp *result);
+ virtual void callBuiltinForeachIteratorObject(IR::Temp *arg, IR::Temp *result);
+ virtual void callBuiltinForeachNextPropertyname(IR::Temp *arg, IR::Temp *result);
+ virtual void callBuiltinPushWithScope(IR::Temp *arg);
+ virtual void callBuiltinPopScope();
+ virtual void callBuiltinDeclareVar(bool deletable, const QString &name);
+ virtual void callBuiltinDefineGetterSetter(IR::Temp *object, const QString &name, IR::Temp *getter, IR::Temp *setter);
+ virtual void callBuiltinDefineProperty(IR::Temp *object, const QString &name, IR::Temp *value);
+ virtual void callBuiltinDefineArrayProperty(IR::Temp *object, int index, IR::Temp *value);
+ virtual void callProperty(IR::Temp *base, const QString &name, IR::ExprList *args, IR::Temp *result);
+ virtual void callSubscript(IR::Temp *base, IR::Temp *index, IR::ExprList *args, IR::Temp *result);
+ virtual void callValue(IR::Temp *value, IR::ExprList *args, IR::Temp *result);
+ virtual void loadThisObject(IR::Temp *temp);
+ virtual void loadConst(IR::Const *sourceConst, IR::Temp *targetTemp);
+ virtual void loadString(const QString &str, IR::Temp *targetTemp);
+ virtual void loadRegexp(IR::RegExp *sourceRegexp, IR::Temp *targetTemp);
+ virtual void getActivationProperty(const QString &name, IR::Temp *temp);
+ virtual void setActivationProperty(IR::Expr *source, const QString &targetName);
+ virtual void initClosure(IR::Closure *closure, IR::Temp *target);
+ virtual void getProperty(IR::Temp *base, const QString &name, IR::Temp *target);
+ virtual void setProperty(IR::Expr *source, IR::Temp *targetBase, const QString &targetName);
+ virtual void getElement(IR::Temp *base, IR::Temp *index, IR::Temp *target);
+ virtual void setElement(IR::Expr *source, IR::Temp *targetBase, IR::Temp *targetIndex);
+ virtual void copyValue(IR::Temp *sourceTemp, IR::Temp *targetTemp);
+ virtual void unop(IR::AluOp oper, IR::Temp *sourceTemp, IR::Temp *targetTemp);
+ virtual void binop(IR::AluOp oper, IR::Expr *leftSource, IR::Expr *rightSource, IR::Temp *target);
+ virtual void inplaceNameOp(IR::AluOp oper, IR::Expr *sourceExpr, const QString &targetName);
+ virtual void inplaceElementOp(IR::AluOp oper, IR::Expr *sourceExpr, IR::Temp *targetBaseTemp, IR::Temp *targetIndexTemp);
+ virtual void inplaceMemberOp(IR::AluOp oper, IR::Expr *source, IR::Temp *targetBase, const QString &targetName);
+
+ typedef Assembler::Address Address;
+ typedef Assembler::Pointer Pointer;
+
+ Address addressForArgument(int index) const
+ {
+ if (index < Assembler::RegisterArgumentCount)
+ return Address(_asm->registerForArgument(index), 0);
+
+ // 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 - Assembler::RegisterArgumentCount + 2) * sizeof(void*));
+ }
+
+ // Some run-time functions take (Value* args, int argc). This function is for populating
+ // the args.
+ Pointer argumentAddressForCall(int argument)
+ {
+ const int index = _function->maxNumberOfArguments - argument;
+ return Pointer(Assembler::StackFrameRegister, sizeof(VM::Value) * (-index)
+ - sizeof(void*) // size of ebp
+ );
+ }
+ Pointer baseAddressForCallArguments()
+ {
+ return argumentAddressForCall(0);
+ }
+
+ VM::String *identifier(const QString &s);
+ virtual void constructActivationProperty(IR::Name *func, IR::ExprList *args, IR::Temp *result);
+ virtual void constructProperty(IR::Temp *base, const QString &name, IR::ExprList *args, IR::Temp *result);
+ virtual void constructValue(IR::Temp *value, IR::ExprList *args, IR::Temp *result);
+
+ virtual void visitJump(IR::Jump *);
+ virtual void visitCJump(IR::CJump *);
+ virtual void visitRet(IR::Ret *);
+
+private:
+ #define isel_stringIfyx(s) #s
+ #define isel_stringIfy(s) isel_stringIfyx(s)
+
+ #define generateFunctionCall(t, function, ...) \
+ _asm->generateFunctionCallImp(t, isel_stringIfy(function), function, __VA_ARGS__)
+
+ int prepareVariableArguments(IR::ExprList* args);
+
+ typedef VM::Value (*ActivationMethod)(VM::ExecutionContext *, VM::String *name, VM::Value *args, int argc);
+ typedef VM::Value (*BuiltinMethod)(VM::ExecutionContext *, VM::Value *args, int argc);
+ void callRuntimeMethodImp(IR::Temp *result, const char* name, ActivationMethod method, IR::Expr *base, IR::ExprList *args);
+ void callRuntimeMethodImp(IR::Temp *result, const char* name, BuiltinMethod method, IR::ExprList *args);
+#define callRuntimeMethod(result, function, ...) \
+ callRuntimeMethodImp(result, isel_stringIfy(function), function, __VA_ARGS__)
+
+ IR::BasicBlock *_block;
+ IR::Function* _function;
+ VM::Function* _vmFunction;
+ Assembler* _asm;
+};
+
+class Q_V4_EXPORT ISelFactory: public EvalISelFactory
+{
+public:
+ virtual ~ISelFactory() {}
+ virtual EvalInstructionSelection *create(VM::ExecutionEngine *engine, IR::Module *module)
+ { return new InstructionSelection(engine, module); }
+};
+
+} // end of namespace MASM
+} // end of namespace QQmlJS
+
+#endif // QV4ISEL_MASM_P_H