aboutsummaryrefslogtreecommitdiffstats
path: root/src/qml/jit/qv4assembler.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/qml/jit/qv4assembler.cpp')
-rw-r--r--src/qml/jit/qv4assembler.cpp2272
1 files changed, 0 insertions, 2272 deletions
diff --git a/src/qml/jit/qv4assembler.cpp b/src/qml/jit/qv4assembler.cpp
deleted file mode 100644
index 3379d9a0e4..0000000000
--- a/src/qml/jit/qv4assembler.cpp
+++ /dev/null
@@ -1,2272 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2017 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$
-**
-****************************************************************************/
-
-#include <QBuffer>
-#include <QFile>
-
-#include "qv4engine_p.h"
-#include "qv4assembler_p.h"
-#include <private/qv4function_p.h>
-#include <private/qv4runtime_p.h>
-#include <private/qv4stackframe_p.h>
-
-#include <wtf/Vector.h>
-#include <assembler/MacroAssembler.h>
-#include <assembler/MacroAssemblerCodeRef.h>
-#include <assembler/LinkBuffer.h>
-#include <WTFStubs.h>
-
-#undef ENABLE_ALL_ASSEMBLERS_FOR_REFACTORING_PURPOSES
-
-#ifdef V4_ENABLE_JIT
-
-QT_BEGIN_NAMESPACE
-namespace QV4 {
-namespace JIT {
-
-#define callHelper(x) PlatformAssemblerCommon::callRuntime(#x, reinterpret_cast<void *>(&x))
-
-const QV4::Value::ValueTypeInternal IntegerTag = QV4::Value::ValueTypeInternal::Integer;
-
-static ReturnedValue toNumberHelper(ReturnedValue v)
-{
- return Encode(Value::fromReturnedValue(v).toNumber());
-}
-
-static ReturnedValue toInt32Helper(ReturnedValue v)
-{
- return Encode(Value::fromReturnedValue(v).toInt32());
-}
-
-#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)
-
-struct PlatformAssembler_X86_64_SysV : JSC::MacroAssembler<JSC::MacroAssemblerX86_64>
-{
- 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 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(RegisterID::ebp);
- move(RegisterID::esp, RegisterID::ebp);
- move(TrustedImmPtr(nullptr), AccumulatorRegister); push(AccumulatorRegister); // exceptionHandler
- push(JSStackFrameRegister);
- push(CppStackFrameRegister);
- push(EngineRegister);
- move(Arg0Reg, CppStackFrameRegister);
- move(Arg1Reg, EngineRegister);
- }
-
- void generatePlatformFunctionExit()
- {
- pop(EngineRegister);
- pop(CppStackFrameRegister);
- pop(JSStackFrameRegister);
- pop(); // exceptionHandler
- pop(RegisterID::ebp);
- ret();
- }
-
- void callAbsolute(const void *funcPtr)
- {
- move(TrustedImmPtr(funcPtr), ScratchRegister);
- call(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)
-
-struct PlatformAssembler_Win64 : JSC::MacroAssembler<JSC::MacroAssemblerX86_64>
-{
- 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(RegisterID::ebp);
- move(RegisterID::esp, RegisterID::ebp);
- move(TrustedImmPtr(nullptr), AccumulatorRegister); push(AccumulatorRegister); // exceptionHandler
- push(JSStackFrameRegister);
- push(CppStackFrameRegister);
- push(EngineRegister);
- move(Arg0Reg, CppStackFrameRegister);
- move(Arg1Reg, EngineRegister);
- }
-
- void generatePlatformFunctionExit()
- {
- pop(EngineRegister);
- pop(CppStackFrameRegister);
- pop(JSStackFrameRegister);
- pop(); // exceptionHandler
- pop(RegisterID::ebp);
- ret();
- }
-
- void callAbsolute(const void *funcPtr)
- {
- move(TrustedImmPtr(funcPtr), ScratchRegister);
- subPtr(TrustedImm32(4 * PointerSize), StackPointerRegister);
- call(ScratchRegister);
- addPtr(TrustedImm32(4 * PointerSize), StackPointerRegister);
- }
-
- 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)
-
-struct PlatformAssembler_X86_All : JSC::MacroAssembler<JSC::MacroAssemblerX86>
-{
- 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()
- {
- addPtr(TrustedImm32(8), StackPointerRegister);
- pop(EngineRegister);
- pop(CppStackFrameRegister);
- pop(JSStackFrameRegister);
- pop(); // exceptionHandler
- pop(RegisterID::ebp);
- ret();
- }
-
- void callAbsolute(const void *funcPtr)
- {
- move(TrustedImmPtr(funcPtr), ScratchRegister);
- call(ScratchRegister);
- }
-
- void pushAligned(RegisterID reg)
- {
- subPtr(TrustedImm32(PointerSize), StackPointerRegister);
- push(reg);
- }
-
- void popAligned(RegisterID reg)
- {
- pop(reg);
- addPtr(TrustedImm32(PointerSize), StackPointerRegister);
- }
-};
-
-typedef PlatformAssembler_X86_All PlatformAssemblerBase;
-
-#endif
-
-#if defined(Q_PROCESSOR_ARM_64) || defined(ENABLE_ALL_ASSEMBLERS_FOR_REFACTORING_PURPOSES)
-
-struct PlatformAssembler_ARM64 : JSC::MacroAssembler<JSC::MacroAssemblerARM64>
-{
- 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()
- {
- move(AccumulatorRegister, ReturnValueRegister);
- popPair(EngineRegister, CppStackFrameRegister);
- popPair(JSStackFrameRegister, AccumulatorRegister);
- popPair(JSC::ARM64Registers::fp, JSC::ARM64Registers::lr);
- ret();
- }
-
- void callAbsolute(const void *funcPtr)
- {
- move(TrustedImmPtr(funcPtr), ScratchRegister);
- call(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)
-
-struct PlatformAssembler_ARM32 : JSC::MacroAssembler<JSC::MacroAssemblerARMv7>
-{
- 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) || defined(V4_BOOTSTRAP)
- 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()
- {
- 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);
- ret();
- }
-
- void callAbsolute(const void *funcPtr)
- {
- move(TrustedImmPtr(funcPtr), dataTempRegister);
- call(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
-
-struct PlatformAssemblerCommon : PlatformAssemblerBase
-{
- const Value* constantTable;
- struct JumpTarget { JSC::MacroAssemblerBase::Jump jump; int offset; };
- std::vector<JumpTarget> patches;
- struct ExceptionHanlderTarget { JSC::MacroAssemblerBase::DataLabelPtr label; int offset; };
- std::vector<ExceptionHanlderTarget> ehTargets;
- QHash<int, JSC::MacroAssemblerBase::Label> labelsByOffset;
- QHash<const void *, const char *> functions;
- std::vector<Jump> catchyJumps;
- Label functionExit;
-
- 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();
- }
- }
-
- void callRuntime(const char *functionName, const void *funcPtr)
- {
- functions.insert(funcPtr, functionName);
- callAbsolute(funcPtr);
- }
-
- 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::Function, 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);
-
- loadPtr(exceptionHandlerAddress(), ScratchRegister);
- Jump exitFunction = branchPtr(Equal, ScratchRegister, TrustedImmPtr(0));
- jump(ScratchRegister);
- exitFunction.link(this);
- loadUndefined();
-
- if (functionExit.isSet())
- jump(functionExit);
- else
- generateFunctionExit();
- }
-
- void addCatchyJump(Jump j)
- {
- Q_ASSERT(j.isSet());
- catchyJumps.push_back(j);
- }
-
- void generateFunctionEntry()
- {
- generatePlatformFunctionEntry();
- loadPtr(Address(CppStackFrameRegister, offsetof(CppStackFrame, jsFrame)), JSStackFrameRegister);
- }
-
- void generateFunctionExit()
- {
- if (functionExit.isSet()) {
- jump(functionExit);
- return;
- }
-
- functionExit = label();
- generatePlatformFunctionExit();
- }
-};
-
-#if QT_POINTER_SIZE == 8 || defined(ENABLE_ALL_ASSEMBLERS_FOR_REFACTORING_PURPOSES)
-struct PlatformAssembler64 : PlatformAssemblerCommon
-{
- void callRuntime(const char *functionName, const void *funcPtr,
- Assembler::CallResultDestination dest)
- {
- PlatformAssemblerCommon::callRuntime(functionName, funcPtr);
- if (dest == Assembler::ResultInAccumulator)
- saveReturnValueInAccumulator();
- }
-
- void saveReturnValueInAccumulator()
- {
- move(ReturnValueRegister, AccumulatorRegister);
- }
-
- void loadUndefined(RegisterID dest = AccumulatorRegister)
- {
- move(TrustedImm64(0), dest);
- }
-
- void copyConst(int constIndex, Address dest)
- {
- //###
- if (constantTable[constIndex].isUndefined()) {
- loadUndefined(ScratchRegister);
- } else {
- load64(loadConstAddress(constIndex, ScratchRegister), ScratchRegister);
- }
- store64(ScratchRegister, dest);
- }
-
- void copyReg(Address src, Address dst)
- {
- load64(src, ScratchRegister);
- store64(ScratchRegister, dst);
- }
-
- void loadPointerFromValue(Address addr, RegisterID dest = AccumulatorRegister)
- {
- load64(addr, dest);
- }
-
- void loadAccumulator(Address addr)
- {
- load64(addr, AccumulatorRegister);
- }
-
- void storeAccumulator(Address addr)
- {
- store64(AccumulatorRegister, addr);
- }
-
- void moveReg(Address sourceRegAddress, Address destRegAddress)
- {
- load64(sourceRegAddress, ScratchRegister);
- store64(ScratchRegister, destRegAddress);
- }
-
- void loadString(int stringId)
- {
- loadAccumulator(loadStringAddress(stringId));
- }
-
- void loadValue(ReturnedValue value)
- {
- move(TrustedImm64(value), AccumulatorRegister);
- }
-
- void storeHeapObject(RegisterID source, Address addr)
- {
- store64(source, addr);
- }
-
- void generateCatchTrampoline()
- {
- PlatformAssemblerCommon::generateCatchTrampoline([this](){loadUndefined();});
- }
-
- void jumpNotUndefined(int offset)
- {
- auto jump = branch64(NotEqual, AccumulatorRegister, TrustedImm64(0));
- patches.push_back({ jump, offset });
- }
-
- Jump jumpEmpty()
- {
- return branch64(Equal, AccumulatorRegister, TrustedImm64(Primitive::emptyValue().asReturnedValue()));
- }
-
- void toBoolean(std::function<void(RegisterID)> continuation)
- {
- urshift64(AccumulatorRegister, TrustedImm32(Value::IsIntegerConvertible_Shift), ScratchRegister);
- auto needsConversion = branch32(NotEqual, TrustedImm32(1), ScratchRegister);
- continuation(AccumulatorRegister);
- Jump done = jump();
-
- // slow path:
- needsConversion.link(this);
- push(AccumulatorRegister);
- move(AccumulatorRegister, registerForArg(0));
- callHelper(Value::toBooleanImpl);
- and32(TrustedImm32(1), ReturnValueRegister, ScratchRegister);
- pop(AccumulatorRegister);
- continuation(ScratchRegister);
-
- done.link(this);
- }
-
- void toNumber()
- {
- urshift64(AccumulatorRegister, TrustedImm32(Value::QuickType_Shift), ScratchRegister);
- auto isNumber = branch32(GreaterThanOrEqual, ScratchRegister, TrustedImm32(Value::QT_Int));
-
- move(AccumulatorRegister, registerForArg(0));
- callHelper(toNumberHelper);
- saveReturnValueInAccumulator();
-
- isNumber.link(this);
- }
-
- void toInt32LhsAcc(Address lhs, RegisterID lhsTarget)
- {
- load64(lhs, lhsTarget);
- urshift64(lhsTarget, TrustedImm32(Value::QuickType_Shift), ScratchRegister2);
- auto lhsIsInt = branch32(Equal, TrustedImm32(Value::QT_Int), ScratchRegister2);
-
- pushAligned(AccumulatorRegister);
- move(lhsTarget, registerForArg(0));
- callHelper(toInt32Helper);
- move(ReturnValueRegister, lhsTarget);
- popAligned(AccumulatorRegister);
-
- lhsIsInt.link(this);
- urshift64(AccumulatorRegister, TrustedImm32(Value::QuickType_Shift), ScratchRegister2);
- auto isInt = branch32(Equal, TrustedImm32(Value::QT_Int), ScratchRegister2);
-
- pushAligned(lhsTarget);
- move(AccumulatorRegister, registerForArg(0));
- callHelper(toInt32Helper);
- saveReturnValueInAccumulator();
- popAligned(lhsTarget);
-
- isInt.link(this);
- }
-
- void toInt32()
- {
- urshift64(AccumulatorRegister, TrustedImm32(Value::QuickType_Shift), ScratchRegister2);
- auto isInt = branch32(Equal, TrustedImm32(Value::QT_Int), ScratchRegister2);
-
- move(AccumulatorRegister, registerForArg(0));
- callRuntime("toInt32Helper", reinterpret_cast<void *>(&toInt32Helper),
- Assembler::ResultInAccumulator);
-
- isInt.link(this);
- }
-
- void regToInt32(Address srcReg, RegisterID targetReg)
- {
- load64(srcReg, targetReg);
- urshift64(targetReg, TrustedImm32(Value::QuickType_Shift), ScratchRegister2);
- auto isInt = branch32(Equal, TrustedImm32(Value::QT_Int), ScratchRegister2);
-
- pushAligned(AccumulatorRegister);
- move(targetReg, registerForArg(0));
- callHelper(toInt32Helper);
- move(ReturnValueRegister, targetReg);
- popAligned(AccumulatorRegister);
-
- isInt.link(this);
- }
-
- void isNullOrUndefined()
- {
- move(AccumulatorRegister, ScratchRegister);
- compare64(Equal, ScratchRegister, TrustedImm32(0), AccumulatorRegister);
- Jump isUndef = branch32(NotEqual, TrustedImm32(0), AccumulatorRegister);
-
- // not undefined
- rshift64(TrustedImm32(32), ScratchRegister);
- compare32(Equal, ScratchRegister, TrustedImm32(int(QV4::Value::ValueTypeInternal::Null)),
- AccumulatorRegister);
-
- isUndef.link(this);
- }
-
- Jump isIntOrBool()
- {
- urshift64(AccumulatorRegister, TrustedImm32(Value::IsIntegerOrBool_Shift), ScratchRegister);
- return branch32(Equal, TrustedImm32(3), ScratchRegister);
- }
-
- void setAccumulatorTag(QV4::Value::ValueTypeInternal tag, RegisterID sourceReg = NoRegister)
- {
- if (sourceReg == NoRegister)
- or64(TrustedImm64(int64_t(tag) << 32), AccumulatorRegister);
- else
- or64(TrustedImm64(int64_t(tag) << 32), sourceReg, AccumulatorRegister);
- }
-
- void encodeDoubleIntoAccumulator(FPRegisterID src)
- {
- moveDoubleTo64(src, AccumulatorRegister);
- move(TrustedImm64(Value::NaNEncodeMask), ScratchRegister);
- xor64(ScratchRegister, AccumulatorRegister);
- }
-
- void pushValueAligned(ReturnedValue v)
- {
- loadValue(v);
- pushAligned(AccumulatorRegister);
- }
-
- void popValueAligned()
- {
- addPtr(TrustedImm32(2 * PointerSize), StackPointerRegister);
- }
-
- Jump binopBothIntPath(Address lhsAddr, std::function<Jump(void)> fastPath)
- {
- urshift64(AccumulatorRegister, TrustedImm32(32), ScratchRegister);
- Jump accNotInt = branch32(NotEqual, TrustedImm32(int(IntegerTag)), ScratchRegister);
- load64(lhsAddr, ScratchRegister);
- urshift64(ScratchRegister, TrustedImm32(32), ScratchRegister2);
- Jump lhsNotInt = branch32(NotEqual, TrustedImm32(int(IntegerTag)), ScratchRegister2);
-
- // both integer
- Jump failure = fastPath();
- Jump done = jump();
-
- // all other cases
- if (failure.isSet())
- failure.link(this);
- accNotInt.link(this);
- lhsNotInt.link(this);
-
- return done;
- }
-
- Jump unopIntPath(std::function<Jump(void)> fastPath)
- {
- urshift64(AccumulatorRegister, TrustedImm32(Value::IsIntegerConvertible_Shift), ScratchRegister);
- Jump accNotIntConvertible = branch32(NotEqual, TrustedImm32(1), ScratchRegister);
-
- // both integer
- Jump failure = fastPath();
- Jump done = jump();
-
- // all other cases
- if (failure.isSet())
- failure.link(this);
- accNotIntConvertible.link(this);
-
- return done;
- }
-
- void callWithAccumulatorByValueAsFirstArgument(std::function<void()> doCall)
- {
- passAsArg(AccumulatorRegister, 0);
- doCall();
- }
-};
-
-typedef PlatformAssembler64 PlatformAssembler;
-#endif
-
-#if QT_POINTER_SIZE == 4 || defined(ENABLE_ALL_ASSEMBLERS_FOR_REFACTORING_PURPOSES)
-struct PlatformAssembler32 : PlatformAssemblerCommon
-{
- void callRuntime(const char *functionName, const void *funcPtr,
- Assembler::CallResultDestination dest)
- {
- PlatformAssemblerCommon::callRuntime(functionName, funcPtr);
- if (dest == Assembler::ResultInAccumulator)
- saveReturnValueInAccumulator();
- }
-
- void saveReturnValueInAccumulator()
- {
- move(ReturnValueRegisterValue, AccumulatorRegisterValue);
- move(ReturnValueRegisterTag, AccumulatorRegisterTag);
- }
-
- void loadUndefined()
- {
- move(TrustedImm32(0), AccumulatorRegisterValue);
- move(TrustedImm32(0), AccumulatorRegisterTag);
- }
-
- void copyConst(int constIndex, Address destRegAddr)
- {
- //###
- if (constantTable[constIndex].isUndefined()) {
- move(TrustedImm32(0), ScratchRegister);
- store32(ScratchRegister, destRegAddr);
- destRegAddr.offset += 4;
- store32(ScratchRegister, destRegAddr);
- } else {
- Address src = loadConstAddress(constIndex);
- loadDouble(src, FPScratchRegister);
- storeDouble(FPScratchRegister, destRegAddr);
- }
- }
-
- void copyReg(Address src, Address dest)
- {
- loadDouble(src, FPScratchRegister);
- storeDouble(FPScratchRegister, dest);
- }
-
- void loadPointerFromValue(Address addr, RegisterID dest = AccumulatorRegisterValue)
- {
- load32(addr, dest);
- }
-
- void loadAccumulator(Address src)
- {
- load32(src, AccumulatorRegisterValue);
- src.offset += 4;
- load32(src, AccumulatorRegisterTag);
- }
-
- void storeAccumulator(Address addr)
- {
- store32(AccumulatorRegisterValue, addr);
- addr.offset += 4;
- store32(AccumulatorRegisterTag, addr);
- }
-
- void moveReg(Address sourceRegAddress, Address destRegAddress)
- {
- load32(sourceRegAddress, ReturnValueRegisterValue);
- sourceRegAddress.offset += 4;
- load32(sourceRegAddress, ReturnValueRegisterTag);
- store32(ReturnValueRegisterValue, destRegAddress);
- destRegAddress.offset += 4;
- store32(ReturnValueRegisterTag, destRegAddress);
- }
-
- void loadString(int stringId)
- {
- load32(loadStringAddress(stringId), AccumulatorRegisterValue);
- move(TrustedImm32(0), AccumulatorRegisterTag);
- }
-
- void loadValue(ReturnedValue value)
- {
- move(TrustedImm32(Value::fromReturnedValue(value).value()), AccumulatorRegisterValue);
- move(TrustedImm32(Value::fromReturnedValue(value).tag()), AccumulatorRegisterTag);
- }
-
- void storeHeapObject(RegisterID source, Address addr)
- {
- store32(source, addr);
- addr.offset += 4;
- store32(TrustedImm32(0), addr);
- }
-
-
- void generateCatchTrampoline()
- {
- PlatformAssemblerCommon::generateCatchTrampoline([this](){loadUndefined();});
- }
-
- void toNumber()
- {
- urshift32(AccumulatorRegisterTag, TrustedImm32(Value::QuickType_Shift - 32), ScratchRegister);
- auto isNumber = branch32(GreaterThanOrEqual, ScratchRegister, TrustedImm32(Value::QT_Int));
-
- if (ArgInRegCount < 2) {
- push(AccumulatorRegisterTag);
- push(AccumulatorRegisterValue);
- } else {
- move(AccumulatorRegisterValue, registerForArg(0));
- move(AccumulatorRegisterTag, registerForArg(1));
- }
- callRuntime("toNumberHelper", reinterpret_cast<void *>(&toNumberHelper),
- Assembler::ResultInAccumulator);
- saveReturnValueInAccumulator();
- if (ArgInRegCount < 2)
- addPtr(TrustedImm32(2 * PointerSize), StackPointerRegister);
-
- isNumber.link(this);
- }
-
- void toInt32LhsAcc(Address lhs, RegisterID lhsTarget)
- {
- bool accumulatorNeedsSaving = AccumulatorRegisterValue == ReturnValueRegisterValue
- || AccumulatorRegisterTag == ReturnValueRegisterTag;
- lhs.offset += 4;
- load32(lhs, lhsTarget);
- lhs.offset -= 4;
- auto lhsIsNotInt = branch32(NotEqual, TrustedImm32(int(IntegerTag)), lhsTarget);
- load32(lhs, lhsTarget);
- auto lhsIsInt = jump();
-
- lhsIsNotInt.link(this);
- if (accumulatorNeedsSaving) {
- push(AccumulatorRegisterTag);
- push(AccumulatorRegisterValue);
- }
- if (ArgInRegCount < 2) {
- push(lhsTarget);
- load32(lhs, lhsTarget);
- push(lhsTarget);
- } else {
- move(lhsTarget, registerForArg(1));
- load32(lhs, registerForArg(0));
- }
- callHelper(toInt32Helper);
- move(ReturnValueRegisterValue, lhsTarget);
- if (ArgInRegCount < 2)
- addPtr(TrustedImm32(2 * PointerSize), StackPointerRegister);
- if (accumulatorNeedsSaving) {
- pop(AccumulatorRegisterValue);
- pop(AccumulatorRegisterTag);
- }
- lhsIsInt.link(this);
-
- auto rhsIsInt = branch32(Equal, TrustedImm32(int(IntegerTag)), AccumulatorRegisterTag);
-
- pushAligned(lhsTarget);
- if (ArgInRegCount < 2) {
- push(AccumulatorRegisterTag);
- push(AccumulatorRegisterValue);
- } else {
- move(AccumulatorRegisterValue, registerForArg(0));
- move(AccumulatorRegisterTag, registerForArg(1));
- }
- callRuntime("toInt32Helper", reinterpret_cast<void *>(&toInt32Helper),
- Assembler::ResultInAccumulator);
- if (ArgInRegCount < 2)
- addPtr(TrustedImm32(2 * PointerSize), StackPointerRegister);
- popAligned(lhsTarget);
-
- rhsIsInt.link(this);
- }
-
- void toInt32()
- {
- urshift32(AccumulatorRegisterTag, TrustedImm32(Value::QuickType_Shift - 32), ScratchRegister);
- auto isInt = branch32(Equal, TrustedImm32(Value::QT_Int), ScratchRegister);
-
- if (ArgInRegCount < 2) {
- push(AccumulatorRegisterTag);
- push(AccumulatorRegisterValue);
- } else {
- move(AccumulatorRegisterValue, registerForArg(0));
- move(AccumulatorRegisterTag, registerForArg(1));
- }
- callRuntime("toInt32Helper", reinterpret_cast<void *>(&toInt32Helper),
- Assembler::ResultInAccumulator);
- if (ArgInRegCount < 2)
- addPtr(TrustedImm32(2 * PointerSize), StackPointerRegister);
-
- isInt.link(this);
- }
-
- void regToInt32(Address srcReg, RegisterID targetReg)
- {
- bool accumulatorNeedsSaving = AccumulatorRegisterValue == ReturnValueRegisterValue
- || AccumulatorRegisterTag == ReturnValueRegisterTag;
- if (accumulatorNeedsSaving) {
- push(AccumulatorRegisterTag);
- push(AccumulatorRegisterValue);
- }
- if (ArgInRegCount < 2) {
- srcReg.offset += 4;
- load32(srcReg, targetReg);
- push(targetReg);
- srcReg.offset -= 4;
- load32(srcReg, targetReg);
- push(targetReg);
- } else {
- load32(srcReg, registerForArg(0));
- srcReg.offset += 4;
- load32(srcReg, registerForArg(1));
- }
- callHelper(toInt32Helper);
- move(ReturnValueRegisterValue, targetReg);
- if (ArgInRegCount < 2)
- addPtr(TrustedImm32(2 * PointerSize), StackPointerRegister);
- if (accumulatorNeedsSaving) {
- pop(AccumulatorRegisterValue);
- pop(AccumulatorRegisterTag);
- }
- }
-
- void isNullOrUndefined()
- {
- Jump notUndefOrPtr = branch32(NotEqual, TrustedImm32(0), AccumulatorRegisterTag);
- compare32(Equal, AccumulatorRegisterValue, TrustedImm32(0), AccumulatorRegisterValue);
- auto done = jump();
-
- // not undefined or managed
- notUndefOrPtr.link(this);
- compare32(Equal, AccumulatorRegisterTag, TrustedImm32(int(QV4::Value::ValueTypeInternal::Null)),
- AccumulatorRegisterValue);
-
- done.link(this);
- }
-
- Jump isIntOrBool()
- {
- urshift32(AccumulatorRegisterTag, TrustedImm32(Value::IsIntegerOrBool_Shift - 32), ScratchRegister);
- return branch32(Equal, TrustedImm32(3), ScratchRegister);
- }
-
- void pushValue(ReturnedValue v)
- {
- push(TrustedImm32(v >> 32));
- push(TrustedImm32(v));
- }
-
- void jumpNotUndefined(int offset)
- {
- move(AccumulatorRegisterTag, ScratchRegister);
- or32(AccumulatorRegisterValue, ScratchRegister);
- auto jump = branch32(NotEqual, ScratchRegister, TrustedImm32(0));
- patches.push_back({ jump, offset });
- }
-
- Jump jumpEmpty()
- {
- return branch32(Equal, AccumulatorRegisterTag, TrustedImm32(Primitive::emptyValue().asReturnedValue() >> 32));
- }
-
- void toBoolean(std::function<void(RegisterID)> continuation)
- {
- urshift32(AccumulatorRegisterTag, TrustedImm32(Value::IsIntegerConvertible_Shift - 32),
- ScratchRegister);
- auto needsConversion = branch32(NotEqual, TrustedImm32(1), ScratchRegister);
- continuation(AccumulatorRegisterValue);
- Jump done = jump();
-
- // slow path:
- needsConversion.link(this);
-
- bool accumulatorNeedsSaving = AccumulatorRegisterValue == ReturnValueRegisterValue
- || AccumulatorRegisterTag == ReturnValueRegisterTag;
- if (accumulatorNeedsSaving) {
- push(AccumulatorRegisterTag);
- push(AccumulatorRegisterValue);
- }
-
- if (ArgInRegCount < 2) {
- push(AccumulatorRegisterTag);
- push(AccumulatorRegisterValue);
- } else {
- move(AccumulatorRegisterValue, registerForArg(0));
- move(AccumulatorRegisterTag, registerForArg(1));
- }
- callHelper(Value::toBooleanImpl);
- if (ArgInRegCount < 2)
- addPtr(TrustedImm32(2 * PointerSize), StackPointerRegister);
-
- and32(TrustedImm32(1), ReturnValueRegisterValue, ScratchRegister);
- if (accumulatorNeedsSaving) {
- pop(AccumulatorRegisterValue);
- pop(AccumulatorRegisterTag);
- }
- continuation(ScratchRegister);
-
- done.link(this);
- }
-
- void setAccumulatorTag(QV4::Value::ValueTypeInternal tag, RegisterID sourceReg = NoRegister)
- {
- if (sourceReg != NoRegister)
- move(sourceReg, AccumulatorRegisterValue);
- move(TrustedImm32(int(tag)), AccumulatorRegisterTag);
- }
-
- void encodeDoubleIntoAccumulator(FPRegisterID src)
- {
- moveDoubleToInts(src, AccumulatorRegisterValue, AccumulatorRegisterTag);
- xor32(TrustedImm32(Value::NaNEncodeMask >> 32), AccumulatorRegisterTag);
- }
-
- void pushValueAligned(ReturnedValue v)
- {
- pushValue(v);
- }
-
- void popValueAligned()
- {
- popValue();
- }
-
- Jump binopBothIntPath(Address lhsAddr, std::function<Jump(void)> fastPath)
- {
- Jump accNotInt = branch32(NotEqual, TrustedImm32(int(IntegerTag)), AccumulatorRegisterTag);
- Address lhsAddrTag = lhsAddr; lhsAddrTag.offset += Value::tagOffset();
- load32(lhsAddrTag, ScratchRegister);
- Jump lhsNotInt = branch32(NotEqual, TrustedImm32(int(IntegerTag)), ScratchRegister);
-
- // both integer
- Address lhsAddrValue = lhsAddr; lhsAddrValue.offset += Value::valueOffset();
- load32(lhsAddrValue, ScratchRegister);
- Jump failure = fastPath();
- Jump done = jump();
-
- // all other cases
- if (failure.isSet())
- failure.link(this);
- accNotInt.link(this);
- lhsNotInt.link(this);
-
- return done;
- }
-
- Jump unopIntPath(std::function<Jump(void)> fastPath)
- {
- Jump accNotInt = branch32(NotEqual, TrustedImm32(int(IntegerTag)), AccumulatorRegisterTag);
-
- // both integer
- Jump failure = fastPath();
- Jump done = jump();
-
- // all other cases
- if (failure.isSet())
- failure.link(this);
- accNotInt.link(this);
-
- return done;
- }
-
- void callWithAccumulatorByValueAsFirstArgument(std::function<void()> doCall)
- {
- if (ArgInRegCount < 2) {
- push(AccumulatorRegisterTag);
- push(AccumulatorRegisterValue);
- } else {
- move(AccumulatorRegisterValue, registerForArg(0));
- move(AccumulatorRegisterTag, registerForArg(1));
- }
- doCall();
- if (ArgInRegCount < 2)
- addPtr(TrustedImm32(2 * PointerSize), StackPointerRegister);
- }
-};
-
-typedef PlatformAssembler32 PlatformAssembler;
-#endif
-
-typedef PlatformAssembler::TrustedImmPtr TrustedImmPtr;
-typedef PlatformAssembler::TrustedImm32 TrustedImm32;
-typedef PlatformAssembler::TrustedImm64 TrustedImm64;
-typedef PlatformAssembler::Address Address;
-typedef PlatformAssembler::RegisterID RegisterID;
-typedef PlatformAssembler::FPRegisterID FPRegisterID;
-
-#define pasm() reinterpret_cast<PlatformAssembler *>(this->d)
-
-static Address regAddr(int reg)
-{
- return Address(PlatformAssembler::JSStackFrameRegister, reg * int(sizeof(QV4::Value)));
-}
-
-Assembler::Assembler(const Value *constantTable)
- : d(new PlatformAssembler)
-{
- pasm()->constantTable = constantTable;
-}
-
-Assembler::~Assembler()
-{
- delete pasm();
-}
-
-void Assembler::generatePrologue()
-{
- pasm()->generateFunctionEntry();
-}
-
-void Assembler::generateEpilogue()
-{
- pasm()->generateCatchTrampoline();
-}
-
-namespace {
-class QIODevicePrintStream: public FilePrintStream
-{
- Q_DISABLE_COPY(QIODevicePrintStream)
-
-public:
- explicit QIODevicePrintStream(QIODevice *dest)
- : FilePrintStream(nullptr)
- , dest(dest)
- , buf(4096, '0')
- {
- Q_ASSERT(dest);
- }
-
- ~QIODevicePrintStream()
- {}
-
- void vprintf(const char* format, va_list argList) WTF_ATTRIBUTE_PRINTF(2, 0)
- {
- const int written = qvsnprintf(buf.data(), buf.size(), format, argList);
- if (written > 0)
- dest->write(buf.constData(), written);
- memset(buf.data(), 0, qMin(written, buf.size()));
- }
-
- void flush()
- {}
-
-private:
- QIODevice *dest;
- QByteArray buf;
-};
-} // anonymous namespace
-
-static void printDisassembledOutputWithCalls(QByteArray processedOutput,
- const QHash<const void*, const char*>& functions)
-{
- for (QHash<const void*, const char*>::ConstIterator it = functions.begin(), end = functions.end();
- it != end; ++it) {
- const QByteArray ptrString = "0x" + QByteArray::number(quintptr(it.key()), 16);
- int idx = 0;
- while (idx >= 0) {
- idx = processedOutput.indexOf(ptrString, idx);
- if (idx < 0)
- break;
- idx = processedOutput.indexOf('\n', idx);
- if (idx < 0)
- break;
- processedOutput = processedOutput.insert(idx, QByteArrayLiteral(" ; ") + it.value());
- }
- }
-
- qDebug("%s", processedOutput.constData());
-}
-
-static QByteArray functionName(Function *function)
-{
- QByteArray name = function->name()->toQString().toUtf8();
- if (name.isEmpty()) {
- name = QByteArray::number(reinterpret_cast<quintptr>(function), 16);
- name.prepend("QV4::Function(0x");
- name.append(')');
- }
- return name;
-}
-
-void Assembler::link(Function *function)
-{
- for (const auto &jumpTarget : pasm()->patches)
- jumpTarget.jump.linkTo(pasm()->labelsByOffset[jumpTarget.offset], pasm());
-
- JSC::JSGlobalData dummy(function->internalClass->engine->executableAllocator);
- JSC::LinkBuffer<PlatformAssembler::MacroAssembler> linkBuffer(dummy, pasm(), nullptr);
-
- for (const auto &ehTarget : pasm()->ehTargets) {
- auto targetLabel = pasm()->labelsByOffset.value(ehTarget.offset);
- linkBuffer.patch(ehTarget.label, linkBuffer.locationOf(targetLabel));
- }
-
- JSC::MacroAssemblerCodeRef codeRef;
-
- static const bool showCode = qEnvironmentVariableIsSet("QV4_SHOW_ASM");
- if (showCode) {
- QBuffer buf;
- buf.open(QIODevice::WriteOnly);
- WTF::setDataFile(new QIODevicePrintStream(&buf));
-
- QByteArray name = functionName(function);
- codeRef = linkBuffer.finalizeCodeWithDisassembly("%s", name.data());
-
- WTF::setDataFile(stderr);
- printDisassembledOutputWithCalls(buf.data(), pasm()->functions);
- } else {
- codeRef = linkBuffer.finalizeCodeWithoutDisassembly();
- }
-
- function->codeRef = new JSC::MacroAssemblerCodeRef(codeRef);
- function->jittedCode = reinterpret_cast<Function::JittedCode>(function->codeRef->code().executableAddress());
-
- // This implements writing of JIT'd addresses so that perf can find the
- // symbol names.
- //
- // Perf expects the mapping to be in a certain place and have certain
- // content, for more information, see:
- // https://github.com/torvalds/linux/blob/master/tools/perf/Documentation/jit-interface.txt
- static bool doProfile = !qEnvironmentVariableIsEmpty("QV4_PROFILE_WRITE_PERF_MAP");
- if (Q_UNLIKELY(doProfile)) {
- static QFile perfMapFile(QString::fromLatin1("/tmp/perf-%1.map")
- .arg(QCoreApplication::applicationPid()));
- static const bool isOpen = perfMapFile.open(QIODevice::WriteOnly);
- if (!isOpen) {
- qWarning("QV4::JIT::Assembler: Cannot write perf map file.");
- doProfile = false;
- } else {
- perfMapFile.write(QByteArray::number(reinterpret_cast<quintptr>(
- codeRef.code().executableAddress()), 16));
- perfMapFile.putChar(' ');
- perfMapFile.write(QByteArray::number(static_cast<qsizetype>(codeRef.size()), 16));
- perfMapFile.putChar(' ');
- perfMapFile.write(functionName(function));
- perfMapFile.putChar('\n');
- perfMapFile.flush();
- }
- }
-}
-
-void Assembler::addLabel(int offset)
-{
- pasm()->labelsByOffset[offset] = pasm()->label();
-}
-
-void Assembler::loadConst(int constIndex)
-{
- //###
- if (pasm()->constantTable[constIndex].isUndefined()) {
- pasm()->loadUndefined();
- } else {
- pasm()->loadAccumulator(pasm()->loadConstAddress(constIndex));
- }
-}
-
-void Assembler::copyConst(int constIndex, int destReg)
-{
- pasm()->copyConst(constIndex, regAddr(destReg));
-}
-
-void Assembler::loadReg(int reg)
-{
- pasm()->loadAccumulator(regAddr(reg));
-}
-
-void JIT::Assembler::moveReg(int sourceReg, int destReg)
-{
- pasm()->moveReg(regAddr(sourceReg), regAddr(destReg));
-}
-
-void Assembler::storeReg(int reg)
-{
- pasm()->storeAccumulator(regAddr(reg));
-}
-
-void Assembler::loadLocal(int index, int level)
-{
- Heap::CallContext ctx;
- Q_UNUSED(ctx)
- pasm()->loadPointerFromValue(regAddr(CallData::Context), PlatformAssembler::ScratchRegister);
- while (level) {
- pasm()->loadPtr(Address(PlatformAssembler::ScratchRegister, ctx.outer.offset), PlatformAssembler::ScratchRegister);
- --level;
- }
- pasm()->loadAccumulator(Address(PlatformAssembler::ScratchRegister, ctx.locals.offset + offsetof(ValueArray<0>, values) + sizeof(Value)*index));
-}
-
-void Assembler::storeLocal(int index, int level)
-{
- Heap::CallContext ctx;
- Q_UNUSED(ctx)
- pasm()->loadPtr(regAddr(CallData::Context), PlatformAssembler::ScratchRegister);
- while (level) {
- pasm()->loadPtr(Address(PlatformAssembler::ScratchRegister, ctx.outer.offset), PlatformAssembler::ScratchRegister);
- --level;
- }
- pasm()->storeAccumulator(Address(PlatformAssembler::ScratchRegister, ctx.locals.offset + offsetof(ValueArray<0>, values) + sizeof(Value)*index));
-}
-
-void Assembler::loadString(int stringId)
-{
- pasm()->loadString(stringId);
-}
-
-void Assembler::loadValue(ReturnedValue value)
-{
- pasm()->loadValue(value);
-}
-
-void JIT::Assembler::storeHeapObject(int reg)
-{
- pasm()->storeHeapObject(PlatformAssembler::ReturnValueRegisterValue, regAddr(reg));
-}
-
-void JIT::Assembler::loadImport(int index)
-{
- Address addr = pasm()->loadCompilationUnitPtr(PlatformAssembler::ScratchRegister);
- addr.offset = offsetof(QV4::CompiledData::CompilationUnitBase, imports);
- pasm()->loadPtr(addr, PlatformAssembler::ScratchRegister);
- addr.offset = index * int(sizeof(QV4::Value*));
- pasm()->loadPtr(addr, PlatformAssembler::ScratchRegister);
- pasm()->loadAccumulator(Address(PlatformAssembler::ScratchRegister));
-}
-
-void Assembler::toNumber()
-{
- pasm()->toNumber();
-}
-
-void Assembler::uminus()
-{
- saveAccumulatorInFrame();
- prepareCallWithArgCount(1);
- passAccumulatorAsArg(0);
- IN_JIT_GENERATE_RUNTIME_CALL(Runtime::method_uMinus, ResultInAccumulator);
- checkException();
-}
-
-void Assembler::ucompl()
-{
- pasm()->toInt32();
- pasm()->xor32(TrustedImm32(-1), PlatformAssembler::AccumulatorRegisterValue);
- pasm()->setAccumulatorTag(IntegerTag);
-}
-
-static ReturnedValue incHelper(const Value v)
-{
- double d;
- if (Q_LIKELY(v.isDouble()))
- d = v.doubleValue();
- else
- d = v.toNumberImpl();
- return Encode(d + 1.);
-}
-
-void Assembler::inc()
-{
- auto done = pasm()->unopIntPath([this](){
- auto overflowed = pasm()->branchAdd32(PlatformAssembler::Overflow,
- PlatformAssembler::AccumulatorRegisterValue,
- TrustedImm32(1),
- PlatformAssembler::ScratchRegister);
- pasm()->setAccumulatorTag(IntegerTag, PlatformAssembler::ScratchRegister);
- return overflowed;
- });
-
- // slow path:
- pasm()->callWithAccumulatorByValueAsFirstArgument([this]() {
- pasm()->callHelper(incHelper);
- pasm()->saveReturnValueInAccumulator();
- });
- checkException();
-
- // done.
- done.link(pasm());
-}
-
-static ReturnedValue decHelper(const Value v)
-{
- double d;
- if (Q_LIKELY(v.isDouble()))
- d = v.doubleValue();
- else
- d = v.toNumberImpl();
- return Encode(d - 1.);
-}
-
-void Assembler::dec()
-{
- auto done = pasm()->unopIntPath([this](){
- auto overflowed = pasm()->branchSub32(PlatformAssembler::Overflow,
- PlatformAssembler::AccumulatorRegisterValue,
- TrustedImm32(1),
- PlatformAssembler::ScratchRegister);
- pasm()->setAccumulatorTag(IntegerTag, PlatformAssembler::ScratchRegister);
- return overflowed;
- });
-
- // slow path:
- pasm()->callWithAccumulatorByValueAsFirstArgument([this]() {
- pasm()->callHelper(decHelper);
- pasm()->saveReturnValueInAccumulator();
- });
- checkException();
-
- // done.
- done.link(pasm());
-}
-
-void Assembler::unot()
-{
- pasm()->toBoolean([this](PlatformAssembler::RegisterID resultReg){
- pasm()->compare32(PlatformAssembler::Equal, resultReg,
- TrustedImm32(0), PlatformAssembler::AccumulatorRegisterValue);
- pasm()->setAccumulatorTag(QV4::Value::ValueTypeInternal::Boolean);
- });
-}
-
-void Assembler::add(int lhs)
-{
- auto done = pasm()->binopBothIntPath(regAddr(lhs), [this](){
- auto overflowed = pasm()->branchAdd32(PlatformAssembler::Overflow,
- PlatformAssembler::AccumulatorRegisterValue,
- PlatformAssembler::ScratchRegister);
- pasm()->setAccumulatorTag(IntegerTag,
- PlatformAssembler::ScratchRegister);
- return overflowed;
- });
-
- // slow path:
- saveAccumulatorInFrame();
- prepareCallWithArgCount(3);
- passAccumulatorAsArg(2);
- passRegAsArg(lhs, 1);
- passEngineAsArg(0);
- IN_JIT_GENERATE_RUNTIME_CALL(Runtime::method_add, ResultInAccumulator);
- checkException();
-
- // done.
- done.link(pasm());
-}
-
-void Assembler::bitAnd(int lhs)
-{
- PlatformAssembler::Address lhsAddr = regAddr(lhs);
- pasm()->toInt32LhsAcc(lhsAddr, PlatformAssembler::ScratchRegister);
- pasm()->and32(PlatformAssembler::ScratchRegister, PlatformAssembler::AccumulatorRegisterValue);
- pasm()->setAccumulatorTag(IntegerTag);
-}
-
-void Assembler::bitOr(int lhs)
-{
- PlatformAssembler::Address lhsAddr = regAddr(lhs);
- pasm()->toInt32LhsAcc(lhsAddr, PlatformAssembler::ScratchRegister);
- pasm()->or32(PlatformAssembler::ScratchRegister, PlatformAssembler::AccumulatorRegisterValue);
- pasm()->setAccumulatorTag(IntegerTag);
-}
-
-void Assembler::bitXor(int lhs)
-{
- PlatformAssembler::Address lhsAddr = regAddr(lhs);
- pasm()->toInt32LhsAcc(lhsAddr, PlatformAssembler::ScratchRegister);
- pasm()->xor32(PlatformAssembler::ScratchRegister, PlatformAssembler::AccumulatorRegisterValue);
- pasm()->setAccumulatorTag(IntegerTag);
-}
-
-void Assembler::ushr(int lhs)
-{
- PlatformAssembler::Address lhsAddr = regAddr(lhs);
- pasm()->toInt32LhsAcc(lhsAddr, PlatformAssembler::ScratchRegister);
- pasm()->and32(TrustedImm32(0x1f), PlatformAssembler::AccumulatorRegisterValue);
- pasm()->urshift32(PlatformAssembler::AccumulatorRegisterValue, PlatformAssembler::ScratchRegister);
- pasm()->move(PlatformAssembler::ScratchRegister, PlatformAssembler::AccumulatorRegisterValue);
- auto doubleEncode = pasm()->branch32(PlatformAssembler::LessThan,
- PlatformAssembler::AccumulatorRegisterValue,
- TrustedImm32(0));
- pasm()->setAccumulatorTag(IntegerTag);
- auto done = pasm()->jump();
-
- doubleEncode.link(pasm());
- pasm()->convertUInt32ToDouble(PlatformAssembler::AccumulatorRegisterValue,
- PlatformAssembler::FPScratchRegister,
- PlatformAssembler::ScratchRegister);
- pasm()->encodeDoubleIntoAccumulator(PlatformAssembler::FPScratchRegister);
- done.link(pasm());
-}
-
-void Assembler::shr(int lhs)
-{
- PlatformAssembler::Address lhsAddr = regAddr(lhs);
- pasm()->toInt32LhsAcc(lhsAddr, PlatformAssembler::ScratchRegister);
- pasm()->and32(TrustedImm32(0x1f), PlatformAssembler::AccumulatorRegisterValue);
- pasm()->rshift32(PlatformAssembler::AccumulatorRegisterValue, PlatformAssembler::ScratchRegister);
- pasm()->move(PlatformAssembler::ScratchRegister, PlatformAssembler::AccumulatorRegisterValue);
- pasm()->setAccumulatorTag(IntegerTag);
-}
-
-void Assembler::shl(int lhs)
-{
- PlatformAssembler::Address lhsAddr = regAddr(lhs);
- pasm()->toInt32LhsAcc(lhsAddr, PlatformAssembler::ScratchRegister);
- pasm()->and32(TrustedImm32(0x1f), PlatformAssembler::AccumulatorRegisterValue);
- pasm()->lshift32(PlatformAssembler::AccumulatorRegisterValue, PlatformAssembler::ScratchRegister);
- pasm()->move(PlatformAssembler::ScratchRegister, PlatformAssembler::AccumulatorRegisterValue);
- pasm()->setAccumulatorTag(IntegerTag);
-}
-
-void Assembler::bitAndConst(int rhs)
-{
- pasm()->toInt32();
- pasm()->and32(TrustedImm32(rhs), PlatformAssembler::AccumulatorRegisterValue);
- pasm()->setAccumulatorTag(IntegerTag);
-}
-
-void Assembler::bitOrConst(int rhs)
-{
- pasm()->toInt32();
- pasm()->or32(TrustedImm32(rhs), PlatformAssembler::AccumulatorRegisterValue);
- pasm()->setAccumulatorTag(IntegerTag);
-}
-
-void Assembler::bitXorConst(int rhs)
-{
- pasm()->toInt32();
- pasm()->xor32(TrustedImm32(rhs), PlatformAssembler::AccumulatorRegisterValue);
- pasm()->setAccumulatorTag(IntegerTag);
-}
-
-void Assembler::ushrConst(int rhs)
-{
- rhs &= 0x1f;
- pasm()->toInt32();
- if (rhs) {
- // a non zero shift will always give a number encodable as an int
- pasm()->urshift32(TrustedImm32(rhs), PlatformAssembler::AccumulatorRegisterValue);
- pasm()->setAccumulatorTag(IntegerTag);
- } else {
- // shift with 0 can lead to a negative result
- auto doubleEncode = pasm()->branch32(PlatformAssembler::LessThan,
- PlatformAssembler::AccumulatorRegisterValue,
- TrustedImm32(0));
- pasm()->setAccumulatorTag(IntegerTag);
- auto done = pasm()->jump();
-
- doubleEncode.link(pasm());
- pasm()->convertUInt32ToDouble(PlatformAssembler::AccumulatorRegisterValue,
- PlatformAssembler::FPScratchRegister,
- PlatformAssembler::ScratchRegister);
- pasm()->encodeDoubleIntoAccumulator(PlatformAssembler::FPScratchRegister);
- done.link(pasm());
- }
-}
-
-void Assembler::shrConst(int rhs)
-{
- rhs &= 0x1f;
- pasm()->toInt32();
- if (rhs)
- pasm()->rshift32(TrustedImm32(rhs), PlatformAssembler::AccumulatorRegisterValue);
- pasm()->setAccumulatorTag(IntegerTag);
-}
-
-void Assembler::shlConst(int rhs)
-{
- rhs &= 0x1f;
- pasm()->toInt32();
- if (rhs)
- pasm()->lshift32(TrustedImm32(rhs), PlatformAssembler::AccumulatorRegisterValue);
- pasm()->setAccumulatorTag(IntegerTag);
-}
-
-void Assembler::mul(int lhs)
-{
- auto done = pasm()->binopBothIntPath(regAddr(lhs), [this](){
- auto overflowed = pasm()->branchMul32(PlatformAssembler::Overflow,
- PlatformAssembler::AccumulatorRegisterValue,
- PlatformAssembler::ScratchRegister);
- pasm()->setAccumulatorTag(IntegerTag,
- PlatformAssembler::ScratchRegister);
- return overflowed;
- });
-
- // slow path:
- saveAccumulatorInFrame();
- prepareCallWithArgCount(2);
- passAccumulatorAsArg(1);
- passRegAsArg(lhs, 0);
- IN_JIT_GENERATE_RUNTIME_CALL(Runtime::method_mul, ResultInAccumulator);
- checkException();
-
- // done.
- done.link(pasm());
-}
-
-void Assembler::div(int lhs)
-{
- saveAccumulatorInFrame();
- prepareCallWithArgCount(2);
- passAccumulatorAsArg(1);
- passRegAsArg(lhs, 0);
- IN_JIT_GENERATE_RUNTIME_CALL(Runtime::method_div, ResultInAccumulator);
- checkException();
-}
-
-void Assembler::mod(int lhs)
-{
- saveAccumulatorInFrame();
- prepareCallWithArgCount(2);
- passAccumulatorAsArg(1);
- passRegAsArg(lhs, 0);
- IN_JIT_GENERATE_RUNTIME_CALL(Runtime::method_mod, ResultInAccumulator);
- checkException();
-}
-
-void Assembler::sub(int lhs)
-{
- auto done = pasm()->binopBothIntPath(regAddr(lhs), [this](){
- auto overflowed = pasm()->branchSub32(PlatformAssembler::Overflow,
- PlatformAssembler::AccumulatorRegisterValue,
- PlatformAssembler::ScratchRegister);
- pasm()->setAccumulatorTag(IntegerTag,
- PlatformAssembler::ScratchRegister);
- return overflowed;
- });
-
- // slow path:
- saveAccumulatorInFrame();
- prepareCallWithArgCount(2);
- passAccumulatorAsArg(1);
- passRegAsArg(lhs, 0);
- IN_JIT_GENERATE_RUNTIME_CALL(Runtime::method_sub, ResultInAccumulator);
- checkException();
-
- // done.
- done.link(pasm());
-}
-
-void Assembler::cmpeqNull()
-{
- pasm()->isNullOrUndefined();
- pasm()->setAccumulatorTag(QV4::Value::ValueTypeInternal::Boolean);
-}
-
-void Assembler::cmpneNull()
-{
- pasm()->isNullOrUndefined();
- pasm()->xor32(TrustedImm32(1), PlatformAssembler::AccumulatorRegisterValue);
- pasm()->setAccumulatorTag(QV4::Value::ValueTypeInternal::Boolean);
-}
-
-void Assembler::cmpeqInt(int lhs)
-{
- auto isIntOrBool = pasm()->isIntOrBool();
- saveAccumulatorInFrame();
- pasm()->pushValueAligned(Encode(lhs));
- if (PlatformAssembler::ArgInRegCount < 2)
- pasm()->push(PlatformAssembler::StackPointerRegister);
- else
- pasm()->move(PlatformAssembler::StackPointerRegister, pasm()->registerForArg(1));
- passAccumulatorAsArg_internal(0, true);
- pasm()->callRuntime("Runtime::method_equal", (void*)Runtime::method_equal, ResultInAccumulator);
- if (PlatformAssembler::ArgInRegCount < 2)
- pasm()->addPtr(TrustedImm32(2 * PlatformAssembler::PointerSize), PlatformAssembler::StackPointerRegister);
- pasm()->popValueAligned();
- auto done = pasm()->jump();
- isIntOrBool.link(pasm());
- pasm()->compare32(PlatformAssembler::Equal, PlatformAssembler::AccumulatorRegisterValue,
- TrustedImm32(lhs),
- PlatformAssembler::AccumulatorRegisterValue);
- pasm()->setAccumulatorTag(QV4::Value::ValueTypeInternal::Boolean);
- done.link(pasm());
-}
-
-void Assembler::cmpneInt(int lhs)
-{
- auto isIntOrBool = pasm()->isIntOrBool();
- saveAccumulatorInFrame();
- pasm()->pushValueAligned(Encode(lhs));
- if (PlatformAssembler::ArgInRegCount < 2)
- pasm()->push(PlatformAssembler::StackPointerRegister);
- else
- pasm()->move(PlatformAssembler::StackPointerRegister, pasm()->registerForArg(1));
- passAccumulatorAsArg_internal(0, true);
- pasm()->callRuntime("Runtime::method_notEqual", (void*)Runtime::method_notEqual, ResultInAccumulator);
- if (PlatformAssembler::ArgInRegCount < 2)
- pasm()->addPtr(TrustedImm32(2 * PlatformAssembler::PointerSize), PlatformAssembler::StackPointerRegister);
- pasm()->popValueAligned();
- auto done = pasm()->jump();
- isIntOrBool.link(pasm());
- pasm()->compare32(PlatformAssembler::NotEqual, PlatformAssembler::AccumulatorRegisterValue,
- TrustedImm32(lhs),
- PlatformAssembler::AccumulatorRegisterValue);
- pasm()->setAccumulatorTag(QV4::Value::ValueTypeInternal::Boolean);
- done.link(pasm());
-}
-
-void Assembler::cmp(int cond, CmpFunc function, const char *functionName, int lhs)
-{
- auto c = static_cast<PlatformAssembler::RelationalCondition>(cond);
- auto done = pasm()->binopBothIntPath(regAddr(lhs), [this, c](){
- pasm()->compare32(c, PlatformAssembler::ScratchRegister,
- PlatformAssembler::AccumulatorRegisterValue,
- PlatformAssembler::AccumulatorRegisterValue);
- pasm()->setAccumulatorTag(QV4::Value::ValueTypeInternal::Boolean);
- return PlatformAssembler::Jump();
- });
-
- // slow path:
- saveAccumulatorInFrame();
- prepareCallWithArgCount(2);
- passAccumulatorAsArg(1);
- passRegAsArg(lhs, 0);
-
- callRuntime(functionName, reinterpret_cast<void*>(function), ResultInAccumulator);
- checkException();
- pasm()->setAccumulatorTag(QV4::Value::ValueTypeInternal::Boolean);
-
- // done.
- done.link(pasm());
-}
-
-void Assembler::cmpeq(int lhs)
-{
- cmp(PlatformAssembler::Equal, &Runtime::method_compareEqual,
- "Runtime::method_compareEqual", lhs);
-}
-
-void Assembler::cmpne(int lhs)
-{
- cmp(PlatformAssembler::NotEqual, &Runtime::method_compareNotEqual,
- "Runtime::method_compareNotEqual", lhs);
-}
-
-void Assembler::cmpgt(int lhs)
-{
- cmp(PlatformAssembler::GreaterThan, &Runtime::method_compareGreaterThan,
- "Runtime::method_compareGreaterThan", lhs);
-}
-
-void Assembler::cmpge(int lhs)
-{
- cmp(PlatformAssembler::GreaterThanOrEqual, &Runtime::method_compareGreaterEqual,
- "Runtime::method_compareGreaterEqual", lhs);
-}
-
-void Assembler::cmplt(int lhs)
-{
- cmp(PlatformAssembler::LessThan, &Runtime::method_compareLessThan,
- "Runtime::method_compareLessThan", lhs);
-}
-
-void Assembler::cmple(int lhs)
-{
- cmp(PlatformAssembler::LessThanOrEqual, &Runtime::method_compareLessEqual,
- "Runtime::method_compareLessEqual", lhs);
-}
-
-void Assembler::cmpStrictEqual(int lhs)
-{
- cmp(PlatformAssembler::Equal, &RuntimeHelpers::strictEqual,
- "RuntimeHelpers::strictEqual", lhs);
-}
-
-void Assembler::cmpStrictNotEqual(int lhs)
-{
- cmp(PlatformAssembler::Equal, &RuntimeHelpers::strictEqual,
- "RuntimeHelpers::strictEqual", lhs);
- pasm()->xor32(TrustedImm32(1), PlatformAssembler::AccumulatorRegisterValue);
- pasm()->setAccumulatorTag(QV4::Value::ValueTypeInternal::Boolean);
-}
-
-void Assembler::jump(int offset)
-{
- pasm()->patches.push_back({ pasm()->jump(), offset });
-}
-
-void Assembler::jumpTrue(int offset)
-{
- pasm()->toBoolean([this, offset](PlatformAssembler::RegisterID resultReg) {
- auto jump = pasm()->branch32(PlatformAssembler::NotEqual, TrustedImm32(0), resultReg);
- pasm()->patches.push_back({ jump, offset });
- });
-}
-
-void Assembler::jumpFalse(int offset)
-{
- pasm()->toBoolean([this, offset](PlatformAssembler::RegisterID resultReg) {
- auto jump = pasm()->branch32(PlatformAssembler::Equal, TrustedImm32(0), resultReg);
- pasm()->patches.push_back({ jump, offset });
- });
-}
-
-void Assembler::jumpNoException(int offset)
-{
- auto jump = pasm()->branch32(
- PlatformAssembler::Equal,
- PlatformAssembler::Address(PlatformAssembler::EngineRegister,
- offsetof(EngineBase, hasException)),
- TrustedImm32(0));
- pasm()->patches.push_back({ jump, offset });
-}
-
-void Assembler::jumpNotUndefined(int offset)
-{
- pasm()->jumpNotUndefined(offset);
-}
-
-void Assembler::prepareCallWithArgCount(int argc)
-{
-#ifndef QT_NO_DEBUG
- Q_ASSERT(remainingArgcForCall == NoCall);
- remainingArgcForCall = argc;
-#endif
-
- if (argc > PlatformAssembler::ArgInRegCount) {
- argcOnStackForCall = int(WTF::roundUpToMultipleOf(16, size_t(argc - PlatformAssembler::ArgInRegCount) * PlatformAssembler::PointerSize));
- pasm()->subPtr(TrustedImm32(argcOnStackForCall), PlatformAssembler::StackPointerRegister);
- }
-}
-
-void Assembler::storeInstructionPointer(int instructionOffset)
-{
- PlatformAssembler::Address addr(PlatformAssembler::CppStackFrameRegister,
- offsetof(QV4::CppStackFrame, instructionPointer));
- pasm()->store32(TrustedImm32(instructionOffset), addr);
-}
-
-Address argStackAddress(int arg)
-{
- int offset = arg - PlatformAssembler::ArgInRegCount;
- Q_ASSERT(offset >= 0);
- return Address(PlatformAssembler::StackPointerRegister, offset * PlatformAssembler::PointerSize);
-}
-
-void Assembler::passAccumulatorAsArg(int arg)
-{
-#ifndef QT_NO_DEBUG
- Q_ASSERT(arg < remainingArgcForCall);
- --remainingArgcForCall;
-#endif
-
- passAccumulatorAsArg_internal(arg, false);
-}
-
-void Assembler::passAccumulatorAsArg_internal(int arg, bool push)
-{
- if (arg < PlatformAssembler::ArgInRegCount) {
- pasm()->addPtr(TrustedImm32(offsetof(CallData, accumulator)),
- PlatformAssembler::JSStackFrameRegister,
- pasm()->registerForArg(arg));
- } else {
- pasm()->addPtr(TrustedImm32(offsetof(CallData, accumulator)),
- PlatformAssembler::JSStackFrameRegister,
- PlatformAssembler::ScratchRegister);
- if (push)
- pasm()->push(PlatformAssembler::ScratchRegister);
- else
- pasm()->storePtr(PlatformAssembler::ScratchRegister,
- argStackAddress(arg));
- }
-}
-
-void Assembler::passFunctionAsArg(int arg)
-{
-#ifndef QT_NO_DEBUG
- Q_ASSERT(arg < remainingArgcForCall);
- --remainingArgcForCall;
-#endif
-
- if (arg < PlatformAssembler::ArgInRegCount) {
- pasm()->loadFunctionPtr(pasm()->registerForArg(arg));
- } else {
- pasm()->loadFunctionPtr(PlatformAssembler::ScratchRegister);
- pasm()->storePtr(PlatformAssembler::ScratchRegister,
- argStackAddress(arg));
- }
-}
-
-void Assembler::passEngineAsArg(int arg)
-{
-#ifndef QT_NO_DEBUG
- Q_ASSERT(arg < remainingArgcForCall);
- --remainingArgcForCall;
-#endif
-
- if (arg < PlatformAssembler::ArgInRegCount) {
- pasm()->move(PlatformAssembler::EngineRegister, pasm()->registerForArg(arg));
- } else {
- pasm()->storePtr(PlatformAssembler::EngineRegister, argStackAddress(arg));
- }
-}
-
-void Assembler::passRegAsArg(int reg, int arg)
-{
-#ifndef QT_NO_DEBUG
- Q_ASSERT(arg < remainingArgcForCall);
- --remainingArgcForCall;
-#endif
-
- if (arg < PlatformAssembler::ArgInRegCount) {
- pasm()->addPtr(TrustedImm32(reg * int(sizeof(QV4::Value))),
- PlatformAssembler::JSStackFrameRegister,
- pasm()->registerForArg(arg));
- } else {
- pasm()->addPtr(TrustedImm32(reg * int(sizeof(QV4::Value))),
- PlatformAssembler::JSStackFrameRegister,
- PlatformAssembler::ScratchRegister);
- pasm()->storePtr(PlatformAssembler::ScratchRegister,
- argStackAddress(arg));
- }
-}
-
-void JIT::Assembler::passCppFrameAsArg(int arg)
-{
-#ifndef QT_NO_DEBUG
- Q_ASSERT(arg < remainingArgcForCall);
- --remainingArgcForCall;
-#endif
-
- if (arg < PlatformAssembler::ArgInRegCount) {
- pasm()->move(PlatformAssembler::CppStackFrameRegister, pasm()->registerForArg(arg));
- } else {
- pasm()->store32(PlatformAssembler::CppStackFrameRegister, argStackAddress(arg));
- }
-}
-
-void Assembler::passInt32AsArg(int value, int arg)
-{
-#ifndef QT_NO_DEBUG
- Q_ASSERT(arg < remainingArgcForCall);
- --remainingArgcForCall;
-#endif
-
- if (arg < PlatformAssembler::ArgInRegCount) {
- pasm()->move(TrustedImm32(value), pasm()->registerForArg(arg));
- } else {
- pasm()->store32(TrustedImm32(value), argStackAddress(arg));
- }
-}
-
-void Assembler::callRuntime(const char *functionName, const void *funcPtr,
- Assembler::CallResultDestination dest)
-{
-#ifndef QT_NO_DEBUG
- Q_ASSERT(remainingArgcForCall == 0);
- remainingArgcForCall = NoCall;
-#endif
- pasm()->callRuntime(functionName, funcPtr, dest);
- if (argcOnStackForCall > 0) {
- pasm()->addPtr(TrustedImm32(argcOnStackForCall), PlatformAssembler::StackPointerRegister);
- argcOnStackForCall = 0;
- }
-}
-
-void Assembler::saveAccumulatorInFrame()
-{
- pasm()->storeAccumulator(PlatformAssembler::Address(PlatformAssembler::JSStackFrameRegister,
- offsetof(CallData, accumulator)));
-}
-
-void Assembler::checkException()
-{
- pasm()->addCatchyJump(
- pasm()->branch32(
- PlatformAssembler::NotEqual,
- PlatformAssembler::Address(PlatformAssembler::EngineRegister,
- offsetof(EngineBase, hasException)),
- TrustedImm32(0)));
-}
-
-void Assembler::gotoCatchException()
-{
- pasm()->addCatchyJump(pasm()->jump());
-}
-
-void Assembler::getException()
-{
- Q_STATIC_ASSERT(sizeof(QV4::EngineBase::hasException) == 1);
-
- Address hasExceptionAddr(PlatformAssembler::EngineRegister,
- offsetof(EngineBase, hasException));
- PlatformAssembler::Jump nope = pasm()->branch8(PlatformAssembler::Equal,
- hasExceptionAddr,
- TrustedImm32(0));
- pasm()->loadPtr(Address(PlatformAssembler::EngineRegister,
- offsetof(EngineBase, exceptionValue)),
- PlatformAssembler::ScratchRegister);
- pasm()->loadAccumulator(Address(PlatformAssembler::ScratchRegister));
- pasm()->store8(TrustedImm32(0), hasExceptionAddr);
- auto done = pasm()->jump();
- nope.link(pasm());
- pasm()->loadValue(Primitive::emptyValue().asReturnedValue());
-
- done.link(pasm());
-}
-
-void Assembler::setException()
-{
- auto noException = pasm()->jumpEmpty();
- Address addr(PlatformAssembler::EngineRegister, offsetof(EngineBase, exceptionValue));
- pasm()->loadPtr(addr, PlatformAssembler::ScratchRegister);
- pasm()->storeAccumulator(Address(PlatformAssembler::ScratchRegister));
- addr.offset = offsetof(EngineBase, hasException);
- Q_STATIC_ASSERT(sizeof(QV4::EngineBase::hasException) == 1);
- pasm()->store8(TrustedImm32(1), addr);
- noException.link(pasm());
-}
-
-void Assembler::setUnwindHandler(int offset)
-{
- auto l = pasm()->storePtrWithPatch(TrustedImmPtr(nullptr), pasm()->exceptionHandlerAddress());
- pasm()->ehTargets.push_back({ l, offset });
-}
-
-
-void Assembler::clearUnwindHandler()
-{
- pasm()->storePtr(TrustedImmPtr(nullptr), pasm()->exceptionHandlerAddress());
-}
-
-void JIT::Assembler::unwindDispatch()
-{
- checkException();
- pasm()->load32(Address(PlatformAssembler::CppStackFrameRegister, offsetof(CppStackFrame, unwindLevel)), PlatformAssembler::ScratchRegister);
- auto noUnwind = pasm()->branch32(PlatformAssembler::Equal, PlatformAssembler::ScratchRegister, TrustedImm32(0));
- pasm()->sub32(TrustedImm32(1), PlatformAssembler::ScratchRegister);
- pasm()->store32(PlatformAssembler::ScratchRegister, Address(PlatformAssembler::CppStackFrameRegister, offsetof(CppStackFrame, unwindLevel)));
- auto jump = pasm()->branch32(PlatformAssembler::Equal, PlatformAssembler::ScratchRegister, TrustedImm32(0));
- gotoCatchException();
- jump.link(pasm());
-
- pasm()->loadPtr(Address(PlatformAssembler::CppStackFrameRegister, offsetof(CppStackFrame, unwindLabel)), PlatformAssembler::ScratchRegister);
- pasm()->jump(PlatformAssembler::ScratchRegister);
-
- noUnwind.link(pasm());
-}
-
-void JIT::Assembler::unwindToLabel(int level, int offset)
-{
- auto l = pasm()->storePtrWithPatch(TrustedImmPtr(nullptr), Address(PlatformAssembler::CppStackFrameRegister, offsetof(CppStackFrame, unwindLabel)));
- pasm()->ehTargets.push_back({ l, offset });
- pasm()->store32(TrustedImm32(level), Address(PlatformAssembler::CppStackFrameRegister, offsetof(CppStackFrame, unwindLevel)));
- gotoCatchException();
-}
-
-void Assembler::pushCatchContext(int index, int name)
-{
- prepareCallWithArgCount(3);
- passInt32AsArg(name, 2);
- passInt32AsArg(index, 1);
- passRegAsArg(CallData::Context, 0);
- IN_JIT_GENERATE_RUNTIME_CALL(Runtime::method_createCatchContext, ResultInAccumulator);
- pasm()->storeAccumulator(pasm()->contextAddress());
-}
-
-void Assembler::popContext()
-{
- Heap::CallContext ctx;
- Q_UNUSED(ctx)
- pasm()->loadPointerFromValue(regAddr(CallData::Context), PlatformAssembler::ScratchRegister);
- pasm()->loadPtr(Address(PlatformAssembler::ScratchRegister, ctx.outer.offset), PlatformAssembler::ScratchRegister);
- pasm()->storeHeapObject(PlatformAssembler::ScratchRegister, regAddr(CallData::Context));
-}
-
-void Assembler::ret()
-{
- pasm()->generateFunctionExit();
-}
-
-} // JIT namespace
-} // QV4 namepsace
-
-QT_END_NAMESPACE
-
-#endif // V4_ENABLE_JIT