aboutsummaryrefslogtreecommitdiffstats
path: root/src/qml/jit
diff options
context:
space:
mode:
authorErik Verbruggen <erik.verbruggen@digia.com>2014-05-23 10:23:15 +0200
committerThe Qt Project <gerrit-noreply@qt-project.org>2014-05-24 12:52:48 +0200
commitddb33ee9ba9e1344caa9be5dbf4b534c3ede692e (patch)
tree7f54d0fcf08eaa1b613d9fe41a9bba650660fbc7 /src/qml/jit
parent75c22465cf8fe262edfe6178bb9ca19661fb710e (diff)
V4: clean-up target specific register definitions and stack usage
All constants referring to registers and all constants and functions that do platform specific things with the stack, are all modev into a separate file. Information about how a specific platform register is used by the ABI is also extended and is now captured in the RegisterInfo class. Usage of this information will be extended in subsequent patches. This also fix ARM register usage: - Correct fp register for Thumb mode. - Only push registers that have to be saved and will actually be used from the stack (i.e. do not push r0-r3 in the function prelude). Change-Id: Ia372505ade8f2648595c7aec1d281955392f34a1 Reviewed-by: Simon Hausmann <simon.hausmann@digia.com>
Diffstat (limited to 'src/qml/jit')
-rw-r--r--src/qml/jit/jit.pri2
-rw-r--r--src/qml/jit/qv4assembler.cpp68
-rw-r--r--src/qml/jit/qv4assembler_p.h161
-rw-r--r--src/qml/jit/qv4isel_masm.cpp96
-rw-r--r--src/qml/jit/qv4registerinfo_p.h98
-rw-r--r--src/qml/jit/qv4targetplatform_p.h397
6 files changed, 517 insertions, 305 deletions
diff --git a/src/qml/jit/jit.pri b/src/qml/jit/jit.pri
index 151ff32df9..7ea4e951d5 100644
--- a/src/qml/jit/jit.pri
+++ b/src/qml/jit/jit.pri
@@ -6,9 +6,11 @@ INCLUDEPATH += $$OUT_PWD
HEADERS += \
$$PWD/qv4assembler_p.h \
$$PWD/qv4regalloc_p.h \
+ $$PWD/qv4targetplatform_p.h \
$$PWD/qv4isel_masm_p.h \
$$PWD/qv4binop_p.h \
$$PWD/qv4unop_p.h \
+ $$PWD/qv4registerinfo_p.h
SOURCES += \
$$PWD/qv4assembler.cpp \
diff --git a/src/qml/jit/qv4assembler.cpp b/src/qml/jit/qv4assembler.cpp
index f090e7d506..7ce682490d 100644
--- a/src/qml/jit/qv4assembler.cpp
+++ b/src/qml/jit/qv4assembler.cpp
@@ -1,6 +1,6 @@
/****************************************************************************
**
-** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/legal
**
** This file is part of the QtQml module of the Qt Toolkit.
@@ -91,58 +91,6 @@ QV4::ExecutableAllocator::ChunkOfPages *CompilationUnit::chunkForFunction(int fu
return handle->chunk();
}
-
-
-/* Platform/Calling convention/Architecture specific section */
-
-#if CPU(X86_64)
-# if OS(LINUX) || OS(MAC_OS_X)
-static const Assembler::RegisterID calleeSavedRegisters[] = {
- JSC::X86Registers::ebx,
- JSC::X86Registers::r12, // LocalsRegister
- JSC::X86Registers::r13,
- JSC::X86Registers::r14, // ContextRegister
- JSC::X86Registers::r15
-};
-# elif OS(WINDOWS)
-static const Assembler::RegisterID calleeSavedRegisters[] = {
- JSC::X86Registers::ebx,
- JSC::X86Registers::esi,
- JSC::X86Registers::edi,
- JSC::X86Registers::r12, // LocalsRegister
- JSC::X86Registers::r13,
- JSC::X86Registers::r14, // ContextRegister
- JSC::X86Registers::r15
-};
-# endif
-#endif
-
-#if CPU(X86)
-static const Assembler::RegisterID calleeSavedRegisters[] = {
- JSC::X86Registers::ebx, // temporary register
- JSC::X86Registers::esi, // ContextRegister
- JSC::X86Registers::edi // LocalsRegister
-};
-#endif
-
-#if CPU(ARM)
-static const Assembler::RegisterID calleeSavedRegisters[] = {
- JSC::ARMRegisters::r11,
- JSC::ARMRegisters::r10,
- JSC::ARMRegisters::r9,
- JSC::ARMRegisters::r8,
- JSC::ARMRegisters::r7,
- JSC::ARMRegisters::r6,
- JSC::ARMRegisters::r5,
- JSC::ARMRegisters::r4
-};
-#endif
-
-const int Assembler::calleeSavedRegisterCount = sizeof(calleeSavedRegisters) / sizeof(calleeSavedRegisters[0]);
-
-/* End of platform/calling convention/architecture specific section */
-
-
const Assembler::VoidType Assembler::Void;
Assembler::Assembler(InstructionSelection *isel, IR::Function* function, QV4::ExecutableAllocator *executableAllocator,
@@ -295,7 +243,7 @@ void Assembler::storeValue(QV4::Primitive value, IR::Expr *destination)
void Assembler::enterStandardStackFrame()
{
- platformEnterStandardStackFrame();
+ platformEnterStandardStackFrame(this);
// ### FIXME: Handle through calleeSavedRegisters mechanism
// or eliminate StackFrameRegister altogether.
@@ -306,16 +254,18 @@ void Assembler::enterStandardStackFrame()
subPtr(TrustedImm32(frameSize), StackPointerRegister);
- for (int i = 0; i < calleeSavedRegisterCount; ++i)
- storePtr(calleeSavedRegisters[i], Address(StackFrameRegister, -(i + 1) * sizeof(void*)));
+ const RegisterInformation &calleeSavedRegisters = getCalleeSavedRegisters();
+ for (int i = 0; i < calleeSavedRegisterCount(); ++i)
+ storePtr(calleeSavedRegisters[i].reg<RegisterID>(), Address(StackFrameRegister, -(i + 1) * sizeof(void*)));
}
void Assembler::leaveStandardStackFrame()
{
// restore the callee saved registers
- for (int i = calleeSavedRegisterCount - 1; i >= 0; --i)
- loadPtr(Address(StackFrameRegister, -(i + 1) * sizeof(void*)), calleeSavedRegisters[i]);
+ const RegisterInformation &calleeSavedRegisters = getCalleeSavedRegisters();
+ for (int i = calleeSavedRegisterCount() - 1; i >= 0; --i)
+ loadPtr(Address(StackFrameRegister, -(i + 1) * sizeof(void*)), calleeSavedRegisters[i].reg<RegisterID>());
int frameSize = _stackLayout.calculateStackFrameSize();
// Work around bug in ARMv7Assembler.h where add32(imm, sp, sp) doesn't
@@ -328,7 +278,7 @@ void Assembler::leaveStandardStackFrame()
#endif
pop(StackFrameRegister);
- platformLeaveStandardStackFrame();
+ platformLeaveStandardStackFrame(this);
}
diff --git a/src/qml/jit/qv4assembler_p.h b/src/qml/jit/qv4assembler_p.h
index 90387dcf79..faef4fd168 100644
--- a/src/qml/jit/qv4assembler_p.h
+++ b/src/qml/jit/qv4assembler_p.h
@@ -1,6 +1,6 @@
/****************************************************************************
**
-** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/legal
**
** This file is part of the QtQml module of the Qt Toolkit.
@@ -47,6 +47,7 @@
#include "private/qv4isel_util_p.h"
#include "private/qv4value_p.h"
#include "private/qv4lookup_p.h"
+#include "qv4targetplatform_p.h"
#include <QtCore/QHash>
#include <QtCore/QStack>
@@ -123,158 +124,12 @@ struct ExceptionCheck<void (*)(QV4::NoThrowContext *, A, B, C)> {
enum { NeedsCheck = 0 };
};
-class Assembler : public JSC::MacroAssembler
+class Assembler : public JSC::MacroAssembler, public TargetPlatform
{
public:
Assembler(InstructionSelection *isel, IR::Function* function, QV4::ExecutableAllocator *executableAllocator,
int maxArgCountForBuiltins);
-#if CPU(X86)
-
-#undef VALUE_FITS_IN_REGISTER
-#undef ARGUMENTS_IN_REGISTERS
-
-#define HAVE_ALU_OPS_WITH_MEM_OPERAND 1
-
- static const RegisterID StackFrameRegister = JSC::X86Registers::ebp;
- static const RegisterID StackPointerRegister = JSC::X86Registers::esp;
- static const RegisterID LocalsRegister = JSC::X86Registers::edi;
- static const RegisterID ContextRegister = JSC::X86Registers::esi;
- static const RegisterID ReturnValueRegister = JSC::X86Registers::eax;
- static const RegisterID ScratchRegister = JSC::X86Registers::ecx;
- static const FPRegisterID FPGpr0 = JSC::X86Registers::xmm0;
- static const FPRegisterID FPGpr1 = JSC::X86Registers::xmm1;
-
- static const int RegisterSize = 4;
-
- static const int RegisterArgumentCount = 0;
- static RegisterID registerForArgument(int)
- {
- Q_ASSERT(false);
- // Not reached.
- return JSC::X86Registers::eax;
- }
-
- // Return address is pushed onto stack by the CPU.
- static const int StackSpaceAllocatedUponFunctionEntry = RegisterSize;
- static const int StackShadowSpace = 0;
- inline void platformEnterStandardStackFrame() {}
- inline void platformLeaveStandardStackFrame() {}
-#elif CPU(X86_64)
-
-#define VALUE_FITS_IN_REGISTER
-#define ARGUMENTS_IN_REGISTERS
-#define HAVE_ALU_OPS_WITH_MEM_OPERAND 1
-
- static const RegisterID StackFrameRegister = JSC::X86Registers::ebp;
- static const RegisterID StackPointerRegister = JSC::X86Registers::esp;
- static const RegisterID LocalsRegister = JSC::X86Registers::r12;
- static const RegisterID ContextRegister = JSC::X86Registers::r14;
- static const RegisterID ReturnValueRegister = JSC::X86Registers::eax;
- static const RegisterID ScratchRegister = JSC::X86Registers::r10;
- static const FPRegisterID FPGpr0 = JSC::X86Registers::xmm0;
- static const FPRegisterID FPGpr1 = JSC::X86Registers::xmm1;
-
- static const int RegisterSize = 8;
-
-#if OS(WINDOWS)
- static const int RegisterArgumentCount = 4;
- static RegisterID registerForArgument(int index)
- {
- static RegisterID regs[RegisterArgumentCount] = {
- JSC::X86Registers::ecx,
- JSC::X86Registers::edx,
- JSC::X86Registers::r8,
- JSC::X86Registers::r9
- };
- Q_ASSERT(index >= 0 && index < RegisterArgumentCount);
- return regs[index];
- };
- static const int StackShadowSpace = 32;
-#else // Unix
- 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
- };
- Q_ASSERT(index >= 0 && index < RegisterArgumentCount);
- return regs[index];
- };
- static const int StackShadowSpace = 0;
-#endif
-
- // Return address is pushed onto stack by the CPU.
- static const int StackSpaceAllocatedUponFunctionEntry = RegisterSize;
- inline void platformEnterStandardStackFrame() {}
- inline void platformLeaveStandardStackFrame() {}
-#elif CPU(ARM)
-
-#undef VALUE_FITS_IN_REGISTER
-#define ARGUMENTS_IN_REGISTERS
-#undef HAVE_ALU_OPS_WITH_MEM_OPERAND
-
- static const RegisterID StackPointerRegister = JSC::ARMRegisters::sp; // r13
- static const RegisterID StackFrameRegister = JSC::ARMRegisters::fp; // r11
- static const RegisterID LocalsRegister = JSC::ARMRegisters::r7;
- static const RegisterID ScratchRegister = JSC::ARMRegisters::r6;
- static const RegisterID ContextRegister = JSC::ARMRegisters::r5;
- static const RegisterID ReturnValueRegister = JSC::ARMRegisters::r0;
- static const FPRegisterID FPGpr0 = JSC::ARMRegisters::d0;
- static const FPRegisterID FPGpr1 = JSC::ARMRegisters::d1;
-
- 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)
- {
- Q_ASSERT(index >= 0 && index < RegisterArgumentCount);
- return static_cast<RegisterID>(JSC::ARMRegisters::r0 + index);
- };
-
- // Registers saved in platformEnterStandardStackFrame below.
- static const int StackSpaceAllocatedUponFunctionEntry = 5 * RegisterSize;
- static const int StackShadowSpace = 0;
- inline void platformEnterStandardStackFrame()
- {
- // Move the register arguments onto the stack as if they were
- // pushed by the caller, just like on ia32. This gives us consistent
- // access to the parameters if we need to.
- push(JSC::ARMRegisters::r3);
- push(JSC::ARMRegisters::r2);
- push(JSC::ARMRegisters::r1);
- push(JSC::ARMRegisters::r0);
- push(JSC::ARMRegisters::lr);
- }
- inline void platformLeaveStandardStackFrame()
- {
- pop(JSC::ARMRegisters::lr);
- addPtr(TrustedImm32(4 * RegisterSize), StackPointerRegister);
- }
-#else
-#error The JIT needs to be ported to this platform.
-#endif
- static const int calleeSavedRegisterCount;
-
-#if CPU(X86) || CPU(X86_64)
- static const int StackAlignment = 16;
-#elif CPU(ARM)
- // Per AAPCS
- static const int StackAlignment = 8;
-#else
-#error Stack alignment unknown for this platform.
-#endif
-
// Explicit type to allow distinguishing between
// pushing an address itself or the value it points
// to onto the stack when calling functions.
@@ -318,7 +173,7 @@ public:
{
public:
StackLayout(IR::Function *function, int maxArgCountForBuiltins)
- : calleeSavedRegCount(Assembler::calleeSavedRegisterCount + 1)
+ : calleeSavedRegCount(Assembler::calleeSavedRegisterCount() + 1)
, maxOutgoingArgumentCount(function->maxNumberOfArguments)
, localCount(function->tempCount)
, savedRegCount(maxArgCountForBuiltins)
@@ -351,7 +206,7 @@ public:
+ RegisterSize; // saved StackFrameRegister
// space for the callee saved registers
- int frameSize = RegisterSize * calleeSavedRegisterCount;
+ int frameSize = RegisterSize * calleeSavedRegisterCount();
frameSize += savedRegCount * sizeof(QV4::Value); // these get written out as Values, not as native registers
Q_ASSERT(frameSize + stackSpaceAllocatedOtherwise < INT_MAX);
@@ -1014,10 +869,8 @@ public:
prepareRelativeCall(function, this);
loadArgumentOnStackOrRegister<0>(arg1);
-#if (OS(LINUX) && CPU(X86) && (defined(__PIC__) || defined(__PIE__))) || \
- (OS(WINDOWS) && CPU(X86))
- load32(Address(StackFrameRegister, -int(sizeof(void*))),
- JSC::X86Registers::ebx); // restore the GOT ptr
+#ifdef RESTORE_EBX_ON_CALL
+ load32(ebxAddressOnStack(), JSC::X86Registers::ebx); // restore the GOT ptr
#endif
callAbsolute(functionName, function);
diff --git a/src/qml/jit/qv4isel_masm.cpp b/src/qml/jit/qv4isel_masm.cpp
index d82fa990f4..8d732ce657 100644
--- a/src/qml/jit/qv4isel_masm.cpp
+++ b/src/qml/jit/qv4isel_masm.cpp
@@ -1,6 +1,6 @@
/****************************************************************************
**
-** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/legal
**
** This file is part of the QtQml module of the Qt Toolkit.
@@ -214,91 +214,6 @@ InstructionSelection::~InstructionSelection()
delete _as;
}
-#if (CPU(X86_64) && (OS(MAC_OS_X) || OS(LINUX))) || (CPU(X86) && OS(LINUX))
-# define REGALLOC_IS_SUPPORTED
-static QVector<int> getIntRegisters()
-{
-# if CPU(X86) && OS(LINUX) // x86 with linux
- static const QVector<int> intRegisters = QVector<int>()
- << JSC::X86Registers::edx
- << JSC::X86Registers::ebx;
-# else // x86_64 with linux or with macos
- static const QVector<int> intRegisters = QVector<int>()
- << JSC::X86Registers::ebx
- << JSC::X86Registers::edi
- << JSC::X86Registers::esi
- << JSC::X86Registers::edx
- << JSC::X86Registers::r9
- << JSC::X86Registers::r8
- << JSC::X86Registers::r13
- << JSC::X86Registers::r15;
-# endif
- return intRegisters;
-}
-
-static QVector<int> getFpRegisters()
-{
-// linux/x86_64, linux/x86, and macos/x86_64:
- static const QVector<int> fpRegisters = QVector<int>()
- << JSC::X86Registers::xmm2
- << JSC::X86Registers::xmm3
- << JSC::X86Registers::xmm4
- << JSC::X86Registers::xmm5
- << JSC::X86Registers::xmm6
- << JSC::X86Registers::xmm7;
- return fpRegisters;
-}
-
-#elif CPU(ARM) && OS(LINUX)
- // Note: this is not generic for all ARM platforms. Specifically, r9 is platform dependent
- // (e.g. iOS reserves it). See the ARM GNU Linux abi for details.
-# define REGALLOC_IS_SUPPORTED
-static QVector<int> getIntRegisters()
-{
- static const QVector<int> intRegisters = QVector<int>()
- << JSC::ARMRegisters::r1
- << JSC::ARMRegisters::r2
- << JSC::ARMRegisters::r3
- << JSC::ARMRegisters::r4
- << JSC::ARMRegisters::r8
- << JSC::ARMRegisters::r9;
- return intRegisters;
-}
-
-static QVector<int> getFpRegisters()
-{
- static const QVector<int> fpRegisters = QVector<int>()
- << JSC::ARMRegisters::d1
- << JSC::ARMRegisters::d2
- << JSC::ARMRegisters::d3
- << JSC::ARMRegisters::d4
- << JSC::ARMRegisters::d5
- << JSC::ARMRegisters::d6;
- return fpRegisters;
-}
-#elif CPU(X86) && OS(WINDOWS)
-# define REGALLOC_IS_SUPPORTED
-static QVector<int> getIntRegisters()
-{
- static const QVector<int> intRegisters = QVector<int>()
- << JSC::X86Registers::edx
- << JSC::X86Registers::ebx;
- return intRegisters;
-}
-
-static QVector<int> getFpRegisters()
-{
- static const QVector<int> fpRegisters = QVector<int>()
- << JSC::X86Registers::xmm2
- << JSC::X86Registers::xmm3
- << JSC::X86Registers::xmm4
- << JSC::X86Registers::xmm5
- << JSC::X86Registers::xmm6
- << JSC::X86Registers::xmm7;
- return fpRegisters;
-}
-#endif
-
void InstructionSelection::run(int functionIndex)
{
IR::Function *function = irModule->functions[functionIndex];
@@ -308,13 +223,10 @@ void InstructionSelection::run(int functionIndex)
IR::Optimizer opt(_function);
opt.run(qmlEngine);
-#ifdef REGALLOC_IS_SUPPORTED
static const bool withRegisterAllocator = qgetenv("QV4_NO_REGALLOC").isEmpty();
- if (opt.isInSSA() && withRegisterAllocator) {
- RegisterAllocator(getIntRegisters(), getFpRegisters()).run(_function, opt);
- } else
-#endif // REGALLOC_IS_SUPPORTED
- {
+ if (Assembler::RegAllocIsSupported && opt.isInSSA() && withRegisterAllocator) {
+ RegisterAllocator(Assembler::getIntRegisters(), Assembler::getFpRegisters()).run(_function, opt);
+ } else {
if (opt.isInSSA())
// No register allocator available for this platform, or env. var was set, so:
opt.convertOutOfSSA();
diff --git a/src/qml/jit/qv4registerinfo_p.h b/src/qml/jit/qv4registerinfo_p.h
new file mode 100644
index 0000000000..b9bef678a3
--- /dev/null
+++ b/src/qml/jit/qv4registerinfo_p.h
@@ -0,0 +1,98 @@
+/****************************************************************************
+**
+** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the QtQml 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 QV4REGISTERINFO_P_H
+#define QV4REGISTERINFO_P_H
+
+#include <QtCore/QString>
+
+QT_BEGIN_NAMESPACE
+
+namespace QV4 {
+namespace JIT {
+
+class RegisterInfo
+{
+public:
+ enum { InvalidRegister = -1 };
+ enum SavedBy { CallerSaved, CalleeSaved };
+ enum RegisterType { RegularRegister, FloatingPointRegister };
+ enum Usage { Predefined, RegAlloc };
+
+public:
+ RegisterInfo()
+ : _reg(InvalidRegister)
+ , _type(RegularRegister)
+ , _savedBy(CallerSaved)
+ , _usage(Predefined)
+ {}
+
+ RegisterInfo(int reg, const QString &prettyName, RegisterType type, SavedBy savedBy, Usage usage)
+ : _reg(reg)
+ , _prettyName(prettyName)
+ , _type(type)
+ , _savedBy(savedBy)
+ , _usage(usage)
+ {}
+
+ bool isValid() const { return _reg != InvalidRegister; }
+ template <typename T> T reg() const { return static_cast<T>(_reg); }
+ bool isCallerSaved() const { return _savedBy == CallerSaved; }
+ bool isCalleeSaved() const { return _savedBy == CalleeSaved; }
+ bool isFloatingPoint() const { return _type == FloatingPointRegister; }
+ bool isRegularRegister() const { return _type == RegularRegister; }
+ bool useForRegAlloc() const { return _usage == RegAlloc; }
+
+private:
+ int _reg;
+ QString _prettyName;
+ RegisterType _type;
+ SavedBy _savedBy;
+ Usage _usage;
+};
+typedef QVector<RegisterInfo> RegisterInformation;
+
+} // JIT namespace
+} // QV4 namespace
+
+QT_END_NAMESPACE
+
+#endif // QV4REGISTERINFO_P_H
diff --git a/src/qml/jit/qv4targetplatform_p.h b/src/qml/jit/qv4targetplatform_p.h
new file mode 100644
index 0000000000..654d2f3f52
--- /dev/null
+++ b/src/qml/jit/qv4targetplatform_p.h
@@ -0,0 +1,397 @@
+/****************************************************************************
+**
+** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the QtQml 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 QV4TARGETPLATFORM_P_H
+#define QV4TARGETPLATFORM_P_H
+
+#include <config.h>
+
+#if ENABLE(ASSEMBLER)
+
+#include "qv4registerinfo_p.h"
+#include <assembler/MacroAssembler.h>
+
+QT_BEGIN_NAMESPACE
+
+namespace QV4 {
+namespace JIT {
+
+// The TargetPlatform class describes how the stack and the registers work on a CPU+ABI combination.
+//
+// All combinations have a separate definition, guarded by #ifdefs. The exceptions are:
+// - Linux/x86 and win32, which are the same, except that linux non-PIC/PIE code does not need to
+// restore ebx (which holds the GOT ptr) before a call
+// - All (supported) ARM platforms, where the only variety is the platform specific usage of r9,
+// and the frame-pointer in Thumb/Thumb2 v.s. ARM mode.
+class TargetPlatform
+{
+public:
+#if CPU(X86) && (OS(LINUX) || OS(WINDOWS))
+ enum { RegAllocIsSupported = 1 };
+
+ static const JSC::MacroAssembler::RegisterID StackFrameRegister = JSC::X86Registers::ebp;
+ static const JSC::MacroAssembler::RegisterID StackPointerRegister = JSC::X86Registers::esp;
+ static const JSC::MacroAssembler::RegisterID LocalsRegister = JSC::X86Registers::edi;
+ static const JSC::MacroAssembler::RegisterID ContextRegister = JSC::X86Registers::esi;
+ static const JSC::MacroAssembler::RegisterID ReturnValueRegister = JSC::X86Registers::eax;
+ static const JSC::MacroAssembler::RegisterID ScratchRegister = JSC::X86Registers::ecx;
+ static const JSC::MacroAssembler::FPRegisterID FPGpr0 = JSC::X86Registers::xmm0;
+ static const JSC::MacroAssembler::FPRegisterID FPGpr1 = JSC::X86Registers::xmm1;
+
+ static RegisterInformation getPlatformRegisterInfo()
+ {
+ typedef RegisterInfo RI;
+ return RegisterInformation()
+ << RI(JSC::X86Registers::edx, QStringLiteral("edx"), RI::RegularRegister, RI::CallerSaved, RI::RegAlloc)
+ << RI(JSC::X86Registers::ebx, QStringLiteral("ebx"), RI::RegularRegister, RI::CalleeSaved, RI::RegAlloc)
+ << RI(JSC::X86Registers::edi, QStringLiteral("edi"), RI::RegularRegister, RI::CalleeSaved, RI::Predefined)
+ << RI(JSC::X86Registers::esi, QStringLiteral("esi"), RI::RegularRegister, RI::CalleeSaved, RI::Predefined)
+ << RI(JSC::X86Registers::xmm2, QStringLiteral("xmm2"), RI::FloatingPointRegister, RI::CallerSaved, RI::RegAlloc)
+ << RI(JSC::X86Registers::xmm3, QStringLiteral("xmm3"), RI::FloatingPointRegister, RI::CallerSaved, RI::RegAlloc)
+ << RI(JSC::X86Registers::xmm4, QStringLiteral("xmm4"), RI::FloatingPointRegister, RI::CallerSaved, RI::RegAlloc)
+ << RI(JSC::X86Registers::xmm5, QStringLiteral("xmm5"), RI::FloatingPointRegister, RI::CallerSaved, RI::RegAlloc)
+ << RI(JSC::X86Registers::xmm6, QStringLiteral("xmm6"), RI::FloatingPointRegister, RI::CallerSaved, RI::RegAlloc)
+ << RI(JSC::X86Registers::xmm7, QStringLiteral("xmm7"), RI::FloatingPointRegister, RI::CallerSaved, RI::RegAlloc)
+ ;
+ }
+
+# undef VALUE_FITS_IN_REGISTER
+ static const int RegisterSize = 4;
+
+# undef ARGUMENTS_IN_REGISTERS
+ static const int RegisterArgumentCount = 0;
+ static JSC::MacroAssembler::RegisterID registerForArgument(int) { Q_UNREACHABLE(); }
+
+ static const int StackAlignment = 16;
+ static const int StackShadowSpace = 0;
+ static const int StackSpaceAllocatedUponFunctionEntry = RegisterSize; // Return address is pushed onto stack by the CPU.
+ static void platformEnterStandardStackFrame(JSC::MacroAssembler *as) { Q_UNUSED(as); }
+ static void platformLeaveStandardStackFrame(JSC::MacroAssembler *as) { Q_UNUSED(as); }
+
+#if OS(WINDOWS) || \
+ (OS(LINUX) && (defined(__PIC__) || defined(__PIE__)))
+
+#define RESTORE_EBX_ON_CALL
+ static JSC::MacroAssembler::Address ebxAddressOnStack()
+ {
+ static int ebxIdx = -1;
+ if (ebxIdx == -1) {
+ int calleeSaves = 0;
+ foreach (const RegisterInfo &info, getRegisterInfo()) {
+ if (info.reg<JSC::X86Registers::RegisterID>() == JSC::X86Registers::ebx) {
+ ebxIdx = calleeSaves;
+ break;
+ } else if (info.isCalleeSaved()) {
+ ++calleeSaves;
+ }
+ }
+ Q_ASSERT(ebxIdx >= 0);
+ ebxIdx += 1;
+ }
+ return JSC::MacroAssembler::Address(StackFrameRegister, ebxIdx * -int(sizeof(void*)));
+ }
+#endif
+
+#endif // Windows on x86
+
+#if CPU(X86_64) && (OS(LINUX) || OS(MAC_OS_X))
+ enum { RegAllocIsSupported = 1 };
+
+ static const JSC::MacroAssembler::RegisterID StackFrameRegister = JSC::X86Registers::ebp;
+ static const JSC::MacroAssembler::RegisterID StackPointerRegister = JSC::X86Registers::esp;
+ static const JSC::MacroAssembler::RegisterID LocalsRegister = JSC::X86Registers::r12;
+ static const JSC::MacroAssembler::RegisterID ContextRegister = JSC::X86Registers::r14;
+ static const JSC::MacroAssembler::RegisterID ReturnValueRegister = JSC::X86Registers::eax;
+ static const JSC::MacroAssembler::RegisterID ScratchRegister = JSC::X86Registers::r10;
+ static const JSC::MacroAssembler::FPRegisterID FPGpr0 = JSC::X86Registers::xmm0;
+ static const JSC::MacroAssembler::FPRegisterID FPGpr1 = JSC::X86Registers::xmm1;
+
+ static RegisterInformation getPlatformRegisterInfo()
+ {
+ typedef RegisterInfo RI;
+ return RegisterInformation()
+ << RI(JSC::X86Registers::ebx, QStringLiteral("rbx"), RI::RegularRegister, RI::CalleeSaved, RI::RegAlloc)
+ << RI(JSC::X86Registers::edi, QStringLiteral("rdi"), RI::RegularRegister, RI::CallerSaved, RI::RegAlloc)
+ << RI(JSC::X86Registers::esi, QStringLiteral("rsi"), RI::RegularRegister, RI::CallerSaved, RI::RegAlloc)
+ << RI(JSC::X86Registers::edx, QStringLiteral("rdx"), RI::RegularRegister, RI::CallerSaved, RI::RegAlloc)
+ << RI(JSC::X86Registers::r9, QStringLiteral("r9"), RI::RegularRegister, RI::CallerSaved, RI::RegAlloc)
+ << RI(JSC::X86Registers::r8, QStringLiteral("r8"), RI::RegularRegister, RI::CallerSaved, RI::RegAlloc)
+ << RI(JSC::X86Registers::r12, QStringLiteral("r12"), RI::RegularRegister, RI::CalleeSaved, RI::Predefined)
+ << RI(JSC::X86Registers::r13, QStringLiteral("r13"), RI::RegularRegister, RI::CalleeSaved, RI::RegAlloc)
+ << RI(JSC::X86Registers::r14, QStringLiteral("r14"), RI::RegularRegister, RI::CalleeSaved, RI::Predefined)
+ << RI(JSC::X86Registers::r15, QStringLiteral("r15"), RI::RegularRegister, RI::CalleeSaved, RI::RegAlloc)
+ << RI(JSC::X86Registers::xmm2, QStringLiteral("xmm2"), RI::FloatingPointRegister, RI::CallerSaved, RI::RegAlloc)
+ << RI(JSC::X86Registers::xmm3, QStringLiteral("xmm3"), RI::FloatingPointRegister, RI::CallerSaved, RI::RegAlloc)
+ << RI(JSC::X86Registers::xmm4, QStringLiteral("xmm4"), RI::FloatingPointRegister, RI::CallerSaved, RI::RegAlloc)
+ << RI(JSC::X86Registers::xmm5, QStringLiteral("xmm5"), RI::FloatingPointRegister, RI::CallerSaved, RI::RegAlloc)
+ << RI(JSC::X86Registers::xmm6, QStringLiteral("xmm6"), RI::FloatingPointRegister, RI::CallerSaved, RI::RegAlloc)
+ << RI(JSC::X86Registers::xmm7, QStringLiteral("xmm7"), RI::FloatingPointRegister, RI::CallerSaved, RI::RegAlloc)
+ ;
+ }
+
+#define VALUE_FITS_IN_REGISTER
+ static const int RegisterSize = 8;
+
+#define ARGUMENTS_IN_REGISTERS
+ static const int RegisterArgumentCount = 6;
+ static JSC::MacroAssembler::RegisterID registerForArgument(int index)
+ {
+ static JSC::MacroAssembler::RegisterID regs[RegisterArgumentCount] = {
+ JSC::X86Registers::edi,
+ JSC::X86Registers::esi,
+ JSC::X86Registers::edx,
+ JSC::X86Registers::ecx,
+ JSC::X86Registers::r8,
+ JSC::X86Registers::r9
+ };
+ Q_ASSERT(index >= 0 && index < RegisterArgumentCount);
+ return regs[index];
+ };
+
+ static const int StackAlignment = 16;
+ static const int StackShadowSpace = 0;
+ static const int StackSpaceAllocatedUponFunctionEntry = RegisterSize; // Return address is pushed onto stack by the CPU.
+ static void platformEnterStandardStackFrame(JSC::MacroAssembler *as) { Q_UNUSED(as); }
+ static void platformLeaveStandardStackFrame(JSC::MacroAssembler *as) { Q_UNUSED(as); }
+#endif // Linux/MacOS on x86_64
+
+#if CPU(X86_64) && OS(WINDOWS)
+ // Register allocation is not (yet) supported on win64, because the ABI related stack handling
+ // is not completely implemented. Specifically, the saving of xmm registers, and the saving of
+ // incoming function parameters to the shadow space is missing.
+ enum { RegAllocIsSupported = 0 };
+
+ static const JSC::MacroAssembler::RegisterID StackFrameRegister = JSC::X86Registers::ebp;
+ static const JSC::MacroAssembler::RegisterID StackPointerRegister = JSC::X86Registers::esp;
+ static const JSC::MacroAssembler::RegisterID LocalsRegister = JSC::X86Registers::r12;
+ static const JSC::MacroAssembler::RegisterID ContextRegister = JSC::X86Registers::r14;
+ static const JSC::MacroAssembler::RegisterID ReturnValueRegister = JSC::X86Registers::eax;
+ static const JSC::MacroAssembler::RegisterID ScratchRegister = JSC::X86Registers::r10;
+ static const JSC::MacroAssembler::FPRegisterID FPGpr0 = JSC::X86Registers::xmm0;
+ static const JSC::MacroAssembler::FPRegisterID FPGpr1 = JSC::X86Registers::xmm1;
+
+ static RegisterInformation getPlatformRegisterInfo()
+ {
+ typedef RegisterInfo RI;
+ return RegisterInformation()
+ << RI(JSC::X86Registers::ebx, QStringLiteral("rbx"), RI::RegularRegister, RI::CalleeSaved, RI::Predefined)
+ << RI(JSC::X86Registers::edi, QStringLiteral("rdi"), RI::RegularRegister, RI::CalleeSaved, RI::Predefined)
+ << RI(JSC::X86Registers::esi, QStringLiteral("rsi"), RI::RegularRegister, RI::CalleeSaved, RI::Predefined)
+ << RI(JSC::X86Registers::edx, QStringLiteral("rdx"), RI::RegularRegister, RI::CallerSaved, RI::Predefined)
+ << RI(JSC::X86Registers::r9, QStringLiteral("r9"), RI::RegularRegister, RI::CallerSaved, RI::Predefined)
+ << RI(JSC::X86Registers::r8, QStringLiteral("r8"), RI::RegularRegister, RI::CallerSaved, RI::Predefined)
+ << RI(JSC::X86Registers::r12, QStringLiteral("r12"), RI::RegularRegister, RI::CalleeSaved, RI::Predefined)
+ << RI(JSC::X86Registers::r13, QStringLiteral("r13"), RI::RegularRegister, RI::CalleeSaved, RI::Predefined)
+ << RI(JSC::X86Registers::r14, QStringLiteral("r14"), RI::RegularRegister, RI::CalleeSaved, RI::Predefined)
+ << RI(JSC::X86Registers::r15, QStringLiteral("r15"), RI::RegularRegister, RI::CalleeSaved, RI::Predefined)
+ ;
+ }
+
+#define VALUE_FITS_IN_REGISTER
+ static const int RegisterSize = 8;
+
+#define ARGUMENTS_IN_REGISTERS
+ static const int RegisterArgumentCount = 4;
+ static JSC::MacroAssembler::RegisterID registerForArgument(int index)
+ {
+ static JSC::MacroAssembler::RegisterID regs[RegisterArgumentCount] = {
+ JSC::X86Registers::ecx,
+ JSC::X86Registers::edx,
+ JSC::X86Registers::r8,
+ JSC::X86Registers::r9
+ };
+ Q_ASSERT(index >= 0 && index < RegisterArgumentCount);
+ return regs[index];
+ };
+
+ static const int StackAlignment = 16;
+ static const int StackShadowSpace = 32;
+ static const int StackSpaceAllocatedUponFunctionEntry = RegisterSize; // Return address is pushed onto stack by the CPU.
+ static void platformEnterStandardStackFrame(JSC::MacroAssembler *as) { Q_UNUSED(as); }
+ static void platformLeaveStandardStackFrame(JSC::MacroAssembler *as) { Q_UNUSED(as); }
+#endif // Windows on x86_64
+
+#if CPU(ARM)
+ enum { RegAllocIsSupported = 1 };
+
+ // The AAPCS specifies that the platform ABI has to define the usage of r9. Known are:
+ // - The GNU/Linux ABI defines it as an additional callee-saved variable register (v6).
+ // - iOS (for which we cannot JIT, but still...) defines it as having a special use, so we do
+ // not touch it, nor use it.
+ // - Any other platform has not been verified, so we conservatively assume we cannot use it.
+#if OS(LINUX)
+#define CAN_USE_R9
+#endif
+
+ // There are two designated frame-pointer registers on ARM, depending on which instruction set
+ // is used for the subroutine: r7 for Thumb or Thumb2, and r11 for ARM. We assign the constants
+ // accordingly, and assign the locals-register to the "other" register.
+#if CPU(ARM_THUMB2)
+ static const JSC::MacroAssembler::RegisterID StackFrameRegister = JSC::ARMRegisters::r7;
+ static const JSC::MacroAssembler::RegisterID LocalsRegister = JSC::ARMRegisters::r11;
+#else // Thumbs down
+ static const JSC::MacroAssembler::RegisterID StackFrameRegister = JSC::ARMRegisters::r11;
+ static const JSC::MacroAssembler::RegisterID LocalsRegister = JSC::ARMRegisters::r7;
+#endif
+ static const JSC::MacroAssembler::RegisterID StackPointerRegister = JSC::ARMRegisters::r13;
+ static const JSC::MacroAssembler::RegisterID ScratchRegister = JSC::ARMRegisters::r6;
+ static const JSC::MacroAssembler::RegisterID ContextRegister = JSC::ARMRegisters::r5;
+ static const JSC::MacroAssembler::RegisterID ReturnValueRegister = JSC::ARMRegisters::r0;
+ static const JSC::MacroAssembler::FPRegisterID FPGpr0 = JSC::ARMRegisters::d0;
+ static const JSC::MacroAssembler::FPRegisterID FPGpr1 = JSC::ARMRegisters::d1;
+
+ static RegisterInformation getPlatformRegisterInfo()
+ {
+ typedef RegisterInfo RI;
+ return RegisterInformation()
+ << RI(JSC::ARMRegisters::r0, QStringLiteral("r0"), RI::RegularRegister, RI::CallerSaved, RI::Predefined)
+ << RI(JSC::ARMRegisters::r1, QStringLiteral("r1"), RI::RegularRegister, RI::CallerSaved, RI::RegAlloc)
+ << RI(JSC::ARMRegisters::r2, QStringLiteral("r2"), RI::RegularRegister, RI::CallerSaved, RI::RegAlloc)
+ << RI(JSC::ARMRegisters::r3, QStringLiteral("r3"), RI::RegularRegister, RI::CallerSaved, RI::RegAlloc)
+ << RI(JSC::ARMRegisters::r4, QStringLiteral("r4"), RI::RegularRegister, RI::CalleeSaved, RI::RegAlloc)
+ << RI(JSC::ARMRegisters::r5, QStringLiteral("r5"), RI::RegularRegister, RI::CalleeSaved, RI::Predefined)
+ << RI(JSC::ARMRegisters::r6, QStringLiteral("r6"), RI::RegularRegister, RI::CalleeSaved, RI::Predefined)
+#if !CPU(ARM_THUMB2)
+ << RI(JSC::ARMRegisters::r7, QStringLiteral("r7"), RI::RegularRegister, RI::CalleeSaved, RI::Predefined)
+#endif
+ << RI(JSC::ARMRegisters::r8, QStringLiteral("r8"), RI::RegularRegister, RI::CalleeSaved, RI::RegAlloc)
+#ifdef CAN_USE_R9
+ << RI(JSC::ARMRegisters::r9, QStringLiteral("r9"), RI::RegularRegister, RI::CalleeSaved, RI::RegAlloc)
+#endif
+ << RI(JSC::ARMRegisters::r10, QStringLiteral("r10"), RI::RegularRegister, RI::CalleeSaved, RI::Predefined)
+#if CPU(ARM_THUMB2)
+ << RI(JSC::ARMRegisters::r11, QStringLiteral("r11"), RI::RegularRegister, RI::CalleeSaved, RI::Predefined)
+#endif
+ << RI(JSC::ARMRegisters::d2, QStringLiteral("d2"), RI::FloatingPointRegister, RI::CallerSaved, RI::RegAlloc)
+ << RI(JSC::ARMRegisters::d3, QStringLiteral("d3"), RI::FloatingPointRegister, RI::CallerSaved, RI::RegAlloc)
+ << RI(JSC::ARMRegisters::d4, QStringLiteral("d4"), RI::FloatingPointRegister, RI::CallerSaved, RI::RegAlloc)
+ << RI(JSC::ARMRegisters::d5, QStringLiteral("d5"), RI::FloatingPointRegister, RI::CallerSaved, RI::RegAlloc)
+ << RI(JSC::ARMRegisters::d6, QStringLiteral("d6"), RI::FloatingPointRegister, RI::CallerSaved, RI::RegAlloc)
+ ;
+ // TODO: someone should check what's up with d8-d15: are they alway available, and are they caller or callee saved?
+ }
+
+#undef VALUE_FITS_IN_REGISTER
+ static const int RegisterSize = 4;
+
+#define ARGUMENTS_IN_REGISTERS
+ static const int RegisterArgumentCount = 4;
+ static JSC::MacroAssembler::RegisterID registerForArgument(int index)
+ {
+ static JSC::MacroAssembler::RegisterID regs[RegisterArgumentCount] = {
+ JSC::ARMRegisters::r0,
+ JSC::ARMRegisters::r1,
+ JSC::ARMRegisters::r2,
+ JSC::ARMRegisters::r3
+ };
+
+ Q_ASSERT(index >= 0 && index < RegisterArgumentCount);
+ return regs[index];
+ };
+
+ static const int StackAlignment = 8; // Per AAPCS
+ static const int StackShadowSpace = 0;
+ static const int StackSpaceAllocatedUponFunctionEntry = 1 * RegisterSize; // Registers saved in platformEnterStandardStackFrame below.
+ static void platformEnterStandardStackFrame(JSC::MacroAssembler *as) { as->push(JSC::ARMRegisters::lr); }
+ static void platformLeaveStandardStackFrame(JSC::MacroAssembler *as) { as->pop(JSC::ARMRegisters::lr); }
+#endif // Linux on ARM (32 bit)
+
+public: // utility functions
+ static RegisterInformation getRegisterInfo()
+ {
+ static const RegisterInformation info = getPlatformRegisterInfo();
+
+ return info;
+ }
+
+ static RegisterInformation &getCalleeSavedRegisters()
+ {
+ static RegisterInformation regs;
+ if (regs.isEmpty()) {
+ foreach (const RegisterInfo &info, getRegisterInfo()) {
+ if (info.isCalleeSaved())
+ regs.append(info);
+ }
+ }
+
+ return regs;
+ }
+
+ static int calleeSavedRegisterCount()
+ {
+ return getCalleeSavedRegisters().size();
+ }
+
+ static QVector<int> getIntRegisters()
+ {
+ // TODO: change the register allocator to cope with caller/callee saved registers
+ static QVector<int> intRegs;
+ if (intRegs.isEmpty()) {
+ foreach (const RegisterInfo &info, getRegisterInfo())
+ if (info.isRegularRegister() && info.useForRegAlloc())
+ intRegs.append(info.reg<int>());
+ }
+
+ return intRegs;
+ }
+
+ static QVector<int> getFpRegisters()
+ {
+ // TODO: change the register allocator to cope with caller/callee saved registers
+ static QVector<int> fpRegs;
+ if (fpRegs.isEmpty()) {
+ foreach (const RegisterInfo &info, getRegisterInfo())
+ if (info.isFloatingPoint() && info.useForRegAlloc())
+ fpRegs.append(info.reg<int>());
+ }
+
+ return fpRegs;
+ }
+};
+
+} // JIT namespace
+} // QV4 namespace
+
+QT_END_NAMESPACE
+
+#endif // ENABLE(ASSEMBLER)
+
+#endif // QV4TARGETPLATFORM_P_H