blob: ead1e757de6239b65a8a44dd998c601d517e2c10 [file] [log] [blame]
/****************************************************************************
**
** Copyright (C) 2018 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** 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 The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://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 3 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL3 included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 3 requirements
** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 2.0 or (at your option) the GNU General
** Public license version 3 or any later version approved by the KDE Free
** Qt Foundation. The licenses are as published by the Free Software
** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-2.0.html and
** https://www.gnu.org/licenses/gpl-3.0.html.
**
** $QT_END_LICENSE$
**
****************************************************************************/
#ifndef QV4PLATFORMASSEMBLER_P_H
#define QV4PLATFORMASSEMBLER_P_H
//
// W A R N I N G
// -------------
//
// This file is not part of the Qt API. It exists purely as an
// implementation detail. This header file may change from version to
// version without notice, or even be removed.
//
// We mean it.
//
#include <private/qv4engine_p.h>
#include <private/qv4global_p.h>
#include <private/qv4function_p.h>
#include <QHash>
#include <wtf/Vector.h>
#include <assembler/MacroAssembler.h>
QT_REQUIRE_CONFIG(qml_jit);
QT_BEGIN_NAMESPACE
namespace QV4 {
namespace JIT {
#if defined(Q_PROCESSOR_X86_64) || defined(ENABLE_ALL_ASSEMBLERS_FOR_REFACTORING_PURPOSES)
#if defined(Q_OS_LINUX) || defined(Q_OS_QNX) || defined(Q_OS_FREEBSD) || defined(Q_OS_DARWIN)
class PlatformAssembler_X86_64_SysV : public JSC::MacroAssembler<JSC::MacroAssemblerX86_64>
{
public:
static constexpr int NativeStackAlignment = 16;
static const RegisterID NoRegister = RegisterID(-1);
static const RegisterID ReturnValueRegister = RegisterID::eax;
static const RegisterID ReturnValueRegisterValue = ReturnValueRegister;
static const RegisterID AccumulatorRegister = RegisterID::eax;
static const RegisterID AccumulatorRegisterValue = AccumulatorRegister;
static const RegisterID ScratchRegister = RegisterID::r10;
static const RegisterID ScratchRegister2 = RegisterID::r9; // Note: overlaps with Arg5Reg, so do not use while setting up a call!
static const RegisterID JSStackFrameRegister = RegisterID::r12;
static const RegisterID CppStackFrameRegister = RegisterID::r13;
static const RegisterID EngineRegister = RegisterID::r14;
static const RegisterID StackPointerRegister = RegisterID::esp;
static const RegisterID FramePointerRegister = RegisterID::ebp;
static const FPRegisterID FPScratchRegister = FPRegisterID::xmm1;
static const FPRegisterID FPScratchRegister2 = FPRegisterID::xmm2;
static const RegisterID Arg0Reg = RegisterID::edi;
static const RegisterID Arg1Reg = RegisterID::esi;
static const RegisterID Arg2Reg = RegisterID::edx;
static const RegisterID Arg3Reg = RegisterID::ecx;
static const RegisterID Arg4Reg = RegisterID::r8;
static const RegisterID Arg5Reg = RegisterID::r9;
static const RegisterID Arg6Reg = NoRegister;
static const RegisterID Arg7Reg = NoRegister;
static const int ArgInRegCount = 6;
void popValue()
{
addPtr(TrustedImmPtr(sizeof(ReturnedValue)), StackPointerRegister);
}
void generatePlatformFunctionEntry()
{
push(FramePointerRegister);
move(StackPointerRegister, FramePointerRegister);
move(TrustedImmPtr(nullptr), AccumulatorRegister); push(AccumulatorRegister); // exceptionHandler
push(JSStackFrameRegister);
push(CppStackFrameRegister);
push(EngineRegister);
move(Arg0Reg, CppStackFrameRegister);
move(Arg1Reg, EngineRegister);
}
void generatePlatformFunctionExit(bool tailCall = false)
{
pop(EngineRegister);
pop(CppStackFrameRegister);
pop(JSStackFrameRegister);
pop(); // exceptionHandler
pop(FramePointerRegister);
if (!tailCall)
ret();
}
void callAbsolute(const void *funcPtr)
{
move(TrustedImmPtr(funcPtr), ScratchRegister);
call(ScratchRegister);
}
void jumpAbsolute(const void *funcPtr)
{
move(TrustedImmPtr(funcPtr), ScratchRegister);
jump(ScratchRegister);
}
void pushAligned(RegisterID reg)
{
subPtr(TrustedImm32(PointerSize), StackPointerRegister);
push(reg);
}
void popAligned(RegisterID reg)
{
pop(reg);
addPtr(TrustedImm32(PointerSize), StackPointerRegister);
}
};
typedef PlatformAssembler_X86_64_SysV PlatformAssemblerBase;
#endif
#if defined(Q_OS_WIN)
class PlatformAssembler_Win64 : public JSC::MacroAssembler<JSC::MacroAssemblerX86_64>
{
public:
static const RegisterID NoRegister = RegisterID(-1);
static const RegisterID ReturnValueRegister = RegisterID::eax;
static const RegisterID ReturnValueRegisterValue = ReturnValueRegister;
static const RegisterID AccumulatorRegister = RegisterID::eax;
static const RegisterID AccumulatorRegisterValue = AccumulatorRegister;
static const RegisterID ScratchRegister = RegisterID::r10;
static const RegisterID ScratchRegister2 = RegisterID::r9; // Note: overlaps with Arg3Reg, so do not use while setting up a call!
static const RegisterID JSStackFrameRegister = RegisterID::r12;
static const RegisterID CppStackFrameRegister = RegisterID::r13;
static const RegisterID EngineRegister = RegisterID::r14;
static const RegisterID StackPointerRegister = RegisterID::esp;
static const RegisterID FramePointerRegister = RegisterID::ebp;
static const FPRegisterID FPScratchRegister = FPRegisterID::xmm1;
static const RegisterID Arg0Reg = RegisterID::ecx;
static const RegisterID Arg1Reg = RegisterID::edx;
static const RegisterID Arg2Reg = RegisterID::r8;
static const RegisterID Arg3Reg = RegisterID::r9;
static const RegisterID Arg4Reg = NoRegister;
static const RegisterID Arg5Reg = NoRegister;
static const RegisterID Arg6Reg = NoRegister;
static const RegisterID Arg7Reg = NoRegister;
static const int ArgInRegCount = 4;
void popValue()
{
addPtr(TrustedImmPtr(sizeof(ReturnedValue)), StackPointerRegister);
}
void generatePlatformFunctionEntry()
{
push(FramePointerRegister);
move(StackPointerRegister, FramePointerRegister);
move(TrustedImmPtr(nullptr), AccumulatorRegister); push(AccumulatorRegister); // exceptionHandler
push(JSStackFrameRegister);
push(CppStackFrameRegister);
push(EngineRegister);
move(Arg0Reg, CppStackFrameRegister);
move(Arg1Reg, EngineRegister);
}
void generatePlatformFunctionExit(bool tailCall = false)
{
pop(EngineRegister);
pop(CppStackFrameRegister);
pop(JSStackFrameRegister);
pop(); // exceptionHandler
pop(FramePointerRegister);
if (!tailCall)
ret();
}
void callAbsolute(const void *funcPtr)
{
move(TrustedImmPtr(funcPtr), ScratchRegister);
subPtr(TrustedImm32(4 * PointerSize), StackPointerRegister);
call(ScratchRegister);
addPtr(TrustedImm32(4 * PointerSize), StackPointerRegister);
}
void jumpAbsolute(const void *funcPtr)
{
move(TrustedImmPtr(funcPtr), ScratchRegister);
jump(ScratchRegister);
}
void pushAligned(RegisterID reg)
{
subPtr(TrustedImm32(PointerSize), StackPointerRegister);
push(reg);
}
void popAligned(RegisterID reg)
{
pop(reg);
addPtr(TrustedImm32(PointerSize), StackPointerRegister);
}
};
typedef PlatformAssembler_Win64 PlatformAssemblerBase;
#endif
#endif
#if (defined(Q_PROCESSOR_X86) && !defined(Q_PROCESSOR_X86_64)) || defined(ENABLE_ALL_ASSEMBLERS_FOR_REFACTORING_PURPOSES)
class PlatformAssembler_X86_All : public JSC::MacroAssembler<JSC::MacroAssemblerX86>
{
public:
static const RegisterID NoRegister = RegisterID(-1);
static const RegisterID ReturnValueRegisterValue = RegisterID::eax;
static const RegisterID ReturnValueRegisterTag = RegisterID::edx;
static const RegisterID ScratchRegister = RegisterID::ecx;
static const RegisterID AccumulatorRegisterValue = ReturnValueRegisterValue;
static const RegisterID AccumulatorRegisterTag = ReturnValueRegisterTag;
static const RegisterID JSStackFrameRegister = RegisterID::ebx;
static const RegisterID CppStackFrameRegister = RegisterID::esi;
static const RegisterID EngineRegister = RegisterID::edi;
static const RegisterID StackPointerRegister = RegisterID::esp;
static const RegisterID FramePointerRegister = RegisterID::ebp;
static const FPRegisterID FPScratchRegister = FPRegisterID::xmm1;
static const RegisterID Arg0Reg = NoRegister;
static const RegisterID Arg1Reg = NoRegister;
static const RegisterID Arg2Reg = NoRegister;
static const RegisterID Arg3Reg = NoRegister;
static const RegisterID Arg4Reg = NoRegister;
static const RegisterID Arg5Reg = NoRegister;
static const RegisterID Arg6Reg = NoRegister;
static const RegisterID Arg7Reg = NoRegister;
static const int ArgInRegCount = 0;
void popValue()
{
addPtr(TrustedImmPtr(sizeof(ReturnedValue)), StackPointerRegister);
}
void generatePlatformFunctionEntry()
{
push(RegisterID::ebp);
move(RegisterID::esp, RegisterID::ebp);
move(TrustedImmPtr(nullptr), AccumulatorRegisterValue); push(AccumulatorRegisterValue); // exceptionHandler
push(JSStackFrameRegister);
push(CppStackFrameRegister);
push(EngineRegister);
// Ensure the stack is 16-byte aligned in order for compiler generated aligned SSE2
// instructions to be able to target the stack.
subPtr(TrustedImm32(8), StackPointerRegister);
loadPtr(Address(FramePointerRegister, 2 * PointerSize), CppStackFrameRegister);
loadPtr(Address(FramePointerRegister, 3 * PointerSize), EngineRegister);
}
void generatePlatformFunctionExit(bool tailCall = false)
{
addPtr(TrustedImm32(8), StackPointerRegister);
pop(EngineRegister);
pop(CppStackFrameRegister);
pop(JSStackFrameRegister);
pop(); // exceptionHandler
pop(RegisterID::ebp);
if (!tailCall)
ret();
}
void callAbsolute(const void *funcPtr)
{
move(TrustedImmPtr(funcPtr), ScratchRegister);
call(ScratchRegister);
}
void jumpAbsolute(const void *funcPtr)
{
move(TrustedImmPtr(funcPtr), ScratchRegister);
jump(ScratchRegister);
}
void pushAligned(RegisterID reg)
{
subPtr(TrustedImm32(3 * PointerSize), StackPointerRegister);
push(reg);
}
void popAligned(RegisterID reg)
{
pop(reg);
addPtr(TrustedImm32(3 * PointerSize), StackPointerRegister);
}
};
typedef PlatformAssembler_X86_All PlatformAssemblerBase;
#endif
#if defined(Q_PROCESSOR_ARM_64) || defined(ENABLE_ALL_ASSEMBLERS_FOR_REFACTORING_PURPOSES)
class PlatformAssembler_ARM64 : public JSC::MacroAssembler<JSC::MacroAssemblerARM64>
{
public:
static const RegisterID NoRegister = RegisterID(-1);
static const RegisterID ReturnValueRegister = JSC::ARM64Registers::x0;
static const RegisterID ReturnValueRegisterValue = ReturnValueRegister;
static const RegisterID AccumulatorRegister = JSC::ARM64Registers::x9;
static const RegisterID AccumulatorRegisterValue = AccumulatorRegister;
static const RegisterID ScratchRegister = JSC::ARM64Registers::x10;
static const RegisterID ScratchRegister2 = JSC::ARM64Registers::x7; // Note: overlaps with Arg7Reg, so do not use while setting up a call!
static const RegisterID JSStackFrameRegister = JSC::ARM64Registers::x19;
static const RegisterID CppStackFrameRegister = JSC::ARM64Registers::x20;
static const RegisterID EngineRegister = JSC::ARM64Registers::x21;
static const RegisterID StackPointerRegister = JSC::ARM64Registers::sp;
static const RegisterID FramePointerRegister = JSC::ARM64Registers::fp;
static const FPRegisterID FPScratchRegister = JSC::ARM64Registers::q1;
static const RegisterID Arg0Reg = JSC::ARM64Registers::x0;
static const RegisterID Arg1Reg = JSC::ARM64Registers::x1;
static const RegisterID Arg2Reg = JSC::ARM64Registers::x2;
static const RegisterID Arg3Reg = JSC::ARM64Registers::x3;
static const RegisterID Arg4Reg = JSC::ARM64Registers::x4;
static const RegisterID Arg5Reg = JSC::ARM64Registers::x5;
static const RegisterID Arg6Reg = JSC::ARM64Registers::x6;
static const RegisterID Arg7Reg = JSC::ARM64Registers::x7;
static const int ArgInRegCount = 8;
void push(RegisterID src)
{
pushToSave(src);
}
void pop(RegisterID dest)
{
popToRestore(dest);
}
void pop()
{
add64(TrustedImm32(16), stackPointerRegister);
}
void popValue()
{
pop();
}
void generatePlatformFunctionEntry()
{
pushPair(JSC::ARM64Registers::fp, JSC::ARM64Registers::lr);
move(RegisterID::sp, RegisterID::fp);
move(TrustedImmPtr(nullptr), AccumulatorRegister); // exceptionHandler
pushPair(JSStackFrameRegister, AccumulatorRegister);
pushPair(EngineRegister, CppStackFrameRegister);
move(Arg0Reg, CppStackFrameRegister);
move(Arg1Reg, EngineRegister);
}
void generatePlatformFunctionExit(bool tailCall = false)
{
if (!tailCall) // do not overwrite arg0 (used in the tail call)
move(AccumulatorRegister, ReturnValueRegister);
popPair(EngineRegister, CppStackFrameRegister);
popPair(JSStackFrameRegister, AccumulatorRegister);
popPair(JSC::ARM64Registers::fp, JSC::ARM64Registers::lr);
if (!tailCall)
ret();
}
void callAbsolute(const void *funcPtr)
{
move(TrustedImmPtr(funcPtr), ScratchRegister);
call(ScratchRegister);
}
void jumpAbsolute(const void *funcPtr)
{
move(TrustedImmPtr(funcPtr), ScratchRegister);
jump(ScratchRegister);
}
void pushAligned(RegisterID reg)
{
pushToSave(reg);
}
void popAligned(RegisterID reg)
{
popToRestore(reg);
}
};
typedef PlatformAssembler_ARM64 PlatformAssemblerBase;
#endif
#if defined(Q_PROCESSOR_ARM_32) || defined(ENABLE_ALL_ASSEMBLERS_FOR_REFACTORING_PURPOSES)
class PlatformAssembler_ARM32 : public JSC::MacroAssembler<JSC::MacroAssemblerARMv7>
{
public:
static const RegisterID NoRegister = RegisterID(-1);
static const RegisterID ReturnValueRegisterValue = JSC::ARMRegisters::r0;
static const RegisterID ReturnValueRegisterTag = JSC::ARMRegisters::r1;
static const RegisterID ScratchRegister = JSC::ARMRegisters::r2;
static const RegisterID AccumulatorRegisterValue = JSC::ARMRegisters::r4;
static const RegisterID AccumulatorRegisterTag = JSC::ARMRegisters::r5;
// r6 is used by MacroAssemblerARMv7
static const RegisterID JSStackFrameRegister = JSC::ARMRegisters::r8;
static const RegisterID CppStackFrameRegister = JSC::ARMRegisters::r10;
#if CPU(ARM_THUMB2)
static const RegisterID FramePointerRegister = JSC::ARMRegisters::r7;
static const RegisterID EngineRegister = JSC::ARMRegisters::r11;
#else // Thumbs down
static const RegisterID FramePointerRegister = JSC::ARMRegisters::r11;
static const RegisterID EngineRegister = JSC::ARMRegisters::r7;
#endif
static const RegisterID StackPointerRegister = JSC::ARMRegisters::r13;
static const FPRegisterID FPScratchRegister = JSC::ARMRegisters::d1;
static const RegisterID Arg0Reg = JSC::ARMRegisters::r0;
static const RegisterID Arg1Reg = JSC::ARMRegisters::r1;
static const RegisterID Arg2Reg = JSC::ARMRegisters::r2;
static const RegisterID Arg3Reg = JSC::ARMRegisters::r3;
static const RegisterID Arg4Reg = NoRegister;
static const RegisterID Arg5Reg = NoRegister;
static const RegisterID Arg6Reg = NoRegister;
static const RegisterID Arg7Reg = NoRegister;
static const int ArgInRegCount = 4;
void popValue()
{
addPtr(TrustedImm32(sizeof(ReturnedValue)), StackPointerRegister);
}
void generatePlatformFunctionEntry()
{
push(JSC::ARMRegisters::lr);
push(FramePointerRegister);
move(StackPointerRegister, FramePointerRegister);
push(TrustedImm32(0)); // exceptionHandler
push(AccumulatorRegisterValue);
push(AccumulatorRegisterTag);
push(addressTempRegister);
push(JSStackFrameRegister);
push(CppStackFrameRegister);
push(EngineRegister);
subPtr(TrustedImm32(4), StackPointerRegister); // stack alignment
move(Arg0Reg, CppStackFrameRegister);
move(Arg1Reg, EngineRegister);
}
void generatePlatformFunctionExit(bool tailCall = false)
{
if (!tailCall) { // do not overwrite arg0 and arg1 (used in the tail call)
move(AccumulatorRegisterValue, ReturnValueRegisterValue);
move(AccumulatorRegisterTag, ReturnValueRegisterTag);
}
addPtr(TrustedImm32(4), StackPointerRegister); // stack alignment
pop(EngineRegister);
pop(CppStackFrameRegister);
pop(JSStackFrameRegister);
pop(addressTempRegister);
pop(AccumulatorRegisterTag);
pop(AccumulatorRegisterValue);
pop(); // exceptionHandler
pop(FramePointerRegister);
pop(JSC::ARMRegisters::lr);
if (!tailCall)
ret();
}
void callAbsolute(const void *funcPtr)
{
move(TrustedImmPtr(funcPtr), dataTempRegister);
call(dataTempRegister);
}
void jumpAbsolute(const void *funcPtr)
{
move(TrustedImmPtr(funcPtr), dataTempRegister);
jump(dataTempRegister);
}
void pushAligned(RegisterID reg)
{
subPtr(TrustedImm32(PointerSize), StackPointerRegister);
push(reg);
}
void popAligned(RegisterID reg)
{
pop(reg);
addPtr(TrustedImm32(PointerSize), StackPointerRegister);
}
};
typedef PlatformAssembler_ARM32 PlatformAssemblerBase;
#endif
class PlatformAssemblerCommon : public JIT::PlatformAssemblerBase
{
public:
PlatformAssemblerCommon(const Value *constantTable)
: constantTable(constantTable)
{}
virtual ~PlatformAssemblerCommon();
Address exceptionHandlerAddress() const
{
return Address(FramePointerRegister, -1 * PointerSize);
}
Address contextAddress() const
{
return Address(JSStackFrameRegister, offsetof(CallData, context));
}
RegisterID registerForArg(int arg) const
{
Q_ASSERT(arg >= 0);
Q_ASSERT(arg < ArgInRegCount);
switch (arg) {
case 0: return Arg0Reg;
case 1: return Arg1Reg;
case 2: return Arg2Reg;
case 3: return Arg3Reg;
case 4: return Arg4Reg;
case 5: return Arg5Reg;
case 6: return Arg6Reg;
case 7: return Arg7Reg;
default:
Q_UNIMPLEMENTED();
Q_UNREACHABLE();
}
}
Address loadFunctionPtr(RegisterID target)
{
Address addr(CppStackFrameRegister, offsetof(CppStackFrame, v4Function));
loadPtr(addr, target);
return Address(target);
}
Address loadCompilationUnitPtr(RegisterID target)
{
Address addr = loadFunctionPtr(target);
addr.offset = offsetof(QV4::FunctionData, compilationUnit);
loadPtr(addr, target);
return Address(target);
}
Address loadConstAddress(int constIndex, RegisterID baseReg = ScratchRegister)
{
Address addr = loadCompilationUnitPtr(baseReg);
addr.offset = offsetof(QV4::CompiledData::CompilationUnitBase, constants);
loadPtr(addr, baseReg);
addr.offset = constIndex * int(sizeof(QV4::Value));
return addr;
}
Address loadStringAddress(int stringId)
{
Address addr = loadCompilationUnitPtr(ScratchRegister);
addr.offset = offsetof(QV4::CompiledData::CompilationUnitBase, runtimeStrings);
loadPtr(addr, ScratchRegister);
return Address(ScratchRegister, stringId * PointerSize);
}
void passAsArg(RegisterID src, int arg)
{
move(src, registerForArg(arg));
}
void generateCatchTrampoline(std::function<void()> loadUndefined)
{
for (Jump j : catchyJumps)
j.link(this);
// We don't need to check for isInterrupted here because if that is set,
// then the first checkException() in any exception handler will find another "exception"
// and jump out of the exception handler.
loadPtr(exceptionHandlerAddress(), ScratchRegister);
Jump exitFunction = branchPtr(Equal, ScratchRegister, TrustedImmPtr(0));
loadUndefined();
jump(ScratchRegister);
exitFunction.link(this);
if (functionExit.isSet())
jump(functionExit);
else
generateFunctionExit();
}
void checkException()
{
// This actually reads 4 bytes, starting at hasException.
// Therefore, it also reads the isInterrupted flag, and triggers an exception on that.
addCatchyJump(
branch32(NotEqual,
Address(EngineRegister, offsetof(EngineBase, hasException)),
TrustedImm32(0)));
}
void addCatchyJump(Jump j)
{
Q_ASSERT(j.isSet());
catchyJumps.push_back(j);
}
void generateFunctionEntry()
{
generatePlatformFunctionEntry();
loadPtr(Address(CppStackFrameRegister, offsetof(CppStackFrame, jsFrame)), JSStackFrameRegister);
allocateStackSpace();
}
virtual void allocateStackSpace() {}
void generateFunctionExit()
{
if (functionExit.isSet()) {
jump(functionExit);
return;
}
functionExit = label();
freeStackSpace();
generatePlatformFunctionExit();
}
virtual void freeStackSpace() {}
void addLabelForOffset(int offset)
{
if (!labelForOffset.contains(offset))
labelForOffset.insert(offset, label());
}
void addJumpToOffset(const Jump &jump, int offset)
{
jumpsToLink.push_back({ jump, offset });
}
void addEHTarget(const DataLabelPtr &label, int offset)
{
ehTargets.push_back({ label, offset });
}
void link(Function *function, const char *jitKind);
Value constant(int idx) const
{ return constantTable[idx]; }
// stuff for runtime calls
void prepareCallWithArgCount(int argc);
void storeInstructionPointer(int instructionOffset);
void passAccumulatorAsArg(int arg);
void pushAccumulatorAsArg(int arg);
void passFunctionAsArg(int arg);
void passEngineAsArg(int arg);
void passJSSlotAsArg(int reg, int arg);
void passAddressAsArg(Address addr, int arg);
void passCppFrameAsArg(int arg);
void passInt32AsArg(int value, int arg);
void passPointerAsArg(void *ptr, int arg);
void callRuntime(const void *funcPtr, const char *functionName = nullptr);
void callRuntimeUnchecked(const void *funcPtr, const char *functionName = nullptr);
void tailCallRuntime(const void *funcPtr, const char *functionName = nullptr);
void setTailCallArg(RegisterID src, int arg);
Address jsAlloca(int slotCount);
void storeInt32AsValue(int srcInt, Address destAddr);
private:
void passAccumulatorAsArg_internal(int arg, bool doPush);
static Address argStackAddress(int arg);
private:
const Value* constantTable;
struct JumpTarget { JSC::MacroAssemblerBase::Jump jump; int offset; };
std::vector<JumpTarget> jumpsToLink;
struct ExceptionHanlderTarget { JSC::MacroAssemblerBase::DataLabelPtr label; int offset; };
std::vector<ExceptionHanlderTarget> ehTargets;
QHash<int, JSC::MacroAssemblerBase::Label> labelForOffset;
QHash<const void *, const char *> functions;
std::vector<Jump> catchyJumps;
Label functionExit;
#ifndef QT_NO_DEBUG
enum { NoCall = -1 };
int remainingArgcForCall = NoCall;
#endif
int argcOnStackForCall = 0;
};
} // JIT namespace
} // QV4 namespace
QT_END_NAMESPACE
#endif // QV4PLATFORMASSEMBLER_P_H